From dd4cacb5381dc869dcfb3df8730315406df02eab Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Thu, 19 Nov 2020 18:24:03 +0100 Subject: [PATCH 001/360] failed approach --- Makefile | 3 +- config/objects/systemObjectList.h | 3 +- gomspace/gomspace.mk | 10 + gomspace/libgscsp/include/gs/csp/address.h | 65 + gomspace/libgscsp/include/gs/csp/command.h | 25 + gomspace/libgscsp/include/gs/csp/conn.h | 26 + gomspace/libgscsp/include/gs/csp/csp.h | 202 + .../libgscsp/include/gs/csp/drivers/can/can.h | 54 + .../libgscsp/include/gs/csp/drivers/i2c/i2c.h | 29 + .../include/gs/csp/drivers/kiss/kiss.h | 30 + gomspace/libgscsp/include/gs/csp/error.h | 28 + .../include/gs/csp/linux/command_line.h | 24 + gomspace/libgscsp/include/gs/csp/log.h | 27 + gomspace/libgscsp/include/gs/csp/port.h | 111 + gomspace/libgscsp/include/gs/csp/router.h | 36 + gomspace/libgscsp/include/gs/csp/rtable.h | 31 + .../include/gs/csp/service_dispatcher.h | 124 + .../libgscsp/include/gs/csp/service_handler.h | 102 + gomspace/libgscsp/lib/libcsp/CHANGELOG | 113 + gomspace/libgscsp/lib/libcsp/CONTRIBUTORS | 3 + gomspace/libgscsp/lib/libcsp/COPYING | 503 + gomspace/libgscsp/lib/libcsp/INSTALL.rst | 30 + gomspace/libgscsp/lib/libcsp/README.rst | 41 + .../libcsp/bindings/python/libcsp/__init__.py | 6 + gomspace/libgscsp/lib/libcsp/doc/example.rst | 123 + gomspace/libgscsp/lib/libcsp/doc/history.rst | 17 + .../libgscsp/lib/libcsp/doc/interfaces.rst | 95 + gomspace/libgscsp/lib/libcsp/doc/libcsp.rst | 21 + gomspace/libgscsp/lib/libcsp/doc/memory.rst | 28 + gomspace/libgscsp/lib/libcsp/doc/mtu.rst | 19 + .../libgscsp/lib/libcsp/doc/protocolstack.rst | 54 + .../libgscsp/lib/libcsp/doc/structure.rst | 27 + gomspace/libgscsp/lib/libcsp/doc/topology.rst | 26 + .../lib/libcsp/examples/csp_if_fifo.c | 165 + .../lib/libcsp/examples/csp_if_fifo_windows.c | 225 + gomspace/libgscsp/lib/libcsp/examples/kiss.c | 151 + .../python_bindings_example_client.py | 42 + .../python_bindings_example_client_can.py | 30 + .../python_bindings_example_server.py | 72 + .../libgscsp/lib/libcsp/examples/simple.c | 200 + .../libgscsp/lib/libcsp/examples/zmqproxy.c | 82 + .../lib/libcsp/include/csp/arch/csp_clock.h | 60 + .../lib/libcsp/include/csp/arch/csp_malloc.h | 39 + .../lib/libcsp/include/csp/arch/csp_queue.h | 49 + .../libcsp/include/csp/arch/csp_semaphore.h | 109 + .../lib/libcsp/include/csp/arch/csp_system.h | 74 + .../lib/libcsp/include/csp/arch/csp_thread.h | 100 + .../lib/libcsp/include/csp/arch/csp_time.h | 57 + .../include/csp/arch/posix/pthread_queue.h | 118 + .../lib/libcsp/include/csp/crypto/csp_hmac.h | 73 + .../lib/libcsp/include/csp/crypto/csp_sha1.h | 81 + .../lib/libcsp/include/csp/crypto/csp_xtea.h | 52 + .../libgscsp/lib/libcsp/include/csp/csp.h | 545 + .../lib/libcsp/include/csp/csp_autoconfig.h | 41 + .../lib/libcsp/include/csp/csp_buffer.h | 92 + .../libgscsp/lib/libcsp/include/csp/csp_cmp.h | 189 + .../lib/libcsp/include/csp/csp_crc32.h | 63 + .../lib/libcsp/include/csp/csp_debug.h | 150 + .../lib/libcsp/include/csp/csp_endian.h | 170 + .../lib/libcsp/include/csp/csp_error.h | 50 + .../lib/libcsp/include/csp/csp_iflist.h | 56 + .../lib/libcsp/include/csp/csp_interface.h | 54 + .../lib/libcsp/include/csp/csp_platform.h | 56 + .../lib/libcsp/include/csp/csp_rtable.h | 149 + .../lib/libcsp/include/csp/csp_types.h | 235 + .../include/csp/drivers/can_socketcan.h | 22 + .../lib/libcsp/include/csp/drivers/i2c.h | 120 + .../lib/libcsp/include/csp/drivers/usart.h | 107 + .../include/csp/interfaces/csp_if_can.h | 76 + .../include/csp/interfaces/csp_if_i2c.h | 51 + .../include/csp/interfaces/csp_if_kiss.h | 110 + .../libcsp/include/csp/interfaces/csp_if_lo.h | 38 + .../include/csp/interfaces/csp_if_zmqhub.h | 26 + .../lib/libcsp/src/arch/freertos/csp_malloc.c | 33 + .../lib/libcsp/src/arch/freertos/csp_queue.c | 66 + .../libcsp/src/arch/freertos/csp_semaphore.c | 96 + .../lib/libcsp/src/arch/freertos/csp_system.c | 139 + .../lib/libcsp/src/arch/freertos/csp_thread.c | 38 + .../lib/libcsp/src/arch/freertos/csp_time.c | 46 + .../lib/libcsp/src/arch/macosx/csp_malloc.c | 31 + .../lib/libcsp/src/arch/macosx/csp_queue.c | 64 + .../libcsp/src/arch/macosx/csp_semaphore.c | 105 + .../lib/libcsp/src/arch/macosx/csp_system.c | 99 + .../lib/libcsp/src/arch/macosx/csp_thread.c | 31 + .../lib/libcsp/src/arch/macosx/csp_time.c | 65 + .../libcsp/src/arch/macosx/pthread_queue.c | 179 + .../lib/libcsp/src/arch/posix/csp_malloc.c | 31 + .../lib/libcsp/src/arch/posix/csp_queue.c | 64 + .../lib/libcsp/src/arch/posix/csp_semaphore.c | 164 + .../lib/libcsp/src/arch/posix/csp_system.c | 131 + .../lib/libcsp/src/arch/posix/csp_thread.c | 55 + .../lib/libcsp/src/arch/posix/csp_time.c | 54 + .../lib/libcsp/src/arch/posix/pthread_queue.c | 243 + .../lib/libcsp/src/arch/windows/README | 18 + .../lib/libcsp/src/arch/windows/csp_malloc.c | 9 + .../lib/libcsp/src/arch/windows/csp_queue.c | 40 + .../libcsp/src/arch/windows/csp_semaphore.c | 74 + .../lib/libcsp/src/arch/windows/csp_system.c | 60 + .../lib/libcsp/src/arch/windows/csp_thread.c | 11 + .../lib/libcsp/src/arch/windows/csp_time.c | 20 + .../libcsp/src/arch/windows/windows_glue.h | 23 + .../libcsp/src/arch/windows/windows_queue.c | 91 + .../libcsp/src/arch/windows/windows_queue.h | 41 + .../lib/libcsp/src/bindings/python/pycsp.c | 1052 ++ .../libgscsp/lib/libcsp/src/crypto/csp_hmac.c | 202 + .../libgscsp/lib/libcsp/src/crypto/csp_sha1.c | 217 + .../libgscsp/lib/libcsp/src/crypto/csp_xtea.c | 134 + gomspace/libgscsp/lib/libcsp/src/csp_bridge.c | 94 + gomspace/libgscsp/lib/libcsp/src/csp_buffer.c | 224 + gomspace/libgscsp/lib/libcsp/src/csp_conn.c | 498 + gomspace/libgscsp/lib/libcsp/src/csp_conn.h | 112 + gomspace/libgscsp/lib/libcsp/src/csp_crc32.c | 140 + gomspace/libgscsp/lib/libcsp/src/csp_debug.c | 133 + gomspace/libgscsp/lib/libcsp/src/csp_dedup.c | 66 + gomspace/libgscsp/lib/libcsp/src/csp_dedup.h | 31 + gomspace/libgscsp/lib/libcsp/src/csp_endian.c | 204 + .../libgscsp/lib/libcsp/src/csp_hex_dump.c | 55 + gomspace/libgscsp/lib/libcsp/src/csp_iflist.c | 100 + gomspace/libgscsp/lib/libcsp/src/csp_io.c | 502 + gomspace/libgscsp/lib/libcsp/src/csp_io.h | 47 + gomspace/libgscsp/lib/libcsp/src/csp_port.c | 105 + gomspace/libgscsp/lib/libcsp/src/csp_port.h | 55 + .../libgscsp/lib/libcsp/src/csp_promisc.c | 82 + .../libgscsp/lib/libcsp/src/csp_promisc.h | 30 + gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c | 149 + gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h | 54 + gomspace/libgscsp/lib/libcsp/src/csp_route.c | 347 + gomspace/libgscsp/lib/libcsp/src/csp_route.h | 24 + .../lib/libcsp/src/csp_service_handler.c | 334 + .../libgscsp/lib/libcsp/src/csp_services.c | 233 + gomspace/libgscsp/lib/libcsp/src/csp_sfp.c | 170 + .../libcsp/src/drivers/can/can_socketcan.c | 201 + .../libcsp/src/drivers/usart/usart_linux.c | 254 + .../libcsp/src/drivers/usart/usart_windows.c | 230 + .../lib/libcsp/src/interfaces/csp_if_can.c | 279 + .../libcsp/src/interfaces/csp_if_can_pbuf.c | 77 + .../libcsp/src/interfaces/csp_if_can_pbuf.h | 31 + .../lib/libcsp/src/interfaces/csp_if_i2c.c | 116 + .../lib/libcsp/src/interfaces/csp_if_kiss.c | 260 + .../lib/libcsp/src/interfaces/csp_if_lo.c | 61 + .../lib/libcsp/src/interfaces/csp_if_zmqhub.c | 165 + .../lib/libcsp/src/rtable/csp_rtable_cidr.c | 233 + .../lib/libcsp/src/rtable/csp_rtable_static.c | 128 + .../lib/libcsp/src/transport/csp_rdp.c | 1102 ++ .../lib/libcsp/src/transport/csp_transport.h | 46 + .../lib/libcsp/src/transport/csp_udp.c | 49 + .../libgscsp/lib/libcsp/utils/cfpsplit.py | 52 + .../libgscsp/lib/libcsp/utils/cspsplit.py | 52 + gomspace/libgscsp/lib/libcsp/waf | 170 + gomspace/libgscsp/lib/libcsp/wscript | 346 + .../libgscsp/src/bindings/python/pygscsp.c | 61 + gomspace/libgscsp/src/clock.c | 23 + gomspace/libgscsp/src/commands.c | 652 ++ gomspace/libgscsp/src/conn.c | 22 + gomspace/libgscsp/src/csp.c | 91 + gomspace/libgscsp/src/drivers/can/can.c | 106 + gomspace/libgscsp/src/drivers/i2c/i2c.c | 77 + gomspace/libgscsp/src/drivers/kiss/kiss.c | 36 + gomspace/libgscsp/src/error.c | 54 + gomspace/libgscsp/src/freertos/cpu.c | 8 + gomspace/libgscsp/src/linux/command_line.c | 265 + gomspace/libgscsp/src/local.h | 21 + gomspace/libgscsp/src/log.c | 64 + gomspace/libgscsp/src/router.c | 84 + gomspace/libgscsp/src/rtable.c | 69 + gomspace/libgscsp/src/service_dispatcher.c | 213 + gomspace/libgscsp/src/service_handler.c | 86 + gomspace/libgscsp/src/transaction.c | 67 + gomspace/libgscsp/wscript | 104 + gomspace/libp60_client/include/p60.h | 48 + gomspace/libp60_client/include/p60_board.h | 35 + gomspace/libp60_client/include/power_if.h | 62 + gomspace/libp60_client/src/cmd/power_if_cmd.c | 147 + gomspace/libp60_client/src/p60_client.c | 33 + gomspace/libp60_client/src/power_if.c | 91 + gomspace/libp60_client/wscript | 28 + .../deprecated/gs/gosh/command/command.h | 49 + .../include/deprecated/gs/gosh/gosh/getopt.h | 22 + .../include/deprecated/gs/gosh/util/console.h | 43 + .../include/deprecated/util/color_printf.h | 26 + gomspace/libutil/include/gs/uthash/utarray.h | 231 + gomspace/libutil/include/gs/uthash/uthash.h | 960 ++ gomspace/libutil/include/gs/uthash/utlist.h | 757 ++ gomspace/libutil/include/gs/uthash/utstring.h | 393 + gomspace/libutil/include/gs/util/base16.h | 90 + gomspace/libutil/include/gs/util/bytebuffer.h | 173 + gomspace/libutil/include/gs/util/byteorder.h | 341 + gomspace/libutil/include/gs/util/check.h | 54 + gomspace/libutil/include/gs/util/clock.h | 88 + gomspace/libutil/include/gs/util/conf_util.h | 10 + gomspace/libutil/include/gs/util/crc32.h | 55 + gomspace/libutil/include/gs/util/crc8.h | 55 + gomspace/libutil/include/gs/util/delay.h | 42 + .../libutil/include/gs/util/drivers/can/can.h | 122 + .../include/gs/util/drivers/gpio/gpio.h | 91 + .../include/gs/util/drivers/i2c/common.h | 88 + .../include/gs/util/drivers/i2c/master.h | 32 + .../include/gs/util/drivers/i2c/slave.h | 79 + .../include/gs/util/drivers/spi/common.h | 66 + .../include/gs/util/drivers/spi/master.h | 95 + .../include/gs/util/drivers/spi/slave.h | 84 + .../include/gs/util/drivers/sys/memory.h | 92 + .../include/gs/util/drivers/watchdog/device.h | 61 + gomspace/libutil/include/gs/util/endian.h | 53 + gomspace/libutil/include/gs/util/error.h | 199 + gomspace/libutil/include/gs/util/fletcher.h | 89 + .../include/gs/util/function_scheduler.h | 79 + .../libutil/include/gs/util/gosh/command.h | 503 + .../libutil/include/gs/util/gosh/console.h | 123 + gomspace/libutil/include/gs/util/hexdump.h | 53 + gomspace/libutil/include/gs/util/linux/argp.h | 40 + .../include/gs/util/linux/command_line.h | 42 + .../include/gs/util/linux/drivers/can/can.h | 29 + .../include/gs/util/linux/drivers/gpio/gpio.h | 146 + .../gs/util/linux/drivers/gpio/gpio_sysfs.h | 91 + .../gs/util/linux/drivers/gpio/gpio_virtual.h | 125 + .../include/gs/util/linux/drivers/i2c/i2c.h | 198 + .../include/gs/util/linux/drivers/spi/spi.h | 175 + .../libutil/include/gs/util/linux/exitcode.h | 40 + .../libutil/include/gs/util/linux/function.h | 49 + gomspace/libutil/include/gs/util/linux/rtc.h | 28 + .../libutil/include/gs/util/linux/signal.h | 40 + .../include/gs/util/linux/sysfs_helper.h | 30 + gomspace/libutil/include/gs/util/log.h | 15 + .../include/gs/util/log/appender/appender.h | 189 + .../include/gs/util/log/appender/console.h | 57 + .../gs/util/log/appender/simple_file.h | 41 + gomspace/libutil/include/gs/util/log/log.h | 853 ++ gomspace/libutil/include/gs/util/minmax.h | 67 + gomspace/libutil/include/gs/util/mutex.h | 63 + gomspace/libutil/include/gs/util/pgm.h | 162 + gomspace/libutil/include/gs/util/queue.h | 102 + gomspace/libutil/include/gs/util/rtc.h | 62 + gomspace/libutil/include/gs/util/sem.h | 75 + gomspace/libutil/include/gs/util/stdio.h | 117 + gomspace/libutil/include/gs/util/string.h | 391 + .../libutil/include/gs/util/test/cmocka.h | 136 + .../libutil/include/gs/util/test/command.h | 80 + gomspace/libutil/include/gs/util/test/log.h | 88 + gomspace/libutil/include/gs/util/thread.h | 173 + gomspace/libutil/include/gs/util/time.h | 95 + gomspace/libutil/include/gs/util/timestamp.h | 73 + gomspace/libutil/include/gs/util/types.h | 114 + gomspace/libutil/include/gs/util/unistd.h | 32 + gomspace/libutil/include/gs/util/vmem.h | 194 + .../include/gs/util/watchdog/watchdog.h | 143 + .../include/gs/util/watchdog/watchdog_task.h | 45 + gomspace/libutil/include/gs/util/zip/zip.h | 62 + gomspace/libutil/src/base16.c | 61 + gomspace/libutil/src/bindings/python/pyutil.c | 73 + gomspace/libutil/src/bytebuffer.c | 128 + gomspace/libutil/src/byteorder.c | 323 + gomspace/libutil/src/clock.c | 113 + gomspace/libutil/src/crc32.c | 79 + gomspace/libutil/src/crc8.c | 68 + gomspace/libutil/src/drivers/can/can.c | 6 + gomspace/libutil/src/drivers/i2c/i2c.c | 6 + gomspace/libutil/src/drivers/spi/spi.c | 6 + gomspace/libutil/src/drivers/sys/memory.c | 37 + gomspace/libutil/src/error.c | 106 + gomspace/libutil/src/fletcher.c | 77 + gomspace/libutil/src/function_scheduler.c | 111 + gomspace/libutil/src/gosh/command.c | 754 ++ gomspace/libutil/src/gosh/command_local.h | 35 + gomspace/libutil/src/gosh/console.c | 758 ++ gomspace/libutil/src/gosh/console_local.h | 10 + gomspace/libutil/src/gosh/default_commands.c | 277 + gomspace/libutil/src/gosh/getopt.c | 55 + gomspace/libutil/src/hexdump.c | 92 + gomspace/libutil/src/linux/argp.c | 34 + gomspace/libutil/src/linux/clock.c | 68 + gomspace/libutil/src/linux/command_line.c | 76 + gomspace/libutil/src/linux/cwd.c | 28 + gomspace/libutil/src/linux/delay.c | 22 + gomspace/libutil/src/linux/drivers/can/can.c | 308 + .../libutil/src/linux/drivers/gpio/gpio.c | 102 + .../src/linux/drivers/gpio/gpio_sysfs.c | 145 + .../src/linux/drivers/gpio/gpio_virtual.c | 171 + gomspace/libutil/src/linux/drivers/i2c/i2c.c | 144 + gomspace/libutil/src/linux/drivers/spi/spi.c | 137 + .../libutil/src/linux/drivers/sys/memory.c | 30 + gomspace/libutil/src/linux/function.c | 41 + gomspace/libutil/src/linux/mutex.c | 59 + gomspace/libutil/src/linux/queue.c | 217 + gomspace/libutil/src/linux/rtc.c | 78 + gomspace/libutil/src/linux/sem.c | 89 + gomspace/libutil/src/linux/signal.c | 38 + gomspace/libutil/src/linux/stdio.c | 36 + gomspace/libutil/src/linux/sysfs_helper.c | 48 + gomspace/libutil/src/linux/thread.c | 89 + gomspace/libutil/src/linux/time.c | 53 + gomspace/libutil/src/lock.c | 30 + gomspace/libutil/src/lock.h | 14 + gomspace/libutil/src/log/appender/console.c | 88 + .../libutil/src/log/appender/simple_file.c | 117 + gomspace/libutil/src/log/commands.c | 392 + gomspace/libutil/src/log/local.h | 27 + gomspace/libutil/src/log/log.c | 705 ++ gomspace/libutil/src/rtc.c | 42 + gomspace/libutil/src/stdio.c | 81 + gomspace/libutil/src/string.c | 746 ++ gomspace/libutil/src/strtoint.c | 399 + gomspace/libutil/src/test/cmocka.c | 63 + gomspace/libutil/src/test/command.c | 176 + gomspace/libutil/src/test/log.c | 165 + gomspace/libutil/src/time.c | 28 + gomspace/libutil/src/timestamp.c | 61 + gomspace/libutil/src/vmem/commands.c | 123 + gomspace/libutil/src/vmem/vmem.c | 143 + gomspace/libutil/src/watchdog/local.h | 18 + gomspace/libutil/src/watchdog/monitor_task.c | 68 + gomspace/libutil/src/watchdog/watchdog.c | 292 + .../libutil/src/zip/cppcheck-suppress.txt | 5 + .../libutil/src/zip/miniz/LIST_OF_CHANGES | 9429 +++++++++++++++++ gomspace/libutil/src/zip/miniz/miniz.c | 7572 +++++++++++++ gomspace/libutil/src/zip/miniz/miniz.h | 1329 +++ gomspace/libutil/src/zip/zip.c | 357 + gomspace/libutil/wscript | 109 + mission/core/InitMission.cpp | 26 +- mission/core/ObjectFactory.cpp | 4 +- mission/devices/P60DockHandler.cpp | 23 + mission/devices/P60DockHandler.h | 18 + test/testtasks/P60DockTestTask.cpp | 88 + test/testtasks/P60DockTestTask.h | 35 + 324 files changed, 57839 insertions(+), 11 deletions(-) create mode 100644 gomspace/gomspace.mk create mode 100644 gomspace/libgscsp/include/gs/csp/address.h create mode 100644 gomspace/libgscsp/include/gs/csp/command.h create mode 100644 gomspace/libgscsp/include/gs/csp/conn.h create mode 100644 gomspace/libgscsp/include/gs/csp/csp.h create mode 100644 gomspace/libgscsp/include/gs/csp/drivers/can/can.h create mode 100644 gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h create mode 100644 gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h create mode 100644 gomspace/libgscsp/include/gs/csp/error.h create mode 100644 gomspace/libgscsp/include/gs/csp/linux/command_line.h create mode 100644 gomspace/libgscsp/include/gs/csp/log.h create mode 100644 gomspace/libgscsp/include/gs/csp/port.h create mode 100644 gomspace/libgscsp/include/gs/csp/router.h create mode 100644 gomspace/libgscsp/include/gs/csp/rtable.h create mode 100644 gomspace/libgscsp/include/gs/csp/service_dispatcher.h create mode 100644 gomspace/libgscsp/include/gs/csp/service_handler.h create mode 100644 gomspace/libgscsp/lib/libcsp/CHANGELOG create mode 100644 gomspace/libgscsp/lib/libcsp/CONTRIBUTORS create mode 100644 gomspace/libgscsp/lib/libcsp/COPYING create mode 100644 gomspace/libgscsp/lib/libcsp/INSTALL.rst create mode 100644 gomspace/libgscsp/lib/libcsp/README.rst create mode 100644 gomspace/libgscsp/lib/libcsp/bindings/python/libcsp/__init__.py create mode 100644 gomspace/libgscsp/lib/libcsp/doc/example.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/history.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/interfaces.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/libcsp.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/memory.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/mtu.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/protocolstack.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/structure.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/topology.rst create mode 100644 gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo.c create mode 100644 gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo_windows.c create mode 100644 gomspace/libgscsp/lib/libcsp/examples/kiss.c create mode 100644 gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client.py create mode 100644 gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client_can.py create mode 100644 gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_server.py create mode 100644 gomspace/libgscsp/lib/libcsp/examples/simple.c create mode 100644 gomspace/libgscsp/lib/libcsp/examples/zmqproxy.c create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_clock.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_malloc.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_queue.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_semaphore.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_system.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_thread.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_time.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/posix/pthread_queue.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_hmac.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_sha1.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_xtea.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_autoconfig.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_buffer.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_cmp.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_crc32.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_debug.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_endian.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_error.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_iflist.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_interface.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_platform.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_rtable.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_types.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/drivers/can_socketcan.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/drivers/i2c.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/drivers/usart.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_can.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_i2c.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_kiss.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_lo.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_zmqhub.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_malloc.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_queue.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_semaphore.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_system.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_thread.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_time.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_malloc.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_queue.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_semaphore.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_system.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_thread.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_time.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/pthread_queue.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_malloc.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_queue.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_semaphore.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_system.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_thread.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_time.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/pthread_queue.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/README create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_malloc.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_queue.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_semaphore.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_system.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_thread.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_time.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_glue.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/bindings/python/pycsp.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/crypto/csp_hmac.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/crypto/csp_sha1.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/crypto/csp_xtea.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_bridge.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_buffer.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_conn.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_conn.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_crc32.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_debug.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_dedup.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_dedup.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_endian.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_hex_dump.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_iflist.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_io.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_io.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_port.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_port.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_promisc.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_promisc.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_route.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_route.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_service_handler.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_services.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_sfp.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/drivers/can/can_socketcan.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_linux.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_windows.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_i2c.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_kiss.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_lo.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_cidr.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_static.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/transport/csp_rdp.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/transport/csp_transport.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/transport/csp_udp.c create mode 100644 gomspace/libgscsp/lib/libcsp/utils/cfpsplit.py create mode 100644 gomspace/libgscsp/lib/libcsp/utils/cspsplit.py create mode 100644 gomspace/libgscsp/lib/libcsp/waf create mode 100644 gomspace/libgscsp/lib/libcsp/wscript create mode 100644 gomspace/libgscsp/src/bindings/python/pygscsp.c create mode 100644 gomspace/libgscsp/src/clock.c create mode 100644 gomspace/libgscsp/src/commands.c create mode 100644 gomspace/libgscsp/src/conn.c create mode 100644 gomspace/libgscsp/src/csp.c create mode 100644 gomspace/libgscsp/src/drivers/can/can.c create mode 100644 gomspace/libgscsp/src/drivers/i2c/i2c.c create mode 100644 gomspace/libgscsp/src/drivers/kiss/kiss.c create mode 100644 gomspace/libgscsp/src/error.c create mode 100644 gomspace/libgscsp/src/freertos/cpu.c create mode 100644 gomspace/libgscsp/src/linux/command_line.c create mode 100644 gomspace/libgscsp/src/local.h create mode 100644 gomspace/libgscsp/src/log.c create mode 100644 gomspace/libgscsp/src/router.c create mode 100644 gomspace/libgscsp/src/rtable.c create mode 100644 gomspace/libgscsp/src/service_dispatcher.c create mode 100644 gomspace/libgscsp/src/service_handler.c create mode 100644 gomspace/libgscsp/src/transaction.c create mode 100644 gomspace/libgscsp/wscript create mode 100644 gomspace/libp60_client/include/p60.h create mode 100644 gomspace/libp60_client/include/p60_board.h create mode 100644 gomspace/libp60_client/include/power_if.h create mode 100644 gomspace/libp60_client/src/cmd/power_if_cmd.c create mode 100644 gomspace/libp60_client/src/p60_client.c create mode 100644 gomspace/libp60_client/src/power_if.c create mode 100644 gomspace/libp60_client/wscript create mode 100644 gomspace/libutil/include/deprecated/gs/gosh/command/command.h create mode 100644 gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h create mode 100644 gomspace/libutil/include/deprecated/gs/gosh/util/console.h create mode 100644 gomspace/libutil/include/deprecated/util/color_printf.h create mode 100644 gomspace/libutil/include/gs/uthash/utarray.h create mode 100644 gomspace/libutil/include/gs/uthash/uthash.h create mode 100644 gomspace/libutil/include/gs/uthash/utlist.h create mode 100644 gomspace/libutil/include/gs/uthash/utstring.h create mode 100644 gomspace/libutil/include/gs/util/base16.h create mode 100644 gomspace/libutil/include/gs/util/bytebuffer.h create mode 100644 gomspace/libutil/include/gs/util/byteorder.h create mode 100644 gomspace/libutil/include/gs/util/check.h create mode 100644 gomspace/libutil/include/gs/util/clock.h create mode 100644 gomspace/libutil/include/gs/util/conf_util.h create mode 100644 gomspace/libutil/include/gs/util/crc32.h create mode 100644 gomspace/libutil/include/gs/util/crc8.h create mode 100644 gomspace/libutil/include/gs/util/delay.h create mode 100644 gomspace/libutil/include/gs/util/drivers/can/can.h create mode 100644 gomspace/libutil/include/gs/util/drivers/gpio/gpio.h create mode 100644 gomspace/libutil/include/gs/util/drivers/i2c/common.h create mode 100644 gomspace/libutil/include/gs/util/drivers/i2c/master.h create mode 100644 gomspace/libutil/include/gs/util/drivers/i2c/slave.h create mode 100644 gomspace/libutil/include/gs/util/drivers/spi/common.h create mode 100644 gomspace/libutil/include/gs/util/drivers/spi/master.h create mode 100644 gomspace/libutil/include/gs/util/drivers/spi/slave.h create mode 100644 gomspace/libutil/include/gs/util/drivers/sys/memory.h create mode 100644 gomspace/libutil/include/gs/util/drivers/watchdog/device.h create mode 100644 gomspace/libutil/include/gs/util/endian.h create mode 100644 gomspace/libutil/include/gs/util/error.h create mode 100644 gomspace/libutil/include/gs/util/fletcher.h create mode 100644 gomspace/libutil/include/gs/util/function_scheduler.h create mode 100644 gomspace/libutil/include/gs/util/gosh/command.h create mode 100644 gomspace/libutil/include/gs/util/gosh/console.h create mode 100644 gomspace/libutil/include/gs/util/hexdump.h create mode 100644 gomspace/libutil/include/gs/util/linux/argp.h create mode 100644 gomspace/libutil/include/gs/util/linux/command_line.h create mode 100644 gomspace/libutil/include/gs/util/linux/drivers/can/can.h create mode 100644 gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h create mode 100644 gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h create mode 100644 gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h create mode 100644 gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h create mode 100644 gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h create mode 100644 gomspace/libutil/include/gs/util/linux/exitcode.h create mode 100644 gomspace/libutil/include/gs/util/linux/function.h create mode 100644 gomspace/libutil/include/gs/util/linux/rtc.h create mode 100644 gomspace/libutil/include/gs/util/linux/signal.h create mode 100644 gomspace/libutil/include/gs/util/linux/sysfs_helper.h create mode 100644 gomspace/libutil/include/gs/util/log.h create mode 100644 gomspace/libutil/include/gs/util/log/appender/appender.h create mode 100644 gomspace/libutil/include/gs/util/log/appender/console.h create mode 100644 gomspace/libutil/include/gs/util/log/appender/simple_file.h create mode 100644 gomspace/libutil/include/gs/util/log/log.h create mode 100644 gomspace/libutil/include/gs/util/minmax.h create mode 100644 gomspace/libutil/include/gs/util/mutex.h create mode 100644 gomspace/libutil/include/gs/util/pgm.h create mode 100644 gomspace/libutil/include/gs/util/queue.h create mode 100644 gomspace/libutil/include/gs/util/rtc.h create mode 100644 gomspace/libutil/include/gs/util/sem.h create mode 100644 gomspace/libutil/include/gs/util/stdio.h create mode 100644 gomspace/libutil/include/gs/util/string.h create mode 100644 gomspace/libutil/include/gs/util/test/cmocka.h create mode 100644 gomspace/libutil/include/gs/util/test/command.h create mode 100644 gomspace/libutil/include/gs/util/test/log.h create mode 100644 gomspace/libutil/include/gs/util/thread.h create mode 100644 gomspace/libutil/include/gs/util/time.h create mode 100644 gomspace/libutil/include/gs/util/timestamp.h create mode 100644 gomspace/libutil/include/gs/util/types.h create mode 100644 gomspace/libutil/include/gs/util/unistd.h create mode 100644 gomspace/libutil/include/gs/util/vmem.h create mode 100644 gomspace/libutil/include/gs/util/watchdog/watchdog.h create mode 100644 gomspace/libutil/include/gs/util/watchdog/watchdog_task.h create mode 100644 gomspace/libutil/include/gs/util/zip/zip.h create mode 100644 gomspace/libutil/src/base16.c create mode 100644 gomspace/libutil/src/bindings/python/pyutil.c create mode 100644 gomspace/libutil/src/bytebuffer.c create mode 100644 gomspace/libutil/src/byteorder.c create mode 100644 gomspace/libutil/src/clock.c create mode 100644 gomspace/libutil/src/crc32.c create mode 100644 gomspace/libutil/src/crc8.c create mode 100644 gomspace/libutil/src/drivers/can/can.c create mode 100644 gomspace/libutil/src/drivers/i2c/i2c.c create mode 100644 gomspace/libutil/src/drivers/spi/spi.c create mode 100644 gomspace/libutil/src/drivers/sys/memory.c create mode 100644 gomspace/libutil/src/error.c create mode 100644 gomspace/libutil/src/fletcher.c create mode 100644 gomspace/libutil/src/function_scheduler.c create mode 100644 gomspace/libutil/src/gosh/command.c create mode 100644 gomspace/libutil/src/gosh/command_local.h create mode 100644 gomspace/libutil/src/gosh/console.c create mode 100644 gomspace/libutil/src/gosh/console_local.h create mode 100644 gomspace/libutil/src/gosh/default_commands.c create mode 100644 gomspace/libutil/src/gosh/getopt.c create mode 100644 gomspace/libutil/src/hexdump.c create mode 100644 gomspace/libutil/src/linux/argp.c create mode 100644 gomspace/libutil/src/linux/clock.c create mode 100644 gomspace/libutil/src/linux/command_line.c create mode 100644 gomspace/libutil/src/linux/cwd.c create mode 100644 gomspace/libutil/src/linux/delay.c create mode 100644 gomspace/libutil/src/linux/drivers/can/can.c create mode 100644 gomspace/libutil/src/linux/drivers/gpio/gpio.c create mode 100644 gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c create mode 100644 gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c create mode 100644 gomspace/libutil/src/linux/drivers/i2c/i2c.c create mode 100644 gomspace/libutil/src/linux/drivers/spi/spi.c create mode 100644 gomspace/libutil/src/linux/drivers/sys/memory.c create mode 100644 gomspace/libutil/src/linux/function.c create mode 100644 gomspace/libutil/src/linux/mutex.c create mode 100644 gomspace/libutil/src/linux/queue.c create mode 100644 gomspace/libutil/src/linux/rtc.c create mode 100644 gomspace/libutil/src/linux/sem.c create mode 100644 gomspace/libutil/src/linux/signal.c create mode 100644 gomspace/libutil/src/linux/stdio.c create mode 100644 gomspace/libutil/src/linux/sysfs_helper.c create mode 100644 gomspace/libutil/src/linux/thread.c create mode 100644 gomspace/libutil/src/linux/time.c create mode 100644 gomspace/libutil/src/lock.c create mode 100644 gomspace/libutil/src/lock.h create mode 100644 gomspace/libutil/src/log/appender/console.c create mode 100644 gomspace/libutil/src/log/appender/simple_file.c create mode 100644 gomspace/libutil/src/log/commands.c create mode 100644 gomspace/libutil/src/log/local.h create mode 100644 gomspace/libutil/src/log/log.c create mode 100644 gomspace/libutil/src/rtc.c create mode 100644 gomspace/libutil/src/stdio.c create mode 100644 gomspace/libutil/src/string.c create mode 100644 gomspace/libutil/src/strtoint.c create mode 100644 gomspace/libutil/src/test/cmocka.c create mode 100644 gomspace/libutil/src/test/command.c create mode 100644 gomspace/libutil/src/test/log.c create mode 100644 gomspace/libutil/src/time.c create mode 100644 gomspace/libutil/src/timestamp.c create mode 100644 gomspace/libutil/src/vmem/commands.c create mode 100644 gomspace/libutil/src/vmem/vmem.c create mode 100644 gomspace/libutil/src/watchdog/local.h create mode 100644 gomspace/libutil/src/watchdog/monitor_task.c create mode 100644 gomspace/libutil/src/watchdog/watchdog.c create mode 100644 gomspace/libutil/src/zip/cppcheck-suppress.txt create mode 100644 gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES create mode 100644 gomspace/libutil/src/zip/miniz/miniz.c create mode 100644 gomspace/libutil/src/zip/miniz/miniz.h create mode 100644 gomspace/libutil/src/zip/zip.c create mode 100644 gomspace/libutil/wscript create mode 100644 mission/devices/P60DockHandler.cpp create mode 100644 mission/devices/P60DockHandler.h create mode 100644 test/testtasks/P60DockTestTask.cpp create mode 100644 test/testtasks/P60DockTestTask.h diff --git a/Makefile b/Makefile index df94de6f..80419a88 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ MISSION_PATH = mission CONFIG_PATH = config TEST_PATH = test UNITTEST_PATH = unittest +GOMSPACE_PATH = gomspace # Board specific paths BSP_PATH = $(BOARD_FILE_ROOT) @@ -109,7 +110,7 @@ INCLUDES := # Directories where $(directoryname).mk files should be included from SUBDIRS := $(FRAMEWORK_PATH) $(TEST_PATH) $(BSP_PATH) $(UNITTEST_PATH)\ - $(CONFIG_PATH) $(MISSION_PATH) + $(CONFIG_PATH) $(MISSION_PATH) $(GOMSPACE_PATH) # INCLUDES += framework/test/catch2 # ETL library include. diff --git a/config/objects/systemObjectList.h b/config/objects/systemObjectList.h index 3b5717fb..a77b8a7b 100644 --- a/config/objects/systemObjectList.h +++ b/config/objects/systemObjectList.h @@ -29,7 +29,8 @@ namespace objects { DUMMY_HANDLER = 0x4400AFFE, /* 0x49 ('I') for Communication Interfaces **/ - ARDUINO_COM_IF = 0x49000001 + ARDUINO_COM_IF = 0x49000001, + P60DOCK_TEST_TASK = 0x00005060 }; } diff --git a/gomspace/gomspace.mk b/gomspace/gomspace.mk new file mode 100644 index 00000000..d36afcd7 --- /dev/null +++ b/gomspace/gomspace.mk @@ -0,0 +1,10 @@ +CSRC += $(wildcard $(CURRENTPATH)/libgscsp/lib/libcsp/src/*.c) +CSRC += $(wildcard $(CURRENTPATH)/libgscsp/src/drivers/can/*.c) + +INCLUDES += $(CURRENTPATH)/libgscsp/include +INCLUDES += $(CURRENTPATH)/libgscsp/lib/libcsp/include/csp/interfaces +INCLUDES += $(CURRENTPATH)/libgscsp/lib/libcsp/include +INCLUDES += $(CURRENTPATH)/libgscsp/lib/libcsp/include/csp +INCLUDES += $(CURRENTPATH)/libutil/include +INCLUDES += $(CURRENTPATH)/libutil/include/gs/util +INCLUDES += $(CURRENTPATH)/lib/libcsp/include \ No newline at end of file diff --git a/gomspace/libgscsp/include/gs/csp/address.h b/gomspace/libgscsp/include/gs/csp/address.h new file mode 100644 index 00000000..9d6e701c --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/address.h @@ -0,0 +1,65 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_ADDRESS_H +#define LIBGSCSP_INCLUDE_GS_CSP_ADDRESS_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Default CSP addresses for nodes in the satellite - often changed for each project. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Default address for OBC (On Board Computer). + Example: a3200-sdk. +*/ +#define GS_CSP_ADDR_OBC 1 +/** + Power supply. + Example: nano-power. +*/ +#define GS_CSP_ADDR_EPS 2 +/** + Payload address. +*/ +#define GS_CSP_ADDR_PAYLOAD_3 3 +/** + Default address for ADCS. + Example: a3200-adcs. +*/ +#define GS_CSP_ADDR_ADCS 4 +/** + Default address for radio. + Example: nanocom-ax. +*/ +#define GS_CSP_ADDR_NANOCOM 5 +/** + Payload address. +*/ +#define GS_CSP_ADDR_PAYLOAD_6 6 +/** + Battery pack. + Example: nano-power-bpx. +*/ +#define GS_CSP_ADDR_BPX 7 +/** + Payload address. +*/ +#define GS_CSP_ADDR_PAYLOAD_8 8 +/** + Reaction wheels. + Example: gsw-600. +*/ +#define GS_CSP_ADDR_GSW600 9 +/** + Antenna module. + Example: ant2150. +*/ +#define GS_CSP_ADDR_ANT2150 10 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/command.h b/gomspace/libgscsp/include/gs/csp/command.h new file mode 100644 index 00000000..79d518db --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/command.h @@ -0,0 +1,25 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_COMMAND_H +#define LIBGSCSP_INCLUDE_GS_CSP_COMMAND_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + CSP commands. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Register CSP commands. + @return_gs_error_t +*/ +gs_error_t gs_csp_register_commands(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/conn.h b/gomspace/libgscsp/include/gs/csp/conn.h new file mode 100644 index 00000000..c8bd755e --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/conn.h @@ -0,0 +1,26 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_CONN_H +#define LIBGSCSP_INCLUDE_GS_CSP_CONN_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Extensions to standard libcsp connection interface. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Return number of open connections. + + @return number of open connections. +*/ +size_t gs_csp_conn_get_open(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/csp.h b/gomspace/libgscsp/include/gs/csp/csp.h new file mode 100644 index 00000000..6268bced --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/csp.h @@ -0,0 +1,202 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_CSP_H +#define LIBGSCSP_INCLUDE_GS_CSP_CSP_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Extensions to standard libcsp. +*/ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Default CSP timeout (mS). + + Default timeout value for communicating with a satellite, based on round-trip time of approximately 500 mS. +*/ +#define GS_CSP_TIMEOUT 3000 + +/** + Check if address is a valid CSP adddress. + @param[in] address CSP address to verify + @return \a true if address is valid. +*/ +bool gs_csp_is_address_valid(uint8_t address); + +/** + gscsp and csp configuration. +*/ +typedef struct { + /** + Forward CSP logs to GomSpace log (libutil). + */ + bool use_gs_log; + + /** + Use command line options. + Configure interfaces specified on the command line. + @note Only supported on Linux - ignored on platforms without command line options. + */ + bool use_command_line_options; + + /** + Size of a CSP buffer (in bytes). + @see csp_buffer_init(). + */ + size_t csp_buffer_size; + /** + Number of CSP buffers to allocate. + @see csp_buffer_init(). + */ + size_t csp_buffers; + + /** + CSP address of the system + */ + uint8_t address; + /** + Host name, returned by the #CSP_CMP_IDENT request. + @note String must remain valid as long as the application is running. + */ + const char *hostname; + /** + Model, returned by the #CSP_CMP_IDENT request. + @note String must remain valid as long as the application is running. + */ + const char *model; + /** + Revision, returned by the #CSP_CMP_IDENT request + @note String must remain valid as long as the application is running. + */ + const char *revision; + +} gs_csp_conf_t; + +/** + Get default CSP configuration for server systems. + @param[in] conf user supplied configuration struct. +*/ +void gs_csp_conf_get_defaults_server(gs_csp_conf_t * conf); + +/** + Get default CSP configuration for embedded systems. + @param[in] conf user supplied configuration struct. +*/ +void gs_csp_conf_get_defaults_embedded(gs_csp_conf_t * conf); + +/** + Initialize CSP. + + Wraps initialization of libcsp, by calling following functions + - hooks CSP log system into GomSpace log system. + - initializes CSP buffers by calling csp_buffer_init() + - initializes CSP by calling csp_init() + - configure interfaces specificed on command line + - configure routing table specificed on command line, or default if only one interface is present. + + @param[in] conf configuration. + @return_gs_error_t +*/ +gs_error_t gs_csp_init(const gs_csp_conf_t * conf); + +/** + Perform an entire request/reply transaction, + + Copies both input buffer and reply to output buffer. + Also makes the connection and closes it again + Differ from 'csp_transaction()' by limiting input buffer size when input length is unknown + + @param[in] prio CSP Prio + @param[in] dest CSP Dest + @param[in] port CSP Port + @param[in] timeout timeout in ms + @param[in] tx_buf pointer to outgoing data buffer + @param[in] tx_len length of request to send + @param[out] rx_buf pointer to incoming data buffer + @param[in] rx_max_len length of expected reply (input buffer size) + @param[out] rx_len pointer to length of reply + @param[in] opts connection options. + @return GS_ERROR_OVERFLOW when input length larger than buffer - it still updates rx_buf + @return GS_ERROR_IO when 'csp_send()' or 'csp_read()' fails + @return GS_ERROR_ALLOC when 'csp_get_buffer()' fails + @return_gs_error_t + */ +gs_error_t gs_csp_transaction2(uint8_t prio, + uint8_t dest, + uint8_t port, + uint32_t timeout, + const void * tx_buf, + size_t tx_len, + void * rx_buf, + size_t rx_max_len, + size_t * rx_len, + uint32_t opts); + +/** + Perform an entire request/reply transaction, + + @param[in] prio CSP Prio + @param[in] dest CSP Dest + @param[in] port CSP Port + @param[in] timeout timeout in ms + @param[in] tx_buf pointer to outgoing data buffer + @param[in] tx_len length of request to send + @param[out] rx_buf pointer to incoming data buffer + @param[in] rx_max_len length of expected reply (input buffer size) + @param[out] rx_len pointer to length of reply + @return GS_ERROR_OVERFLOW when input length larger than buffer - it still updates rx_buf + @return GS_ERROR_IO when 'csp_send()' or 'csp_read()' fails + @return GS_ERROR_ALLOC when 'csp_get_buffer()' fails + @return_gs_error_t + @see gs_csp_transaction2() +*/ +static inline gs_error_t gs_csp_transaction(uint8_t prio, + uint8_t dest, + uint8_t port, + uint32_t timeout, + const void * tx_buf, + size_t tx_len, + void * rx_buf, + size_t rx_max_len, + size_t * rx_len) +{ + return gs_csp_transaction2(prio, dest, port, timeout, tx_buf, tx_len, rx_buf, rx_max_len, rx_len, 0); +} + +/** + Use an existing connection to perform a transaction. + + This is only possible if the next packet is on the same port and destination! + Differ from 'csp_transaction_persistent()' by limiting input buffer size when input length is unknown + + @param[in] conn pointer to connection structure + @param[in] timeout timeout in ms + @param[in] tx_buf pointer to outgoing data buffer + @param[in] tx_len length of request to send + @param[out] rx_buf pointer to incoming data buffer + @param[in] rx_max_len length of expected reply (input buffer size) + @param[out] rx_len pointer to length of reply + @return GS_ERROR_OVERFLOW when input length larger than buffer - it still updates rx_buf + @return GS_ERROR_IO when 'csp_send()' or 'csp_read()' fails + @return GS_ERROR_ALLOC when 'csp_get_buffer()' fails + @return_gs_error_t + */ +gs_error_t gs_csp_transaction_persistent(csp_conn_t * conn, + uint32_t timeout, + const void * tx_buf, + size_t tx_len, + void * rx_buf, + size_t rx_max_len, + size_t * rx_len); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/drivers/can/can.h b/gomspace/libgscsp/include/gs/csp/drivers/can/can.h new file mode 100644 index 00000000..0d10c4fc --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/drivers/can/can.h @@ -0,0 +1,54 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_CAN_CAN_H +#define LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_CAN_CAN_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + GomSpace CAN API for CSP. +*/ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Default CAN interface name. +*/ +#define GS_CSP_CAN_DEFAULT_IF_NAME "CAN" + +/** + Initialize CSP for CAN device. + + @param[in] device CAN device + @param[in] csp_addr CSP address. + @param[in] mtu MTU, normally CSP_CAN_MTU. + @param[in] name name of CSP interface, if NULL #GS_CSP_CAN_DEFAULT_IF_NAME will be used. + @param[in] set_default_route if \a true, the device will be set as default route. + @param[out] csp_if the added CSP interface. + @return #GS_ERROR_EXIST if device already exists. + @return_gs_error_t +*/ +gs_error_t gs_csp_can_init2(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, bool set_default_route, csp_iface_t ** csp_if); + +/** + Initialize CSP for CAN device. + + @param[in] device CAN device + @param[in] csp_addr CSP address. + @param[in] mtu MTU, normally CSP_CAN_MTU. + @param[in] name name of CSP interface, if NULL #GS_CSP_CAN_DEFAULT_IF_NAME will be used. + @param[out] csp_if the added CSP interface. + @return #GS_ERROR_EXIST if device already exists. + @return_gs_error_t + @see gs_csp_can_init2() +*/ +gs_error_t gs_csp_can_init(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, csp_iface_t ** csp_if); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h b/gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h new file mode 100644 index 00000000..4b6204f1 --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h @@ -0,0 +1,29 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_I2C_I2C_H +#define LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_I2C_I2C_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + GomSpace I2C API for CSP. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Initialize CSP for I2C device. + @note I2C device must be initialized allready with the same I2C address as the CSP address. + + @param[in] device I2C device. + @param[in] csp_addr CSP address. + @return_gs_error_t +*/ +gs_error_t gs_csp_i2c_init(uint8_t device, uint8_t csp_addr); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h b/gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h new file mode 100644 index 00000000..cb098fce --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h @@ -0,0 +1,30 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_KISS_KISS_H +#define LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_KISS_KISS_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +/** + @file + + GomSpace KISS API for CSP. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Initialize CSP for KISS device. + @note KISS/UART device must be initialized all ready. + + @param[in] device KISS/UART device. + @return_gs_error_t +*/ +gs_error_t gs_csp_kiss_init(uint8_t device); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/error.h b/gomspace/libgscsp/include/gs/csp/error.h new file mode 100644 index 00000000..8de40787 --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/error.h @@ -0,0 +1,28 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_ERROR_H +#define LIBGSCSP_INCLUDE_GS_CSP_ERROR_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Converting CSP error codes to #gs_error_t +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Convert CSP error. + + @param[in] csp_error CSP error + @return GS error code representing the CSP error. +*/ +gs_error_t gs_csp_error(int csp_error); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/linux/command_line.h b/gomspace/libgscsp/include/gs/csp/linux/command_line.h new file mode 100644 index 00000000..e416eda5 --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/linux/command_line.h @@ -0,0 +1,24 @@ +#ifndef GS_CSP_LINUX_COMMAND_LINE_H +#define GS_CSP_LINUX_COMMAND_LINE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Command line support. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Command line options. +*/ +extern const struct argp_child gs_csp_command_line_options; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/log.h b/gomspace/libgscsp/include/gs/csp/log.h new file mode 100644 index 00000000..91360cc0 --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/log.h @@ -0,0 +1,27 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_LOG_H +#define LIBGSCSP_INCLUDE_GS_CSP_LOG_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + CSP log hook. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Hook into CSP log system. + All CSP logs will be logged through Log (libutil). + + @return_gs_error_t +*/ +gs_error_t gs_csp_log_init(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/port.h b/gomspace/libgscsp/include/gs/csp/port.h new file mode 100644 index 00000000..29fa32e4 --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/port.h @@ -0,0 +1,111 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_PORT_H +#define LIBGSCSP_INCLUDE_GS_CSP_PORT_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Port definitions for standard CSP and GomSpace services. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Port definitions for standard CSP and GomSpace services. +*/ +typedef enum { + /** + CSP Management Protocol - standard CSP service. + */ + GS_CSP_CMP = CSP_CMP, // 0 + /** + Ping - standard CSP service. + */ + GS_CSP_PING = CSP_PING, // 1 + /** + Show process status - standard CSP service. + */ + GS_CSP_PS = CSP_PS, // 2 + /** + Show memory free - standard CSP service. + */ + GS_CSP_MEM_FREE = CSP_MEMFREE, // 3 + GS_CSP_MEMFREE = GS_CSP_MEM_FREE, + /** + Reboot/reset request - standard CSP service. + */ + GS_CSP_REBOOT = CSP_REBOOT, // 4 + /** + Show number of free CSP buffers - standard CSP service. + */ + GS_CSP_BUF_FREE = CSP_BUF_FREE, // 5 + /** + Show uptime (time since last reset) - standard CSP service. + */ + GS_CSP_UPTIME = CSP_UPTIME, // 6 + /** + Parameter service (libparam) + */ + GS_CSP_PORT_RPARAM = 7, + /** + File Transfer Service (libftp) + */ + GS_CSP_PORT_FTP = 9, + /** + Remote log service (liblog) + */ + GS_CSP_PORT_RLOG = 11, + /** + Remote GOSH service (librgosh) + */ + GS_CSP_PORT_RGOSH = 12, + /** + AIS command port (libais). + */ + GS_CSP_PORT_AIS = 13, + /** + ADS-B command port (libadsb). + */ + GS_CSP_PORT_ADSB = 14, + + /** + GomSpace Sensor Bus (libgssb). + */ + GS_CSP_PORT_GSSB = 16, + /** + Flight Planner (libfp). + */ + GS_CSP_PORT_FP = 18, + /** + ADCS (libadcs). + */ + GS_CSP_PORT_ADCS = 20, + /** + House Keeping (libhk). + */ + GS_CSP_PORT_HK = 21, + /** + G(omSpace) script service (libgosh) + */ + GS_CSP_PORT_GSCRIPT = 22, + /** + Remote shell (libgosh). + Executes shell commands (linux server only). + Requires CSP_O_RDP. + */ + GS_CSP_PORT_REMOTE_SHELL = 27, + /** + House keeping beacon port (libhk). + Default port for sending beacons from satellite to ground (configurable). + */ + GS_CSP_PORT_HK_BEACON = 30, + +} gs_csp_port_t; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/router.h b/gomspace/libgscsp/include/gs/csp/router.h new file mode 100644 index 00000000..dae8990a --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/router.h @@ -0,0 +1,36 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_ROUTER_H +#define LIBGSCSP_INCLUDE_GS_CSP_ROUTER_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + CSP router task, with support for stopping/terminating router task. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Start CSP router (task/thread). + @param[in] stack_size stack size in bytes, minimum 300 bytes. + @param[in] priority task priority, normally GS_THREAD_PRIORITY_HIGH. + @return_gs_error_t +*/ +gs_error_t gs_csp_router_task_start(size_t stack_size, gs_thread_priority_t priority); + +/** + Stop CSP router task (for testing). + + Signal stop to the router and waits for it to terminate (join). + @note Join is performed, which may hang forever if the router doesn't respond to the stop request. + @return_gs_error_t +*/ +gs_error_t gs_csp_router_task_stop(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/rtable.h b/gomspace/libgscsp/include/gs/csp/rtable.h new file mode 100644 index 00000000..511b7bc2 --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/rtable.h @@ -0,0 +1,31 @@ +#ifndef GS_CSP_RTABLE_H +#define GS_CSP_RTABLE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + CSP routing table support. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Load routing table. + Extension to csp_rtable_load(). + + @param[in] rtable string containing the routing table to set/load. + @param[in] set_default_route if \a true, sets a default route if no routing table specified and only one interface configured. + @param[in] use_command_line_option if \a true (and command line supported), use command line options to configure routing. + @return_gs_error_t +*/ +gs_error_t gs_csp_rtable_load(const char * rtable, bool set_default_route, bool use_command_line_option); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/service_dispatcher.h b/gomspace/libgscsp/include/gs/csp/service_dispatcher.h new file mode 100644 index 00000000..e80ef66d --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/service_dispatcher.h @@ -0,0 +1,124 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_SERVICE_DISPATCHER_H +#define LIBGSCSP_INCLUDE_GS_CSP_SERVICE_DISPATCHER_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + CSP Service Dispatcher. + + The dispatcher is a task/thread, listening on a configured number of ports and forwards the the incoming connection + to a configured CSP service handler. + The dispatcher touches a software watchdog for every handled connection. +*/ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + CSP service dispatcher configuration. +*/ +typedef struct { + /** + Name of dispatcher. + */ + const char * name; + /** + Array of service handlers - index'ed by CSP port number. + */ + const gs_csp_service_handler_t * handler_array; + /** + Array size of \a handler_array. + */ + unsigned int handler_array_size; + /** + Bind to any unbound ports (CSP_ANY). + Only one task/dispatcher can bind to any ports. This can be used to log unexpected incoming connections. + */ + bool bind_any; + /** + Disable watchdog. + The watchdog is created with a fixed timeout of 20 seconds. + */ + bool disable_watchdog; + /** + CSP connection backlog. + If 0 (zero), the backlog is set to 10. + */ + size_t listen_backlog; + /** + Callback after timeout or processsed connection. + The return value is the next timeout in milli seconds. + Return UINT32_MAX to use default timeout. + */ + unsigned int (*callback)(void); + /** + Socket options. + */ + uint32_t socket_options; +} gs_csp_service_dispatcher_conf_t; + +/** + Basic CSP service handlers. + + Can be used to configure handlers for all basic CSP services. +*/ +#define GS_CSP_BASIC_SERVICE_HANDLERS \ + [GS_CSP_CMP] = gs_csp_cmp_service_handler, \ + [GS_CSP_PING] = gs_csp_ping_service_handler, \ + [GS_CSP_PS] = gs_csp_ps_service_handler, \ + [GS_CSP_MEMFREE] = gs_csp_mem_free_service_handler, \ + [GS_CSP_REBOOT] = gs_csp_reboot_service_handler, \ + [GS_CSP_BUF_FREE] = gs_csp_buf_free_service_handler, \ + [GS_CSP_UPTIME] = gs_csp_uptime_service_handler + +/** + Service dispatcher handle. + @see gs_csp_service_dispatcher_create(), gs_csp_service_dispatcher_close() +*/ +typedef struct gs_csp_service_dispatcher * gs_csp_service_dispatcher_t; + +/** + Create service dispatcher (task/thread). + + @param[in] conf configuration - must remain valid as long as the dispatcher is running. + @param[in] stack_size thread stack size. + @param[in] priority thread priority. + @param[out] return_handle created dispatcher - use NULL if not used. + @return_gs_error_t +*/ +gs_error_t gs_csp_service_dispatcher_create(const gs_csp_service_dispatcher_conf_t * conf, + size_t stack_size, + gs_thread_priority_t priority, + gs_csp_service_dispatcher_t * return_handle); + +/** + Wake up service dispatcher. + + This will cause the disapther to wake up (from listing for new connections), and invoke the configured \a callback function, + before listing for new connections. + + @param[in] handle dispatcher. + @return_gs_error_t +*/ +gs_error_t gs_csp_service_dispatcher_wake_up(gs_csp_service_dispatcher_t handle); + +/** + Destroy/close service dispatcher (for testing). + + Signal stop to the dispatcher and waits for it to terminate (join). + + @note Join is performed, which may hang forever if the dispatcher doesn't respond to the stop request. + @param[in] handle dispatcher. + @return_gs_error_t +*/ +gs_error_t gs_csp_service_dispatcher_destroy(gs_csp_service_dispatcher_t handle); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/service_handler.h b/gomspace/libgscsp/include/gs/csp/service_handler.h new file mode 100644 index 00000000..52479129 --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/service_handler.h @@ -0,0 +1,102 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_SERVICE_HANDLER_H +#define LIBGSCSP_INCLUDE_GS_CSP_SERVICE_HANDLER_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + CSP Service handler. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + CSP Service handler. + + It is the handler's responsibility to process all pakcets on the connection and close the connection when done - even if a failure + is returned. + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +typedef gs_error_t (*gs_csp_service_handler_t)(csp_conn_t * conn); + +/** + Service handler for CSP Management Protocol. + + Invokes standard libcsp service handler. + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +gs_error_t gs_csp_cmp_service_handler(csp_conn_t * conn); + +/** + Service handler for ping. + + Invokes standard libcsp service handler. + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +gs_error_t gs_csp_ping_service_handler(csp_conn_t * conn); + +/** + Service handler for getting process list. + + Invokes standard libcsp service handler. + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +gs_error_t gs_csp_ps_service_handler(csp_conn_t * conn); + +/** + Service handler for getting memory free. + + Invokes GomSpace handler, which doesn't use malloc() to determine \a free memory. + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +gs_error_t gs_csp_mem_free_service_handler(csp_conn_t * conn); + + +/** + Service handler for reboot (reset) of node. + + Invokes standard libcsp service handler. + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +gs_error_t gs_csp_reboot_service_handler(csp_conn_t * conn); + +/** + Service handler for getting free CSP buffers. + + Invokes standard libcsp service handler. + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +gs_error_t gs_csp_buf_free_service_handler(csp_conn_t * conn); + +/** + Service handler for getting uptime (in seconds). + + Invokes GomSpace handler (works on Linux). + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +gs_error_t gs_csp_uptime_service_handler(csp_conn_t * conn); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/lib/libcsp/CHANGELOG b/gomspace/libgscsp/lib/libcsp/CHANGELOG new file mode 100644 index 00000000..a4945716 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/CHANGELOG @@ -0,0 +1,113 @@ +libcsp 1.4, 07-05-2015 +---------------------- +- new: General rtable interface with support for STATIC or CIDR format +- new: CIDR (classless interdomain routing) route table format with netmasks +- new: Bridge capability +- new: Added routing table (de)serialization functions for load/save +- new: Automatic packet deduplication using CRC32 (compile time option) +- new: Autogenerated python bindings using ctypesgen +- new: Task-less operation with router invocation from external scheduler function +- api: Refactor route_if_add to csp_iflist_add +- api: Refactor route_set and friends to rtable_set +- api: Refactor csp_fifo_qos to csp_qfifo +- api: Added defined to be backwards compatible with 1.x +- interfaces: Drop packets on LOOP interface not for own address (blackhole) +- interfaces: New ZMQHUB interface (using zeroMQ over TCP) +- other: Increase stack size from 250 to 1100 for csp_can_rx_task +- other: Cleanup in csp_route.c +- other: Show incoming interface name in debug message +- other: Remove newlines from debug calls +- improvement: Reduce debug hook function complexity with valist passing +- fix: csp_sleep_ms did not work + +libcsp 1.3, 07-05-2015 +---------------------- +- new: Split long process lists into multiple packets +- new: Added posix csp_clock.h +- new: cmp clock functions (requires that you provide csp_clock.h implementation) +- new: Added SFP (Small fragmentation protocol) for larger data chunks +- fix: csp_if_fifo example +- fix: NULL char at the end of rps +- doc: Updated mtu documentation +- other: Tested with FreeRTOS 8.0 +- other: Added disable-stlib option to build only object files + +libcsp 1.2, 25-10-2013 +---------------------- +- Feature release +- New: CMP service for peek and poke of memory +- New: CMP interface statistics struct is now packed +- New: Faster O(1) buffer system with reference counting and automatic alignment +- New: Thread safe KISS driver with support for multiple interfaces +- New: CSP interface struct now holds an opaque pointer to driver handle +- New: removed TXBUF from KISS driver entirely to minimize stack usage, added TX lock instead +- New: Pre-calculated CRC table .romem or PROGMEM on __avr__ +- New: Added buffer overflow protection to KISS interface +- New: Allow posting null pointers on conn RX queues +- New: Lower memory usage on AVR8 +- New: csp_route_save and csp_route_load functions +- New: option --disable-verbose to disable filenames and linenumber on debug +- Protocol: KISS uses csp_crc32 instead of it own embedded crc32 +- Improvement: Use buffer clone function to copy promisc packets +- Bugfix: Fix pointer size (32/16bit) in cmp_peek/poke +- Bugfix: Issue with double free in KISS fixed +- Bugfix: Change rdp_send timeout from packet to connection timeout to make sending task block longer +- Bugfix: Fix conn pool leak when using security check and discarding new packets +- Bugfix: Add packet too short check for CRC32 +- Bugfix: Accept CRC32 responses from nodes without CRC support +- Bugfix: Ensure csp_ping works for packets > 256 bytes +- Bugfix: Cleanup printf inside ISR functions +- Bugfix: Do not add forwarded packets to promisc queue twice +- Bugfix: Fix return value bug of csp_buffer_get when out of buffers +- Bugfix: Always post null pointer with lowest priority, not highest +- Bugfix: Add check on debug level before calling do_csp_debug, fixes #35 +- Other: Export csp/arch include files +- Other: Remove the use of bool type from csp_debug +- Other: Moved csp debug functions to csp_debug.h instead of csp.h +- Other: Ensure assignment of id happens using the uint32_t .ext value of the union, quenches warning + +libcsp 1.1, 24-08-2012 +---------------------- +- Feature release +- Defacto stable since Feb 2012 +- New: I2C interface +- New: KISS interface +- New: USART drivers for Linux, Mac and Windows +- New: Windows/MinGW support +- New: MacOSX support +- New: Interface register function +- New: Interface search function +- New: CMP service for remote route updating +- New: CMP service for interface statistics +- Improvement: Better QoS support +- Improvement: Send RDP control messages with high priority +- Improvement: WAF distcheck now works +- Improvement: Automatic endian discovery +- Improvement: Accept packets with CRC32 checksum if compiled without CRC32 support +- Improvement: Do not wake the router task if RDP is not enabled +- Improvement: Save 102 bytes of RAM by packing route entries +- Cleanup: Simplify CAN configuration +- Cleanup: Move architecture specific code to src/arch +- Bugfix: CSP_MEMFREE gives wrong answer on freertos AVR due to truncation +- Bugfix: Fixed wrong 64-bit size_t in csp_service_handler +- Bugfix: Fixed problem in csp_if_kiss when out of buffers +- Bigfix: Handle bus-off CAN IRQ for AT90CAN128 + +libcsp 1.0.1, 30-10-2011 +------------------------ +- Hotfix release +- Bugfix: missing extern in csp_if_lo.h + +libcsp 1.0, 24-10-2011 +---------------------- +- First official release +- New: CSP 32-bit header 1.0 +- Features: Network Router with promiscous mode, broadcast and QoS +- Features: Connection-oriented transport protocol w. flow-control +- Features: Connection-less "UDP" like transport +- Features: Encryption, Authentication and message check +- Features: Loopback interface +- Features: Python Bindings +- Features: CAN interface w. drivers for several chips +- Features: CSP-services (ping, reboot, uptime, memfree, buffree, ident) + diff --git a/gomspace/libgscsp/lib/libcsp/CONTRIBUTORS b/gomspace/libgscsp/lib/libcsp/CONTRIBUTORS new file mode 100644 index 00000000..97240f60 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/CONTRIBUTORS @@ -0,0 +1,3 @@ +Jeppe Ledet-Pedersen +Johan De Claville Christiansen +Dan Erik Holmstrøm diff --git a/gomspace/libgscsp/lib/libcsp/COPYING b/gomspace/libgscsp/lib/libcsp/COPYING new file mode 100644 index 00000000..54c619ad --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/COPYING @@ -0,0 +1,503 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/gomspace/libgscsp/lib/libcsp/INSTALL.rst b/gomspace/libgscsp/lib/libcsp/INSTALL.rst new file mode 100644 index 00000000..e68a46ed --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/INSTALL.rst @@ -0,0 +1,30 @@ +How to install LibCSP +===================== + +CSP uses the `waf` build system (http://code.google.com/p/waf/). In order to +compile CSP, you first need to configure the toolchain, what operating system +to compile for, the location of required libraries and whether to enable +certain optional features. + +To configure CSP to build with the AVR32 toolchain for FreeRTOS and output +the compiled libcsp.a and header files to the install directory, issue: + +.. code-block:: bash + + ./waf configure --toolchain=avr32- --with-os=freertos --prefix=install + +When compiling for FreeRTOS, the path to the FreeRTOS header files must be +specified with `--with-freertos=PATH.` + +A number of optional features can be enabled by from the configure script. +Support for XTEA encryption can e.g. be enabled with `--enable-xtea`. Run +`./waf configure --help` to list the available configure options. + +The CAN drivers can be enabled by appending the configure option `--with-driver-can=CHIP`, +where CHIP is one of 'socketcan', 'at91sam7a1', 'at91sam7a3' or 'at90can128'. + +To build and copy the library to the location specified with --prefix, use: + +.. code-block:: bash + + ./waf build install diff --git a/gomspace/libgscsp/lib/libcsp/README.rst b/gomspace/libgscsp/lib/libcsp/README.rst new file mode 100644 index 00000000..c8aff3d8 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/README.rst @@ -0,0 +1,41 @@ +The Cubesat Space Protocol +========================== + +Cubesat Space Protocol (CSP) is a small protocol stack written in C. CSP is designed to ease communication between distributed embedded systems in smaller networks, such as Cubesats. The design follows the TCP/IP model and includes a transport protocol, a routing protocol and several MAC-layer interfaces. The core of libcsp includes a router, a socket buffer pool and a connection oriented socket API. + +The protocol is based on a 32-bit header containing both transport and network-layer information. Its implementation is designed for, but not limited to, embedded systems such as the 8-bit AVR microprocessor and the 32-bit ARM and AVR from Atmel. The implementation is written in GNU C and is currently ported to run on FreeRTOS or POSIX operating systems such as Linux. + +The idea is to give sub-system developers of cubesats the same features of a TCP/IP stack, but without adding the huge overhead of the IP header. The small footprint and simple implementation allows a small 8-bit system with less than 4 kB of RAM to be fully connected on the network. This allows all subsystems to provide their services on the same network level, without any master node required. Using a service oriented architecture has several advantages compared to the traditional mater/slave topology used on many cubesats. + + * Standardised network protocol: All subsystems can communicate with eachother + * Service loose coupling: Services maintain a relationship that minimizes dependencies between subsystems + * Service abstraction: Beyond descriptions in the service contract, services hide logic from the outside world + * Service reusability: Logic is divided into services with the intention of promoting reuse. + * Service autonomy: Services have control over the logic they encapsulate. + * Service Redundancy: Easily add redundant services to the bus + * Reduces single point of failure: The complexity is moved from a single master node to several well defines services on the network + +The implementation of LibCSP is written with simplicity in mind, but it's compile time configuration allows it to have some rather advanced features as well: + +Features +-------- + + * Thread safe Socket API + * Router task with Quality of Services + * Connection-oriented operation (RFC 908 and 1151). + * Connection-less operation (similar to UDP) + * ICMP-like requests such as ping and buffer status. + * Loopback interface + * Very Small Footprint 48 kB code and less that 1kB ram required on ARM + * Zero-copy buffer and queue system + * Modular network interface system + * Modular OS interface, ported to FreeRTOS, windows (cygwin) and Linux + * Broadcast traffic + * Promiscuous mode + * Encrypted packets with XTEA in CTR mode + * Truncated HMAC-SHA1 Authentication (RFC 2104) + +LGPL Software license +--------------------- +The source code is available under an LGPL 2.1 license. See COPYING for the license text. + diff --git a/gomspace/libgscsp/lib/libcsp/bindings/python/libcsp/__init__.py b/gomspace/libgscsp/lib/libcsp/bindings/python/libcsp/__init__.py new file mode 100644 index 00000000..39de36b5 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/bindings/python/libcsp/__init__.py @@ -0,0 +1,6 @@ +import sys + +if sys.version_info >= (3, 0): + from libcsp_py3 import * +else: + from libcsp_py2 import * diff --git a/gomspace/libgscsp/lib/libcsp/doc/example.rst b/gomspace/libgscsp/lib/libcsp/doc/example.rst new file mode 100644 index 00000000..b82a055e --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/example.rst @@ -0,0 +1,123 @@ +Client and server example +========================= + +The following examples show the initialization of the protocol stack and examples of client/server code. + +Initialization Sequence +----------------------- + +This code initializes the CSP buffer system, device drivers and router core. The example uses the CAN interface function csp_can_tx but the initialization is similar for other interfaces. The loopback interface does not require any explicit initialization. + +.. code-block:: c + + #include + #include + + /* CAN configuration struct for SocketCAN interface "can0" */ + struct csp_can_config can_conf = {.ifc = "can0"}; + + /* Init buffer system with 10 packets of maximum 320 bytes each */ + csp_buffer_init(10, 320); + + /* Init CSP with address 1 */ + csp_init(1); + + /* Init the CAN interface with hardware filtering */ + csp_can_init(CSP_CAN_MASKED, &can_conf) + + /* Setup default route to CAN interface */ + csp_route_set(CSP_DEFAULT_ROUTE, &csp_can_tx, CSP_HOST_MAC); + + /* Start router task with 500 word stack, OS task priority 1 */ + csp_route_start_task(500, 1); + +Server +------ + +This example shows how to create a server task that listens for incoming connections. CSP should be initialized before starting this task. Note the use of `csp_service_handler()` as the default branch in the port switch case. The service handler will automatically reply to ICMP-like requests, such as pings and buffer status requests. + +.. code-block:: c + + void csp_task(void *parameters) { + /* Create socket without any socket options */ + csp_socket_t *sock = csp_socket(CSP_SO_NONE); + + /* Bind all ports to socket */ + csp_bind(sock, CSP_ANY); + + /* Create 10 connections backlog queue */ + csp_listen(sock, 10); + + /* Pointer to current connection and packet */ + csp_conn_t *conn; + csp_packet_t *packet; + + /* Process incoming connections */ + while (1) { + /* Wait for connection, 10000 ms timeout */ + if ((conn = csp_accept(sock, 10000)) == NULL) + continue; + + /* Read packets. Timout is 1000 ms */ + while ((packet = csp_read(conn, 1000)) != NULL) { + switch (csp_conn_dport(conn)) { + case MY_PORT: + /* Process packet here */ + default: + /* Let the service handler reply pings, buffer use, etc. */ + csp_service_handler(conn, packet); + break; + } + } + + /* Close current connection, and handle next */ + csp_close(conn); + } + } + +Client +------ + +This example shows how to allocate a packet buffer, connect to another host and send the packet. CSP should be initialized before calling this function. RDP, XTEA, HMAC and CRC checksums can be enabled per connection, by setting the connection option to a bitwise OR of any combination of `CSP_O_RDP`, `CSP_O_XTEA`, `CSP_O_HMAC` and `CSP_O_CRC`. + +.. code-block:: c + + int send_packet(void) { + + /* Get packet buffer for data */ + csp_packet_t *packet = csp_buffer_get(data_size); + if (packet == NULL) { + /* Could not get buffer element */ + printf("Failed to get buffer element\\n"); + return -1; + } + + /* Connect to host HOST, port PORT with regular UDP-like protocol and 1000 ms timeout */ + csp_conn_t *conn = csp_connect(CSP_PRIO_NORM, HOST, PORT, 1000, CSP_O_NONE); + if (conn == NULL) { + /* Connect failed */ + printf("Connection failed\\n"); + /* Remember to free packet buffer */ + csp_buffer_free(packet); + return -1; + } + + /* Copy message to packet */ + char *msg = "HELLO"; + strcpy(packet->data, msg); + + /* Set packet length */ + packet->length = strlen(msg); + + /* Send packet */ + if (!csp_send(conn, packet, 1000)) { + /* Send failed */ + printf("Send failed\\n"); + csp_buffer_free(packet); + } + + /* Close connection */ + csp_close(conn); + + return 0 + } diff --git a/gomspace/libgscsp/lib/libcsp/doc/history.rst b/gomspace/libgscsp/lib/libcsp/doc/history.rst new file mode 100644 index 00000000..ad064873 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/history.rst @@ -0,0 +1,17 @@ +History +======= + +The idea was developed by a group of students from Aalborg University in 2008. In 2009 the main developer started working for GomSpace, and CSP became integrated into the GomSpace products. The protocol is based on a 32-bit header containing both transport, network and MAC-layer information. It's implementation is designed for, but not limited to, embedded systems such as the 8-bit AVR microprocessor and the 32-bit ARM and AVR from Atmel. The implementation is written in C and is currently ported to run on FreeRTOS and POSIX and pthreads based operating systems like Linux and BSD. The three letter acronym CSP was originally an abbreviation for CAN Space Protocol because the first MAC-layer driver was written for CAN-bus. Now the physical layer has extended to include spacelink, I2C and RS232, the name was therefore extended to the more general CubeSat Space Protocol without changing the abbreviation. + +Satellites using CSP +-------------------- + +This is the known list of satellites or organisations that uses CSP. + + * GomSpace GATOSS GOMX-1 + * AAUSAT-3 + * EgyCubeSat + * EuroLuna + * NUTS + * Hawaiian Space Flight Laboratory + * GomSpace GOMX-3 diff --git a/gomspace/libgscsp/lib/libcsp/doc/interfaces.rst b/gomspace/libgscsp/lib/libcsp/doc/interfaces.rst new file mode 100644 index 00000000..5a80325c --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/interfaces.rst @@ -0,0 +1,95 @@ +CSP Interfaces +============== + +This is an example of how to implement a new layer-2 interface in CSP. The example is going to show how to create a `csp_if_fifo`, using a set of [named pipes](http://en.wikipedia.org/wiki/Named_pipe). The complete interface example code can be found in `examples/fifo.c`. For an example of a fragmenting interface, see the CAN interface in `src/interfaces/csp_if_can.c`. + +CSP interfaces are declared in a `csp_iface_t` structure, which sets the interface nexthop function and name. A maximum transmission unit can also be set, which forces CSP to drop outgoing packets above a certain size. The fifo interface is defined as: + +.. code-block:: c + + #include + #include + + csp_iface_t csp_if_fifo = { + .name = "fifo", + .nexthop = csp_fifo_tx, + .mtu = BUF_SIZE, + }; + +Outgoing traffic +---------------- + +The nexthop function takes a pointer to a CSP packet and a timeout as parameters. All outgoing packets that are routed to the interface are passed to this function: + +.. code-block:: c + + int csp_fifo_tx(csp_packet_t *packet, uint32_t timeout) { + write(tx_channel, &packet->length, packet->length + sizeof(uint32_t) + sizeof(uint16_t)); + csp_buffer_free(packet); + return 1; + } + +In the fifo interface, we simply transmit the header, length field and data using a write to the fifo. CSP does not dictate the wire format, so other interfaces may decide to e.g. ignore the length field if the physical layer provides start/stop flags. + +_Important notice: If the transmission succeeds, the interface must free the packet and return 1. If transmission fails, the nexthop function should return 0 and not free the packet, to allow retransmissions by the caller._ + +Incoming traffic +---------------- + +The interface also needs to receive incoming packets and pass it to the CSP protocol stack. In the fifo interface, this is handled by a thread that blocks on the incoming fifo and waits for packets: + +.. code-block:: c + + void * fifo_rx(void * parameters) { + csp_packet_t *buf = csp_buffer_get(BUF_SIZE); + /* Wait for packet on fifo */ + while (read(rx_channel, &buf->length, BUF_SIZE) > 0) { + csp_qfifo_write(buf, &csp_if_fifo, NULL); + buf = csp_buffer_get(BUF_SIZE); + } + } + +A new CSP buffer is preallocated with csp_buffer_get(). When data is received, the packet is passed to CSP using `csp_qfifo_write()` and a new buffer is allocated for the next packet. In addition to the received packet, `csp_qfifo_write()` takes two additional arguments: + +.. code-block:: c + + void csp_qfifo_write(csp_packet_t *packet, csp_iface_t *interface, CSP_BASE_TYPE *pxTaskWoken); + +The calling interface must be passed in `interface` to avoid routing loops. Furthermore, `pxTaskWoken` must be set to a non-NULL value if the packet is received in an interrupt service routine. If the packet is received in task context, NULL must be passed. 'pxTaskWoken' only applies to FreeRTOS systems, and POSIX system should always set the value to NULL. + +`csp_qfifo_write` will either accept the packet or free the packet buffer, so the interface must never free the packet after passing it to CSP. + +Initialization +-------------- + +In order to initialize the interface, and make it available to the router, use the following function found in `csp/csp_interface.h`: + +.. code-block:: c + + csp_route_add_if(&csp_if_fifo); + +This actually happens automatically if you try to call `csp_route_add()` with an interface that is unknown to the router. This may however be removed in the future, in order to ensure that all interfaces are initialised before configuring the routing table. The reason is, that some products released in the future may ship with an empty routing table, which is then configured by a routing protocol rather than a static configuration. + +In order to setup a manual static route, use the following example where the default route is set to the fifo interface: + +.. code-block:: c + + csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_fifo, CSP_NODE_MAC); + +All outgoing traffic except loopback, is now passed to the fifo interface's nexthop function. + +Building the example +-------------------- + +The fifo examples can be compiled with: + +.. code-block:: bash + + % gcc csp_if_fifo.c -o csp_if_fifo -I/include -L/build -lcsp -lpthread -lrt + +The two named pipes are created with: + +.. code-block:: bash + + % mkfifo server_to_client client_to_server + diff --git a/gomspace/libgscsp/lib/libcsp/doc/libcsp.rst b/gomspace/libgscsp/lib/libcsp/doc/libcsp.rst new file mode 100644 index 00000000..f866015f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/libcsp.rst @@ -0,0 +1,21 @@ +.. CSP Documentation master file. + +.. _libcsp: + +********************** +CubeSat Space Protocol +********************** + +.. toctree:: + :maxdepth: 3 + + ../README + history + structure + interfaces + memory + protocolstack + topology + mtu + example + diff --git a/gomspace/libgscsp/lib/libcsp/doc/memory.rst b/gomspace/libgscsp/lib/libcsp/doc/memory.rst new file mode 100644 index 00000000..4e38d711 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/memory.rst @@ -0,0 +1,28 @@ +How CSP uses memory +=================== + +CSP has been written for small microprocessor systems. The way memory is handled is therefore a tradeoff between the amount used and the code efficiency. This section tries to give some answers to what the memory is used for and how it it used. The primary memory blocks in use by CSP is: + + * Routing table + * Ports table + * Connection table + * Buffer pool + * Interface list + +Tables +------ +The reason for using tables for the routes, ports and connections is speed. When a new packet arrives the core of CSP needs to do a quick lookup in the connection so see if it can find an existing connection to which the packet matches. If this is not found, it will take a lookup in the ports table to see if there are any applications listening on the incoming port number. Another argument of using tables are pre-allocation. The linker will reserve an area of the memory for which the routes and connections can be stored. This avoid an expensive `malloc()` call during initialization of CSP, and practically costs zero CPU instructions. The downside of using tables are the wasted memory used by unallocated ports and connections. For the routing table the argumentation is the same, pre-allocation is better than calling `malloc()`. + +Buffer Pool +----------- + +The buffer handling system can be compiled for either static allocation or a one-time dynamic allocation of the main memory block. After this, the buffer system is entirely self-contained. All allocated elements are of the same size, so the buffer size must be chosen to be able to handle the maximum possible packet length. The buffer pool uses a queue to store pointers to free buffer elements. First of all, this gives a very quick method to get the next free element since the dequeue is an O(1) operation. Furthermore, since the queue is a protected operating system primitive, it can be accessed from both task-context and interrupt-context. The `csp_buffer_get` version is for task-context and `csp_buffer_get_isr` is for interrupt-context. Using fixed size buffer elements that are preallocated is again a question of speed and safety. + + +A basic concept of the buffer system is called Zero-Copy. This means that from userspace to the kernel-driver, the buffer is never copied from one buffer to another. This is a big deal for a small microprocessor, where a call to `memcpy()` can be very expensive. In practice when data is inserted into a packet, it is shifted a certain number of bytes in order to allow for a packet header to be prepended at the lower layers. This also means that there is a strict contract between the layers, which data can be modified and where. The buffer object is normally casted to a `csp_packet_t`, but when its given to an interface on the MAC layer it's casted to a `csp_i2c_frame_t` for example. + +Interface list +-------------- + +The interface list is a simple single-ended linked list of references to the interface specification structures. These structures are static const and allocated by the linker. The pointer to this data is inserted into the list one time during setup of the interface. Each entry in the routing table has a direct pointer to the interface element, thereby avoiding list lookup, but the list is needed in order for the dynamic route configuration to know which interfaces are available. + diff --git a/gomspace/libgscsp/lib/libcsp/doc/mtu.rst b/gomspace/libgscsp/lib/libcsp/doc/mtu.rst new file mode 100644 index 00000000..27753300 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/mtu.rst @@ -0,0 +1,19 @@ +Maximum Transfer Unit +===================== + +There are two things limiting the MTU of CSP. + + 1. The pre-allocated buffer pool’s allocation size + 2. The link layer protocol. + +So let’s assume that you have made a protocol called KISS with a MTU of 256. The 256 is the total amount of data that you can put into the CSP-packet. However, you need to take the overhead of the link layer into account. Typically this could consist of a length field and/or a start/stop flag. So the actual frame size on the link layer would for example be 256 bytes of data + 2 bytes sync flag + 2 bytes length field. + +This requires a buffer allocation of at lest 256 + 2 + 2. However, the CSP packet itself has some reserved bytes in the beginning of the packet (which you can see in csp.h) - so the recommended buffer allocation size is MAX MTU + 16 bytes. In this case the max MTU would be 256. + +If you try to pass data which is longer than the MTU, the chance is that you will also make a buffer overflow in the CSP buffer pool. However, lets assume that you have two interfaces one with an MTU of 200 bytes and another with an MTU of 100 bytes. In this case you might successfully transfer 150 bytes over the first interface, but the packet will be rejected once it comes to the second interface. + +If you want to increase your MTU of a specific link layer, it is up to the link layer protocol to implement its own fragmentation protocol. A good example is CAN-bus which only allows a frame size of 8 bytes. libcsp have a small protocol for this called the “CAN fragmentation protocol" or CFP for short. This allows data of much larger size to be transferred over the CAN bus. + +Okay, but what if you want to transfer 1000 bytes, and the network maximum MTU is 256? Well, since CSP does not include streaming sockets, only packet’s. Somebody will have to split that data up into chunks. It might be that you application have special knowledge about the datatype you are transmitting, and that it makes sense to split the 1000 byte content into 10 chunks of 100 byte status messages. This, application layer delimitation might be good if you have a situation with packet loss, because your receiver could still make good usage of the partially delivered chunks. + +But, what if you just want 1000 bytes transmitted, and you don’t care about the fragmentation unit, and also don’t want the hassle of writing the fragmentation code yourself? - In this case, libcsp now features a new (still experimental) feature called SFP (small fragmentation protocol) designed to work on the application layer. For this purpose you will not use csp_send and csp_recv, but csp_sfp_send and csp_sfp_recv. This will split your data into chunks of a certain size, enumerate them and transfer over a given connection. If a chunk is missing the SFP client will abort the reception, because SFP does not provide retransmission. If you wish to also have retransmission and orderly delivery you will have to open an RDP connection and send your SFP message to that connection. diff --git a/gomspace/libgscsp/lib/libcsp/doc/protocolstack.rst b/gomspace/libgscsp/lib/libcsp/doc/protocolstack.rst new file mode 100644 index 00000000..365aabbe --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/protocolstack.rst @@ -0,0 +1,54 @@ +The Protocol Stack +================== + +The CSP protocol stack includes functionality on all layers of the TCP/IP model: + +Layer 1: Drivers +---------------- + +Lib CSP is not designed for any specific processor or hardware peripheral, but yet these drivers are required in order to work. The intention of LibCSP is not to provide CAN, I2C or UART drivers for all platforms, however some drivers has been included for some platforms. If you do not find your platform supported, it is quite simple to add a driver that conforms to the CSP interfaces. For example the I2C driver just requires three functions: `init`, `send` and `recv`. For good stability and performance interrupt driven drivers are preferred in favor of polled drivers. Where applicable also DMA usage is recommended. + +Layer 2: MAC interfaces +----------------------- + +CSP has interfaces for I2C, CAN, RS232 (KISS) and Loopback. The layer 2 protocol software defines a frame-format that is suitable for the media. CSP can be easily extended with implementations for even more links. For example a radio-link and IP-networks. The file `csp_interface.h` declares the rx and tx functions needed in order to define a network interface in CSP. During initialisation of CSP each interface will be inserted into a linked list of interfaces that is available to the router. In cases where link-layer addresses are required, such as I2C, the routing table supports specifying next-hop link-layer address directly. This avoids the need to implement an address resolution protocol to translate CSP addresses to I2C addresses. + +Layer 3: Network Router +----------------------- + +The router core is the backbone of the CSP implementation. The router works by looking at a 32-bit CSP header which contains the delivery and source address together with port numbers for the connection. Each router supports both local delivery and forwarding of frames to another destination. Frames will never exit the router on the same interface that they arrives at, this concept is called split horizon, and helps prevent routing loops. + +The main purpose of the router is to accept incoming packets and deliver them to the right message queue. Therefore, in order to listen on a port-number on the network, a task must create a socket and call the accept() call. This will make the task block and wait for incoming traffic, just like a web-server or similar. When an incoming connection is opened, the task is woken. Depending on the task-priority, the task can even preempt another task and start execution immediately. + +There is no routing protocol for automatic route discovery, all routing tables are pre-programmed into the subsystems. The table itself contains a separate route to each of the possible 32 nodes in the network and the additional default route. This means that the overall topology must be decided before putting sub-systems together, as explained in the `topology.md` file. However CSP has an extension on port zero CMP (CSP management protocol), which allows for over-the-network routing table configuration. This has the advantage that default routes could be changed if for example the primary radio fails, and the secondary should be used instead. + +Layer 4: Transport Layer +------------------------ + +LibCSP implements two different Transport Layer protocols, they are called UDP (unreliable datagram protocol) and RDP (reliable datagram protocol). The name UDP has not been chosen to be an exact replica of the UDP (user datagram protocol) known from the TCP/IP model, but they have certain similarities. + +The most important thing to notice is that CSP is entirely a datagram service. There is no stream based service like TCP. A datagram is defined a block of data with a specified size and structure. This block enters the transport layer as a single datagram and exits the transport layer in the other end as a single datagram. CSP preserves this structure all the way to the physical layer for I2C, KISS and Loopback interfaces are used. The CAN-bus interface has to fragment the datagram into CAN-frames of 8 bytes, however only a fully completed datagram will arrive at the receiver. + +UDP +^^^ + +UDP uses a simple transmission model without implicit hand-shaking dialogues for guaranteeing reliability, ordering, or data integrity. Thus, UDP provides an unreliable service and datagrams may arrive out of order, appear duplicated, or go missing without notice. UDP assumes that error checking and correction is either not necessary or performed in the application, avoiding the overhead of such processing at the network interface level. Time-sensitive applications often use UDP because dropping packets is preferable to waiting for delayed packets, which may not be an option in a real-time system. + +UDP is very practical to implement request/reply based communication where a single packet forms the request and a single packet forms the reply. In this case a typical request and wait protocol is used between the client and server, which will simply return an error if a reply is not received within a specified time limit. An error would normally lead to a retransmission of the request from the user or operator which sent the request. + +While UDP is very simple, it also has some limitations. Normally a human in the loop is a good thing when operating the satellite over UDP. But when it comes to larger file transfers, the human becomes the bottleneck. When a high-speed file transfer is initiated data acknowledgment should be done automatically in order to speed up the transfer. This is where the RDP protocol can help. + +RDP +^^^ +CSP provides a transport layer extension called RDP (reliable datagram protocol) which is an implementation of RFC908 and RFC1151. RDP provides a few additional features: + + * Three-way handshake + * Flow Control + * Data-buffering + * Packet re-ordering + * Retransmission + * Windowing + * Extended Acknowledgment + +For more information on this, please refer to RFC908. + diff --git a/gomspace/libgscsp/lib/libcsp/doc/structure.rst b/gomspace/libgscsp/lib/libcsp/doc/structure.rst new file mode 100644 index 00000000..4c9b515c --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/structure.rst @@ -0,0 +1,27 @@ +Structure +========= +The Cubesat Space Protocol library is structured as shown in the following table: + +============================= ========================================================================= +**Folder** **Description** +============================= ========================================================================= +libcsp/include/csp Main include files +libcsp/include/csp/arch Architecture include files +libcsp/include/csp/interfaces Interface include files +libcsp/include/csp/drivers Drivers include files +libcsp/src Main modules for CSP: io, router, connections, services +libcsp/src/interfaces Interface modules for CAN, I2C, KISS, LOOP and ZMQHUB +libcsp/src/drivers/can Driver for CAN +libcsp/src/drivers/usart Driver for USART +libcsp/src/arch/freertos FreeRTOS architecture module +libcsp/src/arch/macosx Mac OS X architecture module +libcsp/src/arch/posix Posix architecture module +libcsp/src/arch/windows Windows architecture module +libcsp/src/rtable Routing table module +libcsp/transport Transport module, UDP and RDP +libcsp/crypto Crypto module +libcsp/utils Utilities +libcsp/bindings/python Python wrapper for libcsp +libcsp/examples CSP examples (source code) +libasf/doc The doc folder contains the source code for this documentation +============================= ========================================================================= diff --git a/gomspace/libgscsp/lib/libcsp/doc/topology.rst b/gomspace/libgscsp/lib/libcsp/doc/topology.rst new file mode 100644 index 00000000..e629c29e --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/topology.rst @@ -0,0 +1,26 @@ +Network Topology +================ + +CSP uses a network oriented terminology similar to what is known from the Internet and the TCP/IP model. A CSP network can be configured for several different topologies. The most common topology is to create two segments, one for the Satellite and one for the Ground-Station. + +.. code-block:: none + + I2C BUS + _______________________________ + / | | | \ + +---+ +---+ +---+ +---+ +---+ + |OBC| |COM| |EPS| |PL1| |PL2| Nodes 0 - 7 (Space segment) + +---+ +---+ +---+ +---+ +---+ + ^ + | Radio + v + +---+ +----+ + |TNC| ------- | PC | Nodes 8 - 15 (Ground segment) + +---+ USB +----+ + + Node 9 Node 10 + +The address range, from 0 to 15, has been segmented into two equal size segments. This allows for easy routing in the network. All addresses starting with binary 1 is on the ground-segment, and all addresses starting with 0 is on the space segment. From CSP v1.0 the address space has been increased to 32 addresses, 0 to 31. But for legacy purposes, the old 0 to 15 is still used in most products. + +The network is configured using static routes initialised at boot-up of each sub-system. This means that the basic routing table must be assigned compile-time of each subsystem. However each node supports assigning an individual route to every single node in the network and can be changed run-time. This means that the network topology can be easily reconfigured after startup. + diff --git a/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo.c b/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo.c new file mode 100644 index 00000000..136fc3aa --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo.c @@ -0,0 +1,165 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TYPE_SERVER 1 +#define TYPE_CLIENT 2 +#define PORT 10 +#define BUF_SIZE 250 + +pthread_t rx_thread; +int rx_channel, tx_channel; + +int csp_fifo_tx(csp_iface_t *ifc, csp_packet_t *packet, uint32_t timeout); + +csp_iface_t csp_if_fifo = { + .name = "fifo", + .nexthop = csp_fifo_tx, + .mtu = BUF_SIZE, +}; + +int csp_fifo_tx(csp_iface_t *ifc, csp_packet_t *packet, uint32_t timeout) { + /* Write packet to fifo */ + if (write(tx_channel, &packet->length, packet->length + sizeof(uint32_t) + sizeof(uint16_t)) < 0) + printf("Failed to write frame\r\n"); + csp_buffer_free(packet); + return CSP_ERR_NONE; +} + +void * fifo_rx(void * parameters) { + csp_packet_t *buf = csp_buffer_get(BUF_SIZE); + /* Wait for packet on fifo */ + while (read(rx_channel, &buf->length, BUF_SIZE) > 0) { + csp_qfifo_write(buf, &csp_if_fifo, NULL); + buf = csp_buffer_get(BUF_SIZE); + } + + return NULL; +} + +int main(int argc, char **argv) { + + int me, other, type; + const char *message = "Testing CSP"; + const char *rx_channel_name; + const char *tx_channel_name; + csp_socket_t *sock; + csp_conn_t *conn; + csp_packet_t *packet; + + /* Run as either server or client */ + if (argc != 2) { + printf("usage: %s \r\n", argv[0]); + return -1; + } + + /* Set type */ + if (strcmp(argv[1], "server") == 0) { + me = 1; + other = 2; + tx_channel_name = "server_to_client"; + rx_channel_name = "client_to_server"; + type = TYPE_SERVER; + } else if (strcmp(argv[1], "client") == 0) { + me = 2; + other = 1; + tx_channel_name = "client_to_server"; + rx_channel_name = "server_to_client"; + type = TYPE_CLIENT; + } else { + printf("Invalid type. Must be either 'server' or 'client'\r\n"); + return -1; + } + + /* Init CSP and CSP buffer system */ + if (csp_init(me) != CSP_ERR_NONE || csp_buffer_init(10, 300) != CSP_ERR_NONE) { + printf("Failed to init CSP\r\n"); + return -1; + } + + tx_channel = open(tx_channel_name, O_RDWR); + if (tx_channel < 0) { + printf("Failed to open TX channel\r\n"); + return -1; + } + + rx_channel = open(rx_channel_name, O_RDWR); + if (rx_channel < 0) { + printf("Failed to open RX channel\r\n"); + return -1; + } + + /* Start fifo RX task */ + pthread_create(&rx_thread, NULL, fifo_rx, NULL); + + /* Set default route and start router */ + csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_fifo, CSP_NODE_MAC); + csp_route_start_task(0, 0); + + /* Create socket and listen for incoming connections */ + if (type == TYPE_SERVER) { + sock = csp_socket(CSP_SO_NONE); + csp_bind(sock, PORT); + csp_listen(sock, 5); + } + + /* Super loop */ + while (1) { + if (type == TYPE_SERVER) { + /* Process incoming packet */ + conn = csp_accept(sock, 1000); + if (conn) { + packet = csp_read(conn, 0); + if (packet) + printf("Received: %s\r\n", packet->data); + csp_buffer_free(packet); + csp_close(conn); + } + } else { + /* Send a new packet */ + packet = csp_buffer_get(strlen(message)); + if (packet) { + strcpy((char *) packet->data, message); + packet->length = strlen(message); + + conn = csp_connect(CSP_PRIO_NORM, other, PORT, 1000, CSP_O_NONE); + printf("Sending: %s\r\n", message); + if (!conn || !csp_send(conn, packet, 1000)) + return -1; + csp_close(conn); + } + sleep(1); + } + } + + close(rx_channel); + close(tx_channel); + + return 0; +} diff --git a/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo_windows.c b/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo_windows.c new file mode 100644 index 00000000..5b360709 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo_windows.c @@ -0,0 +1,225 @@ +#include +#include +#include +#include +#include +#undef interface + +#include +#include + +#define PIPE_BUFSIZE 1024 + +#define TYPE_SERVER 1 +#define TYPE_CLIENT 2 +#define PORT 10 +#define BUF_SIZE 250 + + +static LPCTSTR pipeName = TEXT("\\\\.\\pipe\\CSP_Pipe"); + +static HANDLE pipe = INVALID_HANDLE_VALUE; + +unsigned WINAPI fifo_rx(void *); +unsigned WINAPI pipe_listener(void *); + +void printError(void); + +int csp_fifo_tx(csp_packet_t *packet, uint32_t timeout); + +csp_iface_t csp_if_fifo = { + .name = "fifo", + .nexthop = csp_fifo_tx, + .mtu = BUF_SIZE, +}; + +int csp_fifo_tx(csp_packet_t *packet, uint32_t timeout) { + printf("csp_fifo_tx tid: %lu\n", GetCurrentThreadId()); + DWORD expectedSent = packet->length + sizeof(uint32_t) + sizeof(uint16_t); + DWORD actualSent; + /* Write packet to fifo */ + if( !WriteFile(pipe, &packet->length, expectedSent, &actualSent, NULL) + || actualSent != expectedSent ) { + printError(); + } + + csp_buffer_free(packet); + return CSP_ERR_NONE; +} + + +int main(int argc, char *argv[]) { + int me, other, type; + char *message = "Testing CSP"; + csp_socket_t *sock = NULL; + csp_conn_t *conn = NULL; + csp_packet_t *packet = NULL; + + /* Run as either server or client */ + if (argc != 2) { + printf("usage: server \r\n"); + return -1; + } + + /* Set type */ + if (strcmp(argv[1], "server") == 0) { + me = 1; + other = 2; + type = TYPE_SERVER; + } else if (strcmp(argv[1], "client") == 0) { + me = 2; + other = 1; + type = TYPE_CLIENT; + } else { + printf("Invalid type. Must be either 'server' or 'client'\r\n"); + return -1; + } + + /* Init CSP and CSP buffer system */ + if (csp_init(me) != CSP_ERR_NONE || csp_buffer_init(10, 300) != CSP_ERR_NONE) { + printf("Failed to init CSP\r\n"); + return -1; + } + + if( type == TYPE_SERVER ) { + _beginthreadex(NULL, 0, pipe_listener, NULL, 0, 0); + } else { + pipe = CreateFile( + pipeName, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + 0, + NULL); + if( pipe == INVALID_HANDLE_VALUE ) { + printError(); + return -1; + } + } + + /* Set default route and start router */ + csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_fifo, CSP_NODE_MAC); + csp_route_start_task(0, 0); + + /* Create socket and listen for incoming connections */ + if (type == TYPE_SERVER) { + sock = csp_socket(CSP_SO_NONE); + csp_bind(sock, PORT); + csp_listen(sock, 5); + } + + /* Super loop */ + while (1) { + if (type == TYPE_SERVER) { + /* Process incoming packet */ + conn = csp_accept(sock, 1000); + if (conn) { + packet = csp_read(conn, 0); + if (packet) + printf("Received: %s\r\n", packet->data); + csp_buffer_free(packet); + csp_close(conn); + } + } else { + /* Send a new packet */ + packet = csp_buffer_get(strlen(message)); + if (packet) { + strcpy((char *) packet->data, message); + packet->length = strlen(message); + + conn = csp_connect(CSP_PRIO_NORM, other, PORT, 1000, CSP_O_NONE); + printf("Sending: %s\r\n", message); + if (!conn || !csp_send(conn, packet, 1000)) + return -1; + csp_close(conn); + Sleep(1000); + } + } + } + + return 0; +} + +void printError(void) { + LPTSTR messageBuffer = NULL; + DWORD errorCode = GetLastError(); + DWORD formatMessageRet; + formatMessageRet = FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + errorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&messageBuffer, + 0, + NULL); + + if( !formatMessageRet ) { + wprintf(L"FormatMessage error, code: %lu\n", GetLastError()); + return; + } + + printf("%s\n", messageBuffer); + LocalFree(messageBuffer); +} + +unsigned WINAPI pipe_listener(void *parameters) { + while(1) { + HANDLE pipe = CreateNamedPipe( + pipeName, + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + PIPE_BUFSIZE, + PIPE_BUFSIZE, + 0, + NULL); + BOOL clientConnected; + if( pipe == INVALID_HANDLE_VALUE ) { + printf("Error creating named pipe. Code %lu\n", GetLastError()); + return -1; + } + + // True if client connects *after* server called ConnectNamedPipe + // or *between* CreateNamedPipe and ConnectNamedPipe + clientConnected = + ConnectNamedPipe(pipe, NULL) ? TRUE : GetLastError()==ERROR_PIPE_CONNECTED; + printf("Client connected!\n"); + + if( !clientConnected ) { + printf("Failure while listening for clients. Code %lu\n", GetLastError()); + CloseHandle(pipe); + return -1; + } + printf("Create client thread\n"); + _beginthreadex(NULL, 0, fifo_rx, (PVOID)pipe, 0, 0); + } + + return 0; +} + +unsigned WINAPI fifo_rx(void *handle) { + printf("fifo_rx tid: %lu\n", GetCurrentThreadId()); + HANDLE pipe = (HANDLE) handle; + csp_packet_t *buf = csp_buffer_get(BUF_SIZE); + DWORD bytesRead; + BOOL readSuccess; + + while(1) { + readSuccess = + ReadFile(pipe, &buf->length, BUF_SIZE, &bytesRead, NULL); + if( !readSuccess || bytesRead == 0 ) { + csp_buffer_free(buf); + printError(); + break; + } + csp_qfifo_write(buf, &csp_if_fifo, NULL); + buf = csp_buffer_get(BUF_SIZE); + } + printf("Closing pipe to client\n"); + CloseHandle(pipe); + + return 0; +} diff --git a/gomspace/libgscsp/lib/libcsp/examples/kiss.c b/gomspace/libgscsp/lib/libcsp/examples/kiss.c new file mode 100644 index 00000000..c95eb2aa --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/kiss.c @@ -0,0 +1,151 @@ +/** + * Build this example on linux with: + * ./waf configure --enable-examples --enable-if-kiss --with-driver-usart=linux --enable-crc32 clean build + */ + +#include +#include +#include + +#include +#include + +#define PORT 10 +#define MY_ADDRESS 1 + +#define SERVER_TIDX 0 +#define CLIENT_TIDX 1 +#define USART_HANDLE 0 + +CSP_DEFINE_TASK(task_server) { + int running = 1; + csp_socket_t *socket = csp_socket(CSP_SO_NONE); + csp_conn_t *conn; + csp_packet_t *packet; + csp_packet_t *response; + + response = csp_buffer_get(sizeof(csp_packet_t) + 2); + if( response == NULL ) { + fprintf(stderr, "Could not allocate memory for response packet!\n"); + return CSP_TASK_RETURN; + } + response->data[0] = 'O'; + response->data[1] = 'K'; + response->length = 2; + + csp_bind(socket, CSP_ANY); + csp_listen(socket, 5); + + printf("Server task started\r\n"); + + while(running) { + if( (conn = csp_accept(socket, 10000)) == NULL ) { + continue; + } + + while( (packet = csp_read(conn, 100)) != NULL ) { + switch( csp_conn_dport(conn) ) { + case PORT: + if( packet->data[0] == 'q' ) + running = 0; + csp_buffer_free(packet); + csp_send(conn, response, 1000); + break; + default: + csp_service_handler(conn, packet); + break; + } + } + + csp_close(conn); + } + + csp_buffer_free(response); + + return CSP_TASK_RETURN; +} + +CSP_DEFINE_TASK(task_client) { + + char outbuf = 'q'; + char inbuf[3] = {0}; + int pingResult; + + for(int i = 50; i <= 200; i+= 50) { + pingResult = csp_ping(MY_ADDRESS, 1000, 100, CSP_O_NONE); + printf("Ping with payload of %d bytes, took %d ms\n", i, pingResult); + csp_sleep_ms(1000); + } + csp_ps(MY_ADDRESS, 1000); + csp_sleep_ms(1000); + csp_memfree(MY_ADDRESS, 1000); + csp_sleep_ms(1000); + csp_buf_free(MY_ADDRESS, 1000); + csp_sleep_ms(1000); + csp_uptime(MY_ADDRESS, 1000); + csp_sleep_ms(1000); + + csp_transaction(0, MY_ADDRESS, PORT, 1000, &outbuf, 1, inbuf, 2); + printf("Quit response from server: %s\n", inbuf); + + return CSP_TASK_RETURN; +} + +int main(int argc, char **argv) { + csp_debug_toggle_level(CSP_PACKET); + csp_debug_toggle_level(CSP_INFO); + + csp_buffer_init(10, 300); + csp_init(MY_ADDRESS); + + struct usart_conf conf; + +#if defined(CSP_WINDOWS) + conf.device = argc != 2 ? "COM4" : argv[1]; + conf.baudrate = CBR_9600; + conf.databits = 8; + conf.paritysetting = NOPARITY; + conf.stopbits = ONESTOPBIT; + conf.checkparity = FALSE; +#elif defined(CSP_POSIX) + conf.device = argc != 2 ? "/dev/ttyUSB0" : argv[1]; + conf.baudrate = 500000; +#elif defined(CSP_MACOSX) + conf.device = argc != 2 ? "/dev/tty.usbserial-FTSM9EGE" : argv[1]; + conf.baudrate = 115200; +#endif + + /* Run USART init */ + usart_init(&conf); + + /* Setup CSP interface */ + static csp_iface_t csp_if_kiss; + static csp_kiss_handle_t csp_kiss_driver; + csp_kiss_init(&csp_if_kiss, &csp_kiss_driver, usart_putc, usart_insert, "KISS"); + + /* Setup callback from USART RX to KISS RS */ + void my_usart_rx(uint8_t * buf, int len, void * pxTaskWoken) { + csp_kiss_rx(&csp_if_kiss, buf, len, pxTaskWoken); + } + usart_set_callback(my_usart_rx); + + csp_route_set(MY_ADDRESS, &csp_if_kiss, CSP_NODE_MAC); + csp_route_start_task(0, 0); + + csp_conn_print_table(); + csp_route_print_table(); + csp_route_print_interfaces(); + + csp_thread_handle_t handle_server; + csp_thread_create(task_server, "SERVER", 1000, NULL, 0, &handle_server); + csp_thread_handle_t handle_client; + csp_thread_create(task_client, "CLIENT", 1000, NULL, 0, &handle_client); + + /* Wait for program to terminate (ctrl + c) */ + while(1) { + csp_sleep_ms(1000000); + } + + return 0; + +} diff --git a/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client.py b/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client.py new file mode 100644 index 00000000..123ce36e --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client.py @@ -0,0 +1,42 @@ +#!/usr/bin/python + +# libcsp must be build with at least these options to run this example client: +# ./waf distclean configure build --enable-bindings --enable-crc32 --enable-rdp --enable-if-zmq --with-driver-usart=linux --enable-if-kiss --enable-xtea --enable-if-can --enable-can-socketcan --enable-hmac --enable-examples + +# Can be run from root of libcsp like this: +# LD_LIBRARY_PATH=build PYTHONPATH=bindings/python:build python examples/python_bindings_example_client.py +# + +import os +import time +import libcsp as csp + + +if __name__ == "__main__": + + csp.buffer_init(10, 300) + csp.init(28) + csp.zmqhub_init(28, "localhost") + csp.rtable_set(27, 5, "ZMQHUB") + csp.route_start_task() + + ## allow router task startup + time.sleep(1) + + ## cmp_ident + (rc, host, model, rev, date, time) = csp.cmp_ident(27) + if rc == csp.CSP_ERR_NONE: + print (host, model, rev, date, time) + else: + print ("error in cmp_ident, rc=%i" % (rc)) + + ## transaction + outbuf = bytearray().fromhex('01') + inbuf = bytearray(1) + print ("using csp_transaction to send a single byte") + if csp.transaction(0, 27, 10, 1000, outbuf, inbuf) < 1: + print ("csp_transaction failed") + else: + print ("got reply, data=" + ''.join('{:02x}'.format(x) for x in inbuf)) + + diff --git a/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client_can.py b/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client_can.py new file mode 100644 index 00000000..ec796572 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client_can.py @@ -0,0 +1,30 @@ +#!/usr/bin/python + +# libcsp must be build with at least these options to run this example client: +# ./waf distclean configure build --enable-bindings --enable-crc32 --enable-rdp --enable-if-zmq --with-driver-usart=linux --enable-if-kiss --enable-xtea --enable-if-can --enable-can-socketcan --enable-hmac --enable-examples + +# Can be run from root of libcsp like this: +# LD_LIBRARY_PATH=build PYTHONPATH=bindings/python:build python examples/python_bindings_example_client.py +# + +import os +import time +import libcsp as csp + + +if __name__ == "__main__": + + csp.buffer_init(10, 300) + csp.init(28) + csp.can_socketcan_init("can0") + csp.rtable_set(4, 5, "CAN") + csp.route_start_task() + + ## allow router task startup + time.sleep(1) + + + node = 4 + if csp.ping(node) < 0: + print ("Unable to ping node %d"%(node)) + diff --git a/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_server.py b/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_server.py new file mode 100644 index 00000000..3cf3f5da --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_server.py @@ -0,0 +1,72 @@ +#!/usr/bin/python + +# libcsp must be build with at least these options to run this example server: +# ./waf distclean configure build --enable-bindings --enable-crc32 --enable-rdp --enable-if-zmq --with-driver-usart=linux --enable-if-kiss --enable-xtea --enable-if-can --enable-can-socketcan --enable-hmac --enable-examples + +# Can be run from root of libcsp like this: +# LD_LIBRARY_PATH=build PYTHONPATH=bindings/python:build python examples/python_bindings_example_server.py +# + +import os +import time +import sys +import libcsp as csp +import subprocess + +if __name__ == "__main__": + + # start a zmqproxy to transport messages to and from the client + zmqp = subprocess.Popen('build/zmqproxy') + + # init csp + csp.buffer_init(10, 300) + csp.init(27) + csp.zmqhub_init(27, "localhost") + csp.rtable_set(28, 5, "ZMQHUB") + csp.route_start_task() + + # set identity + csp.set_hostname("test_service") + csp.set_model("bindings") + csp.set_revision("1.2.3") + + # and read it back + print (csp.get_hostname()) + print (csp.get_model()) + print (csp.get_revision()) + + # start listening for packets... + sock = csp.socket() + csp.bind(sock, csp.CSP_ANY) + csp.listen(sock) + while True: + conn = csp.accept(sock) + if not conn: + continue + + print ("connection: source=%i:%i, dest=%i:%i" % (csp.conn_src(conn), + csp.conn_sport(conn), + csp.conn_dst(conn), + csp.conn_dport(conn))) + + while True: + packet = csp.read(conn) + if not packet: + break + + if csp.conn_dport(conn) == 10: + data = bytearray(csp.packet_get_data(packet)) + length = csp.packet_get_length(packet) + print ("got packet, len=" + str(length) + ", data=" + ''.join('{:02x}'.format(x) for x in data)) + + data[0] = data[0] + 1 + reply_packet = csp.buffer_get(1) + if reply_packet: + csp.packet_set_data(reply_packet, data) + csp.sendto_reply(packet, reply_packet, csp.CSP_O_NONE) + + csp.buffer_free(packet) + else: + csp.service_handler(conn, packet) + csp.close(conn) + diff --git a/gomspace/libgscsp/lib/libcsp/examples/simple.c b/gomspace/libgscsp/lib/libcsp/examples/simple.c new file mode 100644 index 00000000..b996f8c1 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/simple.c @@ -0,0 +1,200 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +#include + +/* Using un-exported header file. + * This is allowed since we are still in libcsp */ +#include + +/** Example defines */ +#define MY_ADDRESS 1 // Address of local CSP node +#define MY_PORT 10 // Port to send test traffic to + +CSP_DEFINE_TASK(task_server) { + + /* Create socket without any socket options */ + csp_socket_t *sock = csp_socket(CSP_SO_NONE); + + /* Bind all ports to socket */ + csp_bind(sock, CSP_ANY); + + /* Create 10 connections backlog queue */ + csp_listen(sock, 10); + + /* Pointer to current connection and packet */ + csp_conn_t *conn; + csp_packet_t *packet; + + /* Process incoming connections */ + while (1) { + + /* Wait for connection, 10000 ms timeout */ + if ((conn = csp_accept(sock, 10000)) == NULL) + continue; + + /* Read packets. Timout is 100 ms */ + while ((packet = csp_read(conn, 100)) != NULL) { + switch (csp_conn_dport(conn)) { + case MY_PORT: + /* Process packet here */ + printf("Packet received on MY_PORT: %s\r\n", (char *) packet->data); + csp_buffer_free(packet); + break; + + default: + /* Let the service handler reply pings, buffer use, etc. */ + csp_service_handler(conn, packet); + break; + } + } + + /* Close current connection, and handle next */ + csp_close(conn); + + } + + return CSP_TASK_RETURN; + +} + +CSP_DEFINE_TASK(task_client) { + + csp_packet_t * packet; + csp_conn_t * conn; + + while (1) { + + /** + * Try ping + */ + + csp_sleep_ms(1000); + + int result = csp_ping(MY_ADDRESS, 100, 100, CSP_O_NONE); + printf("Ping result %d [ms]\r\n", result); + + csp_sleep_ms(1000); + + /** + * Try data packet to server + */ + + /* Get packet buffer for data */ + packet = csp_buffer_get(100); + if (packet == NULL) { + /* Could not get buffer element */ + printf("Failed to get buffer element\n"); + return CSP_TASK_RETURN; + } + + /* Connect to host HOST, port PORT with regular UDP-like protocol and 1000 ms timeout */ + conn = csp_connect(CSP_PRIO_NORM, MY_ADDRESS, MY_PORT, 1000, CSP_O_NONE); + if (conn == NULL) { + /* Connect failed */ + printf("Connection failed\n"); + /* Remember to free packet buffer */ + csp_buffer_free(packet); + return CSP_TASK_RETURN; + } + + /* Copy dummy data to packet */ + const char *msg = "Hello World"; + strcpy((char *) packet->data, msg); + + /* Set packet length */ + packet->length = strlen(msg); + + /* Send packet */ + if (!csp_send(conn, packet, 1000)) { + /* Send failed */ + printf("Send failed\n"); + csp_buffer_free(packet); + } + + /* Close connection */ + csp_close(conn); + + } + + return CSP_TASK_RETURN; +} + +int main(int argc, char * argv[]) { + + /** + * Initialise CSP, + * No physical interfaces are initialised in this example, + * so only the loopback interface is registered. + */ + + /* Init buffer system with 10 packets of maximum 300 bytes each */ + printf("Initialising CSP\r\n"); + csp_buffer_init(5, 300); + + /* Init CSP with address MY_ADDRESS */ + csp_init(MY_ADDRESS); + + /* Start router task with 500 word stack, OS task priority 1 */ + csp_route_start_task(500, 1); + + /* Enable debug output from CSP */ + if ((argc > 1) && (strcmp(argv[1], "-v") == 0)) { + printf("Debug enabed\r\n"); + csp_debug_toggle_level(3); + csp_debug_toggle_level(4); + + printf("Conn table\r\n"); + csp_conn_print_table(); + + printf("Route table\r\n"); + csp_route_print_table(); + + printf("Interfaces\r\n"); + csp_route_print_interfaces(); + + } + + /** + * Initialise example threads, using pthreads. + */ + + /* Server */ + printf("Starting Server task\r\n"); + csp_thread_handle_t handle_server; + csp_thread_create(task_server, "SERVER", 1000, NULL, 0, &handle_server); + + /* Client */ + printf("Starting Client task\r\n"); + csp_thread_handle_t handle_client; + csp_thread_create(task_client, "SERVER", 1000, NULL, 0, &handle_client); + + /* Wait for execution to end (ctrl+c) */ + while(1) { + csp_sleep_ms(100000); + } + + return 0; + +} diff --git a/gomspace/libgscsp/lib/libcsp/examples/zmqproxy.c b/gomspace/libgscsp/lib/libcsp/examples/zmqproxy.c new file mode 100644 index 00000000..5e259579 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/zmqproxy.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include +#include + +static void * task_capture(void *ctx) { + + /* Subscriber (RX) */ + void *subscriber = zmq_socket(ctx, ZMQ_SUB); + assert(zmq_connect(subscriber, "tcp://localhost:7000") == 0); + assert(zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, "", 0) == 0); + + while (1) { + zmq_msg_t msg; + zmq_msg_init_size(&msg, 1024); + + /* Receive data */ + if (zmq_msg_recv(&msg, subscriber, 0) < 0) { + zmq_msg_close(&msg); + csp_log_error("ZMQ: %s\r\n", zmq_strerror(zmq_errno())); + continue; + } + + int datalen = zmq_msg_size(&msg); + if (datalen < 5) { + csp_log_warn("ZMQ: Too short datalen: %u\r\n", datalen); + while(zmq_msg_recv(&msg, subscriber, ZMQ_NOBLOCK) > 0) + zmq_msg_close(&msg); + continue; + } + + /* Create new csp packet */ + csp_packet_t * packet = malloc(1024); + if (packet == NULL) { + zmq_msg_close(&msg); + continue; + } + + /* Copy the data from zmq to csp */ + char * satidptr = ((char *) &packet->id) - 1; + memcpy(satidptr, zmq_msg_data(&msg), datalen); + packet->length = datalen - 4 - 1; + + printf("Input: Src %u, Dst %u, Dport %u, Sport %u, Pri %u, Flags 0x%02X, Size %"PRIu16"\r\n", + packet->id.src, packet->id.dst, packet->id.dport, + packet->id.sport, packet->id.pri, packet->id.flags, packet->length); + + free(packet); + zmq_msg_close(&msg); + } +} + +int main(int argc, char ** argv) { + + /** + * ZMQ PROXY + */ + void * ctx = zmq_ctx_new(); + assert(ctx); + + void *frontend = zmq_socket(ctx, ZMQ_XSUB); + assert(frontend); + assert(zmq_bind (frontend, "tcp://*:6000") == 0); + + void *backend = zmq_socket(ctx, ZMQ_XPUB); + assert(backend); + assert(zmq_bind(backend, "tcp://*:7000") == 0); + + pthread_t capworker; + pthread_create(&capworker, NULL, task_capture, ctx); + + printf("Starting ZMQproxy\r\n"); + zmq_proxy(frontend, backend, NULL); + + printf("Closing ZMQproxy\r\n"); + zmq_ctx_destroy(ctx); + return 0; + +} diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_clock.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_clock.h new file mode 100644 index 00000000..3c19c887 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_clock.h @@ -0,0 +1,60 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_CLOCK_H_ +#define _CSP_CLOCK_H_ + +/** + @file + + Clock API. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + Cross-platform timestamp. +*/ +typedef struct { + //! Seconds + uint32_t tv_sec; + //! Nano-seconds. + uint32_t tv_nsec; +} csp_timestamp_t; + +/** + Get time - must be implemented by the user. +*/ +__attribute__((weak)) extern void clock_get_time(csp_timestamp_t * time); + +/** + Set time - must be implemented by the user. +*/ +__attribute__((weak)) extern void clock_set_time(csp_timestamp_t * time); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_CLOCK_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_malloc.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_malloc.h new file mode 100644 index 00000000..12602d1b --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_malloc.h @@ -0,0 +1,39 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_MALLOC_H_ +#define _CSP_MALLOC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +void * csp_malloc(size_t size); +void csp_free(void * ptr); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_MALLOC_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_queue.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_queue.h new file mode 100644 index 00000000..3156c05e --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_queue.h @@ -0,0 +1,49 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_QUEUE_H_ +#define _CSP_QUEUE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define CSP_QUEUE_FULL 0 +#define CSP_QUEUE_ERROR 0 +#define CSP_QUEUE_OK 1 +typedef void * csp_queue_handle_t; + +#include +#include + +csp_queue_handle_t csp_queue_create(int length, size_t item_size); +void csp_queue_remove(csp_queue_handle_t queue); +int csp_queue_enqueue(csp_queue_handle_t handle, void *value, uint32_t timeout); +int csp_queue_enqueue_isr(csp_queue_handle_t handle, void * value, CSP_BASE_TYPE * task_woken); +int csp_queue_dequeue(csp_queue_handle_t handle, void *buf, uint32_t timeout); +int csp_queue_dequeue_isr(csp_queue_handle_t handle, void * buf, CSP_BASE_TYPE * task_woken); +int csp_queue_size(csp_queue_handle_t handle); +int csp_queue_size_isr(csp_queue_handle_t handle); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_QUEUE_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_semaphore.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_semaphore.h new file mode 100644 index 00000000..c8068da2 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_semaphore.h @@ -0,0 +1,109 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_SEMAPHORE_H_ +#define _CSP_SEMAPHORE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +/* POSIX interface */ +#if defined(CSP_POSIX) + +#include +#include + +#define CSP_SEMAPHORE_OK 1 +#define CSP_SEMAPHORE_ERROR 2 +#define CSP_MUTEX_OK CSP_SEMAPHORE_OK +#define CSP_MUTEX_ERROR CSP_SEMAPHORE_ERROR + +typedef sem_t csp_bin_sem_handle_t; +typedef pthread_mutex_t csp_mutex_t; + +#endif // CSP_POSIX + +/* MAC OS X interface */ +#if defined(CSP_MACOSX) + +#include +#include "posix/pthread_queue.h" + +#define CSP_SEMAPHORE_OK PTHREAD_QUEUE_OK +#define CSP_SEMAPHORE_ERROR PTHREAD_QUEUE_EMPTY +#define CSP_MUTEX_OK CSP_SEMAPHORE_OK +#define CSP_MUTEX_ERROR CSP_SEMAPHORE_ERROR + +typedef pthread_queue_t * csp_bin_sem_handle_t; +typedef pthread_queue_t * csp_mutex_t; + +#endif // CSP_MACOSX + +#if defined(CSP_WINDOWS) + +#include +#undef interface + +#define CSP_SEMAPHORE_OK 1 +#define CSP_SEMAPHORE_ERROR 2 +#define CSP_MUTEX_OK CSP_SEMAPHORE_OK +#define CSP_MUTEX_ERROR CSP_SEMAPHORE_ERROR + +typedef HANDLE csp_bin_sem_handle_t; +typedef HANDLE csp_mutex_t; + +#endif + +/* FreeRTOS interface */ +#if defined(CSP_FREERTOS) + +#include +#include + +#define CSP_SEMAPHORE_OK pdPASS +#define CSP_SEMAPHORE_ERROR pdFAIL +#define CSP_MUTEX_OK CSP_SEMAPHORE_OK +#define CSP_MUTEX_ERROR CSP_SEMAPHORE_ERROR + +typedef xSemaphoreHandle csp_bin_sem_handle_t; +typedef xSemaphoreHandle csp_mutex_t; + +#endif // CSP_FREERTOS + +int csp_mutex_create(csp_mutex_t * mutex); +int csp_mutex_remove(csp_mutex_t * mutex); +int csp_mutex_lock(csp_mutex_t * mutex, uint32_t timeout); +int csp_mutex_unlock(csp_mutex_t * mutex); +int csp_bin_sem_create(csp_bin_sem_handle_t * sem); +int csp_bin_sem_remove(csp_bin_sem_handle_t * sem); +int csp_bin_sem_wait(csp_bin_sem_handle_t * sem, uint32_t timeout); +int csp_bin_sem_post(csp_bin_sem_handle_t * sem); +int csp_bin_sem_post_isr(csp_bin_sem_handle_t * sem, CSP_BASE_TYPE * task_woken); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_SEMAPHORE_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_system.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_system.h new file mode 100644 index 00000000..c6c0e5af --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_system.h @@ -0,0 +1,74 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_SYSTEM_H_ +#define _CSP_SYSTEM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define COLOR_MASK_COLOR 0x0F +#define COLOR_MASK_MODIFIER 0xF0 + +typedef enum { + /* Colors */ + COLOR_RESET = 0xF0, + COLOR_BLACK = 0x01, + COLOR_RED = 0x02, + COLOR_GREEN = 0x03, + COLOR_YELLOW = 0x04, + COLOR_BLUE = 0x05, + COLOR_MAGENTA = 0x06, + COLOR_CYAN = 0x07, + COLOR_WHITE = 0x08, + /* Modifiers */ + COLOR_NORMAL = 0x0F, + COLOR_BOLD = 0x10, + COLOR_UNDERLINE = 0x20, + COLOR_BLINK = 0x30, + COLOR_HIDE = 0x40, +} csp_color_t; + +/** + * Writes out a task list into a pre-allocate buffer, + * use csp_sys_tasklist_size to get sizeof buffer to allocate + * @param out pointer to output buffer + * @return + */ +int csp_sys_tasklist(char * out); + +/** + * @return Size of tasklist buffer to allocate for the csp_sys_tasklist call + */ +int csp_sys_tasklist_size(void); + +uint32_t csp_sys_memfree(void); +int csp_sys_reboot(void); +int csp_sys_shutdown(void); +void csp_sys_set_color(csp_color_t color); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_SYSTEM_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_thread.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_thread.h new file mode 100644 index 00000000..3c6ea171 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_thread.h @@ -0,0 +1,100 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_THREAD_H_ +#define _CSP_THREAD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* POSIX interface */ +#if defined(CSP_POSIX) || defined(CSP_MACOSX) + +#include +#include + +#define csp_thread_exit() pthread_exit(NULL) + +typedef pthread_t csp_thread_handle_t; +typedef void * csp_thread_return_t; + +#define CSP_DEFINE_TASK(task_name) csp_thread_return_t task_name(void * param) +#define CSP_TASK_RETURN NULL + +#define csp_sleep_ms(time_ms) usleep(time_ms * 1000); + +#endif // CSP_POSIX + +/* Windows interface */ +#if defined(CSP_WINDOWS) + +#include +#undef interface +#include + +#define csp_thread_exit() _endthreadex(0) + +typedef HANDLE csp_thread_handle_t; +typedef unsigned int csp_thread_return_t; + +#define CSP_DEFINE_TASK(task_name) csp_thread_return_t __attribute__((stdcall)) task_name(void * param) +#define CSP_TASK_RETURN 0 + +#define csp_sleep_ms(time_ms) Sleep(time_ms); + +#endif // CSP_WINDOWS + +/* FreeRTOS interface */ +#if defined(CSP_FREERTOS) + +#include +#include + +#if INCLUDE_vTaskDelete +#define csp_thread_exit() vTaskDelete(NULL) +#else +#define csp_thread_exit() +#endif + +typedef xTaskHandle csp_thread_handle_t; +typedef void csp_thread_return_t; + +#define CSP_DEFINE_TASK(task_name) csp_thread_return_t task_name(void * param) +#define CSP_TASK_RETURN + +#define csp_sleep_ms(time_ms) vTaskDelay(time_ms / portTICK_RATE_MS); + +#endif // CSP_FREERTOS + +#ifndef CSP_WINDOWS +int csp_thread_create(csp_thread_return_t (* routine)(void *), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle); +#else +int csp_thread_create(csp_thread_return_t (* routine)(void *)__attribute__((stdcall)), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_THREAD_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_time.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_time.h new file mode 100644 index 00000000..aa72ab8f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_time.h @@ -0,0 +1,57 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_TIME_H_ +#define _CSP_TIME_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* Blackfin/x86 on Linux */ +#if defined(CSP_POSIX) + +#include +#include +#include + +#endif // CSP_POSIX + +/* AVR/ARM on FreeRTOS */ +#if defined(CSP_FREERTOS) + +#include +#include + +#endif // CSP_FREERTOS + +uint32_t csp_get_ms(void); +uint32_t csp_get_ms_isr(void); +uint32_t csp_get_s(void); +uint32_t csp_get_s_isr(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_TIME_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/posix/pthread_queue.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/posix/pthread_queue.h new file mode 100644 index 00000000..44ef596e --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/posix/pthread_queue.h @@ -0,0 +1,118 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _PTHREAD_QUEUE_H_ +#define _PTHREAD_QUEUE_H_ + +/** + @file + + Queue implemented using pthread locks and conds. + + Inspired by c-pthread-queue by Matthew Dickinson: http://code.google.com/p/c-pthread-queue/ +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include + +/** + Queue error codes. + @{ +*/ +/** + General error code - something went wrong. +*/ +#define PTHREAD_QUEUE_ERROR CSP_QUEUE_ERROR +/** + Queue is empty - cannot extract element. +*/ +#define PTHREAD_QUEUE_EMPTY CSP_QUEUE_ERROR +/** + Queue is full - cannot insert element. +*/ +#define PTHREAD_QUEUE_FULL CSP_QUEUE_ERROR +/** + Ok - no error. +*/ +#define PTHREAD_QUEUE_OK CSP_QUEUE_OK +/** @{ */ + +/** + Queue handle. +*/ +typedef struct pthread_queue_s { + //! Memory area. + void * buffer; + //! Memory size. + int size; + //! Item/element size. + int item_size; + //! Items/elements in queue. + int items; + //! Insert point. + int in; + //! Extract point. + int out; + //! Lock. + pthread_mutex_t mutex; + //! Wait because queue is full (insert). + pthread_cond_t cond_full; + //! Wait because queue is empty (extract). + pthread_cond_t cond_empty; +} pthread_queue_t; + +/** + Create queue. +*/ +pthread_queue_t * pthread_queue_create(int length, size_t item_size); + +/** + Delete queue. +*/ +void pthread_queue_delete(pthread_queue_t * q); + +/** + Enqueue/insert element. +*/ +int pthread_queue_enqueue(pthread_queue_t * queue, void * value, uint32_t timeout); + +/** + Dequeue/extract element. +*/ +int pthread_queue_dequeue(pthread_queue_t * queue, void * buf, uint32_t timeout); + +/** + Return number of elements in the queue. +*/ +int pthread_queue_items(pthread_queue_t * queue); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _PTHREAD_QUEUE_H_ + diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_hmac.h b/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_hmac.h new file mode 100644 index 00000000..8c3f5d6a --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_hmac.h @@ -0,0 +1,73 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_HMAC_H_ +#define _CSP_HMAC_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CSP_HMAC_LENGTH 4 + +/** + * Append HMAC to packet + * @param packet Pointer to packet + * @param include_header use header in hmac calculation (this will not modify the flags field) + * @return 0 on success, negative on failure + */ +int csp_hmac_append(csp_packet_t * packet, bool include_header); + +/** + * Verify HMAC of packet + * @param packet Pointer to packet + * @param include_header use header in hmac calculation (this will not modify the flags field) + * @return 0 on success, negative on failure + */ +int csp_hmac_verify(csp_packet_t * packet, bool include_header); + +/** + * Calculate HMAC on buffer + * + * This function is used by append/verify but cal also be called separately. + * @param key HMAC key + * @param keylen HMAC key length + * @param data pointer to data + * @param datalen lehgth of data + * @param hmac output HMAC calculation (CSP_HMAC_LENGTH) + * @return 0 on success, negative on failure + */ +int csp_hmac_memory(const uint8_t * key, uint32_t keylen, const uint8_t * data, uint32_t datalen, uint8_t * hmac); + +/** + * Save a copy of the key string for use by the append/verify functions + * @param key HMAC key + * @param keylen HMAC key length + * @return Always returns 0 + */ +int csp_hmac_set_key(char * key, uint32_t keylen); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_HMAC_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_sha1.h b/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_sha1.h new file mode 100644 index 00000000..aa7e7a0d --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_sha1.h @@ -0,0 +1,81 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_SHA1_H_ +#define _CSP_SHA1_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* The SHA1 block and message digest size in bytes */ +#define SHA1_BLOCKSIZE 64 +#define SHA1_DIGESTSIZE 20 + +/** + SHA1 state structure +*/ +typedef struct { + //! Internal SHA1 state. + uint64_t length; + //! Internal SHA1 state. + uint32_t state[5]; + //! Internal SHA1 state. + uint32_t curlen; + //! Internal SHA1 state. + uint8_t buf[SHA1_BLOCKSIZE]; +} csp_sha1_state; + +/** + * Initialize the hash state + * @param sha1 The hash state you wish to initialize + */ +void csp_sha1_init(csp_sha1_state * sha1); + +/** + * Process a block of memory though the hash + * @param sha1 The hash state + * @param in The data to hash + * @param inlen The length of the data (octets) + */ +void csp_sha1_process(csp_sha1_state * sha1, const uint8_t * in, uint32_t inlen); + +/** + * Terminate the hash to get the digest + * @param sha1 The hash state + * @param out [out] The destination of the hash (20 bytes) + */ +void csp_sha1_done(csp_sha1_state * sha1, uint8_t * out); + +/** + * Calculate SHA1 hash of block of memory. + * @param msg Pointer to message buffer + * @param len Length of message + * @param sha1 Pointer to SHA1 output buffer. Must be 20 bytes or more! + */ +void csp_sha1_memory(const uint8_t * msg, uint32_t len, uint8_t * hash); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_SHA1_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_xtea.h b/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_xtea.h new file mode 100644 index 00000000..f740b8d5 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_xtea.h @@ -0,0 +1,52 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_XTEA_H_ +#define _CSP_XTEA_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CSP_XTEA_IV_LENGTH 8 + +/** + * XTEA encrypt byte array + * @param plain Pointer to plain text + * @param len Length of plain text + * @param iv Initialization vector + */ +int csp_xtea_encrypt(uint8_t * plain, const uint32_t len, uint32_t iv[2]); + +/** + * Decrypt XTEA encrypted byte array + * @param cipher Pointer to cipher text + * @param len Length of plain text + * @param iv Initialization vector + */ +int csp_xtea_decrypt(uint8_t * cipher, const uint32_t len, uint32_t iv[2]); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_XTEA_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp.h new file mode 100644 index 00000000..6962195b --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp.h @@ -0,0 +1,545 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_H_ +#define _CSP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes */ +#include + +#include + +/* CSP includes */ +#include "csp_types.h" +#include "csp_platform.h" +#include "csp_error.h" +#include "csp_debug.h" +#include "csp_buffer.h" +#include "csp_rtable.h" +#include "csp_iflist.h" + +/** csp_init + * Start up the can-space protocol + * @param my_node_address The CSP node address + */ +int csp_init(uint8_t my_node_address); + +/** csp_set_address + * Set the systems own address + * @param addr The new address of the system + */ +void csp_set_address(uint8_t addr); + +/** csp_get_address + * Get the systems own address + * @return The current address of the system + */ +uint8_t csp_get_address(void); + +/** csp_set_hostname + * Set subsystem hostname. + * This function takes a pointer to a string, which should remain static + * @param hostname Hostname to set + */ +void csp_set_hostname(const char *hostname); + +/** csp_get_hostname + * Get current subsystem hostname. + * @return Pointer to char array with current hostname. + */ +const char *csp_get_hostname(void); + +/** csp_set_model + * Set subsystem model name. + * This function takes a pointer to a string, which should remain static + * @param model Model name to set + */ +void csp_set_model(const char *model); + +/** csp_get_model + * Get current model name. + * @return Pointer to char array with current model name. + */ +const char *csp_get_model(void); + +/** csp_set_revision + * Set subsystem revision. This can be used to override the CMP revision field. + * This function takes a pointer to a string, which should remain static + * @param revision Revision name to set + */ +void csp_set_revision(const char *revision); + +/** csp_get_revision + * Get subsystem revision. + * @return Pointer to char array with software revision. + */ +const char *csp_get_revision(void); + +/** csp_socket + * Create CSP socket endpoint + * @param opts Socket options + * @return Pointer to socket on success, NULL on failure + */ +csp_socket_t *csp_socket(uint32_t opts); + +/** + * Wait for a new connection on a socket created by csp_socket + * @param socket Socket to accept connections on + * @param timeout use CSP_MAX_DELAY for infinite timeout + * @return Return pointer to csp_conn_t or NULL if timeout was reached + */ +csp_conn_t *csp_accept(csp_socket_t *socket, uint32_t timeout); + +/** + * Read data from a connection + * This fuction uses the RX queue of a connection to receive a packet + * If no packet is available and a timeout has been specified + * The call will block. + * Do NOT call this from ISR + * @param conn pointer to connection + * @param timeout timeout in ms, use CSP_MAX_DELAY for infinite blocking time + * @return Returns pointer to csp_packet_t, which you MUST free yourself, either by calling csp_buffer_free() or reusing the buffer for a new csp_send. + */ +csp_packet_t *csp_read(csp_conn_t *conn, uint32_t timeout); + +/** + * Send a packet on an already established connection + * @param conn pointer to connection + * @param packet pointer to packet, + * @param timeout a timeout to wait for TX to complete. NOTE: not all underlying drivers supports flow-control. + * @return returns 1 if successful and 0 otherwise. you MUST free the frame yourself if the transmission was not successful. + */ +int csp_send(csp_conn_t *conn, csp_packet_t *packet, uint32_t timeout); + +/** + * Send a packet on an already established connection, and change the default priority of the connection + * + * @note When using this function, the priority of the connection will change. If you need to change it back + * use another call to csp_send_prio, or ensure that all packets sent on a given connection is using send_prio call. + * + * @param prio csp priority + * @param conn pointer to connection + * @param packet pointer to packet, + * @param timeout a timeout to wait for TX to complete. NOTE: not all underlying drivers supports flow-control. + * @return returns 1 if successful and 0 otherwise. you MUST free the frame yourself if the transmission was not successful. + */ +int csp_send_prio(uint8_t prio, csp_conn_t *conn, csp_packet_t *packet, uint32_t timeout); + +/** + * Perform an entire request/reply transaction + * Copies both input buffer and reply to output buffeer. + * Also makes the connection and closes it again + * @param prio CSP Prio + * @param dest CSP Dest + * @param port CSP Port + * @param timeout timeout in ms + * @param outbuf pointer to outgoing data buffer + * @param outlen length of request to send + * @param inbuf pointer to incoming data buffer + * @param inlen length of expected reply, -1 for unknown size (note inbuf MUST be large enough) + * @return Return 1 or reply size if successful, 0 if error or incoming length does not match or -1 if timeout was reached + */ +int csp_transaction(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, void *outbuf, int outlen, void *inbuf, int inlen); + +/** + * Perform an entire request/reply transaction + * Copies both input buffer and reply to output buffeer. + * Also makes the connection and closes it again + * @param prio CSP Prio + * @param dest CSP Dest + * @param port CSP Port + * @param timeout timeout in ms + * @param outbuf pointer to outgoing data buffer + * @param outlen length of request to send + * @param inbuf pointer to incoming data buffer + * @param inlen length of expected reply, -1 for unknown size (note inbuf MUST be large enough) + * @param opts Connection options. + * @return Return 1 or reply size if successful, 0 if error or incoming length does not match or -1 if timeout was reached + */ +int csp_transaction2(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, void *outbuf, int outlen, void *inbuf, int inlen, uint32_t opts); + +/** + * Use an existing connection to perform a transaction, + * This is only possible if the next packet is on the same port and destination! + * @param conn pointer to connection structure + * @param timeout timeout in ms + * @param outbuf pointer to outgoing data buffer + * @param outlen length of request to send + * @param inbuf pointer to incoming data buffer + * @param inlen length of expected reply, -1 for unknown size (note inbuf MUST be large enough) + * @return + */ +int csp_transaction_persistent(csp_conn_t *conn, uint32_t timeout, void *outbuf, int outlen, void *inbuf, int inlen); + +/** + * Read data from a connection-less server socket + * This fuction uses the socket directly to receive a frame + * If no packet is available and a timeout has been specified the call will block. + * Do NOT call this from ISR + * @return Returns pointer to csp_packet_t, which you MUST free yourself, either by calling csp_buffer_free() or reusing the buffer for a new csp_send. + */ +csp_packet_t *csp_recvfrom(csp_socket_t *socket, uint32_t timeout); + +/** + * Send a packet without previously opening a connection + * @param prio CSP_PRIO_x + * @param dest destination node + * @param dport destination port + * @param src_port source port + * @param opts CSP_O_x + * @param packet pointer to packet + * @param timeout timeout used by interfaces with blocking send + * @return -1 if error (you must free packet), 0 if OK (you must discard pointer) + */ +int csp_sendto(uint8_t prio, uint8_t dest, uint8_t dport, uint8_t src_port, uint32_t opts, csp_packet_t *packet, uint32_t timeout); + +/** + * Send a packet as a direct reply to the source of an incoming packet, + * but still without holding an entire connection + * @param request_packet pointer to packet to reply to + * @param reply_packet actual reply data + * @param opts CSP_O_x + * @param timeout timeout used by interfaces with blocking send + * @return -1 if error (you must free packet), 0 if OK (you must discard pointer) + */ +int csp_sendto_reply(csp_packet_t * request_packet, csp_packet_t * reply_packet, uint32_t opts, uint32_t timeout); + +/** csp_connect + * Used to establish outgoing connections + * This function searches the port table for free slots and finds an unused + * connection from the connection pool + * There is no handshake in the CSP protocol + * @param prio Connection priority. + * @param dest Destination address. + * @param dport Destination port. + * @param timeout Timeout in ms. + * @param opts Connection options. + * @return a pointer to a new connection or NULL + */ +csp_conn_t *csp_connect(uint8_t prio, uint8_t dest, uint8_t dport, uint32_t timeout, uint32_t opts); + +/** csp_close + * Closes a given connection and frees buffers used. + * @param conn pointer to connection structure + * @return CSP_ERR_NONE if connection was closed. Otherwise, an err code is returned. + */ +int csp_close(csp_conn_t *conn); + +/** + * @param conn pointer to connection structure + * @return destination port of an incoming connection + */ +int csp_conn_dport(csp_conn_t *conn); + +/** + * @param conn pointer to connection structure + * @return source port of an incoming connection + */ +int csp_conn_sport(csp_conn_t *conn); + +/** + * @param conn pointer to connection structure + * @return destination address of an incoming connection + */ +int csp_conn_dst(csp_conn_t *conn); + +/** + * @param conn pointer to connection structure + * @return source address of an incoming connection + */ +int csp_conn_src(csp_conn_t *conn); + +/** + * @param conn pointer to connection structure + * @return flags field of an incoming connection + */ +int csp_conn_flags(csp_conn_t *conn); + +/** + * Set socket to listen for incoming connections + * @param socket Socket to enable listening on + * @param conn_queue_length Lenght of backlog connection queue + * @return 0 on success, -1 on error. + */ +int csp_listen(csp_socket_t *socket, size_t conn_queue_length); + +/** + * Bind port to socket + * @param socket Socket to bind port to + * @param port Port number to bind + * @return 0 on success, -1 on error. + */ +int csp_bind(csp_socket_t *socket, uint8_t port); + +/** + * Start the router task. + * @param task_stack_size The number of portStackType to allocate. This only affects FreeRTOS systems. + * @param priority The OS task priority of the router + */ +int csp_route_start_task(unsigned int task_stack_size, unsigned int priority); + +/** + * Call the router worker function manually (without the router task) + * This must be run inside a loop or called periodically for the csp router to work. + * Use this function instead of calling and starting the router task. + * @param timeout max blocking time + * @return -1 if no packet was processed, 0 otherwise + */ +int csp_route_work(uint32_t timeout); + +/** + * Start the bridge task. + * @param task_stack_size The number of portStackType to allocate. This only affects FreeRTOS systems. + * @param priority The OS task priority of the router + * @param _if_a pointer to first side + * @param _if_b pointer to second side + * @return CSP_ERR type + */ +int csp_bridge_start(unsigned int task_stack_size, unsigned int task_priority, csp_iface_t * _if_a, csp_iface_t * _if_b); + +/** + * Enable promiscuous mode packet queue + * This function is used to enable promiscuous mode for the router. + * If enabled, a copy of all incoming packets are placed in a queue + * that can be read with csp_promisc_get(). Not all interface drivers + * support promiscuous mode. + * + * @param buf_size Size of buffer for incoming packets + */ +int csp_promisc_enable(unsigned int buf_size); + +/** + * Disable promiscuous mode. + * If the queue was initialised prior to this, it can be re-enabled + * by calling promisc_enable(0) + */ +void csp_promisc_disable(void); + +/** + * Get packet from promiscuous mode packet queue + * Returns the first packet from the promiscuous mode packet queue. + * The queue is FIFO, so the returned packet is the oldest one + * in the queue. + * + * @param timeout Timeout in ms to wait for a new packet + */ +csp_packet_t *csp_promisc_read(uint32_t timeout); + +/** + * Send multiple packets using the simple fragmentation protocol + * CSP will add total size and offset to all packets + * This can be read by the client using the csp_sfp_recv, if the CSP_FFRAG flag is set + * @param conn pointer to connection + * @param data pointer to data to send + * @param totalsize size of data to send + * @param mtu maximum transfer unit + * @param timeout timeout in ms to wait for csp_send() + * @return 0 if OK, -1 if ERR + */ +int csp_sfp_send(csp_conn_t * conn, const void * data, int totalsize, int mtu, uint32_t timeout); + +/** + * Same as csp_sfp_send but with option to supply your own memcpy function. + * This is usefull if you wish to send data stored in flash memory or another location + * @param conn pointer to connection + * @param data pointer to data to send + * @param totalsize size of data to send + * @param mtu maximum transfer unit + * @param timeout timeout in ms to wait for csp_send() + * @param memcpyfcn, pointer to memcpy function + * @return 0 if OK, -1 if ERR + */ +int csp_sfp_send_own_memcpy(csp_conn_t * conn, const void * data, int totalsize, int mtu, uint32_t timeout, void * (*memcpyfcn)(void *, const void *, size_t)); + +/** + * This is the counterpart to the csp_sfp_send function + * @param conn pointer to active conn, on which you expect to receive sfp packed data + * @param dataout pointer to NULL pointer, whill be overwritten with malloc pointer + * @param datasize actual size of received data + * @param timeout timeout in ms to wait for csp_recv() + * @return 0 if OK, -1 if ERR + */ +int csp_sfp_recv(csp_conn_t * conn, void ** dataout, int * datasize, uint32_t timeout); + +/** + * This is the counterpart to the csp_sfp_send function + * @param conn pointer to active conn, on which you expect to receive sfp packed data + * @param dataout pointer to NULL pointer, whill be overwritten with malloc pointer + * @param datasize actual size of received data + * @param timeout timeout in ms to wait for csp_recv() + * @param first_packet This is a pointer to the first SFP packet (previously received with csp_read) + * @return 0 if OK, -1 if ERR + */ +int csp_sfp_recv_fp(csp_conn_t * conn, void ** dataout, int * datasize, uint32_t timeout, csp_packet_t * first_packet); + +/** + * If the given packet is a service-request (that is uses one of the csp service ports) + * it will be handled according to the CSP service handler. + * This function will either use the packet buffer or delete it, + * so this function is typically called in the last "default" clause of + * a switch/case statement in a csp_listener task. + * In order to listen to csp service ports, bind your listener to the CSP_ANY port. + * This function may only be called from task context. + * @param conn Pointer to the new connection + * @param packet Pointer to the first packet, obtained by using csp_read() + */ +void csp_service_handler(csp_conn_t *conn, csp_packet_t *packet); + +/** + * Send a single ping/echo packet + * @param node node id + * @param timeout timeout in ms + * @param size size of packet to transmit + * @param conn_options csp connection options + * @return >0 = Echo time in ms, -1 = ERR + */ +int csp_ping(uint8_t node, uint32_t timeout, unsigned int size, uint8_t conn_options); + +/** + * Send a single ping/echo packet without waiting for reply + * @param node node id + */ +void csp_ping_noreply(uint8_t node); + +/** + * Request process list. + * @note This is only available for FreeRTOS systems + * @param node node id + * @param timeout timeout in ms + */ +void csp_ps(uint8_t node, uint32_t timeout); + +/** + * Request amount of free memory + * @param node node id + * @param timeout timeout in ms + */ +void csp_memfree(uint8_t node, uint32_t timeout); + +/** + * Request number of free buffer elements + * @param node node id + * @param timeout timeout in ms + */ +void csp_buf_free(uint8_t node, uint32_t timeout); + +/** + * Reboot subsystem + * @param node node id + */ +void csp_reboot(uint8_t node); + +/** + * Shutdown subsystem + * @param node node id + */ +void csp_shutdown(uint8_t node); + +/** + * Request subsystem uptime + * @param node node id + * @param timeout timeout in ms + */ +void csp_uptime(uint8_t node, uint32_t timeout); + +/** + * Set RDP options + * @param window_size Window size + * @param conn_timeout_ms Connection timeout in ms + * @param packet_timeout_ms Packet timeout in ms + * @param delayed_acks Enable/disable delayed acknowledgements + * @param ack_timeout Acknowledgement timeout when delayed ACKs is enabled + * @param ack_delay_count Send acknowledgement for every ack_delay_count packets + */ +void csp_rdp_set_opt(unsigned int window_size, unsigned int conn_timeout_ms, + unsigned int packet_timeout_ms, unsigned int delayed_acks, + unsigned int ack_timeout, unsigned int ack_delay_count); + +/** + * Get RDP options + * @param window_size Window size + * @param conn_timeout_ms Connection timeout in ms + * @param packet_timeout_ms Packet timeout in ms + * @param delayed_acks Enable/disable delayed acknowledgements + * @param ack_timeout Acknowledgement timeout when delayed ACKs is enabled + * @param ack_delay_count Send acknowledgement for every ack_delay_count packets + */ +void csp_rdp_get_opt(unsigned int *window_size, unsigned int *conn_timeout_ms, + unsigned int *packet_timeout_ms, unsigned int *delayed_acks, + unsigned int *ack_timeout, unsigned int *ack_delay_count); + +/** + * Set XTEA key + * @param key Pointer to key array + * @param keylen Length of key + * @return 0 if key was successfully set, -1 otherwise + */ +int csp_xtea_set_key(char *key, uint32_t keylen); + +/** + * Set HMAC key + * @param key Pointer to key array + * @param keylen Length of key + * @return 0 if key was successfully set, -1 otherwise + */ +int csp_hmac_set_key(char *key, uint32_t keylen); + +/** + * Print connection table + */ +void csp_conn_print_table(void); +int csp_conn_print_table_str(char * str_buf, int str_size); + +/** + * Print buffer usage table + */ +void csp_buffer_print_table(void); + +/** + * Hex dump to stdout + */ +void csp_hex_dump(const char *desc, void *addr, int len); + +#ifdef __AVR__ +typedef uint32_t csp_memptr_t; +#else +typedef void * csp_memptr_t; +#endif + +typedef csp_memptr_t (*csp_memcpy_fnc_t)(csp_memptr_t, const csp_memptr_t, size_t); +void csp_cmp_set_memcpy(csp_memcpy_fnc_t fnc); + +/** + * Set csp_debug hook function + * @param f Hook function + */ +#include +typedef void (*csp_debug_hook_func_t)(csp_debug_level_t level, const char *format, va_list args); +void csp_debug_hook_set(csp_debug_hook_func_t f); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_autoconfig.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_autoconfig.h new file mode 100644 index 00000000..77746afd --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_autoconfig.h @@ -0,0 +1,41 @@ +#ifndef W_INCLUDE_CSP_CSP_AUTOCONFIG_H_WAF +#define W_INCLUDE_CSP_CSP_AUTOCONFIG_H_WAF + +#define ENABLE_NANOPOWER2_CLIENT 1 +#define GIT_REV "unknown" +/* #undef CSP_FREERTOS */ +#define CSP_POSIX 1 +/* #undef CSP_WINDOWS */ +/* #undef CSP_MACOSX */ +#define HAVE_LIBZMQ 1 +#define CSP_DEBUG 1 +#define CSP_USE_RDP 1 +#define CSP_USE_CRC32 1 +#define CSP_USE_HMAC 1 +#define CSP_USE_XTEA 1 +#define CSP_USE_PROMISC 1 +#define CSP_USE_QOS 1 +/* #undef CSP_USE_DEDUP */ +/* #undef CSP_USE_INIT_SHUTDOWN */ +#define CSP_USE_CAN 1 +#define CSP_USE_I2C 1 +#define CSP_USE_KISS 1 +#define CSP_USE_ZMQHUB 1 +#define CSP_CONN_MAX 10 +#define CSP_CONN_QUEUE_LENGTH 100 +#define CSP_FIFO_INPUT 100 +#define CSP_MAX_BIND_PORT 31 +#define CSP_RDP_MAX_WINDOW 20 +#define CSP_PADDING_BYTES 8 +#define CSP_CONNECTION_SO 64 +#define CSP_LOG_LEVEL_DEBUG 1 +#define CSP_LOG_LEVEL_INFO 1 +#define CSP_LOG_LEVEL_WARN 1 +#define CSP_LOG_LEVEL_ERROR 1 +#define CSP_LITTLE_ENDIAN 1 +/* #undef CSP_BIG_ENDIAN */ +#define CSP_HAVE_STDBOOL_H 1 +#define CSP_HAVE_LIBSOCKETCAN 1 +#define LIBCSP_VERSION "1.5" + +#endif /* W_INCLUDE_CSP_CSP_AUTOCONFIG_H_WAF */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_buffer.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_buffer.h new file mode 100644 index 00000000..9ed6df77 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_buffer.h @@ -0,0 +1,92 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_BUFFER_H_ +#define _CSP_BUFFER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Start the buffer handling system + * You must specify the number for buffers and the size. All buffers are fixed + * size so you must specify the size of your largest buffer. + * + * @param count Number of buffers to allocate + * @param size Buffer size in bytes. + * + * @return CSP_ERR_NONE if malloc() succeeded, CSP_ERR message otherwise. + */ +int csp_buffer_init(int count, int size); + +/** + * Get a reference to a free buffer. This function can only be called + * from task context. + * + * @param size Specify what data-size you will put in the buffer + * @return pointer to a free csp_packet_t or NULL if out of memory + */ +void * csp_buffer_get(size_t size); + +/** + * Get a reference to a free buffer. This function can only be called + * from interrupt context. + * + * @param buf_size Specify what data-size you will put in the buffer + * @return pointer to a free csp_packet_t or NULL if out of memory + */ +void * csp_buffer_get_isr(size_t buf_size); + +/** + * Free a buffer after use. + * @param packet pointer to memory area, must be acquired by csp_buffer_get(). + */ +void csp_buffer_free(void *packet); + +/** + * Free a buffer after use in ISR context. + * @param packet pointer to memory area, must be acquired by csp_buffer_get(). + */ +void csp_buffer_free_isr(void *packet); + +/** + * Clone an existing packet and increase/decrease cloned packet size. + * @param buffer Existing buffer to clone. + */ +void * csp_buffer_clone(void *buffer); + +/** + * Return how many buffers that are currently free. + * @return number of free buffers + */ +int csp_buffer_remaining(void); + +/** + * Return the size of the CSP buffers + * @return size of CSP buffers + */ +int csp_buffer_size(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CSP_BUFFER_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_cmp.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_cmp.h new file mode 100644 index 00000000..114a8eab --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_cmp.h @@ -0,0 +1,189 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_CMP_H_ +#define _CSP_CMP_H_ + +/** + @file + CSP management protocol (CMP). +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/** + CMP type. + @{ +*/ +/** + CMP request. +*/ +#define CSP_CMP_REQUEST 0x00 +/** + CMP reply. +*/ +#define CSP_CMP_REPLY 0xff +/**@}*/ + +/** + CMP requests. + @{ +*/ +/** + CMP request codes. +*/ +/** + Request identification, compile time, revision, name. +*/ +#define CSP_CMP_IDENT 1 +/** + Set/configure routing. +*/ +#define CSP_CMP_ROUTE_SET 2 +/** + Request interface statistics. +*/ +#define CSP_CMP_IF_STATS 3 +/** + Peek/read data from memory. +*/ +#define CSP_CMP_PEEK 4 +/** + Poke/write data from memory. +*/ +#define CSP_CMP_POKE 5 +/** + Get/set clock. +*/ +#define CSP_CMP_CLOCK 6 +/**@}*/ + +/** + CMP identification - max revision length. +*/ +#define CSP_CMP_IDENT_REV_LEN 20 +/** + CMP identification - max date length. +*/ +#define CSP_CMP_IDENT_DATE_LEN 12 +/** + CMP identification - max time length. +*/ +#define CSP_CMP_IDENT_TIME_LEN 9 + +/** + CMP interface statistics - max interface name length. +*/ +#define CSP_CMP_ROUTE_IFACE_LEN 11 + +/** + CMP peek/read memeory - max read length. +*/ +#define CSP_CMP_PEEK_MAX_LEN 200 + +/** + CMP poke/write memeory - max write length. +*/ +#define CSP_CMP_POKE_MAX_LEN 200 + +/** + CSP management protocol description. +*/ +struct csp_cmp_message { + //! CMP request type. + uint8_t type; + //! CMP request code. + uint8_t code; + union { + struct { + char hostname[CSP_HOSTNAME_LEN]; + char model[CSP_MODEL_LEN]; + char revision[CSP_CMP_IDENT_REV_LEN]; + char date[CSP_CMP_IDENT_DATE_LEN]; + char time[CSP_CMP_IDENT_TIME_LEN]; + } ident; + struct { + uint8_t dest_node; + uint8_t next_hop_mac; + char interface[CSP_CMP_ROUTE_IFACE_LEN]; + } route_set; + struct __attribute__((__packed__)) { + char interface[CSP_CMP_ROUTE_IFACE_LEN]; + uint32_t tx; + uint32_t rx; + uint32_t tx_error; + uint32_t rx_error; + uint32_t drop; + uint32_t autherr; + uint32_t frame; + uint32_t txbytes; + uint32_t rxbytes; + uint32_t irq; + } if_stats; + struct { + uint32_t addr; + uint8_t len; + char data[CSP_CMP_PEEK_MAX_LEN]; + } peek; + struct { + uint32_t addr; + uint8_t len; + char data[CSP_CMP_POKE_MAX_LEN]; + } poke; + csp_timestamp_t clock; + }; +} __attribute__ ((packed)); + +/** + Macro for calculating size of management message. +*/ +#define CMP_SIZE(_memb) (sizeof(((struct csp_cmp_message *)0)->_memb) + sizeof(uint8_t) + sizeof(uint8_t)) + +/** + Generic send management message request. +*/ +int csp_cmp(uint8_t node, uint32_t timeout, uint8_t code, int membsize, struct csp_cmp_message *msg); + +/** + Macro for defining management handling function. +*/ +#define CMP_MESSAGE(_code, _memb) \ +static inline int csp_cmp_##_memb(uint8_t node, uint32_t timeout, struct csp_cmp_message *msg) { \ + return csp_cmp(node, timeout, _code, CMP_SIZE(_memb), msg); \ +} + +CMP_MESSAGE(CSP_CMP_IDENT, ident) +CMP_MESSAGE(CSP_CMP_ROUTE_SET, route_set) +CMP_MESSAGE(CSP_CMP_IF_STATS, if_stats) +CMP_MESSAGE(CSP_CMP_PEEK, peek) +CMP_MESSAGE(CSP_CMP_POKE, poke) +CMP_MESSAGE(CSP_CMP_CLOCK, clock) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_CMP_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_crc32.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_crc32.h new file mode 100644 index 00000000..a474eaf8 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_crc32.h @@ -0,0 +1,63 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_CRC32_H_ +#define _CSP_CRC32_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Generate precomputed CRC32 table + */ +void csp_crc32_gentab(void); + +/** + * Append CRC32 checksum to packet + * @param packet Packet to append checksum + * @param include_header use header in calculation (this will not modify the flags field) + * @return 0 on success, -1 on error + */ +int csp_crc32_append(csp_packet_t * packet, bool include_header); + +/** + * Verify CRC32 checksum on packet + * @param packet Packet to verify + * @param include_header use header in calculation (this will not modify the flags field) + * @return 0 if checksum is valid, -1 otherwise + */ +int csp_crc32_verify(csp_packet_t * packet, bool include_header); + +/** + * Calculate checksum for a given memory area + * @param data pointer to memory + * @param length length of memory to do checksum on + * @return return uint32_t checksum + */ +uint32_t csp_crc32_memory(const uint8_t * data, uint32_t length); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CSP_CRC32_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_debug.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_debug.h new file mode 100644 index 00000000..64429d49 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_debug.h @@ -0,0 +1,150 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_DEBUG_H_ +#define _CSP_DEBUG_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Debug levels */ +typedef enum { + CSP_ERROR = 0, + CSP_WARN = 1, + CSP_INFO = 2, + CSP_BUFFER = 3, + CSP_PACKET = 4, + CSP_PROTOCOL = 5, + CSP_LOCK = 6, +} csp_debug_level_t; + +/* Extract filename component from path */ +#define BASENAME(_file) ((strrchr(_file, '/') ? : (strrchr(_file, '\\') ? : _file)) + 1) + +/* Implement csp_assert_fail_action to override default failure action */ +extern void __attribute__((weak)) csp_assert_fail_action(const char *assertion, const char *file, int line); + +#ifndef NDEBUG + #define csp_assert(exp) \ + do { \ + if (!(exp)) { \ + const char *assertion = #exp; \ + const char *file = BASENAME(__FILE__); \ + int line = __LINE__; \ + printf("\E[1;31m[%02" PRIu8 "] Assertion \'%s\' failed in %s:%d\E[0m\r\n", \ + csp_get_address(), assertion, file, line); \ + if (csp_assert_fail_action) \ + csp_assert_fail_action(assertion, file, line); \ + } \ + } while (0) +#else + #define csp_assert(...) do {} while (0) +#endif + +#ifdef __AVR__ + #include + #include + #define CONSTSTR(data) PSTR(data) + #undef printf + #undef sscanf + #undef scanf + #undef sprintf + #undef snprintf + #define printf(s, ...) printf_P(PSTR(s), ## __VA_ARGS__) + #define sscanf(buf, s, ...) sscanf_P(buf, PSTR(s), ## __VA_ARGS__) + #define scanf(s, ...) scanf_P(PSTR(s), ## __VA_ARGS__) + #define sprintf(buf, s, ...) sprintf_P(buf, PSTR(s), ## __VA_ARGS__) + #define snprintf(buf, size, s, ...) snprintf_P(buf, size, PSTR(s), ## __VA_ARGS__) +#else + #define CONSTSTR(data) data +#endif + +#ifdef CSP_DEBUG + #define csp_debug(level, format, ...) do { do_csp_debug(level, CONSTSTR(format), ##__VA_ARGS__); } while(0) +#else + #define csp_debug(...) do {} while (0) +#endif + +#ifdef CSP_LOG_LEVEL_ERROR + #define csp_log_error(format, ...) csp_debug(CSP_ERROR, format, ##__VA_ARGS__) +#else + #define csp_log_error(...) do {} while (0) +#endif + +#ifdef CSP_LOG_LEVEL_WARN + #define csp_log_warn(format, ...) csp_debug(CSP_WARN, format, ##__VA_ARGS__) +#else + #define csp_log_warn(...) do {} while (0) +#endif + +#ifdef CSP_LOG_LEVEL_INFO + #define csp_log_info(format, ...) csp_debug(CSP_INFO, format, ##__VA_ARGS__) +#else + #define csp_log_info(...) do {} while (0) +#endif + +#ifdef CSP_LOG_LEVEL_DEBUG + #define csp_log_buffer(format, ...) csp_debug(CSP_BUFFER, format, ##__VA_ARGS__) + #define csp_log_packet(format, ...) csp_debug(CSP_PACKET, format, ##__VA_ARGS__) + #define csp_log_protocol(format, ...) csp_debug(CSP_PROTOCOL, format, ##__VA_ARGS__) + #define csp_log_lock(format, ...) csp_debug(CSP_LOCK, format, ##__VA_ARGS__) +#else + #define csp_log_buffer(...) do {} while (0) + #define csp_log_packet(...) do {} while (0) + #define csp_log_protocol(...) do {} while (0) + #define csp_log_lock(...) do {} while (0) +#endif + +/** + * This function should not be used directly, use csp_log_() macro instead + * @param level + * @param format + */ +void do_csp_debug(csp_debug_level_t level, const char *format, ...); + +/** + * Toggle debug level on/off + * @param level Level to toggle + */ +void csp_debug_toggle_level(csp_debug_level_t level); + +/** + * Set debug level + * @param level Level to set + * @param value New level value + */ +void csp_debug_set_level(csp_debug_level_t level, bool value); + +/** + * Get current debug level value + * @param level Level value to get + * @return Level value + */ +int csp_debug_get_level(csp_debug_level_t level); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_DEBUG_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_endian.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_endian.h new file mode 100644 index 00000000..e63a73c2 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_endian.h @@ -0,0 +1,170 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_ENDIAN_H_ +#define _CSP_ENDIAN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * Convert 16-bit integer from host byte order to network byte order + * @param h16 Host byte order 16-bit integer + */ +uint16_t csp_hton16(uint16_t h16); + +/** + * Convert 16-bit integer from host byte order to host byte order + * @param n16 Network byte order 16-bit integer + */ +uint16_t csp_ntoh16(uint16_t n16); + +/** + * Convert 32-bit integer from host byte order to network byte order + * @param h32 Host byte order 32-bit integer + */ +uint32_t csp_hton32(uint32_t h32); + +/** + * Convert 32-bit integer from host byte order to host byte order + * @param n32 Network byte order 32-bit integer + */ +uint32_t csp_ntoh32(uint32_t n32); + +/** + * Convert 64-bit integer from host byte order to network byte order + * @param h64 Host byte order 64-bit integer + */ +uint64_t csp_hton64(uint64_t h64); + +/** + * Convert 64-bit integer from host byte order to host byte order + * @param n64 Network byte order 64-bit integer + */ +uint64_t csp_ntoh64(uint64_t n64); + +/** + * Convert 16-bit integer from host byte order to big endian byte order + * @param h16 Host byte order 16-bit integer + */ +uint16_t csp_htobe16(uint16_t h16); + +/** + * Convert 16-bit integer from host byte order to little endian byte order + * @param h16 Host byte order 16-bit integer + */ +uint16_t csp_htole16(uint16_t h16); + +/** + * Convert 16-bit integer from big endian byte order to little endian byte order + * @param be16 Big endian byte order 16-bit integer + */ +uint16_t csp_betoh16(uint16_t be16); + +/** + * Convert 16-bit integer from little endian byte order to host byte order + * @param le16 Little endian byte order 16-bit integer + */ +uint16_t csp_letoh16(uint16_t le16); + +/** + * Convert 32-bit integer from host byte order to big endian byte order + * @param h32 Host byte order 32-bit integer + */ +uint32_t csp_htobe32(uint32_t h32); + +/** + * Convert 32-bit integer from little endian byte order to host byte order + * @param h32 Host byte order 32-bit integer + */ +uint32_t csp_htole32(uint32_t h32); + +/** + * Convert 32-bit integer from big endian byte order to host byte order + * @param be32 Big endian byte order 32-bit integer + */ +uint32_t csp_betoh32(uint32_t be32); + +/** + * Convert 32-bit integer from little endian byte order to host byte order + * @param le32 Little endian byte order 32-bit integer + */ +uint32_t csp_letoh32(uint32_t le32); + +/** + * Convert 64-bit integer from host byte order to big endian byte order + * @param h64 Host byte order 64-bit integer + */ +uint64_t csp_htobe64(uint64_t h64); + +/** + * Convert 64-bit integer from host byte order to little endian byte order + * @param h64 Host byte order 64-bit integer + */ +uint64_t csp_htole64(uint64_t h64); + +/** + * Convert 64-bit integer from big endian byte order to host byte order + * @param be64 Big endian byte order 64-bit integer + */ +uint64_t csp_betoh64(uint64_t be64); + +/** + * Convert 64-bit integer from little endian byte order to host byte order + * @param le64 Little endian byte order 64-bit integer + */ +uint64_t csp_letoh64(uint64_t le64); + +/** + * Convert float from host to network byte order + * @param f Float in host order + * @return Float in network order + */ +float csp_htonflt(float f); + +/** + * Convert float from network to host byte order + * @param f Float in network order + * @return Float in host order + */ +float csp_ntohflt(float f); + +/** + * Convert double from host to network byte order + * @param d Double in host order + * @return Double in network order + */ +double csp_htondbl(double d); + +/** + * Convert double from network to host order + * @param d Double in network order + * @return Double in host order + */ +double csp_ntohdbl(double d); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_ENDIAN_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_error.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_error.h new file mode 100644 index 00000000..31866607 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_error.h @@ -0,0 +1,50 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_ERROR_H_ +#define _CSP_ERROR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define CSP_ERR_NONE 0 /* No error */ +#define CSP_ERR_NOMEM -1 /* Not enough memory */ +#define CSP_ERR_INVAL -2 /* Invalid argument */ +#define CSP_ERR_TIMEDOUT -3 /* Operation timed out */ +#define CSP_ERR_USED -4 /* Resource already in use */ +#define CSP_ERR_NOTSUP -5 /* Operation not supported */ +#define CSP_ERR_BUSY -6 /* Device or resource busy */ +#define CSP_ERR_ALREADY -7 /* Connection already in progress */ +#define CSP_ERR_RESET -8 /* Connection reset */ +#define CSP_ERR_NOBUFS -9 /* No more buffer space available */ +#define CSP_ERR_TX -10 /* Transmission failed */ +#define CSP_ERR_DRIVER -11 /* Error in driver layer */ +#define CSP_ERR_AGAIN -12 /* Resource temporarily unavailable */ + +#define CSP_ERR_HMAC -100 /* HMAC failed */ +#define CSP_ERR_XTEA -101 /* XTEA failed */ +#define CSP_ERR_CRC32 -102 /* CRC32 failed */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_ERROR_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_iflist.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_iflist.h new file mode 100644 index 00000000..55875657 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_iflist.h @@ -0,0 +1,56 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CSP_IFLIST_H_ +#define CSP_IFLIST_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Add interface to list + * @param ifc Pointer to interface to add + */ +void csp_iflist_add(csp_iface_t *ifc); + +/** + * Lookup interface by name + * @param name String with interface name + * @return Pointer to interface or NULL if not found + */ +csp_iface_t * csp_iflist_get_by_name(const char *name); + +/** + * Print list of interfaces to stdout + */ +void csp_iflist_print(void); + +/** + * Return list of registered interfaces. + */ +csp_iface_t * csp_iflist_get(void); + +#ifdef __cplusplus +} +#endif +#endif /* CSP_IFLIST_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_interface.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_interface.h new file mode 100644 index 00000000..8f04bee3 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_interface.h @@ -0,0 +1,54 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_INTERFACE_H_ +#define _CSP_INTERFACE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * Inputs a new packet into the system + * This function is called from interface drivers ISR to route and accept packets. + * But it can also be called from a task, provided that the pxTaskWoken parameter is NULL! + * + * EXTREMELY IMPORTANT: + * pxTaskWoken arg must ALWAYS be NULL if called from task, + * and ALWAYS be NON NULL if called from ISR! + * If this condition is met, this call is completely thread-safe + * + * This function is fire and forget, it returns void, meaning + * that a packet will always be either accepted or dropped + * so the memory will always be freed. + * + * @param packet A pointer to the incoming packet + * @param interface A pointer to the incoming interface TX function. + * @param pxTaskWoken This must be a pointer a valid variable if called from ISR or NULL otherwise! + */ +void csp_qfifo_write(csp_packet_t *packet, csp_iface_t *interface, CSP_BASE_TYPE *pxTaskWoken); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_INTERFACE_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_platform.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_platform.h new file mode 100644 index 00000000..b33292e9 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_platform.h @@ -0,0 +1,56 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_PLATFORM_H_ +#define _CSP_PLATFORM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Set OS */ +#if defined(CSP_POSIX) || defined(CSP_WINDOWS) || defined(CSP_MACOSX) + #define CSP_BASE_TYPE int + #define CSP_MAX_DELAY (UINT32_MAX) + #define CSP_INFINITY (UINT32_MAX) + #define CSP_DEFINE_CRITICAL(lock) static csp_bin_sem_handle_t lock + #define CSP_INIT_CRITICAL(lock) ({(csp_bin_sem_create(&lock) == CSP_SEMAPHORE_OK) ? CSP_ERR_NONE : CSP_ERR_NOMEM;}) + #define CSP_ENTER_CRITICAL(lock) do { csp_bin_sem_wait(&lock, CSP_MAX_DELAY); } while(0) + #define CSP_EXIT_CRITICAL(lock) do { csp_bin_sem_post(&lock); } while(0) +#elif defined(CSP_FREERTOS) + #include "FreeRTOS.h" + #define CSP_BASE_TYPE portBASE_TYPE + #define CSP_MAX_DELAY portMAX_DELAY + #define CSP_INFINITY portMAX_DELAY + #define CSP_DEFINE_CRITICAL(lock) + #define CSP_INIT_CRITICAL(lock) ({CSP_ERR_NONE;}) + #define CSP_ENTER_CRITICAL(lock) do { portENTER_CRITICAL(); } while (0) + #define CSP_EXIT_CRITICAL(lock) do { portEXIT_CRITICAL(); } while (0) +#else + #error "OS must be either CSP_POSIX, CSP_MACOSX, CSP_FREERTOS OR CSP_WINDOWS" +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_PLATFORM_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_rtable.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_rtable.h new file mode 100644 index 00000000..34cd18e2 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_rtable.h @@ -0,0 +1,149 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CSP_RTABLE_H_ +#define CSP_RTABLE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CSP_NODE_MAC 0xFF +#define CSP_ROUTE_COUNT (CSP_ID_HOST_MAX + 2) +#define CSP_ROUTE_TABLE_SIZE 5 * CSP_ROUTE_COUNT + +/** + * Find outgoing interface in routing table + * @param id Destination node + * @return pointer to outgoing interface or NULL + */ +csp_iface_t * csp_rtable_find_iface(uint8_t id); + +/** + * Find MAC address associated with node + * @param id Destination node + * @return MAC address + */ +uint8_t csp_rtable_find_mac(uint8_t id); + +/** + * Setup routing entry + * @param node Host + * @param mask Number of bits in netmask + * @param ifc Interface + * @param mac MAC address + * @return CSP error type + */ +int csp_rtable_set(uint8_t node, uint8_t mask, csp_iface_t *ifc, uint8_t mac); + +/** + * Print routing table to stdout + */ +void csp_rtable_print(void); + + +/** + * Load the routing table from a buffer + * (deprecated, please use new csp_rtable_load) + * + * Warning: + * The table will be RAW from memory and contains direct pointers, not interface names. + * Therefore it's very important that a saved routing table is deleted after a firmware update + * + * @param route_table_in pointer to routing table buffer + */ +void csp_route_table_load(uint8_t route_table_in[CSP_ROUTE_TABLE_SIZE]); + +/** + * Save the routing table to a buffer + * (deprecated, please use new csp_rtable_save) + * + * Warning: + * The table will be RAW from memory and contains direct pointers, not interface names. + * Therefore it's very important that a saved routing table is deleted after a firmware update + * + * @param route_table_out pointer to routing table buffer + */ +void csp_route_table_save(uint8_t route_table_out[CSP_ROUTE_TABLE_SIZE]); + +/** + * Save routing table as a string to a buffer, which can be parsed + * again by csp_rtable_load. + * @param buffer pointer to buffer + * @param maxlen length of buffer + * @return length of saved string + */ +int csp_rtable_save(char * buffer, int maxlen); + +/** + * Load routing table from a string in the format + * %u/%u %s %u + * - Address + * - Netmask + * - Ifname + * - Mac Address (this field is optional) + * An example routing string is "0/0 I2C, 8/2 KISS" + * The string must be \0 null terminated + * @param buffer Pointer to string + */ +void csp_rtable_load(const char * buffer); + +/** + * Check string for valid routing table + * @param buffer Pointer to string + * @return number of valid entries found + */ +int csp_rtable_check(const char * buffer); + +/** + * Clear routing table: + * This could be done before load to ensure an entire clean table is loaded. + */ +void csp_rtable_clear(void); + +/** + * Setup routing entry to single node + * (deprecated, please use csp_rtable_set) + * + * @param node Host + * @param ifc Interface + * @param mac MAC address + * @return CSP error type + */ +#define csp_route_set(node, ifc, mac) csp_rtable_set(node, CSP_ID_HOST_SIZE, ifc, mac) + +/** + * Print routing table + * (deprecated, please use csp_rtable_print) + */ +#define csp_route_print_table() csp_rtable_print(); + +/** + * Print list of interfaces + * (deprecated, please use csp_iflist_print) + */ +#define csp_route_print_interfaces() csp_iflist_print(); + +#ifdef __cplusplus +} +#endif +#endif /* CSP_RTABLE_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_types.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_types.h new file mode 100644 index 00000000..a9cc28cd --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_types.h @@ -0,0 +1,235 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CSP_TYPES_H_ +#define CSP_TYPES_H_ + +#include +#include // -> CSP_HAVE_X defines +#ifdef CSP_HAVE_STDBOOL_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Make bool for compilers without stdbool.h */ +#ifndef CSP_HAVE_STDBOOL_H +#define bool int +#define false 0 +#define true !false +#endif + +/** + * RESERVED PORTS (SERVICES) + */ + +enum csp_reserved_ports_e { + CSP_CMP = 0, + CSP_PING = 1, + CSP_PS = 2, + CSP_MEMFREE = 3, + CSP_REBOOT = 4, + CSP_BUF_FREE = 5, + CSP_UPTIME = 6, + CSP_ANY = (CSP_MAX_BIND_PORT + 1), + CSP_PROMISC = (CSP_MAX_BIND_PORT + 2) +}; + +typedef enum { + CSP_PRIO_CRITICAL = 0, + CSP_PRIO_HIGH = 1, + CSP_PRIO_NORM = 2, + CSP_PRIO_LOW = 3, +} csp_prio_t; + +#define CSP_PRIORITIES (1 << CSP_ID_PRIO_SIZE) + +#ifdef CSP_USE_QOS +#define CSP_RX_QUEUE_LENGTH (CSP_CONN_QUEUE_LENGTH / CSP_PRIORITIES) +#define CSP_ROUTE_FIFOS CSP_PRIORITIES +#define CSP_RX_QUEUES CSP_PRIORITIES +#else +#define CSP_RX_QUEUE_LENGTH CSP_CONN_QUEUE_LENGTH +#define CSP_ROUTE_FIFOS 1 +#define CSP_RX_QUEUES 1 +#endif + +/** Size of bit-fields in CSP header */ +#define CSP_ID_PRIO_SIZE 2 +#define CSP_ID_HOST_SIZE 5 +#define CSP_ID_PORT_SIZE 6 +#define CSP_ID_FLAGS_SIZE 8 + +#define CSP_HEADER_BITS (CSP_ID_PRIO_SIZE + 2 * CSP_ID_HOST_SIZE + 2 * CSP_ID_PORT_SIZE + CSP_ID_FLAGS_SIZE) +#define CSP_HEADER_LENGTH (CSP_HEADER_BITS / 8) + +#if CSP_HEADER_BITS != 32 && __GNUC__ +#error "Header length must be 32 bits" +#endif + +/** Highest number to be entered in field */ +#define CSP_ID_PRIO_MAX ((1 << (CSP_ID_PRIO_SIZE)) - 1) +#define CSP_ID_HOST_MAX ((1 << (CSP_ID_HOST_SIZE)) - 1) +#define CSP_ID_PORT_MAX ((1 << (CSP_ID_PORT_SIZE)) - 1) +#define CSP_ID_FLAGS_MAX ((1 << (CSP_ID_FLAGS_SIZE)) - 1) + +/** Identifier field masks */ +#define CSP_ID_PRIO_MASK ((uint32_t) CSP_ID_PRIO_MAX << (CSP_ID_FLAGS_SIZE + 2 * CSP_ID_PORT_SIZE + 2 * CSP_ID_HOST_SIZE)) +#define CSP_ID_SRC_MASK ((uint32_t) CSP_ID_HOST_MAX << (CSP_ID_FLAGS_SIZE + 2 * CSP_ID_PORT_SIZE + 1 * CSP_ID_HOST_SIZE)) +#define CSP_ID_DST_MASK ((uint32_t) CSP_ID_HOST_MAX << (CSP_ID_FLAGS_SIZE + 2 * CSP_ID_PORT_SIZE)) +#define CSP_ID_DPORT_MASK ((uint32_t) CSP_ID_PORT_MAX << (CSP_ID_FLAGS_SIZE + 1 * CSP_ID_PORT_SIZE)) +#define CSP_ID_SPORT_MASK ((uint32_t) CSP_ID_PORT_MAX << (CSP_ID_FLAGS_SIZE)) +#define CSP_ID_FLAGS_MASK ((uint32_t) CSP_ID_FLAGS_MAX << (0)) + +#define CSP_ID_CONN_MASK (CSP_ID_SRC_MASK | CSP_ID_DST_MASK | CSP_ID_DPORT_MASK | CSP_ID_SPORT_MASK) + +/** + CSP identifier. +*/ +typedef union { + //! Entire identifier. + uint32_t ext; + //! Individual fields. + struct __attribute__((__packed__)) { +#if defined(CSP_BIG_ENDIAN) && !defined(CSP_LITTLE_ENDIAN) + unsigned int pri : CSP_ID_PRIO_SIZE; + unsigned int src : CSP_ID_HOST_SIZE; + unsigned int dst : CSP_ID_HOST_SIZE; + unsigned int dport : CSP_ID_PORT_SIZE; + unsigned int sport : CSP_ID_PORT_SIZE; + unsigned int flags : CSP_ID_FLAGS_SIZE; +#elif defined(CSP_LITTLE_ENDIAN) && !defined(CSP_BIG_ENDIAN) + unsigned int flags : CSP_ID_FLAGS_SIZE; + unsigned int sport : CSP_ID_PORT_SIZE; + unsigned int dport : CSP_ID_PORT_SIZE; + unsigned int dst : CSP_ID_HOST_SIZE; + unsigned int src : CSP_ID_HOST_SIZE; + unsigned int pri : CSP_ID_PRIO_SIZE; +#else +#error "Must define one of CSP_BIG_ENDIAN or CSP_LITTLE_ENDIAN in csp_platform.h" +#endif + }; +} csp_id_t; + +/** Broadcast address */ +#define CSP_BROADCAST_ADDR CSP_ID_HOST_MAX + +/** Default routing address */ +#define CSP_DEFAULT_ROUTE (CSP_ID_HOST_MAX + 1) + +/** CSP Flags */ +#define CSP_FRES1 0x80 // Reserved for future use +#define CSP_FRES2 0x40 // Reserved for future use +#define CSP_FRES3 0x20 // Reserved for future use +#define CSP_FFRAG 0x10 // Use fragmentation +#define CSP_FHMAC 0x08 // Use HMAC verification +#define CSP_FXTEA 0x04 // Use XTEA encryption +#define CSP_FRDP 0x02 // Use RDP protocol +#define CSP_FCRC32 0x01 // Use CRC32 checksum + +/** CSP Socket options */ +#define CSP_SO_NONE 0x0000 // No socket options +#define CSP_SO_RDPREQ 0x0001 // Require RDP +#define CSP_SO_RDPPROHIB 0x0002 // Prohibit RDP +#define CSP_SO_HMACREQ 0x0004 // Require HMAC +#define CSP_SO_HMACPROHIB 0x0008 // Prohibit HMAC +#define CSP_SO_XTEAREQ 0x0010 // Require XTEA +#define CSP_SO_XTEAPROHIB 0x0020 // Prohibit HMAC +#define CSP_SO_CRC32REQ 0x0040 // Require CRC32 +#define CSP_SO_CRC32PROHIB 0x0080 // Prohibit CRC32 +#define CSP_SO_CONN_LESS 0x0100 // Enable Connection Less mode +#define CSP_SO_INTERNAL_LISTEN 0x1000 // Internal flag: listen called on socket + +/** CSP Connect options */ +#define CSP_O_NONE CSP_SO_NONE // No connection options +#define CSP_O_RDP CSP_SO_RDPREQ // Enable RDP +#define CSP_O_NORDP CSP_SO_RDPPROHIB // Disable RDP +#define CSP_O_HMAC CSP_SO_HMACREQ // Enable HMAC +#define CSP_O_NOHMAC CSP_SO_HMACPROHIB // Disable HMAC +#define CSP_O_XTEA CSP_SO_XTEAREQ // Enable XTEA +#define CSP_O_NOXTEA CSP_SO_XTEAPROHIB // Disable XTEA +#define CSP_O_CRC32 CSP_SO_CRC32REQ // Enable CRC32 +#define CSP_O_NOCRC32 CSP_SO_CRC32PROHIB // Disable CRC32 + +/** + * CSP PACKET STRUCTURE + * Note: This structure is constructed to fit + * with all interface frame types in order to + * have buffer reuse + */ +typedef struct __attribute__((__packed__)) { + uint8_t padding[CSP_PADDING_BYTES]; /**< Interface dependent padding */ + uint16_t length; /**< Length field must be just before CSP ID */ + csp_id_t id; /**< CSP id must be just before data */ + union { + uint8_t data[0]; /**< This just points to the rest of the buffer, without a size indication. */ + uint16_t data16[0]; /**< The data 16 and 32 types makes it easy to reference an integer (properly aligned) */ + uint32_t data32[0]; /**< without the compiler warning about strict aliasing rules. */ + }; +} csp_packet_t; + +/** Interface TX function */ +struct csp_iface_s; +typedef int (*nexthop_t)(struct csp_iface_s * interface, csp_packet_t *packet, uint32_t timeout); + +/** Interface struct */ +typedef struct csp_iface_s { + const char *name; /**< Interface name (keep below 10 bytes) */ + void * driver; /**< Pointer to interface handler structure */ + nexthop_t nexthop; /**< Next hop function */ + uint16_t mtu; /**< Maximum Transmission Unit of interface */ + uint8_t split_horizon_off; /**< Disable the route-loop prevention on if */ + uint32_t tx; /**< Successfully transmitted packets */ + uint32_t rx; /**< Successfully received packets */ + uint32_t tx_error; /**< Transmit errors */ + uint32_t rx_error; /**< Receive errors */ + uint32_t drop; /**< Dropped packets */ + uint32_t autherr; /**< Authentication errors */ + uint32_t frame; /**< Frame format errors */ + uint32_t txbytes; /**< Transmitted bytes */ + uint32_t rxbytes; /**< Received bytes */ + uint32_t irq; /**< Interrupts */ + struct csp_iface_s *next; /**< Next interface */ +} csp_iface_t; + +/** + * This define must be equal to the size of the packet overhead in csp_packet_t. + * It is used in csp_buffer_get() to check the allocated buffer size against + * the required buffer size. + */ +#define CSP_BUFFER_PACKET_OVERHEAD (sizeof(csp_packet_t) - sizeof(((csp_packet_t *)0)->data)) + +/** Forward declaration of socket and connection structures */ +typedef struct csp_conn_s csp_socket_t; +typedef struct csp_conn_s csp_conn_t; + +#define CSP_HOSTNAME_LEN 20 +#define CSP_MODEL_LEN 30 + +/* CSP_REBOOT magic values */ +#define CSP_REBOOT_MAGIC 0x80078007 +#define CSP_REBOOT_SHUTDOWN_MAGIC 0xD1E5529A + +#ifdef __cplusplus +} +#endif +#endif /* CSP_TYPES_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/drivers/can_socketcan.h b/gomspace/libgscsp/lib/libcsp/include/csp/drivers/can_socketcan.h new file mode 100644 index 00000000..0963b414 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/drivers/can_socketcan.h @@ -0,0 +1,22 @@ +/* + * can_socketcan.h + * + * Created on: Feb 6, 2017 + * Author: johan + */ + +#ifndef LIB_CSP_INCLUDE_CSP_DRIVERS_CAN_SOCKETCAN_H_ +#define LIB_CSP_INCLUDE_CSP_DRIVERS_CAN_SOCKETCAN_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +csp_iface_t * csp_can_socketcan_init(const char * ifc, int bitrate, int promisc); + +#ifdef __cplusplus +} +#endif +#endif /* LIB_CSP_INCLUDE_CSP_DRIVERS_CAN_SOCKETCAN_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/drivers/i2c.h b/gomspace/libgscsp/lib/libcsp/include/csp/drivers/i2c.h new file mode 100644 index 00000000..3cf605ee --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/drivers/i2c.h @@ -0,0 +1,120 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file + * Common I2C interface, + * This file is derived from the Gomspace I2C driver, + * + */ + +#ifndef I2C_H_ +#define I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The return value of the driver is a bit strange, + * It should return E_NO_ERR if successfull and the value is -1 + */ +#define E_NO_ERR -1 + +/** + * Maximum transfer length on I2C + */ +#define I2C_MTU 256 + +/** + I2C device modes + @{ +*/ +/** + I2C Master mode. +*/ +#define I2C_MASTER 0 +/** + I2C Slave mode. +*/ +#define I2C_SLAVE 1 +/**@}*/ + +/** + Data structure for I2C frames. + This structs fits on top of #csp_packet_t, removing the need for copying data. +*/ +typedef struct __attribute__((packed)) i2c_frame_s { + //! Not used by CSP + uint8_t padding; + //! Not used by CSP - cleared before Tx + uint8_t retries; + //! Not used by CSP + uint32_t reserved; + //! Destination address + uint8_t dest; + //! Not used by CSP - cleared before Tx + uint8_t len_rx; + //! Length of \a data part + uint16_t len; + //! CSP data + uint8_t data[I2C_MTU]; +} i2c_frame_t; + +/** + Callback for receiving data. + + @param[in] frame received I2C frame + @param[out] pxTaskWoken can be set, if context switch is required due to received data. +*/ +typedef void (*i2c_callback_t) (i2c_frame_t * frame, void * pxTaskWoken); + +/** + Initialise the I2C driver + + Functions is called by csp_i2c_init(). + + @param handle Which I2C bus (if more than one exists) + @param mode I2C device mode. Must be either I2C_MASTER or I2C_SLAVE + @param addr Own slave address + @param speed Bus speed in kbps + @param queue_len_tx Length of transmit queue + @param queue_len_rx Length of receive queue + @param callback If this value is set, the driver will call this function instead of using an RX queue + @return Error code +*/ +int i2c_init(int handle, int mode, uint8_t addr, uint16_t speed, int queue_len_tx, int queue_len_rx, i2c_callback_t callback); + +/** + User I2C transmit function. + + Called by CSP, when sending message over I2C. + + @param handle Handle to the device + @param frame Pointer to I2C frame + @param timeout Ticks to wait + @return Error code +*/ +int i2c_send(int handle, i2c_frame_t * frame, uint16_t timeout); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/drivers/usart.h b/gomspace/libgscsp/lib/libcsp/include/csp/drivers/usart.h new file mode 100644 index 00000000..d2da8448 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/drivers/usart.h @@ -0,0 +1,107 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file + * Common USART interface, + * This file is derived from the Gomspace USART driver, + * the main difference is the assumption that only one USART will be present on a PC + */ + +#ifndef USART_H_ +#define USART_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Usart configuration, to be used with the usart_init call. +*/ +struct usart_conf { + //! USART device. + const char *device; + //! bits per second. + uint32_t baudrate; + //! Number of data bits. + uint8_t databits; + //! Number of stop bits. + uint8_t stopbits; + //! Parity setting. + uint8_t paritysetting; + //! Enable parity checking (Windows only). + uint8_t checkparity; +}; + +/** + Initialise UART with the usart_conf data structure + @param[in] conf full configuration structure +*/ +void usart_init(struct usart_conf *conf); + +/** + In order to catch incoming chars use the callback. + Only one callback per interface. + @param[in] handle usart[0,1,2,3] + @param[in] callback function pointer +*/ +typedef void (*usart_callback_t) (uint8_t *buf, int len, void *pxTaskWoken); + +/** + Set callback for receiving data. +*/ +void usart_set_callback(usart_callback_t callback); + +/** + Insert a character to the RX buffer of a usart + + @param[in] c character to insert + @param[out] pxTaskWoken can be set, if context switch is required due to received data. +*/ +void usart_insert(char c, void *pxTaskWoken); + +/** + Polling putchar (stdin). + + @param[in] c Character to transmit +*/ +void usart_putc(char c); + +/** + Send char buffer on UART (stdout). + + @param[in] buf Pointer to data + @param[in] len Length of data +*/ +void usart_putstr(char *buf, int len); + +/** + Buffered getchar (stdin). + + @return Character received +*/ +char usart_getc(void); + +#ifdef __cplusplus +} +#endif +#endif /* USART_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_can.h b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_can.h new file mode 100644 index 00000000..229671f2 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_can.h @@ -0,0 +1,76 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_IF_CAN_H_ +#define _CSP_IF_CAN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include + +/* CAN header macros */ +#define CFP_HOST_SIZE 5 +#define CFP_TYPE_SIZE 1 +#define CFP_REMAIN_SIZE 8 +#define CFP_ID_SIZE 10 + +/* Macros for extracting header fields */ +#define CFP_FIELD(id,rsiz,fsiz) ((uint32_t)((uint32_t)((id) >> (rsiz)) & (uint32_t)((1 << (fsiz)) - 1))) +#define CFP_SRC(id) CFP_FIELD(id, CFP_HOST_SIZE + CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE, CFP_HOST_SIZE) +#define CFP_DST(id) CFP_FIELD(id, CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE, CFP_HOST_SIZE) +#define CFP_TYPE(id) CFP_FIELD(id, CFP_REMAIN_SIZE + CFP_ID_SIZE, CFP_TYPE_SIZE) +#define CFP_REMAIN(id) CFP_FIELD(id, CFP_ID_SIZE, CFP_REMAIN_SIZE) +#define CFP_ID(id) CFP_FIELD(id, 0, CFP_ID_SIZE) + +/* Macros for building CFP headers */ +#define CFP_MAKE_FIELD(id,fsiz,rsiz) ((uint32_t)(((id) & (uint32_t)((uint32_t)(1 << (fsiz)) - 1)) << (rsiz))) +#define CFP_MAKE_SRC(id) CFP_MAKE_FIELD(id, CFP_HOST_SIZE, CFP_HOST_SIZE + CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE) +#define CFP_MAKE_DST(id) CFP_MAKE_FIELD(id, CFP_HOST_SIZE, CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE) +#define CFP_MAKE_TYPE(id) CFP_MAKE_FIELD(id, CFP_TYPE_SIZE, CFP_REMAIN_SIZE + CFP_ID_SIZE) +#define CFP_MAKE_REMAIN(id) CFP_MAKE_FIELD(id, CFP_REMAIN_SIZE, CFP_ID_SIZE) +#define CFP_MAKE_ID(id) CFP_MAKE_FIELD(id, CFP_ID_SIZE, 0) + +/* Mask to uniquely separate connections */ +#define CFP_ID_CONN_MASK (CFP_MAKE_SRC((uint32_t)(1 << CFP_HOST_SIZE) - 1) | \ + CFP_MAKE_DST((uint32_t)(1 << CFP_HOST_SIZE) - 1) | \ + CFP_MAKE_ID((uint32_t)(1 << CFP_ID_SIZE) - 1)) + +/** + Default Maximum Transmission Unit (MTU) for CSP over CAN. + Maximum value is 2042 bytes. +*/ +#define CSP_CAN_MTU 256 + +int csp_can_rx(csp_iface_t *interface, uint32_t id, const uint8_t * data, uint8_t dlc, CSP_BASE_TYPE *task_woken); +int csp_can_tx(csp_iface_t *interface, csp_packet_t *packet, uint32_t timeout); + +/* Must be implemented by the driver */ +int csp_can_tx_frame(csp_iface_t *interface, uint32_t id, const uint8_t * data, uint8_t dlc); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CSP_IF_CAN_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_i2c.h b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_i2c.h new file mode 100644 index 00000000..c2169843 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_i2c.h @@ -0,0 +1,51 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_IF_I2C_H_ +#define _CSP_IF_I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include +#include + +extern csp_iface_t csp_if_i2c; + +/** + * Capture I2C RX events for CSP + * @param opt_addr local i2c address + * @param handle which i2c device to use + * @param speed interface speed in kHz (normally 100 or 400) + * @return csp_error.h code + */ +int csp_i2c_init(uint8_t opt_addr, int handle, int speed); + +void csp_i2c_rx(i2c_frame_t * frame, void * pxTaskWoken); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CSP_IF_I2C_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_kiss.h b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_kiss.h new file mode 100644 index 00000000..f164cad1 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_kiss.h @@ -0,0 +1,110 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_IF_KISS_H_ +#define _CSP_IF_KISS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include + +/** + * The KISS interface relies on the USART callback in order to parse incoming + * messaged from the serial interface. The USART callback however does not + * support passing the handle number of the responding USART, so you need to implement + * a USART callback for each handle and then call kiss_rx subsequently. + * + * In order to initialize the KISS interface. Fist call kiss_init() and then + * setup your usart to call csp_kiss_rx when new data is available. + * + * When a byte is not a part of a kiss packet, it will be returned to your + * usart driver using the usart_insert funtion that you provide. + * + * @param csp_iface pointer to interface + * @param buf pointer to incoming data + * @param len length of incoming data + * @param pxTaskWoken NULL if task context, pointer to variable if ISR + */ +void csp_kiss_rx(csp_iface_t * interface, uint8_t *buf, int len, void *pxTaskWoken); + +/** + * The putc function is used by the kiss interface to send + * a string of data to the serial port. This function must + * be implemented by the user, and passed to the kiss + * interface through the kiss_init function. + * @param buf byte to push + */ +typedef void (*csp_kiss_putc_f)(char buf); + +/** + * The characters not accepted by the kiss interface, are discarded + * using this function, which must be implemented by the user + * and passed through the kiss_init function. + * + * This reject function is typically used to display ASCII strings + * sent over the serial port, which are not in KISS format. Such as + * debugging information. + * + * @param c rejected character + * @param pxTaskWoken NULL if task context, pointer to variable if ISR + */ +typedef void (*csp_kiss_discard_f)(char c, void *pxTaskWoken); + +typedef enum { + KISS_MODE_NOT_STARTED, + KISS_MODE_STARTED, + KISS_MODE_ESCAPED, + KISS_MODE_SKIP_FRAME, +} kiss_mode_e; + +/** + * This structure should be statically allocated by the user + * and passed to the kiss interface during the init function + * no member information should be changed + */ +typedef struct csp_kiss_handle_s { + //! Put character on usart (tx). + csp_kiss_putc_f kiss_putc; + //! Discard - not KISS data (rx). + csp_kiss_discard_f kiss_discard; + //! Internal KISS state. + unsigned int rx_length; + //! Internal KISS state. + kiss_mode_e rx_mode; + //! Internal KISS state. + unsigned int rx_first; + //! Not used. + volatile unsigned char *rx_cbuf; + //! Internal KISS state. + csp_packet_t * rx_packet; +} csp_kiss_handle_t; + +void csp_kiss_init(csp_iface_t * csp_iface, csp_kiss_handle_t * csp_kiss_handle, csp_kiss_putc_f kiss_putc_f, csp_kiss_discard_f kiss_discard_f, const char * name); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CSP_IF_KISS_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_lo.h b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_lo.h new file mode 100644 index 00000000..793c45ac --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_lo.h @@ -0,0 +1,38 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_IF_LO_H_ +#define _CSP_IF_LO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* CSP includes */ +#include +#include + +extern csp_iface_t csp_if_lo; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_IF_LO_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_zmqhub.h b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_zmqhub.h new file mode 100644 index 00000000..f9ab43bf --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_zmqhub.h @@ -0,0 +1,26 @@ +#ifndef CSP_IF_ZMQHUB_H_ +#define CSP_IF_ZMQHUB_H_ + +#include + +extern csp_iface_t csp_if_zmqhub; + +/** + * Setup ZMQ interface + * @param addr only receive messages matching this address (255 means all) + * @param host Pointer to string containing zmqproxy host + * @return CSP_ERR + */ +int csp_zmqhub_init(uint8_t addr, const char * host); + +/** + * Setup ZMQ interface + * @param addr only receive messages matching this address (255 means all) + * @param publisher_endpoint Pointer to string containing zmqproxy publisher endpoint + * @param subscriber_endpoint Pointer to string containing zmqproxy subscriber endpoint + * @return CSP_ERR + */ +int csp_zmqhub_init_w_endpoints(uint8_t addr, const char * publisher_url, + const char * subscriber_url); + +#endif /* CSP_IF_ZMQHUB_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_malloc.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_malloc.c new file mode 100644 index 00000000..97e5c8f4 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_malloc.c @@ -0,0 +1,33 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +/* FreeRTOS includes */ +#include + +void * csp_malloc(size_t size) { + return pvPortMalloc(size); +} + +void csp_free(void *ptr) { + vPortFree(ptr); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_queue.c new file mode 100644 index 00000000..44efd0eb --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_queue.c @@ -0,0 +1,66 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +/* FreeRTOS includes */ +#include +#include + +/* CSP includes */ +#include + +#include + +csp_queue_handle_t csp_queue_create(int length, size_t item_size) { + return xQueueCreate(length, item_size); +} + +void csp_queue_remove(csp_queue_handle_t queue) { + vQueueDelete(queue); +} + +int csp_queue_enqueue(csp_queue_handle_t handle, void * value, uint32_t timeout) { + if (timeout != CSP_MAX_DELAY) + timeout = timeout / portTICK_RATE_MS; + return xQueueSendToBack(handle, value, timeout); +} + +int csp_queue_enqueue_isr(csp_queue_handle_t handle, void * value, CSP_BASE_TYPE * task_woken) { + return xQueueSendToBackFromISR(handle, value, task_woken); +} + +int csp_queue_dequeue(csp_queue_handle_t handle, void * buf, uint32_t timeout) { + if (timeout != CSP_MAX_DELAY) + timeout = timeout / portTICK_RATE_MS; + return xQueueReceive(handle, buf, timeout); +} + +int csp_queue_dequeue_isr(csp_queue_handle_t handle, void * buf, CSP_BASE_TYPE * task_woken) { + return xQueueReceiveFromISR(handle, buf, task_woken); +} + +int csp_queue_size(csp_queue_handle_t handle) { + return uxQueueMessagesWaiting(handle); +} + +int csp_queue_size_isr(csp_queue_handle_t handle) { + return uxQueueMessagesWaitingFromISR(handle); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_semaphore.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_semaphore.c new file mode 100644 index 00000000..b91757e5 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_semaphore.c @@ -0,0 +1,96 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +/* FreeRTOS includes */ +#include +#include + +/* CSP includes */ +#include + +#include +#include +#include + +int csp_mutex_create(csp_mutex_t * mutex) { + *mutex = xSemaphoreCreateMutex(); + if (*mutex) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_mutex_remove(csp_mutex_t * mutex) { + return csp_bin_sem_remove(mutex); +} + +int csp_mutex_lock(csp_mutex_t * mutex, uint32_t timeout) { + return csp_bin_sem_wait(mutex, timeout); +} + +int csp_mutex_unlock(csp_mutex_t * mutex) { + return csp_bin_sem_post(mutex); +} + +int csp_bin_sem_create(csp_bin_sem_handle_t * sem) { + vSemaphoreCreateBinary(*sem); + return CSP_SEMAPHORE_OK; +} + +int csp_bin_sem_remove(csp_bin_sem_handle_t * sem) { + if ((sem != NULL) && (*sem != NULL)) { + csp_queue_remove(*sem); + } + return CSP_SEMAPHORE_OK; +} + +int csp_bin_sem_wait(csp_bin_sem_handle_t * sem, uint32_t timeout) { + csp_log_lock("Wait: %p", sem); + if (timeout != CSP_MAX_DELAY) + timeout = timeout / portTICK_RATE_MS; + if (xSemaphoreTake(*sem, timeout) == pdPASS) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_bin_sem_post(csp_bin_sem_handle_t * sem) { + csp_log_lock("Post: %p", sem); + if (xSemaphoreGive(*sem) == pdPASS) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_bin_sem_post_isr(csp_bin_sem_handle_t * sem, CSP_BASE_TYPE * task_woken) { + csp_log_lock("Post: %p", sem); + if (xSemaphoreGiveFromISR(*sem, task_woken) == pdPASS) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_system.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_system.c new file mode 100644 index 00000000..a81c84b4 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_system.c @@ -0,0 +1,139 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +#include +#include + +#include + +int csp_sys_tasklist(char * out) { +#if (tskKERNEL_VERSION_MAJOR < 8) + vTaskList((signed portCHAR *) out); +#else + vTaskList(out); +#endif + return CSP_ERR_NONE; +} + +int csp_sys_tasklist_size(void) { + return 40 * uxTaskGetNumberOfTasks(); +} + +uint32_t csp_sys_memfree(void) { + + uint32_t total = 0, max = UINT32_MAX, size; + void * pmem; + + /* If size_t is less than 32 bits, start with 10 KiB */ + size = sizeof(uint32_t) > sizeof(size_t) ? 10000 : 1000000; + + while (1) { + pmem = pvPortMalloc(size + total); + if (pmem == NULL) { + max = size + total; + size = size / 2; + } else { + total += size; + if (total + size >= max) + size = size / 2; + vPortFree(pmem); + } + if (size < 32) break; + } + + return total; +} + +int csp_sys_reboot(void) { + + extern void __attribute__((weak)) cpu_set_reset_cause(unsigned int); + if (cpu_set_reset_cause) + cpu_set_reset_cause(1); + + extern void __attribute__((weak)) cpu_reset(void); + if (cpu_reset) { + cpu_reset(); + while (1); + } + + csp_log_error("Failed to reboot"); + + return CSP_ERR_INVAL; +} + +int csp_sys_shutdown(void) { + + extern void __attribute__((weak)) cpu_shutdown(void); + if (cpu_shutdown) { + cpu_shutdown(); + while (1); + } + + csp_log_error("Failed to shutdown"); + + return CSP_ERR_INVAL; +} + +void csp_sys_set_color(csp_color_t color) { + + unsigned int color_code, modifier_code; + switch (color & COLOR_MASK_COLOR) { + case COLOR_BLACK: + color_code = 30; break; + case COLOR_RED: + color_code = 31; break; + case COLOR_GREEN: + color_code = 32; break; + case COLOR_YELLOW: + color_code = 33; break; + case COLOR_BLUE: + color_code = 34; break; + case COLOR_MAGENTA: + color_code = 35; break; + case COLOR_CYAN: + color_code = 36; break; + case COLOR_WHITE: + color_code = 37; break; + case COLOR_RESET: + default: + color_code = 0; break; + } + + switch (color & COLOR_MASK_MODIFIER) { + case COLOR_BOLD: + modifier_code = 1; break; + case COLOR_UNDERLINE: + modifier_code = 2; break; + case COLOR_BLINK: + modifier_code = 3; break; + case COLOR_HIDE: + modifier_code = 4; break; + case COLOR_NORMAL: + default: + modifier_code = 0; break; + } + + printf("\033[%u;%um", modifier_code, color_code); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_thread.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_thread.c new file mode 100644 index 00000000..af8296cd --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_thread.c @@ -0,0 +1,38 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +/* CSP includes */ +#include + +#include + +int csp_thread_create(csp_thread_return_t (* routine)(void *), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle) { +#if (tskKERNEL_VERSION_MAJOR >= 8) + portBASE_TYPE ret = xTaskCreate(routine, thread_name, stack_depth, parameters, priority, handle); +#else + portBASE_TYPE ret = xTaskCreate(routine, (signed char *) thread_name, stack_depth, parameters, priority, handle); +#endif + if (ret != pdTRUE) + return CSP_ERR_NOMEM; + return CSP_ERR_NONE; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_time.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_time.c new file mode 100644 index 00000000..fd54a8cb --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_time.c @@ -0,0 +1,46 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +/* FreeRTOS includes */ +#include +#include + +/* CSP includes */ +#include + +#include + +uint32_t csp_get_ms(void) { + return (uint32_t)(xTaskGetTickCount() * (1000/configTICK_RATE_HZ)); +} + +uint32_t csp_get_ms_isr(void) { + return (uint32_t)(xTaskGetTickCountFromISR() * (1000/configTICK_RATE_HZ)); +} + +uint32_t csp_get_s(void) { + return (uint32_t)(xTaskGetTickCount()/configTICK_RATE_HZ); +} + +uint32_t csp_get_s_isr(void) { + return (uint32_t)(xTaskGetTickCountFromISR()/configTICK_RATE_HZ); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_malloc.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_malloc.c new file mode 100644 index 00000000..95bb8cc7 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_malloc.c @@ -0,0 +1,31 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +void * csp_malloc(size_t size) { + return malloc(size); +} + +void csp_free(void *ptr) { + free(ptr); +} + diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_queue.c new file mode 100644 index 00000000..a2fb1b4f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_queue.c @@ -0,0 +1,64 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +/* CSP includes */ +#include + +#include +#include + + +csp_queue_handle_t csp_queue_create(int length, size_t item_size) { + return pthread_queue_create(length, item_size); +} + +void csp_queue_remove(csp_queue_handle_t queue) { + return pthread_queue_delete(queue); +} + +int csp_queue_enqueue(csp_queue_handle_t handle, void *value, uint32_t timeout) { + return pthread_queue_enqueue(handle, value, timeout); +} + +int csp_queue_enqueue_isr(csp_queue_handle_t handle, void * value, CSP_BASE_TYPE * task_woken) { + if (task_woken != NULL) + *task_woken = 0; + return csp_queue_enqueue(handle, value, 0); +} + +int csp_queue_dequeue(csp_queue_handle_t handle, void *buf, uint32_t timeout) { + return pthread_queue_dequeue(handle, buf, timeout); +} + +int csp_queue_dequeue_isr(csp_queue_handle_t handle, void *buf, CSP_BASE_TYPE * task_woken) { + *task_woken = 0; + return csp_queue_dequeue(handle, buf, 0); +} + +int csp_queue_size(csp_queue_handle_t handle) { + return pthread_queue_items(handle); +} + +int csp_queue_size_isr(csp_queue_handle_t handle) { + return pthread_queue_items(handle); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_semaphore.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_semaphore.c new file mode 100644 index 00000000..915447f3 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_semaphore.c @@ -0,0 +1,105 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* CSP includes */ +#include + +#include + +int csp_mutex_create(csp_mutex_t * mutex) { + csp_log_lock("Mutex init: %p", mutex); + *mutex = pthread_queue_create(1, sizeof(int)); + if (mutex) { + int dummy = 0; + pthread_queue_enqueue(*mutex, &dummy, 0); + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_mutex_remove(csp_mutex_t * mutex) { + pthread_queue_delete(*mutex); + return CSP_SEMAPHORE_OK; +} + +int csp_mutex_lock(csp_mutex_t * mutex, uint32_t timeout) { + + int ret; + csp_log_lock("Wait: %p timeout %"PRIu32, mutex, timeout); + + if (timeout == CSP_INFINITY) { + /* TODO: fix this to be infinite */ + int dummy = 0; + if (pthread_queue_dequeue(*mutex, &dummy, timeout) == PTHREAD_QUEUE_OK) + ret = CSP_MUTEX_OK; + else + ret = CSP_MUTEX_ERROR; + } else { + int dummy = 0; + if (pthread_queue_dequeue(*mutex, &dummy, timeout) == PTHREAD_QUEUE_OK) + ret = CSP_MUTEX_OK; + else + ret = CSP_MUTEX_ERROR; + } + + return ret == CSP_MUTEX_ERROR ? CSP_SEMAPHORE_ERROR : CSP_SEMAPHORE_OK; +} + +int csp_mutex_unlock(csp_mutex_t * mutex) { + int dummy = 0; + if (pthread_queue_enqueue(*mutex, &dummy, 0) == PTHREAD_QUEUE_OK) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_bin_sem_create(csp_bin_sem_handle_t * sem) { + return csp_mutex_create(sem); +} + +int csp_bin_sem_remove(csp_bin_sem_handle_t * sem) { + return csp_mutex_remove(sem); +} + +int csp_bin_sem_wait(csp_bin_sem_handle_t * sem, uint32_t timeout) { + return csp_mutex_lock(sem, timeout); +} + +int csp_bin_sem_post(csp_bin_sem_handle_t * sem) { + return csp_mutex_unlock(sem); +} + +int csp_bin_sem_post_isr(csp_bin_sem_handle_t * sem, CSP_BASE_TYPE * task_woken) { + return csp_mutex_unlock(sem); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_system.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_system.c new file mode 100644 index 00000000..834cb210 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_system.c @@ -0,0 +1,99 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +#include +#include + +#include + +int csp_sys_tasklist(char * out) { + strcpy(out, "Tasklist not available on OSX"); + return CSP_ERR_NONE; +} + +int csp_sys_tasklist_size(void) { + return 100; +} + +uint32_t csp_sys_memfree(void) { + /* TODO: Fix memory free on OSX */ + uint32_t total = 0; + return total; +} + +int csp_sys_reboot(void) { + /* TODO: Fix reboot on OSX */ + csp_log_error("Failed to reboot"); + + return CSP_ERR_INVAL; +} + +int csp_sys_shutdown(void) { + /* TODO: Fix shutdown on OSX */ + csp_log_error("Failed to shutdown"); + + return CSP_ERR_INVAL; +} + +void csp_sys_set_color(csp_color_t color) { + + unsigned int color_code, modifier_code; + switch (color & COLOR_MASK_COLOR) { + case COLOR_BLACK: + color_code = 30; break; + case COLOR_RED: + color_code = 31; break; + case COLOR_GREEN: + color_code = 32; break; + case COLOR_YELLOW: + color_code = 33; break; + case COLOR_BLUE: + color_code = 34; break; + case COLOR_MAGENTA: + color_code = 35; break; + case COLOR_CYAN: + color_code = 36; break; + case COLOR_WHITE: + color_code = 37; break; + case COLOR_RESET: + default: + color_code = 0; break; + } + + switch (color & COLOR_MASK_MODIFIER) { + case COLOR_BOLD: + modifier_code = 1; break; + case COLOR_UNDERLINE: + modifier_code = 2; break; + case COLOR_BLINK: + modifier_code = 3; break; + case COLOR_HIDE: + modifier_code = 4; break; + case COLOR_NORMAL: + default: + modifier_code = 0; break; + } + + printf("\033[%u;%um", modifier_code, color_code); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_thread.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_thread.c new file mode 100644 index 00000000..ed64856a --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_thread.c @@ -0,0 +1,31 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +/* CSP includes */ +#include + +#include + +int csp_thread_create(csp_thread_return_t (* routine)(void *), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle) { + return pthread_create(handle, NULL, routine, parameters); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_time.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_time.c new file mode 100644 index 00000000..a53f27e6 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_time.c @@ -0,0 +1,65 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +/* CSP includes */ +#include + +#include + +uint32_t csp_get_ms(void) { + struct timespec ts; + + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + ts.tv_sec = mts.tv_sec; + ts.tv_nsec = mts.tv_nsec; + + return (uint32_t)(ts.tv_sec*1000+ts.tv_nsec/1000000); +} + +uint32_t csp_get_ms_isr(void) { + return csp_get_ms(); +} + +uint32_t csp_get_s(void) { + struct timespec ts; + + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + ts.tv_sec = mts.tv_sec; + ts.tv_nsec = mts.tv_nsec; + + return (uint32_t)ts.tv_sec; +} + +uint32_t csp_get_s_isr(void) { + return csp_get_s(); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/pthread_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/pthread_queue.c new file mode 100644 index 00000000..c4ac8c1d --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/pthread_queue.c @@ -0,0 +1,179 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Inspired by c-pthread-queue by Matthew Dickinson +http://code.google.com/p/c-pthread-queue/ +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* CSP includes */ +#include + +pthread_queue_t * pthread_queue_create(int length, size_t item_size) { + + pthread_queue_t * q = malloc(sizeof(pthread_queue_t)); + + if (q != NULL) { + q->buffer = malloc(length*item_size); + if (q->buffer != NULL) { + q->size = length; + q->item_size = item_size; + q->items = 0; + q->in = 0; + q->out = 0; + if (pthread_mutex_init(&(q->mutex), NULL) || pthread_cond_init(&(q->cond_full), NULL) || pthread_cond_init(&(q->cond_empty), NULL)) { + free(q->buffer); + free(q); + q = NULL; + } + } else { + free(q); + q = NULL; + } + } + + return q; + +} + +void pthread_queue_delete(pthread_queue_t * q) { + + if (q == NULL) + return; + + free(q->buffer); + free(q); + + return; + +} + +int pthread_queue_enqueue(pthread_queue_t * queue, void * value, uint32_t timeout) { + + int ret; + + /* Calculate timeout */ + struct timespec ts; + + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + ts.tv_sec = mts.tv_sec; + ts.tv_nsec = mts.tv_nsec; + + uint32_t sec = timeout / 1000; + uint32_t nsec = (timeout - 1000 * sec) * 1000000; + + ts.tv_sec += sec; + + if (ts.tv_nsec + nsec > 1000000000) + ts.tv_sec++; + + ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; + + /* Get queue lock */ + pthread_mutex_lock(&(queue->mutex)); + while (queue->items == queue->size) { + ret = pthread_cond_timedwait(&(queue->cond_full), &(queue->mutex), &ts); + if (ret != 0) { + pthread_mutex_unlock(&(queue->mutex)); + return PTHREAD_QUEUE_FULL; + } + } + + /* Coby object from input buffer */ + memcpy(queue->buffer+(queue->in * queue->item_size), value, queue->item_size); + queue->items++; + queue->in = (queue->in + 1) % queue->size; + pthread_mutex_unlock(&(queue->mutex)); + + /* Nofify blocked threads */ + pthread_cond_broadcast(&(queue->cond_empty)); + + return PTHREAD_QUEUE_OK; + +} + +int pthread_queue_dequeue(pthread_queue_t * queue, void * buf, uint32_t timeout) { + + int ret; + + /* Calculate timeout */ + struct timespec ts; + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + ts.tv_sec = mts.tv_sec; + ts.tv_nsec = mts.tv_nsec; + + uint32_t sec = timeout / 1000; + uint32_t nsec = (timeout - 1000 * sec) * 1000000; + + ts.tv_sec += sec; + + if (ts.tv_nsec + nsec > 1000000000) + ts.tv_sec++; + + ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; + + /* Get queue lock */ + pthread_mutex_lock(&(queue->mutex)); + while (queue->items == 0) { + ret = pthread_cond_timedwait(&(queue->cond_empty), &(queue->mutex), &ts); + if (ret != 0) { + pthread_mutex_unlock(&(queue->mutex)); + return PTHREAD_QUEUE_EMPTY; + } + } + + /* Coby object to output buffer */ + memcpy(buf, queue->buffer+(queue->out * queue->item_size), queue->item_size); + queue->items--; + queue->out = (queue->out + 1) % queue->size; + pthread_mutex_unlock(&(queue->mutex)); + + /* Nofify blocked threads */ + pthread_cond_broadcast(&(queue->cond_full)); + + return PTHREAD_QUEUE_OK; + +} + +int pthread_queue_items(pthread_queue_t * queue) { + + pthread_mutex_lock(&(queue->mutex)); + int items = queue->items; + pthread_mutex_unlock(&(queue->mutex)); + + return items; + +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_malloc.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_malloc.c new file mode 100644 index 00000000..95bb8cc7 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_malloc.c @@ -0,0 +1,31 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +void * csp_malloc(size_t size) { + return malloc(size); +} + +void csp_free(void *ptr) { + free(ptr); +} + diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_queue.c new file mode 100644 index 00000000..a2fb1b4f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_queue.c @@ -0,0 +1,64 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +/* CSP includes */ +#include + +#include +#include + + +csp_queue_handle_t csp_queue_create(int length, size_t item_size) { + return pthread_queue_create(length, item_size); +} + +void csp_queue_remove(csp_queue_handle_t queue) { + return pthread_queue_delete(queue); +} + +int csp_queue_enqueue(csp_queue_handle_t handle, void *value, uint32_t timeout) { + return pthread_queue_enqueue(handle, value, timeout); +} + +int csp_queue_enqueue_isr(csp_queue_handle_t handle, void * value, CSP_BASE_TYPE * task_woken) { + if (task_woken != NULL) + *task_woken = 0; + return csp_queue_enqueue(handle, value, 0); +} + +int csp_queue_dequeue(csp_queue_handle_t handle, void *buf, uint32_t timeout) { + return pthread_queue_dequeue(handle, buf, timeout); +} + +int csp_queue_dequeue_isr(csp_queue_handle_t handle, void *buf, CSP_BASE_TYPE * task_woken) { + *task_woken = 0; + return csp_queue_dequeue(handle, buf, 0); +} + +int csp_queue_size(csp_queue_handle_t handle) { + return pthread_queue_items(handle); +} + +int csp_queue_size_isr(csp_queue_handle_t handle) { + return pthread_queue_items(handle); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_semaphore.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_semaphore.c new file mode 100644 index 00000000..6829dec2 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_semaphore.c @@ -0,0 +1,164 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* CSP includes */ +#include + +#include + +int csp_mutex_create(csp_mutex_t * mutex) { + csp_log_lock("Mutex init: %p", mutex); + if (pthread_mutex_init(mutex, NULL) == 0) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_mutex_remove(csp_mutex_t * mutex) { + if (pthread_mutex_destroy(mutex) == 0) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_mutex_lock(csp_mutex_t * mutex, uint32_t timeout) { + + int ret; + struct timespec ts; + uint32_t sec, nsec; + + csp_log_lock("Wait: %p timeout %"PRIu32, mutex, timeout); + + if (timeout == CSP_INFINITY) { + ret = pthread_mutex_lock(mutex); + } else { + if (clock_gettime(CLOCK_REALTIME, &ts)) + return CSP_SEMAPHORE_ERROR; + + sec = timeout / 1000; + nsec = (timeout - 1000 * sec) * 1000000; + + ts.tv_sec += sec; + + if (ts.tv_nsec + nsec >= 1000000000) + ts.tv_sec++; + + ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; + + ret = pthread_mutex_timedlock(mutex, &ts); + } + + if (ret != 0) + return CSP_SEMAPHORE_ERROR; + + return CSP_SEMAPHORE_OK; +} + +int csp_mutex_unlock(csp_mutex_t * mutex) { + if (pthread_mutex_unlock(mutex) == 0) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_bin_sem_create(csp_bin_sem_handle_t * sem) { + csp_log_lock("Semaphore init: %p", sem); + if (sem_init(sem, 0, 1) == 0) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_bin_sem_remove(csp_bin_sem_handle_t * sem) { + if (sem_destroy(sem) == 0) + return CSP_SEMAPHORE_OK; + else + return CSP_SEMAPHORE_ERROR; +} + +int csp_bin_sem_wait(csp_bin_sem_handle_t * sem, uint32_t timeout) { + + int ret; + struct timespec ts; + uint32_t sec, nsec; + + csp_log_lock("Wait: %p timeout %"PRIu32, sem, timeout); + + if (timeout == CSP_INFINITY) { + ret = sem_wait(sem); + } else { + if (clock_gettime(CLOCK_REALTIME, &ts)) + return CSP_SEMAPHORE_ERROR; + + sec = timeout / 1000; + nsec = (timeout - 1000 * sec) * 1000000; + + ts.tv_sec += sec; + + if (ts.tv_nsec + nsec >= 1000000000) + ts.tv_sec++; + + ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; + + ret = sem_timedwait(sem, &ts); + } + + if (ret != 0) + return CSP_SEMAPHORE_ERROR; + + return CSP_SEMAPHORE_OK; +} + +int csp_bin_sem_post(csp_bin_sem_handle_t * sem) { + CSP_BASE_TYPE dummy = 0; + return csp_bin_sem_post_isr(sem, &dummy); +} + +int csp_bin_sem_post_isr(csp_bin_sem_handle_t * sem, CSP_BASE_TYPE * task_woken) { + csp_log_lock("Post: %p", sem); + *task_woken = 0; + + int value; + sem_getvalue(sem, &value); + if (value > 0) + return CSP_SEMAPHORE_OK; + + if (sem_post(sem) == 0) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_system.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_system.c new file mode 100644 index 00000000..6c882c7c --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_system.c @@ -0,0 +1,131 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +int csp_sys_tasklist(char * out) { + strcpy(out, "Tasklist not available on POSIX"); + return CSP_ERR_NONE; +} + +int csp_sys_tasklist_size(void) { + return 100; +} + +uint32_t csp_sys_memfree(void) { + uint32_t total = 0; + struct sysinfo info; + sysinfo(&info); + total = info.freeram * info.mem_unit; + return total; +} + +int csp_sys_reboot(void) { +#ifdef CSP_USE_INIT_SHUTDOWN + /* Let init(1) handle the reboot */ + int ret = system("reboot"); + (void) ret; /* Silence warning */ +#else + int magic = LINUX_REBOOT_CMD_RESTART; + + /* Sync filesystem before reboot */ + sync(); + reboot(magic); +#endif + + /* If reboot(2) returns, it is an error */ + csp_log_error("Failed to reboot: %s", strerror(errno)); + + return CSP_ERR_INVAL; +} + +int csp_sys_shutdown(void) { +#ifdef CSP_USE_INIT_SHUTDOWN + /* Let init(1) handle the shutdown */ + int ret = system("halt"); + (void) ret; /* Silence warning */ +#else + int magic = LINUX_REBOOT_CMD_HALT; + + /* Sync filesystem before reboot */ + sync(); + reboot(magic); +#endif + + /* If reboot(2) returns, it is an error */ + csp_log_error("Failed to shutdown: %s", strerror(errno)); + + return CSP_ERR_INVAL; +} + +void csp_sys_set_color(csp_color_t color) { + + unsigned int color_code, modifier_code; + switch (color & COLOR_MASK_COLOR) { + case COLOR_BLACK: + color_code = 30; break; + case COLOR_RED: + color_code = 31; break; + case COLOR_GREEN: + color_code = 32; break; + case COLOR_YELLOW: + color_code = 33; break; + case COLOR_BLUE: + color_code = 34; break; + case COLOR_MAGENTA: + color_code = 35; break; + case COLOR_CYAN: + color_code = 36; break; + case COLOR_WHITE: + color_code = 37; break; + case COLOR_RESET: + default: + color_code = 0; break; + } + + switch (color & COLOR_MASK_MODIFIER) { + case COLOR_BOLD: + modifier_code = 1; break; + case COLOR_UNDERLINE: + modifier_code = 2; break; + case COLOR_BLINK: + modifier_code = 3; break; + case COLOR_HIDE: + modifier_code = 4; break; + case COLOR_NORMAL: + default: + modifier_code = 0; break; + } + + printf("\033[%u;%um", modifier_code, color_code); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_thread.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_thread.c new file mode 100644 index 00000000..3277d35d --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_thread.c @@ -0,0 +1,55 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +/* CSP includes */ +#include + +#include + +int csp_thread_create(csp_thread_return_t (* routine)(void *), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle) { + pthread_attr_t attributes, *attr_ref; + int return_code; + + if( pthread_attr_init(&attributes) == 0 ) + { + unsigned int stack_size = PTHREAD_STACK_MIN;// use at least one memory page + + while(stack_size < stack_depth)// must reach at least the provided size + { + stack_size += PTHREAD_STACK_MIN;// keep memory page boundary (some systems may fail otherwise)) + } + attr_ref = &attributes; + + pthread_attr_setdetachstate(attr_ref, PTHREAD_CREATE_DETACHED);// do not waste memory on each call + pthread_attr_setstacksize(attr_ref, stack_size); + } + else + { + attr_ref = NULL; + } + return_code = pthread_create(handle, attr_ref, routine, parameters); + if( attr_ref != NULL ) pthread_attr_destroy(attr_ref); + + return return_code; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_time.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_time.c new file mode 100644 index 00000000..c9677443 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_time.c @@ -0,0 +1,54 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +/* CSP includes */ +#include + +#include + +uint32_t csp_get_ms(void) { + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + return (uint32_t)(ts.tv_sec*1000+ts.tv_nsec/1000000); + else + return 0; +} + +uint32_t csp_get_ms_isr(void) { + return csp_get_ms(); +} + +uint32_t csp_get_s(void) { + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + return (uint32_t)ts.tv_sec; + else + return 0; +} + +uint32_t csp_get_s_isr(void) { + return csp_get_s(); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/pthread_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/pthread_queue.c new file mode 100644 index 00000000..e8b6d4ab --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/posix/pthread_queue.c @@ -0,0 +1,243 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Inspired by c-pthread-queue by Matthew Dickinson +http://code.google.com/p/c-pthread-queue/ +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* CSP includes */ +#include + +static inline int get_deadline(struct timespec *ts, uint32_t timeout_ms) +{ + int ret = clock_gettime(CLOCK_MONOTONIC, ts); + + if (ret < 0) { + return ret; + } + + uint32_t sec = timeout_ms / 1000; + uint32_t nsec = (timeout_ms - 1000 * sec) * 1000000; + + ts->tv_sec += sec; + + if (ts->tv_nsec + nsec >= 1000000000) { + ts->tv_sec++; + } + + ts->tv_nsec = (ts->tv_nsec + nsec) % 1000000000; + + return ret; +} + +static inline int init_cond_clock_monotonic(pthread_cond_t * cond) +{ + + int ret; + pthread_condattr_t attr; + + pthread_condattr_init(&attr); + ret = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + + if (ret == 0) { + ret = pthread_cond_init(cond, &attr); + } + + pthread_condattr_destroy(&attr); + return ret; + +} + +pthread_queue_t * pthread_queue_create(int length, size_t item_size) { + + pthread_queue_t * q = malloc(sizeof(pthread_queue_t)); + + if (q != NULL) { + q->buffer = malloc(length*item_size); + if (q->buffer != NULL) { + q->size = length; + q->item_size = item_size; + q->items = 0; + q->in = 0; + q->out = 0; + if (pthread_mutex_init(&(q->mutex), NULL) || init_cond_clock_monotonic(&(q->cond_full)) || init_cond_clock_monotonic(&(q->cond_empty))) { + free(q->buffer); + free(q); + q = NULL; + } + } else { + free(q); + q = NULL; + } + } + + return q; + +} + +void pthread_queue_delete(pthread_queue_t * q) { + + if (q == NULL) + return; + + free(q->buffer); + free(q); + + return; + +} + + +static inline int wait_slot_available(pthread_queue_t * queue, struct timespec *ts) { + + int ret; + + while (queue->items == queue->size) { + + if (ts != NULL) { + ret = pthread_cond_timedwait(&(queue->cond_full), &(queue->mutex), ts); + } else { + ret = pthread_cond_wait(&(queue->cond_full), &(queue->mutex)); + } + + if (ret != 0 && errno != EINTR) { + return PTHREAD_QUEUE_FULL; //Timeout + } + } + + return PTHREAD_QUEUE_OK; + +} + +int pthread_queue_enqueue(pthread_queue_t * queue, void * value, uint32_t timeout) { + + int ret; + struct timespec ts; + struct timespec *pts = NULL; + + /* Calculate timeout */ + if (timeout != CSP_MAX_DELAY) { + if (get_deadline(&ts, timeout) != 0) { + return PTHREAD_QUEUE_ERROR; + } + pts = &ts; + } else { + pts = NULL; + } + + /* Get queue lock */ + pthread_mutex_lock(&(queue->mutex)); + + ret = wait_slot_available(queue, pts); + if (ret == PTHREAD_QUEUE_OK) { + /* Copy object from input buffer */ + memcpy(queue->buffer+(queue->in * queue->item_size), value, queue->item_size); + queue->items++; + queue->in = (queue->in + 1) % queue->size; + } + + pthread_mutex_unlock(&(queue->mutex)); + + if (ret == PTHREAD_QUEUE_OK) { + /* Nofify blocked threads */ + pthread_cond_broadcast(&(queue->cond_empty)); + } + + return ret; + +} + +static inline int wait_item_available(pthread_queue_t * queue, struct timespec *ts) { + + int ret; + + while (queue->items == 0) { + + if (ts != NULL) { + ret = pthread_cond_timedwait(&(queue->cond_empty), &(queue->mutex), ts); + } else { + ret = pthread_cond_wait(&(queue->cond_empty), &(queue->mutex)); + } + + if (ret != 0 && errno != EINTR) { + return PTHREAD_QUEUE_EMPTY; //Timeout + } + } + + return PTHREAD_QUEUE_OK; + +} + +int pthread_queue_dequeue(pthread_queue_t * queue, void * buf, uint32_t timeout) { + + int ret; + struct timespec ts; + struct timespec *pts; + + /* Calculate timeout */ + if (timeout != CSP_MAX_DELAY) { + if (get_deadline(&ts, timeout) != 0) { + return PTHREAD_QUEUE_ERROR; + } + pts = &ts; + } else { + pts = NULL; + } + + /* Get queue lock */ + pthread_mutex_lock(&(queue->mutex)); + + ret = wait_item_available(queue, pts); + if (ret == PTHREAD_QUEUE_OK) { + /* Coby object to output buffer */ + memcpy(buf, queue->buffer+(queue->out * queue->item_size), queue->item_size); + queue->items--; + queue->out = (queue->out + 1) % queue->size; + } + + pthread_mutex_unlock(&(queue->mutex)); + + if (ret == PTHREAD_QUEUE_OK) { + /* Nofify blocked threads */ + pthread_cond_broadcast(&(queue->cond_full)); + } + + return ret; + +} + +int pthread_queue_items(pthread_queue_t * queue) { + + pthread_mutex_lock(&(queue->mutex)); + int items = queue->items; + pthread_mutex_unlock(&(queue->mutex)); + + return items; + +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/README b/gomspace/libgscsp/lib/libcsp/src/arch/windows/README new file mode 100644 index 00000000..b97ce7f5 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/README @@ -0,0 +1,18 @@ +This directory contains files specific to the windows port of libcsp. + +To compile and create a static library, execute: + + python waf configure --with-os=windows build + +from the root of this project. Note python must be in PATH. + +The build requirements are: + * Windows Vista SP1 + * A recent version of MinGW _or_ MinGW-w64 + * Windows API headers + * cPython 2.5 or newer + +What provides the Windows API headers depends on the development environment: +Using MinGW: Headers provided by w32api package. windows_glue.h header is needed because these headers do not declare condition variables. +Using MinGW-w64: Headers should be available in the default configuration. You may have to compile the distribution from source. windows_glue.h should not be needed. + diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_malloc.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_malloc.c new file mode 100644 index 00000000..4b301e49 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_malloc.c @@ -0,0 +1,9 @@ +#include + +void * csp_malloc(size_t size) { + return malloc(size); +} + +void csp_free(void * ptr) { + free(ptr); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_queue.c new file mode 100644 index 00000000..177f8fa9 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_queue.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include "windows_queue.h" + +csp_queue_handle_t csp_queue_create(int length, size_t item_size) { + return windows_queue_create(length, item_size); +} + +void csp_queue_remove(csp_queue_handle_t queue) { + windows_queue_delete(queue); +} + +int csp_queue_enqueue(csp_queue_handle_t handle, void *value, uint32_t timeout) { + return windows_queue_enqueue(handle, value, timeout); +} + +int csp_queue_enqueue_isr(csp_queue_handle_t handle, void * value, CSP_BASE_TYPE * task_woken) { + if( task_woken != NULL ) + *task_woken = 0; + return windows_queue_enqueue(handle, value, 0); +} + +int csp_queue_dequeue(csp_queue_handle_t handle, void *buf, uint32_t timeout) { + return windows_queue_dequeue(handle, buf, timeout); +} + +int csp_queue_dequeue_isr(csp_queue_handle_t handle, void * buf, CSP_BASE_TYPE * task_woken) { + if( task_woken != NULL ) + *task_woken = 0; + return windows_queue_dequeue(handle, buf, 0); +} + +int csp_queue_size(csp_queue_handle_t handle) { + return windows_queue_items(handle); +} + +int csp_queue_size_isr(csp_queue_handle_t handle) { + return windows_queue_items(handle); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_semaphore.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_semaphore.c new file mode 100644 index 00000000..aa69251e --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_semaphore.c @@ -0,0 +1,74 @@ +#include +#include +#include + +int csp_mutex_create(csp_mutex_t * mutex) { + HANDLE mutexHandle = CreateMutex(NULL, FALSE, FALSE); + if( mutexHandle == NULL ) { + return CSP_MUTEX_ERROR; + } + *mutex = mutexHandle; + return CSP_MUTEX_OK; +} + +int csp_mutex_remove(csp_mutex_t * mutex) { + if( !CloseHandle(*mutex) ) { + return CSP_MUTEX_ERROR; + } + return CSP_MUTEX_OK; +} + +int csp_mutex_lock(csp_mutex_t * mutex, uint32_t timeout) { + if(WaitForSingleObject(*mutex, timeout) == WAIT_OBJECT_0) { + return CSP_MUTEX_OK; + } + return CSP_MUTEX_ERROR; + +} + +int csp_mutex_unlock(csp_mutex_t * mutex) { + if( !ReleaseMutex(*mutex) ) { + return CSP_MUTEX_ERROR; + } + return CSP_MUTEX_OK; +} + +int csp_bin_sem_create(csp_bin_sem_handle_t * sem) { + HANDLE semHandle = CreateSemaphore(NULL, 1, 1, NULL); + if( semHandle == NULL ) { + return CSP_SEMAPHORE_ERROR; + } + *sem = semHandle; + return CSP_SEMAPHORE_OK; +} + +int csp_bin_sem_remove(csp_bin_sem_handle_t * sem) { + if( !CloseHandle(*sem) ) { + return CSP_SEMAPHORE_ERROR; + } + return CSP_SEMAPHORE_OK; +} + +int csp_bin_sem_wait(csp_bin_sem_handle_t * sem, uint32_t timeout) { + if( WaitForSingleObject(*sem, timeout) == WAIT_OBJECT_0 ) { + return CSP_SEMAPHORE_OK; + } + return CSP_SEMAPHORE_ERROR; + +} + +int csp_bin_sem_post(csp_bin_sem_handle_t * sem) { + if( !ReleaseSemaphore(*sem, 1, NULL) ) { + return CSP_SEMAPHORE_ERROR; + } + return CSP_SEMAPHORE_OK; +} + +int csp_bin_sem_post_isr(csp_bin_sem_handle_t * sem, CSP_BASE_TYPE * task_woken) { + if( task_woken != NULL ) { + *task_woken = 0; + } + return csp_bin_sem_post(sem); +} + + diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_system.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_system.c new file mode 100644 index 00000000..262c2052 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_system.c @@ -0,0 +1,60 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +#include +#include + +#include + +int csp_sys_tasklist(char * out) { + strcpy(out, "Tasklist not available on Windows"); + return CSP_ERR_NONE; +} + +uint32_t csp_sys_memfree(void) { + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + GlobalMemoryStatusEx(&statex); + DWORDLONG freePhysicalMem = statex.ullAvailPhys; + size_t total = (size_t) freePhysicalMem; + return (uint32_t)total; +} + +int csp_sys_reboot(void) { + /* TODO: Fix reboot on Windows */ + csp_log_error("Failed to reboot"); + + return CSP_ERR_INVAL; +} + +int csp_sys_shutdown(void) { + /* TODO: Fix shutdown on Windows */ + csp_log_error("Failed to shutdown"); + + return CSP_ERR_INVAL; +} + +void csp_sys_set_color(csp_color_t color) { + /* TODO: Add Windows color output here */ +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_thread.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_thread.c new file mode 100644 index 00000000..ef46a948 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_thread.c @@ -0,0 +1,11 @@ +#include +#include +#include + +int csp_thread_create(csp_thread_return_t (* routine)(void *)__attribute__((stdcall)), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle) { + HANDLE taskHandle = (HANDLE) _beginthreadex(NULL, stack_depth, routine, parameters, 0, 0); + if( taskHandle == 0 ) + return CSP_ERR_NOMEM; // Failure + *handle = taskHandle; + return CSP_ERR_NONE; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_time.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_time.c new file mode 100644 index 00000000..618292ab --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_time.c @@ -0,0 +1,20 @@ +#include +#include +#include + +uint32_t csp_get_ms(void) { + return (uint32_t)GetTickCount(); +} + +uint32_t csp_get_ms_isr(void) { + return csp_get_ms(); +} + +uint32_t csp_get_s(void) { + uint32_t time_ms = csp_get_ms(); + return time_ms/1000; +} + +uint32_t csp_get_s_isr(void) { + return csp_get_s(); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_glue.h b/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_glue.h new file mode 100644 index 00000000..6e0cf6db --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_glue.h @@ -0,0 +1,23 @@ +#ifndef WINDOWS_GLUE_H +#define WINDOWS_GLUE_H + +#include +#undef interface + +#if (_WIN32_WINNT >= 0x0600) + +#define RTL_CONDITION_VARIABLE_INIT 0 +#define RTL_CONDITION_VARIABLE_LOCKMODE_SHARED 1 +#define CONDITION_VARIABLE_INIT RTL_CONDITION_VARIABLE_INIT +#define CONDITION_VARIABLE_LOCKMODE_SHARED RTL_CONDITION_VARIABLE_LOCKMODE_SHARED + +typedef PVOID RTL_CONDITION_VARIABLE; +typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE; + +WINBASEAPI VOID WINAPI InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable); +WINBASEAPI WINBOOL WINAPI SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable, PCRITICAL_SECTION CriticalSection, DWORD dwMilliseconds); +WINBASEAPI VOID WINAPI WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable); +WINBASEAPI VOID WINAPI WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable); + +#endif // _WIN#"_WINNT +#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.c new file mode 100644 index 00000000..aa337dc8 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.c @@ -0,0 +1,91 @@ +#include "windows_queue.h" +#include "windows_glue.h" +#include + +static int queueFull(windows_queue_t * queue) { + return queue->items == queue->size; +} + +static int queueEmpty(windows_queue_t * queue) { + return queue->items == 0; +} + +windows_queue_t * windows_queue_create(int length, size_t item_size) { + windows_queue_t *queue = (windows_queue_t*)malloc(sizeof(windows_queue_t)); + if(queue == NULL) + goto queue_malloc_failed; + + queue->buffer = malloc(length*item_size); + if(queue->buffer == NULL) + goto buffer_malloc_failed; + + queue->size = length; + queue->item_size = item_size; + queue->items = 0; + queue->head_idx = 0; + + InitializeCriticalSection(&(queue->mutex)); + InitializeConditionVariable(&(queue->cond_full)); + InitializeConditionVariable(&(queue->cond_empty)); + goto queue_init_success; + +buffer_malloc_failed: + free(queue); + queue = NULL; +queue_malloc_failed: +queue_init_success: + return queue; +} + +void windows_queue_delete(windows_queue_t * q) { + if(q==NULL) return; + DeleteCriticalSection(&(q->mutex)); + free(q->buffer); + free(q); +} + +int windows_queue_enqueue(windows_queue_t * queue, void * value, int timeout) { + int offset; + EnterCriticalSection(&(queue->mutex)); + while(queueFull(queue)) { + int ret = SleepConditionVariableCS(&(queue->cond_full), &(queue->mutex), timeout); + if( !ret ) { + LeaveCriticalSection(&(queue->mutex)); + return ret == WAIT_TIMEOUT ? WINDOWS_QUEUE_FULL : WINDOWS_QUEUE_ERROR; + } + } + offset = ((queue->head_idx+queue->items) % queue->size) * queue->item_size; + memcpy((unsigned char*)queue->buffer + offset, value, queue->item_size); + queue->items++; + + LeaveCriticalSection(&(queue->mutex)); + WakeAllConditionVariable(&(queue->cond_empty)); + return WINDOWS_QUEUE_OK; +} + +int windows_queue_dequeue(windows_queue_t * queue, void * buf, int timeout) { + EnterCriticalSection(&(queue->mutex)); + while(queueEmpty(queue)) { + int ret = SleepConditionVariableCS(&(queue->cond_empty), &(queue->mutex), timeout); + if( !ret ) { + LeaveCriticalSection(&(queue->mutex)); + return ret == WAIT_TIMEOUT ? WINDOWS_QUEUE_EMPTY : WINDOWS_QUEUE_ERROR; + } + } + memcpy(buf, (unsigned char*)queue->buffer+(queue->head_idx%queue->size*queue->item_size), queue->item_size); + queue->items--; + queue->head_idx = (queue->head_idx + 1) % queue->size; + + LeaveCriticalSection(&(queue->mutex)); + WakeAllConditionVariable(&(queue->cond_full)); + return WINDOWS_QUEUE_OK; +} + +int windows_queue_items(windows_queue_t * queue) { + int items; + EnterCriticalSection(&(queue->mutex)); + items = queue->items; + LeaveCriticalSection(&(queue->mutex)); + + return items; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.h b/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.h new file mode 100644 index 00000000..e6bc5423 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.h @@ -0,0 +1,41 @@ +#ifndef _WINDOWS_QUEUE_H_ +#define _WINDOWS_QUEUE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "windows_glue.h" +#undef interface + +#include + +#define WINDOWS_QUEUE_ERROR CSP_QUEUE_ERROR +#define WINDOWS_QUEUE_EMPTY CSP_QUEUE_ERROR +#define WINDOWS_QUEUE_FULL CSP_QUEUE_ERROR +#define WINDOWS_QUEUE_OK CSP_QUEUE_OK + +typedef struct windows_queue_s { + void * buffer; + int size; + int item_size; + int items; + int head_idx; + CRITICAL_SECTION mutex; + CONDITION_VARIABLE cond_full; + CONDITION_VARIABLE cond_empty; +} windows_queue_t; + +windows_queue_t * windows_queue_create(int length, size_t item_size); +void windows_queue_delete(windows_queue_t * q); +int windows_queue_enqueue(windows_queue_t * queue, void * value, int timeout); +int windows_queue_dequeue(windows_queue_t * queue, void * buf, int timeout); +int windows_queue_items(windows_queue_t * queue); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _WINDOWS_QUEUE_H_ + diff --git a/gomspace/libgscsp/lib/libcsp/src/bindings/python/pycsp.c b/gomspace/libgscsp/lib/libcsp/src/bindings/python/pycsp.c new file mode 100644 index 00000000..f1009d1a --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/bindings/python/pycsp.c @@ -0,0 +1,1052 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if PY_MAJOR_VERSION == 3 +#define IS_PY3 +#endif + +static int is_capsule_of_type(PyObject* capsule, const char* expected_type) { + const char* capsule_name = PyCapsule_GetName(capsule); + if (strcmp(capsule_name, expected_type) != 0) { + PyErr_Format( + PyExc_TypeError, + "capsule contains unexpected type, expected=%s, got=%s", + expected_type, capsule_name); // TypeError is thrown + return 0; + } + return 1; +} + +/** + * csp/csp.h + */ + +/* + * void csp_service_handler(csp_conn_t *conn, csp_packet_t *packet); + */ +static PyObject* pycsp_service_handler(PyObject *self, PyObject *args) { + PyObject* conn_capsule; + PyObject* packet_capsule; + if (!PyArg_ParseTuple(args, "OO", &conn_capsule, &packet_capsule)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(conn_capsule, "csp_conn_t") || + !is_capsule_of_type(packet_capsule, "csp_packet_t")) { + return NULL; // TypeError is thrown + } + + csp_service_handler( + (csp_conn_t*)PyCapsule_GetPointer(conn_capsule, "csp_conn_t"), + (csp_packet_t*)PyCapsule_GetPointer(packet_capsule, "csp_packet_t")); + + Py_RETURN_NONE; +} + +/* + * int csp_init(uint8_t my_node_address); + */ +static PyObject* pycsp_init(PyObject *self, PyObject *args) { + uint8_t my_node_address; + if (!PyArg_ParseTuple(args, "b", &my_node_address)) { + return NULL; // TypeError is thrown + } + + return Py_BuildValue("i", csp_init(my_node_address)); +} + +/* + * void csp_set_hostname(const char *hostname); + */ +static PyObject* pycsp_set_hostname(PyObject *self, PyObject *args) { + char* hostname; + if (!PyArg_ParseTuple(args, "s", &hostname)) { + return NULL; // TypeError is thrown + } + + csp_set_hostname(hostname); + Py_RETURN_NONE; +} + +/* + * const char *csp_get_hostname(void); + */ +static PyObject* pycsp_get_hostname(PyObject *self, PyObject *args) { + return Py_BuildValue("s", csp_get_hostname()); +} + +/* + * void csp_set_model(const char *model); + */ +static PyObject* pycsp_set_model(PyObject *self, PyObject *args) { + char* model; + if (!PyArg_ParseTuple(args, "s", &model)) { + return NULL; // TypeError is thrown + } + + csp_set_model(model); + Py_RETURN_NONE; +} + +/* + * const char *csp_get_model(void); + */ +static PyObject* pycsp_get_model(PyObject *self, PyObject *args) { + return Py_BuildValue("s", csp_get_model()); +} + +/* + * void csp_set_revision(const char *revision); + */ +static PyObject* pycsp_set_revision(PyObject *self, PyObject *args) { + char* revision; + if (!PyArg_ParseTuple(args, "s", &revision)) { + return NULL; // TypeError is thrown + } + + csp_set_revision(revision); + Py_RETURN_NONE; +} + +/* + * const char *csp_get_revision(void); + */ +static PyObject* pycsp_get_revision(PyObject *self, PyObject *args) { + return Py_BuildValue("s", csp_get_revision()); +} + +/* + * csp_socket_t *csp_socket(uint32_t opts); + */ +static PyObject* pycsp_socket(PyObject *self, PyObject *args) { + uint32_t opts = CSP_SO_NONE; + if (!PyArg_ParseTuple(args, "|I", &opts)) { + return NULL; // TypeError is thrown + } + + return PyCapsule_New(csp_socket(opts), "csp_socket_t", NULL); +} + +/* + * csp_conn_t *csp_accept(csp_socket_t *socket, uint32_t timeout); + */ +static PyObject* pycsp_accept(PyObject *self, PyObject *args) { + PyObject* socket_capsule; + uint32_t timeout = 500; + if (!PyArg_ParseTuple(args, "O|I", &socket_capsule, &timeout)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(socket_capsule, "csp_socket_t")) { + return NULL; // TypeError is thrown + } + + void* socket = PyCapsule_GetPointer(socket_capsule, "csp_socket_t"); + csp_conn_t* conn = csp_accept((csp_socket_t*)socket, timeout); + if (conn == NULL) { + Py_RETURN_NONE; // because a capsule cannot contain a NULL-pointer + } + + return PyCapsule_New(conn, "csp_conn_t", NULL); +} + +/* + * csp_packet_t *csp_read(csp_conn_t *conn, uint32_t timeout); + */ +static PyObject* pycsp_read(PyObject *self, PyObject *args) { + PyObject* conn_capsule; + uint32_t timeout = 500; + if (!PyArg_ParseTuple(args, "O|I", &conn_capsule, &timeout)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { + return NULL; // TypeError is thrown + } + + void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); + csp_packet_t* packet = csp_read((csp_conn_t*)conn, timeout); + if (packet == NULL) { + Py_RETURN_NONE; // because capsule cannot contain a NULL-pointer + } + + return PyCapsule_New(packet, "csp_packet_t", NULL); +} + +/* +* int csp_send(csp_conn_t * conn, csp_packet_t * packet, uint32_t timeout) +*/ +static PyObject* pycsp_send(PyObject *self, PyObject *args) { + PyObject* conn_capsule; + PyObject* packet_capsule; + uint32_t timeout = 500; + if (!PyArg_ParseTuple(args, "OO|I", &conn_capsule, &packet_capsule, &timeout)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { + return NULL; // TypeError is thrown + } + + void* packet = PyCapsule_GetPointer(packet_capsule, "csp_packet_t"); + if (packet == NULL) { + Py_RETURN_NONE; + } + + void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); + + int result = csp_send(conn, packet, timeout); + + return Py_BuildValue("i", result); +} + +/* + * int csp_transaction(uint8_t prio, uint8_t dest, uint8_t port, + * uint32_t timeout, void *outbuf, int outlen, + * void *inbuf, int inlen); + */ +static PyObject* pycsp_transaction(PyObject *self, PyObject *args) { + uint8_t prio; + uint8_t dest; + uint8_t port; + uint32_t timeout; + Py_buffer inbuf; + Py_buffer outbuf; + if (!PyArg_ParseTuple(args, "bbbIw*w*", &prio, &dest, &port, &timeout, &outbuf, &inbuf)) { + return NULL; // TypeError is thrown + } + + int result = csp_transaction(prio, dest, port, timeout, + outbuf.buf, outbuf.len, + inbuf.buf, inbuf.len); + + return Py_BuildValue("i", result); +} + +/* int csp_sendto(uint8_t prio, uint8_t dest, uint8_t dport, uint8_t src_port, uint32_t opts, csp_packet_t *packet, uint32_t timeout); */ +static PyObject* pycsp_sendto(PyObject *self, PyObject *args) { + uint8_t prio; + uint8_t dest; + uint8_t dport; + uint8_t src_port; + uint32_t opts; + PyObject* packet_capsule; + uint32_t timeout; + if (!PyArg_ParseTuple(args, "bbbbIOI", &prio, &dest, &dport, &src_port, &opts, &packet_capsule, &timeout)) { + Py_RETURN_NONE; + } + + void* packet = PyCapsule_GetPointer(packet_capsule, "csp_packet_t"); + if (packet == NULL) { + Py_RETURN_NONE; + } + + return Py_BuildValue("i", csp_sendto(prio, + dest, + dport, + src_port, + opts, + (csp_packet_t*)packet, + timeout)); +} + + +/* + * int csp_sendto_reply(csp_packet_t * request_packet, + * csp_packet_t * reply_packet, + * uint32_t opts, uint32_t timeout); + */ +static PyObject* pycsp_sendto_reply(PyObject *self, PyObject *args) { + PyObject* request_packet_capsule; + PyObject* reply_packet_capsule; + uint32_t opts = CSP_O_NONE; + uint32_t timeout = 500; + if (!PyArg_ParseTuple(args, "OO|II", &request_packet_capsule, &reply_packet_capsule, &opts, &timeout)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(request_packet_capsule, "csp_packet_t") || + !is_capsule_of_type(reply_packet_capsule, "csp_packet_t")) { + return NULL; // TypeError is thrown + } + + void* request_packet = PyCapsule_GetPointer(request_packet_capsule, "csp_packet_t"); + void* reply_packet = PyCapsule_GetPointer(reply_packet_capsule, "csp_packet_t"); + + return Py_BuildValue("i", csp_sendto_reply((csp_packet_t*)request_packet, + (csp_packet_t*)reply_packet, + opts, + timeout)); +} + +/* + * csp_conn_t *csp_connect(uint8_t prio, uint8_t dest, uint8_t dport, uint32_t timeout, uint32_t opts); + */ +static PyObject* pycsp_connect(PyObject *self, PyObject *args) { + uint8_t prio; + uint8_t dest; + uint8_t dport; + uint32_t timeout; + uint32_t opts; + if (!PyArg_ParseTuple(args, "bbbII", &prio, &dest, &dport, &timeout, &opts)) { + return NULL; // TypeError is thrown + } + + csp_conn_t *conn = csp_connect(prio, dest, dport, timeout,opts); + + return PyCapsule_New(conn, "csp_conn_t", NULL); +} + +/* + * int csp_close(csp_conn_t *conn); + */ +static PyObject* pycsp_close(PyObject *self, PyObject *conn_capsule) { + if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { + return NULL; // TypeError is thrown + } + + void *conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); + return Py_BuildValue("i", csp_close((csp_conn_t*)conn)); +} + +/* + * int csp_conn_dport(csp_conn_t *conn); + */ +static PyObject* pycsp_conn_dport(PyObject *self, PyObject *conn_capsule) { + if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { + return NULL; // TypeError is thrown + } + + void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); + return Py_BuildValue("i", csp_conn_dport((csp_conn_t*)conn)); +} + +/* + * int csp_conn_sport(csp_conn_t *conn); + */ +static PyObject* pycsp_conn_sport(PyObject *self, PyObject *conn_capsule) { + if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { + return NULL; // TypeError is thrown + } + + void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); + return Py_BuildValue("i", csp_conn_sport((csp_conn_t*)conn)); +} + +/* int csp_conn_dst(csp_conn_t *conn); */ +static PyObject* pycsp_conn_dst(PyObject *self, PyObject *conn_capsule) { + if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { + return NULL; // TypeError is thrown + } + + void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); + return Py_BuildValue("i", csp_conn_dst((csp_conn_t*)conn)); +} + +/* + * int csp_conn_src(csp_conn_t *conn); + */ +static PyObject* pycsp_conn_src(PyObject *self, PyObject *conn_capsule) { + if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { + return NULL; // TypeError is thrown + } + + void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); + return Py_BuildValue("i", csp_conn_src((csp_conn_t*)conn)); +} + +/* int csp_listen(csp_socket_t *socket, size_t conn_queue_length); */ +static PyObject* pycsp_listen(PyObject *self, PyObject *args) { + PyObject* socket_capsule; + size_t conn_queue_len = 10; + if (!PyArg_ParseTuple(args, "O|n", &socket_capsule, &conn_queue_len)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(socket_capsule, "csp_socket_t")) { + return NULL; // TypeError is thrown + } + + void* sock = PyCapsule_GetPointer(socket_capsule, "csp_socket_t"); + return Py_BuildValue("i", csp_listen((csp_socket_t*)sock, conn_queue_len)); +} + +/* int csp_bind(csp_socket_t *socket, uint8_t port); */ +static PyObject* pycsp_bind(PyObject *self, PyObject *args) { + PyObject* socket_capsule; + uint8_t port; + if (!PyArg_ParseTuple(args, "Ob", &socket_capsule, &port)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(socket_capsule, "csp_socket_t")) { + return NULL; // TypeError is thrown + } + + void* sock = PyCapsule_GetPointer(socket_capsule, "csp_socket_t"); + return Py_BuildValue("i", csp_bind((csp_socket_t*)sock, port)); +} + +/* int csp_route_start_task(unsigned int task_stack_size, unsigned int priority); */ +static PyObject* pycsp_route_start_task(PyObject *self, PyObject *args) { + unsigned int priority = CSP_PRIO_NORM; + if (!PyArg_ParseTuple(args, "|I", &priority)) { + return NULL; // TypeError is thrown + } + + return Py_BuildValue("i", csp_route_start_task(0, priority)); +} + +/* + * int csp_ping(uint8_t node, uint32_t timeout, + * unsigned int size, uint8_t conn_options); + */ +static PyObject* pycsp_ping(PyObject *self, PyObject *args) { + uint8_t node; + uint32_t timeout = 500; + unsigned int size = 100; + uint8_t conn_options = CSP_O_NONE; + if (!PyArg_ParseTuple(args, "b|IIb", &node, &timeout, &size, &conn_options)) { + return NULL; // TypeError is thrown + } + + return Py_BuildValue("i", csp_ping(node, timeout, size, conn_options)); +} + +/* + * void csp_reboot(uint8_t node); + */ +static PyObject* pycsp_reboot(PyObject *self, PyObject *args) { + uint8_t node; + if (!PyArg_ParseTuple(args, "b", &node)) { + return NULL; // TypeError is thrown + } + + csp_reboot(node); + Py_RETURN_NONE; +} + +/* + * void csp_shutdown(uint8_t node); + */ +static PyObject* pycsp_shutdown(PyObject *self, PyObject *args) { + uint8_t node; + if (!PyArg_ParseTuple(args, "b", &node)) { + return NULL; // TypeError is thrown + } + + csp_shutdown(node); + Py_RETURN_NONE; +} + +/* + * void csp_rdp_set_opt(unsigned int window_size, + * unsigned int conn_timeout_ms, + * unsigned int packet_timeout_ms, + * unsigned int delayed_acks, + * unsigned int ack_timeout, + * unsigned int ack_delay_count); + */ +static PyObject* pycsp_rdp_set_opt(PyObject *self, PyObject *args) { + unsigned int window_size; + unsigned int conn_timeout_ms; + unsigned int packet_timeout_ms; + unsigned int delayed_acks; + unsigned int ack_timeout; + unsigned int ack_delay_count; + if (!PyArg_ParseTuple(args, "IIIIII", &window_size, &conn_timeout_ms, + &packet_timeout_ms, &delayed_acks, + &ack_timeout, &ack_delay_count)) { + return NULL; // TypeError is thrown + } +#ifdef CSP_USE_RDP + csp_rdp_set_opt(window_size, conn_timeout_ms, packet_timeout_ms, + delayed_acks, ack_timeout, ack_delay_count); +#endif + Py_RETURN_NONE; +} + +/* + * void csp_rdp_get_opt(unsigned int *window_size, + * unsigned int *conn_timeout_ms, + * unsigned int *packet_timeout_ms, + * unsigned int *delayed_acks, + * unsigned int *ack_timeout, + * unsigned int *ack_delay_count); + */ +static PyObject* pycsp_rdp_get_opt(PyObject *self, PyObject *args) { + + unsigned int window_size = 0; + unsigned int conn_timeout_ms = 0; + unsigned int packet_timeout_ms = 0; + unsigned int delayed_acks = 0; + unsigned int ack_timeout = 0; + unsigned int ack_delay_count = 0; +#ifdef CSP_USE_RDP + csp_rdp_get_opt(&window_size, + &conn_timeout_ms, + &packet_timeout_ms, + &delayed_acks, + &ack_timeout, + &ack_delay_count); +#endif + return Py_BuildValue("IIIIII", + window_size, + conn_timeout_ms, + packet_timeout_ms, + delayed_acks, + ack_timeout, + ack_delay_count); +} + + +/* + * + * int csp_xtea_set_key(char *key, uint32_t keylen); + */ +static PyObject* pycsp_xtea_set_key(PyObject *self, PyObject *args) { + char* key; + uint32_t keylen; + if (!PyArg_ParseTuple(args, "si", &key, &keylen)) { + return NULL; // TypeError is thrown + } + return Py_BuildValue("i", csp_xtea_set_key(key, keylen)); +} +/** + * csp/csp_rtable.h + */ + +/* + * int csp_rtable_set(uint8_t node, uint8_t mask, + * csp_iface_t *ifc, uint8_t mac); + */ +static PyObject* pycsp_rtable_set(PyObject *self, PyObject *args) { + uint8_t node; + uint8_t mask; + char* interface_name; + uint8_t mac = CSP_NODE_MAC; + if (!PyArg_ParseTuple(args, "bbs|b", &node, &mask, &interface_name, &mac)) { + return NULL; // TypeError is thrown + } + + return Py_BuildValue("i", csp_rtable_set(node, + mask, + csp_iflist_get_by_name(interface_name), + mac)); +} + +/* + * void csp_rtable_clear(void); + */ +static PyObject* pycsp_rtable_clear(PyObject *self, PyObject *args) { + csp_rtable_clear(); + Py_RETURN_NONE; +} + +/* +* int csp_rtable_check(const char * buffer) +*/ +static PyObject* pycsp_rtable_check(PyObject *self, PyObject *args) { + char* buffer; + if (!PyArg_ParseTuple(args, "s", &buffer)) { + return NULL; // TypeError is thrown + } + + return Py_BuildValue("i", csp_rtable_check(buffer)); +} + +/* +* void csp_rtable_load(const char * buffer) +*/ +static PyObject* pycsp_rtable_load(PyObject *self, PyObject *args) { + char* buffer; + if (!PyArg_ParseTuple(args, "s", &buffer)) { + return NULL; // TypeError is thrown + } + + csp_rtable_load(buffer); + Py_RETURN_NONE; +} + +/** + * csp/csp_buffer.h + */ + +/* + * int csp_buffer_init(int count, int size); + */ +static PyObject* pycsp_buffer_init(PyObject *self, PyObject *args) { + int count; + int size; + if (!PyArg_ParseTuple(args, "ii", &count, &size)) { + return NULL; // TypeError is thrown + } + + return Py_BuildValue("i", csp_buffer_init(count, size)); +} + +/* + * void * csp_buffer_get(size_t size); + */ +static PyObject* pycsp_buffer_get(PyObject *self, PyObject *args) { + size_t size; + if (!PyArg_ParseTuple(args, "n", &size)) { + return NULL; // TypeError is thrown + } + + void* packet = csp_buffer_get(size); + if (packet == NULL) { + Py_RETURN_NONE; + } + + return PyCapsule_New(packet, "csp_packet_t", NULL); +} +/* + * void csp_buffer_free(void *packet); + */ +static PyObject* pycsp_buffer_free(PyObject *self, PyObject *args) { + PyObject* packet_capsule; + if (!PyArg_ParseTuple(args, "O", &packet_capsule)) { + return NULL; // TypeError is thrown + } + + + if (!is_capsule_of_type(packet_capsule, "csp_packet_t")) { + return NULL; // TypeError is thrown + } + + csp_buffer_free(PyCapsule_GetPointer(packet_capsule, "csp_packet_t")); + Py_RETURN_NONE; +} + +/* + * int csp_buffer_remaining(void); + */ +static PyObject* pycsp_buffer_remaining(PyObject *self, PyObject *args) { + return Py_BuildValue("i", csp_buffer_remaining()); +} + +/** + * csp/csp_cmp.h + */ + +/* + * static inline int csp_cmp_ident(uint8_t node, uint32_t timeout, + * struct csp_cmp_message *msg) + */ +static PyObject* pycsp_cmp_ident(PyObject *self, PyObject *args) { + uint8_t node; + uint32_t timeout = 500; + if (!PyArg_ParseTuple(args, "b|i", &node, &timeout)) { + return NULL; // TypeError is thrown + } + + struct csp_cmp_message msg; + int rc = csp_cmp_ident(node, timeout, &msg); + return Py_BuildValue("isssss", + rc, + msg.ident.hostname, + msg.ident.model, + msg.ident.revision, + msg.ident.date, + msg.ident.time); +} + +/* + * static inline int csp_cmp_route_set(uint8_t node, uint32_t timeout, + * struct csp_cmp_message *msg) + */ +static PyObject* pycsp_cmp_route_set(PyObject *self, PyObject *args) { + uint8_t node; + uint32_t timeout = 500; + uint8_t addr; + uint8_t mac; + char* ifstr; + if (!PyArg_ParseTuple(args, "bibbs", &node, &timeout, &addr, &mac, &ifstr)) { + return NULL; // TypeError is thrown + } + + struct csp_cmp_message msg; + msg.route_set.dest_node = addr; + msg.route_set.next_hop_mac = mac; + strncpy(msg.route_set.interface, ifstr, CSP_CMP_ROUTE_IFACE_LEN); + int rc = csp_cmp_route_set(node, timeout, &msg); + return Py_BuildValue("i", + rc); +} + +/* static inline int pycsp_cmp_peek(uint8_t node, uint32_t timeout, struct csp_cmp_message *msg); */ +static PyObject* pycsp_cmp_peek(PyObject *self, PyObject *args) { + uint8_t node; + uint32_t timeout; + uint8_t len; + uint32_t addr; + Py_buffer outbuf; + + if (!PyArg_ParseTuple(args, "biibw*", &node, &timeout, &addr, &len, &outbuf)) { + Py_RETURN_NONE; + } + + if (len > CSP_CMP_PEEK_MAX_LEN) { + len = CSP_CMP_PEEK_MAX_LEN; + } + struct csp_cmp_message msg; + msg.peek.addr = csp_hton32(addr); + msg.peek.len = len; + int rc = csp_cmp_peek(node, timeout, &msg); + if (rc != CSP_ERR_NONE) { + Py_RETURN_NONE; + } + memcpy(outbuf.buf, msg.peek.data, len); + outbuf.len = len; + + return Py_BuildValue("i", rc); +} + +/* static inline int pycsp_cmp_poke(uint8_t node, uint32_t timeout, struct csp_cmp_message *msg); */ +static PyObject* pycsp_cmp_poke(PyObject *self, PyObject *args) { + uint8_t node; + uint32_t timeout; + uint8_t len; + uint32_t addr; + Py_buffer inbuf; + + if (!PyArg_ParseTuple(args, "biibw*", &node, &timeout, &addr, &len, &inbuf)) { + Py_RETURN_NONE; + } + + if (len > CSP_CMP_POKE_MAX_LEN) { + len = CSP_CMP_POKE_MAX_LEN; + } + struct csp_cmp_message msg; + msg.poke.addr = csp_hton32(addr); + msg.poke.len = len; + memcpy(msg.poke.data, inbuf.buf, len); + int rc = csp_cmp_poke(node, timeout, &msg); + if (rc != CSP_ERR_NONE) { + Py_RETURN_NONE; + } + + return Py_BuildValue("i", rc); +} + +/* static inline int csp_cmp_clock(uint8_t node, uint32_t timeout, struct csp_cmp_message *msg); */ +static PyObject* pycsp_cmp_clock(PyObject *self, PyObject *args) { + uint8_t node; + uint32_t timeout; + uint32_t sec; + uint32_t nsec; + if (!PyArg_ParseTuple(args, "bIII", &node, &timeout, &sec, &nsec)) { + Py_RETURN_NONE; + } + + struct csp_cmp_message msg; + msg.clock.tv_sec = csp_hton32(sec); + msg.clock.tv_nsec = csp_hton32(nsec); + return Py_BuildValue("i", csp_cmp_clock(node, timeout, &msg)); +} + +/** + * csp/interfaces/csp_if_zmqhub.h + */ + +/* + * int csp_zmqhub_init(char addr, char * host); + */ +static PyObject* pycsp_zmqhub_init(PyObject *self, PyObject *args) { + char addr; + char* host; + if (!PyArg_ParseTuple(args, "bs", &addr, &host)) { + return NULL; // TypeError is thrown + } + + return Py_BuildValue("i", csp_zmqhub_init(addr, host)); +} + +/** + * csp/drivers/can_socketcan.h + */ + +/* + * csp_iface_t * csp_can_socketcan_init(const char * ifc, int bitrate, int promisc); + */ +static PyObject* pycsp_can_socketcan_init(PyObject *self, PyObject *args) +{ + char* ifc; + int bitrate = 1000000; + int promisc = 0; + + if (!PyArg_ParseTuple(args, "s|ii", &ifc, &bitrate, &promisc)) + { + return NULL; + } + + csp_can_socketcan_init(ifc, bitrate, promisc); + Py_RETURN_NONE; +} + + +/** + * csp/interfaces/csp_if_kiss.h + */ + +/* + * int csp_kiss_init(char addr, char * host); + */ +static PyObject* pycsp_kiss_init(PyObject *self, PyObject *args) { + char* device; + uint32_t baudrate = 500000; + uint32_t mtu = 512; + const char* if_name = "KISS"; + if (!PyArg_ParseTuple(args, "s|IIs", &device, &baudrate, &mtu, &if_name)) { + return NULL; // TypeError is thrown + } + + static csp_iface_t csp_if_kiss; + static csp_kiss_handle_t csp_kiss_driver; + csp_if_kiss.mtu = (uint16_t) mtu; + struct usart_conf conf = {.device = device, .baudrate = baudrate}; + csp_kiss_init(&csp_if_kiss, &csp_kiss_driver, usart_putc, usart_insert, if_name); + usart_init(&conf); + + void my_usart_rx(uint8_t * buf, int len, void * pxTaskWoken) { + csp_kiss_rx(&csp_if_kiss, buf, len, pxTaskWoken); + } + usart_set_callback(my_usart_rx); + + Py_RETURN_NONE; +} + +/** + * Helpers - accessing csp_packet_t members + */ +static PyObject* pycsp_packet_set_data(PyObject *self, PyObject *args) { + PyObject* packet_capsule; + Py_buffer data; + if (!PyArg_ParseTuple(args, "Ow*", &packet_capsule, &data)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(packet_capsule, "csp_packet_t")) { + return NULL; // TypeError is thrown + } + + csp_packet_t* packet = PyCapsule_GetPointer(packet_capsule, "csp_packet_t"); + + memcpy((char *)packet->data, data.buf, data.len); + packet->length = data.len; + + Py_RETURN_NONE; +} +static PyObject* pycsp_packet_get_data(PyObject *self, PyObject *packet_capsule) { + if (!is_capsule_of_type(packet_capsule, "csp_packet_t")) { + return NULL; // TypeError is thrown + } + + csp_packet_t* packet = PyCapsule_GetPointer(packet_capsule, "csp_packet_t"); +#ifdef IS_PY3 + return Py_BuildValue("y#", packet->data, packet->length); +#else + return Py_BuildValue("s#", packet->data, packet->length); +#endif +} + +static PyObject* pycsp_packet_get_length(PyObject *self, PyObject *packet_capsule) { + if (!is_capsule_of_type(packet_capsule, "csp_packet_t")) { + return NULL; // TypeError is thrown + } + + csp_packet_t* packet = PyCapsule_GetPointer(packet_capsule, "csp_packet_t"); + return Py_BuildValue("H", packet->length); +} + +static PyMethodDef methods[] = { + + /* csp/csp.h */ + {"service_handler", pycsp_service_handler, METH_VARARGS, ""}, + {"init", pycsp_init, METH_VARARGS, ""}, + {"set_hostname", pycsp_set_hostname, METH_VARARGS, ""}, + {"get_hostname", pycsp_get_hostname, METH_NOARGS, ""}, + {"set_model", pycsp_set_model, METH_VARARGS, ""}, + {"get_model", pycsp_get_model, METH_NOARGS, ""}, + {"set_revision", pycsp_set_revision, METH_VARARGS, ""}, + {"get_revision", pycsp_get_revision, METH_NOARGS, ""}, + {"socket", pycsp_socket, METH_VARARGS, ""}, + {"accept", pycsp_accept, METH_VARARGS, ""}, + {"read", pycsp_read, METH_VARARGS, ""}, + {"send", pycsp_send, METH_VARARGS, ""}, + {"transaction", pycsp_transaction, METH_VARARGS, ""}, + {"sendto_reply", pycsp_sendto_reply, METH_VARARGS, ""}, + {"sendto", pycsp_sendto, METH_VARARGS, ""}, + {"connect", pycsp_connect, METH_VARARGS, ""}, + {"close", pycsp_close, METH_O, ""}, + {"conn_dport", pycsp_conn_dport, METH_O, ""}, + {"conn_sport", pycsp_conn_sport, METH_O, ""}, + {"conn_dst", pycsp_conn_dst, METH_O, ""}, + {"conn_src", pycsp_conn_src, METH_O, ""}, + {"listen", pycsp_listen, METH_VARARGS, ""}, + {"bind", pycsp_bind, METH_VARARGS, ""}, + {"route_start_task", pycsp_route_start_task, METH_VARARGS, ""}, + {"ping", pycsp_ping, METH_VARARGS, ""}, + {"reboot", pycsp_reboot, METH_VARARGS, ""}, + {"shutdown", pycsp_shutdown, METH_VARARGS, ""}, + {"rdp_set_opt", pycsp_rdp_set_opt, METH_VARARGS, ""}, + {"rdp_get_opt", pycsp_rdp_get_opt, METH_NOARGS, ""}, + {"xtea_set_key", pycsp_xtea_set_key, METH_VARARGS, ""}, + + /* csp/csp_rtable.h */ + {"rtable_set", pycsp_rtable_set, METH_VARARGS, ""}, + {"rtable_clear", pycsp_rtable_clear, METH_NOARGS, ""}, + {"rtable_check", pycsp_rtable_check, METH_VARARGS, ""}, + {"rtable_load", pycsp_rtable_load, METH_VARARGS, ""}, + + /* csp/csp_buffer.h */ + {"buffer_init", pycsp_buffer_init, METH_VARARGS, ""}, + {"buffer_free", pycsp_buffer_free, METH_VARARGS, ""}, + {"buffer_get", pycsp_buffer_get, METH_VARARGS, ""}, + {"buffer_remaining", pycsp_buffer_remaining, METH_NOARGS, ""}, + + /* csp/csp_cmp.h */ + {"cmp_ident", pycsp_cmp_ident, METH_VARARGS, ""}, + {"cmp_route_set", pycsp_cmp_route_set, METH_VARARGS, ""}, + {"cmp_peek", pycsp_cmp_peek, METH_VARARGS, ""}, + {"cmp_poke", pycsp_cmp_poke, METH_VARARGS, ""}, + {"cmp_clock", pycsp_cmp_clock, METH_VARARGS, ""}, + + + /* csp/interfaces/csp_if_zmqhub.h */ + {"zmqhub_init", pycsp_zmqhub_init, METH_VARARGS, ""}, + {"kiss_init", pycsp_kiss_init, METH_VARARGS, ""}, + + /* csp/drivers/can_socketcan.h */ + {"can_socketcan_init", pycsp_can_socketcan_init, METH_VARARGS, ""}, + + /* helpers */ + {"packet_get_length", pycsp_packet_get_length, METH_O, ""}, + {"packet_get_data", pycsp_packet_get_data, METH_O, ""}, + {"packet_set_data", pycsp_packet_set_data, METH_VARARGS, ""}, + + /* sentinel */ + {NULL, NULL, 0, NULL} +}; + +#ifdef IS_PY3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "libcsp_py3", + NULL, + -1, + methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +#ifdef IS_PY3 +PyMODINIT_FUNC PyInit_libcsp_py3(void) { +#else + PyMODINIT_FUNC initlibcsp_py2(void) { +#endif + + PyObject* m; + +#ifdef IS_PY3 + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule("libcsp_py2", methods); +#endif + /** + * csp/csp_types.h + */ + + /* RESERVED PORTS */ + PyModule_AddIntConstant(m, "CSP_CMP", CSP_CMP); + PyModule_AddIntConstant(m, "CSP_PING", CSP_PING); + PyModule_AddIntConstant(m, "CSP_PS", CSP_PS); + PyModule_AddIntConstant(m, "CSP_MEMFREE", CSP_MEMFREE); + PyModule_AddIntConstant(m, "CSP_REBOOT", CSP_REBOOT); + PyModule_AddIntConstant(m, "CSP_BUF_FREE", CSP_BUF_FREE); + PyModule_AddIntConstant(m, "CSP_UPTIME", CSP_UPTIME); + PyModule_AddIntConstant(m, "CSP_ANY", CSP_MAX_BIND_PORT + 1); + PyModule_AddIntConstant(m, "CSP_PROMISC", CSP_MAX_BIND_PORT + 2); + + /* PRIORITIES */ + PyModule_AddIntConstant(m, "CSP_PRIO_CRITICAL", CSP_PRIO_CRITICAL); + PyModule_AddIntConstant(m, "CSP_PRIO_HIGH", CSP_PRIO_HIGH); + PyModule_AddIntConstant(m, "CSP_PRIO_NORM", CSP_PRIO_NORM); + PyModule_AddIntConstant(m, "CSP_PRIO_LOW", CSP_PRIO_LOW); + + /* FLAGS */ + PyModule_AddIntConstant(m, "CSP_FFRAG", CSP_FFRAG); + PyModule_AddIntConstant(m, "CSP_FHMAC", CSP_FHMAC); + PyModule_AddIntConstant(m, "CSP_FXTEA", CSP_FXTEA); + PyModule_AddIntConstant(m, "CSP_FRDP", CSP_FRDP); + PyModule_AddIntConstant(m, "CSP_FCRC32", CSP_FCRC32); + + /* SOCKET OPTIONS */ + PyModule_AddIntConstant(m, "CSP_SO_NONE", CSP_SO_NONE); + PyModule_AddIntConstant(m, "CSP_SO_RDPREQ", CSP_SO_RDPREQ); + PyModule_AddIntConstant(m, "CSP_SO_RDPPROHIB", CSP_SO_RDPPROHIB); + PyModule_AddIntConstant(m, "CSP_SO_HMACREQ", CSP_SO_HMACREQ); + PyModule_AddIntConstant(m, "CSP_SO_HMACPROHIB", CSP_SO_HMACPROHIB); + PyModule_AddIntConstant(m, "CSP_SO_XTEAREQ", CSP_SO_XTEAREQ); + PyModule_AddIntConstant(m, "CSP_SO_XTEAPROHIB", CSP_SO_XTEAPROHIB); + PyModule_AddIntConstant(m, "CSP_SO_CRC32REQ", CSP_SO_CRC32REQ); + PyModule_AddIntConstant(m, "CSP_SO_CRC32PROHIB", CSP_SO_CRC32PROHIB); + PyModule_AddIntConstant(m, "CSP_SO_CONN_LESS", CSP_SO_CONN_LESS); + + /* CONNECT OPTIONS */ + PyModule_AddIntConstant(m, "CSP_O_NONE", CSP_O_NONE); + PyModule_AddIntConstant(m, "CSP_O_RDP", CSP_O_RDP); + PyModule_AddIntConstant(m, "CSP_O_NORDP", CSP_O_NORDP); + PyModule_AddIntConstant(m, "CSP_O_HMAC", CSP_O_HMAC); + PyModule_AddIntConstant(m, "CSP_O_NOHMAC", CSP_O_NOHMAC); + PyModule_AddIntConstant(m, "CSP_O_XTEA", CSP_O_XTEA); + PyModule_AddIntConstant(m, "CSP_O_NOXTEA", CSP_O_NOXTEA); + PyModule_AddIntConstant(m, "CSP_O_CRC32", CSP_O_CRC32); + PyModule_AddIntConstant(m, "CSP_O_NOCRC32", CSP_O_NOCRC32); + + + /** + * csp/csp_error.h + */ + + PyModule_AddIntConstant(m, "CSP_ERR_NONE", CSP_ERR_NONE); + PyModule_AddIntConstant(m, "CSP_ERR_NOMEM", CSP_ERR_NOMEM); + PyModule_AddIntConstant(m, "CSP_ERR_INVAL", CSP_ERR_INVAL); + PyModule_AddIntConstant(m, "CSP_ERR_TIMEDOUT", CSP_ERR_TIMEDOUT); + PyModule_AddIntConstant(m, "CSP_ERR_USED", CSP_ERR_USED); + PyModule_AddIntConstant(m, "CSP_ERR_NOTSUP", CSP_ERR_NOTSUP); + PyModule_AddIntConstant(m, "CSP_ERR_BUSY", CSP_ERR_BUSY); + PyModule_AddIntConstant(m, "CSP_ERR_ALREADY", CSP_ERR_ALREADY); + PyModule_AddIntConstant(m, "CSP_ERR_RESET", CSP_ERR_RESET); + PyModule_AddIntConstant(m, "CSP_ERR_NOBUFS", CSP_ERR_NOBUFS); + PyModule_AddIntConstant(m, "CSP_ERR_TX", CSP_ERR_TX); + PyModule_AddIntConstant(m, "CSP_ERR_DRIVER", CSP_ERR_DRIVER); + PyModule_AddIntConstant(m, "CSP_ERR_AGAIN", CSP_ERR_AGAIN); + PyModule_AddIntConstant(m, "CSP_ERR_HMAC", CSP_ERR_HMAC); + PyModule_AddIntConstant(m, "CSP_ERR_XTEA", CSP_ERR_XTEA); + PyModule_AddIntConstant(m, "CSP_ERR_CRC32", CSP_ERR_CRC32); + + /** + * csp/rtable.h + */ + PyModule_AddIntConstant(m, "CSP_NODE_MAC", CSP_NODE_MAC); + +#ifdef IS_PY3 + return m; +#endif + } + diff --git a/gomspace/libgscsp/lib/libcsp/src/crypto/csp_hmac.c b/gomspace/libgscsp/lib/libcsp/src/crypto/csp_hmac.c new file mode 100644 index 00000000..ae7fbb00 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/crypto/csp_hmac.c @@ -0,0 +1,202 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* Hash-based Message Authentication Code - based on code from libtom.org */ + +#include +#include +#include + +/* CSP includes */ +#include + +#include +#include + +#ifdef CSP_USE_HMAC + +#define HMAC_KEY_LENGTH 16 + +/* HMAC key */ +static uint8_t csp_hmac_key[HMAC_KEY_LENGTH]; + +/* HMAC state structure */ +typedef struct { + csp_sha1_state md; + uint8_t key[SHA1_BLOCKSIZE]; +} hmac_state; + +static int csp_hmac_init(hmac_state * hmac, const uint8_t * key, uint32_t keylen) { + uint32_t i; + uint8_t buf[SHA1_BLOCKSIZE]; + + /* NULL pointer and key check */ + if (!hmac || !key || keylen < 1) + return CSP_ERR_INVAL; + + /* Make sure we have a large enough key */ + if(keylen > SHA1_BLOCKSIZE) { + csp_sha1_memory(key, keylen, hmac->key); + if(SHA1_DIGESTSIZE < SHA1_BLOCKSIZE) + memset((hmac->key) + SHA1_DIGESTSIZE, 0, (size_t)(SHA1_BLOCKSIZE - SHA1_DIGESTSIZE)); + } else { + memcpy(hmac->key, key, (size_t)keylen); + if(keylen < SHA1_BLOCKSIZE) + memset((hmac->key) + keylen, 0, (size_t)(SHA1_BLOCKSIZE - keylen)); + } + + /* Create the initial vector */ + for(i = 0; i < SHA1_BLOCKSIZE; i++) + buf[i] = hmac->key[i] ^ 0x36; + + /* Prepend to the hash data */ + csp_sha1_init(&hmac->md); + csp_sha1_process(&hmac->md, buf, SHA1_BLOCKSIZE); + + return CSP_ERR_NONE; +} + +static int csp_hmac_process(hmac_state * hmac, const uint8_t * in, uint32_t inlen) { + + /* NULL pointer check */ + if (!hmac || !in) + return CSP_ERR_INVAL; + + /* Process data */ + csp_sha1_process(&hmac->md, in, inlen); + + return CSP_ERR_NONE; +} + +static int csp_hmac_done(hmac_state * hmac, uint8_t * out) { + + uint32_t i; + uint8_t buf[SHA1_BLOCKSIZE]; + uint8_t isha[SHA1_DIGESTSIZE]; + + if (!hmac || !out) + return CSP_ERR_INVAL; + + /* Get the hash of the first HMAC vector plus the data */ + csp_sha1_done(&hmac->md, isha); + + /* Create the second HMAC vector vector */ + for(i = 0; i < SHA1_BLOCKSIZE; i++) + buf[i] = hmac->key[i] ^ 0x5C; + + /* Now calculate the outer hash */ + csp_sha1_init(&hmac->md); + csp_sha1_process(&hmac->md, buf, SHA1_BLOCKSIZE); + csp_sha1_process(&hmac->md, isha, SHA1_DIGESTSIZE); + csp_sha1_done(&hmac->md, buf); + + /* Copy to output */ + for (i = 0; i < SHA1_DIGESTSIZE; i++) + out[i] = buf[i]; + + return CSP_ERR_NONE; +} + +int csp_hmac_memory(const uint8_t * key, uint32_t keylen, const uint8_t * data, uint32_t datalen, uint8_t * hmac) { + hmac_state state; + + /* NULL pointer check */ + if (!key || !data || !hmac) + return CSP_ERR_INVAL; + + /* Init HMAC state */ + if (csp_hmac_init(&state, key, keylen) != 0) + return CSP_ERR_INVAL; + + /* Process data */ + if (csp_hmac_process(&state, data, datalen) != 0) + return CSP_ERR_INVAL; + + /* Output HMAC */ + if (csp_hmac_done(&state, hmac) != 0) + return CSP_ERR_INVAL; + + return CSP_ERR_NONE; +} + +int csp_hmac_set_key(char * key, uint32_t keylen) { + + /* Use SHA1 as KDF */ + uint8_t hash[SHA1_DIGESTSIZE]; + csp_sha1_memory((uint8_t *)key, keylen, hash); + + /* Copy key */ + memcpy(csp_hmac_key, hash, HMAC_KEY_LENGTH); + + return CSP_ERR_NONE; + +} + +int csp_hmac_append(csp_packet_t * packet, bool include_header) { + + /* NULL pointer check */ + if (packet == NULL) + return CSP_ERR_INVAL; + + uint8_t hmac[SHA1_DIGESTSIZE]; + + /* Calculate HMAC */ + if (include_header) { + csp_hmac_memory(csp_hmac_key, HMAC_KEY_LENGTH, (uint8_t *) &packet->id, packet->length + sizeof(packet->id), hmac); + } else { + csp_hmac_memory(csp_hmac_key, HMAC_KEY_LENGTH, packet->data, packet->length, hmac); + } + + /* Truncate hash and copy to packet */ + memcpy(&packet->data[packet->length], hmac, CSP_HMAC_LENGTH); + packet->length += CSP_HMAC_LENGTH; + + return CSP_ERR_NONE; + +} + +int csp_hmac_verify(csp_packet_t * packet, bool include_header) { + + /* NULL pointer check */ + if (packet == NULL) + return CSP_ERR_INVAL; + + uint8_t hmac[SHA1_DIGESTSIZE]; + + /* Calculate HMAC */ + if (include_header) { + csp_hmac_memory(csp_hmac_key, HMAC_KEY_LENGTH, (uint8_t *) &packet->id, packet->length + sizeof(packet->id) - CSP_HMAC_LENGTH, hmac); + } else { + csp_hmac_memory(csp_hmac_key, HMAC_KEY_LENGTH, packet->data, packet->length - CSP_HMAC_LENGTH, hmac); + } + + /* Compare calculated HMAC with packet header */ + if (memcmp(&packet->data[packet->length] - CSP_HMAC_LENGTH, hmac, CSP_HMAC_LENGTH) != 0) { + /* HMAC failed */ + return CSP_ERR_HMAC; + } else { + /* Strip HMAC */ + packet->length -= CSP_HMAC_LENGTH; + return CSP_ERR_NONE; + } + +} + +#endif // CSP_USE_HMAC diff --git a/gomspace/libgscsp/lib/libcsp/src/crypto/csp_sha1.c b/gomspace/libgscsp/lib/libcsp/src/crypto/csp_sha1.c new file mode 100644 index 00000000..6c3920e9 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/crypto/csp_sha1.c @@ -0,0 +1,217 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* Code originally from Python's SHA1 Module, who based it on libtom.org */ + +#include +#include + +/* CSP includes */ +#include + +#include + +#if defined(CSP_USE_HMAC) || defined(CSP_USE_XTEA) + +/* Rotate left macro */ +#define ROL(x,y) (((x) << (y)) | ((x) >> (32-y))) + +/* Endian Neutral macros that work on all platforms */ +#define STORE32H(x, y) do { (y)[0] = (uint8_t)(((x) >> 24) & 0xff); \ + (y)[1] = (uint8_t)(((x) >> 16) & 0xff); \ + (y)[2] = (uint8_t)(((x) >> 8) & 0xff); \ + (y)[3] = (uint8_t)(((x) >> 0) & 0xff); } while (0) + +#define LOAD32H(x, y) do { (x) = ((uint32_t)((y)[0] & 0xff) << 24) | \ + ((uint32_t)((y)[1] & 0xff) << 16) | \ + ((uint32_t)((y)[2] & 0xff) << 8) | \ + ((uint32_t)((y)[3] & 0xff) << 0); } while (0) + +#define STORE64H(x, y) do { (y)[0] = (uint8_t)(((x) >> 56) & 0xff); \ + (y)[1] = (uint8_t)(((x) >> 48) & 0xff); \ + (y)[2] = (uint8_t)(((x) >> 40) & 0xff); \ + (y)[3] = (uint8_t)(((x) >> 32) & 0xff); \ + (y)[4] = (uint8_t)(((x) >> 24) & 0xff); \ + (y)[5] = (uint8_t)(((x) >> 16) & 0xff); \ + (y)[6] = (uint8_t)(((x) >> 8) & 0xff); \ + (y)[7] = (uint8_t)(((x) >> 0) & 0xff); } while (0) + +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) + +/* SHA1 macros */ +#define F0(x,y,z) (z ^ (x & (y ^ z))) +#define F1(x,y,z) (x ^ y ^ z) +#define F2(x,y,z) ((x & y) | (z & (x | y))) +#define F3(x,y,z) (x ^ y ^ z) + +#define FF_0(a, b, c, d, e, i) do {e = (ROL(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROL(b, 30);} while (0) +#define FF_1(a, b, c, d, e, i) do {e = (ROL(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROL(b, 30);} while (0) +#define FF_2(a, b, c, d, e, i) do {e = (ROL(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROL(b, 30);} while (0) +#define FF_3(a, b, c, d, e, i) do {e = (ROL(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROL(b, 30);} while (0) + +static void csp_sha1_compress(csp_sha1_state * sha1, const uint8_t * buf) { + + uint32_t a, b, c, d, e, W[80], i; + + /* Copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) + LOAD32H(W[i], buf + (4*i)); + + /* Copy state */ + a = sha1->state[0]; + b = sha1->state[1]; + c = sha1->state[2]; + d = sha1->state[3]; + e = sha1->state[4]; + + /* Expand it */ + for (i = 16; i < 80; i++) + W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1); + + /* Compress */ + i = 0; + + /* Round one */ + for (; i < 20;) { + FF_0(a, b, c, d, e, i++); + FF_0(e, a, b, c, d, i++); + FF_0(d, e, a, b, c, i++); + FF_0(c, d, e, a, b, i++); + FF_0(b, c, d, e, a, i++); + } + + /* Round two */ + for (; i < 40;) { + FF_1(a, b, c, d, e, i++); + FF_1(e, a, b, c, d, i++); + FF_1(d, e, a, b, c, i++); + FF_1(c, d, e, a, b, i++); + FF_1(b, c, d, e, a, i++); + } + + /* Round three */ + for (; i < 60;) { + FF_2(a, b, c, d, e, i++); + FF_2(e, a, b, c, d, i++); + FF_2(d, e, a, b, c, i++); + FF_2(c, d, e, a, b, i++); + FF_2(b, c, d, e, a, i++); + } + + /* Round four */ + for (; i < 80;) { + FF_3(a, b, c, d, e, i++); + FF_3(e, a, b, c, d, i++); + FF_3(d, e, a, b, c, i++); + FF_3(c, d, e, a, b, i++); + FF_3(b, c, d, e, a, i++); + } + + /* Store */ + sha1->state[0] += a; + sha1->state[1] += b; + sha1->state[2] += c; + sha1->state[3] += d; + sha1->state[4] += e; + +} + +void csp_sha1_init(csp_sha1_state * sha1) { + + sha1->state[0] = 0x67452301UL; + sha1->state[1] = 0xefcdab89UL; + sha1->state[2] = 0x98badcfeUL; + sha1->state[3] = 0x10325476UL; + sha1->state[4] = 0xc3d2e1f0UL; + sha1->curlen = 0; + sha1->length = 0; + +} + +void csp_sha1_process(csp_sha1_state * sha1, const uint8_t * in, uint32_t inlen) { + + uint32_t n; + while (inlen > 0) { + if (sha1->curlen == 0 && inlen >= SHA1_BLOCKSIZE) { + csp_sha1_compress(sha1, in); + sha1->length += SHA1_BLOCKSIZE * 8; + in += SHA1_BLOCKSIZE; + inlen -= SHA1_BLOCKSIZE; + } else { + n = MIN(inlen, (SHA1_BLOCKSIZE - sha1->curlen)); + memcpy(sha1->buf + sha1->curlen, in, (size_t)n); + sha1->curlen += n; + in += n; + inlen -= n; + if (sha1->curlen == SHA1_BLOCKSIZE) { + csp_sha1_compress(sha1, sha1->buf); + sha1->length += 8*SHA1_BLOCKSIZE; + sha1->curlen = 0; + } + } + } + +} + +void csp_sha1_done(csp_sha1_state * sha1, uint8_t * out) { + + uint32_t i; + + /* Increase the length of the message */ + sha1->length += sha1->curlen * 8; + + /* Append the '1' bit */ + sha1->buf[sha1->curlen++] = 0x80; + + /* If the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (sha1->curlen > 56) { + while (sha1->curlen < 64) + sha1->buf[sha1->curlen++] = 0; + csp_sha1_compress(sha1, sha1->buf); + sha1->curlen = 0; + } + + /* Pad up to 56 bytes of zeroes */ + while (sha1->curlen < 56) + sha1->buf[sha1->curlen++] = 0; + + /* Store length */ + STORE64H(sha1->length, sha1->buf + 56); + csp_sha1_compress(sha1, sha1->buf); + + /* Copy output */ + for (i = 0; i < 5; i++) + STORE32H(sha1->state[i], out + (4 * i)); + +} + +void csp_sha1_memory(const uint8_t * msg, uint32_t len, uint8_t * hash) { + + csp_sha1_state md; + csp_sha1_init(&md); + csp_sha1_process(&md, msg, len); + csp_sha1_done(&md, hash); + +} + +#endif // CSP_USE_HMAC diff --git a/gomspace/libgscsp/lib/libcsp/src/crypto/csp_xtea.c b/gomspace/libgscsp/lib/libcsp/src/crypto/csp_xtea.c new file mode 100644 index 00000000..718824d1 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/crypto/csp_xtea.c @@ -0,0 +1,134 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* Simple implementation of XTEA in CTR mode */ + +#include +#include + +/* CSP includes */ +#include +#include +#include +#include + +#ifdef CSP_USE_XTEA + +#define XTEA_BLOCKSIZE 8 +#define XTEA_ROUNDS 32 +#define XTEA_KEY_LENGTH 16 + +/* XTEA key */ +static uint32_t csp_xtea_key[XTEA_KEY_LENGTH/sizeof(uint32_t)] __attribute__ ((aligned(sizeof(uint32_t)))); + +#define STORE32L(x, y) do { (y)[3] = (uint8_t)(((x) >> 24) & 0xff); \ + (y)[2] = (uint8_t)(((x) >> 16) & 0xff); \ + (y)[1] = (uint8_t)(((x) >> 8) & 0xff); \ + (y)[0] = (uint8_t)(((x) >> 0) & 0xff); } while (0) + +#define LOAD32L(x, y) do { (x) = ((uint32_t)((y)[3] & 0xff) << 24) | \ + ((uint32_t)((y)[2] & 0xff) << 16) | \ + ((uint32_t)((y)[1] & 0xff) << 8) | \ + ((uint32_t)((y)[0] & 0xff) << 0); } while (0) + +/* This function takes 64 bits of data in block and the 128 bits key in key */ +static inline void csp_xtea_encrypt_block(uint8_t *block, uint8_t const *key) { + + uint32_t i, v0, v1, delta = 0x9E3779B9, sum = 0, k[4]; + + LOAD32L(k[0], &key[0]); + LOAD32L(k[1], &key[4]); + LOAD32L(k[2], &key[8]); + LOAD32L(k[3], &key[12]); + + LOAD32L(v0, &block[0]); + LOAD32L(v1, &block[4]); + + for (i = 0; i < XTEA_ROUNDS; i++) { + v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]); + sum += delta; + v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum >> 11) & 3]); + } + + STORE32L(v0, &block[0]); + STORE32L(v1, &block[4]); + +} + +static inline void csp_xtea_xor_byte(uint8_t * dst, uint8_t * src, uint32_t len) { + + unsigned int i; + for (i = 0; i < len; i++) + dst[i] ^= src[i]; + +} + +int csp_xtea_set_key(char * key, uint32_t keylen) { + + /* Use SHA1 as KDF */ + uint8_t hash[SHA1_DIGESTSIZE]; + csp_sha1_memory((uint8_t *)key, keylen, hash); + + /* Copy key */ + memcpy(csp_xtea_key, hash, XTEA_KEY_LENGTH); + + return CSP_ERR_NONE; + +} + +int csp_xtea_encrypt(uint8_t * plain, const uint32_t len, uint32_t iv[2]) { + + unsigned int i; + uint32_t stream[2]; + + uint32_t blocks = (len + XTEA_BLOCKSIZE - 1)/ XTEA_BLOCKSIZE; + uint32_t remain; + + /* Initialize stream */ + stream[0] = csp_htobe32(iv[0]); + stream[1] = csp_htobe32(iv[1]); + + for (i = 0; i < blocks; i++) { + /* Create stream */ + csp_xtea_encrypt_block((uint8_t *)stream, (uint8_t *)csp_xtea_key); + + /* Calculate remaining bytes */ + remain = len - i * XTEA_BLOCKSIZE; + + /* XOR plain text with stream to generate cipher text */ + csp_xtea_xor_byte(&plain[len - remain], (uint8_t *)stream, remain < XTEA_BLOCKSIZE ? remain : XTEA_BLOCKSIZE); + + /* Increment counter */ + stream[0] = csp_htobe32(iv[0]); + stream[1] = csp_htobe32(iv[1]++); + } + + return CSP_ERR_NONE; + +} + +int csp_xtea_decrypt(uint8_t * cipher, const uint32_t len, uint32_t iv[2]) { + + /* Since we use counter mode, we can reuse the encryption function */ + return csp_xtea_encrypt(cipher, len, iv); + +} + +#endif // CSP_USE_XTEA diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_bridge.c b/gomspace/libgscsp/lib/libcsp/src/csp_bridge.c new file mode 100644 index 00000000..1c579a9f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_bridge.c @@ -0,0 +1,94 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include "csp_route.h" +#include "csp_qfifo.h" +#include "csp_io.h" +#include "csp_promisc.h" + +static csp_iface_t* if_a = NULL; +static csp_iface_t* if_b = NULL; + +static CSP_DEFINE_TASK(csp_bridge) { + + csp_qfifo_t input; + csp_packet_t * packet; + + /* Here there be bridging */ + while (1) { + + /* Get next packet to route */ + if (csp_qfifo_read(&input) != CSP_ERR_NONE) + continue; + + packet = input.packet; + + csp_log_packet("Input: Src %u, Dst %u, Dport %u, Sport %u, Pri %u, Flags 0x%02X, Size %"PRIu16, + packet->id.src, packet->id.dst, packet->id.dport, + packet->id.sport, packet->id.pri, packet->id.flags, packet->length); + + /* Here there be promiscuous mode */ +#ifdef CSP_USE_PROMISC + csp_promisc_add(packet); +#endif + + /* Find the opposing interface */ + csp_iface_t * ifout; + if (input.interface == if_a) { + ifout = if_b; + } else { + ifout = if_a; + } + + /* Send to the interface directly, no hassle */ + if (csp_send_direct(packet->id, packet, ifout, 0) != CSP_ERR_NONE) { + csp_log_warn("Router failed to send"); + csp_buffer_free(packet); + } + + /* Next message, please */ + continue; + + } + + return CSP_TASK_RETURN; + +} + +int csp_bridge_start(unsigned int task_stack_size, unsigned int task_priority, csp_iface_t * _if_a, csp_iface_t * _if_b) { + + /* Set static references to A/B side of bridge */ + if_a = _if_a; + if_b = _if_b; + + static csp_thread_handle_t handle; + int ret = csp_thread_create(csp_bridge, "BRIDGE", task_stack_size, NULL, task_priority, &handle); + + if (ret != 0) { + csp_log_error("Failed to start task"); + return CSP_ERR_NOMEM; + } + + return CSP_ERR_NONE; + +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_buffer.c b/gomspace/libgscsp/lib/libcsp/src/csp_buffer.c new file mode 100644 index 00000000..8947f337 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_buffer.c @@ -0,0 +1,224 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +/* CSP includes */ +#include +#include +#include +#include +#include + +#ifndef CSP_BUFFER_ALIGN +#define CSP_BUFFER_ALIGN (sizeof(int *)) +#endif + +typedef struct csp_skbf_s { + unsigned int refcount; + void * skbf_addr; + char skbf_data[]; +} csp_skbf_t; + +static csp_queue_handle_t csp_buffers; +static char * csp_buffer_pool; +static unsigned int count, size; + +CSP_DEFINE_CRITICAL(csp_critical_lock); + +int csp_buffer_init(int buf_count, int buf_size) { + + unsigned int i; + csp_skbf_t * buf; + + count = buf_count; + size = buf_size + CSP_BUFFER_PACKET_OVERHEAD; + unsigned int skbfsize = (sizeof(csp_skbf_t) + size); + skbfsize = CSP_BUFFER_ALIGN * ((skbfsize + CSP_BUFFER_ALIGN - 1) / CSP_BUFFER_ALIGN); + unsigned int poolsize = count * skbfsize; + + csp_buffer_pool = csp_malloc(poolsize); + if (csp_buffer_pool == NULL) + goto fail_malloc; + + csp_buffers = csp_queue_create(count, sizeof(void *)); + if (!csp_buffers) + goto fail_queue; + + if (CSP_INIT_CRITICAL(csp_critical_lock) != CSP_ERR_NONE) + goto fail_critical; + + memset(csp_buffer_pool, 0, poolsize); + + for (i = 0; i < count; i++) { + + /* We have already taken care of pointer alignment since + * skbfsize is an integer multiple of sizeof(int *) + * but the explicit cast to a void * is still necessary + * to tell the compiler so. + */ + buf = (void *) &csp_buffer_pool[i * skbfsize]; + buf->refcount = 0; + buf->skbf_addr = buf; + + csp_queue_enqueue(csp_buffers, &buf, 0); + + } + + return CSP_ERR_NONE; + +fail_critical: + csp_queue_remove(csp_buffers); +fail_queue: + csp_free(csp_buffer_pool); +fail_malloc: + return CSP_ERR_NOMEM; + +} + +void *csp_buffer_get_isr(size_t buf_size) { + + csp_skbf_t * buffer = NULL; + CSP_BASE_TYPE task_woken = 0; + + if (buf_size + CSP_BUFFER_PACKET_OVERHEAD > size) + return NULL; + + csp_queue_dequeue_isr(csp_buffers, &buffer, &task_woken); + if (buffer == NULL) + return NULL; + + if (buffer != buffer->skbf_addr) + return NULL; + + buffer->refcount++; + return buffer->skbf_data; + +} + +void *csp_buffer_get(size_t buf_size) { + + csp_skbf_t * buffer = NULL; + + if (buf_size + CSP_BUFFER_PACKET_OVERHEAD > size) { + csp_log_error("Attempt to allocate too large block %u", buf_size); + return NULL; + } + + csp_queue_dequeue(csp_buffers, &buffer, 0); + if (buffer == NULL) { + csp_log_error("Out of buffers"); + return NULL; + } + + csp_log_buffer("GET: %p %p", buffer, buffer->skbf_addr); + + if (buffer != buffer->skbf_addr) { + csp_log_error("Corrupt CSP buffer"); + return NULL; + } + + buffer->refcount++; + return buffer->skbf_data; +} + +void csp_buffer_free_isr(void *packet) { + CSP_BASE_TYPE task_woken = 0; + if (!packet) + return; + + csp_skbf_t * buf = packet - sizeof(csp_skbf_t); + + if (((uintptr_t) buf % CSP_BUFFER_ALIGN) > 0) + return; + + if (buf->skbf_addr != buf) + return; + + if (buf->refcount == 0) { + return; + } else if (buf->refcount > 1) { + buf->refcount--; + return; + } else { + buf->refcount = 0; + csp_queue_enqueue_isr(csp_buffers, &buf, &task_woken); + } + +} + +void csp_buffer_free(void *packet) { + if (!packet) { + csp_log_error("Attempt to free null pointer"); + return; + } + + csp_skbf_t * buf = packet - sizeof(csp_skbf_t); + + if (((uintptr_t) buf % CSP_BUFFER_ALIGN) > 0) { + csp_log_error("FREE: Unaligned CSP buffer pointer %p", packet); + return; + } + + if (buf->skbf_addr != buf) { + csp_log_error("FREE: Invalid CSP buffer pointer %p", packet); + return; + } + + if (buf->refcount == 0) { + csp_log_error("FREE: Buffer already free %p", buf); + return; + } else if (buf->refcount > 1) { + buf->refcount--; + csp_log_error("FREE: Buffer %p in use by %u users", buf, buf->refcount); + return; + } else { + buf->refcount = 0; + csp_log_buffer("FREE: %p", buf); + csp_queue_enqueue(csp_buffers, &buf, 0); + } + +} + +void *csp_buffer_clone(void *buffer) { + + csp_packet_t *packet = (csp_packet_t *) buffer; + + if (!packet) + return NULL; + + csp_packet_t *clone = csp_buffer_get(packet->length); + + if (clone) + memcpy(clone, packet, size); + + return clone; + +} + +int csp_buffer_remaining(void) { + return csp_queue_size(csp_buffers); +} + +int csp_buffer_size(void) { + return size; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_conn.c b/gomspace/libgscsp/lib/libcsp/src/csp_conn.c new file mode 100644 index 00000000..7daa569d --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_conn.c @@ -0,0 +1,498 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +/* CSP includes */ +#include +#include + +#include +#include +#include +#include +#include + +#include "csp_conn.h" +#include "transport/csp_transport.h" + +/* Static connection pool */ +static csp_conn_t arr_conn[CSP_CONN_MAX]; + +/* Connection pool lock */ +static csp_bin_sem_handle_t conn_lock; + +/* Source port */ +static uint8_t sport; + +/* Source port lock */ +static csp_bin_sem_handle_t sport_lock; + +void csp_conn_check_timeouts(void) { +#ifdef CSP_USE_RDP + int i; + for (i = 0; i < CSP_CONN_MAX; i++) + if (arr_conn[i].state == CONN_OPEN) + if (arr_conn[i].idin.flags & CSP_FRDP) + csp_rdp_check_timeouts(&arr_conn[i]); +#endif +} + +int csp_conn_get_rxq(int prio) { + +#ifdef CSP_USE_QOS + return prio; +#else + return 0; +#endif + +} + +int csp_conn_lock(csp_conn_t * conn, uint32_t timeout) { + + if (csp_mutex_lock(&conn->lock, timeout) != CSP_MUTEX_OK) + return CSP_ERR_TIMEDOUT; + + return CSP_ERR_NONE; + +} + +int csp_conn_unlock(csp_conn_t * conn) { + + csp_mutex_unlock(&conn->lock); + + return CSP_ERR_NONE; + +} + +int csp_conn_enqueue_packet(csp_conn_t * conn, csp_packet_t * packet) { + + if (!conn) + return CSP_ERR_INVAL; + + int rxq; + if (packet != NULL) { + rxq = csp_conn_get_rxq(packet->id.pri); + } else { + rxq = CSP_RX_QUEUES - 1; + } + + if (csp_queue_enqueue(conn->rx_queue[rxq], &packet, 0) != CSP_QUEUE_OK) { + csp_log_error("RX queue %p full with %u items", conn->rx_queue[rxq], csp_queue_size(conn->rx_queue[rxq])); + return CSP_ERR_NOMEM; + } + +#ifdef CSP_USE_QOS + int event = 0; + if (csp_queue_enqueue(conn->rx_event, &event, 0) != CSP_QUEUE_OK) { + csp_log_error("QOS event queue full"); + return CSP_ERR_NOMEM; + } +#endif + + return CSP_ERR_NONE; +} + +int csp_conn_init(void) { + + /* Initialize source port */ + srand(csp_get_ms()); + sport = (rand() % (CSP_ID_PORT_MAX - CSP_MAX_BIND_PORT)) + (CSP_MAX_BIND_PORT + 1); + + if (csp_bin_sem_create(&sport_lock) != CSP_SEMAPHORE_OK) { + csp_log_error("No more memory for sport semaphore"); + return CSP_ERR_NOMEM; + } + + int i, prio; + for (i = 0; i < CSP_CONN_MAX; i++) { + for (prio = 0; prio < CSP_RX_QUEUES; prio++) + arr_conn[i].rx_queue[prio] = csp_queue_create(CSP_RX_QUEUE_LENGTH, sizeof(csp_packet_t *)); + +#ifdef CSP_USE_QOS + arr_conn[i].rx_event = csp_queue_create(CSP_CONN_QUEUE_LENGTH, sizeof(int)); +#endif + arr_conn[i].state = CONN_CLOSED; + + if (csp_mutex_create(&arr_conn[i].lock) != CSP_MUTEX_OK) { + csp_log_error("Failed to create connection lock"); + return CSP_ERR_NOMEM; + } + +#ifdef CSP_USE_RDP + if (csp_rdp_allocate(&arr_conn[i]) != CSP_ERR_NONE) { + csp_log_error("Failed to create queues for RDP in csp_conn_init"); + return CSP_ERR_NOMEM; + } +#endif + } + + if (csp_bin_sem_create(&conn_lock) != CSP_SEMAPHORE_OK) { + csp_log_error("No more memory for conn semaphore"); + return CSP_ERR_NOMEM; + } + + return CSP_ERR_NONE; + +} + +csp_conn_t * csp_conn_find(uint32_t id, uint32_t mask) { + + /* Search for matching connection */ + int i; + csp_conn_t * conn; + id = (id & mask); + for (i = 0; i < CSP_CONN_MAX; i++) { + conn = &arr_conn[i]; + if ((conn->state != CONN_CLOSED) && (conn->type == CONN_CLIENT) && ((conn->idin.ext & mask) == id)) + return conn; + } + + return NULL; + +} + +static int csp_conn_flush_rx_queue(csp_conn_t * conn) { + + csp_packet_t * packet; + + int prio; + + /* Flush packet queues */ + for (prio = 0; prio < CSP_RX_QUEUES; prio++) { + while (csp_queue_dequeue(conn->rx_queue[prio], &packet, 0) == CSP_QUEUE_OK) + if (packet != NULL) + csp_buffer_free(packet); + } + + /* Flush event queue */ +#ifdef CSP_USE_QOS + int event; + while (csp_queue_dequeue(conn->rx_event, &event, 0) == CSP_QUEUE_OK); +#endif + + return CSP_ERR_NONE; + +} + +csp_conn_t * csp_conn_allocate(csp_conn_type_t type) { + + int i, j; + static uint8_t csp_conn_last_given = 0; + csp_conn_t * conn; + + if (csp_bin_sem_wait(&conn_lock, 100) != CSP_SEMAPHORE_OK) { + csp_log_error("Failed to lock conn array"); + return NULL; + } + + /* Search for free connection */ + i = csp_conn_last_given; + i = (i + 1) % CSP_CONN_MAX; + + for (j = 0; j < CSP_CONN_MAX; j++) { + conn = &arr_conn[i]; + if (conn->state == CONN_CLOSED) + break; + i = (i + 1) % CSP_CONN_MAX; + } + + if (conn->state == CONN_OPEN) { + csp_log_error("No more free connections"); + csp_bin_sem_post(&conn_lock); + return NULL; + } + + conn->idin.ext = 0; + conn->idout.ext = 0; + conn->socket = NULL; + conn->timestamp = 0; + conn->type = type; + conn->state = CONN_OPEN; + + csp_conn_last_given = i; + csp_bin_sem_post(&conn_lock); + + return conn; + +} + +csp_conn_t * csp_conn_new(csp_id_t idin, csp_id_t idout) { + + /* Allocate connection structure */ + csp_conn_t * conn = csp_conn_allocate(CONN_CLIENT); + + if (conn) { + /* No lock is needed here, because nobody else * + * has a reference to this connection yet. */ + conn->idin.ext = idin.ext; + conn->idout.ext = idout.ext; + conn->timestamp = csp_get_ms(); + + /* Ensure connection queue is empty */ + csp_conn_flush_rx_queue(conn); + } + + return conn; + +} + +int csp_close(csp_conn_t * conn) { + + if (conn == NULL) { + csp_log_error("NULL Pointer given to csp_close"); + return CSP_ERR_INVAL; + } + + if (conn->state == CONN_CLOSED) { + csp_log_protocol("Conn already closed"); + return CSP_ERR_NONE; + } + +#ifdef CSP_USE_RDP + /* Ensure RDP knows this connection is closing */ + if (conn->idin.flags & CSP_FRDP || conn->idout.flags & CSP_FRDP) + if (csp_rdp_close(conn) == CSP_ERR_AGAIN) + return CSP_ERR_NONE; +#endif + + /* Lock connection array while closing connection */ + if (csp_bin_sem_wait(&conn_lock, 100) != CSP_SEMAPHORE_OK) { + csp_log_error("Failed to lock conn array"); + return CSP_ERR_TIMEDOUT; + } + + /* Set to closed */ + conn->state = CONN_CLOSED; + + /* Ensure connection queue is empty */ + csp_conn_flush_rx_queue(conn); + + if (conn->socket && (conn->type == CONN_SERVER) && (conn->opts & (CSP_SO_CONN_LESS | CSP_SO_INTERNAL_LISTEN))) { + csp_queue_remove(conn->socket); + conn->socket = NULL; + } + + /* Reset RDP state */ +#ifdef CSP_USE_RDP + if (conn->idin.flags & CSP_FRDP) + csp_rdp_flush_all(conn); +#endif + + /* Unlock connection array */ + csp_bin_sem_post(&conn_lock); + + return CSP_ERR_NONE; +} + +csp_conn_t * csp_connect(uint8_t prio, uint8_t dest, uint8_t dport, uint32_t timeout, uint32_t opts) { + + /* Force options on all connections */ + opts |= CSP_CONNECTION_SO; + + /* Generate identifier */ + csp_id_t incoming_id, outgoing_id; + incoming_id.pri = prio; + incoming_id.dst = csp_get_address(); + incoming_id.src = dest; + incoming_id.sport = dport; + incoming_id.flags = 0; + outgoing_id.pri = prio; + outgoing_id.dst = dest; + outgoing_id.src = csp_get_address(); + outgoing_id.dport = dport; + outgoing_id.flags = 0; + + /* Set connection options */ + if (opts & CSP_O_NOCRC32) { + opts &= ~CSP_O_CRC32; + } + + if (opts & CSP_O_RDP) { +#ifdef CSP_USE_RDP + incoming_id.flags |= CSP_FRDP; + outgoing_id.flags |= CSP_FRDP; +#else + csp_log_error("Attempt to create RDP connection, but CSP was compiled without RDP support"); + return NULL; +#endif + } + + if (opts & CSP_O_HMAC) { +#ifdef CSP_USE_HMAC + outgoing_id.flags |= CSP_FHMAC; + incoming_id.flags |= CSP_FHMAC; +#else + csp_log_error("Attempt to create HMAC authenticated connection, but CSP was compiled without HMAC support"); + return NULL; +#endif + } + + if (opts & CSP_O_XTEA) { +#ifdef CSP_USE_XTEA + outgoing_id.flags |= CSP_FXTEA; + incoming_id.flags |= CSP_FXTEA; +#else + csp_log_error("Attempt to create XTEA encrypted connection, but CSP was compiled without XTEA support"); + return NULL; +#endif + } + + if (opts & CSP_O_CRC32) { +#ifdef CSP_USE_CRC32 + outgoing_id.flags |= CSP_FCRC32; + incoming_id.flags |= CSP_FCRC32; +#else + csp_log_error("Attempt to create CRC32 validated connection, but CSP was compiled without CRC32 support"); + return NULL; +#endif + } + + /* Find an unused ephemeral port */ + csp_conn_t * conn = NULL; + + /* Wait for sport lock - note that csp_conn_new(..) is called inside the lock! */ + if (csp_bin_sem_wait(&sport_lock, 1000) != CSP_SEMAPHORE_OK) + return NULL; + + const uint8_t start = sport; + while (++sport != start) { + if (sport > CSP_ID_PORT_MAX) + sport = CSP_MAX_BIND_PORT + 1; + + outgoing_id.sport = sport; + incoming_id.dport = sport; + + /* Match on destination port of _incoming_ identifier */ + if (csp_conn_find(incoming_id.ext, CSP_ID_DPORT_MASK) == NULL) { + /* Break - we found an unused ephemeral port + allocate connection while locked to mark port in use */ + conn = csp_conn_new(incoming_id, outgoing_id); + break; + } + } + + /* Post sport lock */ + csp_bin_sem_post(&sport_lock); + + if (conn == NULL) + return NULL; + + /* Set connection options */ + conn->opts = opts; + +#ifdef CSP_USE_RDP + /* Call Transport Layer connect */ + if (outgoing_id.flags & CSP_FRDP) { + /* If the transport layer has failed to connect + * deallocate connection structure again and return NULL */ + if (csp_rdp_connect(conn, timeout) != CSP_ERR_NONE) { + csp_close(conn); + return NULL; + } + } +#endif + + /* We have a successful connection */ + return conn; + +} + +inline int csp_conn_dport(csp_conn_t * conn) { + + return conn->idin.dport; + +} + +inline int csp_conn_sport(csp_conn_t * conn) { + + return conn->idin.sport; + +} + +inline int csp_conn_dst(csp_conn_t * conn) { + + return conn->idin.dst; + +} + +inline int csp_conn_src(csp_conn_t * conn) { + + return conn->idin.src; + +} + +inline int csp_conn_flags(csp_conn_t * conn) { + + return conn->idin.flags; + +} + +#ifdef CSP_DEBUG +void csp_conn_print_table(void) { + + int i; + csp_conn_t * conn; + + for (i = 0; i < CSP_CONN_MAX; i++) { + conn = &arr_conn[i]; + printf("[%02u %p] S:%u, %u -> %u, %u -> %u, sock: %p\r\n", + i, conn, conn->state, conn->idin.src, conn->idin.dst, + conn->idin.dport, conn->idin.sport, conn->socket); +#ifdef CSP_USE_RDP + if (conn->idin.flags & CSP_FRDP) + csp_rdp_conn_print(conn); +#endif + } +} + +int csp_conn_print_table_str(char * str_buf, int str_size) { + + int i, start = 0; + csp_conn_t * conn; + char buf[100]; + + /* Display up to 10 connections */ + if (CSP_CONN_MAX - 10 > 0) + start = CSP_CONN_MAX - 10; + + for (i = start; i < CSP_CONN_MAX; i++) { + conn = &arr_conn[i]; + snprintf(buf, sizeof(buf), "[%02u %p] S:%u, %u -> %u, %u -> %u, sock: %p\n", + i, conn, conn->state, conn->idin.src, conn->idin.dst, + conn->idin.dport, conn->idin.sport, conn->socket); + + strncat(str_buf, buf, str_size); + if ((str_size -= strlen(buf)) <= 0) + break; + } + + return CSP_ERR_NONE; +} +#endif + +const csp_conn_t * csp_conn_get_array(size_t * size) +{ + *size = CSP_CONN_MAX; + return arr_conn; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_conn.h b/gomspace/libgscsp/lib/libcsp/src/csp_conn.h new file mode 100644 index 00000000..3fa0ff52 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_conn.h @@ -0,0 +1,112 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_CONN_H_ +#define _CSP_CONN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +#include +#include + +/** @brief Connection states */ +typedef enum { + CONN_CLOSED = 0, + CONN_OPEN = 1, +} csp_conn_state_t; + +/** @brief Connection types */ +typedef enum { + CONN_CLIENT = 0, + CONN_SERVER = 1, +} csp_conn_type_t; + +typedef enum { + RDP_CLOSED = 0, + RDP_SYN_SENT, + RDP_SYN_RCVD, + RDP_OPEN, + RDP_CLOSE_WAIT, +} csp_rdp_state_t; + +/** @brief RDP Connection header + * @note Do not try to pack this struct, the posix sem handle will stop working */ +typedef struct { + csp_rdp_state_t state; /**< Connection state */ + uint16_t snd_nxt; /**< The sequence number of the next segment that is to be sent */ + uint16_t snd_una; /**< The sequence number of the oldest unacknowledged segment */ + uint16_t snd_iss; /**< The initial send sequence number */ + uint16_t rcv_cur; /**< The sequence number of the last segment received correctly and in sequence */ + uint16_t rcv_irs; /**< The initial receive sequence number */ + uint16_t rcv_lsa; /**< The last sequence number acknowledged by the receiver */ + uint32_t window_size; + uint32_t conn_timeout; + uint32_t packet_timeout; + uint32_t delayed_acks; + uint32_t ack_timeout; + uint32_t ack_delay_count; + uint32_t ack_timestamp; + csp_bin_sem_handle_t tx_wait; + csp_queue_handle_t tx_queue; + csp_queue_handle_t rx_queue; +} csp_rdp_t; + +/** @brief Connection struct */ +struct csp_conn_s { + csp_conn_type_t type; /* Connection type (CONN_CLIENT or CONN_SERVER) */ + csp_conn_state_t state; /* Connection state (CONN_OPEN or CONN_CLOSED) */ + csp_mutex_t lock; /* Connection structure lock */ + csp_id_t idin; /* Identifier received */ + csp_id_t idout; /* Identifier transmitted */ +#ifdef CSP_USE_QOS + csp_queue_handle_t rx_event; /* Event queue for RX packets */ +#endif + csp_queue_handle_t rx_queue[CSP_RX_QUEUES]; /* Queue for RX packets */ + csp_queue_handle_t socket; /* Socket to be "woken" when first packet is ready */ + uint32_t timestamp; /* Time the connection was opened */ + uint32_t opts; /* Connection or socket options */ +#ifdef CSP_USE_RDP + csp_rdp_t rdp; /* RDP state */ +#endif +}; + +int csp_conn_lock(csp_conn_t * conn, uint32_t timeout); +int csp_conn_unlock(csp_conn_t * conn); +int csp_conn_enqueue_packet(csp_conn_t * conn, csp_packet_t * packet); +int csp_conn_init(void); +csp_conn_t * csp_conn_allocate(csp_conn_type_t type); +csp_conn_t * csp_conn_find(uint32_t id, uint32_t mask); +csp_conn_t * csp_conn_new(csp_id_t idin, csp_id_t idout); +void csp_conn_check_timeouts(void); +int csp_conn_get_rxq(int prio); + +const csp_conn_t * csp_conn_get_array(size_t * size); // for test purposes only! + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_CONN_H_ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_crc32.c b/gomspace/libgscsp/lib/libcsp/src/csp_crc32.c new file mode 100644 index 00000000..8bf2145f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_crc32.c @@ -0,0 +1,140 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +#include +#include + +#include + +#ifdef CSP_USE_CRC32 + +#ifdef __AVR__ +#include +static const uint32_t crc_tab[256] PROGMEM = { +#else +static const uint32_t crc_tab[256] = { +#endif + 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, + 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, + 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, + 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, + 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, + 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, + 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, + 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, + 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, + 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, + 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, + 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, + 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, + 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, + 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, + 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, + 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, + 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, + 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, + 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, + 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, + 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, + 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, + 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, + 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, + 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, + 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, + 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, + 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, + 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, + 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, + 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 }; + +uint32_t csp_crc32_memory(const uint8_t * data, uint32_t length) { + uint32_t crc; + + crc = 0xFFFFFFFF; + while (length--) +#ifdef __AVR__ + crc = pgm_read_dword(&crc_tab[(crc ^ *data++) & 0xFFL]) ^ (crc >> 8); +#else + crc = crc_tab[(crc ^ *data++) & 0xFFL] ^ (crc >> 8); +#endif + + return (crc ^ 0xFFFFFFFF); +} + +int csp_crc32_append(csp_packet_t * packet, bool include_header) { + + uint32_t crc; + + /* NULL pointer check */ + if (packet == NULL) + return CSP_ERR_INVAL; + + /* Calculate CRC32, convert to network byte order */ + if (include_header) { + crc = csp_crc32_memory((uint8_t *) &packet->id, packet->length + sizeof(packet->id)); + } else { + crc = csp_crc32_memory(packet->data, packet->length); + } + crc = csp_hton32(crc); + + /* Copy checksum to packet */ + memcpy(&packet->data[packet->length], &crc, sizeof(uint32_t)); + packet->length += sizeof(uint32_t); + + return CSP_ERR_NONE; + +} + +int csp_crc32_verify(csp_packet_t * packet, bool include_header) { + + uint32_t crc; + + /* NULL pointer check */ + if (packet == NULL) + return CSP_ERR_INVAL; + + if (packet->length < sizeof(uint32_t)) + return CSP_ERR_INVAL; + + /* Calculate CRC32, convert to network byte order */ + if (include_header) { + crc = csp_crc32_memory((uint8_t *) &packet->id, packet->length + sizeof(packet->id) - sizeof(uint32_t)); + } else { + crc = csp_crc32_memory(packet->data, packet->length - sizeof(uint32_t)); + } + crc = csp_hton32(crc); + + /* Compare calculated checksum with packet header */ + if (memcmp(&packet->data[packet->length] - sizeof(uint32_t), &crc, sizeof(uint32_t)) != 0) { + /* CRC32 failed */ + return CSP_ERR_INVAL; + } else { + /* Strip CRC32 */ + packet->length -= sizeof(uint32_t); + return CSP_ERR_NONE; + } + +} + +#endif // CSP_USE_CRC32 diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_debug.c b/gomspace/libgscsp/lib/libcsp/src/csp_debug.c new file mode 100644 index 00000000..2e710cb3 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_debug.c @@ -0,0 +1,133 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +#ifdef __AVR__ +#include +#endif + +/* CSP includes */ +#include + +#include + +/* Custom debug function */ +csp_debug_hook_func_t csp_debug_hook_func = NULL; + +/* Debug levels */ +static bool csp_debug_level_enabled[] = { + [CSP_ERROR] = true, + [CSP_WARN] = true, + [CSP_INFO] = false, + [CSP_BUFFER] = false, + [CSP_PACKET] = false, + [CSP_PROTOCOL] = false, + [CSP_LOCK] = false, +}; + +/* Some compilers do not support weak symbols, so this function + * can be used instead to set a custom debug hook */ +void csp_debug_hook_set(csp_debug_hook_func_t f) +{ + csp_debug_hook_func = f; +} + +void do_csp_debug(csp_debug_level_t level, const char *format, ...) +{ + int color = COLOR_RESET; + va_list args; + + /* Don't print anything if log level is disabled */ + if (level > CSP_LOCK || !csp_debug_level_enabled[level]) + return; + + switch(level) { + case CSP_INFO: + color = COLOR_GREEN | COLOR_BOLD; + break; + case CSP_ERROR: + color = COLOR_RED | COLOR_BOLD; + break; + case CSP_WARN: + color = COLOR_YELLOW | COLOR_BOLD; + break; + case CSP_BUFFER: + color = COLOR_MAGENTA; + break; + case CSP_PACKET: + color = COLOR_GREEN; + break; + case CSP_PROTOCOL: + color = COLOR_BLUE; + break; + case CSP_LOCK: + color = COLOR_CYAN; + break; + default: + return; + } + + va_start(args, format); + + /* If csp_debug_hook symbol is defined, pass on the message. + * Otherwise, just print with pretty colors ... */ + if (csp_debug_hook_func) { + csp_debug_hook_func(level, format, args); + } else { + csp_sys_set_color(color); +#ifdef __AVR__ + vfprintf_P(stdout, format, args); +#else + vprintf(format, args); +#endif + printf("\r\n"); + csp_sys_set_color(COLOR_RESET); + } + + va_end(args); +} + +void csp_debug_set_level(csp_debug_level_t level, bool value) +{ + if (level > CSP_LOCK) + return; + csp_debug_level_enabled[level] = value; +} + +int csp_debug_get_level(csp_debug_level_t level) +{ + if (level > CSP_LOCK) + return 0; + return csp_debug_level_enabled[level]; +} + +void csp_debug_toggle_level(csp_debug_level_t level) +{ + if (level > CSP_LOCK) { + printf("Max level is 6\r\n"); + return; + } + csp_debug_level_enabled[level] = (csp_debug_level_enabled[level]) ? false : true; + printf("Level %u: value %u\r\n", level, csp_debug_level_enabled[level]); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_dedup.c b/gomspace/libgscsp/lib/libcsp/src/csp_dedup.c new file mode 100644 index 00000000..d263c7a4 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_dedup.c @@ -0,0 +1,66 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +#include +#include +#include + +#include "csp_dedup.h" + +/* Check the last CSP_DEDUP_COUNT packets for duplicates */ +#define CSP_DEDUP_COUNT 16 + +/* Only consider packet a duplicate if received under CSP_DEDUP_WINDOW_MS ago */ +#define CSP_DEDUP_WINDOW_MS 1000 + +/* Store packet CRC's in a ringbuffer */ +static uint32_t csp_dedup_array[CSP_DEDUP_COUNT] = {}; +static uint32_t csp_dedup_timestamp[CSP_DEDUP_COUNT] = {}; +static int csp_dedup_in = 0; + +bool csp_dedup_is_duplicate(csp_packet_t *packet) +{ + /* Calculate CRC32 for packet */ + uint32_t crc = csp_crc32_memory((const uint8_t *) &packet->id, packet->length + sizeof(packet->id)); + + /* Check if we have received this packet before */ + for (int i = 0; i < CSP_DEDUP_COUNT; i++) { + + /* Check for match */ + if (crc == csp_dedup_array[i]) { + + /* Check the timestamp */ + if (csp_get_ms() < csp_dedup_timestamp[i] + CSP_DEDUP_WINDOW_MS) + return true; + } + } + + /* If not, insert packet into duplicate list */ + csp_dedup_array[csp_dedup_in] = crc; + csp_dedup_timestamp[csp_dedup_in] = csp_get_ms(); + csp_dedup_in = (csp_dedup_in + 1) % CSP_DEDUP_COUNT; + + return false; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_dedup.h b/gomspace/libgscsp/lib/libcsp/src/csp_dedup.h new file mode 100644 index 00000000..75a3f124 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_dedup.h @@ -0,0 +1,31 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CSP_DEDUP_H_ +#define CSP_DEDUP_H_ + +/** + * Check for a duplicate packet + * @param packet pointer to packet + * @return false if not a duplicate, true if duplicate + */ +bool csp_dedup_is_duplicate(csp_packet_t *packet); + +#endif /* CSP_DEDUP_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_endian.c b/gomspace/libgscsp/lib/libcsp/src/csp_endian.c new file mode 100644 index 00000000..6d0ef226 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_endian.c @@ -0,0 +1,204 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +/* CSP includes */ +#include +#include + +/* Convert 16-bit number from host byte order to network byte order */ +inline uint16_t __attribute__ ((__const__)) csp_hton16(uint16_t h16) { +#ifdef CSP_BIG_ENDIAN + return h16; +#else + return (((h16 & 0xff00) >> 8) | + ((h16 & 0x00ff) << 8)); +#endif +} + +/* Convert 16-bit number from network byte order to host byte order */ +inline uint16_t __attribute__ ((__const__)) csp_ntoh16(uint16_t n16) { + return csp_hton16(n16); +} + +/* Convert 32-bit number from host byte order to network byte order */ +inline uint32_t __attribute__ ((__const__)) csp_hton32(uint32_t h32) { +#ifdef CSP_BIG_ENDIAN + return h32; +#else + return (((h32 & 0xff000000) >> 24) | + ((h32 & 0x000000ff) << 24) | + ((h32 & 0x0000ff00) << 8) | + ((h32 & 0x00ff0000) >> 8)); +#endif +} + +/* Convert 32-bit number from network byte order to host byte order */ +inline uint32_t __attribute__ ((__const__)) csp_ntoh32(uint32_t n32) { + return csp_hton32(n32); +} + +/* Convert 64-bit number from host byte order to network byte order */ +inline uint64_t __attribute__ ((__const__)) csp_hton64(uint64_t h64) { +#ifdef CSP_BIG_ENDIAN + return h64; +#else + return (((h64 & 0xff00000000000000LL) >> 56) | + ((h64 & 0x00000000000000ffLL) << 56) | + ((h64 & 0x00ff000000000000LL) >> 40) | + ((h64 & 0x000000000000ff00LL) << 40) | + ((h64 & 0x0000ff0000000000LL) >> 24) | + ((h64 & 0x0000000000ff0000LL) << 24) | + ((h64 & 0x000000ff00000000LL) >> 8) | + ((h64 & 0x00000000ff000000LL) << 8)); +#endif +} + +/* Convert 64-bit number from host byte order to network byte order */ +inline uint64_t __attribute__ ((__const__)) csp_ntoh64(uint64_t n64) { + return csp_hton64(n64); +} + +/* Convert 16-bit number from host byte order to big endian byte order */ +inline uint16_t __attribute__ ((__const__)) csp_htobe16(uint16_t h16) { + return csp_hton16(h16); +} + +/* Convert 16-bit number from host byte order to little endian byte order */ +inline uint16_t __attribute__ ((__const__)) csp_htole16(uint16_t h16) { +#ifdef CSP_LITTLE_ENDIAN + return h16; +#else + return (((h16 & 0xff00) >> 8) | + ((h16 & 0x00ff) << 8)); +#endif +} + +/* Convert 16-bit number from big endian byte order to little endian byte order */ +inline uint16_t __attribute__ ((__const__)) csp_betoh16(uint16_t be16) { + return csp_ntoh16(be16); +} + +/* Convert 16-bit number from little endian byte order to host byte order */ +inline uint16_t __attribute__ ((__const__)) csp_letoh16(uint16_t le16) { + return csp_htole16(le16); +} + +/* Convert 32-bit number from host byte order to big endian byte order */ +inline uint32_t __attribute__ ((__const__)) csp_htobe32(uint32_t h32) { + return csp_hton32(h32); +} + +/* Convert 32-bit number from little endian byte order to host byte order */ +inline uint32_t __attribute__ ((__const__)) csp_htole32(uint32_t h32) { +#ifdef CSP_LITTLE_ENDIAN + return h32; +#else + return (((h32 & 0xff000000) >> 24) | + ((h32 & 0x000000ff) << 24) | + ((h32 & 0x0000ff00) << 8) | + ((h32 & 0x00ff0000) >> 8)); +#endif +} + +/* Convert 32-bit number from big endian byte order to host byte order */ +inline uint32_t __attribute__ ((__const__)) csp_betoh32(uint32_t be32) { + return csp_ntoh32(be32); +} + +/* Convert 32-bit number from little endian byte order to host byte order */ +inline uint32_t __attribute__ ((__const__)) csp_letoh32(uint32_t le32) { + return csp_htole32(le32); +} + +/* Convert 64-bit number from host byte order to big endian byte order */ +inline uint64_t __attribute__ ((__const__)) csp_htobe64(uint64_t h64) { + return csp_hton64(h64); +} + +/* Convert 64-bit number from host byte order to little endian byte order */ +inline uint64_t __attribute__ ((__const__)) csp_htole64(uint64_t h64) { +#ifdef CSP_LITTLE_ENDIAN + return h64; +#else + return (((h64 & 0xff00000000000000LL) >> 56) | + ((h64 & 0x00000000000000ffLL) << 56) | + ((h64 & 0x00ff000000000000LL) >> 40) | + ((h64 & 0x000000000000ff00LL) << 40) | + ((h64 & 0x0000ff0000000000LL) >> 24) | + ((h64 & 0x0000000000ff0000LL) << 24) | + ((h64 & 0x000000ff00000000LL) >> 8) | + ((h64 & 0x00000000ff000000LL) << 8)); +#endif +} + +/* Convert 64-bit number from big endian byte order to host byte order */ +inline uint64_t __attribute__ ((__const__)) csp_betoh64(uint64_t be64) { + return csp_ntoh64(be64); +} + +/* Convert 64-bit number from little endian byte order to host byte order */ +inline uint64_t __attribute__ ((__const__)) csp_letoh64(uint64_t le64) { + return csp_htole64(le64); +} + + +/* Convert float from host byte order to network byte order */ +inline float __attribute__ ((__const__)) csp_htonflt(float f) { +#ifdef CSP_BIG_ENDIAN + return f; +#else + union v { + float f; + uint32_t i; + }; + union v val; + val.f = f; + val.i = csp_hton32(val.i); + return val.f; +#endif +} + +/* Convert float from host byte order to network byte order */ +inline float __attribute__ ((__const__)) csp_ntohflt(float f) { + return csp_htonflt(f); +} + +/* Convert double from host byte order to network byte order */ +inline double __attribute__ ((__const__)) csp_htondbl(double d) { +#ifdef CSP_BIG_ENDIAN + return d; +#else + union v { + double d; + uint64_t i; + }; + union v val; + val.d = d; + val.i = csp_hton64(val.i); + return val.d; +#endif +} + +/* Convert float from host byte order to network byte order */ +inline double __attribute__ ((__const__)) csp_ntohdbl(double d) { + return csp_htondbl(d); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_hex_dump.c b/gomspace/libgscsp/lib/libcsp/src/csp_hex_dump.c new file mode 100644 index 00000000..af0a2660 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_hex_dump.c @@ -0,0 +1,55 @@ +#include +#include + +void csp_hex_dump (const char *desc, void *addr, int len) +{ + int i; + unsigned char buff[17]; + unsigned char *pc = (unsigned char*)addr; + + // Output description if given. + if (desc != NULL) + printf ("%s:\r\n", desc); + + if (len == 0) { + printf(" ZERO LENGTH\r\n"); + return; + } + if (len < 0) { + printf(" NEGATIVE LENGTH: %i\r\n",len); + return; + } + + // Process every byte in the data. + for (i = 0; i < len; i++) { + // Multiple of 16 means new line (with line offset). + + if ((i % 16) == 0) { + // Just don't print ASCII for the zeroth line. + if (i != 0) + printf (" %s\r\n", buff); + + // Output the offset. + printf (" %p ", addr + i); + } + + // Now the hex code for the specific character. + printf (" %02x", pc[i]); + + // And store a printable ASCII character for later. + if ((pc[i] < 0x20) || (pc[i] > 0x7e)) + buff[i % 16] = '.'; + else + buff[i % 16] = pc[i]; + buff[(i % 16) + 1] = '\0'; + } + + // Pad out last line if not exactly 16 characters. + while ((i % 16) != 0) { + printf (" "); + i++; + } + + // And print the final ASCII bit. + printf (" %s\r\n", buff); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_iflist.c b/gomspace/libgscsp/lib/libcsp/src/csp_iflist.c new file mode 100644 index 00000000..2bfef422 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_iflist.c @@ -0,0 +1,100 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +/* Interfaces are stored in a linked list*/ +static csp_iface_t * interfaces = NULL; + +csp_iface_t * csp_iflist_get_by_name(const char *name) { + csp_iface_t *ifc = interfaces; + while(ifc) { + if (strncmp(ifc->name, name, 10) == 0) + break; + ifc = ifc->next; + } + return ifc; +} + +void csp_iflist_add(csp_iface_t *ifc) { + + /* Add interface to pool */ + if (interfaces == NULL) { + /* This is the first interface to be added */ + interfaces = ifc; + ifc->next = NULL; + } else { + /* One or more interfaces were already added */ + csp_iface_t * i = interfaces; + while (i != ifc && i->next) + i = i->next; + + /* Insert interface last if not already in pool */ + if (i != ifc && i->next == NULL) { + i->next = ifc; + ifc->next = NULL; + } + } + +} + +csp_iface_t * csp_iflist_get(void) +{ + return interfaces; +} + +#ifdef CSP_DEBUG +static int csp_bytesize(char *buf, int len, unsigned long int n) { + char postfix; + double size; + + if (n >= 1048576) { + size = n/1048576.0; + postfix = 'M'; + } else if (n >= 1024) { + size = n/1024.; + postfix = 'K'; + } else { + size = n; + postfix = 'B'; + } + + return snprintf(buf, len, "%.1f%c", size, postfix); +} + +void csp_iflist_print(void) { + csp_iface_t * i = interfaces; + char txbuf[25], rxbuf[25]; + + while (i) { + csp_bytesize(txbuf, 25, i->txbytes); + csp_bytesize(rxbuf, 25, i->rxbytes); + printf("%-5s tx: %05"PRIu32" rx: %05"PRIu32" txe: %05"PRIu32" rxe: %05"PRIu32"\r\n" + " drop: %05"PRIu32" autherr: %05"PRIu32 " frame: %05"PRIu32"\r\n" + " txb: %"PRIu32" (%s) rxb: %"PRIu32" (%s)\r\n\r\n", + i->name, i->tx, i->rx, i->tx_error, i->rx_error, i->drop, + i->autherr, i->frame, i->txbytes, txbuf, i->rxbytes, rxbuf); + i = i->next; + } + +} +#endif + diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_io.c b/gomspace/libgscsp/lib/libcsp/src/csp_io.c new file mode 100644 index 00000000..3d7f614a --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_io.c @@ -0,0 +1,502 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +/* CSP includes */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "csp_io.h" +#include "csp_port.h" +#include "csp_conn.h" +#include "csp_route.h" +#include "csp_promisc.h" +#include "csp_qfifo.h" +#include "transport/csp_transport.h" + +/** CSP address of this node */ +static uint8_t csp_my_address; + +/* Hostname, model and build revision */ +static const char *csp_hostname = NULL; +static const char *csp_model = NULL; +static const char *csp_revision = GIT_REV; + +#ifdef CSP_USE_PROMISC +extern csp_queue_handle_t csp_promisc_queue; +#endif + +void csp_set_address(uint8_t addr) +{ + csp_my_address = addr; +} + +uint8_t csp_get_address(void) +{ + return csp_my_address; +} + +void csp_set_hostname(const char *hostname) +{ + csp_hostname = hostname; +} + +const char *csp_get_hostname(void) +{ + return csp_hostname; +} + +void csp_set_model(const char *model) +{ + csp_model = model; +} + +const char *csp_get_model(void) +{ + return csp_model; +} + +void csp_set_revision(const char *revision) +{ + csp_revision = revision; +} + +const char *csp_get_revision(void) +{ + return csp_revision; +} + +int csp_init(unsigned char address) { + + int ret; + + /* Initialize CSP */ + csp_set_address(address); + + ret = csp_conn_init(); + if (ret != CSP_ERR_NONE) + return ret; + + ret = csp_port_init(); + if (ret != CSP_ERR_NONE) + return ret; + + ret = csp_qfifo_init(); + if (ret != CSP_ERR_NONE) + return ret; + + /* Loopback */ + csp_iflist_add(&csp_if_lo); + + /* Register loopback route */ + csp_route_set(csp_get_address(), &csp_if_lo, CSP_NODE_MAC); + + /* Also register loopback as default, until user redefines default route */ + csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_lo, CSP_NODE_MAC); + + return CSP_ERR_NONE; + +} + +csp_socket_t * csp_socket(uint32_t opts) { + + /* Validate socket options */ +#ifndef CSP_USE_RDP + if (opts & CSP_SO_RDPREQ) { + csp_log_error("Attempt to create socket that requires RDP, but CSP was compiled without RDP support"); + return NULL; + } +#endif + +#ifndef CSP_USE_XTEA + if (opts & CSP_SO_XTEAREQ) { + csp_log_error("Attempt to create socket that requires XTEA, but CSP was compiled without XTEA support"); + return NULL; + } +#endif + +#ifndef CSP_USE_HMAC + if (opts & CSP_SO_HMACREQ) { + csp_log_error("Attempt to create socket that requires HMAC, but CSP was compiled without HMAC support"); + return NULL; + } +#endif + +#ifndef CSP_USE_CRC32 + if (opts & CSP_SO_CRC32REQ) { + csp_log_error("Attempt to create socket that requires CRC32, but CSP was compiled without CRC32 support"); + return NULL; + } +#endif + + /* Drop packet if reserved flags are set */ + if (opts & ~(CSP_SO_RDPREQ | CSP_SO_XTEAREQ | CSP_SO_HMACREQ | CSP_SO_CRC32REQ | CSP_SO_CONN_LESS)) { + csp_log_error("Invalid socket option"); + return NULL; + } + + /* Use CSP buffers instead? */ + csp_socket_t * sock = csp_conn_allocate(CONN_SERVER); + if (sock == NULL) + return NULL; + + /* If connectionless, init the queue to a pre-defined size + * if not, the user must init the queue using csp_listen */ + if (opts & CSP_SO_CONN_LESS) { + sock->socket = csp_queue_create(CSP_CONN_QUEUE_LENGTH, sizeof(csp_packet_t *)); + if (sock->socket == NULL) { + csp_close(sock); + return NULL; + } + } else { + sock->socket = NULL; + } + sock->opts = opts; + + return sock; + +} + +csp_conn_t * csp_accept(csp_socket_t * sock, uint32_t timeout) { + + if (sock == NULL) + return NULL; + + if (sock->socket == NULL) + return NULL; + + csp_conn_t * conn; + if (csp_queue_dequeue(sock->socket, &conn, timeout) == CSP_QUEUE_OK) + return conn; + + return NULL; + +} + +csp_packet_t * csp_read(csp_conn_t * conn, uint32_t timeout) { + + csp_packet_t * packet = NULL; + + if (conn == NULL || conn->state != CONN_OPEN) + return NULL; + +#ifdef CSP_USE_QOS + int prio, event; + if (csp_queue_dequeue(conn->rx_event, &event, timeout) != CSP_QUEUE_OK) + return NULL; + + for (prio = 0; prio < CSP_RX_QUEUES; prio++) + if (csp_queue_dequeue(conn->rx_queue[prio], &packet, 0) == CSP_QUEUE_OK) + break; +#else + if (csp_queue_dequeue(conn->rx_queue[0], &packet, timeout) != CSP_QUEUE_OK) + return NULL; +#endif + +#ifdef CSP_USE_RDP + /* Packet read could trigger ACK transmission */ + if (conn->idin.flags & CSP_FRDP && conn->rdp.delayed_acks) + csp_rdp_check_ack(conn); + +#endif + + return packet; + +} + +int csp_send_direct(csp_id_t idout, csp_packet_t * packet, csp_iface_t * ifout, uint32_t timeout) { + + if (packet == NULL) { + csp_log_error("csp_send_direct called with NULL packet"); + goto err; + } + + if ((ifout == NULL) || (ifout->nexthop == NULL)) { + csp_log_error("No route to host: %#08x", idout.ext); + goto err; + } + + csp_log_packet("OUT: S %u, D %u, Dp %u, Sp %u, Pr %u, Fl 0x%02X, Sz %u VIA: %s", + idout.src, idout.dst, idout.dport, idout.sport, idout.pri, idout.flags, packet->length, ifout->name); + + /* Copy identifier to packet (before crc, xtea and hmac) */ + packet->id.ext = idout.ext; + +#ifdef CSP_USE_PROMISC + /* Loopback traffic is added to promisc queue by the router */ + if (idout.dst != csp_get_address() && idout.src == csp_get_address()) { + packet->id.ext = idout.ext; + csp_promisc_add(packet); + } +#endif + + /* Only encrypt packets from the current node */ + if (idout.src == csp_get_address()) { + /* Append HMAC */ + if (idout.flags & CSP_FHMAC) { +#ifdef CSP_USE_HMAC + /* Calculate and add HMAC (does not include header for backwards compatability with csp1.x) */ + if (csp_hmac_append(packet, false) != 0) { + /* HMAC append failed */ + csp_log_warn("HMAC append failed!"); + goto tx_err; + } +#else + csp_log_warn("Attempt to send packet with HMAC, but CSP was compiled without HMAC support. Discarding packet"); + goto tx_err; +#endif + } + + /* Append CRC32 */ + if (idout.flags & CSP_FCRC32) { +#ifdef CSP_USE_CRC32 + /* Calculate and add CRC32 (does not include header for backwards compatability with csp1.x) */ + if (csp_crc32_append(packet, false) != 0) { + /* CRC32 append failed */ + csp_log_warn("CRC32 append failed!"); + goto tx_err; + } +#else + csp_log_warn("Attempt to send packet with CRC32, but CSP was compiled without CRC32 support. Sending without CRC32r"); + idout.flags &= ~(CSP_FCRC32); +#endif + } + + if (idout.flags & CSP_FXTEA) { +#ifdef CSP_USE_XTEA + /* Create nonce */ + uint32_t nonce, nonce_n; + nonce = (uint32_t)rand(); + nonce_n = csp_hton32(nonce); + memcpy(&packet->data[packet->length], &nonce_n, sizeof(nonce_n)); + + /* Create initialization vector */ + uint32_t iv[2] = {nonce, 1}; + + /* Encrypt data */ + if (csp_xtea_encrypt(packet->data, packet->length, iv) != 0) { + /* Encryption failed */ + csp_log_warn("Encryption failed! Discarding packet"); + goto tx_err; + } + + packet->length += sizeof(nonce_n); +#else + csp_log_warn("Attempt to send XTEA encrypted packet, but CSP was compiled without XTEA support. Discarding packet"); + goto tx_err; +#endif + } + } + + /* Store length before passing to interface */ + uint16_t bytes = packet->length; + uint16_t mtu = ifout->mtu; + + if (mtu > 0 && bytes > mtu) + goto tx_err; + + if ((*ifout->nexthop)(ifout, packet, timeout) != CSP_ERR_NONE) + goto tx_err; + + ifout->tx++; + ifout->txbytes += bytes; + return CSP_ERR_NONE; + +tx_err: + ifout->tx_error++; +err: + return CSP_ERR_TX; + +} + +int csp_send(csp_conn_t * conn, csp_packet_t * packet, uint32_t timeout) { + + int ret; + + if ((conn == NULL) || (packet == NULL) || (conn->state != CONN_OPEN)) { + csp_log_error("Invalid call to csp_send"); + return 0; + } + +#ifdef CSP_USE_RDP + if (conn->idout.flags & CSP_FRDP) { + if (csp_rdp_send(conn, packet, timeout) != CSP_ERR_NONE) { + csp_iface_t * ifout = csp_rtable_find_iface(conn->idout.dst); + if (ifout != NULL) + ifout->tx_error++; + csp_log_warn("RDP send failed!"); + return 0; + } + } +#endif + + csp_iface_t * ifout = csp_rtable_find_iface(conn->idout.dst); + ret = csp_send_direct(conn->idout, packet, ifout, timeout); + + return (ret == CSP_ERR_NONE) ? 1 : 0; + +} + +int csp_send_prio(uint8_t prio, csp_conn_t * conn, csp_packet_t * packet, uint32_t timeout) { + conn->idout.pri = prio; + return csp_send(conn, packet, timeout); +} + +int csp_transaction_persistent(csp_conn_t * conn, uint32_t timeout, void * outbuf, int outlen, void * inbuf, int inlen) { + + int size = (inlen > outlen) ? inlen : outlen; + csp_packet_t * packet = csp_buffer_get(size); + if (packet == NULL) + return 0; + + /* Copy the request */ + if (outlen > 0 && outbuf != NULL) + memcpy(packet->data, outbuf, outlen); + packet->length = outlen; + + if (!csp_send(conn, packet, timeout)) { + csp_buffer_free(packet); + return 0; + } + + /* If no reply is expected, return now */ + if (inlen == 0) + return 1; + + packet = csp_read(conn, timeout); + if (packet == NULL) + return 0; + + if ((inlen != -1) && ((int)packet->length != inlen)) { + csp_log_error("Reply length %u expected %u", packet->length, inlen); + csp_buffer_free(packet); + return 0; + } + + memcpy(inbuf, packet->data, packet->length); + int length = packet->length; + csp_buffer_free(packet); + return length; + +} + +int csp_transaction(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, void * outbuf, int outlen, void * inbuf, int inlen) { + return csp_transaction2(prio, dest, port, timeout, outbuf, outlen, inbuf, inlen, 0); +} + +int csp_transaction2(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, void * outbuf, int outlen, void * inbuf, int inlen, uint32_t opts) { + + csp_conn_t * conn = csp_connect(prio, dest, port, 0, opts); + if (conn == NULL) + return 0; + + int status = csp_transaction_persistent(conn, timeout, outbuf, outlen, inbuf, inlen); + + csp_close(conn); + + return status; + +} + +csp_packet_t * csp_recvfrom(csp_socket_t * socket, uint32_t timeout) { + + if ((socket == NULL) || (!(socket->opts & CSP_SO_CONN_LESS))) + return NULL; + + csp_packet_t * packet = NULL; + csp_queue_dequeue(socket->socket, &packet, timeout); + + return packet; + +} + +int csp_sendto(uint8_t prio, uint8_t dest, uint8_t dport, uint8_t src_port, uint32_t opts, csp_packet_t * packet, uint32_t timeout) { + + packet->id.flags = 0; + + if (opts & CSP_O_RDP) { + csp_log_error("Attempt to create RDP packet on connection-less socket"); + return CSP_ERR_INVAL; + } + + if (opts & CSP_O_HMAC) { +#ifdef CSP_USE_HMAC + packet->id.flags |= CSP_FHMAC; +#else + csp_log_error("Attempt to create HMAC authenticated packet, but CSP was compiled without HMAC support"); + return CSP_ERR_NOTSUP; +#endif + } + + if (opts & CSP_O_XTEA) { +#ifdef CSP_USE_XTEA + packet->id.flags |= CSP_FXTEA; +#else + csp_log_error("Attempt to create XTEA encrypted packet, but CSP was compiled without XTEA support"); + return CSP_ERR_NOTSUP; +#endif + } + + if (opts & CSP_O_CRC32) { +#ifdef CSP_USE_CRC32 + packet->id.flags |= CSP_FCRC32; +#else + csp_log_error("Attempt to create CRC32 validated packet, but CSP was compiled without CRC32 support"); + return CSP_ERR_NOTSUP; +#endif + } + + packet->id.dst = dest; + packet->id.dport = dport; + packet->id.src = csp_get_address(); + packet->id.sport = src_port; + packet->id.pri = prio; + + csp_iface_t * ifout = csp_rtable_find_iface(dest); + if (csp_send_direct(packet->id, packet, ifout, timeout) != CSP_ERR_NONE) + return CSP_ERR_NOTSUP; + + return CSP_ERR_NONE; + +} + +int csp_sendto_reply(csp_packet_t * request_packet, csp_packet_t * reply_packet, uint32_t opts, uint32_t timeout) { + if (request_packet == NULL) + return CSP_ERR_INVAL; + + return csp_sendto(request_packet->id.pri, request_packet->id.src, request_packet->id.sport, request_packet->id.dport, opts, reply_packet, timeout); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_io.h b/gomspace/libgscsp/lib/libcsp/src/csp_io.h new file mode 100644 index 00000000..6ea8dfec --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_io.h @@ -0,0 +1,47 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_IO_H_ +#define _CSP_IO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +/** + * Function to transmit a frame without an existing connection structure. + * This function is used for stateless transmissions + * @param idout 32bit CSP identifier + * @param packet pointer to packet, + * @param ifout pointer to output interface + * @param timeout a timeout to wait for TX to complete. NOTE: not all underlying drivers supports flow-control. + * @return returns 1 if successful and 0 otherwise. you MUST free the frame yourself if the transmission was not successful. + */ +int csp_send_direct(csp_id_t idout, csp_packet_t * packet, csp_iface_t * ifout, uint32_t timeout); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_IO_H_ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_port.c b/gomspace/libgscsp/lib/libcsp/src/csp_port.c new file mode 100644 index 00000000..2a4ac2a9 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_port.c @@ -0,0 +1,105 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +/* CSP includes */ +#include +#include + +#include +#include +#include + +#include "csp_port.h" +#include "csp_conn.h" + +/* Allocation of ports */ +static csp_port_t ports[CSP_MAX_BIND_PORT + 2]; + +csp_socket_t * csp_port_get_socket(unsigned int port) { + + csp_socket_t * ret = NULL; + + if (port >= CSP_ANY) + return NULL; + + /* Match dport to socket or local "catch all" port number */ + if (ports[port].state == PORT_OPEN) + ret = ports[port].socket; + else if (ports[CSP_ANY].state == PORT_OPEN) + ret = ports[CSP_ANY].socket; + + return ret; + +} + +int csp_port_init(void) { + + memset(ports, PORT_CLOSED, sizeof(csp_port_t) * (CSP_MAX_BIND_PORT + 2)); + + return CSP_ERR_NONE; + +} + +int csp_listen(csp_socket_t * socket, size_t conn_queue_length) { + + if (socket == NULL) + return CSP_ERR_INVAL; + + socket->socket = csp_queue_create(conn_queue_length, sizeof(csp_conn_t *)); + if (socket->socket == NULL) + return CSP_ERR_NOMEM; + + socket->opts |= CSP_SO_INTERNAL_LISTEN; + + return CSP_ERR_NONE; + +} + +int csp_bind(csp_socket_t * socket, uint8_t port) { + + if (socket == NULL) + return CSP_ERR_INVAL; + + if (port > CSP_ANY) { + csp_log_error("Only ports from 0-%u (and CSP_ANY for default) are available for incoming ports", CSP_ANY); + return CSP_ERR_INVAL; + } + + /* Check if port number is valid */ + if (ports[port].state != PORT_CLOSED) { + csp_log_error("Port %d is already in use", port); + return CSP_ERR_USED; + } + + csp_log_info("Binding socket %p to port %u", socket, port); + + /* Save listener */ + ports[port].socket = socket; + ports[port].state = PORT_OPEN; + + return CSP_ERR_NONE; + +} + + diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_port.h b/gomspace/libgscsp/lib/libcsp/src/csp_port.h new file mode 100644 index 00000000..d2ec06e9 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_port.h @@ -0,0 +1,55 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_PORT_H_ +#define _CSP_PORT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +/** @brief Port states */ +typedef enum { + PORT_CLOSED = 0, + PORT_OPEN = 1, +} csp_port_state_t; + +/** @brief Port struct */ +typedef struct { + csp_port_state_t state; // Port state + csp_socket_t * socket; // New connections are added to this socket's conn queue +} csp_port_t; + +/** + * Init ports array + */ +int csp_port_init(void); + +csp_socket_t * csp_port_get_socket(unsigned int dport); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_PORT_H_ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_promisc.c b/gomspace/libgscsp/lib/libcsp/src/csp_promisc.c new file mode 100644 index 00000000..5f156c33 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_promisc.c @@ -0,0 +1,82 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +#ifdef CSP_USE_PROMISC + +static csp_queue_handle_t csp_promisc_queue = NULL; +static int csp_promisc_enabled = 0; + +int csp_promisc_enable(unsigned int buf_size) { + + /* If queue already initialised */ + if (csp_promisc_queue != NULL) { + csp_promisc_enabled = 1; + return CSP_ERR_NONE; + } + + /* Create packet queue */ + csp_promisc_queue = csp_queue_create(buf_size, sizeof(csp_packet_t *)); + + if (csp_promisc_queue == NULL) + return CSP_ERR_INVAL; + + csp_promisc_enabled = 1; + return CSP_ERR_NONE; + +} + +void csp_promisc_disable(void) { + csp_promisc_enabled = 0; +} + +csp_packet_t * csp_promisc_read(uint32_t timeout) { + + if (csp_promisc_queue == NULL) + return NULL; + + csp_packet_t * packet = NULL; + csp_queue_dequeue(csp_promisc_queue, &packet, timeout); + + return packet; + +} + +void csp_promisc_add(csp_packet_t * packet) { + + if (csp_promisc_enabled == 0) + return; + + if (csp_promisc_queue != NULL) { + /* Make a copy of the message and queue it to the promiscuous task */ + csp_packet_t *packet_copy = csp_buffer_clone(packet); + if (packet_copy != NULL) { + if (csp_queue_enqueue(csp_promisc_queue, &packet_copy, 0) != CSP_QUEUE_OK) { + csp_log_error("Promiscuous mode input queue full"); + csp_buffer_free(packet_copy); + } + } + } + +} + +#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_promisc.h b/gomspace/libgscsp/lib/libcsp/src/csp_promisc.h new file mode 100644 index 00000000..be62edda --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_promisc.h @@ -0,0 +1,30 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CSP_PROMISC_H_ +#define CSP_PROMISC_H_ + +/** + * Add packet to promiscuous mode packet queue + * @param packet Packet to add to the queue + */ +void csp_promisc_add(csp_packet_t * packet); + +#endif /* CSP_PROMISC_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c b/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c new file mode 100644 index 00000000..9329b2ca --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c @@ -0,0 +1,149 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include "csp_qfifo.h" + +static csp_queue_handle_t qfifo[CSP_ROUTE_FIFOS]; +#ifdef CSP_USE_QOS +static csp_queue_handle_t qfifo_events; +#endif + +int csp_qfifo_init(void) { + int prio; + + /* Create router fifos for each priority */ + for (prio = 0; prio < CSP_ROUTE_FIFOS; prio++) { + if (qfifo[prio] == NULL) { + qfifo[prio] = csp_queue_create(CSP_FIFO_INPUT, sizeof(csp_qfifo_t)); + if (!qfifo[prio]) + return CSP_ERR_NOMEM; + } + } + +#ifdef CSP_USE_QOS + /* Create QoS fifo notification queue */ + qfifo_events = csp_queue_create(CSP_FIFO_INPUT, sizeof(int)); + if (!qfifo_events) + return CSP_ERR_NOMEM; +#endif + + return CSP_ERR_NONE; + +} + +int csp_qfifo_read(csp_qfifo_t * input) { + +#ifdef CSP_USE_QOS + int prio, found, event; + + /* Wait for packet in any queue */ + if (csp_queue_dequeue(qfifo_events, &event, FIFO_TIMEOUT) != CSP_QUEUE_OK) + return CSP_ERR_TIMEDOUT; + + /* Find packet with highest priority */ + found = 0; + for (prio = 0; prio < CSP_ROUTE_FIFOS; prio++) { + if (csp_queue_dequeue(qfifo[prio], input, 0) == CSP_QUEUE_OK) { + found = 1; + break; + } + } + + if (!found) { + csp_log_warn("Spurious wakeup: No packet found"); + return CSP_ERR_TIMEDOUT; + } +#else + if (csp_queue_dequeue(qfifo[0], input, FIFO_TIMEOUT) != CSP_QUEUE_OK) + return CSP_ERR_TIMEDOUT; +#endif + + return CSP_ERR_NONE; + +} + +void csp_qfifo_write(csp_packet_t * packet, csp_iface_t * interface, CSP_BASE_TYPE * pxTaskWoken) { + + int result; + + if (packet == NULL) { + if (pxTaskWoken == NULL) { // Only do logging in non-ISR context + csp_log_warn("csp_new packet called with NULL packet"); + } + return; + } else if (interface == NULL) { + if (pxTaskWoken == NULL) { // Only do logging in non-ISR context + csp_log_warn("csp_new packet called with NULL interface"); + } + if (pxTaskWoken == NULL) + csp_buffer_free(packet); + else + csp_buffer_free_isr(packet); + return; + } + + csp_qfifo_t queue_element; + queue_element.interface = interface; + queue_element.packet = packet; + +#ifdef CSP_USE_QOS + int fifo = packet->id.pri; +#else + int fifo = 0; +#endif + + if (pxTaskWoken == NULL) + result = csp_queue_enqueue(qfifo[fifo], &queue_element, 0); + else + result = csp_queue_enqueue_isr(qfifo[fifo], &queue_element, pxTaskWoken); + +#ifdef CSP_USE_QOS + static int event = 0; + + if (result == CSP_QUEUE_OK) { + if (pxTaskWoken == NULL) + csp_queue_enqueue(qfifo_events, &event, 0); + else + csp_queue_enqueue_isr(qfifo_events, &event, pxTaskWoken); + } +#endif + + if (result != CSP_QUEUE_OK) { + if (pxTaskWoken == NULL) { // Only do logging in non-ISR context + csp_log_warn("ERROR: Routing input FIFO is FULL. Dropping packet."); + } + interface->drop++; + if (pxTaskWoken == NULL) + csp_buffer_free(packet); + else + csp_buffer_free_isr(packet); + } + +} + +void csp_qfifo_wake_up(void) { + csp_qfifo_t queue_element; + queue_element.interface = NULL; + queue_element.packet = NULL; + csp_queue_enqueue(qfifo[0], &queue_element, 0); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h b/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h new file mode 100644 index 00000000..2910c48d --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h @@ -0,0 +1,54 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CSP_QFIFO_H_ +#define CSP_QFIFO_H_ + +#ifdef CSP_USE_RDP +#define FIFO_TIMEOUT 100 //! If RDP is enabled, the router needs to awake some times to check timeouts +#else +#define FIFO_TIMEOUT CSP_MAX_DELAY //! If no RDP, the router can sleep untill data arrives +#endif + +/** + * Init FIFO/QOS queues + * @return CSP_ERR type + */ +int csp_qfifo_init(void); + +typedef struct { + csp_iface_t * interface; + csp_packet_t * packet; +} csp_qfifo_t; + +/** + * Read next packet from router input queue + * @param input pointer to router queue item element + * @return CSP_ERR type + */ +int csp_qfifo_read(csp_qfifo_t * input); + +/** + * Wake up any task (e.g. router) waiting on messages. + * For testing. + */ +void csp_qfifo_wake_up(void); + +#endif /* CSP_QFIFO_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_route.c b/gomspace/libgscsp/lib/libcsp/src/csp_route.c new file mode 100644 index 00000000..627dfdc8 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_route.c @@ -0,0 +1,347 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +/* CSP includes */ +#include +#include +#include + +#include +#include + +#include +#include + +#include "csp_port.h" +#include "csp_conn.h" +#include "csp_io.h" +#include "csp_promisc.h" +#include "csp_qfifo.h" +#include "csp_dedup.h" +#include "transport/csp_transport.h" +#include "csp_buffer.h" + +/** + * Check supported packet options + * @param interface pointer to incoming interface + * @param packet pointer to packet + * @return CSP_ERR_NONE is all options are supported, CSP_ERR_NOTSUP if not + */ +static int csp_route_check_options(csp_iface_t *interface, csp_packet_t *packet) +{ +#ifndef CSP_USE_XTEA + /* Drop XTEA packets */ + if (packet->id.flags & CSP_FXTEA) { + csp_log_error("Received XTEA encrypted packet, but CSP was compiled without XTEA support. Discarding packet"); + interface->autherr++; + return CSP_ERR_NOTSUP; + } +#endif + +#ifndef CSP_USE_HMAC + /* Drop HMAC packets */ + if (packet->id.flags & CSP_FHMAC) { + csp_log_error("Received packet with HMAC, but CSP was compiled without HMAC support. Discarding packet"); + interface->autherr++; + return CSP_ERR_NOTSUP; + } +#endif + +#ifndef CSP_USE_RDP + /* Drop RDP packets */ + if (packet->id.flags & CSP_FRDP) { + csp_log_error("Received RDP packet, but CSP was compiled without RDP support. Discarding packet"); + interface->rx_error++; + return CSP_ERR_NOTSUP; + } +#endif + return CSP_ERR_NONE; +} + +/** + * Helper function to decrypt, check auth and CRC32 + * @param security_opts either socket_opts or conn_opts + * @param interface pointer to incoming interface + * @param packet pointer to packet + * @return -1 Missing feature, -2 XTEA error, -3 CRC error, -4 HMAC error, 0 = OK. + */ +static int csp_route_security_check(uint32_t security_opts, csp_iface_t * interface, csp_packet_t * packet) { + +#ifdef CSP_USE_XTEA + /* XTEA encrypted packet */ + if (packet->id.flags & CSP_FXTEA) { + /* Read nonce */ + uint32_t nonce; + memcpy(&nonce, &packet->data[packet->length - sizeof(nonce)], sizeof(nonce)); + nonce = csp_ntoh32(nonce); + packet->length -= sizeof(nonce); + + /* Create initialization vector */ + uint32_t iv[2] = {nonce, 1}; + + /* Decrypt data */ + if (csp_xtea_decrypt(packet->data, packet->length, iv) != 0) { + /* Decryption failed */ + csp_log_error("Decryption failed! Discarding packet"); + interface->autherr++; + return CSP_ERR_XTEA; + } + } else if (security_opts & CSP_SO_XTEAREQ) { + csp_log_warn("Received packet without XTEA encryption. Discarding packet"); + interface->autherr++; + return CSP_ERR_XTEA; + } +#endif + + /* CRC32 verified packet */ + if (packet->id.flags & CSP_FCRC32) { +#ifdef CSP_USE_CRC32 + if (packet->length < 4) + csp_log_error("Too short packet for CRC32, %u", packet->length); + /* Verify CRC32 (does not include header for backwards compatability with csp1.x) */ + if (csp_crc32_verify(packet, false) != 0) { + /* Checksum failed */ + csp_log_error("CRC32 verification error! Discarding packet"); + interface->rx_error++; + return CSP_ERR_CRC32; + } + } else if (security_opts & CSP_SO_CRC32REQ) { + csp_log_warn("Received packet without CRC32. Accepting packet"); +#else + /* Strip CRC32 field and accept the packet */ + csp_log_warn("Received packet with CRC32, but CSP was compiled without CRC32 support. Accepting packet"); + packet->length -= sizeof(uint32_t); +#endif + } + +#ifdef CSP_USE_HMAC + /* HMAC authenticated packet */ + if (packet->id.flags & CSP_FHMAC) { + /* Verify HMAC (does not include header for backwards compatability with csp1.x) */ + if (csp_hmac_verify(packet, false) != 0) { + /* HMAC failed */ + csp_log_error("HMAC verification error! Discarding packet"); + interface->autherr++; + return CSP_ERR_HMAC; + } + } else if (security_opts & CSP_SO_HMACREQ) { + csp_log_warn("Received packet without HMAC. Discarding packet"); + interface->autherr++; + return CSP_ERR_HMAC; + } +#endif + +#ifdef CSP_USE_RDP + /* RDP packet */ + if (!(packet->id.flags & CSP_FRDP)) { + if (security_opts & CSP_SO_RDPREQ) { + csp_log_warn("Received packet without RDP header. Discarding packet"); + interface->rx_error++; + return CSP_ERR_INVAL; + } + } +#endif + + return CSP_ERR_NONE; + +} + +int csp_route_work(uint32_t timeout) { + + csp_qfifo_t input; + csp_packet_t * packet; + csp_conn_t * conn; + csp_socket_t * socket; + +#ifdef CSP_USE_RDP + /* Check connection timeouts (currently only for RDP) */ + csp_conn_check_timeouts(); +#endif + + /* Get next packet to route */ + if (csp_qfifo_read(&input) != CSP_ERR_NONE) + return -1; + + packet = input.packet; + if (!packet) + return -1; + + csp_log_packet("INP: S %u, D %u, Dp %u, Sp %u, Pr %u, Fl 0x%02X, Sz %"PRIu16" VIA: %s", + packet->id.src, packet->id.dst, packet->id.dport, + packet->id.sport, packet->id.pri, packet->id.flags, packet->length, input.interface->name); + + /* Here there be promiscuous mode */ +#ifdef CSP_USE_PROMISC + csp_promisc_add(packet); +#endif + +#ifdef CSP_USE_DEDUP + /* Check for duplicates */ + if (csp_dedup_is_duplicate(packet)) { + /* Discard packet */ + csp_log_packet("Duplicate packet discarded"); + input.interface->drop++; + csp_buffer_free(packet); + return 0; + } +#endif + + /* Now we count the message (since its deduplicated) */ + input.interface->rx++; + input.interface->rxbytes += packet->length; + + /* If the message is not to me, route the message to the correct interface */ + if ((packet->id.dst != csp_get_address()) && (packet->id.dst != CSP_BROADCAST_ADDR)) { + + /* Find the destination interface */ + csp_iface_t * dstif = csp_rtable_find_iface(packet->id.dst); + + /* If the message resolves to the input interface, don't loop it back out */ + if ((dstif == NULL) || ((dstif == input.interface) && (input.interface->split_horizon_off == 0))) { + csp_buffer_free(packet); + return 0; + } + + /* Otherwise, actually send the message */ + if (csp_send_direct(packet->id, packet, dstif, 0) != CSP_ERR_NONE) { + csp_log_warn("Router failed to send"); + csp_buffer_free(packet); + } + + /* Next message, please */ + return 0; + } + + /* Discard packets with unsupported options */ + if (csp_route_check_options(input.interface, packet) != CSP_ERR_NONE) { + csp_buffer_free(packet); + return 0; + } + + /* The message is to me, search for incoming socket */ + socket = csp_port_get_socket(packet->id.dport); + + /* If the socket is connection-less, deliver now */ + if (socket && (socket->opts & CSP_SO_CONN_LESS)) { + if (csp_route_security_check(socket->opts, input.interface, packet) < 0) { + csp_buffer_free(packet); + return 0; + } + if (csp_queue_enqueue(socket->socket, &packet, 0) != CSP_QUEUE_OK) { + csp_log_error("Conn-less socket queue full"); + csp_buffer_free(packet); + return 0; + } + return 0; + } + + /* Search for an existing connection */ + conn = csp_conn_find(packet->id.ext, CSP_ID_CONN_MASK); + + /* If this is an incoming packet on a new connection */ + if (conn == NULL) { + + /* Reject packet if no matching socket is found */ + if (!socket) { + csp_buffer_free(packet); + return 0; + } + + /* Run security check on incoming packet */ + if (csp_route_security_check(socket->opts, input.interface, packet) < 0) { + csp_buffer_free(packet); + return 0; + } + + /* New incoming connection accepted */ + csp_id_t idout; + idout.pri = packet->id.pri; + idout.src = csp_get_address(); + + idout.dst = packet->id.src; + idout.dport = packet->id.sport; + idout.sport = packet->id.dport; + idout.flags = packet->id.flags; + + /* Create connection */ + conn = csp_conn_new(packet->id, idout); + + if (!conn) { + csp_log_error("No more connections available"); + csp_buffer_free(packet); + return 0; + } + + /* Store the socket queue and options */ + conn->socket = socket->socket; + conn->opts = socket->opts; + + /* Packet to existing connection */ + } else { + + /* Run security check on incoming packet */ + if (csp_route_security_check(conn->opts, input.interface, packet) < 0) { + csp_buffer_free(packet); + return 0; + } + + } + +#ifdef CSP_USE_RDP + /* Pass packet to RDP module */ + if (packet->id.flags & CSP_FRDP) { + csp_rdp_new_packet(conn, packet); + return 0; + } +#endif + + /* Pass packet to UDP module */ + csp_udp_new_packet(conn, packet); + return 0; +} + +static CSP_DEFINE_TASK(csp_task_router) { + + /* Here there be routing */ + while (1) { + csp_route_work(FIFO_TIMEOUT); + } + + return CSP_TASK_RETURN; + +} + +int csp_route_start_task(unsigned int task_stack_size, unsigned int priority) { + + static csp_thread_handle_t handle_router; + int ret = csp_thread_create(csp_task_router, "RTE", task_stack_size, NULL, priority, &handle_router); + + if (ret != 0) { + csp_log_error("Failed to start router task"); + return CSP_ERR_NOMEM; + } + + return CSP_ERR_NONE; + +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_route.h b/gomspace/libgscsp/lib/libcsp/src/csp_route.h new file mode 100644 index 00000000..2a20f49f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_route.h @@ -0,0 +1,24 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_ROUTE_H_ +#define _CSP_ROUTE_H_ + +#endif // _CSP_ROUTE_H_ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_service_handler.c b/gomspace/libgscsp/lib/libcsp/src/csp_service_handler.c new file mode 100644 index 00000000..0090afc1 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_service_handler.c @@ -0,0 +1,334 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +/* CSP includes */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "csp_route.h" + +#define CSP_RPS_MTU 196 + +/** + * The CSP CMP mempy function is used to, override the function used to + * read/write memory by peek and poke. + */ +#ifdef __AVR__ +static uint32_t wrap_32bit_memcpy(uint32_t to, const uint32_t from, size_t size) { + return (uint32_t) (uintptr_t) memcpy((void *) (uintptr_t) to, (const void *) (uintptr_t) from, size); +} +static csp_memcpy_fnc_t csp_cmp_memcpy_fnc = wrap_32bit_memcpy; +#else +static csp_memcpy_fnc_t csp_cmp_memcpy_fnc = (csp_memcpy_fnc_t) memcpy; +#endif + + +void csp_cmp_set_memcpy(csp_memcpy_fnc_t fnc) { + csp_cmp_memcpy_fnc = fnc; +} + +static int do_cmp_ident(struct csp_cmp_message *cmp) { + + /* Copy revision */ + strncpy(cmp->ident.revision, csp_get_revision(), CSP_CMP_IDENT_REV_LEN); + cmp->ident.revision[CSP_CMP_IDENT_REV_LEN - 1] = '\0'; + + /* Copy compilation date */ + strncpy(cmp->ident.date, __DATE__, CSP_CMP_IDENT_DATE_LEN); + cmp->ident.date[CSP_CMP_IDENT_DATE_LEN - 1] = '\0'; + + /* Copy compilation time */ + strncpy(cmp->ident.time, __TIME__, CSP_CMP_IDENT_TIME_LEN); + cmp->ident.time[CSP_CMP_IDENT_TIME_LEN - 1] = '\0'; + + /* Copy hostname */ + strncpy(cmp->ident.hostname, csp_get_hostname(), CSP_HOSTNAME_LEN); + cmp->ident.hostname[CSP_HOSTNAME_LEN - 1] = '\0'; + + /* Copy model name */ + strncpy(cmp->ident.model, csp_get_model(), CSP_MODEL_LEN); + cmp->ident.model[CSP_MODEL_LEN - 1] = '\0'; + + return CSP_ERR_NONE; + +} + +static int do_cmp_route_set(struct csp_cmp_message *cmp) { + + csp_iface_t *ifc = csp_iflist_get_by_name(cmp->route_set.interface); + if (ifc == NULL) + return CSP_ERR_INVAL; + + if (csp_route_set(cmp->route_set.dest_node, ifc, cmp->route_set.next_hop_mac) != CSP_ERR_NONE) + return CSP_ERR_INVAL; + + return CSP_ERR_NONE; + +} + +static int do_cmp_if_stats(struct csp_cmp_message *cmp) { + + csp_iface_t *ifc = csp_iflist_get_by_name(cmp->if_stats.interface); + if (ifc == NULL) + return CSP_ERR_INVAL; + + cmp->if_stats.tx = csp_hton32(ifc->tx); + cmp->if_stats.rx = csp_hton32(ifc->rx); + cmp->if_stats.tx_error = csp_hton32(ifc->tx_error); + cmp->if_stats.rx_error = csp_hton32(ifc->rx_error); + cmp->if_stats.drop = csp_hton32(ifc->drop); + cmp->if_stats.autherr = csp_hton32(ifc->autherr); + cmp->if_stats.frame = csp_hton32(ifc->frame); + cmp->if_stats.txbytes = csp_hton32(ifc->txbytes); + cmp->if_stats.rxbytes = csp_hton32(ifc->rxbytes); + cmp->if_stats.irq = csp_hton32(ifc->irq); + + return CSP_ERR_NONE; +} + +static int do_cmp_peek(struct csp_cmp_message *cmp) { + + cmp->peek.addr = csp_hton32(cmp->peek.addr); + if (cmp->peek.len > CSP_CMP_PEEK_MAX_LEN) + return CSP_ERR_INVAL; + + /* Dangerous, you better know what you are doing */ + csp_cmp_memcpy_fnc((csp_memptr_t) (uintptr_t) cmp->peek.data, (csp_memptr_t) (unsigned long) cmp->peek.addr, cmp->peek.len); + + return CSP_ERR_NONE; + +} + +static int do_cmp_poke(struct csp_cmp_message *cmp) { + + cmp->poke.addr = csp_hton32(cmp->poke.addr); + if (cmp->poke.len > CSP_CMP_POKE_MAX_LEN) + return CSP_ERR_INVAL; + + /* Extremely dangerous, you better know what you are doing */ + csp_cmp_memcpy_fnc((csp_memptr_t) (unsigned long) cmp->poke.addr, (csp_memptr_t) (uintptr_t) cmp->poke.data, cmp->poke.len); + + return CSP_ERR_NONE; + +} + +static int do_cmp_clock(struct csp_cmp_message *cmp) { + + cmp->clock.tv_sec = csp_ntoh32(cmp->clock.tv_sec); + cmp->clock.tv_nsec = csp_ntoh32(cmp->clock.tv_nsec); + + if ((cmp->clock.tv_sec != 0) && (clock_set_time != NULL)) { + clock_set_time(&cmp->clock); + } + + if (clock_get_time != NULL) { + clock_get_time(&cmp->clock); + } + + cmp->clock.tv_sec = csp_hton32(cmp->clock.tv_sec); + cmp->clock.tv_nsec = csp_hton32(cmp->clock.tv_nsec); + return CSP_ERR_NONE; + +} + +/* CSP Management Protocol handler */ +static int csp_cmp_handler(csp_conn_t * conn, csp_packet_t * packet) { + + int ret = CSP_ERR_INVAL; + struct csp_cmp_message * cmp = (struct csp_cmp_message *) packet->data; + + /* Ignore everything but requests */ + if (cmp->type != CSP_CMP_REQUEST) + return ret; + + switch (cmp->code) { + case CSP_CMP_IDENT: + ret = do_cmp_ident(cmp); + packet->length = CMP_SIZE(ident); + break; + + case CSP_CMP_ROUTE_SET: + ret = do_cmp_route_set(cmp); + packet->length = CMP_SIZE(route_set); + break; + + case CSP_CMP_IF_STATS: + ret = do_cmp_if_stats(cmp); + packet->length = CMP_SIZE(if_stats); + break; + + case CSP_CMP_PEEK: + ret = do_cmp_peek(cmp); + break; + + case CSP_CMP_POKE: + ret = do_cmp_poke(cmp); + break; + + case CSP_CMP_CLOCK: + ret = do_cmp_clock(cmp); + break; + + default: + ret = CSP_ERR_INVAL; + break; + } + + cmp->type = CSP_CMP_REPLY; + + return ret; +} + +void csp_service_handler(csp_conn_t * conn, csp_packet_t * packet) { + + switch (csp_conn_dport(conn)) { + + case CSP_CMP: + /* Pass to CMP handler */ + if (csp_cmp_handler(conn, packet) != CSP_ERR_NONE) { + csp_buffer_free(packet); + return; + } + break; + + case CSP_PING: + /* A ping means, just echo the packet, so no changes */ + csp_log_info("SERVICE: Ping received"); + break; + + case CSP_PS: { + /* Sanity check on request */ + if ((packet->length != 1) || (packet->data[0] != 0x55)) { + /* Sanity check failed */ + csp_buffer_free(packet); + /* Clear the packet, it has been freed */ + packet = NULL; + break; + } + /* Start by allocating just the right amount of memory */ + int task_list_size = csp_sys_tasklist_size(); + char * pslist = csp_malloc(task_list_size); + /* Check for malloc fail */ + if (pslist == NULL) { + /* Send out the data */ + strcpy((char *)packet->data, "Not enough memory"); + packet->length = strlen((char *)packet->data); + /* Break and let the default handling send packet */ + break; + } + + /* Retrieve the tasklist */ + csp_sys_tasklist(pslist); + int pslen = strnlen(pslist, task_list_size); + + /* Split the potentially very long string into packets */ + int i = 0; + while(i < pslen) { + + /* Allocate packet buffer, if need be */ + if (packet == NULL) + packet = csp_buffer_get(CSP_RPS_MTU); + if (packet == NULL) + break; + + /* Calculate length, either full MTU or the remainder */ + packet->length = (pslen - i > CSP_RPS_MTU) ? CSP_RPS_MTU : (pslen - i); + + /* Send out the data */ + memcpy(packet->data, &pslist[i], packet->length); + i += packet->length; + if (!csp_send(conn, packet, 0)) + csp_buffer_free(packet); + + /* Clear the packet reference when sent */ + packet = NULL; + + } + csp_free(pslist); + break; + } + + case CSP_MEMFREE: { + uint32_t total = csp_sys_memfree(); + + total = csp_hton32(total); + memcpy(packet->data, &total, sizeof(total)); + packet->length = sizeof(total); + + break; + } + + case CSP_REBOOT: { + uint32_t magic_word; + memcpy(&magic_word, packet->data, sizeof(magic_word)); + + magic_word = csp_ntoh32(magic_word); + + /* If the magic word is valid, reboot */ + if (magic_word == CSP_REBOOT_MAGIC) { + csp_sys_reboot(); + } else if (magic_word == CSP_REBOOT_SHUTDOWN_MAGIC) { + csp_sys_shutdown(); + } + + + + csp_buffer_free(packet); + return; + } + + case CSP_BUF_FREE: { + uint32_t size = csp_buffer_remaining(); + size = csp_hton32(size); + memcpy(packet->data, &size, sizeof(size)); + packet->length = sizeof(size); + break; + } + + case CSP_UPTIME: { + uint32_t time = csp_get_s(); + time = csp_hton32(time); + memcpy(packet->data, &time, sizeof(time)); + packet->length = sizeof(time); + break; + } + + default: + csp_buffer_free(packet); + return; + } + + if (packet != NULL) { + if (!csp_send(conn, packet, 0)) + csp_buffer_free(packet); + } + +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_services.c b/gomspace/libgscsp/lib/libcsp/src/csp_services.c new file mode 100644 index 00000000..5392cb82 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_services.c @@ -0,0 +1,233 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +/* CSP includes */ +#include +#include +#include + +#include + +int csp_ping(uint8_t node, uint32_t timeout, unsigned int size, uint8_t conn_options) { + + unsigned int i; + uint32_t start, time, status = 0; + + /* Counter */ + start = csp_get_ms(); + + /* Open connection */ + csp_conn_t * conn = csp_connect(CSP_PRIO_NORM, node, CSP_PING, timeout, conn_options); + if (conn == NULL) + return -1; + + /* Prepare data */ + csp_packet_t * packet; + packet = csp_buffer_get(size); + if (packet == NULL) + goto out; + + /* Set data to increasing numbers */ + packet->length = size; + for (i = 0; i < size; i++) + packet->data[i] = i; + + /* Try to send frame */ + if (!csp_send(conn, packet, 0)) + goto out; + + /* Read incoming frame */ + packet = csp_read(conn, timeout); + if (packet == NULL) + goto out; + + /* Ensure that the data was actually echoed */ + for (i = 0; i < size; i++) + if (packet->data[i] != i % (0xff + 1)) + goto out; + + status = 1; + +out: + /* Clean up */ + if (packet != NULL) + csp_buffer_free(packet); + csp_close(conn); + + /* We have a reply */ + time = (csp_get_ms() - start); + + if (status) { + return time; + } else { + return -1; + } + +} + +void csp_ping_noreply(uint8_t node) { + + /* Prepare data */ + csp_packet_t * packet; + packet = csp_buffer_get(1); + + /* Check malloc */ + if (packet == NULL) + return; + + /* Open connection */ + csp_conn_t * conn = csp_connect(CSP_PRIO_NORM, node, CSP_PING, 0, 0); + if (conn == NULL) { + csp_buffer_free(packet); + return; + } + + packet->data[0] = 0x55; + packet->length = 1; + + printf("Ping ignore reply node %u.\r\n", (unsigned int) node); + + /* Try to send frame */ + if (!csp_send(conn, packet, 0)) + csp_buffer_free(packet); + + csp_close(conn); + +} + +void csp_reboot(uint8_t node) { + uint32_t magic_word = csp_hton32(CSP_REBOOT_MAGIC); + csp_transaction(CSP_PRIO_NORM, node, CSP_REBOOT, 0, &magic_word, sizeof(magic_word), NULL, 0); +} + +void csp_shutdown(uint8_t node) { + uint32_t magic_word = csp_hton32(CSP_REBOOT_SHUTDOWN_MAGIC); + csp_transaction(CSP_PRIO_NORM, node, CSP_REBOOT, 0, &magic_word, sizeof(magic_word), NULL, 0); +} + +void csp_ps(uint8_t node, uint32_t timeout) { + + /* Open connection */ + csp_conn_t * conn = csp_connect(CSP_PRIO_NORM, node, CSP_PS, 0, 0); + if (conn == NULL) + return; + + /* Prepare data */ + csp_packet_t * packet; + packet = csp_buffer_get(95); + + /* Check malloc */ + if (packet == NULL) + goto out; + + packet->data[0] = 0x55; + packet->length = 1; + + printf("PS node %u: \r\n", (unsigned int) node); + + /* Try to send frame */ + if (!csp_send(conn, packet, 0)) + goto out; + + while(1) { + + /* Read incoming frame */ + packet = csp_read(conn, timeout); + if (packet == NULL) + break; + + /* We have a reply, add our own NULL char */ + packet->data[packet->length] = 0; + printf("%s", packet->data); + + /* Each packet from csp_read must to be freed by user */ + csp_buffer_free(packet); + } + + printf("\r\n"); + + /* Clean up */ +out: + if (packet != NULL) + csp_buffer_free(packet); + csp_close(conn); + +} + +void csp_memfree(uint8_t node, uint32_t timeout) { + + uint32_t memfree; + + int status = csp_transaction(CSP_PRIO_NORM, node, CSP_MEMFREE, timeout, NULL, 0, &memfree, sizeof(memfree)); + if (status == 0) { + printf("Network error\r\n"); + return; + } + + /* Convert from network to host order */ + memfree = csp_ntoh32(memfree); + + printf("Free Memory at node %u is %"PRIu32" bytes\r\n", (unsigned int) node, memfree); + +} + +void csp_buf_free(uint8_t node, uint32_t timeout) { + + uint32_t size = 0; + + int status = csp_transaction(CSP_PRIO_NORM, node, CSP_BUF_FREE, timeout, NULL, 0, &size, sizeof(size)); + if (status == 0) { + printf("Network error\r\n"); + return; + } + size = csp_ntoh32(size); + printf("Free buffers at node %u is %"PRIu32"\r\n", (unsigned int) node, size); + +} + +void csp_uptime(uint8_t node, uint32_t timeout) { + + uint32_t uptime = 0; + + int status = csp_transaction(CSP_PRIO_NORM, node, CSP_UPTIME, timeout, NULL, 0, &uptime, sizeof(uptime)); + if (status == 0) { + printf("Network error\r\n"); + return; + } + uptime = csp_ntoh32(uptime); + printf("Uptime of node %u is %"PRIu32" s\r\n", (unsigned int) node, uptime); + +} + +int csp_cmp(uint8_t node, uint32_t timeout, uint8_t code, int membsize, struct csp_cmp_message * msg) { + msg->type = CSP_CMP_REQUEST; + msg->code = code; + int status = csp_transaction(CSP_PRIO_NORM, node, CSP_CMP, timeout, msg, membsize, msg, membsize); + if (status == 0) + return CSP_ERR_TIMEDOUT; + + return CSP_ERR_NONE; +} + diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_sfp.c b/gomspace/libgscsp/lib/libcsp/src/csp_sfp.c new file mode 100644 index 00000000..96ef36e1 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_sfp.c @@ -0,0 +1,170 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include "csp_conn.h" + +typedef struct __attribute__((__packed__)) { + uint32_t offset; + uint32_t totalsize; +} sfp_header_t; + +/** + * SFP Headers: + * The following functions are helper functions that handles the extra SFP + * information that needs to be appended to all data packets. + */ +static sfp_header_t * csp_sfp_header_add(csp_packet_t * packet) { + sfp_header_t * header = (sfp_header_t *) &packet->data[packet->length]; + packet->length += sizeof(sfp_header_t); + memset(header, 0, sizeof(sfp_header_t)); + return header; +} + +static sfp_header_t * csp_sfp_header_remove(csp_packet_t * packet) { + sfp_header_t * header = (sfp_header_t *) &packet->data[packet->length-sizeof(sfp_header_t)]; + packet->length -= sizeof(sfp_header_t); + return header; +} + +int csp_sfp_send_own_memcpy(csp_conn_t * conn, const void * data, int totalsize, int mtu, uint32_t timeout, void * (*memcpyfcn)(void *, const void *, size_t)) { + + int count = 0; + while(count < totalsize) { + + /* Allocate packet */ + csp_packet_t * packet = csp_buffer_get(mtu); + if (packet == NULL) + return -1; + + /* Calculate sending size */ + int size = totalsize - count; + if (size > mtu) + size = mtu; + + /* Print debug */ + csp_debug(CSP_PROTOCOL, "Sending SFP at %x size %u", data + count, size); + + /* Copy data */ + (*memcpyfcn)(packet->data, data + count, size); + packet->length = size; + + /* Set fragment flag */ + conn->idout.flags |= CSP_FFRAG; + + /* Add SFP header */ + sfp_header_t * sfp_header = csp_sfp_header_add(packet); + sfp_header->totalsize = csp_hton32(totalsize); + sfp_header->offset = csp_hton32(count); + + /* Send data */ + if (!csp_send(conn, packet, timeout)) { + csp_buffer_free(packet); + return -1; + } + + /* Increment count */ + count += size; + + } + + return 0; + +} + +int csp_sfp_send(csp_conn_t * conn, const void * data, int totalsize, int mtu, uint32_t timeout) { + return csp_sfp_send_own_memcpy(conn, data, totalsize, mtu, timeout, &memcpy); +} + +int csp_sfp_recv_fp(csp_conn_t * conn, void ** dataout, int * datasize, uint32_t timeout, csp_packet_t * first_packet) { + + unsigned int last_byte = 0; + + *dataout = NULL; /* Allow caller to assume csp_free() can always be called when dataout is non-NULL */ + + /* Get first packet from user, or from connection */ + csp_packet_t * packet = NULL; + if (first_packet == NULL) { + packet = csp_read(conn, timeout); + if (packet == NULL) + return -1; + } else { + packet = first_packet; + } + + do { + + /* Check that SFP header is present */ + if ((packet->id.flags & CSP_FFRAG) == 0) { + csp_debug(CSP_ERROR, "Missing SFP header"); + csp_buffer_free(packet); + return -1; + } + + /* Read SFP header */ + sfp_header_t * sfp_header = csp_sfp_header_remove(packet); + sfp_header->offset = csp_ntoh32(sfp_header->offset); + sfp_header->totalsize = csp_ntoh32(sfp_header->totalsize); + + csp_debug(CSP_PROTOCOL, "SFP fragment %u/%u", sfp_header->offset + packet->length, sfp_header->totalsize); + + if (sfp_header->offset > last_byte + 1) { + csp_debug(CSP_ERROR, "SFP missing %u bytes", sfp_header->offset - last_byte); + csp_buffer_free(packet); + return -1; + } else { + last_byte = sfp_header->offset + packet->length; + } + + /* Allocate memory */ + if (*dataout == NULL) + *dataout = csp_malloc(sfp_header->totalsize); + if (*dataout == NULL) { + csp_debug(CSP_ERROR, "No dyn-memory for SFP fragment"); + csp_buffer_free(packet); + return -1; + } + + /* Copy data to output */ + *datasize = sfp_header->totalsize; + memcpy(*dataout + sfp_header->offset, packet->data, packet->length); + + if (sfp_header->offset + packet->length >= sfp_header->totalsize) { + csp_debug(CSP_PROTOCOL, "SFP complete"); + csp_buffer_free(packet); + return 0; + } else { + csp_buffer_free(packet); + } + + } while((packet = csp_read(conn, timeout)) != NULL); + + return -1; + +} + +int csp_sfp_recv(csp_conn_t * conn, void ** dataout, int * datasize, uint32_t timeout) { + return csp_sfp_recv_fp(conn, dataout, datasize, timeout, NULL); +} + diff --git a/gomspace/libgscsp/lib/libcsp/src/drivers/can/can_socketcan.c b/gomspace/libgscsp/lib/libcsp/src/drivers/can/can_socketcan.c new file mode 100644 index 00000000..7d12f184 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/drivers/can/can_socketcan.c @@ -0,0 +1,201 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* SocketCAN driver */ +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#ifdef CSP_HAVE_LIBSOCKETCAN +#include +#endif + +static struct can_socketcan_s { + int socket; + csp_iface_t interface; +} socketcan[1] = { + { + .interface = { + .name = "CAN", + .nexthop = csp_can_tx, + .mtu = CSP_CAN_MTU, + .driver = &socketcan[0], + }, + }, +}; + +static void * socketcan_rx_thread(void * parameters) +{ + struct can_frame frame; + int nbytes; + + while (1) { + /* Read CAN frame */ + nbytes = read(socketcan[0].socket, &frame, sizeof(frame)); + if (nbytes < 0) { + csp_log_error("read: %s", strerror(errno)); + continue; + } + + if (nbytes != sizeof(frame)) { + csp_log_warn("Read incomplete CAN frame"); + continue; + } + + /* Frame type */ + if (frame.can_id & (CAN_ERR_FLAG | CAN_RTR_FLAG) || !(frame.can_id & CAN_EFF_FLAG)) { + /* Drop error and remote frames */ + csp_log_warn("Discarding ERR/RTR/SFF frame"); + continue; + } + + /* Strip flags */ + frame.can_id &= CAN_EFF_MASK; + + /* Call RX callbacsp_can_rx_frameck */ + csp_can_rx(&socketcan[0].interface, frame.can_id, frame.data, frame.can_dlc, NULL); + } + + /* We should never reach this point */ + pthread_exit(NULL); +} + + +int csp_can_tx_frame(csp_iface_t *interface, uint32_t id, const uint8_t * data, uint8_t dlc) +{ + struct can_frame frame; + int i, tries = 0; + memset(&frame, 0, sizeof(frame)); + if (dlc > 8) + return -1; + + /* Copy identifier */ + frame.can_id = id | CAN_EFF_FLAG; + + /* Copy data to frame */ + for (i = 0; i < dlc; i++) + frame.data[i] = data[i]; + + /* Set DLC */ + frame.can_dlc = dlc; + + /* Send frame */ + while (write(socketcan[0].socket, &frame, sizeof(frame)) != sizeof(frame)) { + if (++tries < 1000 && errno == ENOBUFS) { + /* Wait 10 ms and try again */ + usleep(10000); + } else { + csp_log_error("write: %s", strerror(errno)); + break; + } + } + + return 0; +} + +csp_iface_t * csp_can_socketcan_init(const char * ifc, int bitrate, int promisc) +{ + struct ifreq ifr; + struct sockaddr_can addr; + pthread_t rx_thread; + + printf("Init can interface %s\n", ifc); + +#ifdef CSP_HAVE_LIBSOCKETCAN + /* Set interface up */ + if (bitrate > 0) { + can_do_stop(ifc); + can_set_bitrate(ifc, bitrate); + can_set_restart_ms(ifc, 100); + can_do_start(ifc); + } +#endif + + /* Create socket */ + if ((socketcan[0].socket = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { + csp_log_error("socket: %s", strerror(errno)); + return NULL; + } + + /* Locate interface */ + strncpy(ifr.ifr_name, ifc, IFNAMSIZ - 1); + if (ioctl(socketcan[0].socket, SIOCGIFINDEX, &ifr) < 0) { + csp_log_error("ioctl: %s", strerror(errno)); + return NULL; + } + memset(&addr, 0, sizeof(addr)); + /* Bind the socket to CAN interface */ + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + if (bind(socketcan[0].socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + csp_log_error("bind: %s", strerror(errno)); + return NULL; + } + + /* Set filter mode */ + if (promisc == 0) { + + struct can_filter filter; + filter.can_id = CFP_MAKE_DST(csp_get_address()); + filter.can_mask = CFP_MAKE_DST((1 << CFP_HOST_SIZE) - 1); + + if (setsockopt(socketcan[0].socket, SOL_CAN_RAW, CAN_RAW_FILTER, &filter, sizeof(filter)) < 0) { + csp_log_error("setsockopt: %s", strerror(errno)); + return NULL; + } + + } + + /* Create receive thread */ + if (pthread_create(&rx_thread, NULL, socketcan_rx_thread, NULL) != 0) { + csp_log_error("pthread_create: %s", strerror(errno)); + return NULL; + } + + csp_iflist_add(&socketcan[0].interface); + + return &socketcan[0].interface; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_linux.c b/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_linux.c new file mode 100644 index 00000000..c4ceeb27 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_linux.c @@ -0,0 +1,254 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +int fd; +usart_callback_t usart_callback = NULL; + +static void *serial_rx_thread(void *vptr_args); + +int getbaud(int ifd) { + struct termios termAttr; + int inputSpeed = -1; + speed_t baudRate; + tcgetattr(ifd, &termAttr); + /* Get the input speed. */ + baudRate = cfgetispeed(&termAttr); + switch (baudRate) { + case B0: + inputSpeed = 0; + break; + case B50: + inputSpeed = 50; + break; + case B110: + inputSpeed = 110; + break; + case B134: + inputSpeed = 134; + break; + case B150: + inputSpeed = 150; + break; + case B200: + inputSpeed = 200; + break; + case B300: + inputSpeed = 300; + break; + case B600: + inputSpeed = 600; + break; + case B1200: + inputSpeed = 1200; + break; + case B1800: + inputSpeed = 1800; + break; + case B2400: + inputSpeed = 2400; + break; + case B4800: + inputSpeed = 4800; + break; + case B9600: + inputSpeed = 9600; + break; + case B19200: + inputSpeed = 19200; + break; + case B38400: + inputSpeed = 38400; + break; + case B57600: + inputSpeed = 57600; + break; + case B115200: + inputSpeed = 115200; + break; + case B230400: + inputSpeed = 230400; + break; +#ifndef CSP_MACOSX + case B460800: + inputSpeed = 460800; + break; + case B500000: + inputSpeed = 500000; + break; + case B576000: + inputSpeed = 576000; + break; + case B921600: + inputSpeed = 921600; + break; + case B1000000: + inputSpeed = 1000000; + break; + case B1152000: + inputSpeed = 1152000; + break; + case B1500000: + inputSpeed = 1500000; + break; + case B2000000: + inputSpeed = 2000000; + break; + case B2500000: + inputSpeed = 2500000; + break; + case B3000000: + inputSpeed = 3000000; + break; + case B3500000: + inputSpeed = 3500000; + break; + case B4000000: + inputSpeed = 4000000; + break; +#endif + } + + return inputSpeed; + +} + +void usart_init(struct usart_conf * conf) { + + struct termios options; + pthread_t rx_thread; + + fd = open(conf->device, O_RDWR | O_NOCTTY | O_NONBLOCK); + + if (fd < 0) { + printf("Failed to open %s: %s\r\n", conf->device, strerror(errno)); + return; + } + + int brate = 0; + switch(conf->baudrate) { + case 4800: brate=B4800; break; + case 9600: brate=B9600; break; + case 19200: brate=B19200; break; + case 38400: brate=B38400; break; + case 57600: brate=B57600; break; + case 115200: brate=B115200; break; + case 230400: brate=B230400; break; +#ifndef CSP_MACOSX + case 460800: brate=B460800; break; + case 500000: brate=B500000; break; + case 576000: brate=B576000; break; + case 921600: brate=B921600; break; + case 1000000: brate=B1000000; break; + case 1152000: brate=B1152000; break; + case 1500000: brate=B1500000; break; + case 2000000: brate=B2000000; break; + case 2500000: brate=B2500000; break; + case 3000000: brate=B3000000; break; + case 3500000: brate=B3500000; break; + case 4000000: brate=B4000000; break; +#endif + default: + printf("Unsupported baudrate requested, defaulting to 500000, requested baudrate=%u\n", conf->baudrate); + brate=B500000; + break; + } + + tcgetattr(fd, &options); + cfsetispeed(&options, brate); + cfsetospeed(&options, brate); + options.c_cflag |= (CLOCAL | CREAD); + options.c_cflag &= ~PARENB; + options.c_cflag &= ~CSTOPB; + options.c_cflag &= ~CSIZE; + options.c_cflag |= CS8; + options.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); + options.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | PARMRK | INPCK | ISTRIP | IXON); + options.c_oflag &= ~(OCRNL | ONLCR | ONLRET | ONOCR | OFILL | OPOST); + options.c_cc[VTIME] = 0; + options.c_cc[VMIN] = 1; + tcsetattr(fd, TCSANOW, &options); + if (tcgetattr(fd, &options) == -1) + perror("error setting options"); + fcntl(fd, F_SETFL, 0); + + /* Flush old transmissions */ + if (tcflush(fd, TCIOFLUSH) == -1) + printf("Error flushing serial port - %s(%d).\n", strerror(errno), errno); + + if (pthread_create(&rx_thread, NULL, serial_rx_thread, NULL) != 0) + return; + +} + +void usart_set_callback(usart_callback_t callback) { + usart_callback = callback; +} + +void usart_insert(char c, void * pxTaskWoken) { + printf("%c", c); +} + +void usart_putstr(char * buf, int len) { + if (write(fd, buf, len) != len) + return; +} + +void usart_putc(char c) { + if (write(fd, &c, 1) != 1) + return; +} + +char usart_getc(void) { + char c; + if (read(fd, &c, 1) != 1) return 0; + return c; +} + +static void *serial_rx_thread(void *vptr_args) { + unsigned int length; + uint8_t * cbuf = malloc(100000); + + // Receive loop + while (1) { + length = read(fd, cbuf, 300); + if (length <= 0) { + perror("Error: "); + exit(1); + } + if (usart_callback) + usart_callback(cbuf, length, NULL); + } + return NULL; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_windows.c b/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_windows.c new file mode 100644 index 00000000..91ffe87d --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_windows.c @@ -0,0 +1,230 @@ +#include +#include +#include + +#include +#include + +static HANDLE portHandle = INVALID_HANDLE_VALUE; +static HANDLE rxThread = INVALID_HANDLE_VALUE; +static CRITICAL_SECTION txSection; +static LONG isListening = 0; +static usart_callback_t usart_callback = NULL; + +static void prvSendData(char *buf, int bufsz); +static int prvTryOpenPort(const char* intf); +static int prvTryConfigurePort(const struct usart_conf*); +static int prvTrySetPortTimeouts(void); +static const char* prvParityToStr(BYTE paritySetting); + +#ifdef CSP_DEBUG +static void prvPrintError(void) { + char *messageBuffer = NULL; + DWORD errorCode = GetLastError(); + DWORD formatMessageRet; + formatMessageRet = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + errorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (char*)&messageBuffer, + 0, + NULL); + + if( !formatMessageRet ) { + csp_log_error("FormatMessage error, code: %lu", GetLastError()); + return; + } + csp_log_error("%s", messageBuffer); + LocalFree(messageBuffer); +} +#endif + +#ifdef CSP_DEBUG +#define printError() prvPrintError() +#else +#define printError() do {} while(0) +#endif + +static int prvTryOpenPort(const char *intf) { + portHandle = CreateFileA( + intf, + GENERIC_READ|GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + 0, + NULL); + + if( portHandle == INVALID_HANDLE_VALUE ) { + DWORD errorCode = GetLastError(); + if( errorCode == ERROR_FILE_NOT_FOUND ) { + csp_log_error("Could not open serial port, because it didn't exist!"); + } + else + csp_log_error("Failure opening serial port! Code: %lu", errorCode); + return 1; + } + return 0; +} + +static int prvTryConfigurePort(const struct usart_conf * conf) { + DCB portSettings = {0}; + portSettings.DCBlength = sizeof(DCB); + if(!GetCommState(portHandle, &portSettings) ) { + csp_log_error("Could not get default settings for open COM port! Code: %lu", GetLastError()); + return -1; + } + portSettings.BaudRate = conf->baudrate; + portSettings.Parity = conf->paritysetting; + portSettings.StopBits = conf->stopbits; + portSettings.fParity = conf->checkparity; + portSettings.fBinary = TRUE; + portSettings.ByteSize = conf->databits; + if( !SetCommState(portHandle, &portSettings) ) { + csp_log_error("Error when setting COM port settings! Code:%lu", GetLastError()); + return 1; + } + + GetCommState(portHandle, &portSettings); + + csp_log_info("Port: %s, Baudrate: %lu, Data bits: %d, Stop bits: %d, Parity: %s", + conf->device, conf->baudrate, conf->databits, conf->stopbits, prvParityToStr(conf->paritysetting)); + return 0; +} + +static const char* prvParityToStr(BYTE paritySetting) { + static const char *parityStr[] = { + "None", + "Odd", + "Even", + "N/A" + }; + char const *resultStr = NULL; + + switch(paritySetting) { + case NOPARITY: + resultStr = parityStr[0]; + break; + case ODDPARITY: + resultStr = parityStr[1]; + break; + case EVENPARITY: + resultStr = parityStr[2]; + break; + default: + resultStr = parityStr[3]; + }; + return resultStr; +} + +static int prvTrySetPortTimeouts(void) { + COMMTIMEOUTS timeouts = {0}; + + if( !GetCommTimeouts(portHandle, &timeouts) ) { + csp_log_error("Error gettings current timeout settings"); + return 1; + } + + timeouts.ReadIntervalTimeout = 5; + timeouts.ReadTotalTimeoutMultiplier = 1; + timeouts.ReadTotalTimeoutConstant = 5; + timeouts.WriteTotalTimeoutMultiplier = 1; + timeouts.WriteTotalTimeoutConstant = 5; + + if(!SetCommTimeouts(portHandle, &timeouts)) { + csp_log_error("Error setting timeouts!"); + return 1; + } + + return 0; +} + +unsigned WINAPI prvRxTask(void* params) { + DWORD bytesRead; + DWORD eventStatus; + uint8_t recvBuffer[24]; + SetCommMask(portHandle, EV_RXCHAR); + + while(isListening) { + WaitCommEvent(portHandle, &eventStatus, NULL); + if( !(eventStatus & EV_RXCHAR) ) { + continue; + } + if( !ReadFile(portHandle, recvBuffer, 24, &bytesRead, NULL)) { + csp_log_warn("Error receiving data! Code: %lu", GetLastError()); + continue; + } + if( usart_callback != NULL ) + usart_callback(recvBuffer, (size_t)bytesRead, NULL); + } + return 0; +} + +static void prvSendData(char *buf, int bufsz) { + DWORD bytesTotal = 0; + DWORD bytesActual; + if( !WriteFile(portHandle, buf, bufsz-bytesTotal, &bytesActual, NULL) ) { + csp_log_error("Could not write data. Code: %lu", GetLastError()); + return; + } + if( !FlushFileBuffers(portHandle) ) { + csp_log_warn("Could not flush write buffer. Code: %lu", GetLastError()); + } +} + +void usart_shutdown(void) { + InterlockedExchange(&isListening, 0); + CloseHandle(portHandle); + portHandle = INVALID_HANDLE_VALUE; + if( rxThread != INVALID_HANDLE_VALUE ) { + WaitForSingleObject(rxThread, INFINITE); + rxThread = INVALID_HANDLE_VALUE; + } + DeleteCriticalSection(&txSection); +} + +void usart_listen(void) { + InterlockedExchange(&isListening, 1); + rxThread = (HANDLE)_beginthreadex(NULL, 0, &prvRxTask, NULL, 0, NULL); +} + +void usart_putstr(char* buf, int bufsz) { + EnterCriticalSection(&txSection); + prvSendData(buf, bufsz); + LeaveCriticalSection(&txSection); +} + +void usart_insert(char c, void *pxTaskWoken) { + /* redirect debug output to stdout */ + printf("%c", c); +} + +void usart_set_callback(usart_callback_t callback) { + usart_callback = callback; +} + +void usart_init(struct usart_conf * conf) { + if( prvTryOpenPort(conf->device) ) { + printError(); + return; + } + + if( prvTryConfigurePort(conf) ) { + printError(); + return; + } + + if( prvTrySetPortTimeouts() ) { + printError(); + return; + } + + InitializeCriticalSection(&txSection); + + /* Start receiver thread */ + usart_listen(); +} + + diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can.c new file mode 100644 index 00000000..5add8334 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can.c @@ -0,0 +1,279 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* CAN frames contains at most 8 bytes of data, so in order to transmit CSP + * packets larger than this, a fragmentation protocol is required. The CAN + * Fragmentation Protocol (CFP) header is designed to match the 29 bit CAN + * identifier. + * + * The CAN identifier is divided in these fields: + * src: 5 bits + * dst: 5 bits + * type: 1 bit + * remain: 8 bits + * identifier: 10 bits + * + * Source and Destination addresses must match the CSP packet. The type field + * is used to distinguish the first and subsequent frames in a fragmented CSP + * packet. Type is BEGIN (0) for the first fragment and MORE (1) for all other + * fragments. Remain indicates number of remaining fragments, and must be + * decremented by one for each fragment sent. The identifier field serves the + * same purpose as in the Internet Protocol, and should be an auto incrementing + * integer to uniquely separate sessions. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "csp_if_can_pbuf.h" + +/* CFP Frame Types */ +enum cfp_frame_t { + CFP_BEGIN = 0, + CFP_MORE = 1 +}; + +int csp_can_rx(csp_iface_t *interface, uint32_t id, const uint8_t *data, uint8_t dlc, CSP_BASE_TYPE *task_woken) +{ + csp_can_pbuf_element_t *buf; + uint8_t offset; + + /* Random packet loss */ +#if 0 + int random = rand(); + if (random < RAND_MAX * 0.00005) { + csp_log_warn("Dropping frame"); + return; + } +#endif + + /* Bind incoming frame to a packet buffer */ + buf = csp_can_pbuf_find(id, CFP_ID_CONN_MASK); + + /* Check returned buffer */ + if (buf == NULL) { + if (CFP_TYPE(id) == CFP_BEGIN) { + buf = csp_can_pbuf_new(id, task_woken); + if (buf == NULL) { + //csp_log_warn("No available packet buffer for CAN"); + interface->rx_error++; + return CSP_ERR_NOMEM; + } + } else { + //csp_log_warn("Out of order id 0x%X remain %u", CFP_ID(id), CFP_REMAIN(id)); + interface->frame++; + return CSP_ERR_INVAL; + } + } + + /* Reset frame data offset */ + offset = 0; + + switch (CFP_TYPE(id)) { + + case CFP_BEGIN: + + /* Discard packet if DLC is less than CSP id + CSP length fields */ + if (dlc < sizeof(csp_id_t) + sizeof(uint16_t)) { + //csp_log_warn("Short BEGIN frame received"); + interface->frame++; + csp_can_pbuf_free(buf, task_woken); + break; + } + + /* Check for incomplete frame */ + if (buf->packet != NULL) { + /* Reuse the buffer */ + //csp_log_warn("Incomplete frame"); + interface->frame++; + } else { + /* Allocate memory for frame */ + if (task_woken == NULL) { + buf->packet = csp_buffer_get(interface->mtu); + } else { + buf->packet = csp_buffer_get_isr(interface->mtu); + } + if (buf->packet == NULL) { + //csp_log_error("Failed to get buffer for CSP_BEGIN packet"); + interface->frame++; + csp_can_pbuf_free(buf, task_woken); + break; + } + } + + /* Copy CSP identifier and length*/ + memcpy(&(buf->packet->id), data, sizeof(csp_id_t)); + buf->packet->id.ext = csp_ntoh32(buf->packet->id.ext); + memcpy(&(buf->packet->length), data + sizeof(csp_id_t), sizeof(uint16_t)); + buf->packet->length = csp_ntoh16(buf->packet->length); + + /* Reset RX count */ + buf->rx_count = 0; + + /* Set offset to prevent CSP header from being copied to CSP data */ + offset = sizeof(csp_id_t) + sizeof(uint16_t); + + /* Set remain field - increment to include begin packet */ + buf->remain = CFP_REMAIN(id) + 1; + + /* FALLTHROUGH */ + + case CFP_MORE: + + /* Check 'remain' field match */ + if (CFP_REMAIN(id) != buf->remain - 1) { + //csp_log_error("CAN frame lost in CSP packet"); + csp_can_pbuf_free(buf, task_woken); + interface->frame++; + break; + } + + /* Decrement remaining frames */ + buf->remain--; + + /* Check for overflow */ + if ((buf->rx_count + dlc - offset) > buf->packet->length) { + //csp_log_error("RX buffer overflow"); + interface->frame++; + csp_can_pbuf_free(buf, task_woken); + break; + } + + /* Copy dlc bytes into buffer */ + memcpy(&buf->packet->data[buf->rx_count], data + offset, dlc - offset); + buf->rx_count += dlc - offset; + + /* Check if more data is expected */ + if (buf->rx_count != buf->packet->length) + break; + + /* Data is available */ + csp_qfifo_write(buf->packet, interface, task_woken); + + /* Drop packet buffer reference */ + buf->packet = NULL; + + /* Free packet buffer */ + csp_can_pbuf_free(buf, task_woken); + + break; + + default: + //csp_log_warn("Received unknown CFP message type"); + csp_can_pbuf_free(buf, task_woken); + break; + + } + + return CSP_ERR_NONE; +} + +int csp_can_tx(csp_iface_t *interface, csp_packet_t *packet, uint32_t timeout) +{ + + /* CFP Identification number */ + static volatile int csp_can_frame_id = 0; + + /* Get local copy of the static frameid */ + int ident = csp_can_frame_id++; + + uint16_t tx_count; + uint8_t bytes, overhead, avail, dest; + uint8_t frame_buf[8]; + + /* Calculate overhead */ + overhead = sizeof(csp_id_t) + sizeof(uint16_t); + + /* Insert destination node mac address into the CFP destination field */ + dest = csp_rtable_find_mac(packet->id.dst); + if (dest == CSP_NODE_MAC) + dest = packet->id.dst; + + /* Create CAN identifier */ + uint32_t id = 0; + id |= CFP_MAKE_SRC(packet->id.src); + id |= CFP_MAKE_DST(dest); + id |= CFP_MAKE_ID(ident); + id |= CFP_MAKE_TYPE(CFP_BEGIN); + id |= CFP_MAKE_REMAIN((packet->length + overhead - 1) / 8); + + /* Calculate first frame data bytes */ + avail = 8 - overhead; + bytes = (packet->length <= avail) ? packet->length : avail; + + /* Copy CSP headers and data */ + uint32_t csp_id_be = csp_hton32(packet->id.ext); + uint16_t csp_length_be = csp_hton16(packet->length); + + memcpy(frame_buf, &csp_id_be, sizeof(csp_id_be)); + memcpy(frame_buf + sizeof(csp_id_be), &csp_length_be, sizeof(csp_length_be)); + memcpy(frame_buf + overhead, packet->data, bytes); + + /* Increment tx counter */ + tx_count = bytes; + + /* Send first frame */ + if (csp_can_tx_frame(interface, id, frame_buf, overhead + bytes)) { + //csp_log_warn("Failed to send CAN frame in csp_tx_can"); + interface->tx_error++; + return CSP_ERR_DRIVER; + } + + /* Send next frames if not complete */ + while (tx_count < packet->length) { + /* Calculate frame data bytes */ + bytes = (packet->length - tx_count >= 8) ? 8 : packet->length - tx_count; + + /* Prepare identifier */ + id = 0; + id |= CFP_MAKE_SRC(packet->id.src); + id |= CFP_MAKE_DST(dest); + id |= CFP_MAKE_ID(ident); + id |= CFP_MAKE_TYPE(CFP_MORE); + id |= CFP_MAKE_REMAIN((packet->length - tx_count - bytes + 7) / 8); + + /* Increment tx counter */ + tx_count += bytes; + + /* Send frame */ + if (csp_can_tx_frame(interface, id, packet->data + tx_count - bytes, bytes)) { + //csp_log_warn("Failed to send CAN frame in Tx callback"); + interface->tx_error++; + return CSP_ERR_DRIVER; + } + } + + csp_buffer_free(packet); + + return CSP_ERR_NONE; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.c new file mode 100644 index 00000000..65f18de9 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.c @@ -0,0 +1,77 @@ +/* + * csp_if_can_pbuf.c + * + * Created on: Feb 3, 2017 + * Author: johan + */ + +#include +#include "csp_if_can_pbuf.h" + +/* Number of packet buffer elements */ +#define PBUF_ELEMENTS CSP_CONN_MAX + +/* Buffer element timeout in ms */ +#define PBUF_TIMEOUT_MS 1000 + +static csp_can_pbuf_element_t csp_can_pbuf[PBUF_ELEMENTS] = {}; + +int csp_can_pbuf_free(csp_can_pbuf_element_t *buf, CSP_BASE_TYPE *task_woken) +{ + /* Free CSP packet */ + if (buf->packet != NULL) { + if (task_woken == NULL) { + csp_buffer_free(buf->packet); + } else { + csp_buffer_free_isr(buf->packet); + } + } + + /* Mark buffer element free */ + buf->packet = NULL; + buf->rx_count = 0; + buf->cfpid = 0; + buf->last_used = 0; + buf->remain = 0; + buf->state = BUF_FREE; + + return CSP_ERR_NONE; +} + +csp_can_pbuf_element_t *csp_can_pbuf_new(uint32_t id, CSP_BASE_TYPE *task_woken) +{ + uint32_t now = csp_get_ms(); + + for (int i = 0; i < PBUF_ELEMENTS; i++) { + + /* Perform cleanup in used pbufs */ + if (csp_can_pbuf[i].state == BUF_USED) { + if (now - csp_can_pbuf[i].last_used > PBUF_TIMEOUT_MS) + csp_can_pbuf_free(&csp_can_pbuf[i], task_woken); + } + + if (csp_can_pbuf[i].state == BUF_FREE) { + csp_can_pbuf[i].state = BUF_USED; + csp_can_pbuf[i].cfpid = id; + csp_can_pbuf[i].remain = 0; + csp_can_pbuf[i].last_used = now; + return &csp_can_pbuf[i]; + } + + } + + return NULL; + +} + +csp_can_pbuf_element_t *csp_can_pbuf_find(uint32_t id, uint32_t mask) +{ + for (int i = 0; i < PBUF_ELEMENTS; i++) { + if ((csp_can_pbuf[i].state == BUF_USED) && ((csp_can_pbuf[i].cfpid & mask) == (id & mask))) { + csp_can_pbuf[i].last_used = csp_get_ms(); + return &csp_can_pbuf[i]; + } + } + return NULL; +} + diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.h b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.h new file mode 100644 index 00000000..3e71c26c --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.h @@ -0,0 +1,31 @@ +/* + * csp_if_can_pbuf.h + * + * Created on: Feb 3, 2017 + * Author: johan + */ + +#ifndef LIB_CSP_SRC_INTERFACES_CSP_IF_CAN_PBUF_H_ +#define LIB_CSP_SRC_INTERFACES_CSP_IF_CAN_PBUF_H_ + +/* Packet buffers */ +typedef enum { + BUF_FREE = 0, /* Buffer element free */ + BUF_USED = 1, /* Buffer element used */ +} csp_can_pbuf_state_t; + +typedef struct { + uint16_t rx_count; /* Received bytes */ + uint32_t remain; /* Remaining packets */ + uint32_t cfpid; /* Connection CFP identification number */ + csp_packet_t *packet; /* Pointer to packet buffer */ + csp_can_pbuf_state_t state; /* Element state */ + uint32_t last_used; /* Timestamp in ms for last use of buffer */ +} csp_can_pbuf_element_t; + +int csp_can_pbuf_free(csp_can_pbuf_element_t *buf, CSP_BASE_TYPE *task_woken); +csp_can_pbuf_element_t *csp_can_pbuf_new(uint32_t id, CSP_BASE_TYPE *task_woken); +csp_can_pbuf_element_t *csp_can_pbuf_find(uint32_t id, uint32_t mask); +void csp_can_pbuf_cleanup(CSP_BASE_TYPE *task_woken); + +#endif /* LIB_CSP_SRC_INTERFACES_CSP_IF_CAN_PBUF_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_i2c.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_i2c.c new file mode 100644 index 00000000..c5d105df --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_i2c.c @@ -0,0 +1,116 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include + +static int csp_i2c_handle = 0; + +int csp_i2c_tx(csp_iface_t * interface, csp_packet_t * packet, uint32_t timeout) { + + /* Cast the CSP packet buffer into an i2c frame */ + i2c_frame_t * frame = (i2c_frame_t *) packet; + + /* Insert destination node into the i2c destination field */ + if (csp_rtable_find_mac(packet->id.dst) == CSP_NODE_MAC) { + frame->dest = packet->id.dst; + } else { + frame->dest = csp_rtable_find_mac(packet->id.dst); + } + + /* Save the outgoing id in the buffer */ + packet->id.ext = csp_hton32(packet->id.ext); + + /* Add the CSP header to the I2C length field */ + frame->len += sizeof(packet->id); + frame->len_rx = 0; + + /* Some I2C drivers support X number of retries + * CSP don't care about this. If it doesn't work the first + * time, don'y use time on it. + */ + frame->retries = 0; + + /* enqueue the frame */ + if (i2c_send(csp_i2c_handle, frame, timeout) != E_NO_ERR) + return CSP_ERR_DRIVER; + + return CSP_ERR_NONE; + +} + +/** + * When a frame is received, cast it to a csp_packet + * and send it directly to the CSP new packet function. + * Context: ISR only + * @param frame + */ +void csp_i2c_rx(i2c_frame_t * frame, void * pxTaskWoken) { + + static csp_packet_t * packet; + + /* Validate input */ + if (frame == NULL) + return; + + if ((frame->len < 4) || (frame->len > I2C_MTU)) { + csp_if_i2c.frame++; + csp_buffer_free_isr(frame); + return; + } + + /* Strip the CSP header off the length field before converting to CSP packet */ + frame->len -= sizeof(csp_id_t); + + /* Convert the packet from network to host order */ + packet = (csp_packet_t *) frame; + packet->id.ext = csp_ntoh32(packet->id.ext); + + /* Receive the packet in CSP */ + csp_qfifo_write(packet, &csp_if_i2c, pxTaskWoken); + +} + +int csp_i2c_init(uint8_t addr, int handle, int speed) { + + /* Create i2c_handle */ + csp_i2c_handle = handle; + if (i2c_init(csp_i2c_handle, I2C_MASTER, addr, speed, 10, 10, csp_i2c_rx) != E_NO_ERR) + return CSP_ERR_DRIVER; + + /* Register interface */ + csp_iflist_add(&csp_if_i2c); + + return CSP_ERR_NONE; + +} + +/** Interface definition */ +csp_iface_t csp_if_i2c = { + .name = "I2C", + .nexthop = csp_i2c_tx, +}; diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_kiss.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_kiss.c new file mode 100644 index 00000000..fe5707f6 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_kiss.c @@ -0,0 +1,260 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define KISS_MTU 256 + +#define FEND 0xC0 +#define FESC 0xDB +#define TFEND 0xDC +#define TFESC 0xDD + +#define TNC_DATA 0x00 +#define TNC_SET_HARDWARE 0x06 +#define TNC_RETURN 0xFF + +static int kiss_lock_init = 0; +static csp_bin_sem_handle_t kiss_lock; + +/* Send a CSP packet over the KISS RS232 protocol */ +static int csp_kiss_tx(csp_iface_t * interface, csp_packet_t * packet, uint32_t timeout) { + + if (interface == NULL || interface->driver == NULL) + return CSP_ERR_DRIVER; + + /* Add CRC32 checksum */ + csp_crc32_append(packet, false); + + /* Save the outgoing id in the buffer */ + packet->id.ext = csp_hton32(packet->id.ext); + packet->length += sizeof(packet->id.ext); + + /* Lock */ + csp_bin_sem_wait(&kiss_lock, 1000); + + /* Transmit data */ + csp_kiss_handle_t * driver = interface->driver; + driver->kiss_putc(FEND); + driver->kiss_putc(TNC_DATA); + for (unsigned int i = 0; i < packet->length; i++) { + if (((unsigned char *) &packet->id.ext)[i] == FEND) { + ((unsigned char *) &packet->id.ext)[i] = TFEND; + driver->kiss_putc(FESC); + } else if (((unsigned char *) &packet->id.ext)[i] == FESC) { + ((unsigned char *) &packet->id.ext)[i] = TFESC; + driver->kiss_putc(FESC); + } + driver->kiss_putc(((unsigned char *) &packet->id.ext)[i]); + } + driver->kiss_putc(FEND); + + /* Free data */ + csp_buffer_free(packet); + + /* Unlock */ + csp_bin_sem_post(&kiss_lock); + + return CSP_ERR_NONE; +} + +/** + * When a frame is received, decode the kiss-stuff + * and eventually send it directly to the CSP new packet function. + */ +void csp_kiss_rx(csp_iface_t * interface, uint8_t * buf, int len, void * pxTaskWoken) { + + /* Driver handle */ + csp_kiss_handle_t * driver = interface->driver; + + while (len--) { + + /* Input */ + unsigned char inputbyte = *buf++; + + /* If packet was too long */ + if (driver->rx_length > interface->mtu) { + //csp_log_warn("KISS RX overflow"); + interface->rx_error++; + driver->rx_mode = KISS_MODE_NOT_STARTED; + driver->rx_length = 0; + } + + switch (driver->rx_mode) { + + case KISS_MODE_NOT_STARTED: + + /* Send normal chars back to usart driver */ + if (inputbyte != FEND) { + if (driver->kiss_discard != NULL) + driver->kiss_discard(inputbyte, pxTaskWoken); + break; + } + + /* Try to allocate new buffer */ + if (driver->rx_packet == NULL) { + if (pxTaskWoken == NULL) { + driver->rx_packet = csp_buffer_get(interface->mtu); + } else { + driver->rx_packet = csp_buffer_get_isr(interface->mtu); + } + } + + /* If no more memory, skip frame */ + if (driver->rx_packet == NULL) { + driver->rx_mode = KISS_MODE_SKIP_FRAME; + break; + } + + /* Start transfer */ + driver->rx_length = 0; + driver->rx_mode = KISS_MODE_STARTED; + driver->rx_first = 1; + break; + + case KISS_MODE_STARTED: + + /* Escape char */ + if (inputbyte == FESC) { + driver->rx_mode = KISS_MODE_ESCAPED; + break; + } + + /* End Char */ + if (inputbyte == FEND) { + + /* Accept message */ + if (driver->rx_length > 0) { + + /* Check for valid length */ + if (driver->rx_length < CSP_HEADER_LENGTH + sizeof(uint32_t)) { + //csp_log_warn("KISS short frame skipped, len: %u", driver->rx_length); + interface->rx_error++; + driver->rx_mode = KISS_MODE_NOT_STARTED; + break; + } + + /* Count received frame */ + interface->frame++; + + /* The CSP packet length is without the header */ + driver->rx_packet->length = driver->rx_length - CSP_HEADER_LENGTH; + + /* Convert the packet from network to host order */ + driver->rx_packet->id.ext = csp_ntoh32(driver->rx_packet->id.ext); + + /* Validate CRC */ + if (csp_crc32_verify(driver->rx_packet, false) != CSP_ERR_NONE) { + //csp_log_warn("KISS invalid crc frame skipped, len: %u", driver->rx_packet->length); + interface->rx_error++; + driver->rx_mode = KISS_MODE_NOT_STARTED; + break; + } + + /* Send back into CSP, notice calling from task so last argument must be NULL! */ + csp_qfifo_write(driver->rx_packet, interface, pxTaskWoken); + driver->rx_packet = NULL; + driver->rx_mode = KISS_MODE_NOT_STARTED; + break; + + } + + /* Break after the end char */ + break; + } + + /* Skip the first char after FEND which is TNC_DATA (0x00) */ + if (driver->rx_first) { + driver->rx_first = 0; + break; + } + + /* Valid data char */ + ((char *) &driver->rx_packet->id.ext)[driver->rx_length++] = inputbyte; + + break; + + case KISS_MODE_ESCAPED: + + /* Escaped escape char */ + if (inputbyte == TFESC) + ((char *) &driver->rx_packet->id.ext)[driver->rx_length++] = FESC; + + /* Escaped fend char */ + if (inputbyte == TFEND) + ((char *) &driver->rx_packet->id.ext)[driver->rx_length++] = FEND; + + /* Go back to started mode */ + driver->rx_mode = KISS_MODE_STARTED; + break; + + case KISS_MODE_SKIP_FRAME: + + /* Just wait for end char */ + if (inputbyte == FEND) + driver->rx_mode = KISS_MODE_NOT_STARTED; + + break; + + } + + } + +} + +void csp_kiss_init(csp_iface_t * csp_iface, csp_kiss_handle_t * csp_kiss_handle, csp_kiss_putc_f kiss_putc_f, csp_kiss_discard_f kiss_discard_f, const char * name) { + + /* Init lock only once */ + if (kiss_lock_init == 0) { + csp_bin_sem_create(&kiss_lock); + kiss_lock_init = 1; + } + + /* Register device handle as member of interface */ + csp_iface->driver = csp_kiss_handle; + csp_kiss_handle->kiss_discard = kiss_discard_f; + csp_kiss_handle->kiss_putc = kiss_putc_f; + csp_kiss_handle->rx_packet = NULL; + csp_kiss_handle->rx_mode = KISS_MODE_NOT_STARTED; + + /* Set default MTU if not given */ + if (csp_iface->mtu == 0) { + csp_iface->mtu = KISS_MTU; + } + + /* Setup other mandatories */ + csp_iface->nexthop = csp_kiss_tx; + csp_iface->name = name; + + /* Regsiter interface */ + csp_iflist_add(csp_iface); + +} diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_lo.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_lo.c new file mode 100644 index 00000000..f3e81b15 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_lo.c @@ -0,0 +1,61 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* CSP includes */ +#include +#include +#include +#include + +#include +#include + +#include "../csp_route.h" + +/** + * Loopback interface transmit function + * @param packet Packet to transmit + * @param timeout Timout in ms + * @return 1 if packet was successfully transmitted, 0 on error + */ +static int csp_lo_tx(csp_iface_t * interface, csp_packet_t * packet, uint32_t timeout) { + + /* Drop packet silently if not destined for us. This allows + * blackhole routing addresses by setting their nexthop to + * the loopback interface. + */ + if (packet->id.dst != csp_get_address()) { + /* Consume and drop packet */ + csp_buffer_free(packet); + return CSP_ERR_NONE; + } + + /* Send back into CSP, notice calling from task so last argument must be NULL! */ + csp_qfifo_write(packet, &csp_if_lo, NULL); + + return CSP_ERR_NONE; + +} + +/* Interface definition */ +csp_iface_t csp_if_lo = { + .name = "LOOP", + .nexthop = csp_lo_tx, +}; diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c new file mode 100644 index 00000000..5292663b --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c @@ -0,0 +1,165 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +/* CSP includes */ +#include +#include +#include +#include +#include +#include + +/* ZMQ */ +#include + +static void * context; +static void * publisher; +static void * subscriber; +static csp_bin_sem_handle_t tx_wait; + +/** + * Interface transmit function + * @param packet Packet to transmit + * @param timeout Timeout in ms + * @return 1 if packet was successfully transmitted, 0 on error + */ +int csp_zmqhub_tx(csp_iface_t * interface, csp_packet_t * packet, uint32_t timeout) { + + /* Send envelope */ + uint8_t dest = csp_rtable_find_mac(packet->id.dst); + if (dest == CSP_NODE_MAC) + dest = packet->id.dst; + + uint16_t length = packet->length; + uint8_t * destptr = ((uint8_t *) &packet->id) - sizeof(dest); + memcpy(destptr, &dest, sizeof(dest)); + csp_bin_sem_wait(&tx_wait, CSP_INFINITY); /* Using ZMQ in thread safe manner*/ + int result = zmq_send(publisher, destptr, length + sizeof(packet->id) + sizeof(dest), 0); + csp_bin_sem_post(&tx_wait); /* Release tx semaphore */ + if (result < 0) + csp_log_error("ZMQ send error: %u %s\r\n", result, strerror(result)); + + csp_buffer_free(packet); + + return CSP_ERR_NONE; + +} + +CSP_DEFINE_TASK(csp_zmqhub_task) { + + while(1) { + zmq_msg_t msg; + assert(zmq_msg_init_size(&msg, 1024) == 0); + + /* Receive data */ + if (zmq_msg_recv(&msg, subscriber, 0) < 0) { + zmq_msg_close(&msg); + csp_log_error("ZMQ: %s", zmq_strerror(zmq_errno())); + continue; + } + + int datalen = zmq_msg_size(&msg); + if (datalen < 5) { + csp_log_warn("ZMQ: Too short datalen: %u", datalen); + while(zmq_msg_recv(&msg, subscriber, ZMQ_NOBLOCK) > 0) + zmq_msg_close(&msg); + continue; + } + + /* Create new csp packet */ + csp_packet_t * packet = csp_buffer_get(256); + if (packet == NULL) { + zmq_msg_close(&msg); + continue; + } + + /* Copy the data from zmq to csp */ + uint8_t * destptr = ((uint8_t *) &packet->id) - sizeof(*destptr); + memcpy(destptr, zmq_msg_data(&msg), datalen); + packet->length = datalen - sizeof(packet->id) - sizeof(*destptr); + + /* Queue up packet to router */ + csp_qfifo_write(packet, &csp_if_zmqhub, NULL); + + zmq_msg_close(&msg); + } + + return CSP_TASK_RETURN; + +} + +int csp_zmqhub_init(uint8_t addr, const char * host) { + char url_pub[100]; + char url_sub[100]; + + sprintf(url_pub, "tcp://%s:6000", host); + sprintf(url_sub, "tcp://%s:7000", host); + + return csp_zmqhub_init_w_endpoints(addr, url_pub, url_sub); +} + +int csp_zmqhub_init_w_endpoints(uint8_t addr, const char * publisher_endpoint, + const char * subscriber_endpoint) { + + context = zmq_ctx_new(); + assert(context); + + csp_log_info("INIT ZMQ with addr %u to servers %s / %s\r\n", + addr, publisher_endpoint, subscriber_endpoint); + + /* Publisher (TX) */ + publisher = zmq_socket(context, ZMQ_PUB); + assert(publisher); + assert(zmq_connect(publisher, publisher_endpoint) == 0); + + /* Subscriber (RX) */ + subscriber = zmq_socket(context, ZMQ_SUB); + assert(subscriber); + assert(zmq_connect(subscriber, subscriber_endpoint) == 0); + + if (addr == CSP_NODE_MAC) { // == 255 + assert(zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, NULL, 0) == 0); + } else { + assert(zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, &addr, 1) == 0); + } + /* ZMQ isn't thread safe, so we add a binary semaphore to wait on for tx */ + if (csp_bin_sem_create(&tx_wait) != CSP_SEMAPHORE_OK) { + csp_log_error("Failed to initialize semaphore in csp_zmqhub_init_w_endpoints"); + return CSP_ERR_NOMEM; + } + /* Start RX thread */ + static csp_thread_handle_t handle_subscriber; + int ret = csp_thread_create(csp_zmqhub_task, "ZMQ", 20000, NULL, 0, &handle_subscriber); + csp_log_info("Task start %d\r\n", ret); + + /* Register interface */ + csp_iflist_add(&csp_if_zmqhub); + + return CSP_ERR_NONE; + +} + +/* Interface definition */ +csp_iface_t csp_if_zmqhub = { + .name = "ZMQHUB", + .nexthop = csp_zmqhub_tx, +}; diff --git a/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_cidr.c b/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_cidr.c new file mode 100644 index 00000000..5758dc3c --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_cidr.c @@ -0,0 +1,233 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include + +/* Local typedef for routing table */ +typedef struct __attribute__((__packed__)) csp_rtable_s { + uint8_t address; + uint8_t netmask; + uint8_t mac; + csp_iface_t * interface; + struct csp_rtable_s * next; +} csp_rtable_t; + +/* Routing entries are stored in a linked list*/ +static csp_rtable_t * rtable = NULL; + +static csp_rtable_t * csp_rtable_find(uint8_t addr, uint8_t netmask, uint8_t exact) { + + /* Remember best result */ + csp_rtable_t * best_result = NULL; + uint8_t best_result_mask = 0; + + /* Start search */ + csp_rtable_t * i = rtable; + while(i) { + + /* Look for exact match */ + if (i->address == addr && i->netmask == netmask) { + best_result = i; + break; + } + + /* Try a CIDR netmask match */ + if (!exact) { + uint8_t hostbits = (1 << (CSP_ID_HOST_SIZE - i->netmask)) - 1; + uint8_t netbits = ~hostbits; + //printf("Netbits %x Hostbits %x\r\n", netbits, hostbits); + + /* Match network addresses */ + uint8_t net_a = i->address & netbits; + uint8_t net_b = addr & netbits; + //printf("A: %hhx, B: %hhx\r\n", net_a, net_b); + + /* We have a match */ + if (net_a == net_b) { + if (i->netmask >= best_result_mask) { + //printf("Match best result %u %u\r\n", best_result_mask, i->netmask); + best_result = i; + best_result_mask = i->netmask; + } + } + + } + + i = i->next; + + } + +#if 0 + if (best_result) + csp_debug(CSP_PACKET, "Using routing entry: %u/%u dev %s m:%u\r\n", best_result->address, best_result->netmask, best_result->interface->name, best_result->mac); +#endif + + return best_result; + +} + +void csp_rtable_clear(void) { + for (csp_rtable_t * i = rtable; (i);) { + void * freeme = i; + i = i->next; + csp_free(freeme); + } + rtable = NULL; + + /* Set loopback up again */ + csp_rtable_set(csp_get_address(), CSP_ID_HOST_SIZE, &csp_if_lo, CSP_NODE_MAC); + +} + +static int csp_rtable_parse(const char * buffer, int dry_run) { + + int valid_entries = 0; + + /* Copy string before running strtok */ + char * str = alloca(strlen(buffer) + 1); + memcpy(str, buffer, strlen(buffer) + 1); + + /* Get first token */ + str = strtok(str, ","); + + while ((str) && (strlen(str) > 1)) { + int address = 0, netmask = 0, mac = 255; + char name[10] = {}; + if (sscanf(str, "%u/%u %s %u", &address, &netmask, name, &mac) != 4) { + if (sscanf(str, "%u/%u %s", &address, &netmask, name) != 3) { + csp_log_error("Parse error %s", str); + return -1; + } + } + //printf("Parsed %u/%u %u %s\r\n", address, netmask, mac, name); + csp_iface_t * ifc = csp_iflist_get_by_name(name); + if (ifc) { + if (dry_run == 0) + csp_rtable_set(address, netmask, ifc, mac); + } else { + csp_log_error("Unknown interface %s", name); + return -1; + } + valid_entries++; + str = strtok(NULL, ","); + } + + return valid_entries; +} + +void csp_rtable_load(const char * buffer) { + csp_rtable_parse(buffer, 0); +} + +int csp_rtable_check(const char * buffer) { + return csp_rtable_parse(buffer, 1); +} + +int csp_rtable_save(char * buffer, int maxlen) { + int len = 0; + for (csp_rtable_t * i = rtable; (i); i = i->next) { + if (i->mac != CSP_NODE_MAC) { + len += snprintf(buffer + len, maxlen - len, "%u/%u %s %u, ", i->address, i->netmask, i->interface->name, i->mac); + } else { + len += snprintf(buffer + len, maxlen - len, "%u/%u %s, ", i->address, i->netmask, i->interface->name); + } + } + return len; +} + +csp_iface_t * csp_rtable_find_iface(uint8_t id) { + csp_rtable_t * entry = csp_rtable_find(id, CSP_ID_HOST_SIZE, 0); + if (entry == NULL) + return NULL; + return entry->interface; +} + +uint8_t csp_rtable_find_mac(uint8_t id) { + csp_rtable_t * entry = csp_rtable_find(id, CSP_ID_HOST_SIZE, 0); + if (entry == NULL) + return 255; + return entry->mac; +} + +int csp_rtable_set(uint8_t _address, uint8_t _netmask, csp_iface_t *ifc, uint8_t mac) { + + if (ifc == NULL) + return CSP_ERR_INVAL; + + /* Set default route in the old way */ + int address, netmask; + if (_address == CSP_DEFAULT_ROUTE) { + netmask = 0; + address = 0; + } else { + netmask = _netmask; + address = _address; + } + + /* Fist see if the entry exists */ + csp_rtable_t * entry = csp_rtable_find(address, netmask, 1); + + /* If not, create a new one */ + if (!entry) { + entry = csp_malloc(sizeof(csp_rtable_t)); + if (entry == NULL) + return CSP_ERR_NOMEM; + + entry->next = NULL; + /* Add entry to linked-list */ + if (rtable == NULL) { + /* This is the first interface to be added */ + rtable = entry; + } else { + /* One or more interfaces were already added */ + csp_rtable_t * i = rtable; + while (i->next) + i = i->next; + i->next = entry; + } + } + + /* Fill in the data */ + entry->address = address; + entry->netmask = netmask; + entry->interface = ifc; + entry->mac = mac; + + return CSP_ERR_NONE; +} + +#ifdef CSP_DEBUG +void csp_rtable_print(void) { + + for (csp_rtable_t * i = rtable; (i); i = i->next) { + if (i->mac == 255) { + printf("%u/%u %s\r\n", i->address, i->netmask, i->interface->name); + } else { + printf("%u/%u %s %u\r\n", i->address, i->netmask, i->interface->name, i->mac); + } + } + +} +#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_static.c b/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_static.c new file mode 100644 index 00000000..ea993027 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_static.c @@ -0,0 +1,128 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +/* Local typedef for routing table */ +typedef struct __attribute__((__packed__)) csp_rtable_s { + csp_iface_t * interface; + uint8_t mac; +} csp_rtable_t; + +/* Static storage context for routing table */ +static csp_rtable_t routes[CSP_ROUTE_COUNT] = {}; + +/** + * Find entry in static routing table + * This is done by table lookup with fallback to the default route + * The reason why the csp_rtable_t struct is not returned directly + * is that we wish to hide the storage format, mainly because of + * the alternative routing table storage (cidr). + * @param id Node + * @return pointer to found routing entry + */ +static csp_rtable_t * csp_rtable_find(uint8_t id) { + + if (routes[id].interface != NULL) { + return &routes[id]; + } else if (routes[CSP_DEFAULT_ROUTE].interface != NULL) { + return &routes[CSP_DEFAULT_ROUTE]; + } + return NULL; + +} + +csp_iface_t * csp_rtable_find_iface(uint8_t id) { + csp_rtable_t * route = csp_rtable_find(id); + if (route == NULL) + return NULL; + return route->interface; +} + +uint8_t csp_rtable_find_mac(uint8_t id) { + csp_rtable_t * route = csp_rtable_find(id); + if (route == NULL) + return 255; + return route->mac; +} + +void csp_rtable_clear(void) { + memset(routes, 0, sizeof(routes[0]) * CSP_ROUTE_COUNT); +} + +void csp_route_table_load(uint8_t route_table_in[CSP_ROUTE_TABLE_SIZE]) { + memcpy(routes, route_table_in, sizeof(routes[0]) * CSP_ROUTE_COUNT); +} + +void csp_route_table_save(uint8_t route_table_out[CSP_ROUTE_TABLE_SIZE]) { + memcpy(route_table_out, routes, sizeof(routes[0]) * CSP_ROUTE_COUNT); +} + +int csp_rtable_set(uint8_t node, uint8_t mask, csp_iface_t *ifc, uint8_t mac) { + + /* Don't add nothing */ + if (ifc == NULL) + return CSP_ERR_INVAL; + + /** + * Check if the interface has been added. + * + * NOTE: For future implementations, interfaces should call + * csp_route_add_if in its csp_if__init function, instead + * of registering at first route_set, in order to make the interface + * available to network based (CMP) route configuration. + */ + csp_iflist_add(ifc); + + /* Set route */ + if (node <= CSP_DEFAULT_ROUTE) { + routes[node].interface = ifc; + routes[node].mac = mac; + } else { + csp_log_error("Failed to set route: invalid node id %u", node); + return CSP_ERR_INVAL; + } + + return CSP_ERR_NONE; + +} + +void csp_rtable_load(const char * buffer) { +} + +int csp_rtable_check(const char * buffer) { + return -1; +} + +#ifdef CSP_DEBUG +void csp_rtable_print(void) { + int i; + printf("Node Interface Address\r\n"); + for (i = 0; i < CSP_DEFAULT_ROUTE; i++) + if (routes[i].interface != NULL) + printf("%4u %-9s %u\r\n", i, + routes[i].interface->name, + routes[i].mac == CSP_NODE_MAC ? i : routes[i].mac); + printf(" * %-9s %u\r\n", routes[CSP_DEFAULT_ROUTE].interface->name, routes[CSP_DEFAULT_ROUTE].mac); + +} +#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/transport/csp_rdp.c b/gomspace/libgscsp/lib/libcsp/src/transport/csp_rdp.c new file mode 100644 index 00000000..e19968e2 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/transport/csp_rdp.c @@ -0,0 +1,1102 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + * This is a implementation of the seq/ack handling taken from the Reliable Datagram Protocol (RDP) + * For more information read RFC 908/1151. The implementation has been extended to include support for + * delayed acknowledgments, to improve performance over half-duplex links. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "../csp_port.h" +#include "../csp_conn.h" +#include "../csp_io.h" +#include "csp_transport.h" + +#ifdef CSP_USE_RDP + +#define RDP_SYN 0x01 +#define RDP_ACK 0x02 +#define RDP_EAK 0x04 +#define RDP_RST 0x08 + +static uint32_t csp_rdp_window_size = 4; +static uint32_t csp_rdp_conn_timeout = 10000; +static uint32_t csp_rdp_packet_timeout = 1000; +static uint32_t csp_rdp_delayed_acks = 1; +static uint32_t csp_rdp_ack_timeout = 1000 / 4; +static uint32_t csp_rdp_ack_delay_count = 4 / 2; + +/* Used for queue calls */ +static CSP_BASE_TYPE pdTrue = 1; + +typedef struct __attribute__((__packed__)) { + /* The timestamp is placed in the padding bytes */ + uint8_t padding[CSP_PADDING_BYTES - 2 * sizeof(uint32_t)]; + uint32_t quarantine; // EACK quarantine period + uint32_t timestamp; // Time the message was sent + uint16_t length; // Length field must be just before CSP ID + csp_id_t id; // CSP id must be just before data + uint8_t data[]; // This just points to the rest of the buffer, without a size indication. +} rdp_packet_t; + +typedef struct __attribute__((__packed__)) { + union __attribute__((__packed__)) { + uint8_t flags; + struct __attribute__((__packed__)) { +#if defined(CSP_BIG_ENDIAN) && !defined(CSP_LITTLE_ENDIAN) + unsigned int res : 4; + unsigned int syn : 1; + unsigned int ack : 1; + unsigned int eak : 1; + unsigned int rst : 1; +#elif defined(CSP_LITTLE_ENDIAN) && !defined(CSP_BIG_ENDIAN) + unsigned int rst : 1; + unsigned int eak : 1; + unsigned int ack : 1; + unsigned int syn : 1; + unsigned int res : 4; +#else + #error "Must define one of CSP_BIG_ENDIAN or CSP_LITTLE_ENDIAN in csp_platform.h" +#endif + }; + }; + uint16_t seq_nr; + uint16_t ack_nr; +} rdp_header_t; + +/** + * RDP Headers: + * The following functions are helper functions that handles the extra RDP + * information that needs to be appended to all data packets. + */ +static rdp_header_t * csp_rdp_header_add(csp_packet_t * packet) { + rdp_header_t * header = (rdp_header_t *) &packet->data[packet->length]; + packet->length += sizeof(rdp_header_t); + memset(header, 0, sizeof(rdp_header_t)); + return header; +} + +static rdp_header_t * csp_rdp_header_remove(csp_packet_t * packet) { + rdp_header_t * header = (rdp_header_t *) &packet->data[packet->length-sizeof(rdp_header_t)]; + packet->length -= sizeof(rdp_header_t); + return header; +} + +static rdp_header_t * csp_rdp_header_ref(csp_packet_t * packet) { + rdp_header_t * header = (rdp_header_t *) &packet->data[packet->length-sizeof(rdp_header_t)]; + return header; +} + +/* Functions for comparing wrapping sequence numbers and timestamps */ + +/* Return 1 if seq is between start and end (both inclusive) */ +static inline int csp_rdp_seq_between(uint16_t seq, uint16_t start, uint16_t end) { + return (uint16_t)(end - start) >= (uint16_t)(seq - start); +} + +/* Return 1 if seq is before cmp */ +static inline int csp_rdp_seq_before(uint16_t seq, uint16_t cmp) { + return (int16_t)(seq - cmp) < 0; +} + +/* Return 1 if seq is after cmp */ +static inline int csp_rdp_seq_after(uint16_t seq, uint16_t cmp) { + return csp_rdp_seq_before(cmp, seq); +} + +/* Return 1 if time is between start and end (both inclusive) */ +static inline int csp_rdp_time_between(uint32_t time, uint32_t start, uint32_t end) { + return (uint32_t)(end - start) >= (uint32_t)(time - start); +} + +/* Return 1 if time is before cmp */ +static inline int csp_rdp_time_before(uint32_t time, uint32_t cmp) { + return (int32_t)(time - cmp) < 0; +} + +/* Return 1 if time is after cmp */ +static inline int csp_rdp_time_after(uint32_t time, uint32_t cmp) { + return csp_rdp_time_before(cmp, time); +} + +/** + * CONTROL MESSAGES + * The following function is used to send empty messages, + * with ACK, SYN or RST flag. + */ +static int csp_rdp_send_cmp(csp_conn_t * conn, csp_packet_t * packet, int flags, int seq_nr, int ack_nr) { + + csp_id_t idout; + + /* Generate message */ + if (!packet) { + packet = csp_buffer_get(20); + if (!packet) + return CSP_ERR_NOMEM; + packet->length = 0; + } + + /* Add RDP header */ + rdp_header_t * header = csp_rdp_header_add(packet); + header->seq_nr = csp_hton16(seq_nr); + header->ack_nr = csp_hton16(ack_nr); + header->ack = (flags & RDP_ACK) ? 1 : 0; + header->eak = (flags & RDP_EAK) ? 1 : 0; + header->syn = (flags & RDP_SYN) ? 1 : 0; + header->rst = (flags & RDP_RST) ? 1 : 0; + + /* Send copy to tx_queue, before sending packet to IF */ + if (flags & RDP_SYN) { + rdp_packet_t * rdp_packet = csp_buffer_clone(packet); + if (rdp_packet == NULL) return CSP_ERR_NOMEM; + rdp_packet->timestamp = csp_get_ms(); + if (csp_queue_enqueue(conn->rdp.tx_queue, &rdp_packet, 0) != CSP_QUEUE_OK) + csp_buffer_free(rdp_packet); + } + + /* Send control messages with high priority */ + idout = conn->idout; + idout.pri = conn->idout.pri < CSP_PRIO_HIGH ? conn->idout.pri : CSP_PRIO_HIGH; + + /* Send packet to IF */ + csp_iface_t * ifout = csp_rtable_find_iface(idout.dst); + if (csp_send_direct(idout, packet, ifout, 0) != CSP_ERR_NONE) { + csp_log_error("INTERFACE ERROR: not possible to send"); + csp_buffer_free(packet); + return CSP_ERR_BUSY; + } + + /* Update last ACK time stamp */ + if (flags & RDP_ACK) { + conn->rdp.rcv_lsa = ack_nr; + conn->rdp.ack_timestamp = csp_get_ms(); + } + + return CSP_ERR_NONE; + +} + +/** + * EXTENDED ACKNOWLEDGEMENTS + * The following function sends an extended ACK packet + */ +static int csp_rdp_send_eack(csp_conn_t * conn) { + + /* Allocate message */ + csp_packet_t * packet_eack = csp_buffer_get(100); + if (packet_eack == NULL) return CSP_ERR_NOMEM; + packet_eack->length = 0; + + /* Loop through RX queue */ + int i, count; + csp_packet_t * packet; + count = csp_queue_size(conn->rdp.rx_queue); + for (i = 0; i < count; i++) { + + if (csp_queue_dequeue_isr(conn->rdp.rx_queue, &packet, &pdTrue) != CSP_QUEUE_OK) { + csp_log_error("Cannot dequeue from rx_queue in queue deliver"); + break; + } + + /* Add seq nr to EACK packet */ + rdp_header_t * header = csp_rdp_header_ref(packet); + packet_eack->data16[packet_eack->length/sizeof(uint16_t)] = csp_hton16(header->seq_nr); + packet_eack->length += sizeof(uint16_t); + csp_log_protocol("Added EACK nr %u", header->seq_nr); + + /* Requeue */ + csp_queue_enqueue_isr(conn->rdp.rx_queue, &packet, &pdTrue); + + } + + return csp_rdp_send_cmp(conn, packet_eack, RDP_ACK | RDP_EAK, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + +} + + +/** + * SYN Packet + * The following function sends a SYN packet + */ +static int csp_rdp_send_syn(csp_conn_t * conn) { + + /* Allocate message */ + csp_packet_t * packet = csp_buffer_get(100); + if (packet == NULL) return CSP_ERR_NOMEM; + + /* Generate contents */ + packet->data32[0] = csp_hton32(csp_rdp_window_size); + packet->data32[1] = csp_hton32(csp_rdp_conn_timeout); + packet->data32[2] = csp_hton32(csp_rdp_packet_timeout); + packet->data32[3] = csp_hton32(csp_rdp_delayed_acks); + packet->data32[4] = csp_hton32(csp_rdp_ack_timeout); + packet->data32[5] = csp_hton32(csp_rdp_ack_delay_count); + packet->length = 6 * sizeof(uint32_t); + + return csp_rdp_send_cmp(conn, packet, RDP_SYN, conn->rdp.snd_iss, 0); + +} + +static inline int csp_rdp_receive_data(csp_conn_t * conn, csp_packet_t * packet) { + + /* Remove RDP header before passing to userspace */ + csp_rdp_header_remove(packet); + + /* Enqueue data */ + if (csp_conn_enqueue_packet(conn, packet) < 0) { + csp_log_warn("Conn RX buffer full"); + return CSP_ERR_NOBUFS; + } + + return CSP_ERR_NONE; + +} + +static inline void csp_rdp_rx_queue_flush(csp_conn_t * conn) { + + /* Loop through RX queue */ + int i, count; + csp_packet_t * packet; + +front: + count = csp_queue_size(conn->rdp.rx_queue); + for (i = 0; i < count; i++) { + + if (csp_queue_dequeue_isr(conn->rdp.rx_queue, &packet, &pdTrue) != CSP_QUEUE_OK) { + csp_log_error("Cannot dequeue from rx_queue in queue deliver"); + break; + } + + rdp_header_t * header = csp_rdp_header_ref(packet); + csp_log_protocol("RX Queue deliver matching Element, seq %u", header->seq_nr); + + /* If the matching packet was found: */ + if (header->seq_nr == (uint16_t)(conn->rdp.rcv_cur + 1)) { + csp_log_protocol("Deliver seq %u", header->seq_nr); + csp_rdp_receive_data(conn, packet); + conn->rdp.rcv_cur++; + /* Loop from first element again */ + goto front; + + /* Otherwise, requeue */ + } else { + csp_queue_enqueue_isr(conn->rdp.rx_queue, &packet, &pdTrue); + } + + } + +} + +static inline bool csp_rdp_seq_in_rx_queue(csp_conn_t * conn, uint16_t seq_nr) { + + /* Loop through RX queue */ + int i, count; + rdp_packet_t * packet; + count = csp_queue_size(conn->rdp.rx_queue); + for (i = 0; i < count; i++) { + + if (csp_queue_dequeue_isr(conn->rdp.rx_queue, &packet, &pdTrue) != CSP_QUEUE_OK) { + csp_log_error("Cannot dequeue from rx_queue in queue exists"); + break; + } + + csp_queue_enqueue_isr(conn->rdp.rx_queue, &packet, &pdTrue); + + rdp_header_t * header = csp_rdp_header_ref((csp_packet_t *) packet); + csp_log_protocol("RX Queue exists matching Element, seq %u", header->seq_nr); + + /* If the matching packet was found, deliver */ + if (header->seq_nr == seq_nr) { + csp_log_protocol("We have a match"); + return true; + } + + } + + return false; + +} + +static inline int csp_rdp_rx_queue_add(csp_conn_t * conn, csp_packet_t * packet, uint16_t seq_nr) { + + if (csp_rdp_seq_in_rx_queue(conn, seq_nr)) + return CSP_QUEUE_ERROR; + return csp_queue_enqueue_isr(conn->rdp.rx_queue, &packet, &pdTrue); + +} + +static void csp_rdp_flush_eack(csp_conn_t * conn, csp_packet_t * eack_packet) { + + /* Loop through TX queue */ + int i, j, count; + rdp_packet_t * packet; + count = csp_queue_size(conn->rdp.tx_queue); + for (i = 0; i < count; i++) { + + if (csp_queue_dequeue(conn->rdp.tx_queue, &packet, 0) != CSP_QUEUE_OK) { + csp_log_error("Cannot dequeue from tx_queue in flush EACK"); + break; + } + + rdp_header_t * header = csp_rdp_header_ref((csp_packet_t *) packet); + csp_log_protocol("EACK compare element, time %u, seq %u", packet->timestamp, csp_ntoh16(header->seq_nr)); + + /* Look for this element in EACKs */ + int match = 0; + for (j = 0; j < (int)((eack_packet->length - sizeof(rdp_header_t)) / sizeof(uint16_t)); j++) { + if (csp_ntoh16(eack_packet->data16[j]) == csp_ntoh16(header->seq_nr)) + match = 1; + + /* Enable this if you want EACK's to trigger retransmission */ + if (csp_ntoh16(eack_packet->data16[j]) > csp_ntoh16(header->seq_nr)) { + uint32_t time_now = csp_get_ms(); + if (csp_rdp_time_after(time_now, packet->quarantine)) { + packet->timestamp = time_now - conn->rdp.packet_timeout - 1; + packet->quarantine = time_now + conn->rdp.packet_timeout / 2; + } + } + } + + if (match == 0) { + /* If not found, put back on tx queue */ + csp_queue_enqueue(conn->rdp.tx_queue, &packet, 0); + } else { + /* Found, free */ + csp_log_protocol("TX Element %u freed", csp_ntoh16(header->seq_nr)); + csp_buffer_free(packet); + } + + } + +} + +static inline bool csp_rdp_should_ack(csp_conn_t * conn) { + + /* If delayed ACKs are not used, always ACK */ + if (!conn->rdp.delayed_acks) { + return true; + } + + /* ACK if time since last ACK is greater than ACK timeout */ + uint32_t time_now = csp_get_ms(); + if (csp_rdp_time_after(time_now, conn->rdp.ack_timestamp + conn->rdp.ack_timeout)) + return true; + + /* ACK if number of unacknowledged packets is greater than delay count */ + if (csp_rdp_seq_after(conn->rdp.rcv_cur, conn->rdp.rcv_lsa + conn->rdp.ack_delay_count)) + return true; + + return false; + +} + +void csp_rdp_flush_all(csp_conn_t * conn) { + + if ((conn == NULL) || conn->rdp.tx_queue == NULL) { + csp_log_error("Null pointer passed to rdp flush all"); + return; + } + + rdp_packet_t * packet; + + /* Empty TX queue */ + while (csp_queue_dequeue_isr(conn->rdp.tx_queue, &packet, &pdTrue) == CSP_QUEUE_OK) { + if (packet != NULL) { + csp_log_protocol("RDP %p: Flush TX Element, time %u, seq %u", conn, packet->timestamp, csp_ntoh16(csp_rdp_header_ref((csp_packet_t *) packet)->seq_nr)); + csp_buffer_free(packet); + } + } + + /* Empty RX queue */ + while (csp_queue_dequeue_isr(conn->rdp.rx_queue, &packet, &pdTrue) == CSP_QUEUE_OK) { + if (packet != NULL) { + csp_log_protocol("RDP %p: Flush RX Element, time %u, seq %u", conn, packet->timestamp, csp_ntoh16(csp_rdp_header_ref((csp_packet_t *) packet)->seq_nr)); + csp_buffer_free(packet); + } + } + +} + + +int csp_rdp_check_ack(csp_conn_t * conn) { + + /* Check all RX queues for spare capacity */ + int prio, avail = 1; + for (prio = 0; prio < CSP_RX_QUEUES; prio++) { + if (CSP_RX_QUEUE_LENGTH - csp_queue_size(conn->rx_queue[prio]) <= 2 * (int32_t)conn->rdp.window_size) { + avail = 0; + break; + } + } + + /* If more space available, only send after ack timeout or immediately if delay_acks is zero */ + if (avail && csp_rdp_should_ack(conn)) + csp_rdp_send_cmp(conn, NULL, RDP_ACK, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + + return CSP_ERR_NONE; + +} + +static inline bool csp_rdp_is_conn_ready_for_tx(csp_conn_t * conn) +{ + // Check Tx window (messages waiting for acks) + if (csp_rdp_seq_after(conn->rdp.snd_nxt, conn->rdp.snd_una + conn->rdp.window_size - 1)) { + return false; + } + return true; +} + +/** + * This function must be called with regular intervals for the + * RDP protocol to work as expected. This takes care of closing + * stale connections and retransmitting traffic. A good place to + * call this function is from the CSP router task. + */ +void csp_rdp_check_timeouts(csp_conn_t * conn) { + + rdp_packet_t * packet; + + /** + * CONNECTION TIMEOUT: + * Check that connection has not timed out inside the network stack + * */ + uint32_t time_now = csp_get_ms(); + if (conn->socket != NULL) { + if (csp_rdp_time_after(time_now, conn->timestamp + conn->rdp.conn_timeout)) { + csp_log_warn("RDP %p: Found a lost connection (now: %u, ts: %u, to: %u), closing now", + conn, time_now, conn->timestamp, conn->rdp.conn_timeout); + csp_close(conn); + return; + } + } + + /** + * CLOSE-WAIT TIMEOUT: + * After waiting a while in CLOSE-WAIT, the connection should be closed. + */ + if (conn->rdp.state == RDP_CLOSE_WAIT) { + if (csp_rdp_time_after(time_now, conn->timestamp + conn->rdp.conn_timeout)) { + csp_log_protocol("RDP %p: CLOSE_WAIT timeout", conn); + csp_close(conn); + } + return; + } + + /** + * MESSAGE TIMEOUT: + * Check each outgoing message for TX timeout + */ + int i, count; + count = csp_queue_size(conn->rdp.tx_queue); + for (i = 0; i < count; i++) { + + if ((csp_queue_dequeue_isr(conn->rdp.tx_queue, &packet, &pdTrue) != CSP_QUEUE_OK) || packet == NULL) { + csp_log_warn("Cannot dequeue from tx_queue in check timeout"); + break; + } + + /* Get header */ + rdp_header_t * header = csp_rdp_header_ref((csp_packet_t *) packet); + + /* If acked, do not retransmit */ + if (csp_rdp_seq_before(csp_ntoh16(header->seq_nr), conn->rdp.snd_una)) { + csp_log_protocol("TX Element Free, time %u, seq %u, una %u", packet->timestamp, csp_ntoh16(header->seq_nr), conn->rdp.snd_una); + csp_buffer_free(packet); + continue; + } + + /* Check timestamp and retransmit if needed */ + if (csp_rdp_time_after(time_now, packet->timestamp + conn->rdp.packet_timeout)) { + csp_log_protocol("TX Element timed out, retransmitting seq %u", csp_ntoh16(header->seq_nr)); + + /* Update to latest outgoing ACK */ + header->ack_nr = csp_hton16(conn->rdp.rcv_cur); + + /* Send copy to tx_queue */ + packet->timestamp = csp_get_ms(); + csp_packet_t * new_packet = csp_buffer_clone(packet); + csp_iface_t * ifout = csp_rtable_find_iface(conn->idout.dst); + if (csp_send_direct(conn->idout, new_packet, ifout, 0) != CSP_ERR_NONE) { + csp_log_warn("Retransmission failed"); + csp_buffer_free(new_packet); + } + + } + + /* Requeue the TX element */ + csp_queue_enqueue_isr(conn->rdp.tx_queue, &packet, &pdTrue); + + } + + /** + * ACK TIMEOUT: + * Check ACK timeouts, if we have unacknowledged segments + */ + if (conn->rdp.delayed_acks) { + csp_rdp_check_ack(conn); + } + + /* Wake user task if connection is open and additional Tx can be done */ + if ((conn->rdp.state == RDP_OPEN) && csp_rdp_is_conn_ready_for_tx(conn)) { + csp_log_protocol("RDP %p: Wake Tx task (check timeouts)", conn); + csp_bin_sem_post(&conn->rdp.tx_wait); + } +} + +void csp_rdp_new_packet(csp_conn_t * conn, csp_packet_t * packet) { + + /* Get RX header and convert to host byte-order */ + rdp_header_t * rx_header = csp_rdp_header_ref(packet); + rx_header->ack_nr = csp_ntoh16(rx_header->ack_nr); + rx_header->seq_nr = csp_ntoh16(rx_header->seq_nr); + + csp_log_protocol("RDP %p: Received in S %u: syn %u, ack %u, eack %u, " + "rst %u, seq_nr %5u, ack_nr %5u, packet_len %u (%u)", + conn, conn->rdp.state, rx_header->syn, rx_header->ack, rx_header->eak, + rx_header->rst, rx_header->seq_nr, rx_header->ack_nr, + packet->length, packet->length - sizeof(rdp_header_t)); + + /* If a RESET was received. */ + if (rx_header->rst) { + + if (rx_header->ack) { + /* Store current ack'ed sequence number */ + conn->rdp.snd_una = rx_header->ack_nr + 1; + } + + if (conn->rdp.state == RDP_CLOSE_WAIT || conn->rdp.state == RDP_CLOSED) { + csp_log_protocol("RDP %p: RST received in CLOSE_WAIT or CLOSED. Now closing connection", conn); + goto discard_close; + } else { + csp_log_protocol("RDP %p: Got RESET in state %u", conn, conn->rdp.state); + + if (rx_header->seq_nr == (uint16_t)(conn->rdp.rcv_cur + 1)) { + csp_log_protocol("RDP %p: RESET in sequence, no more data incoming, reply with RESET", conn); + conn->rdp.state = RDP_CLOSE_WAIT; + conn->timestamp = csp_get_ms(); + csp_rdp_send_cmp(conn, NULL, RDP_ACK | RDP_RST, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + goto discard_close; + } else { + csp_log_protocol("RDP %p: RESET out of sequence, keep connection open", conn); + goto discard_open; + } + } + } + + /* The BIG FAT switch (state-machine) */ + switch(conn->rdp.state) { + + /** + * STATE == CLOSED + */ + case RDP_CLOSED: { + + /* No SYN flag set while in closed. Inform by sending back RST */ + if (!rx_header->syn) { + csp_log_protocol("Not SYN received in CLOSED state. Discarding packet"); + csp_rdp_send_cmp(conn, NULL, RDP_RST, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + goto discard_close; + } + + csp_log_protocol("RDP: SYN-Received"); + + /* Setup TX seq. */ + conn->rdp.snd_iss = (uint16_t)rand(); + conn->rdp.snd_nxt = conn->rdp.snd_iss + 1; + conn->rdp.snd_una = conn->rdp.snd_iss; + + /* Store RX seq. */ + conn->rdp.rcv_cur = rx_header->seq_nr; + conn->rdp.rcv_irs = rx_header->seq_nr; + conn->rdp.rcv_lsa = rx_header->seq_nr; + + /* Store RDP options */ + conn->rdp.window_size = csp_ntoh32(packet->data32[0]); + conn->rdp.conn_timeout = csp_ntoh32(packet->data32[1]); + conn->rdp.packet_timeout = csp_ntoh32(packet->data32[2]); + conn->rdp.delayed_acks = csp_ntoh32(packet->data32[3]); + conn->rdp.ack_timeout = csp_ntoh32(packet->data32[4]); + conn->rdp.ack_delay_count = csp_ntoh32(packet->data32[5]); + csp_log_protocol("RDP: Window Size %u, conn timeout %u, packet timeout %u", + conn->rdp.window_size, conn->rdp.conn_timeout, conn->rdp.packet_timeout); + csp_log_protocol("RDP: Delayed acks: %u, ack timeout %u, ack each %u packet", + conn->rdp.delayed_acks, conn->rdp.ack_timeout, conn->rdp.ack_delay_count); + + /* Connection accepted */ + conn->rdp.state = RDP_SYN_RCVD; + + /* Send SYN/ACK */ + csp_rdp_send_cmp(conn, NULL, RDP_ACK | RDP_SYN, conn->rdp.snd_iss, conn->rdp.rcv_irs); + + goto discard_open; + + } + break; + + /** + * STATE == SYN-SENT + */ + case RDP_SYN_SENT: { + + /* First check SYN/ACK */ + if (rx_header->syn && rx_header->ack) { + + conn->rdp.rcv_cur = rx_header->seq_nr; + conn->rdp.rcv_irs = rx_header->seq_nr; + conn->rdp.rcv_lsa = rx_header->seq_nr - 1; + conn->rdp.snd_una = rx_header->ack_nr + 1; + conn->rdp.ack_timestamp = csp_get_ms(); + conn->rdp.state = RDP_OPEN; + + csp_log_protocol("RDP: NP: Connection OPEN"); + + /* Send ACK */ + csp_rdp_send_cmp(conn, NULL, RDP_ACK, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + + /* Wake TX task */ + csp_log_protocol("RDP %p: Wake Tx task (ack)", conn); + csp_bin_sem_post(&conn->rdp.tx_wait); + + goto discard_open; + } + + /* If there was no SYN in the reply, our SYN message hit an already open connection + * This is handled by sending a RST. + * Normally this would be followed up by a new connection attempt, however + * we don't have a method for signaling this to the user space. + */ + if (rx_header->ack) { + csp_log_error("Half-open connection found, sending RST"); + csp_rdp_send_cmp(conn, NULL, RDP_RST, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + csp_log_protocol("RDP %p: Wake Tx task (rst)", conn); + csp_bin_sem_post(&conn->rdp.tx_wait); + + goto discard_open; + } + + /* Otherwise we have an invalid command, such as a SYN reply to a SYN command, + * indicating simultaneous connections, which is not possible in the way CSP + * reserves some ports for server and some for clients. + */ + csp_log_error("Invalid reply to SYN request"); + goto discard_close; + + } + break; + + /** + * STATE == OPEN + */ + case RDP_SYN_RCVD: + case RDP_OPEN: + { + + /* SYN or !ACK is invalid */ + if (rx_header->syn || !rx_header->ack) { + if (rx_header->seq_nr != conn->rdp.rcv_irs) { + csp_log_error("Invalid SYN or no ACK, resetting!"); + goto discard_close; + } else { + csp_log_protocol("Ignoring duplicate SYN packet!"); + goto discard_open; + } + } + + /* Check sequence number */ + if (!csp_rdp_seq_between(rx_header->seq_nr, conn->rdp.rcv_cur + 1, conn->rdp.rcv_cur + conn->rdp.window_size * 2)) { + csp_log_protocol("Invalid sequence number! %"PRIu16" not between %"PRIu16" and %"PRIu16, + rx_header->seq_nr, conn->rdp.rcv_cur + 1, conn->rdp.rcv_cur + 1 + conn->rdp.window_size * 2); + /* If duplicate SYN received, send another SYN/ACK */ + if (conn->rdp.state == RDP_SYN_RCVD) + csp_rdp_send_cmp(conn, NULL, RDP_ACK | RDP_SYN, conn->rdp.snd_iss, conn->rdp.rcv_irs); + /* If duplicate data packet received, send EACK back */ + if (conn->rdp.state == RDP_OPEN) + csp_rdp_send_eack(conn); + + goto discard_open; + } + + /* Check ACK number */ + if (!csp_rdp_seq_between(rx_header->ack_nr, conn->rdp.snd_una - 1 - (conn->rdp.window_size * 2), conn->rdp.snd_nxt - 1)) { + csp_log_error("Invalid ACK number! %u not between %u and %u", + rx_header->ack_nr, conn->rdp.snd_una - 1 - (conn->rdp.window_size * 2), conn->rdp.snd_nxt - 1); + goto discard_open; + } + + /* Check SYN_RCVD ACK */ + if (conn->rdp.state == RDP_SYN_RCVD) { + if (rx_header->ack_nr != conn->rdp.snd_iss) { + csp_log_error("SYN-RCVD: Wrong ACK number"); + goto discard_close; + } + csp_log_protocol("RDP: NC: Connection OPEN"); + conn->rdp.state = RDP_OPEN; + + /* If a socket is set, this message is the first in a new connection + * so the connection must be queued to the socket. */ + if (conn->socket != NULL) { + + /* Try queueing */ + if (csp_queue_enqueue(conn->socket, &conn, 0) == CSP_QUEUE_FULL) { + csp_log_error("ERROR socket cannot accept more connections"); + goto discard_close; + } + + /* Ensure that this connection will not be posted to this socket again + * and remember that the connection handle has been passed to userspace + * by setting the socket = NULL */ + conn->socket = NULL; + } + + } + + /* Store current ack'ed sequence number */ + conn->rdp.snd_una = rx_header->ack_nr + 1; + + /* We have an EACK */ + if (rx_header->eak) { + if (packet->length > sizeof(rdp_header_t)) + csp_rdp_flush_eack(conn, packet); + goto discard_open; + } + + /* If no data, return here */ + if (packet->length <= sizeof(rdp_header_t)) + goto discard_open; + + /* If message is not in sequence, send EACK and store packet */ + if (rx_header->seq_nr != (uint16_t)(conn->rdp.rcv_cur + 1)) { + if (csp_rdp_rx_queue_add(conn, packet, rx_header->seq_nr) != CSP_QUEUE_OK) { + csp_log_protocol("Duplicate sequence number"); + csp_rdp_check_ack(conn); + goto discard_open; + } + csp_rdp_send_eack(conn); + goto accepted_open; + } + + /* Store sequence number before stripping RDP header */ + uint16_t seq_nr = rx_header->seq_nr; + + /* Receive data */ + if (csp_rdp_receive_data(conn, packet) != CSP_ERR_NONE) + goto discard_open; + + /* Update last received packet */ + conn->rdp.rcv_cur = seq_nr; + + /* Only ACK the message if there is room for a full window in the RX buffer. + * Unacknowledged segments are ACKed by csp_rdp_check_timeouts when the buffer is + * no longer full. */ + csp_rdp_check_ack(conn); + + /* Flush RX queue */ + csp_rdp_rx_queue_flush(conn); + + goto accepted_open; + + } + break; + + case RDP_CLOSE_WAIT: + + /* Ignore SYN or !ACK */ + if (rx_header->syn || !rx_header->ack) { + csp_log_protocol("Invalid SYN or no ACK in CLOSE-WAIT"); + goto discard_open; + } + + /* Check ACK number */ + if (!csp_rdp_seq_between(rx_header->ack_nr, conn->rdp.snd_una - 1 - (conn->rdp.window_size * 2), conn->rdp.snd_nxt - 1)) { + csp_log_error("Invalid ACK number! %u not between %u and %u", + rx_header->ack_nr, conn->rdp.snd_una - 1 - (conn->rdp.window_size * 2), conn->rdp.snd_nxt - 1); + goto discard_open; + } + + /* Store current ack'ed sequence number */ + conn->rdp.snd_una = rx_header->ack_nr + 1; + + /* Send back a reset */ + csp_rdp_send_cmp(conn, NULL, RDP_ACK | RDP_RST, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + + goto discard_open; + + default: + csp_log_error("RDP: ERROR default state!"); + goto discard_close; + } + +discard_close: + /* If user-space has received the connection handle, wake it up, + * by sending a NULL pointer, user-space should close connection */ + if (conn->socket == NULL) { + csp_log_protocol("RDP %p: Waiting for userspace to close", conn); + csp_conn_enqueue_packet(conn, NULL); + } else { + csp_close(conn); + } + +discard_open: + csp_buffer_free(packet); +accepted_open: + return; + +} + +int csp_rdp_connect(csp_conn_t * conn, uint32_t timeout) { + + int retry = 1; + + conn->rdp.window_size = csp_rdp_window_size; + conn->rdp.conn_timeout = csp_rdp_conn_timeout; + conn->rdp.packet_timeout = csp_rdp_packet_timeout; + conn->rdp.delayed_acks = csp_rdp_delayed_acks; + conn->rdp.ack_timeout = csp_rdp_ack_timeout; + conn->rdp.ack_delay_count = csp_rdp_ack_delay_count; + conn->rdp.ack_timestamp = csp_get_ms(); + +retry: + csp_log_protocol("RDP %p: Active connect, conn state %u", conn, conn->rdp.state); + + if (conn->rdp.state == RDP_OPEN) { + csp_log_error("RDP %p: Connection already open", conn); + return CSP_ERR_ALREADY; + } + + /* Randomize ISS */ + conn->rdp.snd_iss = (uint16_t)rand(); + + conn->rdp.snd_nxt = conn->rdp.snd_iss + 1; + conn->rdp.snd_una = conn->rdp.snd_iss; + + csp_log_protocol("RDP %p: AC: Sending SYN", conn); + + /* Ensure semaphore is busy, so router task can release it */ + csp_bin_sem_wait(&conn->rdp.tx_wait, 0); + + /* Send SYN message */ + conn->rdp.state = RDP_SYN_SENT; + if (csp_rdp_send_syn(conn) != CSP_ERR_NONE) + goto error; + + /* Wait for router task to release semaphore */ + csp_log_protocol("RDP %p: AC: Waiting for SYN/ACK reply...", conn); + int result = csp_bin_sem_wait(&conn->rdp.tx_wait, conn->rdp.conn_timeout); + + if (result == CSP_SEMAPHORE_OK) { + if (conn->rdp.state == RDP_OPEN) { + csp_log_protocol("RDP %p: AC: Connection OPEN", conn); + return CSP_ERR_NONE; + } else if(conn->rdp.state == RDP_SYN_SENT) { + if (retry) { + csp_log_warn("RDP %p: Half-open connection detected, RST sent, now retrying", conn); + csp_rdp_flush_all(conn); + retry = 0; + goto retry; + } else { + csp_log_error("RDP %p: Connection stayed half-open, even after RST and retry!", conn); + goto error; + } + } + } else { + csp_log_protocol("RDP %p: AC: Connection Failed", conn); + goto error; + } + +error: + conn->rdp.state = RDP_CLOSE_WAIT; + return CSP_ERR_TIMEDOUT; + +} + +int csp_rdp_send(csp_conn_t * conn, csp_packet_t * packet, uint32_t timeout) { + + if (conn->rdp.state != RDP_OPEN) { + csp_log_error("RDP: ERROR cannot send, connection reset"); + return CSP_ERR_RESET; + } + + while ((conn->rdp.state == RDP_OPEN) && (csp_rdp_is_conn_ready_for_tx(conn) == false)) { + csp_log_protocol("RDP %p: Waiting for window update before sending seq %u", conn, conn->rdp.snd_nxt); + if ((csp_bin_sem_wait(&conn->rdp.tx_wait, conn->rdp.conn_timeout)) != CSP_SEMAPHORE_OK) { + csp_log_error("RDP %p: Timeout during send", conn); + return CSP_ERR_TIMEDOUT; + } + } + + if (conn->rdp.state != RDP_OPEN) { + csp_log_error("RDP: ERROR cannot send, connection reset"); + return CSP_ERR_RESET; + } + + /* Add RDP header */ + rdp_header_t * tx_header = csp_rdp_header_add(packet); + tx_header->ack_nr = csp_hton16(conn->rdp.rcv_cur); + tx_header->seq_nr = csp_hton16(conn->rdp.snd_nxt); + tx_header->ack = 1; + + /* Send copy to tx_queue */ + rdp_packet_t * rdp_packet = csp_buffer_clone(packet); + if (rdp_packet == NULL) { + csp_log_error("Failed to allocate packet buffer"); + return CSP_ERR_NOMEM; + } + + rdp_packet->timestamp = csp_get_ms(); + rdp_packet->quarantine = 0; + if (csp_queue_enqueue(conn->rdp.tx_queue, &rdp_packet, 0) != CSP_QUEUE_OK) { + csp_log_error("No more space in RDP retransmit queue"); + csp_buffer_free(rdp_packet); + return CSP_ERR_NOBUFS; + } + + csp_log_protocol("RDP: Sending in S %u: syn %u, ack %u, eack %u, " + "rst %u, seq_nr %5u, ack_nr %5u, packet_len %u (%u)", + conn->rdp.state, tx_header->syn, tx_header->ack, tx_header->eak, + tx_header->rst, csp_ntoh16(tx_header->seq_nr), csp_ntoh16(tx_header->ack_nr), + packet->length, packet->length - sizeof(rdp_header_t)); + + conn->rdp.snd_nxt++; + return CSP_ERR_NONE; + +} + +int csp_rdp_allocate(csp_conn_t * conn) { + + csp_log_protocol("RDP: Creating RDP queues for conn %p", conn); + + /* Set initial state */ + conn->rdp.state = RDP_CLOSED; + conn->rdp.conn_timeout = csp_rdp_conn_timeout; + conn->rdp.packet_timeout = csp_rdp_packet_timeout; + + /* Create a binary semaphore to wait on for tasks */ + if (csp_bin_sem_create(&conn->rdp.tx_wait) != CSP_SEMAPHORE_OK) { + csp_log_error("Failed to initialize semaphore"); + return CSP_ERR_NOMEM; + } + + /* Create TX queue */ + conn->rdp.tx_queue = csp_queue_create(CSP_RDP_MAX_WINDOW, sizeof(csp_packet_t *)); + if (conn->rdp.tx_queue == NULL) { + csp_log_error("Failed to create TX queue for conn"); + csp_bin_sem_remove(&conn->rdp.tx_wait); + return CSP_ERR_NOMEM; + } + + /* Create RX queue */ + conn->rdp.rx_queue = csp_queue_create(CSP_RDP_MAX_WINDOW * 2, sizeof(csp_packet_t *)); + if (conn->rdp.rx_queue == NULL) { + csp_log_error("Failed to create RX queue for conn"); + csp_bin_sem_remove(&conn->rdp.tx_wait); + csp_queue_remove(conn->rdp.tx_queue); + return CSP_ERR_NOMEM; + } + + return CSP_ERR_NONE; + +} + +/** + * @note This function may only be called from csp_close, and is therefore + * without any checks for null pointers. + */ +int csp_rdp_close(csp_conn_t * conn) { + + if (conn->rdp.state == RDP_CLOSED) + return CSP_ERR_NONE; + + /* If message is open, send reset */ + if (conn->rdp.state != RDP_CLOSE_WAIT) { + conn->rdp.state = RDP_CLOSE_WAIT; + conn->timestamp = csp_get_ms(); + csp_rdp_send_cmp(conn, NULL, RDP_ACK | RDP_RST, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + csp_log_protocol("RDP %p: Close, sent RST", conn); + csp_bin_sem_post(&conn->rdp.tx_wait); // wake up any pendng Tx + return CSP_ERR_AGAIN; + } + + csp_log_protocol("RDP %p: Close in CLOSE_WAIT, now closing", conn); + conn->rdp.state = RDP_CLOSED; + return CSP_ERR_NONE; + +} + +/** + * RDP Set socket options + * Controls important parameters of the RDP protocol. + * These settings will be applied to all new outgoing connections. + * The settings are global, so be sure no other task are conflicting with your settings. + */ +void csp_rdp_set_opt(unsigned int window_size, unsigned int conn_timeout_ms, + unsigned int packet_timeout_ms, unsigned int delayed_acks, + unsigned int ack_timeout, unsigned int ack_delay_count) { + csp_rdp_window_size = window_size; + csp_rdp_conn_timeout = conn_timeout_ms; + csp_rdp_packet_timeout = packet_timeout_ms; + csp_rdp_delayed_acks = delayed_acks; + csp_rdp_ack_timeout = ack_timeout; + csp_rdp_ack_delay_count = ack_delay_count; +} + +void csp_rdp_get_opt(unsigned int * window_size, unsigned int * conn_timeout_ms, + unsigned int * packet_timeout_ms, unsigned int * delayed_acks, + unsigned int * ack_timeout, unsigned int * ack_delay_count) { + + if (window_size) + *window_size = csp_rdp_window_size; + if (conn_timeout_ms) + *conn_timeout_ms = csp_rdp_conn_timeout; + if (packet_timeout_ms) + *packet_timeout_ms = csp_rdp_packet_timeout; + if (delayed_acks) + *delayed_acks = csp_rdp_delayed_acks; + if (ack_timeout) + *ack_timeout = csp_rdp_ack_timeout; + if (ack_delay_count) + *ack_delay_count = csp_rdp_ack_delay_count; +} + +#ifdef CSP_DEBUG +void csp_rdp_conn_print(csp_conn_t * conn) { + + if (conn == NULL) + return; + + printf("\tRDP: State %"PRIu16", rcv %"PRIu16", snd %"PRIu16", win %"PRIu32"\r\n", + conn->rdp.state, conn->rdp.rcv_cur, conn->rdp.snd_una, conn->rdp.window_size); + +} +#endif + +#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/transport/csp_transport.h b/gomspace/libgscsp/lib/libcsp/src/transport/csp_transport.h new file mode 100644 index 00000000..7fcda3dc --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/transport/csp_transport.h @@ -0,0 +1,46 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_TRANSPORT_H_ +#define _CSP_TRANSPORT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** ARRIVING SEGMENT */ +void csp_udp_new_packet(csp_conn_t * conn, csp_packet_t * packet); +void csp_rdp_new_packet(csp_conn_t * conn, csp_packet_t * packet); + +/** RDP: USER REQUESTS */ +int csp_rdp_connect(csp_conn_t * conn, uint32_t timeout); +int csp_rdp_allocate(csp_conn_t * conn); +int csp_rdp_close(csp_conn_t * conn); +void csp_rdp_conn_print(csp_conn_t * conn); +int csp_rdp_send(csp_conn_t * conn, csp_packet_t * packet, uint32_t timeout); +int csp_rdp_check_ack(csp_conn_t * conn); +void csp_rdp_check_timeouts(csp_conn_t * conn); +void csp_rdp_flush_all(csp_conn_t * conn); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CSP_TRANSPORT_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/transport/csp_udp.c b/gomspace/libgscsp/lib/libcsp/src/transport/csp_udp.c new file mode 100644 index 00000000..61732703 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/transport/csp_udp.c @@ -0,0 +1,49 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include "../csp_port.h" +#include "../csp_conn.h" +#include "csp_transport.h" + +void csp_udp_new_packet(csp_conn_t * conn, csp_packet_t * packet) { + + /* Enqueue */ + if (csp_conn_enqueue_packet(conn, packet) < 0) { + csp_log_error("Connection buffer queue full!"); + csp_buffer_free(packet); + return; + } + + /* Try to queue up the new connection pointer */ + if (conn->socket != NULL) { + if (csp_queue_enqueue(conn->socket, &conn, 0) != CSP_QUEUE_OK) { + csp_log_warn("Warning socket connection queue full"); + csp_close(conn); + return; + } + + /* Ensure that this connection will not be posted to this socket again */ + conn->socket = NULL; + } + +} + diff --git a/gomspace/libgscsp/lib/libcsp/utils/cfpsplit.py b/gomspace/libgscsp/lib/libcsp/utils/cfpsplit.py new file mode 100644 index 00000000..9a350e3e --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/utils/cfpsplit.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python + +# Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +# Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +# Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +# Split CFP header in protocol fields + +import sys + +def usage(): + print("usage: cfpsplit.py HEADER") + +def main(): + try: + hdr = sys.argv[1] + except: + usage() + sys.exit(-1) + + try: + hdrhex = int(hdr, 16) + except: + print("HEADER must be in hexadecimal format") + sys.exit(-1) + + if hdrhex > 0x1fffffff: + print("HEADER is not a valid CFP header") + sys.exit(-1) + + print("Source: {0}".format((hdrhex >> 24) & 0x1f)) + print("Destination: {0}".format((hdrhex >> 19) & 0x1f)) + print("Type: {0}".format("MORE" if ((hdrhex >> 18) & 0x01) else "BEGIN")) + print("Remain: {0}".format((hdrhex >> 10) & 0xff)) + print("Identifier: {0}".format((hdrhex >> 0) & 0x3ff)) + +if __name__ == "__main__": + main() diff --git a/gomspace/libgscsp/lib/libcsp/utils/cspsplit.py b/gomspace/libgscsp/lib/libcsp/utils/cspsplit.py new file mode 100644 index 00000000..f4ed942f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/utils/cspsplit.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python + +# Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +# Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +# Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +# Split CSP header in protocol fields + +import sys + +def usage(): + print("usage: cspsplit.py HEADER") + +def main(): + try: + hdr = sys.argv[1] + except: + usage() + sys.exit(-1) + + try: + hdrhex = int(hdr, 16) + except: + print("HEADER must be in hexadecimal format") + sys.exit(-1) + + print("Priotity: {0}".format((hdrhex >> 30) & 0x03)) + print("Source: {0}".format((hdrhex >> 25) & 0x1f)) + print("Destination: {0}".format((hdrhex >> 20) & 0x1f)) + print("Destination port: {0}".format((hdrhex >> 14) & 0x3f)) + print("Source port: {0}".format((hdrhex >> 8) & 0x3f)) + print("HMAC: {0}".format("Yes" if ((hdrhex >> 3) & 0x01) else "No")) + print("XTEA: {0}".format("Yes" if ((hdrhex >> 2) & 0x01) else "No")) + print("RDP: {0}".format("Yes" if ((hdrhex >> 1) & 0x01) else "No")) + print("CRC32: {0}".format("Yes" if ((hdrhex >> 0) & 0x01) else "No")) + +if __name__ == "__main__": + main() diff --git a/gomspace/libgscsp/lib/libcsp/waf b/gomspace/libgscsp/lib/libcsp/waf new file mode 100644 index 00000000..4b322f1a --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/waf @@ -0,0 +1,170 @@ +#!/usr/bin/env python +# encoding: ISO8859-1 +# Thomas Nagy, 2005-2016 + +""" +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. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 AUTHOR 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. +""" + +import os, sys, inspect + +VERSION="1.8.19" +REVISION="b1fc8f7baef51bd2db4c2971909a568d" +GIT="22213cd8abbd141bda40667f7ca2a48f2d6ad785" +INSTALL='' +C1='#5' +C2='#/' +C3='#,' +cwd = os.getcwd() +join = os.path.join + + +WAF='waf' +def b(x): + return x +if sys.hexversion>0x300000f: + WAF='waf3' + def b(x): + return x.encode() + +def err(m): + print(('\033[91mError: %s\033[0m' % m)) + sys.exit(1) + +def unpack_wafdir(dir, src): + f = open(src,'rb') + c = 'corrupt archive (%d)' + while 1: + line = f.readline() + if not line: err('run waf-light from a folder containing waflib') + if line == b('#==>\n'): + txt = f.readline() + if not txt: err(c % 1) + if f.readline() != b('#<==\n'): err(c % 2) + break + if not txt: err(c % 3) + txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r')).replace(b(C3), b('\x00')) + + import shutil, tarfile + try: shutil.rmtree(dir) + except OSError: pass + try: + for x in ('Tools', 'extras'): + os.makedirs(join(dir, 'waflib', x)) + except OSError: + err("Cannot unpack waf lib into %s\nMove waf in a writable directory" % dir) + + os.chdir(dir) + tmp = 't.bz2' + t = open(tmp,'wb') + try: t.write(txt) + finally: t.close() + + try: + t = tarfile.open(tmp) + except: + try: + os.system('bunzip2 t.bz2') + t = tarfile.open('t') + tmp = 't' + except: + os.chdir(cwd) + try: shutil.rmtree(dir) + except OSError: pass + err("Waf cannot be unpacked, check that bzip2 support is present") + + try: + for x in t: t.extract(x) + finally: + t.close() + + for x in ('Tools', 'extras'): + os.chmod(join('waflib',x), 493) + + if sys.hexversion<0x300000f: + sys.path = [join(dir, 'waflib')] + sys.path + import fixpy2 + fixpy2.fixdir(dir) + + os.remove(tmp) + os.chdir(cwd) + + try: dir = unicode(dir, 'mbcs') + except: pass + try: + from ctypes import windll + windll.kernel32.SetFileAttributesW(dir, 2) + except: + pass + +def test(dir): + try: + os.stat(join(dir, 'waflib')) + return os.path.abspath(dir) + except OSError: + pass + +def find_lib(): + src = os.path.abspath(inspect.getfile(inspect.getmodule(err))) + base, name = os.path.split(src) + + #devs use $WAFDIR + w=test(os.environ.get('WAFDIR', '')) + if w: return w + + #waf-light + if name.endswith('waf-light'): + w = test(base) + if w: return w + err('waf-light requires waflib -> export WAFDIR=/folder') + + dirname = '%s-%s-%s' % (WAF, VERSION, REVISION) + for i in (INSTALL,'/usr','/usr/local','/opt'): + w = test(i + '/lib/' + dirname) + if w: return w + + #waf-local + dir = join(base, (sys.platform != 'win32' and '.' or '') + dirname) + w = test(dir) + if w: return w + + #unpack + unpack_wafdir(dir, src) + return dir + +wafdir = find_lib() +sys.path.insert(0, wafdir) + +if __name__ == '__main__': + + from waflib import Scripting + Scripting.waf_entry_point(cwd, VERSION, wafdir) + +#==> +#BZh91AY&SYmEõKQ#/ÿÿÿ°#,Óÿÿÿÿÿÿÿÿÿÿÿ„ Y Â#%H4#,`(bÜrû}Ñ#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,ÕÓ­ul]ZåÍë}i{l4­´ï±®í_pÝlkLϱ÷dzvúݺ{¾]òxì¾ó¥Ô´©…Rúøq楯½¯y\ÃÛe… h«Ì÷g¡éEm.Ç»u­w¦×ºÔë]2]ôõyk=·{»º¼å·[ž®×™½×ywÞ@=ggÅíkWe÷œ}}À}ìowÕãNzî#,#,#,è#, yì#,x->€è#,ûØÜ<¼À*©©{¸WLåÜû·a¦ƒOl¥Ø5nûÛ§FƒËÊ#,·m6Ð ØÑÛPP½ºu(QBª#5 JJöeGc@#,¤’ P6bªîàïA—nâûîׯZ>ÝÃãH½ž'»{´½íp#/ÍKØÔvPÊZ6îîûÞtÃjÒ>©·Þ·£¾{šûzèÓÝl›»_7Zíôìíëéß}ÙÛ¡¦MZûÚõlíζˮ83oM<€k=bWGÓªU¤Ž rz5O{½ÏyÞå뽇 ôz#/o3ÕPKh—F;ÛÝæ·Ûl5­#5ªvê½Ù¦‡¯f­î{©%žöëÕŽÚ»sg¼RÃË’î}¹Ÿ}ÞÐ#/#//·ZÅ"õîiµÍÀŸç@[ßsÇ­·®Øèì^s +ŽÞ€>û½îBqŸ*ÓKïxÓG5_/»=ÝÐ=ª£¾Ü'Ø}Â>9¶¦¶ë¯½÷e…åÏ6íëžÝÓmõvuÛnúåëÎãï{›E³{«·6·u.#/Ýö»ÎÛêï·îNî»^FM>ŽO}¤ÓˆßX¥­áÍL|R¡ZÛu.9ñ.÷;ìí«/nûÝÞÛ¯7rúçµj;<è¼ßF¾ù¹¾öogƒŸnžïj½zÛ|`uï¾uòú-íèúy=gÔ#, J=°#@˜S{0)ÚRO½Ôó5^‡¯^ñN²>·3îeÝÖk|½ÚðöP•Ü§;{¸Š‰ïUíØ)¨+×Kßw^|#,=Üu #,=ïŸ^—|ívõÞ§Ãv¾Ÿqw{ß]8¾ŽtÓz#¸§í×HÛ˜×@ÓÄåÎÙì^vÛlÒÈλ÷¼zÞ‹›g¾|å6ÝÛÀ%W ¢ëî»ïW×ݶûêx};ìßešô>æ&¾Ž{o=—Þ}î»{¶oŸkÛÝÞ:Þ{}»‡ÛkL}½>û>ya—Û½¾vòÛÀÖŠï°£®šqM_^/…ó:è5í„éx_-ê»IÚžÛíïynOµ@}o³+LUS¯4ºŸZ:û=àuîžæî­a+ïW{ëS¥¾ofw[{½ï\î7Ïvò_|î÷\VŠ€:Õ/±¡Û̳ÏnR„+Åw¨Ñ†#/×_wÑãÛ@mg #,#,ùíÜ:;¶5èkGv»sÉ®Wß"}½Àt@õïxõõèÞê“6ù·wuÏN×Vvû¤½­Îíº‹F’HÍÎ.î‰õ‡Sy½çUr^ßN/FϧÝîO®·Ð¦çq«^;N!ßyNû¬·£à´Ä“NŽí¸{›ovŒkwV¾]ÜÚÛv™òzÉ÷ßskí´ÙNÛ®Ûo6¾÷ÏSæo‡#|w M @#,É Ó#/ ™iODžˆ¥=CjA‰‘êx JhD@„Äi2hÔj6™Sð£D4òÓ'¨#,#,#,4#,#,A!! A¢bh' Sòh ž©6Dõ='©é6 Ð7©#,#,#,#,#,'ªQI4j<ši‰¤ôSf”ôÑ=OHz@#/#,Ш#,3I¡ #,#,#,#,$ˆ#, i0M#,§¡¦‰¦"{I“I‚O$z4Ð#,#,#,#,j"#, Ñ #5™é=SCÑ<©ížò‡Šzž§ê˜€ Ð#,È×ý+m«ÿîbcú†Ö¹µ¹uÉ~ÆÛS°“)#5=¶®º3&ª-5³åV­WêêmV¾Èþ#òþ'—òüµû #Îo{ÉÃMòÎg5ÌÇœ¦o9­Ì¦ç.înç9£šs-Ïð´èJ}B-~¨Z¯¦ÛRªßkæÈD&Tƒ%ŠªÆ(°xT)U\óâãóÏEÓ<š7^øIË̶ëXI³&>rµŒÕÞVª«L*ØiH ?#/ÕõŠ7ÀR ÀYeË©jÒµZ*Ú1µm#,-ÕB¨IX(¤È‚ ‚¡!„[*E±#,|à…R‚ Õ F±V«m¯¿kjµL‚@¡ ı™¦ &D4c6™QSR%Œ‰%(ÒŠm¤¨EL’X XMSQT”DJ “4M”-”ÆJÌ £I,hM0¥F’)6"ÑJmIJZS"Ô@ %–’#5’`˜2’)lQm“T#/A”²¢–&¥()%Ò‰Yš‹F¢´«iU©I6¢dÌ™4lUZ•¬f˜fÌÓ6¤±šm°KM±5-M2jadS$š djF•¤ÖB*M&ƒL’ZH-¦±’²h˜!`£3M1šlb`•4°HA˜†31#/†I‘(‰(l›R@‘KŠÉ¡’#2‘„–f–)2A´˜c%4–ÒTZ#/¦5*ECI†Š4Òl(’Q&È¥±1Pl™M¢’e¤2’&ƒF”ŒÉRŠ)™6ÈT2(–E’BH…6"ÒX5 ¨…"J*5D”…3b $Ô–)1H‰”Œd™3Fa-™S ØJ‚ˆ‰!*M‰ ’M%`Ä”–,³0lÚ#M#FÂJ!e$ ¤Í‘)š¥›,¥Ë0É¥’ji”h#/¥ŠK264ed&bIZ––HXCeA¦Ì Æ£f‘±†SKS[M†!3H¢ÌDjL”š@ÓIK-,©QQD‚Š#/‚&$Ȉ’”Æ4 #$4ÌP¢!•3-¤EaJ¤!”©&B”…6’ÒQl‘¬i&I% E’šÈ¶F̆LцÉ&Ê“L¦¢1Ë*™¥1 P©“DTѳSb“(²2bJE*I!e2,Ji‚´¤É²’f&É£&B¡¤`B5$Ë)YI†ÐY6J@“!%“(ÈE3A’2™HË0–’•Mš*6‹BeÈ”‘ÔbØÒLÖE#/&60’FTi#/*%k,˜Q¬eš™"f‹&–DJÅ,€5JJ2ŒÒ5µ6Ûh(¶0IS@´”ÊHÑb™)’cI£l–”³F˜¤Ìe3K*M”±jdcal’#5›(ÊFhÓe¯Úmv4…•¤¤%J2SX«EbÑQ²IšTDÓ%KAQ°Š’V¦"†Æ–!™e) RF³*Ô&Ú,Šk&Cc)–•E¡bd¦5-*c$&,32•Y£e”#k*ER©X¦Ê$²£)µdÔˆÖɦVD©5 [%YYJSL+f(i‘5£KMD–’%ƱXÕ3h¶ÛH3`±ªÂF¤Ñ¶Æѱ²Qª3LÄ5E!¨4jÅQ°ÍHmbY0¢5³Rhe1%‚h±„5(”Ú–Äm$šÆ5!b´’šµ³VÓA,#ei6F&³l‰3)©¥#5I–Õ6¢–’”Ô²¤¶š¦ÒZ¦˜“²¦Rɶ–m¦ÌZ4f¶k32I¬±¡›¤ÛKYRSJ(ˆ C5J4‰ŒQ°b„- 3–ѵ$JME2š£iI¥FLš#/%0ŠE,¨ŠAieH€i¢˜)’e6hbÄ„¤TZ,É b•š’ÀclË3K1š`©¨™Ñ2FLlBÌK!I´lI¤£&h4‹2‹S2TÅ4Rma3`Ñ#5TXÌ1S6 RÉBlE†54Ú3 3h¨±±±F„hÆÉ©¡"“aK-“$¤¦L¦Á’Ø…3R‰2I²ÒˆJ¨²Ô™¢6”ÒlÆÒei+Ä#”dfM”“BTš“)FÌÓj[,Ø´”³I²lbTQfŠJfdÑ©–´Œ”¥¢ÁH‘›$FY‘1¢Òš#@ÖY6Jhbb&“I F¢5BTmmˆ­1¤ÃI2ÄÊ &‘h¦•É K#5¥e$š *5“0²ie24´›mIkhЙfÚ‚H´–ÅA£ ,#/›R”JQliIš¨Ù&k2*H’£I"Ë*ÔƆMEc&&VJˆ¦”¡Q¥%4ET±*Je)FÛ`µ$Qd£dª0Ê6Kd¤Ô›j”ÑIEJjµ&ÅCI3d†RTXiH‹- ””ÆhÁ´˜#5‰3BÁª”FÈÊV&#JKEhƲEd„6%`Š1”¶#h¬¤”T€h1E& “V”ZST¦Òj-±¬VÍ1Y-f¢©š’‹Å(#(1³B$¡4l”Á£VÄm‹hØÒšÖHe¢#5Æ&¢Ñ­6Ë6£h´TZÆI5©fÍÒÊĪ1h³,UMIHÛ(Ë)DÒFÊÅ`’Æ’Ù-d¢Ô–±I´¦eM¢Â‘QIF‹kT­´ŒeCI¢$©”Z66† ÒZ[$ÛIŒÉl‚›%Eµ$¶ŠÑ­‹FÛhÚ¡K&ÖÄZ¦¥e´J2ŠbFÒL`©lMšlT‘²È¨ ™‰1$™I2$¡jM±fV¦?‹çý5üKý&¼ |ü©ŒRžÜÐZdI‹©±‡þå©-Iû²Ò/E¹±ò»´–^ï|¿¦¿¤ë×ô£Æ°Tԥƪ?ðÖã,Sý^‰b¨ O¦ò¢ób¬M4ºd7%‚•Ä3³m´5T;%ëvþ>zãyg÷îÐÿƒÌ³'ù£Ÿ,¯uc/eÕLŠYÝ]ÈZ1±, òt–u÷ë-²'«êÆÚe)‰QéjoÎQmå¦Ðn¥ØГfN½1j—qÈqÖ=c,„Â’¦6Ýr¸6=)`ó¨S‚¢5Š¨ªìÃKJÈÒ|9ëW®Y×[#¿Êní·ei”-M(¥@Ñ ¸_ñQ eRËFƶh&«ìºòO9Q ‰¸‘6Y6?óÀÝ€4Í5ȤU5vZ±ËQ­îX?ùhÿÀ¦ãaRµ^Ô›2Æ*Šžê2ØÁdX¿ë¹aßÝZ3#,©Ñ#57ªAOS(C (`)UAÒ¼®—é­u›ërÖæå‹òöêÞKŠež f>ÐD¹Ó§‘&²–9©%C™E¤¹æ%Š¿žªùOUòmº˜šƒ@ìQ†EÇÛ{zY]J4}]¢­0n(i¥JÂn@rpeË’nºìNºéŠƒ}K[ËÎÿlàUŠ ,D¬ÐÑ(Fí¶R·-"‚¿MTFzè­UiŽ´ÿÚz`™`ÿ¦ˆÎ™O-Li6ÂJ°¹@`@hÔ¨OÐVâ<çÕ€˜Ú˜Dã™{Œ’àq¶Ü`Cò“U}Ã]¿l]~>îÙ›ˆ­Vpò…§†o‘;J0Û)¨ãjåýeNôÕ8TãLhµÅ©j¶0æCfB(t\´Ã·µö% v3IêåS—ʉf´0 ÷09!àá­ñÁ±´µºÎš‰™Ú†{¦’z XZ%l²ÜÝ(ÂOa"ÚO– ½:Þ>×åŠ0ö@¨ÎÚÑfÉPe‰J#5WïÉ—RcäÝ¿£ZÁ6–‘»GÕ"_ºø7Ýv›$£#}þ»_zîF: ãe.¶W7"^*®P‹ÿ‰¥ð$cós´WŽLŽVÚiþÎУ²?.ãä]u6Š1£^9™dÞ5Ë–Æ«ù)¨Óï84mëwßêü¯ ™þº¾ïó{_Kâíå¹£UÝ\XŒQd$Äa–“Þ뻩 (hdS£C"¬éÊŒ&/º_†W x«¦¬oW“ñ{ÑJ_7*#5¾óáy›â¸ÌWíMu­»4 ‰"1SJBÌV·b·cX²júOöÅòW#kðº„"ȆùkÁ‡ÏPÐ?íV"0ãKŸEÓlØþz'<• "1Ò¶³d< ™!µõwë¼®mÔß9u#Es”H²sª›»Œ…¦õAu¢–•­Bz’ZÅŽ£”ÈP‚wQ&šÒ›³äšêP¨¬¢ÚTD×¾ï˜XùíÏIà•½raißÝv‘’dªFÓÊÊ90Õ L"ÈòªKv‰ÑÄ®áçˆ6ÊÃm-8ÂÉ2ÔQ¶Ùìᦻ`¶"§#5ôºœûªŒÀ(ò@Þø%€.ê}UÁ b‡dtAí²—ðŒ´Ö3Úá·0÷"+„úÇitˈ!cûœøÏE0Œ«“ꆀáÇ6¿v¹ÎÞ,MP—“$XŠ‚Œb‚ ÝT‚}åuÒV …H±CZ*SHuÅqf?áNåyaðÚ»™:¡¨ã…ufÿ/jiÉÐ80jN §Hï¯Öo/žø9`Î>®¿/,šÁ)Bµ)ÍA¿:—+«v#W*ƒÆ|™u ²&7½DjBQN84ÛüÕK°™&d¦«ý#5*mÏí¯gÓ|¸ÕÍŸQNoø (|‹¡Ù(ÅsÛ_á|¼»ðÄV'rï¾I3Æm¼c+¯-ÍIŸEMT}[×@0ØÏÂŽì$‰hJº¯ZÅX¿|ê*—º&dìFŽÚmÄŽÈŽ0¡üGʯg™kú‰;¼e ÷›¤x Á×ÇœønãoîqØàäñÕOì´÷¿.w’ô‡ž˜7p’3Œ¶=æF¶÷¿½P'ãûµ†HùOÀÌhËhÕq¦{æ2°oïüÒ¿„ѯ%BÒ„–¨¯:?_ÛëñͺC—öGÊŠo‡®.W’wD+:Äy/²"]žòæO{{õ•X*Rpª‘ëkq*(øV1)"­¯MëÝ´ò‹ýfŠì†˜­PcMïôå1­AÄ«pÒ¤V=§Aç=ÓFÐì¾ì¿n.ØÜ=oeŽH!aÝ$™hNü|dm«]-üÑ”ÈLÛ@áò:<¥—¤!iõ—o »h-ˆHAWã‰ûs2±ÃpTªj¹î]¬ð«³ƒ-öN˜H”Š#5Ft—æ¸>ªµ¨;ùÖ”ú?ÝŒv3ÜÜ¥D#PübžÐÓ®ÏZ:Ö4@Iî¥*h­=(<—Ü+Ã4—|õ#5ÇÅþŸšµB—_xá Ÿ>Ä4¯]ÀG§H­Ñ Œ|]#5b"«£.xù›ã•#/.SθÊîta¦aæ”ÚØ”†•7lDݶØ1Õmð¿þü,8HÑ“èºr.ÿ›>y#/‘A;÷Éí âo͘«HjEá¤Aƒhlù½W—â(¥ôvÝë\—évê0‚1:éeˆ9Jö0¯¢ÑG’·I”Ü•óåþÕéçþ§[Oïï¼û6±º{0)º¡J‰jUª×’ÒÙ.éaðg¸müÌAÖg­@I#5ÇBÞ‰¼`ÑG¡àaé-†{_#/™[á%Îs¶­OÏ>Ñ»5²F3Ù1õ «8 9ºùý71ÝF¿m€§zä¦(§-|4°²øbÌdj~.£áøQ’ʤX€Š=_©žoŽxpîð§çÌU5øøïWìýÊ,饌„{‰#ŒÖ³Õ'‘Tiç¯<P8°)‰:YßmMî£b‰w@ ‚Á@a”ãƒÓŒ=x³Õ¥dÀ}øëy”Ð+MuÞøb…#5nê3›°èM6~ŠR-äœÙ¡‡Žó\æòx@ëpÔ8\Ê6ir¢t{î¦P¤ª¡AFšòh„»ÜäSC°¡ã1ºb™RüŽÓ`^©š;4õªâÍl)W»µZ›ívE€Àe³CÌL¢ˆ²šèóª¤;&#/F‘Ò§»t^yyÊxq¦.K•ö3¸ë·á˜ËÌèQIŒ:d$Z¨g§7‹ ”†B©É=0JŠBJq¢}öÉé†>4ßi¶DÛ%RR„Ç’Â"[àCþõçoqE1×íàä‚ØáÚ{~Yƒ>«ÉökZ™;xZoÚ¤Lhø‰êÂ×VRŠÄ9³HÉ`œMuôÆÅxë²7cÌOrJD2ÇÓ: uÁv˜ôOîrÊêe“¦DeÿØ$Ï:3Îw׈X© *B²‹Ÿ,žöJø¾â¡œð½Úõˆ^ï0s‡wÒ‚åÓX‹F¶;¢ûn^Ÿß‡Ž›\ÍÈT#5p€Lt"Ý3ÃtíÝé8§Ç§„ÊóÑšMÀ¨§ƒHœ(£1ÅBP0ŒA¢Äßøºj¯f¯†§…Ó»}s[Õ{C©Ý}ÿ>Ï7M/e«å-o‘Œîe‡#5#5Ö¼ ¤dSRª{^{÷ê}i›ƒ¤#,$ ¡NjG÷G5íIÉOµÇÔ?Ë–ç§WègLäãóg]EÇòü*Ô;Þþù» ðzþ¨/o/b‘œwÒA«^?%g%ÛÓê÷ªzn©÷|ö.?#×}$éäüq=^E¤nñí¥¤Ö ìFcïv–f¦¶,ù#/³,ðgîg›œ!³¾#5~Š«ªPžâiå:: Ðš:䲦‰ïQi±WýÐÊ9ªÃÝkdUWk¢™B#/IMvýõgØøé(:0Ì"ðp8®H±/Fý“à@ô:Jæg‘ÿºÃª Uüבä¢e;tÊ™á‡óúÎ3†ÙöÛ¹ðÐC~ÛÍêÜôzM,„ÂçöÂÁT®œw6—j†)Ú!¥kûçövñ|­Cï£ÒPðˆ—.QËËÀGòB|‚rÆ=*D2•þ,Ñ®wÀ ÊÈßà›3•ÏÏÒìâý©ÕÈá´J?JwHMÂSÖ¥ÒXTñj,‡)< Ó'iÆ~ÈØG÷u>’wºÒ9×w5‘¬ú¹Lf8ë$„¿Z‹LÅfã4ž.çÒœLVsR÷¼`ÆY ALjg½)ÀÅ“BÏj~oJ“4„³}vZZÉU):èg {·£uü8P¹¨x󘳜ï³leüÊ:o]éùÙìÞÍÄîß<ï{ÔǽY/”?3Çðé5œÝà_µÊÐÓ1)4º:mË¿–šCuŒ›¥»¥ Ì „(b1#»/4ÜÂc-Å;Ä2Ž…Ç£«1T]†ÆcFzÏf¼ñ…YÕ#5FmUSZ6I»+dU½^¶S#/›4ãßO ËD=ô[¡©ÝqŒ1ùÚÕ¶UOÛÖ±Zä~ë3"Y·þ‚c|4oZ–0åÁËú]y‚üQ›‡ÛQâûÿFÃãó뼟#/6#/ùAA“Á©zø`e°¶÷¢—TT•˜,„UQ²–PûzÝkLCh¢%jV•MP-R‰¦˜.ð€èÔdNdƒMÙdJ¿•ù¢ç;­Ži]š\òQ?†8ÁUòØ–†Å#/ yJŸµRN5ûZ+H÷5úZ:||jînÖá¹½h§ÂqÖŽÌìëÙ˜ÕaÚtèI«Ý#¶Û‘‘§&ZƒÄ‹#Œå Ñß÷CÙmÃ)ã.#/„6G®it¬„/½iô®µP-§¥Ž¶›~òâZ0ú:¿~®J+JmÇM}î/sÚ»±¸´^i@ÁÑñ©Ç%”ÈCÊAòÍThÝ°Ñû|Æ‹Ç[4¨wpUüÜϧ‡ýú#稺…f¾\bÊÏLc‰Ñç¯B°Vü8éqæ÷ë²^©À€¡ Æ&[>¼Üµk6ª«Ž˜ñãl<ø9^K#/ÎÌSm/××;)ÂøtýVÖE×,×iýëþÖw-#5õÄ4&á7ÂߺutßÅdwçi#/>÷ÅZÙ~ŸÓ™¡©]w«DÚñ¥ï¨û|œ»}>˜ê®#uŸ¤†òñ´ÎÉáMgYYRóªó«TY¼q‰f¤Üбœ*qoj å›®¥ñ“f+­?Éæg—mº‡Ký¸Ç&Lã·C}W$3Ó«·4àe)„Þ«­býŒÕ“|×Æ©Ú²ÂÐ>u?……#/$î‡Ìã–æÂçŽi¤[Sß¹åÔ‰¦Ì“æƒïù¯|Ó #/‰é®Sw?„ëë›Ù{œùFÃÂ.Ó_Y$ŒøFïl;timâøv¬¨CÛÇO”+)ŽÐ~:*‰ºx­d!žÆ4W'߶Q1üÖðoØ„÷IëúÂfOÏËz6½Š²k.&Ü‚õwsŠð$D981…2â®Í»±í´øåsÊ#¬ŽOn6ÖØ›*3לÊ[LÖhùW’"¹#1˜|α#,TªME‹ºMqéªoävs6¸]–/œqŽ\ø<$öAó©C}¾%è•©LÑÉáSéM$ÔV9Ÿl{§šzk;öO~)tW¦\¹kר›¥§Uo‰˜–¬LÏ|^Ó‘s›¥žsÙe¶»¹ÖÎÝ›ìanÊ‘ üj‘@z•A6‹ßøý¼†ö´3Ž°¬·‚W{x‘a$ý++o}ÝZ¢@þ¨³e]Ò¡ºà•3¹äúT?Ù…S¨ÛU5ºÚaŽãnæ~ØbPI𥠮Ž¿/;#5ä‘ú ¦ÞªR“9ØK8ǣü¼9·Ùѽ(ÃKhœ-¡ºGsÂ(Ùk8Aqj wÇ”„Uü° s¢Ç“ÏŒÚãî‰Uy_¡'·~Â+Ž~ÕXgÔÒ]©I•â#/Lx¢ùBw3Â>gGè•B²BÇq×]!©¨w]ßçÏœ]vÆg›ëNßM4ô¾À§aBú9æsÒ5xöí¨£ÞsµG ’†Y¡Y†µ£$ÔÃîz´”¹@¾ì3š^Gt—+Î%y ݽ,Ù|ÛõR¡T¼$¥¼´IëCî—ÁYÛ;gX²$…MëÄäóÇC ÿ‰§Ù¢ªvgÑdKÍ9oI×V³…™ëÅ]ŸJÌvsȵ¤ŒPRÑ®¶Œa“¿÷3QÙ¬C Œ>©½–Bû÷ìÙ0´·¥òTUBšˆEeƒµ¶([¡(ùhí†G„\ìÙII“Þª‹K®D+²QÃášÀ«YÍÑæf®_m#/žìt};ôx#¡ZÍÎÖ·øÆ>cÿ8K|MPÓÃýPññå’ŒDÂd!,›I¶KƒÊæƒeN–ÇMÑbˆdÜ]‡ç;ê>¢ÉUò!¾yzwîgÓãòç¿ÐªPÛî[Õ@ðú?š@“L$NLjÿU­£¤PX´[7åä³ev4ú®P©iÏ›iyÐI'iq v†Êyº#/z¬¨¤8è‡Zõjòú¾›ž½¦Æ†þ Éîæwñz{&|I¾ÝZáÐX‰˜¼DÛFì Þy‰ÉT,cšÉ˜@#,˜`>únãùªfk­ÚøX~8Â~%·e“¨ócº¨šÝäÝÿ<ÿ¦æÒÛ Uí·i€Û À‰G’oŽ ÿ_;#/¿[´²Da©wà¨Õ  "Å‹>gΤÇÙµ]'•neÂfqU Å‘©z='U.aš6|½¥v•…O…¼¹süÓ¤QîüåÜÉšo$ !ãñU³,ÉU«}Z#W`åÕu”8Ò0HÈE[„^ÛÜ`//«]º#/tP^(ƒ–¸–wQná…·„VÍ%Ît’bƒ(ÚÌÌám˜Ìݽp“L'o˜“ 5û'ìs¥µË/”ô›Œ@ V„ÈM^%€æ-©ÞîbæaµÃÝ—«©bíð‡¢›ú~øûþâ€cþÕ À¬-Á§ø°t‰š„¯£PŽ#51U·Oìï,…P‡Â&£ïöw̯m¸âÇø?èòb®uYƒ©ëµ®Ê9•TñÏ?ŸM,ýxÁª·ögß ÌÚ¡¯F΃›ãӮݷXG÷ÂíÈÑU^ekuþß'TI²A¦Hk+Í~Fî!I—vsõ×^Å€ã€ÎQçs@õM=¸ä˜#/¤fÿ»¦ÙÕQL"žSL+Ü¡KSiÆÔ£ú sOǃ:…NVʹ”SsAßPT%B'ú? ˜u'.BÝÝ®³é©±ËPõŽÐh`¡¯1ŠÕ¾¤´¥æã@vü©õh7)ÝwÎyî*³Þ‘Á­I$5!ÝÂe‘óÌr&šmïC³C(¸³W&HLÁRÊý’iÚB­YàÓ{­ØNlÍ¡3¡†’)G¡5ç4nÛ@Û;Þ7覧þÊÍ‘‚)¾œuËÌÃVfeš5IDðç”jß„!@¿h¤ŠG4hf6D™X9FF)èÄ»ÝünZC†ÄDKßm£IúüyüÕ¶aÓÒå»4ÁAÀŲ¥Âñ?†¥´¦g² ýX<Ä ÂZ3°áÊÞ´IÊc#/ŸHªc?Œ‹œXXÌúéíåv‘ïìÏðŽ[Ù ¼»Œî*뉣êQÖ°ÆŸ{wN4‰Fè·ÀLdIAÛƒ´ˆŽší3¨×[”˜B¿wE fì°²‡Œ„©8÷p€»VCùô ¦§±#5÷L5i8.^£TéiݬòÇ40öþ\Î×s¶©ì\løîlÿ‹=ÄlêŸp·¯vöµ®M#/µ>ÇùòúàW§{ßl½3㢂̶WTô™ÈÀ×xTs+•¸S´ÀÚ{¥EP¹§~n^&¶þÅPï¦Ê.XZ9™IÑ®¿¥=SF™9ˆg!8ïyùþ—W¡4`˜üÔytÅ1î˜×ó©7,»/+i'}‰†nß”Ùðþî©“–Ðû†¤lï°#Ö:§¬>sñèÒòš§˜ÊÛl;BÞ`–§iùŸ•dŒVÁFú8Úq”ªtyG6¿Ÿ5#/+žÆúo¡E{fð÷w »¬ppÍ(”&d¥ïqÓ­|ŸÃf¸•‚áºÒIÀçË¿1œ åU‹c¿v¨Ø餑&`q|kŒLþ 5XQpùàâj‹‡Ü23(!°Èò¦íæËî–;¤„Aë|»¿Âö¢ãY#5mÜJä:Å!Ó·³¡ñ¦øïûkM³çV1»è¢ÊÇ“’&”˜«aÌ/†'Þóžk¦ùòԉ½ž*ŸNu½ÁD½L‚Á3´‰´µèJß?‡Ðg<á@dCDžÃ#5j3xÚX‹TiˆÒnÀ£:2.î\µÆ ¶Öƒi¤šQccyHà,ÇlÑa%Btš“0úæ?œq§¤ôÌü.£C¿ÿ`‘BÄ=uìç"1vŒ•€‹ ´‡Ðb*póÜÕe…6oçü¿ÈÌÌ¡™´!³¡!&[3F a6?>¹6LÕâå\¢•AuØÍ·¬.ÓªúR|ân [#5 hŒ;2ÌJAÈôSÄ£6.²ì³fÂJf”óêZ%•+æ|bôcÊN¶G.ä¢Óg]w$¯Çû93ÆÙéó?³ÄÉî®Ý5×J7*Wk˜²jrï•¡ ªÑÎ{ÈoóÆ;‹ÓXýZš„ww´Ù·¾ ØnÚ3‹óÄ@ûƒâ\ëÇHfÅ]†ZdjÊ!“â¼v¹5n>OsÔ5›_FjÂÿE[Å7sn×(Dð˜¤Úã¿ã©Û²f}‹ˆo(}Ë¥é/o¢ùÝ3MÔ#/*ô\˜ÒÛS‚c"ðµ]tÇe¢°üL(Dvó5èyÓCêÒeòó´Ky£lÎú!ÂÅ8–Ud˜ùî–Ià ‡0¹6ä`‹œ½B˜àB[‰CÕeØ©xìú\ªN¯ŸXÄ?Ÿ~öŒZWÞxßV8gŒâE/ptv6À¨¿1+Í- ÜKu—–™‡ÂÁ!+²5D7­KaA³Ù¦qšd·Žˆ=3`¢QSO›ú»ÓîŒýËñbYuvL 7´Æ` þ_Ïò3”‘ldÚZ¯®Ü+ÔCä–|’ó9©Ï»ÀªóÞùò{ê}2%\z¸m‘oM[ ‡þjÞ=Ì4å¾q0öÁH¦Y²aµ8B󺻼ó4æ¯;‘˜’,i•¦JH,Š£µ¾XÐLèÖ¿o?Gßœ=úr8üžLÔËe%0Š(5aH­RšÄPÁŒ+š>­{±­¢jED¥EAa zêVå —%YbTÂ}~Zâç 9‹×;® Š´< 9ÅFŸ*ŒP¢“’Oö~º+fcÈÇW%Ÿ®ƒ’莚ù¦‚0þ²HXºÐf¸0íf¼d­ø×Êú£Ç<wòÍT¿uH6\‰²E…0i©¥Ìà]äÉ*ê‚ÐÖD\LÄÀ‚l`Mü6W›ôñŶ•u=&0á‡t……"|"n¾½¨Æ¸‡L™×MoãùvÈ=Eóç'8H£¿ÈSÏ·©¢Œ–!#NÌí^ ýó†Z«¬i[<.ž6P*‰#5¥«7eP¹òƒS†¶ÙßÐ7bPžG®æˆŽRÖŸù2TÆ4`œ@×8jLL¦ŒF“K"áfƒµ™­ ‹å™›#5`g©¡œæÊ-TbB¢Â®¸ÜÑß]Mt:›´Ë®ñ^6ú-ËJöh?­‘¬ù¤1Š¢¶à¨%¢ó0ÝáÑ")œ…" G¿J.ëϯé‘úw½yŽüˆSªICQÄ(`a kï5¼UÉ4[5-Q¤aÉ‹#/XEÂV\ !<î­r×ÉnÍ⯄VêVÉ­š–½Q½é­°åBê£hD‡‹F{Ip×kN:µóŠW9HU’غ¯«U¥.àHªo>µ]Vâ"/z(•~©r#5°«+j¾O AÜÀÎÆîK]›ÈcÙ«×ûj¯v={[vëƒdIÑàj=qÞFRUxoÍ¥Ÿñp UswØU+nnÈ:.öÐÍôz¡êÓÓ–e~ƒ<P¶1öÊ1gMÛ7*â_'‚Ï0úº½ÀJÅ7(’Ù#5™H0Q’車£WË2¬úr«û³Õ“u˜­¨”»ŒªÜ¹hÂÊ) OƒnšÜt¾²I [º_Ž™Ù¿]A8âòVT‡ãP[úÜÔ“™NËù¿Å›¿»qž|tKƒê¹Î[ãðŸyVàWí­÷Íø6††Ná¡—´MŠ<·u,Ư âLÁ³:FßU¦hÞ‡1ü;HÆ‘Œ @ dJ•¦ÛÏ/5Ûòë±±^¸j-ñ/F‚d‹"ÂÈÐ ’ RE—‹¢¢²˜H4›I#/ I³.Îaϳš=u:Äj¢úc³ùô­5¾VR…k/’IÇú¬îvýÞ¼ñÇsÆc«üË©’è#ÒsD»OGÍøM‹F)ÅâH„cpÎ"MUöo¿WáÈu¡uG¾#–œ)˜{žSªd>?«ðr¨dÇr6&foÙ²j[!¬×J­!bSB»%ÖMk6{fþïp#/¶2ѲÞgZwéÊ/ê80n\„9PÁ$ï=®˜Xu,[À&ŽÅŠ­iêŸ ý§/ôËRdOʪ)È(dµûÓ.Z¤ØÆ(Q…E·T(0QµÔϵ’–L·:+wÚŒ‘gwÕ9¼†!ÇJ¯éiKËÈéÛ¥þ²ÙøÔÔs“Äf¨î¼ÜûN~¾\¤Èn€˜6ó$”Á<>)Î.±X‘! ö£&}÷·¿búŽŽ ð’þ2 ×z’lŽëì² ¬v×LT¢‰d$ŒyD}^ò—¶ßgöÎøNÑŒRèuÆ–8ÖT¤ˆ¡Ý®q/òÄ}–þ/)$·´Ø^sfõlÀ‡÷*ŒÛräÊ´‘¢Ì‹ÝU,^;æ\ÓæMt0se#5kã,6EUPq'=q#Ÿ^ºá§D>±à¡lÎF•¾)NB„xSqF†£ü* Y‚$/#/2·™&½¡¿ÙóŸòàû Àܲda=®ÄÝ­,ÕÂ\&ãf*ÑõÈZëÚjô¾½!ÊóŒ×;¤1î9TÆuCBs U.¢¢$ÚŒrÛ\ÚHµÍ¹­ÜÚÝ-¦iÌ÷n½öºDSU<*ì¨.;ð`X&Écñâ¤àèŽfÖ¡“ ¸n‰d©LNk”Ëë8ÇHQ¨rö>ÓÚzÂeâªhS30gÐcÕó`L#š~m!ô·#Íí#Ç/¿ÊFÝTŸoÇÝï]ýltËQ~×PÌbæiŽ«ê±­ #/„¬Q÷þõm¨ã¤ÿaëÑÕÚ-;ݾ´ÇêÞíÒŒ[ÓC%ߊãÊÉIŠ¼ÔÝåå«çÖjÖ<êyuåB?j§«`Áœ?Á½ÆhW,¿ëh¯ÖŽ2Îÿ>rã#íåoû«"å'RúÎôï ïPxÅ—²W–Ç+Û“Ë©­iÈ"#]“¼ 1û³BF]ÍãÈŒ²Ä½4†Ÿ=9üxOÏsÂzú_ìû;áDUãâÓ}><ûáË/1¤ÊÞ2n­ÿG&iŸ×LCk¸bÔƒ¨Òuüß«/5µÓÖ֓*“Ì:rëìÙ•·¯¡_ÑÄñ^+Ëùëûª•Òó]ÐZ!ê>Ì£Ù*6mçõ¿ðÍôcÙð>N¾+ú÷~Þ>ï·òųæ3öf_ž:Í´™Ø½gDøK;¹#5ì¡ ×‰E¦Qx Õ4{hyOçfßñì²Eʼnb|•ãŸ®_'¯AC9<Õ9³zt¢“FB”Ó–¨P!õ×­¿õL²k;±ù×Óöwé·•¶ ¾Ü#5ÇiéöY÷ÂŽÁ5‰V¡GW3à«Éa1¦”4Ü åÞQcziÉIP%4QhÕ¨%B¾ïßF¿Ä*†ÚhÿÒªB-ôÁä‡IWïü¿Nš¹™™‚–X0; ]ËÂâùsWŠùÿ{wëßÈsœ¡™ÄÜ"Ä[ø¶‰A™!!…Bb3âv´Lµ%“øÊæLHfÊ–%Iùf&’Ò£kúÿŽvÝlQY\Üvq0Ι ’ Þ&¹1 ¬=Å°ÝÖ^[-ŸÌÄ? MÃnzM¦v¶‰e4.Z)M!t¿}^Mzߣϻæù1ãDF"whª #52’ØO€b¢‘S†‚&H'{÷_ôLô®ÖxŽA‡N+Qó¡Ù ÈdD>žŸ{ý]L‡v0ŽQ£ˆ0›$3~ër½¿¿®¶¿B½EXŒ°ÚŒx¾gáb™d¿é«Hu¢„dY¼#5gEkò«Öõ·K^Í]J½ImóÑ\ˆ%%„Qñ.?äùÜúS¡Vª%´ÉlÞ"–eHhÀ¦#5[*‚‰àù]Ã11þCHOÑŸ0xjgüø/¦$(—ãoð³¿%Œ_ù#5»U0}q–_ùé§ï^™?3üììÙ:¦Ú [4À6?¸ ž³S»Lë[ž13£ŒN´?á½$y×%’1@z‰»qÁ„ ÓÎö ¥mú"Õz_ ΢׸n"=°áxM *¨èÎ3 뚣IU+«ÏN_F,Ýø#âI@ÿ·*"Ãû.N§#5è’‘P‰CdìQŒ.ð±q.CÛÒçúBkÝ…gâÖbkßùØdE=l|öDU)I÷0¤ý JÃõ´#·Mj°šëjú†Þâ–füÝuý‚å£W¨ê·/ÆÅ$㇮¥‰ƒCá?‹òÕÓåÛë>Tbß-ß»Ëñ§®¿¹Ú¸sÇž>8[Â%hæïÏïŸyù*ýÿMý"MÅy—JûŸNm…>‰Ö¿*™Ë匩E¬ÄÆi|ÿXçËgáÍa×vö1•t‡=¦ŽÏßH‡:ƒo­–ƒ˜–Rô<5áî{-ºÚG"j  Q‚¯•þ³&jçû(áÐ*ú°»#,ÀJo¹|ezmûf~áàµÅê¾?Ãþœ)í†ÌýúÓõé ¬»”M¹õÂ''ßÝV7q™°¹,RveS»wð28É/œVÄídîð$/@T\cLï¡îª´3cv¾»-E±Ø£L>ÝÀ4#,Ô%ñ3#5Oóô=Q[MW9ÙetŽ˜Æ=cñõ_[*[åØ´å§ÍEÍœÕÁ²Ï¥¯è—zµd ¦ã¯‘a¤ÃB#5LÜý445è>K·ñW*–¤ßYÜz¡=„¥ÆRLÜíã?Äܲ\*™wÂyÿ~ïÂ|ŒÎ¬ÜN& ^Û ?.¹©ÝT8#/ZÅ5ý­{ò€¤êÍÄ…¤c‘°o0€ÛNÂsüþ ›:Òß9t û „"uúO|ÈU¼&;éì·ïl}ðèÞIÈ~³ù¡Þš“°G-²DǯŠ‘,îìïå ßÜñ‹ýoÒÈo½Îc|ÈÑÙHxžG¤¯ÔDy¤!&B1d8ÐÁüóù Wð_¶?uŽÙ“fñ!’*„ùO@‰Ö˜|‡+N/•©ù?ºuôgYèÏn¥›y^9ÌœûS:gwi‡³ƒóDáIM~‰ˆÓ4ÑŠ »LFÚŸµè{!V4 A2IbçBÉpVl­à#ƒýYà.½Üât’‡cšH’LJ·×~µ ¦ÿüÁØòû»Õz0:* #5|ÀK‰¥TR#,Ý TDDEWåîñ† ÝÔîöLoÏ—M‰þeaüµúå”Ò%'ô©_ããÖ\Zñn2Sh2PÉ,ƒ ÎAÀ1¥ €ÒŒ]îoFƒåÖi31-´t¡1ûzŠÉøÓÔ¿ŸÍ³fîùfïû{{¸×êòâÇÛê>th|´tÜ»XöÝg»KzÿuÞÝGÈqü·Þsé#/xT{sÝ ìÀÛ3Gš¹ÆšðÆ/çPïêî?^½tiÇöíʼrÕÕùgÝQŸ£uÖBáUüèòá»~Tr«Žò¿úOœ¦~—½CÈ·x¹éþ8÷OMµ­³ –¼wkrùãWÔó‡DÍøÆ_)À§ÃuŸ^ýÞxú—ͧwÞDá¶ÍÝÍŸ<÷Ó»ö–†ˆözsËŸ²Û=méòñ5™°;²õz4ž\ú5žž^-mÓø7¯ùü~}7VGãi²f¶ÆœףɻÅ#/íæ×+%BÜ{bÚqóöž9N+ôÐŽ:àÞ‚¹í,9Ç?§fãÃg=÷í|ÝóÏú©–ª³Å»«–È×#/¯J¯ÌGFÎjàu~~=vû²l?¥0†zJäOtªå§Vy×l«4S\‘,‚ñZºö´Ipç=%Ò>^û.ðSž]Z·U³´UÒ:k²;9ÿ]1‚öâÜÕߤƎ|vø¡nj·gmJÊy çÝ—IÍ®Ìô°ù\ÀÆ2+ׯ‰#5U¨<8œ„äŠãô<¡÷üpm~òÝ:ê~Eüæë|°¸Ù·Ô´éJÝCø‘?wŲîû´úyüv–CŒ2ݳD'år.gmQ+õao.]¬ãÍeû=WUZeB+ÏÒ¦ÞZ¡#5•kôòvPÑþØÜ©ºþQÉ®S†Ùuü¾&¶7Ó3û¿ >¡´Iëæìüg™ïª’ѽSIŒ‹ÍR¯ß$£¹ÿMx~O6{‹!׿?ÎyÈß- ®+òÃdž_vÛ:¬È'ªÿò=Ê¢ï€AáPe Êß^»óÚlËuîŽßoš>ä¿n«—×áåáJbíÑüÌšÚÛ£þ÷×ðÚÕŸ»gËüý¸òÕ›B‘\çýœz*Ñ‘õzÆ¿W51ø/U[dXhÆݹ»gWó=™9µYgº€^ÞY÷}’¸³O]Ó/n¸{kÓÏÏüvëøº+¶ÉæMrôádÜ„ÿZK×\6¹þ8éjË“qpGtK³”×°Ž3öfÙ¶a²È—ú|ÿÎË~læmÙºOy·ý¿ËwÃäïúáXo?[ïæÛ|ñÏÓMB-Ñ^Ÿ]>&æª>ÚDò¼Ä(ŽøhðúwsþZ¿IºPØòÅè¢FFU!dÔú9Þå—ÒS“åáqC°H¤"œ‹L$⟎Ï_Å *l‰¦>@E ÃZ˜¶25˜fÚG˜—Ùòi÷ž ß»´«Ÿ´éê×óùù_ËÁ—¯òù~z÷öè#ð9‡œèòô°spšìúX¿oë­¼ñì;Ïô÷ño¯òþãfoš­Ñlí¯WEÞê›CTÚ|ú_Ó~˳s+\û~_x~;tÆ~£Iaæ&Ü^–¾7Í«/=f8|ÛEW.¾vÕ®ÉðÒ|ìº'ëÓi¿ðêÌS|²·•Rzì¹Û»låøرuû+êZtš§­­Pg•±JüíP9¡[ÈVË1qB T/;WRØž•¼/“Ý©tåÇTë²™^—Ç®œÞîeJKNWõf»–TäSsv'k»òÉ)Ês³—Ù Q¸ÂÜÍÍ)ÙýÜcÆy#E’I'!i!¹Ž¢Zƒ9/ÜÛ?#/^k#5óíõ ²¾>­_˜Ãâáâê¥;žÀÝ*kMê”;þ‘:ª'¶S©¨f‰Å<)ñí„>8Âœrìçß„1ds…óÂhœ!rÐ˦~߬rl}÷5ŠÕ½¹µwTb©<èäPÈØíÁõvDN¢Ô½ãvïŠ~¾UÞ±Þ·!žZ‡ŒüÒPéZ\ZgW ËDK¢’áBQx 3d¸YfHg¿ˆ—äöYp¸hâ×a-³Òf*•ùËrϯ˜ªÉ™l¶üÓ›™½[;âh÷üòÕauÀ‹bq&„ÑÆ%£–É„zV€Ë1 V­„±}2+†ó I–ºW k-ìÞ{ÿfë„'¦o›}†üµ=uÛ9c{bgîצ^cf·×mv·8›ôBP”+çšP[ÂiÃËMùõ>(c“9§HJíYŠ¿ÙàW§=‡ùK¼`¾—üÔ²y»5íÝÍò|•V¤r]:’®—vw×Ê—Ùëëü§GÃ/¨Ú#“tð5/ÓêÙ#/p<ël{ƒîŠ²Iÿ_/d¾Œºnå‹Ó¶žÉF Ùy!ÝÓ4"«ÎÞ6Ý}F8#/ÛôÇÕÓîóú¨cê4™G¼26©tÈÔsyJ\³Ó×Q`š„ùd`Žï>p#ûIȃU^^J¾Š¾©…×ê­õ.EwË»/¢ÜÕøý$¾ŸËWõ­a\q´ZŒÌ¹‘²¶ä%`Ïž*;GªAºÖÇuöÃta­¬¤°ŽƒšVŠ•$Ç´Cc†E„‚ª(8Ü#5*"ªjDÚF 6ΞšÛ[k[‰Ò `ÒŽ ÈLXµ‚V“a¦HhÄYSI¤ÝU X–š’¤0­Ò#@ÝÓ¶–k¨¨,›Ä06…ûóüY‹Ã8h Ô$m÷E¡=ø§M§X¾îóÈÞ³!¹À‚ŸìuòX~Õ1©&~˜­Zj]'åþáhkQ˜XÁàñغ9ˆˆ¢13S²%”R(Èùªæº t{¢t/9h#08Ž$ø™”ˆŽJ:QFk1}KIPc 0i`QV‹† M@„4í Dé Aà<Èwoì‡fIˆ”xS-ÇÔgoþl,î)~½ÿŸt»gÒ·Ÿ1‡ôëÂËóQ¨ñ/4W¥hÑÙÓ?¾«9¶Y¤æül¦Zµ%û½CÌ·þŸÉæÍ÷a_#/úz~Ó®ŒDÕ‹u~½-2üÔß]Ÿ%Ë<ãÙâ{n¹w;åmxû'š”ÓæýóÌ=ÇÏiäÐ1¯¥¬i5B·”}#5>fÅ®>ãÉÕêý_ƒÿ…^­ZýišöBB°ãÊ DÒ8%k½ÿw÷­?AfoºwqáÓ×¢}Y?¦ú‘³ñ…Ñþ’iIå)B1x×^@Àäêñã?åÛáO%>ÿ?㪥Íá4N=ßÜùÏ/ÉguÉ~>w祑ùkêøºÿºþ®þš»ïüìݸÝû«ü5zë(¨–‡î¤à}†spçGÁÊ|¢®õ?È~Aˆøo{Í8VšÏHm0ÿaÌcb!…hô22Ã!I¥n0KJÑÊØ¥ß%IH Ó@ÓHÁ˜2¬)#,i³ÜuF Ó¦$©Z¹LÚ›&ÈÉ®Ýôó^šö÷ÀÄŽ˜–™SÍ)jŠ€ÄÀr7h(UX¥¡`È£¡ÚHŒ*V&šefeX6<+-iNþüF„<Ç+Ú“{†º†Í„f#/² £IºàEƒ©‰‘AÆÚN…iÑÅv“yåN=Q˜R2ŠŠ9‰Á£DI°n€ÄB° ›pcK J ¸‘Š)"Éó†%ºæ¡¶„¦ˆ2)@lƃ2#/e&:EÕ‘'(<)‘LRÛŠX›-7օ̤«J#5%F#50¬ (älRÍ>7³Mi¡²ˆ‚Æ—s6„B§ˆ‘îÀÇ⢷f“ /öZU™¨¨V¦œ®Â jPï‚ÀÇX`- ed ?@¡ÐóÈQ§Â'Ѹ˜.j.DÝÊGºìqrº¡hs#/ü¸1”>=j0}'t’Pƒ»¼0ïsòM¬8…Ù#/¤$Ò¾«š0,ô.e‹/³ùÕå¹óš~hsÌÀ7ïQÉá8m5_:ˆñô{þdã·ltþTmg"éø•vS“Rìi— ²v÷I¢n7]#/CŒŠThb¬ƒÖ0£«ÊI¯DðZª^1¢ìfe!™i?Ï#8þ^[©50î!Ý5ô;ÖÿŒýÓôø›£<(.™£ÉÄ#äv;³)™ ·¢€¸ÄÐ|oà¨2{»ÙËþ\þûn¼XôÆ–TµMå Ú­EUµ6Ç?ðíS§Qá×±ÿfhèïÜTU¼Â[wBëµÛ¤/ÑÜž¼âBBåWÙ&Ž/^ša6¼yõ›¶MšºR—±FåºjnþHÉ$·o½•«hqØÏ#/<Ú”%­èµµ£&¯­¢r¶ý;_É56„UòȇÐVç1Ê'}˜}CŽnLé €ø •DÛÿ®±¦Ú¤ld„q‘!¨—ðb¶?Ó—MìÒ60¬Î8;"Ê·LÐ!ÅO7³éÕôztÝów—ÎõøOþ¿¦_DÉ‹cꀠˆTH(¤QŒèkš°ôÉ(VôMÁëLê ]Æ‚^©†1‘¡¥aÃ[ÌÃTu¢šùè] ÒÞà†r‚Ì2Æ¢Iæ¥f˜äq|(£x8V‘Šã3ƒˆ]»” Ò*0be¨°#5¾§¡è‘MÊx›X0¯g½«Èâ­–êŽÞÚÁgáó1@¼aå°Ù²=°¬h´;_ÞFC4FµÝ£*%ié†'äeCÑK9ntlV ‰ž™’Æ‘à:iëC9ª*‡·§iâ3‹b4‚ƒPK³5¾j&JQ@z+F ,#Q6ʵ´kï`bäJ.×^Î )iÄêvº‘rŒ‰6Q¨k0wçc+z;EA³¾hk ·ÄZ4”!÷îõ5M)Ž4ܦˆæšÑ ¦ŸüŸéž&ÿï?}éçʪ½Ñú;úéC£êÊÈô÷S^_kwž3^c¿ÏýÞrìº*>äV¿¿ˆü)úØmâËÎI ‘tÒHÜØêluÚ~&|f7¡TΘ77lÓ€ãDc#5çDŒx»S &´21· 1›l£'bF–åÖ“qÄB2š‹õ’,Ter¢Ö9q¼UºöT²ÀÐœj¸¹¦²dÄ…”9¨´SLŽÄËÌ…’™A ZaϬ|C;öÒ®½-j†‹´ªÁôÞŒ¥¤e]Jß1§×@l*œâCr¦[‚Çã9¼P@™è… àtДC0]#áŒfØûÓ³AqC­I*V÷Á“&sbÓ-Œ^,\ņÊy¹`tœZiAȤ ‚ŠGb“vHƈé”OR¿ºkYþkÓ¿©wóõä½üÅïŸïTGò†ÿgÇ«Ûë{ç1J6OøÅ)ÕãWj¶63sr²Ž„Z™ÓÀ˜0É©4NX°#I(9NÆÉ‹³»ÌlßGqªVdþ¸»­ÚcºLåpr¦v‰ˆa”G›Q#5šÐ&àð¼Ó‹0œ‹Ô„¿L¤—ô#fÌýí£#/êüj̳˜ ë;d3ÄÐãž,X« n¹bŒI”ÈòQ”pÔ.6ó²ÇâA±£a©¼l±·#f*U¼Ã2ÊeÃs]×›ËÍçW]9wP$$¡°`ÁÝšÙbЧ…ÂÍV¾þMw+^ïæÂ" 7¾+š±]š](Ò†‘ÔÀ¤Š¥R —mdÓ×GóÕ¤ÆúÿtD˜(4 x8)#5Ó°ã —È’4û5ÄlËŒH™˜¡#/§ao|›!ŽñBiNb™Ì!8˜‘±—#/’ÎoàDJÃö°Þ[áË€™%À‰Uº;åœ3˜aŒ/Í8kÒ fA#/¨í;æ~doa™]7›8:›ÙÉ°Ê`”ÂBLìívP¾|l¬kåóñx ¶Ð“ZôãÍ©u4„¯fù}’Ê]¤6ªºÉ²¡°,™&M+ˆwònÁµÛ#/à ƒˆ8,·äF Á‚÷r7Q¸J-âœÎ-“vmk­tQ6v5#5',ˆÇjŽÚÔÃv+zâ΃®©à+GÉcvs¦ÁÒ´ÝXÎÐqšW/€š!³X:XÆ1–¨qïìºÍfÙÂn¹ª\†¥HÕÐkƒ… µ‘Æ»\ëÙœL‹O¹®psnÝÔç\“..L“Òª™Zµ–ç%'frf“€ODHåaô;ôì÷Ž#/bûõL^…vîóØ\“#/ç<ÓLEç¥Æ#ÀŠ5x^éö'>7®±å->6ÚW¤òßoÌùëµôSƒ-¹ò~ÂÄoƒFqRæ2>De^ÌF/K©± ·}`²ÿÔsD!ô!à˜ÎÉŠÄç£ÿÉ&û|¾=mêw%²êOçÀõ¹£~k¿ †§µæesQ»?"ë0òJ»ˆØ+Uny\(·˜›qUF̳ÁSl¨·ï©ÆËês¶Œ]$„¥:dsu§‡å%ýš÷̧_#5sûL†3Ï‹{7Ó›fïÇ|2SDï錙49õÐèõi[ã>•&™0™2@×ÄrC’™wì®ï·ñÞfŸË™ŠÖYmsD¨ìz;A‡ËÃÍõ:vYÁ—Ášˆ˜1bð°]2ÔøÈCæDv!ÌRoñèqb|¥)iÅpg“¾«ŒÓ'šZlÿ¯GL·Û#/{Oíq„g=ùo¥‹X[èÃ¥¬@c«‡‹„CY·2Kdu£é}ÞˆêýÕk·;9Œ5[þ½§\A|+/éwÇè£b $Ú-2 exìÁ2f*Ÿ)ŽÑ—-üqÈØ2ô’½²\3°bB„b`•E£ú¦àoêf/\dÄ#/$]‘ ÉPq©A;HÁˆ¸;€Å3i»ø˜ô3žÏµ®³¾@˜)à‰DËùÛœsª¡àLï”þ¦íTãÑ¢¯´Ò©H©‘¤Jœ“ð&á=Så^;Üy¹…3«€’ƒÔž…K¿‘Ó#/ù²ôa¼#¶ßJ(¿¤ð©'ŽôZen· Zoí¢£Ü²[¹ƒ^o(5úÅd÷o]§h=Oh’G·&{¥ü#5dýZ…ðúgHÑzëºìCZ$V¢ð¼fS%¦Ã{i› n˧ª(“ ½‚0GË«ãšßÀ™)'¿|YÀôxÇhv¤™‚!Ƽ1ç׌ìÏsFÍ[HÜÑý½œuh劥ûÅÄxŽZ_)éúD©iœ¦jL<¹ ÖyÌc†Ì¯E¦²OóON4Z”ãæ&NFÛèÀ»C¹ÀeÑË5Üß$?ääS¯?ÜD3ÊŽ¦ÿN6ø¯³ v‡«.å:¼èÆ!€Hßã<ˆ]27|jƒ$Ó‘î¨0ÜÎTé$=Ì“,aÇgG>ãôDÞ‰á@'û.'Øøñ£_%æš·‡ ýUgn=-šåMŠroš^bZk£œÓI«&˜t:pé²2¬-{n»}nû10ÙÕcb(€–æº_FÕ±í£+ÅV›-÷´[}ʲ³PíŠÌ©¥ λ‰¡ÜëÂG‘Üv¨¨3^Í1'bøŸ˜ö/M˜ùöÑ„níevè›;ôJª®åÖ)l¹Ê—qµ‹w–‘¸Ìv]έ–j–f»ãÄ;ÿåQ_'.=”Ó‹÷¹”+Ãçå³ßá~ÃÝ‘œj°Òaß‹ˆg—Œ÷ÊXÆßXl´#5¬ya(\CÒv»±Å¿w¶í3Þqf2N"^JHç—æÊØ!þûÖ‡ø¬¦ìîË‚ÞSØà‰¹'*…Î {æç\•¥Ùq#/3”Ó†_gÀ’P—]ê<¸˜þ_Ê篵äúÞø¯Yï§:pùÁ"&¯-P&Ð5*¦÷¨Z¦–¼øL‰Ê™¶á™€ÚET4 Ë©:G¶ºXØ_sBÆ;2וZ~gÑqwF¸GFãÎ"[1”jjáuIý&™çà®V÷Ú›zC¿‡lg* ®¤]ƒ Û]jP‘Pí-Ç~Â#/Sa£â›[ëf<òÒ‹àrª9–b’ÐÐvÍzg¦­°¯\ë|õéQ’ h!ý^MÜmûcÎËÛ¸‹.Hn%ÓV3û—¬O¤ñNc3ßi{=Ûæ¿ÉÕ¬{ÙÛ|Á6ÓR„ÐâZôoÍcž.±ìÎäi.Ù(Ûa–U%ÎE;Å·¾aÐQŸ&Ò-FL4aØW*µ$MÚVÀƒ ¦!ÉæIˆ9Gתªúã§bDÝdÀ:Þ¤¥-WjjWÈè^6ôìUðäéÝ;§·KWñ×UvQ¬·.¡„*àóJ#,Ü‘$†s\’8¨±Ê'ø {ǧéÌ¿=sœ.ƒø/奊8<³W”¾=¦Z8l`ï;1)qŸZ·zΨœ{¹ÕQƒÂ‘ÌN'â{#,ï“ß®FâÄ›nØÑhùÇ;mñ1Mé²÷#œËŽ™q(¸VU qCáêÂ%I<ŽÎÍ™4s¶äH“°‡¿œË51€–$1¾È'lLq½-wqVaé¢4í&n½2/½¸œù§Go\ïµ\²t“÷—%øó¶ ìÖÉù*£ß2Š‡ðÜ÷ÎL$mð,¨‚<#5ëÆS2Ê[Áïs}ÌË¡¾Ïûï¬ Añ×R&9ðrD·,Ö(ƒKÉ賨Ê!L½FªFv³¦Â²P!f¾òynÌi&•îëaÁF,Î=x)“Re¦Þ¹=5"^#?#eóO•Ç-½eÀQ€~²,Äx-¸Lª ôÈlgW‡ÕHþÃ×—ÎÌ£}Š°˜ÜˆI n±hš{a¢ÐŒ¹ØšTéyV驵ú0ÞåèúÂÃýaãþvD^fÝßü~îMQN„ÉAÝWG~ïÕóÎÝŽÍQæ3]Ÿ)û#/»lÒîô\ñ|Þÿ•ùöH—ç.Øõ×f|`éøkÌhd7ˆ}g­gXVÖX%AE¯ÊŽÎV≟ £}ï õ/A ±ˆFõsÅÕY~’‰aG6âq¬¶©ªð;ŽÝJ*8…ê¦9íûüBºÊ—7o¿zí<œ}*ÏÉ´Q¦m¢ŽqI«ò8í8ZTD„¿ËúÁ¶[CNÒVF·¥üÅܳk%E^VÏ4Ä[w \3:“ñ¦jüRk)rP௼m9©¢Ûáe7ßÆ«ÌKpWW>ê]4÷‚ÂvÝ2YósÆuJ*rºO$¯œpí´Àž®zµÞÿ¯ñÝðßoÂý¸³°±ÛƼv'®’ŒfÊ”œ¾#ñ·H¾™ýUèi_Âëì}ØÅH¹÷D²ÌøÆšêãc1óI=ÝR¿™ùƒYSeY8=ùóXlY$®­]œ|•t”xJÍeÄ´N ÌŽ<Äckº\y!ý³ú<’2×–°ÓTNzw“^ÙPRiˆK»?…¡79ƒÞÏó{kõYX~›Æêãºmª³á'ámYªÂ™ðŒo€ˆ‘ "í¿ì®…e5,¶·½[—ÊP±µyo,­ž/ m±ë4ßH"$!LÚ&tŠWsW•èf5ð5fH‰l*;Ú®LOt3dcu r®‚#5a ô‰I<%Ç(G¦Uöø¶êªÚê.x—‰ô®Ô’—Òqðƒûf=b¹oG*0'ÍŒÄe{ÃË,bDŠDîÝÚ) ¼òB=‹¾Qe…£ÃG9l5až¼üÕ«¼s*+ó§¤ÊËçÎ̉{æàöþJâîÁìEiˆ‰díÊ£²Ço c[¥¾ —÷>ˆ6h_TvtÞ¿/>JÚ1†û"•Už5(÷ónšÜ2â*KCz×_[¡bú–QA]#èºfqiׇžUyNOS©çžq• ˆ7¹¡u×ø'Ò#5Ñy$ü rdòç53„å®äûÁÞúv{’ÜÉ-q¾1©4L“tpºo¢ß6YÍÏu¿"˜Ë2óWçØΪ9½VBâ§cÆ[Ù#5U;elóÌaWê[Sk\òVôËd.¯‡§§ÏaÌn5Ä“ß$‹Åó5j‡wǺ¬&6ßKxª®kk7q×î…ƒÓ¶d"õäö¬`|¯H²E°§ˆ©3êäÎ÷=k}ZǾéàŒ3÷NµŒóóßïX^XŽžÑ\Ü$Ξ‡Hi%ÙF裣ü|«<ãD U1Ÿœ{uÎ?o!¸Õü7t¯+Ô¿hÜôñkÓq3Wùbbüó-Æêxš…D:hvUƒÄ:s¿ãÄ÷?jZQ¸ŸG=y{ðîºâºã8­òúÏo~$èF øó'·7à 4³Ç ßWÇžkÏni’´9ùêÿ5Á£#5ªÆC¯5ò9çm±¡h3?¥lMAòÄصÜ`[U5¾<Ãœ¹[Unü±>Ü3bÑg\#uNI{®ýü秢Ïw>ÅñÛÓëY7ÎàNƒ‹•ënåçu6Lþ55Ê…vYª nª¨GF±®9Ú©¢Õ†’)¡¢.žÍ<9秊ãZ”YîôyBÇÙã™yj¬µÅrOíÎpe{#ç³êùé°ž•b\ãàA<`STO­ùžÙJ÷YŒL.g´šƒBV•Ae®ÜU‰®¸bU2²Õno’Š¯]`ªD{ÜTõ‹©wjuûD…4ð<梺âcŸ.ç”´}O>k¾úJb~÷n9ðFI럿›ŸOÎ#YÇB*4/9ž2ÿWö^“¬my$œýL{7½D°Œ.É¢98‘}ÑÇ—Æú#à¯:HóÑû®™Jk‡a›”#/û¥ÀòÍó‚¡/wéñã»]3¨mWQUpÕͦý÷™d”¢ÚE¨Ó^£sñ¤Ÿš¼ìÇÃzš0EüþŸ-ü+÷aöï­M‘kÕÝ¢›!Jë7YOß+O++^´A— ¬Úõ& SØžQ#/Ô2ÑG¯#5BAÓhêwlÍ*ìN§n-z×!å>+­5S¨§]S5Oš¶À°Õt#5ÚîTt>ڸϺSŽP×…ÇÚêz>7ñŸ4î·©ž"úxí0µÝ¯æ çzºÐXnß9~]ëVƒîÓro.˜iÇG¥\\\¨$y«…ȼÒAðwÉ2Š‡ TÜ‹´ N“çW4f²F¼Ù¿WÛéJÉå–Ëéﺙaf¯ñZF–Å zº±™$?CÀÍYײÖÌeÅùw$ ¾|µ<.‰_£æa«ŸÂ¹ãXGãF¾dªàx!ç+xóÔë#5B:&adΓ RÞª« hR#5DMüíÚhDc7,O=P®Ã1¿e0¥Ó|›e’ɇUlêÞžøü"¸í^UàPÔ›¿z¸nŒŸ¿=c&÷Ë—ÅM%çß”;º>^X­Ðß4}ÕÅsIñÚ¹¦¼§G{Õ"B×Åå¶o.ZµcJÅš&±š·Bd[× }άù!#5¬¯”%›šPËÍVŠo¡çòWA-«\c#,¶½1ˆD^æü¡§½‹ë¢Šny–„z_„NÛn/¹vÕÔtÞåÏw~ørÎkš$Îcy»ãªcüoÍ`]]¾~.÷ᄦ¯Å–2±†£äãÔøO­›ÄÕ×oÄ£52©Ãö¿âøò¦9ß#/ùÁ€KôŸ·ßÇÕ%½æyÜŸZ×Ãàð<â’¾ªeˆšƒB;s†ò‰n¼i[%§uÕ‘Ððœu¯DzÙÔÔ D]S1áËà ë +FËa  àìÖ#Ç1ú騃4uá2#/óÍôÍw¸@kS.‹s²Ïžwµ¥W‘Ct­p/Yk²Í—xGb;¬;«Ž.;EÇ´wΡ¦;a”'/[Ê© µÝÜ·Bvð«Ç‘(cÛ|7㟨]õæ¦bÖ‰C§d¦™YTc<7WÓ‹éÙUw=Zë0¼ÐǶþþknDqqZ7ÆPlÅR¨jsÕÃTõÕ¿Iï,ù³e šäÆÄ5ª1f÷nM<šÌ¢YdÍèIŒÂŠ³u˜žµ[\­gW…nïƒóV$QÍî>Õ¥÷ž¼TÕÉbåL/éˆb0›é׈֟ŽO³á÷]Mzà™î©²¼nKÒ¿Ôý»ôéÓªéËäܼ äy†—ÃÓW‡ˆAüFŸ.#5{ç®/~ä »ÈúÉmqoG:7—Rì<áá:ߣ2µcÚAuÒ^ºNš°!§CÚŠ\Œ³Ä€ C EÂ|HY9(îKÊ¿%ç#/'ýF/;Ìúj>`Ë_d¥º¨G’2/®^•Ûó‚úÄÈáÞ3—ò›=‘úðóÛÍŽÚ®üëÉtåìùl5J»ÎúúöÉãP?ßïHK×Øá×3¥œO2³ÝY<…òáT LâÊcÙø¡þï1. ËáѤü#/¿kUò„ž—š’ÞAøÄ ÑÈ’ÀÕG½ÉÖšèdÌ·éÅš–»âá3 ø£j±ˆ-1†7ÄŠÑh†K•BÚÕåqy§®ÆOG|`xO Qb(D£ª´\ÿd,¦ò XˆWõÔliï½2뉷íOØ•írqIÍzÎWÖ»,©õãD´Žö‡V·Å¶ûzþ³¦¦ÊÄoƒ]¹9ZbÔNŽoqÚäÂQç·l‘¨¹Ñ‘;¦Ó}óëUC‡Ôܧä -:úÕcó‰TsV씣§C¢Ñøm…dî«„œGlç*:¸IÊyH~Ž|,ðŠé†=Ð?‡n,OŠˆGv‚È–• vHø=Þ’1¾x3!>*Ý»L¡¾¡«µÞl™72éR šÁo¦(§LbåÖÿ5~CµâNá·w©{Eöº.“ƒH^:ì;Š™Žæ’tˆB—zéš³Þäç<&ÉTcKÚ#/vÙGÜPf¯e¿®f|ßÄzm$Ð爄rÿ{Žpr>ËISÀyYCdÅ5)œcÑ‹Æ<ÇxdÖ›Œæíû‘qˆ[¸)’RÔ'¢çË1È?¬·2¨é¬r”T·göl8ÈǤm›É0Ï–<ùËìf&&qÐà˜Ì¯…6e„œ34ëÑ7m+Ó‡ËrRÁ ï³}Pë.dž?g@ºÍ^,嫶cŒŠ:M:ÿ¦ëîÛÕ#,pöÿin-camvÙÒ™¦›ËŽ!hèÅJ¼3m׆Š„¿oŽñ~³›oA1 [Fy]}Œ¹gÒ1ÙS®Šïô;¤ÜI“vÑÂQßæƆ–ú#/»Ôü~¥î5Ù„°ƒÀ»TDJv®Þ_,pcÛê~Nö©ŸÚŽt×ô"ww__§n‚4N-uF:µWø½Úâñ½|~gû†÷bkKÀ#³¹ÐC»–¢— ât£ùÿJàú”äpðx})–) A.ç¢È„t3ïQ¨ÔðP„ó©uÔô,óÂ~;[Mc5)hº,ý§ñoš«nŸÌI|\!ë#h¹,ý§Ç¨V47£Á‹èõíôFãÎ<ý›Q¾9êNs_»)Áëìlîs+[-Ö¼¼3×li2ÂÚ6ý¦ÌJ:nW)C©øý>{­îñ´°ûå®R\¬Ù­3Dɾd7¥µ¿F?H¼\Zœ Hï\ uï?5–Ud!z!Ò˜µI§ëñhµN±#/$Û˜„†tÈöaùáqä³l1¶VÂèd¿¨í‘>¯ûÅCŠ0J¤‘Dm"¯§ò«‰˜+&Ö-X(¥Ìöf†#% !D è1È&çâæH+†›ÂP¦iÑQc7¡`«; sÅJm¥bÑ ØÒUòÖ­U"ª¥ƒÆù@1,>*«q“—pÝÛ¹‹'ª§jWµZ´R»4?ÆXlàFÒH‡Nì/ÈFT†¼ü‘…­é y›œlWƒ#/ïù2ÍÎ_Db´0©Ïí=ÚßKE*ªì<¾éýYT‘VqHTA|ÒÛÿeeÛF\P…äOô³7(Y~^êš½òøÃFº|Ý×[Mh­(÷¸Púö7fî„¿Çôzf{!P¦ÑLí1Ê”9C„5ð9ø›CS¾ÏUÞ|‚¿.fŽwûÎ1ü×Á¿'ÚÝÄgs¬ÏÁ+M-¹=Zqµ®îéjm}êŽ~ÊDŠkÐÃÌR$þI¼ ÓJ¯P|Ñ÷÷™úBm&2Q´û@°”ûÎ’ü¤;¬dØæR'ð~÷òUtˆb›ìDÂI«s’vCÙ¥JEP ÜhQû„c6AäQOê«žó‰6з='ïdXùÎYø}öíöýéo•n~ª3}é¡éS*ïBÒéìÒÖ˜r¿{o³Æì=ž›tÎúͶÅÁa#/J*#4«àWÁ¤¶0ˆS×F—q˜ß‡J6HGÚmÖ…ÏðÇ•Îè=#ÝÅ€V†Æ{‡y¢`‚wð©_“(Ìtñ³‚“b¸ò¬G¯•rÓX|Ulão,þï;²g„ðãxa»D,°ç#5¯¿JÏ>GòwG#îÜ$Ѓ-#,xÍ1w@P¾[wöp øIðúüÿé¬M=SÍRMÝ¡Aô¦à¼~q×Å1¦8D7‰àCœõÿVKÊmðí¡Õ¼N̓íªaì*R¡hÈlW¦f®ñ“QF¥á=Ú¦9Ë.wì:†3t)I†gRó ¢F¨ÝpÀцVÞL®Mvúa5#ª ?3ëιîTÖ‚q‘‚±BR‰½Ì7tñ©)–˜ÒâàmÀG(eA0€ï ¡Ãyßg üåµDŽß”_’ÕY*k~²+Q_Š©ê®*KNýæïN÷JË=L™õ û4¾q×RhíÝK«nf=`{ºàNV5ÊätÏr~]Oø•#@ªtFö«CãP È4 &“"Ó¢{t×H†wüìê¤ÚâòÏaÙPøÞ7vÊ[JŽª/y]‡T˜M¢8áÍL„ Ÿ-1¹×>ƒ“çêžêh°fÑk­bR‚MdR‹sðÓš§Ãmex:×#/µ¦^ž‘,…ðíòó„‘¢Aè{îÆ%ëdõ‚„ÍyóЪ] WžþÒYñ0kNRÉâ¯F9Wdo‡aKÑ|X"´ ‚2CÉ”¬PQìM ~‚«ã™´×a#5bÃï‰I#5Wc§ÁŽj9Åe¼¥÷[n cVÀù‚ßËñÔtÎSr‘72A¹‚Þ‰Ÿ²!t~¡®» ÄT%I³iL©±¾Y-Ù³t£tiq\;’Ño®âçN¹ÇNØ/+#/äÊzñ¥ÕTR8 )#/#/ˆ_#/—#/z—óÞÐ1/g§g–sºÐÔƒž(£ lâ%£·¾ÚsÄÚðuš…pIë—Y GA6Êx=ÌWà#«" Ô;MNü]ìàß‘¬;Ì|K4È!²/Ÿ@ä”CËC´µWW|3bÑ–Šóë­ˆ71žÍ|1€ýË6©–¡¦c.«æÌ<5oŽ OÀCI»fÎÙ÷Ï;¾#)Åa,~~X›Œ3q¨ÝvÀXÀgj3+ÅÕœŠñÑ;Îs’ˆ1âsÆO¥u¶ãÃÁ'Gø·NBæåˆË¬ŽG?£½ÂšßQ˜Á,]ôÀÄXL§I„þØ,¢uH§|i¸8††J(M¥ƒ˜–æ}«ž²ÄwÎÎûAº»˜/Wl#/s•3•GJ+Mã Ù %L¡œ\hå©LU2åkïÍlgß&ji±ÃXòLšPõÏiè÷ñVq!ÖÇüìo8s +#/ZלLVN‹<ðÇEÞH­¦Y(A¦\.{jÙŽWšNvµÝinæJÓŒÈ)«‰º6øÝtÔ5vjvãBg¢$ÐÔ #/#/—`’° 3ßvUo¯#5f›ÞväTšÙ9aï féÃ,}k¶¬ÚÖ©e&†r­ƒnx…¬R0!¡¹àÓØhŒ,í¬f]³>†|f´Ã±òÜ}ÜæÝ/7M¾ãAª•ò)(c5iE¤‹Ic#5m9øëòò9ʉ”xm4Ül4j†A8ÐÀ–MùûAÂ#5hÓ·«Ò·p³à&ºVî Õ&’¸E&‡©u¨<"Jl =>M|ØúÜ4"Rüås¾z§ï´þÈH?WúXRÏ.ï„O.Zè MP0ÿ¼…¿ÝJaÜ"ŠÍ6»._‘»o/<«1•*I ŸßüßÕãaʪTz¡ú”3þ¥6ï;M©ÅX}c! ¿ D&†aùº¸¿ók›V~tÓ¬ ¾0ø|eƒ„\gn$„¡›#5˜q’È:3þcÃ|½I&ŽD?fró¬Öºd9 BMtÃÜ¿u«-ÔÇ}8A^ZO÷¦£¿Ãã ð`x¡C†QõˆV-@‘Fè‹€);‘ Hb…˜{˜¢cÙˆ_c…9E’Ý#,ƒZÙI¥€Ø @ÓEL0î*"¯àï½Å.%%°R ÈçzG1”×éiEJ”Iá¨D*ΖÍ­‚í3<6f"È,²`‘¡Rè`Á…ÈSuï‚&g·X@’'ô q(&æ52ëI|]îëúóìóc‹/c—3³|šÿ!³Ù¹ì<²†"³ãöüfDÿ—Ë]q?ãÝlú6¿½%ýÏÊ[ûá…ÒÈ’Ä#/^!¸j 9q‰öŸ—ó®LŒý±=ŸMüÕðó¨(¸òéa‰épRjMŽTZ˜XxŒÌÁª™e1âcHIŠ~(´É{^£œÄz-#5ë?èÕGJ‹(9¸ÖÞˆ¶ˆ?£–r¨gCiŒõ¶>.sÎ`Œ¥é?äQ¦;#Ýçλ´ŒÌcr®·w’ŒyÖÝÉo Þiî«“VÈ,Ñ;mGJïlò) ]Ú,x3˜»AûÇ##/%iˆß!’aÇÀñ«Hl…uÎ#58 sV¢;Ê8–P±‘7(•¼hšèWÆPa)‹—/zU#/Ù;Æhê¨Õe#5OöÝïÊå3Å¡ ùü5!ä#¡ÄFŽíoÕ¿eCö[Ü:12µº ýp:Dì>F͇ðš(wQ–ëgaÌü(0Å¡{zƒ¼Õ+«ÂBCõð0óÎÇQ‰Eø®jøu×n#/,YÑ $dŒ‰^æõO39:Ñi¦¨©H¬PYET,í·¦³ q˜<ç3¹5wæm³GµÕºÖ&â’ð#/3p²»V`îƒ “IŒ¨$ˆ#5ñ*€¤Ý*”P!*¡Y_ŒA®D´Ýéó×õŽ}´#/B<»XÔ”î Â"B(T{#/Õ‘Œyõ†#/Pyög® 0ìÁ[’F pÎ8Ûmymp΢»H]!º ¶ƒÃ?9r':”"‚ÛMP:1H¸7 †Ó0´Nl`;(ÊΆ´qÌ£PKD}|ŽßUµÆ&>ul*ºŒ4¤TÛ¬à¡%Ýq­Äk^ø80 <'¬OH<,u³#ÛÊ)µ¹³·<ÎÄO}FÆpW|´yÓëÞdLÈó¼¬dd¨ªNÝÎéD8¦3¥ë#‘¶!ΉÎ4E„€gÒE8T„#5¢«­%WWMµí‘çö7UŒB¤ „D N<èdPF-©KfP‰"GÏ꯷/+Hå5I—té¡D–•¡/TÑÇ·€ˆmGšNG•t×¼ÈuJn1-Ȫ”%•É•37yzI ,jzüS&|YóÚNj…ÕOªê!äÑåR—(ÏŒ«òó¨s1ß>+#ÔÁ€‰Hˆ Õ\^âÞ¦„*pEëÎN>>ôŠ#L(ô1Œ#(.UÔ¸O{ɹÓ5D¢VÂ% ¡R] (׬Øó^Y¦O sУS7Å›`–C‘wÈ¢*ᩈØwÅ„NÖq°V4Ï=¬9ÚP’ ôa=J˜JúèC#,õÑAˆH=ùaఠȼHÐ}›=QÕ‚ )¨ÉÁ†tâæEÚékag=LÑ+¸ ÀMä¾ÂÞÃ)€Dˆ©Nï$[—”$!!&A… ¶àûº#xK"¸æÍú,M°¨Ïƒ3rçÑr4&z8éëJ VÉ›XXž­ºã#[•€`¢Z;Õ#5„dñÖótSO+k¸s!u~H£óíWZuË' e*:*ôÂ#5·ùÅóCr 2'o h(:¹ôÎϲ`L™²ÀwÝ@ ‚‡,7–÷ákW*ã/Ü-SÛÓKUB¼ÀZ#5±SB†Ò6é¾ÿ$çW(ŠÁ¹M‚Î%éCËÌùð8éÄÎ/ƒ:ì¢f‹ºêgÕæR‘þ<Ú#/1³Thõzõ½Ž…Ê®©ÑÉelUdà‹ÝÝßœB’“D¢H$ mTK=hŠA0i*zšëMË[ufr­7 63PA™ã“Ý9² N®ú-ŽX󹌊t;‡T±ñöÙPË1ømÝó³2RH(£XxM‚üŠ(”–!2ÉJöœ9ƒ7>®SXøžÎÛäc$õÆÅT#èær•8"p«ºÜyK}³ÊÛhŠG4!…Ä'–˜Ë)Õ)d °ÏÖùtó-vEØ…ª…[â÷ÙrCÙÛq[¤aÒ¸2.¦Ë8¨#/…(Ê6 mžJöU÷ùKf»QÂLï¸:kÁ’ȳö‹>‡~N•\&µÍ¿2BV~c‘˜ÛË7¯­¥ùãnü¦#/½­¸›üæÉŒy¢“ÄCØœ›4 øF¬ŠDA†'¥iT¦„Ù6¿èº8|#52Å"šê),(5#)Pö¢p ô9QòHmšt¯‡Çú,ë‘\tváv–‰ÛG.K} vCŽÞEâ«ÜÎŽ1£d4>?P=ˆ¾¶•M!5H«©Sà÷»Ñ|zë¹ÃÆÊ~x!Ë£»4­7ãíŸF'é’qŸ0ƒêìÎt,#Ñ÷¶ØðÖ[†A1,Xwl¥áý#5›ƒ{Ø‹KK9l£‡wÜ·#,ÝëÁ™¹!×I'D:u”ó!zÐÖs,ëÃ×ykåälö;ºÃ@#5L«qž½ÅZE µÅÙÍø̬#/¡uò‡;²)ÄCnûôõuÀófµ´5W´ˆó~£áÆç"&à±Î9Õ)Ò#ØA„-3aüFðÃ@J2ˆ÷}šyÃÁÎB;Zv`äYÔƒ¨­‘m„”ÒÅ£Öº©,É%)š1D5$:±0ðlT¥ªL—¨Øš57ˆq•‚¨=š%$7š#,zˆÞÛ˜“õÄ4—õzm‡SêS‹ß†t;ûùËJ,Á¯ìâuBuR!¿"¶Tï‘Iȃߣ5~#y5‡–$!¹t$à‡cò¯C™òlzEu]Åu&fr²Ëò^»j`…KJ ÐE#,Èôò–‘Ñ6z~ç ­œ›¾M‰:êƒÛ A2›ÉAÇÏNí»vlÃ1vkB>ÖÜ€–£–œ¾êسµÍp?tL“7‰1Æ÷2>9¢X’˜Öã+s¯:Å€°x~ÏϘdcDú>þXüœvÌ~ÿB¨e’¨o{l¾P3Š\yÑEºzC~à”äUdM"aùi¸K£š—ý¬ÌÁÓ(ò£ËËSû&R–iâf챇ùmåëÇÙÐÌâOt ½<#5VûZ:ï•»»\œXJ”ùžääÄÚ%o|©¾~À&b º“A+¸«: @Ï#50‹Y™ƒæ3­»ztÿa/da1A_âýã¤?Ô‘!!Êa/à ¨ù¾ÞtÙ]a¡¶&»e‘‚x@=æI®ûXt›õ ÂÌQBòüׂ“áeuÒ¯ÇÊ¥³éñÐ>Úôbý³Óm¹EoõÖOê•ÝÓwYmuwþ®'.pQ̆!3só÷œ»sñð»„#u1¥ygW[Ç#ùØsaI þ$¤¤(HŒ‘B¤?£%6¥ L¥þOyaýŸíÂ1÷úZ¨DoH˜j/½Øúañ|bB/ç‚P2w3ä£ur¡ ¡Ã¦;ÁqÓHq³äKD¥–•[Ž8V¾Þ±«˜öYŸ¤›~•ØÛGÔî#5šÖ2y_–Šçö~eÙÒõóÿÔÒïÞuø™†‹]fW—x€ Œ/®éîý÷ôá}•?ƒ30_¾}R«6-bj¬y‹;#/’`o§~VíÖ‡(uD×Y_s Îj&8Úc_¿yŽÌèfø¢e¡®G4·‡ÊŠ$Ôzj¯Îø1rVaD£ìkZWGó¾-·çg2mjˆ•Š¸gÕë}agæ+ª%ž®Þ³ê6açãwï1­rN–›Ns˜5311Pú`ŽKt¤yº¸æ!èóËÇwoëÅ‘`NÌ1/ú(KôÄkøÞ*²>²Š$>@ªˆ«ù~1[Þ+óÿ9RqXÌ°Ìr…§#,&éùúµs¹¥Cõ¢R"é&H<ìLjñã·¯œ‘º{ú(Ø».qÑAãºÉÂû¿Ñöc?‰.îöhD d(ù|mû7óê#/@OÖÈmLoO`•^.Þ²]ép0ÕÒûttð†WGš)xt áy(kÈóaöÙwu+°uÀ-‘³jß®Ï(ñ¿‡šÞÑ:l ^ÔuyãÉ¢Ë`Y-ŸAßêÜm z5ÄìØy½òT‹à禇˫çÑ¥"ß— ÌÁ'á9´äiÏ#5¡–´ÖÎÎÃ|©›fÇ"ÎÞ¸] ¶1z¬ë1[ĺ•|ý®®Z µ¤Ó’"kmõY‡lkø=xû|÷¾DYe-bBfGC\¦"ËÉ.}yfnûýÍÞ½ÿ5“Ïœûvúc1#,…† £E˜b"®P»–æ>!#ÚÞ³Ïí9NgÅ®¦ÓLOpÞ¶f`ý ¢'ÞÆã‹eå3šÒæÙh õæ„€’„)9⬣u4œ9À¯ãßsª"➺_ÂMÿÙåöÞ7Öÿ‡5ö¸ÒùLÃ.ì©"¸H¤{áÕup”æU“g†:¶z8]›½™˜}‡ßš2Ûª!Œ·@¼Ç3‰<“Nf?¿œi•A¨àÅ^½# ¼õ©ÉÛ<ï^Å¥ÎÞhmöÞ-4î¼3#,¬ßÕ½#/ÒüNªÞ,ÿW?]®É߈!Vâ šæ ‹¼Ãáà=PÌI êEš­/l×À’0iQýñ¿é–õû³”´wÕ""ª‡JæþöâB™PKE¿yŸžùçµæßþ¹®>Ó'#5|#/y²‹ð—;ÇÓb·sŸ*Ž/›öΠC÷xëƒñŒ’ýo‡×.^NÊ”:2t¸7·ä¸õ²OĆ!8KÁÛ’¥r„¥i‰(<öA³aNbìñ®SòþëÊw5Ú/ã¬Ow•Ë<‘0üÞ„z*Û/1IÊNyàÛõ¥w4Oª¡Ë^]¼/ ©/„»úÚðLz Ð M–óPÐòF×ù$sžHDŽO\°OQv¾/Úáªuñ\̉zà}Ûð‡˜ƒåÔ“¯Í¶N§Ž'¬âÇzžñ&]›ÇG:ñÄq£®ë~|Á83M0Ŷ-^\{uïŽñ×z+îs>ÛˆMgÙUùb6vLtOt*dƒdtºŠóõæèj·C‰~ÈyRãÈX¯~Lw$êéjãΫJÏœf.(ó|v5|cw1†”YùÝ%;ó‹;vÖ{ç]ëSª0¥“¨{ý#5™O~ªìù–aÁSúÞFÒº}“#5 SSa:›; bî4Í‘ÓM0–vñ®•8èL±ßðu_z<ÍQCØYª-™_¢eœö“"¡Ï¯# §ÒðÄ*‚Òð6¦yI¼GTWUñöò¬·/dzI#;~÷?N€ÀXó‰gíÖ©‹åðÃ2ô´ª3·kÓÀ…˜¹­1Ý›è›W®Ã¿.’ýQµlUŸõ}à«¢àu#ù6‘oÖé”ùÃZ¤î|üeyš¹áŒ|ÓÃ?u#/äˆyÌž0yÉ e²Á©}?6ÃöKžk›öò6^÷Ò$d›žÓ¬ú¡¬õ}lªŸAd0­•÷)¹eÓš*ŽñbfŽ\=~]H3ÑËÁGY'œ{l;üÅ8,J»Åž¤c.ê`ó—gÃG©½êÁ„çƒ÷¿ö«3õqà[Ci30öÔŠFª^;ÎlËškF½µíáøíwX56ZËY}.ˆsŸœušÿVÌŒsç9§wÃWi&yZ_ycé'-ê0ñÛÏ̽%êí¤uàÏAž«¬t?whlŸl?CUÀÓôÙl™ s¨#Ê·š¬§dÐRé.)NÈøõ}­¦r“öGüi©Ÿo‡6#¥Å)CýW_™ègß. ì,O/óD(-_ZÉA*9ìæZÜŠpÔìñ‚­þQàÌçÛeÁ×$n9µw;­-k1æ#/Ò·ÃùÐåÅÄ1èSñû2}j—Ç07ß?†ïŸmKó¢Iîìì‘lÝKpû‰Ä—æçÓÃÁÝú¹µømÛ¿Jç‚©£Fú%ü²ú3Ÿ)m5S0W–‚k(êN>vZ´9J =–âT*õ;ñRƒþkÀÍ á–¦·R^4ÞpÑðóï#5~§zHßÚžØ$ÇO¾p÷|œ-a{#õâaöýPt΢‘j+Vß3¯ZmY·EÛHÂDÚÛ´Bò…ñ¦dBi]×k%ôKÊ~âfQxô & Û´P“Å1¥8ƒÑGâ ´Å$¿äjêÅ‹ò‘à%ÄÎ{‡“éj£øYB®DÂ^Äi/¦ê8Ä0(O¬DãÔ,|–-‹$ʽ³—­.kstÓ‘Mâœ@Æ/(ì‹ðåñ 4(@vχ$ß㦔葠9#Æ_#5…“ôÌtMô4aþ¡G.ÚqÇò"Iêƒ";¼ÆøZó~”±Ë°#5±¹Ë£]õ5äÛ/èCKK–S¾üdûiÁxjÓ!ÒëqÄ ¦mäAìŽV-Ñ#b0ÿ9¢P“õUphÑñn‘kYB.Åã'Aˆly! ­ýw¬ÚmA/Ò³4ŒÞ¿Yþw6¿1…1>o„7?\/ŠM„‚ˆý±<#5³g‡‘ã"ÿ«îêÍÑ ìMSfé‡ZtžY´>õ”µ"ÙY:uè©×í7R§#Ö9D‰›/;¿+ü:ÈLœ20ÞÊ;ñ¿.ÎRýUß]§ì>öüM•cNnIï»ô#/OÐËâëøë峿ž,MÂ61ú¹§ù“Ë}^õ™¬'[XŒç*« J¼ßæ|wªŠsiùHÞ´½Å V’<°>ì³Oáð›Â+¸7þNE…»‹È„œ*jýI@ùJ„Hà8;׬×sº“uÁÂå¡É 0bî.ÊT÷À¼èôÀºSÖtǪ¦J+3½N°dl%ùðfg kD×Iú!{Hë_wçÛ†™Ï¶>ØéÎÇeâã(nvç"ìÊ<îB.&¥tÔwtô˜ëCYLæs¸™ª­$Ýh¨›±e—de^V©“ÊÿÇÝŸZ«Ûku$$Gpq3 Ý€Hb0PëÚ‹V#,°;«ÃO­=zò&°¨ã¾ZÊe2‰š7ˆ„Ý&q!þ±ãY}.+ÐWæ/b\îñ œn&݈vWdH% š=2ƒú®¹†!ð‚-Î5·6÷Ál÷ïÆCÜÅOèÉ@&àÕ=Js†¨Ï#,y]a>”VmÚ@ÂÊÕ{­y •OßAׄyáÄõ‚„× \ÖÞvæ,ÖTö²Ùá§N-e{ed:*gsàC;º¸Ü'ÆùJý~lŠHg Í®ð¸E¨‰W7‡ŽúŠžu+l¥­uSf½MÆYÔL`fe‡#/k8î± uŒq°å‡›9,èŸx$YG±©ä‚C¹ßMp­@üpÍkI·_luÌÇPaw=µ„H– w>õÉ©;qx,ÔñÈÂCÊX°L!T2šj‹vúˆeÛ.l:¼Á Úesj“5Æ2"X’~¦·O—¢ÉØ{{aϧy¼}á˜Û£ßÑ·›nÒVKJ3ÏlõʺÍ5N³¾Ò–¾Ú1,iª¬Ú{lÓ…åÚ³ u¯c³Ni0äÅtl_µ6ÔΚŽà#{³“AÁg©í¿<Šˆ{]ÉÓ^ÈsüS™)ZãÂÃij›ÞŒÄ“ú¸@è]ݤۻ¡}Ù¿<0UÆ&„Òþ¾¿7¼õßµ7È„u¯0$þÿÂ/ ˆÒ*‚g¿¶s§¦…áš¾}+˜óŒ 9ð7Ÿ‹®uüE4×J ï­±eóûú¬OÖ"&ܵ*£¤NžÓa•›ÄšcUÈ:bðÌÖxæÞxí*G¢¬¨sf¾&#/f2ÆJ&fŒ­·EVú‘ªfE*ä8R¦|¹çZV2©r¿«„Ý8Mý®Í«¢K¦p„þ•`©} 7É'˵U³QßùyØÞ9åͦQ#/(8z»X°Ìi¯KçÎÐÒe(U”W•0„~³ãøyÿ^¢ü(:zKk¬Ç’ ðŒdÀðV¨jÇŠ™û¾Õ~ënõÞNÍàã•ÊE^ÔúPù4ÆŽ„#5žBGeS‰Îá ¸éÆäiØ)ÏlO>hfëjÜj„ô¥f )•t~×3ߘŸ é BS/£j–n¬+²oº%ºCK›,¬†™k¿UE.ýЇ©šH”VéÃD/$ÏÛ»ÅD|¤îvá×Ý>}³ 1¯(Ç»àÆqš·¿EÙ°¹e% uÚ2öž§µ•ëÙi˜ÎÅÕ,Ѹ.'g±•b¹9€™YV#5ßk¯6ï#5êø*tòž0å#/2ÐRÀJ²Ÿ~Gó`jM½]å‹beýqKAJ`ñb¼­¼¿i8±!#/wî=„+-ÖØW8#,žp²CûÛˆÒÅ\wñ_Çc]îgÑ¿Ùõä_t…Ýy¼Õ×êßÝñÓC“9YH°fôQ¥þ5Œ´(ÛsŸ­š”›Í6ö8e6Äîè…;iøÑÁDvü7:L²í•ÓŠƒÍ:C¾ßÃŽï}y!!æT}£E#/înE ïQ†×ÔÒ&GÈaç´õ Ý#/=Ì4!´Kkúiÿ•†™7ô§s;cQ(Ò>=9\ÌeVŒé,¬,Y9µÜi@{}6ß_ßôÓ¶ëw0RDXìyð0Îh©ê~ú¯=O¶¥6Ê{k1¨÷|=9ñ©XÊƶØd{<³È½ˆRÔi##5;7¿ÑñP­‹R«”*&vl¸VO^5Ö5Žæq&ïèYè_f_ÑÆá‡óãÆ#5mÉÊÚ•äÒþÝ+ß FoÓœpÙŠvcgïøUôÈÈr°R~¹ÛyÜ"ij!”4f¬ä‹¢’d’K°™mí@(wÊaá›=§„õÇ“³®ã&öéQÑ\÷ú'âñÐ9Ý‚-ïß·®²GlM,]ÑÍä_Âyý?d¾÷CW“6#/úénP<¼å¹ú¯€Š¶W•ï6ì­²)†î9÷.¬9>sl:颅\†`ÒúgvÕ‡º9í>žª®ì¢YŒ0¡kË|`ÞÉ6´ÞéßìÕU¨%bÔ[ya·>ûé,ðÙq+Œ­Ci1b©œêíyØë3?TïñÆ..ˆ>Àè)®ýèÍxqûuÏz®Iûúo‡ßÄ`Ö5qŽYøç"­c0¬¦‡c5¶û´-à]¡àl„jÄ1Ï{bÜ…éÙšcçc‡GN=ýˆwä“Fz^`Å#5ç9HªÔmºj­Tœ ÕõDÈùNÛñÖóÆò#~¾Œù<Žù„&}<§åpÞ:òRÝQŽÏ4¬Œ3?–åœÙ½rÕFøðçómwÊ5èÚ@#<Ô–éPúS&79\Ó*E6HÜc>±n. E–gÛÀ: %“È{û°ä½(Ôa©#/Ó±8kŠ™‡nXÔÅ–ÌÀœS4AT(q»«Ýž2­Ÿ¯^M}PÀºm͵L‡túUø#3émk$íØä‚„¹üÆ¿Ç¡v˜Èº_=¶77˜ ‹¦Äån–âÛü æA ÈÒØFQ’›WÆbr%ºŒ)Øpr17ü çXÛŸÏ~è:«Sì~Ê:æíµük¶QË´88öÌ„¥q®0§kÕþ1Æ3ÄÉ%¿ué0#Pè!ÂÛ(¿##œÛn«jëŸf]š(ñÐh0r½tæ^ÃDYÑU{á‰ÛU »jz e~0Ž’^+c´x’ŽXuFOUY’Ëbpwù û*¬¯wIásÏ Z.7³A&ÐATiÆ$óÔtç‘ny[š«­ˆ_qsóK®·k*ºüœ9§ê†ÃÆ&Û`äe´>U\7ì¨Â&ØûËGI8å…û~_¹´€M’¬Y‡·Áù+•YcQTákC’+Ðg.ËÃUò­óÕ˜Ž.ñº4Ý5¨×œ¬gµÊê™S{w3ï¢ß¶ ­™©¦nªÔ·U@Ó\¸±l#5Zõ,Ô,nûdÆÆÔqr¯KŸŸ[߈jî[›%Ÿ&ºøLPIªä~býºaûŠú-ÍÈç#±¹€×¶,Pæ÷s®€Á0æÑeØ^8¹;=À'•¬=a Ó£MÛÔý9Y‘l˜V= Ê;ù˜®J͸j¸ººVÆ}ûg¶~·Ïfˆ;†ÄÚÆPË>¾wŠ¸Ò맶è™ðìÏù£ZëGÕVOA@%¿ùþ[?GÇñžÞóÛõxQÒÇD>ˆ¿ÒF¿”L+Й‡›ÿ›ÓDð˜ûâúìBµÝq< wõWÁ9äs¶¬ÖVj¢ªÄàÊ<ÎS¹9›-[61øØÓ_íëSïòóY{ŠûKãràr—é÷Û{yc‹v¾<ðSŸÉYâæsyV‡Õžâšr_e’ÌòÏûŸ§Ço›—Óù|–~—ól|Š²ð ÷5†ê¼c¦÷~‚ÖoÖg?ZÇVœ‰²°¶Ò#/ü ÏÇ–Z~¿ Xƒ¼áôËö&ÉÓeÑá@ªvH¡9” Ç ™–[_ì$÷~àt¿»6}ž/©\ ö°~ €ßb#,_`éÆ#/ο°`M™BI?ä/õÓÁ#,!ߢ¾™°€åa#±#/é‚6%Vá pU",#,þÇü¥ ËŽÝ³ü_Ôyk«·fDO+‘h›k öÁØ­™?Î=á6˜À Œyu£ íéÞn4LØv7*pÄÔ2“_vC„JÝn5 B"N¶¨Ö˜IµEœoRO—Å 3¹ Èz1~Ĉj á‚U1–º¢¼÷ò[§`áâÓѱîbv½çï°è|}þ Åú—Ú}®h£™¤=¨;!œ#,ÿdE, Þ.àø“­LÒËHæÆåî}ÖÉ52U¶u¨Yþ'צ* í ÞôÂêéú69¦‰èܼÇäÄAO´Oñ.‡‡øwwà¦ôé“âXñg\ÿMZ%Zß²mǸ°FG$-~AæþLéyOø/²í8Ô;:#/¼Úy >²1ò}~G×6ý¯SØ„ÑA`­'šü'ÕjY£›‚A"a‘KQ=eksý=ZŠ>'Ì2†ë¡ÌÈÙŸò“ Y*v}Ð7Wæ=¸¸;µçÃcUŒ%b.qJžº“XŽ\@"âØj.6IN‡Œ$6$ÇRg˜R±Du€Oä†AŸÑ<Š¼Þ¤?ËG¨bÿALxü*UVªa‰‘|O¢˜ÖR<¸€G°7®Ãknà#/€Çï$êÕ5îFÕïSqÜè‡#P-"†Ðñ²ÁŠ#/” )"b€N²cè{Ø\`pRƒK$aì-“"ÆÐ:\ÄNkÌ×"G:•°»°„,dLXÂT­J#/p/hÂQh:†÷çïH+P#/ Ðûâñ#5Ý™y‚ÝÕ¿õràÌ‘DÜã¡@Þ’¡€x͉¿.tJ‚†QÃBÆa2D‡ýd¹ÿ©ƒÝ ò€€xû‹—˜’#5ÒV}xT‚1òÿ+í‡ß\kƒgDÆ‹FhU<è…ÇCßá{‚JXÿÉq¯Õ¿Ï:‚ ˜(8£û<³êÎ&'[_ñÌõ³}fÖD»8RHç»?¨¸û]Á; ¨F#¸·yó4I“O}r$Õ’Ù9J>¥»äpææm9 Pþ{•T†ðüÏ)LHð§qDBD"S.‰Å¹Ÿ´ÚàáØëSHB3B= 8?ê—#/©Ä²í7ŽÿÝysµRTõ4ˆ„ €Sä4§äõþž‚ÕR„ÉƳ¼¥rl™ßm4ªUQÖ«lÕm ÏŸgzâŽý¸ag?q¸8àáæò8Ø?½÷ñqàGৈzNs‹,Xï×iå uÐÕ9”r4  îw`ä]Ñ,Û͈ÃôC­ú¾û-ë~“âF*^ƒä=ŠCÈ$%¯Rff{¿–š´6nÁkÝKIk}/òeŒʆº(ú&î?”û¤)#,ZÓ`ùT×ÐSÂû®3|s§V¸L[¡WwtÄ$N”Î êÒµ~à¤aA|‘¨Ÿñãäû!ƒ»KÓ4—iž#,,±*!¡5@´DÙ‡Ûgpøï]éá8„Ô‚Xd#åþè‰e¦JÓ¥aü”E"E‹|ƒ„¤4ìÕ:#/ú_¥Qqi,BT<Ú@Ò#,‹¼6?i`>|vîÞ#óaGÑ䘮dC1 Ž¬>¡J ¾ï»þ·46}¡öðð"*’™çÖ¦Ór‹Nñ‰Å³¸ÝP ëÒKÓb]ñÄ; #,GŽöŒD6™ø¥Ÿá±d6Q¿¡bÀûf(h©¾=ôÞé4¶xÄ—9°ˆŽF)R 0ñ‘Ã2‚Á!ÌIY"ÑÄÀ{ŽOwy_#,ÅÈšÄ>#×äଠ²‘Fm­Ïð~n5UB"{iÀâœ{Ty7, ?_ƒØ9¸Xf&f4e°³ØºS‘u0bØ.„ Xr!ù_¼ì7œûGû˜=/#,taû¿«÷÷l” `ÿ6…Ïß#$3<£¬m¡F’XÐß =.Y%„êüz¸Ž«ª¿#5Íùnî„»ìU[Ãu<ôhqkÈrªÍI ÕF³5„+Œ|‘ä|¥Ç·§HÞáI®T«|˜U3z5›–#ù¨‰z™Z›&`™±æ\ÈS©XD"“¦ìx N‡Ä£uEÈ÷iVeCMf°»D!cGùX@8l|߯èü‘¨,¨2"Hª~x¯Ù”ã,"s0þFŸó3Í®¤þ¿·ëõXö>ír6ýí÷W³—ÍU¾¦¿¾tvë€μ‚wCÅ¢$‰G$’I––ÆÉ#Ÿ`~ò xäa>Ÿ¯ô£ùDyý¨q§‡#,Þu(KCî!ÏÀ´%±°pxŠ‹_³G«K•ù—·7?h(ûãw|Ë4™fÈ‚Êñd“B¬Þ‹³XÄÄé•}Aá¸ÉɃ8)ÓID¾8ânòHàîât’HßUå]äúO<é'Wpë))¬éBŒCxÆ6ˆ,M^#yk#OFü#/Sfœ%Î;âSÜ÷‡-Q„Søï× ÷ÖgäÇ#,qô¾œ„ÉOHPÑFã›ä!dã²€½ø~•ö²Ð0¨‘#/ú/Ï\èn©¦æ5š6š6»¶×Ÿºû™ fï@xÖ$ü´ºü™Xƒ^æXö½€)g×H#,QT¹°CÔPô>ÞƒðC××÷?3ªOˆ›š±Z}ƒ@pH¾9¥¹‘#+ñ9„ ~Ç~¯pm>Þ ^óùè€F4äw_øŸ¬Óêlªr  $þËý({]›;Óñ7ˆpaÞ¬{E;#Dc‚;€àøx$Âd´lÊ6¤AÓç]qñwžAÅÜÑ€¶}¨Ïg"´DÊ<#,çá;ø”Ú4ÿŒê| ·pœ-ý9ðžÑPõ‚‚Š$!!|á4ȳ֧öKpx('™‰B&ÏEŽˆx'7ËðÌÜðäAjXúG®tŒ"± :dñ‡ÕÅCâp¯¬#5…ú»¿ã )úüt€_d„cÙù+ò }’e¯¾×Vñ=ÁàŸ(¶í~t3yxœÝähŸ *(kŒ-A[0ôº™6 b’z™$’y€\U=@f{8ÿ-´@µÊqͲ4dˆž¿GëñH¢^}ã3DI­VW½´£Ç»?¡>¾†  òå–Û¦rÜ«k|[çäÿ òÁnzŒã$ÙØF$ö·Añ‰`(2½0„*±u4Q“ŠÊÇf#5BËß…44ʽ‹…~ºTN;:šÔ)1J³ÛíøÈf &a™êQÈ$Šª&$0buq’ãÆñ#&Ën¾O5›˜NǨǠm}i§-î#,ˆ¼ÄöOg{®C1 ÷xX#/Ð_Ϭï<Á*B2† ôv;ŒDùÄj¶©vª­Kµg«³ˆ¦'¥'úÏX€ß0>¬žðö+Û¿„èêASÄ#,î6‡nÆŠrt`9+ÀR‹>SÅþAv%¿V^}MLÂÞ7 ‚iŒ3¯Ò·ôýÉ?¼Â)*Ÿç»¶'úmYCû^cCh:ÖiÆÍH#/3D"G[Ú¾#/B31tÔF®¤(wfC‡·OÍã«jç6¥­r„ˆîy­ƒf-`"÷•Ø®[ #,9RÕ|;ªªÙ,p…\À£þq6{˼Ññ ìó”*{€¡ÄcçxÛ°Ùô}FÓ`§0ô‹"¢)*F˜ >òÉÔý#,dû1EÉŠn‡e)Ô}a2}¹ÈÌ„9”hhX±ƒô\ì¹ÀðõWî»÷lËð1¯CÀWÄlŒhãYy°Ì홤w„NÒA$D"DŒQ ˆD˜Ð]È~™b!ï¢.Ì…ÌÎQgÕ}ÞáˆMwÒÕç uœ5@ŠbIrI2qÆöºDfä̦‚‚BLHzѽ`.~´P+g“P}BâQp=èþ„Á"#5° ÄP~ ôXŒ€ŒŒ2bÙ`’hXPÕèR@D0ƒ!#,báE&I¨‚dzý€¡Áƒšj4jZüÎì`Ro<ò÷¡âfFÆG‡Ž›Êø™&AB<A#ˆ°Ü«JQØÂÂõ_j4OP~1)Ù¼ÑLˆ}9šJ#5„IØ­ ÀˆGõ(þ¿ïøþèG>aöCÂï5AÈ#Uçì+)'µ¨£QÒ¡@ ±’m&S3oŸy«çï[;µskÎÜZÕÙB#bA#eSmw^xê³Ë®[Q‹{{>!œ9üíÓè«$Û:ü`x˜ÌÁ¡£Z]kuýà”ÝpËâÌA>²@%®Ð|Š( BùúÞ#,ÃUØÄ4´Ã°Úýú)’^ ”8‰l†•B‚ÁB) #56 ‚%›1Ä„:hf…È|è⥅¬”ñoòª²»ùÍ㜠=ïéveÌ^à„âE¥ÄyÑ¢A ›7'^äýSí¢–q®»´2œú¬‚m8…0-®Â‡lB¶É£Ÿ4{³ž^Æw[©š˜ÛÈFã#,Úf’³ƒ˜ÃÑm=ÿ zÈwwXÊ•®!^òÔÑ$¸Ù;Ág¶¯"ظn骔¬UQ|7¬+ýÀ?nÞÃéC .Ij^TÙHØÛên˜…}`À‡³cbåôoZýßœþé1†Ñ6}âØ«KL© ä â„‚#,ö$÷ &¸’O·êq0Y½¹‚ J<äÎ$ …Ô2¹”Àd£³#”T¢ƒ@’sì}Ýh¨€"r#ÕGSBPJfXâŽu2rŒrÙ±H&*7¦˜ "?P>'°¼ýžïп#¬¼˜“áÂÊô;OºZpìÙÕ!b÷Äã›$!·½Ï #äUóx÷37^Å7SÉ°®¡øï%by寧 bȱ;Ûõ¡PFKdZ˜*ví¥Š$™že¥ìÃxÉÉzOgÄGê#5MÉÁ ì.JGDÅþ|ÞôÌ¢¿RNÊ»Ë%ÙŠ+.ÀÄ©%#/ `ÄÀi1;½…&¥ø(­ÆrE„2–½Û# þq8D\èk\qÙõxø¦eŒ~¤`9•hT¥ŠÈ‰Ì\#…æy¼0nxho„H‡AL““#,T7»Ô#/‘ ¡l÷í-À#,@Óc¸?R(ØC·ÙöÙ.ŒL-ÈúzÎt fÌǨ u×¾øMœä" ‡ê²¦#5.€DìÕ û½X9ØrÄ:æP•×ˆ{ú“È;JéEX`“&@€YØoñ³›¹Ç¿4¬^m@ª1K ˜Ë I2mN/´ü›á2Eh®0­ÜŽ(¤Ùë^‰ûåI}²,€Ü#/ÑÞçP€‚ $4) zj™&“D);&$M¦ì/é×9À£¡ Ñ£D&èä$ZfÕÌ1úñ2:§6A¬å‰<—÷ˆþ¼£e“ë‡vÕrlwìC5s<%j¼™fgv÷§' ò´Öm¶3Dì=çëî”ðów]Ž£S£Ö{RD]‡#5â¿&Î.Aƒˆ+Ū9Wa¤Ö—^¢„Ì¥úÊ#Ú]§@ø$Ä å<“â—ëÇPIë§øeI$ÃŽÄ ;”­l h7àän\ÿV·· L‘ÓP‹É• è~‚(êgrò7·F0ŽrF* àF¯@l¤r7ÞŠà~xOZ/$ØhW§0øb˜¸Ñ ’¦%ª-‚¬LsÝ×ÀáÍíÌìsFEÞQB=õ´ÔÇ\ŸWÜè…³­<³·L¡¼îOÆRù!¨e/¥„ëõ™,<¢h<¾(ÖR,RåÜ#/™ò»w3vA&Ø?¬Þ¿O~÷¢Bâš¾"võÿRƒ3Ðn`ÌB®¥ÑQýñµ}/ =¶×ùc˜^65iÔKVäÜRMΟÎÞGgc›²h“š‚L!0‰IÈyÓvHðGiÕDçi2LÐ/ñµáTÍQþ^G4ìë ™¼Xtà†}p‰‡fì€ D Û|,8ݵ|²Û»ã†Ü3q׋±½?ˆ$ÏÖL@£ÄFL+¦Z÷‡Š4³FëŸ Ýt^ôpBÄ7£AµÁ#5CèÁ-4Hðp\ÆBÀ@è`©IõGãÞ`UîŽÓ LñûÚ(Çìˆ&\ ˆB$` Ÿ¿¨ï°.ªpmKÑèsîL»ÊÀ²à& Z*…ž‡¨àí{šfÐT7|ÿ­ÇÙ Ù=C¡ÍÆþœp„œbùôq¾XÆtL–?ëÐÄŸ€=ŽÒÞTVrG°.µ€\À'Ç8b\ÜÜàpqqÄp C¼È ¨ä•õû‰ªü{¾W€n88£·èJn»ÕG³Ã`Tv°)$+§ªüW¶ ©<ÂL«!{+ò>¿ô¸¤èU–#äˆÄíWt£ŠÅŠ2-µ#5˜ŒíøK•W iÛLY­À_Ù²’#l #¬­ÝŸÅµqíŠns¯ÞT‘¦–ôD·¿ðë?aÈžÔ­µ[i#/†Ú¡+ÒÐ¥f¶f,‹x ¸÷Õsà&öЂA–xno¾+½+'cùorXýºõ½9ŸoÚ—O²ó¨>óû_‰×õD~Gö!W*z&ýÌ*|õÒOö¸[|vKy¿y«¥ÖZæ¦o.qÓ2Ø6 jË A ,«L¢€~A¡€ÚF hàši²nÝ´ÒKÐbDÉŒJ1V4J¨„¨Ò´Ø#4°(‚±P¢¶„ˆ+Ùm·ÂÞÞu­â6ñIXÅ^à‰F ²*¤4ÿ€›Sþ g×#/ŒÜ„+ÿx¿Ôp‚Kf·Á=8 $Fhà BÈ(f¿€~}Bc‹Y$þõ–«Ô&1tõØ4AeòbÊïÝZ¹ôpÁqy :0¢G o~H wt«GRäÜÊô´*Äts† çk *ÅVLv Ä;/¦Ã7ÈLû›‡yêÐì{ȃHDS.W?=ÿ;~c³÷~/ûVñ@è„;ÁZÁ•ßƒlýFúQk¨˜¹Œgáþx»±Ú«úy/Ÿëý3b·Þl§~V’ÀÊe!’/‰ó¦f=¿ r’j‹Ð-"†œšÝý®ØN¯ äW¥¾ïÚ“×2 t“3¾î%š'3@ø@Dá' E·t@?Þcî.Î÷Ó¿´uñQì±—#/7dr‰Š*!9ÌNcÍØqúý‰F®;O7˜ŠBbqaHÌ€íøâ>>tɧ´ƒK×Ý7–1nóµÛì ¤W”P0€™À-PáBB™Ýõ¿Œ$ÍR$’R#5Á¿å‚"Fd(;ówI›Õä¤2dxDr¡øïdÞg¤qÈ!¼w ­¸3g׶£û[ØÔ)‚¶6åhJYšÃDlDÁt¡É#>jä)PÌ Åáù=nÌ7*ÛœˆA'P÷IÊï…ü†%l$Ž°¤„dàü©« 4¤áhîÕ‹@+!§§v‘‘²ç€k»ˆðsZš‹~‚üSºŒð!¿ŽñMO¦NZ3h>"Á#,R]"Aˆ HZig‰#/yš†!ç-üا“p¥Òûù¼Ÿý=ƒ´3‡×U<’mE™^ô:Œ‘EnBø¼É8<Ÿr‚°ÿOƪçÌüËšS¦¶ï©Âó¥Ñ=;iG\•;\×¾f óDœýLŸ¬õßhcÉË ·Ã_ÐãµwsI‘;-”™˜¶dˆ1êË+aïòYáT³GÒµ@ªY¬'îqÿgöŽ`”êhiôA˜"ÈžNÍñ»0¾D4ùµ4ªý|6¸ä¸Iµ&Єîu ‚¹ûàW-ÑÅDéW2Z9{š¼©%Ý$‘AQ)‘Æ|²±šôrE—yÌ!Vî=!#/iÊ:ƒŠaË¡².㼬†Z(}ø›U}¦¶BÎ~\šlG[I–÷+_OJܵÕÙv,´ÅË<ÈÃ4¥ß"¸ú A0Ž\&CïÉÛüôŽ>é’…—£EÛ#qVyO;õ#,‹Ž&¤U^#,ÛV¿#/ ÁA¿õØ/‹¯°øE·¼òi$©ñжœ•4Šõï•Hù,ù¡ü-„ó³+°Ì[„¾´Ñý VFl/žF%¦D©œ¼Œ @jñT#õ_UðÍS$hd8eb½í¯\%:LÔPþKÔÿw¾º~ß×µ’Ú=ÊoRJƒ¸›¢ñÝÏ]<áøEùÇ©}£Ãv‹#ÜøZé®#/­1RmªÄÆ}.ÚÛ•ˆµ¡¼F¸ñ×~Y#/çË›ï}&G;/kº«7å¼Àȸ칳\Œ‹•è¦*LFHzm€þ¹ðÔ¬¦×ë­*Y·^ŒíBå<žP¦Ë°@Mü²¿ ¡G5AsƒÚc Ñj«RsÍM¦óñ™ö¬&®Ü§„ÝqQ=%½‘=Pæ“ö„zt–J6œ^dxñvÓgŒïwHB^ÀíîQ#/´Ðº;œ;‹KÇEIõsyã!`Ôõõ¡ŠÒr6;öp{ëQ³ÕU9U1#01‰QS4h5)+5$ ÏQá­½ÑÆ9³•„¼>ÐfY0ã·nýˆE¥lßì{ä8¬¤ƒŒðÕlZ:¶•{V›*_ô8T50O‘ø~>_ô¯çù«ù.ÞÑœ¸äxô¼`KtymG"­Êk#/‰&³j-‘Ù³Ò¥÷YÐa]¹ïXR»‹ü*Š­Ô,Â$îÐéï«3Q¯GeR;tªá¸ò]>§óêåm§tNxPI_ñ:w‡ÞMgð9éy›ã9Ëƈ+²¬þ7=iÛü®ü˜øô<õÑŒž1é!»ŠÏ…#5ÇÛÁ1âEÙ㓶N¥Zw¾mA„¤ßar•š¡‹“;<邺ß2 !£ƒòŽ(ƒÜO~gÆ“µ¨ãX™ž;“0â !˜sG;Ì)¯`¿ëÎáõ·äûÛ§¶w÷\Ñò‡#/s%yOnËöpȇmdE‡,0;‘%°ü þc-{‰éÄñ¯U•3ì¥G¡ê«ƒ~£ßs‡†|m΋ŠæÜfûËOÁ5qow\;>Ã1Ê „këÃþª…ãéÒc}_Xó‚ÒLÃ:nWWwgºŽòÓËÙL:V€Ï›Èk©û¹ò ãÉ{Þ©­q:n³={r§¨³7 \;=¸ÝÐT ̈†P1‚ëÀó°¡¼ŠØˆƒ”Q#,("¹³0c¹Õ’Ü^7Rá@ãÌ„û¨J€ œPwAßåSŠkwÓûÕ^¦öElUNÙ ÂBïxF’sd4ó(ä†àV¶*r.¦ÙÕñ¼ægÝ]zB‚eÑ® ¡”ËØY˜.¢¬Oš©qªzyî­ó™à°dÈh›µý'¬Ì¬>´Siá(¦a¬b`îñ&@@ó rQäyW:ªÐ¤ðòÈ5Ü’¶e2W²&.ž¢ôÖÖŠcfJ3,xÎÏ~º?Å À<’4˜#ˆº€ÃYXa¡ET€0Á††±†ƒP‹J›®·£A¯ 1ÒQLç{8Š™#,p}郛!‰§¬¹à^^©~c^ÝÄé¸t'¯ÛE³{(,$’ö±!ÉaËmª©®¢a«Tbßj;[—!¼êçtvK£×.}Ú¿‡[µwôÂêì}½ý˜Æ­íøΓöj×CYËé§Ûÿ]¥Ú4Ýß¼]…€ã×M¡Cì7´‡mÊ;Š¨®ÈÕSxšŠl³ëd¼ FnË`((YM" â]•VÓŒýA&LJà/Þ•u¶î[‰5RÕýÏúŸÐø·ÄÍe,æo•Úo-ŠÙ]cU!%¤ª%„ƒòþÇT÷´¯±N!é!Q«»nÏ"¼î ‰¿½þÀz`ÉçÏm̦Ñ6“~¬IÁ| ú0‰„! +¬(ÏÚïyr.z“y ¶KK™cDw}’QµÄáÜ쨑¶Ò&¬;,„ŽCÂøb¶Ùº¼ò±EŽœ ¯\(°B,B&ðÍvȆšÔIg1G¼ÖŽ¦à&‚6Ô)ôàÀ„ÅQ˜Iã„Û'72…ÊYÄŽ{¯oãÚ믉|]T-4d¥_¤±ï.™ 01˳³¥¥­˜vyh¦ztÛ,¾@z¬”Àl qŽLBØ3vÛ ›zÍtj‚ZÙ»ø¡EYß•°ë¹«/¯5­NzʺáŽ.éÔ£)™ömk{U´i;ÊQiL<4êh±Ç6Ïqcã×WPr·Ç–ÎûÌœ"#ÓmÛû!wh”Ú^ÆŽ¼ì\¹Äa±ð[Y·¡èNZ)©lxÒ4S ^ÁÏôds>!ñà4‘“„ôî úÐÏÌb]n&ÆCÂF2îgÈ47„ë—(ÛÝçïØe×¼4,J'j=f)c òº¨MÇ8Mý|9eÝážÝwCF $‰dªIk6l~¹zôÉ«ŠRï¬{!ñ6òR`Šj‚Ó¼'ŒD˜!™½Ô22Þ$.¦3 HQ^‹5#y…ÀÆq3šÓ©²Ä)k°y ñÃzÅ,½|c¨FÄÀ‡»ùwu  ø;#/|4Ö >€·8HkÒÝ¡ì¯9Ç\x:GÕ”jì+¼Ü—7ÙG"&È÷(p³‰éz½cÔ&¦Ç¡  §q¨¡9#s oØë¹s2,©Úm#/Œha›X}ØÀÔƒà’9oVõqëÊwx„¹4ž„z/sÊâÆ9L6mt^”üJ†–$9^Æì’s¨ bˆ;xb\ðeÛþ»÷¨¡Rw»êXê-¾HÞˆ/‹™˜S¨dƒÄå @3‡Ã§ÉÀiº¶ø¯fï׃>çÞòÐOoªq›Âc-“ ,#/MÖ,û~ˆ÷Q¶Ã‰ 6‡ÔiØN<Ò¦2 ‘1ÃêŒÙ´×½d$è„ nyJ¦ÜD¦Î÷{Z$æ°`’ L¹}îšÑ\]Þ/bê`ôØȉÃÞ(‡¸Ü¤&‡QD^÷"àš@g0Gƒhj÷{0e! \(ÊBˆgüÿ@â= IMÊ’ˆÓÆmu±)¤H‘HvŠ›@×xdÙ>d¬j;ÕÉ£‡èÒ`DˆCáÁÉ¡ÃæK-„!™fBAG 1–i¡ÇØLái:àÙ6î/bŠ-jÍ~¢˜`3–3)ÝàJcXŠ¿Ÿ¡Ctˆ3(HÔbè0#,Œ] ¤;•x8Î!=–ÐÖü¦©áäf#5E!SNÙ9æ}ÿ^Ìô1¬¶˜³Ìð#5 !Ñøê`v#/s‘ 3ë©n%%=À{#:ŒŠãžÚ1@ˆ9s(ã ÍSCg³U¡@×,l¸Kd\²SU3Œ¬X7Š12âóæ›àðVp¦ne.S`a‹2=Í‚!ñ{dk2¢ÎÇFzæ9.þ—è„Ð¥aO%PÈ·LÃ#5˜Šd@g‰HzNcƒ”p›˜¬äd#Å:úŒ7¥p)¯¯Û%­ìŒæl9æÀŒ{^ðÂŽº2™–3^„¹´Ž2l#/¡F×q[–*.IÔe©RPY.ûsÙì¡Ý>¡­½‚Åžìcm¶ª]ꮪÚ³Ê]ªªª­yüîv$:†ìWÓáÖ—.DÑES1ÃÀ;Æ|¾8)›Ä5Žs¡åZNòcú¸¾„ʹ>Û žˆ˜CnÆŠdm#5ÆëU$5³Ñ3:g²¬’lf…-Ër%a=¥Š‚MXȵ‘À ÎF%F#, q.&gEÓ;-Ùê(ÊjÌ;2a!l†jŠof÷–rBgHÇ"-3$Ç(Øñ©ý° ®z}&Žž[†úíÛiu®&yüÍÅ‹±]ûDÿÖ„ íçÑ>¶ÍŒë‡ÿ:?ÛA£É!Ú=¯šæ»û0|x®Jü"©‹"¬VEø ÿÚ–,KËI‹NwïÝ]ì#/¤f‚…¤¡îòØ^zîú¸(Ö>%Â÷.X`Á**,F"”Y*–Áô( BQËú^‚‡±ª(h”ö\Š€!œ€˜:.m6#Ÿ9 ¢Ã£Ç¾0È?ÉÃýìÿŒüŪÇý?ôì I©¦5¸ô}Ð* °}ªùzvÛgêç³k³)4”ÕÚ·óճdz³ÑÞ=ÉÝJHlü=-ï)¹#,öiÏ &ýjR“Q²ÚdÛ) M¼ªŠ"HƒAHN QÏlÆ€9J·Ù\‘€Äš±iêüÓFFMlZ)rà3íþO:·Žû9qÛ¹xÀ ¬”“Ô.^Š<,û~ä„‘.ÄT¡¨ˆ4¢=Û('ïk©{¬r²5ì{ìUçýe\s´Œa©½‡‹âÒR|“ô÷ " ÌÊ%Œ A´& ¨üs=$ŠOÂ}òå4Ó#,ŒT²‚f®ªD@7)Ø @;ÐSÙ(hÀBDÈàªÀwûõŠ™—ÔsÒ¥ÂIäÅçy°Ìk1EAPp‰V ±±ŒEõÊ€Ù?AÆ&ŒF71ýí•FèkÙÜp‡”¬LhñÇãcí M`¡©³|„{L‰ÈªM°~eŠh•:üŠBÐH #,=fG@–ï§Ù 2cSàuQhbªÛÇXXÔP3–2Ï[ jFO#, kV–æ[†íû¬þtGÉ€+¦@`àÐ@ $EðÒû¦.ôÂ(A0 $ù'!:É÷ÅaDD$E"âD€W‡È.)åÅ$õ[u·[O.Þåáí×æîÓ'Ž;tUÏÕ©•¶¸ñIlNµƒXk#5iB Ð L”€¥BÉ‘6Sü¡þnW,jw^K{"õoK)%4[Þݼz­ÍìŠö\¹175ÒKË»–5Ç÷žkÇ.‘Ά74••Ýbå>¹ÛÊt»ëåk&±OªR*–‡x ‚hDÀÞ¿¤â32FÂRbkËÍ«ùðmø`\ ˆ§°˜¡q3þ‰K`Z6ôYûÈEEb±ê?)È'²×ð÷OçÈvû+“E’c©Bu‰Q¬C²æ¡È›0åˆÆÑJÒEj+”…‹œjNIA˜,¼íУž¬Ú3œú­´ÌÚZóà$`8Àãºr$ŠšR³¸®ºõU¿ÁÛ‚Ä"ª€qQàvÐ DŒd‰"áF,ŽFt#ÏÛ³–ëUH¯ñA1&öì¹äO ÇÓƒ‘Í_Jµ¼ '‚”àe#ÎTæ0¡É® \;Ò’hEd$rH”JÓntBt›)¥…%A€~,D ˆÇ®i¿‹u.œ0ðZ‡]Æ]Ámr85Ù2/â6ð݃ȓÞ8A4ÕÁRa#5î\K!¥Ž“ÏÁ1í#/#/¦¬8ˆÚ UƒµÞ^Ø!%ÔW¸/ØNÍôòý/Éus@øÄT{0îï徨å(´­õo÷ŸöÉ»nj좈AѳLË—eÌ!¡²ƒÉ™é}gÛ—¯è(Œ!EBŠ”RuvqÜœNå”rA5OM&t¾ˆ#,°‹(´3}ÒD~@ÆÌÉ ÓBéTáØ"jÓÌ¢ê–,è'žI×—Qm¡‘ 9§ö4º¬R¾þsîÒåÚfnKšÙc„@wxîÇumüþ>gaü,ÙeTJ$hªdTwÀ›ƒÀi¨Ý …Ñó #/£m±ªÅÕFEJ$¶*¦¥ZÌ…*’¥ª-’ՆʊÍšµ*Ø‚ˆúN ' òœmôÊ“”8lñ|‘a¨2 ȨœüÅ(VÑ#,@ ôý[Yœ½Lo’§…ˆp†ÚBØßì¸ðÊT`3#/ ±UÖ$ÌŒi(ô-ì;ѱ#,%• öÀÁX8±e:b=s˜z¬#/|÷U_… ÆØðGÕšFLöM6Ž˜Ë7L(âÃsCIFE h ˜6ZEWÉZ£9‰2銯·ëÚ¶D_nõ@V@Û´”ÑSc :³—hg=é9Ò­A‘m*]%]%¤#,”öÜ¿§³Á;ÈÀs ¤D*¨€;6„OÛ¼à<û6·Þ¯¼µd±ŠÍšÌªûÔáª*Jekr®Y+–»JfÅ“E¨¯ÆµÍÕãt-q+å*øÉ+8˜(n‹#, @AÈï]ç}z>Ž±µ¶úŽÿv[Êi£t´‡ü .7|^®­ ëz¤‡*ôù,‡²Ä‚$‡ïN"“Þ}¨ˆ•v>Å:ÿÙ»W¯Ëöýœßßþ6Ú˜9!Žuš.$@„ Îÿ2ü[p˜“,)µŠ’Й@îeî½*„?K ‘#5)Q`¢+åT:¶«n;N9XÉÖhæÐ)Qÿ\X/ç$&ÏÃIeTù¿öiª'T ?‚ï“Å:›x§¬1#/o / (gÂT¿«{ˆhbn#/´bDÖgdç®A²²c¨DH¥Ó¹2l`›zÝž‚ôaWõ\Ü0ÃÚ‚ÿ„Dvvu‘dC!«çq †ˆY‹ð:°°@¨i­ŒÅ¢6ÚÆA¸¿U#/¹‹o{dÖöˆä€¶úxÒ$ U 6$cL¹Ç¬zsE#5PþÇ›ç36pÅBAtʼn²¼–¶ÈÊâaDÜpÖò±ƒ@™ª‰®ËoÑO "¬ $(¾â’¢¡ëñ£¹T;5<€÷Òž1gN\Þ€ÝùÑùØÜ„Ê#ÅÐ~R›…BÖˆ)ª¢‚±eÄb]Vž¿·©æAHŒŠz‚¨¢$¨‚ #5DH ²xü‰2#,¦B†1X#,šd==ävߟsƒMjX3ù vNˆ#5Å÷QHFÅO~Úms`j#/6À#¡}@ô±d#, ² ”`†|ÁÃë²dèììõSö¿¿åŒdoß(ßž$ÛPîÂÕÛ8º“„‚"‚Ö[÷P–O|RMamC²¬. ý™³ãsg£B÷ÄL¤ø¼Ì’ù§ŸƒeZmr´¾#ÈbÒ¤GHJò8,öÒÿG‚tŒ>£Êâ÷òˆã4g¦#xVcmÖ¿[Dõ£DøL.z¦ ò­`tx~{SsÞ{.ž7Ö;g€Öœž×Ø<‘Ô²öýZFà[ÈQ0˜I»ñ~1Ï^zí…öÉT<Œ-ÀƒÌÁ`¡O¡dΙâXÈÇ×Û²X-SdéÒc(‚ˆ: ¿ÅçMÒûrw®ýGÞu£V‡ÏlþèZn uºc:·¼ü¸˜K‡­Ñ=ç–VuAÚ¨ÓFå§j–×J³5C¡!™œ°Ä+ÆB¯Ë¬1¦¶éO;îåò±#5<>?f×ëË»¿¬щ\^6&‰3Xi[²«Œ«}š^šèÅi°¥¾8Ž 66 `ÚŽÅÌ„G¬ê;8¡ÏÅ{Ôò-75¥­ hZšµ]ØzÑä¿®ÍZ[[»Š’'Šã,͵&æfñ¹«Ïf@ J0b¡cŠè©ª&hìÏ ‘‡äþ66mƒMž‹‹÷0äÞx®C¶×Ü"Ó±‚àÎo)žªÐb/ÇòrêïÞ™— /Æfï_#,À‡`À#¦3¾Fk‡¡£ ªk FÇÀf iœÂÉ“õµÂX“ ©,KíÀ/@÷lgèpÙ½œv7Â9ì¢isÙj.uäñC˜èÍqѤ÷†Fa"Ê íL(ËÂ8Aß(2p5S¯(SMUJ,b1d;vó%ÕD%&~×Ô„ÂÈ¢Ò)qæåÝ=DZ öí¾CDA‚F`˜õI=h§–}ïjá#/ÌPðŒwßàL!!“±s‘–DÊÆï˜øéÖÇ‹1;-°à9#,rF¾TÍœ îCGç³ðÿ‘ïxüÅM}`z| jFB‡*)ZP‡ÔÐ|*¦¤o/FGƒHqB:l×N0$—=HDégõ3¿vkï¼²wÁLÕ ÀØqdæõý[” 2!§}›Œc+äv@“¯ÝÚV»„Mþ§AçF6(ç,‘O#/óëÅ©š¦µ¼Úæ)dR›%E®–ìÕÔ³DÎíµuKk»ñ¬æëºë^/àxÞLj9bð¢Ô²! M¼;K˜ ‚SIyË»‹‡y¿ %„l+[óÞÚ¾Òû·ÊhjFRÔÈ«Q5ýS» ÚÃb4Z9˜œ^PmU¼{¯.³€\^øoúêýß›„žt2‰Dó.ËE#U ‰ßˆ±#€áE0žAªuªÂQÎ- YJÉCÞGB!ß#/ÿœÀï£éÀ>#/Ó'QtˆpòÉ#,#,rÛ#ÉåCª °¦C7;ë˜i’Í=h€÷%[»,9­ŒpQ9¡lGJ©„¢æe†¹újÄ3&šîÞµï@i¥ß±M †+e~Ì+‚âŽÿI%KLžÐ*¯©êdž|vž[ïH'$'ÓÐzSê¢bI"•jnÝ]hÖå»;­ÚêÝ­Ýo#CT’7©!Q4•ª#,#/$&H‚ØYöšJ…n¢B¡‚GA8žúXên%µ(.Ždb$ƒP(a áˆ}h¡–6Ï2`4LT5BÞ†ŠÏÙ£ž°šíÀÞI Žû×è<}O¿*¬-¶¶2<[ýY³ÏiÇ"Ëm±mž¢“Ä„‡V#,¥^¸aëš_» ó#/Í\vÈHPÌÃK#,ÓI:ˆ„RD#C·.#X¤7`q/ÇÈ¢éj¡Ö™Þ"ˆ wbwX‘D#v;¤á¶–·¾ÜÐCdXS à¡Øì449íÑD¼Gð¯»C4šËãz¦wÃëøóo5ìmìxÓ30ᤆ‚ÄZît¶6‰èù]ÇOÿdÅ34Q/¯Ï|r2oD”•²,HÈu¢#/±}gžÙ#òc¦³ÅZ’1ùCª¤Þü%à«Ò‘­5)$6‡߀£nÙü!û4ZÊ»I e@¯¹Ì\\6†ëNF¶Èn…$ £äµ)φ»pj²®¥J~Õ³rçÁÓÄÆ6~~–»3ÐС‚׎¨hãÒè„P®s¦úäÃ… jþÊŒ¨4ÌG9û(!¯EUCàì†3Ç7¨ÀÃ7n ­ÃA ´¼Ê/N6Aš ¨Q¸]\è|ò¡ B)L\Âaùƒa°{yÀ…Îl§²j Ð-" ê„„¹†¢Te…,‘9¿ÑÏ[²•üñ¡Ë3äCH&%•V «YAìU*#,…EV Òõ•ªœ$:Ä’ÙAÌ»±ˆF•$*$,„#2¥\c Ã3ØÒÖ“=Ì<šÍ¨Ül÷–ª3¢P A¾50tÖ,-(¸«jÙ‰€I0Ì‹#,Ûo)MD2› l²¶¾F#55`êR“®W¥GŸû'V/¾y”•Ýe•ë‰o¶”Ë‹$…;‹ÖT2‰±¤.; ººP– ã‘O”,HéÆÈ…EÙúDk-ö6™›PPrÌQ'äHéÅ´Íáµ^œSÜ‚Æ}“̶I†MK¹ue% ¼#/OwQÄö9oÌ’þ$áJ•‚ðÌ@ 9:Àq¶i#,,óF(ÐÎ$¡è/ãíÎd°À±~F6óññö÷#ìñâöšpoKž%EýKâF ©T+n‘„ã÷tæN»ô"s-qE’(¡—Yëï?µ ’B+!)ÐDè¥l>Ÿ¯W}ö†&ìÏ™kÖ2¥ž/Ë;Iëï3Ôz¨ñß…šjwHeSR‚Ž»Áp–0úžÛÉ{Óóõˆà¦&ƒìÔq¹áãøÇéˆ"ƒTIÙá„[\“Q êbçD BÍØNKœQPa0Nmj–pvT—sÖ#Þn#/ƒ~s_áò«{‡´`øæsp«í#,öþ³±…*/Z2)MÓzÕw0œâþÍÆñdoéO*TWäð4Ëõã8Ôîñ:Õ%ì(»ÕXÒrª°5ÁŸçgøY3ÒBnc1o|p#/7Ò[sQ¡¦!A9©«.Ë%Zo»-ïÜwJ,i¬#5#,U@W@t`¯?)@M†5B¨É2KäàÈ Ú'2/Z¤K@‘KÀ¹:EÊ ÈÈ –Æ#54ð ITpÇh8ÑÙœ¶ÏO&“‚ÅWMÊ8ZÂó\‰ô˜³a¦,ûŒ…aÆßé#/¶RÙÌOÊKl=ô—a<VN-ÛÅ¿IÍ+pÂ5A´ÐI§Ã$ñ ÖFh>àÕk;5åy¤2z/Ìm”„†Á5áÄÁ›‡±ÛQvb³ûÊ¢'G0Ð c#, Ŧϗ³¡;Ñõí4¶» A6e0!Šˆ¨4‹æ´¤ÏÇ¥ª.ƃ&ÆŽ%Ì”"Ùn±¤3M²IÄ#5i£I#/ #5 E4ðÒãc=íõ[&hˆ„¢ƒö³&úA…Y©b” ‘ ˆÇ@¸Ž#5 €ÞZÂãˆ}d “@¬ì‘¿ih`û^¿6ó€wn§§à™É§U>Õ0G©{`H‚@‹ ŽGYn#,5ïÑÓ«®Mc›=&Ø1¦Æ€wNÿGG"ÿa樌^oÊàq)8÷ä?L¹`—ÞOóAM ’g’©çÙdÿwæÈ!ÒB*B"‰sºvYƉè í­¿’Ðl‹6-oȹžunIKmÛ¯¹jª6Ô„‚ÿ`E´U´E$A¢ #5—iôê÷§¼£#,zˆÈ‘|ëî:¯iÏCÜ$©[¢X7ºz°îЀm…” T“íæu¦Vzž³äqHDî!2@‘†H%2RkHS$Ì–b“lZL´¥ÕÓ2¶˜dŠ6šT!’š#0)6IJÌ‘¯µÛ¦&Mi4h–R›Y¡S)™#0(Ð#/©‰I¡ÙÝD*hR$ŠIIbb Q’PZ4M’’Á(EŠiKQ²(š šFe‘¦£1!¥„”QŠ³Mgz»ö•;À8¦,ú0Ì9.ÛœX&Aò~u=JÎÙŸ·ôf̈ÿx¡=;p%­S*F9.¾ó•e† ì:¡§ºy®ƒ~)W¾/×ÝtÊe#/´îÕ¤•¬D!$Åt2ÒXï-œq1ñ ÐzŸM“Fýìß…Âöï7€y9,碓³¾åì¹·[BJ²G6”þ‰kÒË¥gßÏø¦dþ$¬|>˜/»}!‹…aº« ªhÀ\³#y,P!pÄ ^F¢ü#, @9/rÆcPÕ,ÒSiZMa4•¤¬ËL$$,qpxÖ}miåTx0ƒQÊ™Lø1Ç?büÄχŠ­ F=DØ„}ö“Dˆ•õêÚM³ ! ZÅ¥=ÙþÚäcõÖ;ÛÔµŽÅèõ}"DcqøC‘–Á[oZ}>·rþd‡/F› …Ùt”½*› Jè^á€faúþ‹²H1Õ‹õ‘½ZŽ 1d~æí“{©?å¼WÙÝ­Ûµ-ѵ´cH%µ“#V iô8$Ýiš m¿ ÒöÛMó“(á©ã#´Ê%j7®N.ø""àï3]{ãŽéDÆ°¢›Aa¿rP´OezA¹ÁÞi‚ìÆBÝ|J{Lš feðv^`ÙGäÌÜ$°Y¶ÜKß#5<öÒ@Ø#´ê@íÜeˆ¡ú½’ö?o-tž¼;î¿¢¼Í”‘@†kübØ<<õµc/Ñ´À5kìèrŸÏèÐ!V ÒiϸB½†vW5ƒI²¿5ç†ã-†?mg:eY| ±:YPìžì²ªôS||S%JÓÄ©=ý~õÊŽVpj@¨{% ܬ!¹Ï‘Ð3¯ ôœ²[ÓïäY ¸Y#,7\F0–rÑsÇ'B;Òmˤ7#5ˆÁñÞÉ ,>!C ÄÐ$ÃbaÌÃÔ#/Ôÿ¡¨Í}¤Cog‡ŸZ’ñI–ÓìvƤPû`M2!äûFˆèÖ Ó…-Ì­ÚÆÓÊ;Z#…ê¨Xe$|2’}ÙåÞùÍÖ?£V®lÛfI”Ô†ì)ÔÛÈïZºQW¬Æo a31þMf•.¥2^BåÒy51Á„-,.K¯W”£ÔZ1ìf¬Þž1`9Û©š‰”—ñ¢LKКB$ÎÔm¼JÝ µ6üt’AIÒÊΉÂæ>ùÛw•wws!šYÁŒL\.iäÁ Tø0R0JtÉžçOK7¢©á?óíÄÁz¶¹~#š¢ŒË­;"¥àFá`ÜådçάËì–Ã#5ƒC0jvœÖ ÚcTêX~Ôê¸Ü·1Roø‹g„r¤Øóˆ3%ÃÊ LBì 2´>t#/<;;, ú7žx¦dºCäÓ@Öp5‹¨íUƈڜ‘«y(aÌ\rm†–Âz¡W««2ùZBA¢ ¦³Wo0áë”àÛq’52v¾Ø³/Á§Áuy¾—h ûº;v[Û$ç3¨â3€ËÒÇu,­úfwÕØcbÔRd,vrhÀ L»_;l\;þNq#,X(‚‡cÆáŠ(ŠÕHeûÁ5-1”êqDW;4Xa&(Œ~]çªO÷Ž‡øÞu’ÛŽÇLêÀ¼øãs¸’xíÇ)Þns/x.ï>YÌ㦫 ¤’kL:‡C›Ø‘2Ž6I7= ¼c-l‚vÛ…É%ÅÞ“¥¢*êoNÐdÝΦ—ØÆëD@³ß™9;6.Än%à‘ÓÞÇG=²öâaÝðÜì¿Ün æˇbsÎéÎ'\µŽøRž¦Î]j)XÎÌqMíC“´#÷å¼—qê.gxÕßÃ7­0ln6Ôi•Â¸Ýq-n#ll#/j&¡Ü(]èºÇ&M–7K}KJÆèôRrA‘ƒaÎ`î¦é‹"Œm¾86v¤cpÎLc+ÑÆíÙ\»•ÓZÇsl£ÔÅ\#/e¬S!(òBƒfækKZï½´k**)šjÝ”ˆJfGºVXnÁC#ŸBÞ(BÛ‚ iÐ#5Ñ'Ks­ Á\½ Ï•1GQì±mP¹rIY¨M†1C8ÎÌöC´ù†ÇG2>TP™‘³.e†Ô[ê‡FPaNü+imðg`ÀŠrÐ5×U/V@ÅCd&Æ^‚,ÆÓI53S¥¤ ÓQ‰v9‡ Ta%3 8][ßPJc´$dÂ"méÙKJ¢P‘ê´TÕºùØÔ3‘É 3ø1z®C³mΕ­·Ìõ’`Lƒo´ÚwB\G,A(©Y+”;ßtÓcI¬7rX<ð5iaNF:tÞåt4 ÍËËÕ6ÂXK›e:G #5&$Y<Ú k‰ÈCEñçÃeá—Èã9€·zâòñ³Ñú‰ƒiÈDS‚QHn!¾¬s(a–M…d&°U2LŒTBš@»©O©6f¶RêT–Q§v(bÈ°2’P¹•40òd£zݘphU°-€`ªJº™8T-!–ój¬ YlY)7ªP1šË0`aV‚e©6IO$¤a–`J£€^¡ÓAX6öôÒŒM‡ Œ+ã¥dLÙR’Ù²[,¼Ô±›2evgrx³VE0`õQÇhc¶ögYföΔ:™]ë‰Ö©—ZRðz ‹LiM+ÙÂ3„‰‰w-Í ãÔ/®Ñ‰Ä!+)’e#,òôö ñ8à:H“a ë„<>VàÔ-gnK`lErùÔö×¥ó}™ÄŽí`G½+½è…PèP}R9‚AsI¦Ðî±¢`TiBƒfèÖ9³h'VÙåâ˜m‘#,@ ‡ ”ΆEÁ¶ÁÝÜÚ3#/¦Læ3ÈdçJ×¼ÑLMmH) #/¦á#H. ÑUV8(|WAÈ]G’DX°j(L Œ°:ˆÄõñÉ#,ß±ouš)‚&ßZ7-½m^¶¯%â-OnÛÒL6C„CŒŽÛ…o4ÌXn74§ž"£¯˜Ùä/ë¼ô|…‘æ#-¤J:?åike$‘#3 œ9ð3 £·}hELȆŒ÷ Ç ˜pqD` ¡‡­#/ŒAĶ‘@Š÷ǘ†ØhñÛ²M ÐQ£f&—¬GcrÕV ÒÅÚ•HˆurŽ˜U1Êò.IÀ8ɽÌ0(vî)7†Fk6Â&Â¥$,Ù3£™‰HB*Ùˆ@…À†Çc‘¾Œ8pv¨Ú‚‚x±£Iè,Òóa½Íf‘л/Y‘Øï%Óz`X†‰FÐÁÍuC­T¡k@º ,Ä׫zè6‚/#5úì”&i°ÜŒ`èpWî¬5M‡4f3•‰cžm,OqÞÁ™º5¡·#;pd0Ãr›\A¹Ë„á­Ê¡‰ªJ,&0  "BÁþÆ @‡ø¶”ôBE„M )˜»‰h °RÂìJU#5#/†ŸÞñWòx¿«Õ;€ÚüwV춌Œ‚²­M!¸>cûÌ‚N´TzÊqˆÒ—B«øÀï•#A¢¨³°µ¡²Ó!!ÜApVà^È;U îËKùEòù‡ÓÜÌj4ÈÉëÇÖ31®[>”çq9"ë_óADpX³[dú¡Ç.¦Ð‹¤ ih§¤#5tÄݺ…±RÍŽAiÅÎdÎ-+X¸#‘ƒ†Ûd¦¦k`(o Í[FFK¦ Œ#5ÚïMݧ`b̸«;¡b¨mMšv*†|.ã©´¶Œ÷À8›ˆKœd¹B‘$1ÜýÚСU{nÝ:Çk–emúi-m&ó@„U Œ‘›ïò‚PØ8„C‹ —§®‰€—#/yPåJ–,‚Ъ1Ã:z÷ E¸ª[géý?P±;÷ÇÊq:‡—à ²¯ÒE]¿vÓM+oßkè¼l¼%ɦcI]wfsu‰QmÒþÑy©ü÷#mg¢}Ƨ¦p¡Ô²¤g,rHȳÚÐ"Q#/Fžãò±2Ð>Uñø”Ýq Bá0®#/7>ÓGÞ‡ˆÈa$¶ÅRQ´¦Ú+FÕ%E-35PhÛEŒ#/ €I#, U¯ø&ïaážY‚_h –êSß·«½qLCà]NØ*~M¦½ÂžéØ˦Ÿ¹ç|ÞÉ}9š5v ²KÂÆÙ‰#Mè h$ÝFY•D…¤Ò ro!¬¨{§ŸM@H Šqö:-'„Íe¬ #ÎfÐu”/V*(~ÆRH)#,ÔÉRZ üä;¶#,÷v6hñçÑS¬Xd&A·ßUÆh*1’Ó"F¿#tJ²4&Ði©²#,\ŠÒ%¢ Ä«ÅmXÔ¸óD1–!p„HO“š3pÃLä\ÅÍeº&šEKÀ1€‰dÀfwùÏGÁðbvúÊ#/‚›”]! BÑjÅ l].t§Øè$ Ýq.´ýÄ[YD*"Ix¢ü,†ØŠä(£¹œFXÿB`>šùdé0òð°A |ûÅA¼$&œ ?mFƆ´Â~Ø#¥Ço´] 35o]ÈŠÈæºü!®Ï½ý ñk@nmpF_ol==1–„ɶW¤3ˆyQ„«Kc+ChãÚ la¦oZ4´cX±EzŸÝì°ó:ìҙǥ éVP½´[MÚé×3.º˜)d«Cƒaç¬074ê¥#53©#3“Îðãžfi™ª¿Â&©¨ý;dÎѱÎù!ÝÙÇ6Ü=ˆ.Ù¢“•@°.I›9Ä`5†#/#`†k”¢eL¬;C¬€Ú ÝÒ–S3:g"K`¹ AÍ=:j4Y%¸ºv~Øg3ˆj ‚qÚv†Ì6K:A‰F%‘–XÄ)¥rÔ)ÀÁ\Ød‰ #,ÅÌT°Ò¸0¦L1 ¦ ™C#/‹  †9‡Z$#5YEÇ„03#/Žnh/Ë[棈 ”¸?ã RD^„NFÝáeÓ×Ýë± ³Ùeýjæ°pH±]” £ý'ófn ?Q?T¡pü¡Î °Ÿ»â HÐ5à$éLò°]YG=#,‘Z@ùýPÍ)¥^î d#,ÓNqN˜U4QUUU#5¨4ïFßÛH²[h­’­bÕ¤«Uùµ”Û˜Æ~+ëÄÈ’8}üϸïd­¾h‹s#5}Ë#5ó”‹PꦊüOô`8ã¿›Ü:ubÅr¿½†âa©k²wŽËGº#/Š«d‹‘A“‡,ë§ q¤Ó2enjêˆMªt”’ÂÕÊu…®iubãê;ÞÚÊEF1¯p1¶×Ðèà\PàÄiÊtó©·¡ÁªR ‰1œ¤¥Ö;KÌ4›y¦óYÛ¢ÜÌZ’ž‡¾:Ý­t Ù&)§Už pQßPYbÞÈ…13±³Ë5B"òQ(ÜD е±fKñ-g)\áÎ:;X´3ßääáœBàQ‘2qño#"ì°˜±J|Å!¢ž†”ֵ̕+â;vÕ™§{o(Q4Þø½,m½MŒ/ˆêtQõ6ûe)Ég‰žL˜â}¶`òdCRŽ MNä2Jò¢ƒc`”VwvÍfÜË—\”ä† ¾,,Cˆî— "( ÌÅ9xokeAE¦ #,ƒPJ`Æ ˜¬FŒÍ2<Âå݈ Jte.%¡qžûæÅZóȹ4Rë&¶nÈĉ@K™…œBèÒ…8€Ð…úÙ¦#5:z¶ˆŒ©zÙŸÒ55 ø]ªîÝ’m[}Fù.Kµ³awsK·\f©Î·³s¦]ÎÉÆN»Œ¶ò‰ªéh6ëWi+r»®Ýݤů;¥5;Ow^o5¼jB×-¹­ÚTj“Ch*‘Êëi#/#/ii"Vª†…#,nÛ^62šÓI I‘6V6ÆÔÔ¢™®¥®•¥šX‰¬1b«"CÑå´ÙÀ0Æ fl#/’+[IQY’$AG‰?I«Ñ{%´"Й ö1‰±Œ˜‡}’Ã`¤¨œNM£.Ä¢-"°T†Hl²o‚ób ê;Ï;‰ØL'¬„Ï^‡êaKîZˆYLÃ?y·òb<´@÷Äà#/NíÍtFLJçmz¢×«å¾=›ÏT¯¤Kóéƒy#,ú¨UEÆz,qƒ‚æPî ‡ö¼Ïé’Hð|{†éLûK‚‡8Ú~šêÙL/B`ÁBÑjÔ‚ªÿ~ #5ÃlƒBfh •Z4XRÒ#/BD×d7Q¶Ûfv[MÅ)”a‚Ñû³3ߥ‹}Ù9-ù·XùÄ6kÚP%,jTŽ5\nƒ È3§vŠ'ݬJ¢s\mje2+çÅ@̪3p—¿ zϱ•¹êkÐ#ƒ§l‚Ó r*°+xºg"De“§çvJ9ó“Ýg ë‘t/Ð…ÂÌ(7$ÑtãxŸ§èk¨Ó¡®{ƤØkTcEÚnÍLRY&mÞfè·­Œ‡êøvüc-LªÔ„µrœä¦”Š(–·Ÿ|›[[å­ Þºf²Ò¢Y¦›i›El¤ÕJûKü?ÉÛ_¦Õ_&©¬Óm”µ¾­‘#|)‚D…š– gv¼™J×JƶrÅQm‚”o ÀÄ#/Ôˆ™ÐYÙ5ÜP£ÕH%A@$E 5Å-%&Õñiº0”jIk)¶­6ͦV̵šSE*KbÃ#ELª•±-¥0”PÚl¥2%I›)™´B˜Õ2‰)(¶5&²T•¨5)”Y šJjE(™±%©i²6jɵ4˜,‘T¦IY°•ZPl¥H”$’e’“)3’jdÑK6©¶1ª&Vƒ"FÔ”Ô¦Û*šÖ¥šL–4¦MJUK*Ù*Õ|ªµÝ­²²ÛM¤³i)*ùM­®•6mT¦Ûi*­«á«Í–¢«ÌÕcZÑl¦ØßZªåj‘5jUP‘CIF9Ÿ/HpnÏÀ–NÝoŽ†MYÛH÷e³{°Ù2í›0ñÑcBÝë'~«ÅÈ㸫 ©½»hYá$©=!â^#/)ÂÈÞD‡u/÷€1ؾèž_n'¢£²=PÂÇk´4#5.Ã,=ü½,k³g]¸bÙ 3meÌzË£»>™2Aó1ŽË`yd„E,Žàuõ¥¯¡}8þMCFßl¬ët+÷ŒYE„ Ã¥Q¦(fI QÖšÃM$DD‚jXªÅU#/ û#,;£Ü{dkù‹X'©Üè,š¡é5vî‡K°6Á0ùå&¹Ó’ v¢ª~#,© åžÅåûÐÀƒ1›°ý"|u‚E. y!ŒJ’Š­ÝÓ¯ÀºÆ2âCÛstæ¦!\ \£:q±1®"µàv_´• åïB*75¶0"t^+òA¦#/tøySyjzM‡I!Š“»4ê#ñôÇåo{ºòœÆa^E\^i­éY×O<íF‡ëu¼]ðи±FµÝ qWX¼4×Ñ沶ð·eÍ’¶½ºQW]ƒÙkÏc“B7kéR“ŽæÇ1…qPë6Mù«!ÎÿÌ]"LÅÃþŽHe™EÆZP+®ŒHŒ–Ú¹ÛéÆýƒ’cZPPRJA7+¯è—'±Š+ÚN…7HI!„ØòX;A¡–5g—ZÞÄXí=òª4ÍáGÄÔAFM#/½P*‘*0f=EîdÑhduç§ej®C2)Ò¬„BáPª °aAär+ò0€¢Ld^±zî.5£'[šÑ3D#5GÇx?!Ó¥ãQT­9ÖM°)¥hw)¹_cí#PEêzq–§MKCr¦ UK†QË4`ÅŽŽL·~%cÞPt#"#,ȆÈHÈýËiTÐëlñ¬ZŤŊ ”a&B[e¯Õ›2FŽìe$qJLØù ¯ÅÞöÌh”È#/"#,#¤Òløb#5&’G­*ä‹áÌTcÄÐhŸ,ô­†Þ-:Õ uåÕkQ5; 墬lí4QYTQ˜×¶˜Plv;¼ò´wÇy#/ÔcSfW<|ò:Òx½‚›PìàÓ·rì·NñA4ÒÀb²’tÁG­ R]Sc#Ng#>Ìðn,•D ´é‰B!²L8 ¡Írº$Š¢Jª¢„IÖ¥ ˆ[J¨ÝØY’k¦ëmGÉm½È¶+jòïY>!S®@‰Œ`F‚eAB¢*\¤–ÙB#µÄÄÌ0€}”Û×–Å׃Æd>É·#€ª1@ð3;õxÎ]Ü©q¦¸@åÝÑ"Zº#4Å–ŠW‹‰·ë_x ,À¥™ùúùùBkdÂ+õµ¢šâÿ!Õ€E‡:“A#/b`5|ܤ€(BÙ1UmµrÆͲÍ%6W]6‰×M5ŠÔj¿‘XŠ,I¶kÚQ­½÷«Ùl©hÄú?ª­#,a#,APÂ"PÆ7À°Î!Bå„îa”ü1NaÖ3÷¬ÝBÓçUk´0+Ø"A¡0¬ðf·×6˜Ä¿&®/†``i4‡ßø` `¢ì3›c°0-¡€*ŸŸÐmÃ#,ŒAV¢ª4JÑàÉg?+ŸUú›4ð;㺣,7–"’IÅ ˆψ¹ª‡×>;vI#,%ÖCh#/ý¹;Ç‘éO«Yöýyñ½Ïí½Ï镯 ­vǺ.øuQ³“‰Ûì!ø«6åF†n²àCw7i¨ÎD=wyG˜¢"»ØT"Ûöqô#¬pvv- @¡Y^F#Kô¼j(Ûh b¯XTe[1nŒX„ š¥ßìöoçÈ:Á2 B?PC¨Šq#/ªeÂÕ؃ÏÑ騱â¯Ó=ì_è0[ öúÄ=CmVKb¶¿Rjµ,®mu›U·Kj£i+¬µ¹ZÚ5²ú°ïFŘ¢‚TD$A¢% !&#,3«=wÞÂîËÑýpAW¹ÁVØÀ¹JPe$À" ê%#59#ª:BaXLÚhcAèÐÚÙw°»5 ÈÅ3a OÖsarz“Í(Ñê É8š£ÊÎ%cþQ:øÁGÁU,!ÜHwÑÞ< 1÷¤µH²ØR**+àvúÐÜQø÷hc10*Ä5Ã…hÂômXp[,‡šûä€&¡#/ÇŸq‘ãßM¼+1yåÖ~N,HVRª¡¤Àhxü½ü;;R#¨” 8J<ˆ¨R6USK‹Ç^4R †ÃÓ~¼Ÿ}ì_Œþ=!…„P6QúÉÊ&÷-š[­T&–"`åÕ¼Sh ‡ 1³ØW6¼s«¶î‰(Ù5&*RVѵ Ô×Ê[´i­¦•”öWRk%XªQÛ°-î¹@mßß¿p¥Á;#i“ïvÒEÇ€42£tñJ¶éÆ­…;ˆy³ÌoTŠU7ûmiàУ6ˆøêU&$¨gmÍ(¥8¸àðÝ`ÎqDUå‡Äa3œêèHzmW¹"Á(ª ¢ÅQ!Æêˆ#&Rä+YO’@Áa¸è ]æ’ Ø 1G¹wù '¥íí`u’$’LÀýq±ƒƒíõë¿×÷[ÝÅ é¤ÐqØ%³™¿wRh„"…›hÂ)V›¢`¿äøm#/¹›dŽzÈþzÌö‹ž–¶ün´h5õâR—¦È¬‰Cá :'ª¥t›ûŒÂQPnÊv@às’¾7i5$Ÿ{1#,Ø(2š0Ù†A“ ˆ†#/Ü …F%#,>Ìõý¸ñŸf“Õšà0†n(c‚<ù˜1ЫÌÒrÏõ¢#,¨å¤Ñ*M—ÙóTI%FÁÄ8¶Y0z¦$öi…“¾ñ“òÄt¿Š6ÒuuóObˆ{_zišó®˜‚|ºNµÄ&åßMå~hÖˆ´b-"„¡jM$%"’ªm´µ%¢Ú21™¯Ö› 2hJ‹K?q¶¹µ¦eR¥%XÔQM)i6ÓLKfµJÆ›YM-dÖ‰±ØÚPj•£"ËZQ¦U-*kU’)h5†‡æz”#/i„O÷?6“Žìd¶¤"f#€ƒˆ£ÕáücD‚5$AJ ÍZ£j5¨ÚêkZånÍà[2@$dH¸buC»«~H_r«o³¯£[š¹ÃW(ÆMÔ¿Áꄉù’ ² ùË”Íü¬¯¯uV,š”#/¤K>av\öýÙ#,2Ï~ñ¡: ·(Û°»`ˆÜ§.H€w`‰åßþw0âW„Ah€ÔöDáÏMÂzÓŠÙýÄ A2=‹öP•U*P” •¨ßäQ/j[¤(q XO½œ¯"ØÊ<Þ¿ §ðÌ•´Üm×Bƒ$€ÑÕÐ!=L=|î€âª¥Êh"jD£9–8˜'ëÝ•Å¿2Ð33²›–7ü}‚§¨‰Ú½&Œ$ziDk´ç*©°å4ø †õ@<{GÈ#/gA'1#,bjIÄ·Xj‡P3väž<䱬äN Hw0ãÈàlúḆ©ü\£Ï\»(ÍØH±’ƒŒÄ¡ýk<ÆÍœ„!pIª0Zà~¿ÙgÊ!G¹Ëú «÷Çòùi‹|@¡4´²/âçÝü¤û»My–Ôl&žä"Nçký’À½[FYD0uűŒ[ªd“Bd˜bû©e²¶ö¹Ò^^à07 š…ÅsC’»+Ž_°ÞäÂ} ‡±‡±»­S .Ü6‹i@11Å¥²„øf£&K>^&—×m5ŸFá~¬RE ‘AN䥂(Æ#b„ñKw>ïdŸ«6kG´:htt#,á=_ïÝŒ—¡p2€É¼n¬²ÈH‚‚£c¦TÛ=Ò1ˆÈ,¶’2&š,K¨QC£Ou†n–ê–‹4T$Y”²‚`UD)å-SÆ“¢~„˼S.›€(ÐÛ XcQ“¬qÀ-Ô' ùŠ÷ÁˆÌòAydfe@v`b qLqºß m]*H™ªJêä€Jd¹Ý¡-îÁçtõ¨vÁwÄ"Á\Ý++î6-¿KÍyñòåÕ7<“yrBóÎ¥~I#k,Œ'¢½>ÝÍ•E“\‘P3HoVžLÆ¢"3°ÇwkM´×m*o#/¡'EÚÖÆÆÒq8‹¹‹A-ÂH0„¤”z ]á£ïÒÖ ¤,€ÓŒQU¦¦¼ÌœÅ<eÍŸûB'0rwd§ëµ¸Žjá*Çy²K5^P¸Ç @œ3)ÙïcÞ·Ôº¨WŠ…RÅa0ý¸;§ÃaDȢ߅¶•Êoïó£}g%ø×Ã.³Ì¡T ÔåÊBIª¤‹n¼†È[FRPì#·[Ñ$Y íTiãŠ$økÒ¢µùfúÄ/êvAÎW<r²àˆ›®G$ÆbBÅÞì‰LCh~µ–Å…'6ÌA5F#,Öýäˆ7¤¥‰Oß¼(ÀF[$ï&»ÂZJËÜåóÞöcn½ŒBÛÁª?³ja䥅‹J“k.91-”âa¬†x}L®³Q·#/£ìfξž@¶k€jGR‚†‚РˆÙ±¼º]ª…`B@Fì(‰•iR´@HôE(¨„Ážf´#5¤•Àõw”:S §™±tEvoöο±P1uã±Ä5ç鬙kÈb¤ÄD(u’´ÇvËæð9´t` ¿«ØÜxÄD$6!É›UdE:ö`VAA%Z¬KÆö¶‹¸\ˆÙGèˆeêÉp×^Ó•³j‰©Èàýý°Öúü›Ý<‘}]ÜjÄ~ñhóuµ]v›xPšDÛ^ºò¥ƒQZ›JW 6ìB #,Æ„6’% 1‘¡(2¤*TUF¡ (PH}WC™È¢‚Ø÷P;{kTƒ¾ ˆ‹`©º›SU(ª¨€ªûù^§òW{Ä1\*ð&GaWŽ0­ n(šwŸ##57ôx—nïmëĬcºÂ[p™Œ(À#5Óa;@#:÷/2Þ(’µåÎæ“_R(ô€Ç¦9»ZÉ6ÐIN0ŒJlC*šDh) ›Ñ6¸L±"l˜sEg6f%Y¨–Sd WLë ÆžB]å0ìè›È‰Û­«DÈÂHÙ“Ä/òmZhl0Ò#/ós`Ö¤UD7wD 0ÚÄ1l®¤2Ž{TõEOé8 ÚpãÂB@„u"T#,/˜-ÙÖ—77¡çKïîcI©Ûê´Œ#d=^£š‘ix=KZ…ì#/À›'ùõ6á­•F¿sƒLu8š&ÇÀ:hì¡)#,êƒy, ‡¢*]ZRj™¶ÊZ6eLÖ¨ªRµùUù›[ò"W]¶Ú¹±…!(`°¤)’(£Î€‡Oݸcó!Ò<®Yh¹·£j˜_HqÚ#5€¬==Ö³VB¡ïš1NGŽÂ^uç–\T[”žö«öÑäÝYGÞAÏ ŒC#»:8ŒmNçÒãÓYÂÉŸ÷`â/ $–”kR/ë~ªÀÚE–y'áPÉ<Ö»ùf·˜ÀÚ4Ñ$ØÔÙ'½å2‰¡Ž’Êhå‡8á}“n±ªÓl@‹ŒQ:ÉP#5FõQA4ä'^ Ã#5 1ÉW)«¬ï½ºôë1LÅ‹=•_ ²¦))Š•*l#/r(\4JM¦f†AæwôÒþY’Kjé>Æ#/­µø˜þÜ‘cVÏN}M·ø¦<óMÛò#gz8ò!§Þì2vu¬#/eÁ;|jù`³ßÛDF`(ƒj¿ÕD«–™÷yyž#,zÐOIâ¢Û€Qž”`4jû{~Û‡œ^È”˜„ãÞ…ð dÅ(›N©È”ÕúñtHQ|ÑÑ÷&4Í@{R!ÄÇ*›ÑÀ܈7,cŒ —!Ïë`²|èVcSWn;>³<D’×—ê½õÓÖã„nŽ™àO‡d¿`”:üg„3!š¶#ªTÝ%T@÷DgD47:ÍŸvÁ£ Õ^}ó¯rû žŒGœ·1Ç+>ÇiïrC€Â'*¥YC(•9$—š 2idHAˆ½-"g7{´¿=Ù€¡¸/Bï6.®¯W°°³ý_EÞ+ Q!¶yVÑ`¨ÄÀdvÊ—RÚÕžvëÓ½©«lÍ[z­t֯ћSM_©uҕĈàVxâùÈ›ÍFFRàs±Ó$h1jšø$”¯ü_íbÇõ7ñ¶îÒÙè’¤=È?ìî› ƒÇ•™hæžrõ[F*&ƒkã±xŠ©ÄójV°¸²¡#Ê~HRe¬ç­ulLôеd#/0÷ƒ4â…ÅÁ±å­­Io#|Nz>P 4Ç–" ˆ§R7ø†%C2ämê﹄€G¢#`Â#5í‚H_8FHT¤Õ¨,±\ÝÂØJ€ ·vµ×,ÆÝn³Viµ›6ÔÍi’¥™«lËUu[7e4¼\“Jím}R¦bÚÙ`@E9Øèq`@ß: ë÷ÏDéÏÙñ»oUëÖæ÷<˜ÜÔ³ßÏØÒÙ5DzÌ"µäú*‘‹4„ª‡ÎÓ5!ñ>éMI¹ó†3lÂAëõlõš¾…ÒcZ<«ëÑÄ#/›rÄ£I-¥¦‹ý{¨l­>@ ÈÁkQ ²LU‡MFa°õ8½Ö¬ìbE,…” Æ4ú#/Sž¿Õ¹õ©ßW#/6ÞM»J16æ¸ß¸7plëÁð#/ÈâÊÅ_p6h^²oó®Ãnªø‚,ESøëÒ`ØßÕí[¸`”]Ô¶©#5hŽXæUÕ»°¨Dˆ€A¶ÄÂó RF~ÃVø‚Z*îÖÈ3%Ø÷Hk)JòFÛÐlÈ(3™TqMP90yÍEÁšAuög¡å#/­áTCð~”z,^G™"`÷¿=·<â‘I:~ÇÁï4òOZiƒ[9 ‰PÜäÈù}þg›òÙI0IÐFÿˆK÷#tH²À¬í dZvζâŒî0\7 ŠwnòÐ;#/ì8…‹È® Älô Ò¬ÜÖp#/ÇØ\×yܽ÷ù˜Œ"0ð3Ázõ¶ÛñâiK¸™íÚ(ˆ—IˆöÀ²RaDú•VIu }YK=™.!ö»Ò< áàE„Ö0‚È'!ÔeÁÝ)þ5‚›«1ŽÕÜkÂô Ž¡È3oÅ0ƒ? T7å àÜ„Aú tæ„&Øðº4qü`e3bXFËM£Lö›-¿#/ždl‰ß‚…@rMÓÔ±î£?Â27!áSÑ°»SXÇ•‚´ºÛ¬ÐÊR5vûÃÌø Š‡ÇßÊ|7ÓÜR~"Ä@ž €¨‰™ç;§2€^|7Á2ªº€¡êȵx«Qm¶Š¢¶Å¶£jŒQ!FÒ HP4&0»æû_ò__l'¬a€Ä;HÀ‰@?¿¡Á¹U{ ¸ØŽèØtÛO®¶qqFåœÃØ(nao3[²AD†¬Ì¹ë"1è2•Äšž—-¶ä+|±ÇšpAÌŸî#,í¦ž§˜`8óâŒ!o#˜$†Q[4ÆycP!øÖX¦20üÝ¡ðµ æú4ñý_­óU Q¨(¦‡­O^ýÔª›ÍÔ”IÐ(9†<„£ÄÏB€£`0Pž"ÂdvIOè!·ð©#/[IÀÔ£×ÇyÕ3†Ó}„ˆþ3ÍBçÕÜ|Fo«1=ð<6}Õ æeÖŽž˜Òbè T#/°*ãUÊJª’ƒÉïÁo6Í÷M¾¾å®Å]Ò«!²~Ô¡ˆÀˆ’{ÏaM² dp£AlMH?¿Ýî.xS>Cŧ£1îM|,‘¦Ýøòëd50®n>0†3¿hkľEƒÝFo5qIE.8<<4‰fjiªž ‹4ÍéßcÛC½U³5üïÂÙ”.!CF^ž¢2ónN£méEvÏ>†ùa0cc…¦ó±±—½æ¾¦ºèmi`Q00ƒ!’Ÿ€O¸eSiA›Léõ]-ÊÓ#âý%í»ìç/F 8éØ]T(£¾¬I¼¾ Úñƒ¼ç”ý8.0üa­áæy•žExѭퟧfpuꛧ<‘#5òáÃáŒÔ¤–%áq y³+Òž¤ÒœcÅQMBBÈniúÅI¼·Å‚ø¡d8ΓÙ#5ß<†×ÙÀ®Ù0áH:í@i}᤿5K`S™Ó#/$¦S«ø}aêêü“S.=êqP@o’ƒæ "¨ÌˆØZK‹d²¿8("|hUlºCHMœq­À°¦«2£J±¥ Á.å¾VñÒɼm»*®·6²m»ÇI±Z*òêK][r®íÈÌÝ×h®®ifÍÈÙ±²¥¹Â§vÖ’ÚM³l¬Œ#,´…ˆ BAB¨2ìÀl@¤œPK°ú†G ˆ­;ÑȨÛ£Ó)¡ñ¡Jk©ôaùuó÷¾vÖùµ`J•l¾5YpMZÒ”ºÕ»-¶ZóËlþ8¶P¸7Š‹Â6XjbH2@'%ÍÊÍ|my3D¶[kÊÕÑF.>/=òe5ŠÂ) €Ê„Ë!E´Vñ«©•I? íP%±X2”ض-¢1Y•Æ£TmTÍ££EE3F²Ve$ÈÍR Å´Í%±kf¯vè#5$9 ”A´÷ï°¡òÄÅ:þ,€ÉôÖ­{{#/&Õ„ “ky·í_‚ØúW§|vñm#/O:ˆ´OãÅÍ·’r½Š£]³„×VÃÑP"å#,‰H@Œ“¶rñMš*¯É+~&µ\JÚñ[¥ý[v"V)O7]&©ÝÕÓk·i)µ®&Åm£&²Vî®Ò›V•T¯W[KIQ‚”‹MÿÍ!Ä6^Ÿ™ A~’ŒüjIèJU G&0A´É F;JCay8ä X„EV)!­ÛP\7œøµJW#5#/ÅxaNŠ¦èŒ"ïW]0äÂñÕmúŸhP{ö5>Âo>«ãÆO~#5?^‹HÃ)AˆÃðEƒÞ~ÁÖ•84}& ð¸ëmf,FE[ÃôÙTlcUáŒcÓJ€ÐÒÌ­Y… ö2º$šhÁŒŸÇŠ÷ånµ´ÍáöLc,ÇzÈð³†d·øš˜ÛÇ¿aCsb­†á‹»±-PZ—öR#5¥(P ¼!Ûgꮤ¸MŒ;:>‡$Q8duÃ<^ÑwᲩœù½‹§[¢5]ÉÖó™¢mÜY`¾‚[hÆ‚QŸg{«42Š¸Ó-½?¾ãø“¾â ˆ#ö§Ö;ûñáÀ¬föÖãu»`vH©½O*£•ÄQÃ÷žt?º±ë0T‡!‰çÜLì3Kܺn¨E2ñ-Åõ!ó`y†f@<`«ôMmcTm¡-¾º_}µ¯Ï-äŒHÚGüäL¯J&12ˆÈg#,KEdχQlšÕZ5\Õµåuæê½À•ÜX1ü€nËÇ>pD  <ê0?a?C_¡ÏÙXZQ¶AÕ&´×_·y®ùq¢ÚÊV®––0£%îh€Ö ƒBƒKF¡¾@ÁÛXÍ…£ô½šØ‰Pl4$†ƒÚ¶ïvÕ¾Ø5ª™IŒQ­UãM±oŸ¸Ú¼î݉ð»Æ®¤J(D¦eR{Œ%—!a#‘¤šZawiZ{Ò¥cl¬Â‚àL#5X»‰›¹*Äid-Y* «°ˆ f c €ÂŠ‰(T(±`4½¨t6ÀLÁƒï¥¤µ\E”C2èËôé½q4bàÓ( ¢1‡¸–T„ ò_IP¼æð…#/JK¯¬úpcÒ4a`ªsõ€q•cõfLÜ&†CsÎÎWРèqŒc0Ô–£nÜþòÝš3³˜@9@’zDTQ1#,ò2“v¶ßIùüihqºX=nìšG·o¼7¢Éÿ¶¤²ÂçägƒgHÏíUyì78~X‡C8GG×!HC‘{zðç±úµ:Ô\9úpXÉŸWó𶖬¬äôþ1] ½þ¤q{8ë©qö8é ÖË(΀TáÇPUAà vü›&—ɷ䘎YJè’¤ÓHB eŠ#ÜÄI™˜ŸxÐ×mí Ç2¸¥©#5?U€yÈ,ª)ji-: [G„0÷KÁlÅ@(`-ËYEl8¶<¾€ÂàWH#“‘^yÎéáÏ>Â;u茒ÿi~6a“éã!ØgtÎÇ…ô+ÁæQÃË®6õ4õ5AÝþ÷@>þ¸’AðEUø&+»tî•\Õ¦·[MJ¾ü!VùîwÐP…D¨Þw&Vãû3‹u÷6Ûè×\J•Õ°fÓ±ˆF{‚Í…wŸ£Ù¸’I Ž-U#ÎòóÍ4櫆Iºï<Þe¢S–æ^s JjI’±”ªñmÕ+bÑ ÉcA²[Âk¦´š;¥uy¼GK¶è\·wn‘]/ñµx£ššW——mvœ¶e’uÏ5·U±«m±³MO5Ú“&Ôi6žuÜY.»­Ý”é·E+;®×*êNîÓbÑcš¨¦†(TE‡÷P(ÆÂ)qUö'²pØ`›‚‹Ù·×½UƘ[µ9QüžŠ$;ÔþÞñ-F :Eð„ €H–@S¹ˆ–U—Ú£ä$ëÄËóGÞŠÃx Ø×H7#,|`HŒLÃkÑÒûÙø¦‹õè•ÅÝ°ŒŠÐîõÞš7zòñŸu£á¹?GsÔ›NÀõ‘t•XÖfmQ)™¥ôÕíÌ$ è„#5uZ*Ðb Áp?„#,X(g:½ül*&ŒXEXD’0I†$OaáêPúÕBùòèØ5+¶u×wRÍEE»­w·m¼’ü>ï!ªgá#5ÂØÕ5jL¢·‹ÃÚR¨g ¢ÔA¢έðˆR&HÁz×M!;ŠH¢@0·1ÃB"ŠÌf£o¾uªˆÖ­×m»i³ìkÊŸë«nÕ»Ål¢&4:§žýé˜d'È@k:dÿGöáí)R0 L0)A´(‚#5l`|ÝüSCÙXÔ ú€î@#/ñ¦¶›YfËU4Ö¦ØÛi©ƒ†ð/#,1Û³é0VçQ#,uÌmõí³lšÊ¢¥Ô™›` *ÏÈñ`ÔÕT#¸ú0ÑFÑJRRj˜0²”€'ðP"$P ¹pÃrª¿êƒŽs[S>Šã5‹±\”å,AL•¦~>4Â7H΄ˆx²gW‹Llf-mEúºw÷c~«#,¥¼‘Šb„ BOÄ!{ßá?=¹^"Eå#,úe‡0ƒù³È8ƒÈg„+`_ÓÕ}CyfÊÈHC ÛIÚÔ4ˆ>7€ ÔÀÚz“8blfh J å…¡ü #>,-j#ø6 `j#/$Õ’1W&³hÂÁ8é$B(rA#/…Ú²¨0@ÞÝEd&1<¬¨#5´b#N°ÑM›¨X; •AµM¤‰„Xñ`]ÛL¨žúów•æ·ˆÖ-GŠ®X¼jå“W/‹*µâ¶«ÆW¬5úR¶Ûk;fN=Ñó{njöÖö‰0Ã#h~€bH$ÑG(‹"c\Æ<.ð ²Hk_Æ*-j‹Fž›i¡µ,Œ%£!Q*Ã6ÅîTb¨ÄIE#,ª5AE@‘‰w@ALZ`m6Ô]ƒÆC±Ï<±ÀHA}~…Ýɨ'§bWŒÅå½ù}$µ…ª ”Ž!A¤õ@Œ%(”Р7#/€º±—|ò³±†äOvj)À‘Œ$° ÄyDz·A¢ ²©€D‰(…B¨ ó÷E>A×óÕëX4¯ž6Y7OmwM¢ f#/”bubF(´„ÌèyCó?4YÐ5™á3˜Ag™OøÅ6¼zôþ¥üÔÎàÆ–ûlvAÈ[Ú>pZJ¥¤ÖðÀçÙ*üÍm5ÚFv“°ÃC$MËUÚèˆñt»¼îõÖë‰ùHÓF Á0cKOxÔÌnÉ©]!ýšp#/2ŒÃZ}G‡ý%R¨,¤³N ¢2M«O‘BPZÿ L–ڽϰÜtvc¦#5vbz"‰ù'‘êÔ/#/¦gyêA¼™Â ¯1>¸ìFâˆTWlüÕAœv÷ª ¹FEÆ"€HRD'º†˜ˆ¬¢#,‘#,“˜C¼"XSò#5â`yÓ`ì~ø#…¾Þ¨$ ¼Bﺌí§Pðþ>ödu½ê`B#’4”„§è¶¿nU°››¢ ’‚'ÐoÔ‡®Bx|úŸ¨WÓ—Jö•À."Š5'á±½}å™ÍP9JH”(˜ oÓì#MøÍõ-›¨6œh–Ã%wúÌ°:wýf79 ÕÓ¤’•*ø˜“c¥L°º†Ä@ûÐg¡Ð¢‡\ææiÆ`Ïz\·^è!ö!£[$f”§4XBKš LÈ­*­`&Y4n"Z}_$?/‚x*»ý»Û–&ào÷#/¼h‡¼Hba !ðd;¬_/Q­}h7Êúæ "/:ÜÏxð±Ö/Ë×ÆmàÛ™UT`ûäsž“»¼Ñ6]Y3PµŸÍ{4ÂÖšüÍ—èª;VÊBÝE‹–e0à:ûv„r¨Ã`Ð4#/'8eF©j¬qÛE¤¦‹„b±"À,q­Á#/#+Lé m-0f“Q2ÃìgrI §!Žú²Ù.¼æL;ëúµ HùƒNU”kbf CÕǯFsSÖçØ·÷R'¶ Kâv+Š`Ç”7±={9 lßGf-2>ú#¾Ýº‹xãˆZÞÂœ¡¨x‘ª†¯n¼ÇŸ‘ÞS¿eµI™Îé•|>Ÿõª·ò:lÊP#5Á.ƒÛ^)¥àIò z nÙp£¦ÓLMñéfÿÍß fæ‡ôl‚¥Þ5©^‡.ØÝJud„&ó#5!„3@8‡ )ùÔPhȘz#/QO@'»1ÔÃk:#/Âs>ø;ÁóÊõYZ”*€ðo†vfƒa‘UAÉðìêêÝž@JŸÏ8EuBåœs¦cÈÅš.oŽA°Mı Ô@i©Øp› n"õ¥R¡Û¯†VàeA‰Ð`T#š…pÿîöÔÀ¹@±~“K?¹’|v‘=•ýÞÐ0 Õ iL$DXªÝ–Y„´Œ` Ðò(ôêó®4 m¸¬žÝÍ#5hñ(>ú©¿Ñ1ðm§Ž#/?­üì9óœMI#5BHj¿ŸæÖÃ}_¹5}J#/~‡Ê­ÈÑ­¼šÒnD„ÄF‘ï’FrÙš»“…@ä7®ÇÍ<Ãó‡*„óÙµÉVÓee¿vÂvøxw$NIYúðñð›|h“"Øê½'¯dÐ<õCrÆXµÁ !߈h!2ocnÛìüÞZqpÂD¡ñ·=ØØ–ad1äm”" ¢#,™O2åkp´Î`ì ÒS¾ctà|]ËLõ¦ýW“„ 9Ñ1☖òFqexèô¤@îŽ?fëUÐÒáa¬';ôß¼tN*©&d8œ³ÇFÞ#/­bá=‚u³ž»YfŽ–¡˜ö:Ux1°ì¨HI$«6]ÇÖÂ0á|XBm™a¬Œ3¥|HM®JQ…8åÔæ,ãW7æï÷l—ÆŸÒÐ È9þ¹10H¤%¤"±Dô©ü‰¥a|> _éUƒw¸ˆŠ’H0ˆ²»KUÕ#/ŠŸ+›ägØ~Z}/¥0#/´Mê:·²1ƒÈ4=çÙ‡ä=éÙ.¢ý<ÍÌ4-à˜›Pr<ÎœD1Ûômz»¼Ì-¼¿jö¹ùäqò â admæC\ÕjÌ0¶ØÕ¬Õ­-K‡T\c#ç ŠÁ^%Š¤â#5šI#5–jwáx<ÖCí3ôƒhÇÕlº‰µ&W±Í-þž˜Å7AãÚo@Œ4œPCr‘†A)FP%DE!] þO¯*܆áĬé¼~žøÞÒ¿«·×½m™ Où¡TŠ´ÛÀ¤ê@>Í]`É÷*çÀt[6¸œpbZõõò`¡RÚ¡oB7‹#/]}Ùœf‰ <ŽF[CؘÀ€UUFëa…ß`}¦ì¥‘÷œ(–Æ®-Š ,HÀZÚÈ}x& ¢B·º²#/"PÔ³ÒäÃîË£©t3ìµ¢‘H";r÷ý{à~SH«ë¸î­ËmÜýû­RQ¬c[eRšVjlX–­*@B,êݲÀnxR…÷!ÄÄ ;òøô#5ŸKD‚R‘H(EÝ»ðå4Ó·ùo<ÀdRlÌÈËI&Â#/4”$¦Ä¡´ÊÃ%A²ÊšKHÓ"BÊ”©d)k÷s`Z#,Ç14t„ƒ¬GJf:Óc¡Îž©ËQ¦éá‡uáuž9Î.*v3#/&È„m1¨Œá˜A®¯ ´Ái¯%Q÷:¬Ë+Wwiå#Z¼tÃ+*qÝðif¤ž¸gè,LkzHÅâ ŠËÄ8öŽ \@ !ÞõóŸ)ãI³Ùœ¢»Bº@صYt+t'a¦˜¶@qÇ(£#”T‰¹ù&@b8˜ŽCq£â\Z.=ÛÏxÎ:oS,¢j¶†­õ¢²ö ߎ ÁÒägb5¥œÌ< 1wqáÇ&”¢òDd$‡(íõc_“#ã1ïQkR3„†ð×4V5ý ãÏóOíY;Ô1ZäI ¤þ4DF@ÂÕm¨¬‰–ÁºÆÄ#/24A#I`‚mŠ¶ CbH†Rg~¶®©\º«–›®Õ&·g%Í%æÊJ6Ć˜‰Å²´1¬™p.¶c6ÑŒ‹V#5ÀZ€;nR¡.Ñr!E’ŽË%#,æ8²¢ÚÔf?Ê#,*Â@c 3W¹“n].jw[¥¶Ûu{õ#/'·„ØÌÓšQŒAÌ<ë#,B™‘„#5ÅÓ#,{¨ãZm§ìU+qؼñA¬ ËÉXc)ÿ¼0Çðø›ÀÂB?'Yã ]5Ý]Ñ£È<ØüâWð/#5ŽÑ@Wjš2¥aeŽ(h¤b‚lt¬‡âÚlš(± ³\8l¨´›M ¢¼m¯smžæ-Ë·q‘Jr‰HÄÁ¸¢U =›y#iGM(ÚE¥ “š„qd ¾Dƒ,DCtF“X8¢‰Ë#QI_S³=Ok­{ïÃÂ%{Ž¸M- 6:7&Œ¡+…U§Kd2³ämbB¸ˆX°N5R+%"{2€±d+ 31ÆÒÆ6C ë ˜`ÃRtn(”¥#…IB=$yÔ*`ÝɳcšÖo(žjïzÝŠf;P˜›dÛ.ñæijæfyPŽ"eMž¡²X”™um[¸£ ‘Ƭ•¼#5Õds"X,#ËŒ£2†5€õˆß`ښÊÉïëñk†èh1ÐGC7DAŒj3l3 ™YÚ¨8‡¨Ñ#/j,Œ•Å‘ƒŒoÎàÃR féŒlñ­Y‚n(ë9·4TÖ€5#57× d.vt<Ô`¤yªŽŠ± á´¬f#/ôœ²j4œjŒ#/ ‚b¢Ý#5f“E³(È’Šɦ“bóLÛãÆMœcHB^»>hƒÛqËÙØÚ0‹£X>¥i °Nm(ÐvÖ­$äE‰l2ê’[BÜÁšf‰”,˜D„i4ÀND™…”’$119#,ƒ(`Pè…¤Œä¡¬GäV:Xi°Ç“Fµ}#,Œéáˆcm˜â¢6„˜&0‰ ‚hT‚"m#/,)^ª§FJ&ô{Xg&ÃAÏk´cG6»L~´c´¢¼A*u6(Ì&BÖ-#/4©ªcl[ÈËn“±1›g­M#m>Jash(Ë°Öšû¡ìbÂ…täDT×çѤpìEÐÄUHOID6<¥´ yÃpß4t=(·YeºU$â9¶H|“m'#,÷:hÜF [s(€Ùؘ;0fȈ„i-Æø*@Á’ä4!B†ÐQ bJŠ£"¤Á€4l`Ñö’È^)"¢à4fŸj´ÉÌéÜ‘iì%0±ý­*’ñ…*åM±“w½-åÝ›¤öñºë•ê¼^Mß]öWà´bƒkFª Qd`‘‹!GQ#5Õ?÷w#,YCüBd¼1#,.&ˆOϺýP6” $-Ù#,.vâ¢ê~Oæ2Æ÷¹E@_3#5#/(žª(ÔúˆBŠ2 ¨nÊH B"ˆÈ¢DŒ‹Fhƒ¸Š,™—±î B'¸¢´A9^çHä;æy{ìmò¡# BäR”Ÿ–Ÿ“Å!KFúÃyhÁ…ˆ7wRƒNçÖ‡uדù«xõÅœëcn®®š—¤ *©’Ásj‹G½%Ú¹™‚⋱‚†ótRSRHCö)gœ€víRK†æ¦ì·È˜Ê‰#/0ã§-™÷2cºþo£PDS{n)¥®åÙÞZƸK‘Þ¸k©ô¸–—à!ôÒ`6ùáw/hæÌŒGê]!¯Ú瘙Ií.À±œöÆ6AÈ¿x_Né‚!›Þq; þ°þH®­HD™¹§F*·;2“è×À “¿òyg©‰±!ê"^¸«gŸUݾÌõt48Y©/#/Ðý‡´HÆ"“L(òpDèE‘‚2%tù§`˜†Y‡¼ß{OGºÔwËRÃ*ãmTXÏêúçÖët©²å\T*#,›˜;Š5ÚkíÈ7–9”O.¢|ÂÀø`J¡Ù•[Y Ã¬Ã"ÜÎóh˜…²FbÁ"©TûY‚@ÀhZ¨ÑžæƒSé~'éãÅc«5nZUI'(i¶(°¦0%$Ù«âoƒ}Ì6À—r¾âçöåQB TÜ@´C!Uþ5A”ª¦t ÊKQ¶˜—VÅ×[ ÖOW4mðæ·_n›kžWbW¯®[kÇ5sh£xÜÖï;ZÅɵ!Ín•k`[%²BØ  KVØ#/ép¦Ýýæ·^ud®îå5\¯WÂ’,b#Hƒ¼aN@ð{4TÂØ8¦"|@º\GØ™ûƒÐb·²4c@IŠ¢å#,GÄŠÚ Ò#,z@÷?Ë€âEK´±ƒ»»omWÇ$ñ4§ƒ¾P¯Î!ÌSÎ)JÐ#—å?q @>úà…%Xù)Ô‰‚n"ÈUElïµ”×%­Ù¥®ãm×w#5ì¶tXîï.áB¶—T€§‚%€ÄÑ„pZÅj-¶´–¶íj&Úº„Y$#5j¤K6V#5˜vÉÄÂØ‘DNDQƒ$VHATˆ} #,Í#,t”¯ý¥Põ*†¿š£¥'U÷ÕOF¾áãA°GÞB&Çq–º¾ —ˆ#5©˜½¸³Àô¨!ÜzM‰X=ˆ`¿YÌÅéô”H'J^‡·`dÅï‚„:>B¹bEc„dR@²l¥14Øщ¡³-3DÊJI‰±´2¶ÑV¶Å¶ÅV›J¦U*Å©­cXÚf¢Í^hû‡Ÿik’2µ™¶@ Ð91‚•È‘>ü)pM#/1¨<¡–‘²1HEéd%T°5˜«ÊAh GGŒXÝ"˜W#5)`#/ƒeldE‘¡È1’T:„¨UFÁ‚44D"22*T ­Œ#,„•æfi–L"Ä'Ïõåkª&ô%¡ŠY¥¥Ý;7 ëO®׽^ùPD AF• B c#5FÖ‡h.*W N0é°^ËÅ6¦´“ÝshhyöKkÎ#/«EU)¥^ }#,1 ’´6ÃÃÛ±”!77´qÊà)…2u—ðm:;9øtM­`,Å#5ÎY!‹VF@A1ÄÞ©µ-Ö$<8k”bHµ›†µ’Âe.#,óm“Æááçç$¿Fb‰{¤£Žõç—]5ÕæÒåLÌßrý•ßÛ•F­¨ÛU\Õ\Ö»½¦©+ãkÝìÕÕààØç÷AÊ.qþY ”D³Úû°¹bVUÒã6±dš¤X|?f¸èmŽ8ÖAŒâ凔´}cï€r×BüÎÜâ'óÄË͸=÷PnÝO12R_áë'¸¯òvÛ¸‘´ÖâËϯ¿¶o.‘”‘ ï×eu¨={¬çpïÍl’×iõÜ“ÅÆ;ç:Ý7OKt Œk/ÑÂ)áÎ…-™Š—ÛÉ[ž/}‘äEð„/,L'ü©r‡B¤òŒ‹ôèþ©ºó’9·å]¸tMÐߊkåGW¨tYAÑ3Ï[”5ÑlJèÚ‡ÜEúy»F]Î×!Ý»®éŸÂ%#,âÅÃWN-¿b2 ÖtóßtU°uĶCŒ¯LÕK7ZXn®?“êv¹#,:°éÙN-Q“6ç¶<”h•Ò䮚ž¥°Ïå0¼‡99{ÃV48ŽŽÙ=4å²γÑ|=ÍÍvLç”ù·:8D§Èãwwj%™ ]N•æøkµŒa‚Ñnt{òƒu^9{’×F娄ǟ¥IÔ?9 ~\³½¶Í•Dã숭lÃ>7éŽÌʲéßá*ÔpDÝ5¿]NuD¤¨€ßTSLœEHˆE’æêßmyžú,[¯·ýxvvb–)ªÞWƒÕÛbOãdéb€ºL(«D”Ž—2ùÿS°wÈ´;¿®K×Oy7ËcÒ›c¢P4áÑ*“m…™¨W•Ï’’”ÇÊq[Û¾kÚwy@ûcoÍÑñð{ÃTã¢Ó<#1܇Ä÷Q'wbâü@ë¾½ìâ±ÊŽ¦u~HŠŠÉR×Þù*W˜çO•vé5Ó>ü¤#”F#5wÁTÀá öª'¤ÇRNÐú³†ºÐìÌ rldã5·îù<…ŽeÍëS’]žú=ÃñôÂ3«¦gÂH:&f#|8ßJÙjZœÊJÉÏËÇv0„! ³uŽ‹Šxéǘ!ÝÑÌ®ZœÕQ…sãšQ!Ô8s’„;È+Äu5LÆldR-ߧXRpËf‘(%¸t&!Hìj@"¢ˆÌkè/Nâ~’Ó#núž‰±gëFpðægž&˜Ý»áAÄÈéÐrúçü¾Õ´Ïq©6ºð?qä—™%bLn8ƒY|)®Ø¨ñ¬D¡ÙºøvKxdÍB—3¦zÛàMæ,4C^æ£ÜR£oä~‘¬—2_&O”O¼û˜¬àsÎÁÐç©7ï}ðkÄcŠvòÓ—#³ùônš8ü­øщH…Ë»<|:Ѫí`ƒ¬ºê‡ïD[¿e1›Ú\š»÷Æʤӱﳷ Üì.u«#ÑŸ^$àU†|£3ŸH%LôG›È´­$‰PúžÔªï¢sÇ,¤Ñlu;tm_8Ûð'äésâ]«1Çú`Ü©G„Aï‡#5ë?­å#­ðv(+t>Tú=õ®¾½<ö Aïäx @€2#5Õ‡¦æ¦&Gcª'!c–#/·Xäe“j•¦#/»•*Ô•©ò<óXœªG­_qû”4b8ì;z‹=AÀ~xHôj „qDÃ1#/*Î’v6˜±)‘){¬o¡xÑÇlè4gwò `¨äsÑ—ÅÏ•8Õ…•LbYˆØ-Á\/ILIUãœ)–Íd›mÀ9ÃmRº½Ã”(•‚YãJ^X*'¯$ÂõtÖþx“%S4!2Bð2Їs½le!ÒŠš #+‡—`“3‰—…ÚÊÂ\ºê!l2  ñ9’F£w»PW ¨ÞdÐÏa!HØ6Žã}i*ÔìÍ®“,Ìj]Š¹vmH+‘´¨óËnûd¥lrË-–¼œEŠ¡¹g2PÅj] Aò™–t#, )zè)É(— #5ˆF#,B(D[ðÄÑdÛ«…vmìdz²ÓÄ€îÐèRÏF‘,¨NHéÄÃ-òIÓ ®·@#/Ð3@Ë(ÈOœÔuç öÐÎ>± 9A%A‡š\=ZïëÅ?š•|4G°ª(="…LˆŽÈ»CÏ=Gš/¿ôK¾Ãßž<‡>7p%RÞh¥CÙL²s;Iî‡û‡H)Y.$gá„FÛ\ám°ØÌ>òùÓœ>O룦z“Ò»¢ãÕP{ƒ÷ó´‡M9ëµÉjj?Þ/£#/Û¿·k­¬„7U¨òƒ¹òwF‘®û³e1¶ˆÃw¿1¥6 X'#,Ä öJÇÄ·–Ûu¥¤kL9w*ûGnô |Pz iló0;®8~k¸óé¿F‹„ds$.j¦¸–S½£$2*!‘„’×S’Ú–3o`b‰#4@öæR÷àƒ ý8Dæ‚šyvvã˜b;8=qÀIzÓ¾.TéhünøÉÖáÆA¨Ò¦¼µØÖØq<3Gá¥:¸†ÀùŒ‘éÓM^áO•õÙK»p| 9#/š5ÞUš˜¡ª æË#5ïh*ÆN5²Qu}X5EG’ma¼°áÂÙeœ"5#/ƒ‹â¾—PAÍþüÆ8ýNœµ)é FT³†o—AÓ§\pµ Sh%¨ÔVÕ*ÉRXs›)ºÖfÌVjró¼ÊŒÌ•ÙË|¼ðL’vïlÇÉÀ´*C‚üô_ÊÇm PýX ¨ñÈ=À;ֈ缹e!M,à-²7‡R3±Áíu²œó3Îe²¸‡žy@ó((̈Æg„Py {»–ʤj®¡PÐׂ%öà˜Ì:f,øÒ­&CcÑ®d¥”Ò†#/¶…&„BÂ\ØH©½Ö–²›N,a$ß¾Mnô!Ìà:§ ØŒ ;$7„Ãj¬‘0çËì~€è®ÚòÔjxïédj†l#/~¿¯T~?"úµ¬%š—ò>œä=ÆòLo2±5!£À*€”‚}î·‰“¥D*Òs¬ðf…Ò³½1±fs“W‡D<=Áî^ÒØÈ÷¥£HQU:@ÐZX°æCV‹FѱD»¬ëw*I0 65'mû_±okV-ç–ºÕC0x5EÐØÑ¡Æ”£tZJ²F08ä àD¦@«fÞ­QA¬kšâsmͨõvíœiêGy£YUSq"T'†+·AêB¸`daL‹šbBÌQVd²ÕŒ{†±&0dUC¥›ÌwÓ6Î=>rFža†ßFv¶´O9×"}ª(ÙZ]›`Ú@ÚUÆ#¡DÐj¥†#2Yj2ZÝL3^‡võEÞ““')Œc !b3ä+•„nãËÃxºÍKÌÊ#c7ƒ´lÜA£A¶lȱÖ6¹¬5©Ñ™¼I¹s{)FÛmbm¥jZ#/µH›j¼0‹$ÍË_¦÷u®Œ½ÉÄ*qÔŠwœ#5Fu(3»ãƈŒ)a)ÓpM,(PÊ ©ÓcåƒfHÃSKÅ2¤Ô1wÌ¢ˆxpk3Žâ †iYŽ.Ílo! —R¤Æ±¶–ˆ@Óê+\ФIÛR¶Â7vÕÛmá¦oĨ#/)Âl¤‡æÂ41‰ïlñBMÐÑ¡ƒ[:JÓ6Ôj©je*Š¢…Xa†ñ“LV1·š‹.„ËÛ—KG]ÈŒ3…Ek©Š´š˜:¶†›¤†@aú°wmݳ hq²iƒ2òÈ ¶ûiæqõ<âñ˵aQÓèÃÙ”~n¡£UJ5™b´à£„Bc9GpáF2›¦ Q½åƒUƒ#cDÇF2#/BØR…hl;™1F%Ž´c4-]Fi¶pÂyë+`æ­z¥W¦dpìT¤ŠçaÌá“#jP˲ÆÔ£„rªÛ°ê ƒÐÖ?„… ­GÒ¦fn*£âjˆ‘ˆR-yZ«Œzp§m¥W—”\8@s¹eÇ-:1ês[u¡ñ­½,-™J`qšu6¾i¶Œ.òaZ³ JF™áÜ$go$®Öi‘Ôàè-2“FHÄFK3º*ÁÁ…ÓŒ»!^ž5¤E¤ŸIPÁQ®úµo´#/:Žp0ãG 0%2ÈÛ¾ÂlDqJs;¤*õÇŽ§åó„}+?_èX~×;ˆÒh©4n>õæóξw·¶zê_Ð×ÒŒ3+Ѧ#,B6i±J>°X"B“´*Q)#5UHkø¥2Iâû=µ(Òe!ߧeS¾¬gy­[€i T¦2Û³÷œŠ $UUFJ2ßê*{ÑŸñ/PèEÏó+ÚIŸCªšc‰jó=¾¸CÉûÀþ^°æ‹ëA"qm!–·JÍÈÍPƒ€ñÂ@A²ûµï¿JÙ&a28÷bÍ„Ú[Ýøš§Õ„zÞlº… uq–ÐúðöîF›ºNîäÈ!ݽx÷õ5¼i]tjaQp%-T¨Á³È3=‹g›ÝÆuë2‡^Ð÷¢? ;Q<ÍùT¡“ŒHQˆ á6o-ÕA#ôÏË9ž½Â(Vk{–±´à‘À]‰LÎÈ€ôRƒQ‘a#,X°Aˆ¯)¶¹µ«¦ñ­kË«¶¹¥R«ÍpÝüSòEæE?Aß×ß(Ò}ü$$ŒcPÙQ²’¶Ñ­(ÔF$ØQRRa¶¦VË2j’Ù¦ÅZÆÍ)*‰-&6fdÉ¥–Å)HÊZiR”fJˆ¡Šm¢l”li²Rš,Ô©¥h5"É› 0Œš2[V1­­üëßÒ¿%Þ‰‚ ñÀö¼«hâ/¶%¸PyòŒå¸ûæåteÌÄóÜýOÐ×ó°›ü\÷Õêî¶Ï\ÚD‡ÆsVÑ|’aAdƒpp½ïj–«U¬ZÊ#/5ÂþGŸ§Ç4AóÙÔo³Dó.F#5ä´v‚~Y»zOg†ƒƒM#55n’öÄ 5/öî„ð )"‚‹¬kI­}æÕ®[1¬)4H)-A›_r]¡j•BÅ#5PÅFR>´²eÏ€`'qxå!BŒ*O·Û˜\3W@Ëd}ö^¿°¸j@j" þ˜QjxoCŸŽ]+L"k¦VºŠŒ èËRûŽQÌE4\#/4‹¡w›¢eÙ“$ÂXÃ#,4Ž±w$Âl&‡…1H ªÏmM–ê”$ÅP* ÖXj%í%†¥ñÝ›&õÙcßÍÕõÍz“zÑmF:š¢¬´ò½¥*KHÆ‘#55Q’¥Ñ#5E#,ï8ã'áí5§æá ÙòÅ6FK^΃ҺâP{7¿g_©y»Þ-FÞ­»"’bTi²ƒYDqbÊÿÙÒÈlÐ.g›.j˜R´4•/ ¦d£$1A€`½Qˆ<,1‚:5$m|Ú¬ 8tˆDn`*LCq-ä "I$‘ÁPÙ·‡dœÐʨg˜b¥(¡˜HѨ€7$Ç¡æi;¼ÄMó­#/é\W‡_78ÏÚ•×(,ú/dî"B_òá6ø0 hú½*s¬añ²‰ª£-n]MµA}êÂRЗ0 úT%Ý|È#,ñ‚¿ ¡p˜{ ÄW(4ôçèþ·Œªôn%Ô¢•[«xc%Ö~~>O–ºèjIÛ:ãØ?‘ëSQž‹ñ*ûó)¤ÒÂ:#Êse·ö˜#Ø8…ïúèbáöôaç¦~ÉäX2ŸaÌÈWJñÆÓ­Œz™TZ™ÎÚäÉ64.Œ#51B}©%÷s]kÉ^vœƒ-¾ßaî°i«Ð=v²¾´äœ­r4ié>4"’§< f׸‘©"ø5,:ã»;í˶LÏgÕ&åØ›>f;}J`8§²$DW‘ë5êOñšØ§¦#/‡÷œËEŽç`VŽ@)2g³š Ú611ÿ}XwÄh7!€ì#QýÿTÄ7vuI¨™3>Þ_b7Olbwr>^þ‘BIDI(€Š%çìBöÕ(´jtû´íƒ }'‘n,,)Ÿ¿.¾¯ÏD~ìèGëì~Ç­n~MLáØÎôFB«¦‹ PÆ,+rc¹`Ã6'^ž]hlÅ0ÔU÷¡ƒÑËqQ$îö¡š©*}_m[îÃx`¾fo\e#/1IqˆoÁÚkö‰¼¤þB%„Ž¹°ÙW*Y5ÔX6Gîg|¢ƒ]82¿’Ü1´„–‘™Ÿèw»Þ:*DôyG7p‘l¹ 9R%T:­+ŠŽ\~q5Œæg”à§FÔ²4Ã0ÖÚbj„‚"Bl3Æ 2&#,¤LífÚŸÔZV’ÐÈúˆ¨ª) Ìú—l!Ã4ÈvWº«²™º"¨ih±bE `BFÈ„TIx6;8ØÓâ„Gx£½¡Èk™¡¤’9É¢K7PeÌÓ=™Ø#,˳RƘÈ­h¦RĹ”6ºsÐÙLv‘ƒª³”¬A‡8¦Më¥×'“&èy¶ ÃD…ˆ³Z(`€nQ©ê?i˜` `‚PÈÄ̃Þ"¸7§VŽ¨hͤ•B[ÊBÒ£SÈ4,U±M‚FÌÝîãø¥‘Y-…mÃs=rkš†™Ü±Qš ²dãg[YšÔE`؈‚Ù™ƒNcQ¨œWõúù¾¹Þ ûëgC‹èý #àSAcÕ›f&3ÖF|N.š°cðœ(F®u0ù„õ\ô€Ç;9ç5`Ž¯…í.†êiа;eÛCÀûï&:V3+»ä:ô)˜–t[½C‚;Î’Š[„.êö†5¦9Î'½‡<³‚XÐŽ8-TÑGˆ’Iº›AÊ… °4IAŠ’³#5Ð(„4Ãà˜o³Â^+Þž£ÈFÝøf´kq’Ç—á“SîÃJj—9½Ú›Ê㶠cïLé”hG“×2©á¤AkHÌŽqlcŒ°—Ó`CF”„8íîŠã ÎöêØDI"ÒÆL¨¬2‹™C4 xv´ÚMBÔrç4è…"•j‰D°Î²Òb|ErEbÝc,n#/3AÃkPÁ- A èw ƒ¦¶FH¨åJKy|2”˜LÕÙSÙÚâs\Iu`B2 ëÆÛ#/H³%@òÚ™Þju ©æ>Ír+R–fCÂÐe¶2g=×Ü×mtyBçC‘±Öi ¡f°E2Ç#,Ò7 ƒ@毧̇jXH8ºÎ.Q0tWF;bÑtç±Ócir8ŽMÒ(e#?ê‡h0._Òƒ Ì–‰Ó57“HaÊ< $t3 Sl†tÓi#,s´“Uˆ²P¢& mð±N5:þ[VÆ-ÎPd+‚¶’к0psW)„‡.˜(êã–Kiä¶ 5˜šf…PŒ`dYˆc0’“™Øïú×;ËÓð1 ¸ë\‡Zg;‰Ø0SC#,šÊ©&;XÒ){(zžpÛhK“bK¶èä&º†2Žƒö_ø6˜¶ÎS9’Ô`ôÊŒ¯ƒòö“wLôöx€51X0“Í“¹š£~G36‹ xÑ4õë~F´(ã›ky%\»}ˆGGѼ³Ñ_ k§Žp9kI©X«Ob\8W˜¬L°ˆ3‡f²á G”› ¥£íéxıu»Ú“¶¸ò• #5ÒtÚš–b¿o[£¦ À"l]D¥!Á˜¡*£ó~í¥¥÷ ƹȴš·¿¼7½NP¡Ù¨‚Ê]<ä¹nî7ƒ»åZ íû‚ï¨ò žzbŠd׎(ÍÙ1Ä0ã2ölUñ7’¼–¹¤å£^·*éÁX)ðžäŽtÂfªH›¦ -¬¸1laù¦‡@Íå1¯GYÛv"öÉ,˜;ç„ÎCÉœÉÕZÒ¾Rê41ë~¦XŸŸ•ôÎ0ÑÈ*ÐÆ»ùœ‚#FÎf;&Úlðæd#/ø´3J±v2›§œ¶/5Ê·æF*VøDtCH>4š[ï ’u,w1Œ`¢ÑÌËá¥GBmðX¿cõy­ÓŒÞ0fßE4Q«HˆPÈz!‹ªhEçAFH"¸ªPÝÖMO6÷ÜÉÂÄ;½S¤]Áõë- 2m)\g†`uns…˜®EÌv#DÌ" 3µœúQ4ºÙ"6#/KÀ2ÁÐÃDb¬HªŒbj0¦Iz©#/ÎUñO/wÉHRöYu,««DëJb(‘ÙÅ®ÿ#,Ì1aª"/eHÚ‚žhïCÀø3bi˜RœÊ»ƒÀ CiÁ¨Q Á’pìŒÆá Äaƒ¨bb_BÖŠ*EsI`dl!‚LZÐ6؈‰ ìªXò¨¦&Ý„—²z½}'Ñu”¹F TTEA³GnP]f^®¹=£`Ë*„;E„HH)¨ 5#,æE~íÿÜ[ײöUAÖs—¯}Ø* &ɸ‰U$_°. Äh”"%Q Èvøž@PÈO.Mæ31<Â+"Æ’©bP2Á8âd‚TLc`Ç4kÄÕçxKÍÝbT®[ÞëA±ä! d… È𢢌A¨5%TABJ‹J :éˆã#, >l|si(A¤:ënKßwL¹C®’dˆdÐØ&`¬R, „Nˆ{úÓ³´|û¼B|&>~šíFù ½pà‡ˆ)òáõ´Æ~嚈•Î†Ÿ×3¹FŒPp ‰R‘Ks1ŒµVDD Ð9†Y~И]ÄcaS&¾¨™Jëä%„õuØ'CŸAMìM€ð iÉîŽã¡L’xØÃ)âA!ÜH‹Žû"ÌCÉ©ä±Í#,…0¿‡B°ˆX¥ àïÙϲ؂l‚H„€†a>’6LNpNþ=AÓU7ö#5‡h‚˜|>#, t"qvõl"HÐjá†Tvè®#5dÜ:cD“A‘„\r,É#/ör}°áM‹BÏÌ~eŠ0„a#¥¹#ÏK5 Nè"‚i¢1XY«:ÔEŠñd<¹饤CM"ò£¿!Ý,FÙ‡†a­4¦…ªÂšØ}C¹Ï;PÚC-¶`¯³k9NPïÃ+Zë-sŸ‘‘ƒNÉ ; Ô÷gÛl¨í­õÛ”I°6“jÀ*á,YpèhYhý[¾¸©¼ïðQãU#,E€§¹% 6Ø¢j2‹•1pA-šý–a]Z³š‹06ˆpM Nÿ¬NJJ†RS,Ûs#,Þ&àŠN|P¤¡#,ë:Ûv¬®¾`R)eZ·Ò —Aý‚«! Ó.¾™Âþd|yõl C7Y0Ó®e‰ÖpLCÍ8äP$ E`AAÀU€®ç²=|°Mß#ÆƉòõª×aÈáÐ-@ª!RÈ.B¨6#,R¼„j#5~'»èý½ø$Àce„Yˆž>ߣáQ¼æÅœ+4¢SøÑÈtx×_¢ŠRÉk ‚ß…Ãð?ɨ|>>ïo*ÌŒ>k,"˜ö{M þ3Ah„'ÿÕ·Ä–ŽoN憨m·4kÊ«@(í#,¥$HßÝE‡*oßû©hÚä¾’¿ª ÝZDúbl *|ûÇd,)À_ï€vX.Øbvòر-¸$HÈLÈÅç\¬VaI)"îåŠûžtÞh5xñ^5û’çž^o+Ï|ñM¦«´E°ÙT"6¯uÛ¨à &³KQD™ Q底6Ó6†˜@J” *pþ$Šl¢›OùÊ_w›¼½y$†@!» ¼9›Æ@eÖD«M"¦!ë5ùßHö#,õö‡ok"È,€ÁH1FItIÜ‚Œ‚HKJ“$–*eh²YfKf’m_õãc}ÍWòõô)TC™Qª4še,Òîü°IüOÈEP¨‰Ÿ²–»|Æf7Ò@,)ºî¦I#,àOØc_T½´Ý×6bldÔM¬ÚŠ*Åe¦FÒ{çžjˆ@B {(#,´D"ïŸóD-ÍA5ÿ‡‰˜uw“âú¾¸Á×Iâ¯A5ÕÁ¾Cxtœþ{ŠÊÄ "ñ½WDLp1 ÷¢ž$‹Á¥ÇŠ3˜)–S T‘²Â½´`ÏžfÆð)B°ÆÄ%—óéA¸{ù›iq¢à2 Fû˜ã†1Øž¥MÂÀËCÚXS¢yL@A|Á€A¤Ím6´”„$µÍÉ­R­)6¦Útï–¦‚ Š)sVÛ7“Tì"®J€Ø=Z”`J¦H(HöÚÃe·XOn’ãK¸Ý¨ÕZ¦µÂ} @xÉàRŽ˜ô<ýT-ÙÉiHØœý4#âì:ÆØ£"H›hx’öBVÜÛl Lµ‰Ž„À?,·ïgÍóºÒå†.[6oYhD x˜`næçü¥¿©¶ÕÕúº¾¹}¾:(52&‰RE‘¬SEŠ)(*"Ú2UB•È­úm¯5#5- ÚJ€¦§á•³ñQ –|dK,'Ü2n„ŒD*–QE1cG¢Šh™ññ5± *…¡·`'¥ïŸ\p]»% n»š ´È‚…dCDZ‚´¡¬P›i²ƒ!ƒ$`'‰µòíÌÛæÎíí¥VXjc·Õ¾>øÁW6¾¿9Ž>¢ZØ–0l³(CÝÚmwû š_©ý~C´+CaXe²œÚã-‚#"T²44x d`;ý´:`&ÍlkrÜ’•}}«•¼»¨’Ú*+|®ëÎ˱\ÚZõ©ç[[Æ£E¥™ªÏrGë6³#¸Qý¥d8$-#,Ì,&íOQÏ¢I¨u#œˆr"ĺ3Çü3AZM±¦¬M ( pÈõhX}tfò]JCñ`aÀP®%Li¾pCq5‚u‚]¶ÅaÕ%A‘B0Xs¢k”´nåÕã^o*ëIbÝš™™UÜí´Ò¦Ô¡¯{µÎV+*TÔQ±­çvךû+½¡A#,¦Ac)H&5„h`ÆÈÚ[R•¥4ËfZé·nè”Ò ‚ˆNE¡RDBNεm!‰°éžXK„=¢ºÿÛ—òà«‚Yƒg±¯¤Uòf┘4Ñ8/Ž1†aU3ç qyjI²ë²©Ùíîù"Ö/PXL*&†©J8»÷zÞìñ0lèÑcMû=#/fü…º³ìÛÕB(£Š‡"­yšëÚ%ôÉ!ô^ˆKž‰ BA¢"˜5‰#/ðè:8$ÉQ;’ý 6’_éc MæÿÀZ׎§_¬•¥Çk“Û|å†ýi‹in‘Û¦Jµ ª-ä~?Prg´š¼<ûh_cBQ‘ƒQºô0m­Têð#/(PD>›r8”š_™­ê`×L‹ãõ9ô`¢ÀŸ~úÙ¤q<–ó€’Ešôbä¡HXÜáÛ(Mˉ‚„KÆV#5vÂ9¡4k%Pm¬ýLzŒlŒ¶Œ"À×F\¢é¿HbqK÷M|§hͤ†ÉpdLT“‘=Ic0äd¸(ŒR„¥ €CJâ'#Ãg¥1üÙå—÷#ö^3À!Ç<ª„¤2îz?2P?ø>³Ê¿DÉB6 ʇr³¯y±cÞÀÉï;ݦ"ó¥jIb8h™#ߎ'\¥„Ç:-¥i#,¾e#CûaU°þ¦ŠùŠ¶Ý¿hzž­:µ9´ â(dÿj‡©†È˜2*&½5趙®õmÑ߶…ÆÆF Ú[âôv3óŒõÞäB4Db†'RÖèmI€*™‚ØB#˜BC¡â”_óÄÈé†`– ¯N—À±¤ˆçç"RÚº#,“m2hæaŒ‡/b"fg;Q‰¬ãÛ¬˜‚ö ¬;h-Oî5z¼ìw™hiìºâˆ¤ýØA´ ¨cñ¯Ž+qÎz)\ X¡7 uâÆtù–‚ åþ%)`aá<‘êz¢¾*~LÌÁù]ü7¼žÜ4Ò÷̺‹DSo·\-baúâ.èg_îþ_áò~øÿ»ýÿîÿ»þͶ¿þ^Ïû7¿ÿ‡þ¼?ãþ_÷}ÿþ¹~ÿü<¿ŸüÿúßÿWûçÿ<ßønëÿ—§ðéŸþ?ùYýÿ÷ÿûÿ‡§þ{>ð³þ_ñïÿ‡øËÿχåÍÿøÿËþîÿ¯Ü~O÷þÿ¿7ßùéñ87ÝõõvŸù]†‡ô‡õ«b"jy6Å5M…\?Ð9ßJ<˜«î°B U!œpEÝ!#ZûW‘nóøwïi|§ñyÎî™$Š¢1Œy„ô2IRC²Šl`†éÝG¹¯(Ay4Ú!®z©¨§#,˜6Ç3ø]þꥂƒÜ?îßžÔÓi˜\Ùp–êx†ëqFï„_÷TK´,ã5(„æ)A@µ|nÌ&8ãt§00ÀQa×úèS<šßSÌÿxÿ/ûÞÒÊ?÷yšz6¦ÌÖÐèQþmIŒ‰ôŠ‚Å ºI'ˆÈeŒÌ ¯I?ôÍ@œIÀÜq¿ ÿ•ieqÖ&!3"…2*×r­göòì {­0ªB Ü”Ï&QFišÈ4).¨±ƒ—Y/$³ýùã’ìç1UjUø¦‘2ðÍD)(»p®ýq¡X0š+šANL1#/(=í8C(hškT˜mѤÝEpq1›ˆŒZæá–°ÛÖÓF˜›H†CÄ#/ÿeÉV×#/(k†â¯ÙæIJƒˆ”iåÅÓ%KK¦#/¡²°(R°™ÍŽÆo®'?ì&#/ôçÌö~¨]1ì¾3.ÊbVæ.Èœ¼Óò™àƲÌÌ5¡‘Þø(ÛÚ¿¤—^Íár#%µíÒsVoîÀUÓØÃy…I9óovÿy–#Ûî h1‡¢ #eëÛ³¶5c+KMoÎÃX`­±Œ9¤ž$½CÛ#/V¡¶çB¡<)aó¯´×»á¸ F¼6 ».ˆ¥ÔÏ×·*•ØŘ/S8òÒ`y±3DEa éŠHÎûs#1ïÎËXÍ¡&Hc|·E!Š†Q‹{ňPÑ~––2© E$€¨šy‘¨§J'\3Z€#,À’1-î ü ‰bfi¾ØX(/Õa狸1ågi±ZÒ#‘»#Rý^¼<À¦S ‚ˆ‹ ËJ%B…ATZ²”ʶJÒkL”²C`ÆÊú]ªå#,2Ê€qS#,™?Þ@2ˆÈÁ?ß&<*›(«yÁ-‹'3Ù( %ÂT@¥b(yóúCèïGU¤?ê‘Œ‰ yNð`ò54±Í%2gúF„c!t§“ì#5„Âdx‡‰útttþó‰,¤TG3‡ êú¥#5%±œsøâÓoæ0Ï{BŸûdk»:uNô§VÇë*K~¯xÆ=%ȼ©¾=Í©ò°ööpcõ•]*Se`nL2\aÓs.® #^áÆÙ²Ñ>Ê,7Ÿt›Qyä>–*m4ØšÙîá=(Ýá{.eoÆD'4Š°‡TCVzI”D%%Ý€-W­nm¥•´¥ëk^·ÂÕ}Ëã­IQTZ“D³hŒÆ#/1(мf±Ó¬"5Ýa+O(~^“ÒõÃñ¢ K‡?ìÄø KÔiµ @r19Nac#56œìÁäK–*%*¸”øóèI}0í$&PšÕk##=”´î#5'¯òŸe»".hp ÒH²!!7’æE Ðö‡qFO$v£“íà'‡ŒÿØ ¸zäj*„bECkµÇf•„”ÕË›­«%jF¸jûr¼Ûo%Wؽh›53_•ZüÈ£h€#,ˆäw·Ïá™åóÿ×Ö‚w!=~¨©ãå(ø{f8ò0m¶ÖŸŒx;.‰x§ª#/gȤòû?ñÿ¡EB§ýZþvÌÌ#/l‚Å'ù< Ué6áæçûÔU'ý]¿Å¨£Sõ#/ J®ýá—Ò>ý{pæWi.ò#/¹ÿÜZXßæ§wú¿ì†¯SüþÓúùµµ™ù#¥l³·¢1¡¨zeë¢×Ç¥vñ‰’©œ~®yËAƒSù>¶ÉÓ¶ˆÄÆVJsøzK„pYkϼ#Dâ¢ZÍÆ! ^G¿§,ÀŠÃ$ Œ}ûYOÎÏužº6³8•È'ÇõçÙL*Ï«Ï£o3¸žÍ~ŸWüÕ‘àRsŒâ;Ó¹j¬b/È5Y_ç²V7Ä|¤É{~¯ÿþ.äŠp¡ Ú‹ê– +#<== +#-----BEGIN PGP SIGNATURE-----\nVersion: GnuPG v2\n\niQIcBAABCgAGBQJWpU3oAAoJEGelZe39+Q5kv04P/iyvALGAg2Z8oICEDjFkEXWW\nh2CMGLItAhqb3xNeV8WUMMpY4MbRRpN6cU/SPmt+as4oVn2pozca93eWD7yOxukK\n10seOyLTBamS0Wf+BNr6jYXZRQ2N7inc2p6AD75pMOFSg2HeIeQJ0aUIAxNeeojZ\nmUiLYMdtcrF1Kh7KWZAkYSbIAEjJeobLqk2oY7UyqKcODc4RtZJV1InnO4DItEWD\nnd3F5kkVMw4pwYAXaikmCXYBKHXdF5w82KxqEjrAWSoULipX0BVCsSbQ2L0UOs5h\nKXUS4M7AaYKyCcO17E7CnVXaW+vOVyGEECxtSaExWgK5MvYHIGE1OFvb12PkUvUY\nc7CiBxk6X5eZkPyxgxDj20r8zNQVGZ8jDI8Wg08yTAl8+09qCtkE8gGMdNeHYwX8\n2xDH+A3+19022ZZdyO2t5+2AzU6Kkl1qTPKaXJWFRtr8ApD45Y4D3/GAsTNqdOMi\nWeh1XvqQdHjm9rEoJX8aBXShzCMCNhmZalbUhrdzQY6/hnl0PqnlPtyvtkjCvWoF\nXLF6q8YV/ZtqCc36vePZ6lpUQB6FG3g6fhMGraT2VOmT3TROcG17pqIz5y9+85xy\nVSaDc82uHlyzIsZ7vuhV6d9x4yXnFkjMAogCJv6mitFbQsd+LtXYkU+2Zq6wOoEp\ndLLfK0Km4Vs9FYAUbuUi\n=7D7V\n-----END PGP SIGNATURE-----\n diff --git a/gomspace/libgscsp/lib/libcsp/wscript b/gomspace/libgscsp/lib/libcsp/wscript new file mode 100644 index 00000000..7b9cbdba --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/wscript @@ -0,0 +1,346 @@ +#!/usr/bin/env python +# encoding: utf-8 + +# Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +# Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +# Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import os + +APPNAME = 'libcsp' +VERSION = '1.5' + +top = '.' +out = 'build' + +def options(ctx): + # Load GCC options + ctx.load('gcc') + + ctx.add_option('--toolchain', default=None, help='Set toolchain prefix') + + # Set libcsp options + gr = ctx.add_option_group('libcsp options') + gr.add_option('--includes', default='', help='Add additional include paths. Separate with comma') + gr.add_option('--install-csp', action='store_true', help='Installs CSP headers and lib') + + gr.add_option('--disable-output', action='store_true', help='Disable CSP output') + gr.add_option('--disable-stlib', action='store_true', help='Build objects only') + gr.add_option('--enable-rdp', action='store_true', help='Enable RDP support') + gr.add_option('--enable-qos', action='store_true', help='Enable Quality of Service support') + gr.add_option('--enable-promisc', action='store_true', help='Enable promiscuous mode support') + gr.add_option('--enable-crc32', action='store_true', help='Enable CRC32 support') + gr.add_option('--enable-hmac', action='store_true', help='Enable HMAC-SHA1 support') + gr.add_option('--enable-xtea', action='store_true', help='Enable XTEA support') + gr.add_option('--enable-bindings', action='store_true', help='Enable Python bindings') + gr.add_option('--enable-python3-bindings', action='store_true', help='Enable Python3 bindings') + gr.add_option('--enable-examples', action='store_true', help='Enable examples') + gr.add_option('--enable-dedup', action='store_true', help='Enable packet deduplicator') + + # Interfaces + gr.add_option('--enable-if-i2c', action='store_true', help='Enable I2C interface') + gr.add_option('--enable-if-kiss', action='store_true', help='Enable KISS/RS.232 interface') + gr.add_option('--enable-if-can', action='store_true', help='Enable CAN interface') + gr.add_option('--enable-if-zmqhub', action='store_true', help='Enable ZMQHUB interface') + + # Drivers + gr.add_option('--enable-can-socketcan', action='store_true', help='Enable Linux socketcan driver') + gr.add_option('--with-driver-usart', default=None, metavar='DRIVER', help='Build USART driver. [windows, linux, None]') + + # OS + gr.add_option('--with-os', metavar='OS', default='posix', help='Set operating system. Must be either \'posix\', \'macosx\', \'windows\' or \'freertos\'') + gr.add_option('--enable-init-shutdown', action='store_true', help='Use init system commands for shutdown/reboot') + + # Options + gr.add_option('--with-rdp-max-window', metavar='SIZE', type=int, default=20, help='Set maximum window size for RDP') + gr.add_option('--with-max-bind-port', metavar='PORT', type=int, default=31, help='Set maximum bindable port') + gr.add_option('--with-max-connections', metavar='COUNT', type=int, default=10, help='Set maximum number of concurrent connections') + gr.add_option('--with-conn-queue-length', metavar='SIZE', type=int, default=100, help='Set maximum number of packets in queue for a connection') + gr.add_option('--with-router-queue-length', metavar='SIZE', type=int, default=10, help='Set maximum number of packets to be queued at the input of the router') + gr.add_option('--with-padding', metavar='BYTES', type=int, default=8, help='Set padding bytes before packet length field') + gr.add_option('--with-loglevel', metavar='LEVEL', default='debug', help='Set minimum compile time log level. Must be one of \'error\', \'warn\', \'info\' or \'debug\'') + gr.add_option('--with-rtable', metavar='TABLE', default='static', help='Set routing table type') + gr.add_option('--with-connection-so', metavar='CSP_SO', type=int, default='0x0000', help='Set outgoing connection socket options, see csp.h for valid values') + gr.add_option('--with-bufalign', metavar='BYTES', type=int, help='Set buffer alignment') + +def configure(ctx): + # Validate OS + if not ctx.options.with_os in ('posix', 'windows', 'freertos', 'macosx'): + ctx.fatal('--with-os must be either \'posix\', \'windows\', \'macosx\' or \'freertos\'') + + # Validate USART drivers + if not ctx.options.with_driver_usart in (None, 'windows', 'linux'): + ctx.fatal('--with-driver-usart must be either \'windows\' or \'linux\'') + + if not ctx.options.with_loglevel in ('error', 'warn', 'info', 'debug'): + ctx.fatal('--with-loglevel must be either \'error\', \'warn\', \'info\' or \'debug\'') + + # Setup and validate toolchain + if (len(ctx.stack_path) <= 1) and ctx.options.toolchain: + ctx.env.CC = ctx.options.toolchain + 'gcc' + ctx.env.AR = ctx.options.toolchain + 'ar' + + ctx.load('gcc') + + # Set git revision define + git_rev = os.popen('git describe --always 2> /dev/null || echo unknown').read().strip() + + # Setup DEFINES + ctx.define('GIT_REV', git_rev) + + # Set build output format + ctx.env.FEATURES = ['c'] + if not ctx.options.disable_stlib: + ctx.env.FEATURES += ['cstlib'] + + # Setup CFLAGS + if (len(ctx.stack_path) <= 1) and (len(ctx.env.CFLAGS) == 0): + ctx.env.prepend_value('CFLAGS', ["-std=gnu99", "-g", "-Os", "-Wall", "-Wextra", "-Wshadow", "-Wcast-align", "-Wwrite-strings", "-Wno-unused-parameter"]) + + # Setup extra includes + ctx.env.append_unique('INCLUDES_CSP', ['include'] + ctx.options.includes.split(',')) + + # Add default files + ctx.env.append_unique('FILES_CSP', ['src/*.c','src/interfaces/csp_if_lo.c','src/transport/csp_udp.c','src/arch/{0}/**/*.c'.format(ctx.options.with_os)]) + + # Store OS as env variable + ctx.env.append_unique('OS', ctx.options.with_os) + + # Libs + if 'posix' in ctx.env.OS: + ctx.env.append_unique('LIBS', ['rt', 'pthread', 'util']) + elif 'macosx' in ctx.env.OS: + ctx.env.append_unique('LIBS', ['pthread']) + + # Check for recursion + if ctx.path == ctx.srcnode: + ctx.options.install_csp = True + + # Windows build flags + if ctx.options.with_os == 'windows': + ctx.env.append_unique('CFLAGS', ['-D_WIN32_WINNT=0x0600']) + + ctx.define_cond('CSP_FREERTOS', ctx.options.with_os == 'freertos') + ctx.define_cond('CSP_POSIX', ctx.options.with_os == 'posix') + ctx.define_cond('CSP_WINDOWS', ctx.options.with_os == 'windows') + ctx.define_cond('CSP_MACOSX', ctx.options.with_os == 'macosx') + + # Add CAN driver + if ctx.options.enable_can_socketcan: + ctx.env.append_unique('FILES_CSP', 'src/drivers/can/can_socketcan.c') + + # Add USART driver + if ctx.options.with_driver_usart != None: + ctx.env.append_unique('FILES_CSP', 'src/drivers/usart/usart_{0}.c'.format(ctx.options.with_driver_usart)) + + # Interfaces + if ctx.options.enable_if_can: + ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_can.c') + ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_can_pbuf.c') + if ctx.options.enable_if_i2c: + ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_i2c.c') + if ctx.options.enable_if_kiss: + ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_kiss.c') + if ctx.options.enable_if_zmqhub: + ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_zmqhub.c') + ctx.check_cfg(package='libzmq', args='--cflags --libs') + ctx.env.append_unique('LIBS', ctx.env.LIB_LIBZMQ) + + # Store configuration options + ctx.env.ENABLE_BINDINGS = ctx.options.enable_bindings + ctx.env.ENABLE_EXAMPLES = ctx.options.enable_examples + + # Check for python development + if ctx.options.enable_bindings: + ctx.env.LIBCSP_PYTHON2 = ctx.check_cfg(package='python2', args='--cflags --libs', atleast_version='2.7', mandatory=False) + if ctx.options.enable_python3_bindings: + ctx.env.LIBCSP_PYTHON3 = ctx.check_cfg(package='python3', args='--cflags --libs', atleast_version='3.5', mandatory=False) + + # Create config file + if not ctx.options.disable_output: + ctx.env.append_unique('FILES_CSP', 'src/csp_debug.c') + else: + ctx.env.append_unique('EXCL_CSP', 'src/csp_debug.c') + + if ctx.options.enable_rdp: + ctx.env.append_unique('FILES_CSP', 'src/transport/csp_rdp.c') + + if ctx.options.enable_crc32: + ctx.env.append_unique('FILES_CSP', 'src/csp_crc32.c') + else: + ctx.env.append_unique('EXCL_CSP', 'src/csp_crc32.c') + + if not ctx.options.enable_dedup: + ctx.env.append_unique('EXCL_CSP', 'src/csp_dedup.c') + + if ctx.options.enable_hmac: + ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_hmac.c') + ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_sha1.c') + + if ctx.options.enable_xtea: + ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_xtea.c') + ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_sha1.c') + + ctx.env.append_unique('FILES_CSP', 'src/rtable/csp_rtable_' + ctx.options.with_rtable + '.c') + + ctx.define_cond('CSP_DEBUG', not ctx.options.disable_output) + ctx.define_cond('CSP_USE_RDP', ctx.options.enable_rdp) + ctx.define_cond('CSP_USE_CRC32', ctx.options.enable_crc32) + ctx.define_cond('CSP_USE_HMAC', ctx.options.enable_hmac) + ctx.define_cond('CSP_USE_XTEA', ctx.options.enable_xtea) + ctx.define_cond('CSP_USE_PROMISC', ctx.options.enable_promisc) + ctx.define_cond('CSP_USE_QOS', ctx.options.enable_qos) + ctx.define_cond('CSP_USE_DEDUP', ctx.options.enable_dedup) + ctx.define_cond('CSP_USE_INIT_SHUTDOWN', ctx.options.enable_init_shutdown) + ctx.define_cond('CSP_USE_CAN', ctx.options.enable_if_can) + ctx.define_cond('CSP_USE_I2C', ctx.options.enable_if_i2c) + ctx.define_cond('CSP_USE_KISS', ctx.options.enable_if_kiss) + ctx.define_cond('CSP_USE_ZMQHUB', ctx.options.enable_if_zmqhub) + ctx.define('CSP_CONN_MAX', ctx.options.with_max_connections) + ctx.define('CSP_CONN_QUEUE_LENGTH', ctx.options.with_conn_queue_length) + ctx.define('CSP_FIFO_INPUT', ctx.options.with_router_queue_length) + ctx.define('CSP_MAX_BIND_PORT', ctx.options.with_max_bind_port) + ctx.define('CSP_RDP_MAX_WINDOW', ctx.options.with_rdp_max_window) + ctx.define('CSP_PADDING_BYTES', ctx.options.with_padding) + ctx.define('CSP_CONNECTION_SO', ctx.options.with_connection_so) + + if ctx.options.with_bufalign != None: + ctx.define('CSP_BUFFER_ALIGN', ctx.options.with_bufalign) + + # Set logging level + ctx.define_cond('CSP_LOG_LEVEL_DEBUG', ctx.options.with_loglevel in ('debug')) + ctx.define_cond('CSP_LOG_LEVEL_INFO', ctx.options.with_loglevel in ('debug', 'info')) + ctx.define_cond('CSP_LOG_LEVEL_WARN', ctx.options.with_loglevel in ('debug', 'info', 'warn')) + ctx.define_cond('CSP_LOG_LEVEL_ERROR', ctx.options.with_loglevel in ('debug', 'info', 'warn', 'error')) + + # Check compiler endianness + endianness = ctx.check_endianness() + ctx.define_cond('CSP_LITTLE_ENDIAN', endianness == 'little') + ctx.define_cond('CSP_BIG_ENDIAN', endianness == 'big') + + # Check for stdbool.h + ctx.check_cc(header_name='stdbool.h', mandatory=False, define_name='CSP_HAVE_STDBOOL_H', type='cstlib') + + # Check for libsocketcan.h + if ctx.options.enable_if_can and ctx.options.enable_can_socketcan: + have_socketcan = ctx.check_cc(lib='socketcan', mandatory=False, define_name='CSP_HAVE_LIBSOCKETCAN') + if have_socketcan: + ctx.env.append_unique('LIBS', ['socketcan']) + + ctx.define('LIBCSP_VERSION', VERSION) + + ctx.write_config_header('include/csp/csp_autoconfig.h') + +def build(ctx): + + # Set install path for header files + install_path = False + if ctx.options.install_csp: + install_path = '${PREFIX}/lib' + ctx.install_files('${PREFIX}/include/csp', ctx.path.ant_glob('include/csp/*.h')) + ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_lo.h') + + if 'src/interfaces/csp_if_can.c' in ctx.env.FILES_CSP: + ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_can.h') + if 'src/interfaces/csp_if_i2c.c' in ctx.env.FILES_CSP: + ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_i2c.h') + if 'src/interfaces/csp_if_kiss.c' in ctx.env.FILES_CSP: + ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_kiss.h') + if 'src/interfaces/csp_if_zmqhub.c' in ctx.env.FILES_CSP: + ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_zmqhub.h') + if 'src/drivers/usart/usart_{0}.c'.format(ctx.options.with_driver_usart) in ctx.env.FILES_CSP: + ctx.install_as('${PREFIX}/include/csp/drivers/usart.h', 'include/csp/drivers/usart.h') + if 'src/drivers/can/can_socketcan.c' in ctx.env.FILES_CSP: + ctx.install_as('${PREFIX}/include/csp/drivers/can_socketcan.h', 'include/csp/drivers/can_socketcan.h') + + ctx.install_files('${PREFIX}/include/csp', 'include/csp/csp_autoconfig.h', cwd=ctx.bldnode) + + ctx(export_includes='include', name='csp_h') + + ctx(features=ctx.env.FEATURES, + source=ctx.path.ant_glob(ctx.env.FILES_CSP, excl=ctx.env.EXCL_CSP), + target = 'csp', + includes= ctx.env.INCLUDES_CSP, + export_includes = ctx.env.INCLUDES_CSP, + use = 'include freertos_h', + install_path = install_path, + ) + + # Build shared library for Python bindings + if ctx.env.ENABLE_BINDINGS: + ctx.shlib(source = ctx.path.ant_glob(ctx.env.FILES_CSP, excl=ctx.env.EXCL_CSP), + name = 'csp_shlib', + target = 'csp', + includes = ctx.env.INCLUDES_CSP, + export_includes = 'include', + use = ['include'], + lib = ctx.env.LIBS) + + # python3 bindings + if ctx.env.LIBCSP_PYTHON3: + ctx.shlib(source = ['src/bindings/python/pycsp.c'], + target = 'csp_py3', + includes = ctx.env.INCLUDES_CSP + ctx.env.INCLUDES_PYTHON3, + export_includes = 'include', + use = ['csp_shlib', 'include'], + lib = ctx.env.LIBS) + + # python2 bindings + if ctx.env.LIBCSP_PYTHON2: + ctx.shlib(source = ['src/bindings/python/pycsp.c'], + target = 'csp_py2', + includes = ctx.env.INCLUDES_CSP + ctx.env.INCLUDES_PYTHON2, + export_includes = 'include', + use = ['csp_shlib', 'include'], + lib = ctx.env.LIBS) + + if ctx.env.ENABLE_EXAMPLES: + ctx.program(source = ctx.path.ant_glob('examples/simple.c'), + target = 'simple', + includes = ctx.env.INCLUDES_CSP, + lib = ctx.env.LIBS, + use = 'csp') + + if ctx.options.enable_if_kiss: + ctx.program(source = 'examples/kiss.c', + target = 'kiss', + includes = ctx.env.INCLUDES_CSP, + lib = ctx.env.LIBS, + use = 'csp') + + if ctx.options.enable_if_zmqhub: + ctx.program(source = 'examples/zmqproxy.c', + target = 'zmqproxy', + includes = ctx.env.INCLUDES_CSP, + lib = ctx.env.LIBS, + use = 'csp') + + if 'posix' in ctx.env.OS: + ctx.program(source = 'examples/csp_if_fifo.c', + target = 'fifo', + includes = ctx.env.INCLUDES_CSP, + lib = ctx.env.LIBS, + use = 'csp') + + if 'windows' in ctx.env.OS: + ctx.program(source = ctx.path.ant_glob('examples/csp_if_fifo_windows.c'), + target = 'csp_if_fifo', + includes = ctx.env.INCLUDES_CSP, + use = 'csp') + +def dist(ctx): + ctx.excl = 'build/* **/.* **/*.pyc **/*.o **/*~ *.tar.gz' diff --git a/gomspace/libgscsp/src/bindings/python/pygscsp.c b/gomspace/libgscsp/src/bindings/python/pygscsp.c new file mode 100644 index 00000000..c69d346b --- /dev/null +++ b/gomspace/libgscsp/src/bindings/python/pygscsp.c @@ -0,0 +1,61 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +#include + +#include + +#if PY_MAJOR_VERSION == 3 +#define IS_PY3 +#endif + +/* gs_error_t gs_csp_i2c_init(uint8_t device, uint8_t csp_addr); */ +static PyObject* pygscsp_csp_i2c_init(PyObject *self, PyObject *args) { + uint8_t device; + uint8_t csp_addr; + + if (!PyArg_ParseTuple(args, "BB", &device, &csp_addr)) { + Py_RETURN_NONE; + } + + return Py_BuildValue("i", gs_csp_i2c_init(device, csp_addr)); +} + + +static PyMethodDef methods[] = { + + {"i2c_init", pygscsp_csp_i2c_init, METH_VARARGS, ""}, + + /* sentinel */ + {NULL, NULL, 0, NULL} +}; + +#ifdef IS_PY3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "libgscsp_py3", + NULL, + -1, + methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +#ifdef IS_PY3 +PyMODINIT_FUNC PyInit_libgscsp_py3(void) { +#else +PyMODINIT_FUNC initlibgscsp_py2(void) { +#endif + +#ifdef IS_PY3 + PyObject* m = PyModule_Create(&moduledef); +#else + Py_InitModule("libgscsp_py2", methods); +#endif + +#ifdef IS_PY3 + return m; +#endif + } + diff --git a/gomspace/libgscsp/src/clock.c b/gomspace/libgscsp/src/clock.c new file mode 100644 index 00000000..9e9a7d53 --- /dev/null +++ b/gomspace/libgscsp/src/clock.c @@ -0,0 +1,23 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Required by libcsp. + Proto-typed in ./libcsp/include/csp/arch/csp_clock.h, but with different argumet! + + __attribute__((weak)) extern void clock_get_time(csp_timestamp_t * time); + __attribute__((weak)) extern void clock_set_time(csp_timestamp_t * time); +*/ + +#include +#include + +void clock_get_time(csp_timestamp_t * time) +{ + gs_clock_get_time((gs_timestamp_t*)time); +} + +void clock_set_time(csp_timestamp_t * time) +{ + gs_clock_set_time((gs_timestamp_t*)time); +} diff --git a/gomspace/libgscsp/src/commands.c b/gomspace/libgscsp/src/commands.c new file mode 100644 index 00000000..6abd3019 --- /dev/null +++ b/gomspace/libgscsp/src/commands.c @@ -0,0 +1,652 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static gs_error_t parse_node_timeout(gs_command_context_t *ctx, int node_index, uint8_t * node, int timeout_index, uint32_t * timeout) +{ + gs_error_t error = GS_OK; + if (node) { + *node = csp_get_address(); + + if (ctx->argc > node_index) { + error = gs_string_to_uint8(ctx->argv[node_index], node); + } + } + + if (timeout && (error == GS_OK)) { + *timeout = 1000; + + if (ctx->argc > timeout_index) { + error = gs_string_to_uint32(ctx->argv[timeout_index], timeout); + } + } + + return error; +} + +static int cmd_ping(gs_command_context_t *ctx) +{ + uint8_t node; + uint32_t timeout; + int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); + if (res) { + return res; + } + + uint32_t size = 1; + if ((ctx->argc > 3) && (gs_string_to_uint32(ctx->argv[3], &size) != GS_OK)) { + return GS_ERROR_ARG; + } + + uint32_t options = CSP_O_NONE; + if (ctx->argc > 4) { + const char * features = ctx->argv[4]; + if (strchr(features, 'r')) + options |= CSP_O_RDP; + if (strchr(features, 'x')) + options |= CSP_O_XTEA; + if (strchr(features, 'h')) + options |= CSP_O_HMAC; + if (strchr(features, 'c')) + options |= CSP_O_CRC32; + } + + printf("Ping node %u, timeout %" PRIu32 ", size %" PRIu32 ": options: 0x%" PRIx32 " ... ", node, timeout, size, options); + + const uint64_t start = gs_clock_get_nsec(); + const int time = csp_ping(node, timeout, size, options); + const uint64_t stop = gs_clock_get_nsec(); + const float elapsed = (((float)(stop - start)) / 1E6); + if (time < 0) { + printf("timeout after %.03f ms\r\n", elapsed); + return GS_ERROR_TIMEOUT; + } + + printf("reply in %.03f ms\r\n", elapsed); + + return GS_OK; +} + +static int cmd_ps(gs_command_context_t *ctx) +{ + uint8_t node; + uint32_t timeout; + int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); + if (res) { + return res; + } + + csp_ps(node, timeout); + + return GS_OK; +} + +static int cmd_memfree(gs_command_context_t *ctx) +{ + uint8_t node; + uint32_t timeout; + int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); + if (res) { + return res; + } + + csp_memfree(node, timeout); + + return GS_OK; +} + +static int cmd_reboot(gs_command_context_t *ctx) +{ + if (ctx->argc < 2) { + return GS_ERROR_ARG; + } + uint8_t node; + int res = parse_node_timeout(ctx, 1, &node, 0, NULL); + if (res) { + return res; + } + + csp_reboot(node); + + return GS_OK; +} + +static int cmd_shutdown(gs_command_context_t *ctx) +{ + if (ctx->argc < 2) { + return GS_ERROR_ARG; + } + uint8_t node; + int res = parse_node_timeout(ctx, 1, &node, 0, NULL); + if (res) { + return res; + } + + csp_shutdown(node); + + return GS_OK; +} + +static int cmd_buf_free(gs_command_context_t *ctx) +{ + uint8_t node; + uint32_t timeout; + int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); + if (res) { + return res; + } + + csp_buf_free(node, timeout); + + return GS_OK; +} + +static int cmd_uptime(gs_command_context_t *ctx) +{ + uint8_t node; + uint32_t timeout; + int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); + if (res) { + return res; + } + + csp_uptime(node, timeout); + + return GS_OK; +} + +#ifdef CSP_DEBUG + +static int cmd_csp_route_print_table(gs_command_context_t *ctx) +{ + csp_route_print_table(); + return GS_OK; +} + +static int cmd_csp_route_print_interfaces(gs_command_context_t *ctx) +{ + csp_route_print_interfaces(); + return GS_OK; +} + +static int cmd_csp_conn_print_table(gs_command_context_t *ctx) +{ + csp_conn_print_table(); + return GS_OK; +} + +#endif + +#if CSP_USE_RDP +static int cmd_csp_rdp_set_opt(gs_command_context_t *ctx) +{ + if (ctx->argc < 7) { + return GS_ERROR_ARG; + } + int res; + uint32_t window_size; + if ((res = gs_string_to_uint32(ctx->argv[1], &window_size))) { + return res; + } + uint32_t conn_timeout; + if ((res = gs_string_to_uint32(ctx->argv[2], &conn_timeout))) { + return res; + } + uint32_t packet_timeout; + if ((res = gs_string_to_uint32(ctx->argv[3], &packet_timeout))) { + return res; + } + uint32_t delayed_acks; + if ((res = gs_string_to_uint32(ctx->argv[4], &delayed_acks))) { + return res; + } + uint32_t ack_timeout; + if ((res = gs_string_to_uint32(ctx->argv[5], &ack_timeout))) { + return res; + } + uint32_t ack_delay_count; + if ((res = gs_string_to_uint32(ctx->argv[6], &ack_delay_count))) { + return res; + } + + printf("Setting arguments to: window size %" PRIu32 ", conn timeout %" PRIu32 ", packet timeout %" PRIu32 ", delayed acks %" PRIu32 ", ack timeout %" PRIu32 ", ack delay count %" PRIu32 "\r\n", + window_size, conn_timeout, packet_timeout, delayed_acks, ack_timeout, ack_delay_count); + + csp_rdp_set_opt(window_size, conn_timeout, packet_timeout, delayed_acks, ack_timeout, ack_delay_count); + + return GS_OK; +} +#endif + +static int cmd_cmp_ident(gs_command_context_t *ctx) +{ + uint8_t node; + uint32_t timeout; + int ret = parse_node_timeout(ctx, 1, &node, 2, &timeout); + if (ret) { + return ret; + } + + struct csp_cmp_message msg; + + ret = csp_cmp_ident(node, timeout, &msg); + if (ret != CSP_ERR_NONE) { + printf("CSP error: %d\r\n", ret); + return gs_csp_error(ret);; + } + + printf("Hostname: %s\r\n", msg.ident.hostname); + printf("Model: %s\r\n", msg.ident.model); + printf("Revision: %s\r\n", msg.ident.revision); + printf("Date: %s\r\n", msg.ident.date); + printf("Time: %s\r\n", msg.ident.time); + + return GS_OK; +} + +static int cmd_cmp_route_set(gs_command_context_t *ctx) +{ + if (ctx->argc != 6) + return GS_ERROR_ARG; + + uint8_t node = atoi(ctx->argv[1]); + uint32_t timeout = atoi(ctx->argv[2]); + printf("Sending route_set to node %"PRIu8" timeout %"PRIu32"\r\n", node, timeout); + + struct csp_cmp_message msg; + msg.route_set.dest_node = atoi(ctx->argv[3]); + msg.route_set.next_hop_mac = atoi(ctx->argv[4]); + strncpy(msg.route_set.interface, ctx->argv[5], 10); + printf("Dest_node: %u, next_hop_mac: %u, interface %s\r\n", msg.route_set.dest_node, msg.route_set.next_hop_mac, msg.route_set.interface); + + int ret = csp_cmp_route_set(node, timeout, &msg); + if (ret != CSP_ERR_NONE) { + printf("CSP error: %d\r\n", ret); + return gs_csp_error(ret); + } + + return GS_OK; +} + +static int cmd_cmp_ifc(gs_command_context_t *ctx) { + + uint8_t node; + uint32_t timeout; + char * interface; + + if (ctx->argc > 4 || ctx->argc < 3) + return GS_ERROR_ARG; + + node = atoi(ctx->argv[1]); + interface = ctx->argv[2]; + + if (ctx->argc < 4) + timeout = 1000; + else + timeout = atoi(ctx->argv[3]); + + struct csp_cmp_message msg; + strncpy(msg.if_stats.interface, interface, CSP_CMP_ROUTE_IFACE_LEN); + + printf("Requesting interface stats for interface %s\r\n", interface); + + int ret = csp_cmp_if_stats(node, timeout, &msg); + if (ret != CSP_ERR_NONE) { + printf("CSP error: %d\r\n", ret); + return gs_csp_error(ret); + } + + msg.if_stats.tx = csp_ntoh32(msg.if_stats.tx); + msg.if_stats.rx = csp_ntoh32(msg.if_stats.rx); + msg.if_stats.tx_error = csp_ntoh32(msg.if_stats.tx_error); + msg.if_stats.rx_error = csp_ntoh32(msg.if_stats.rx_error); + msg.if_stats.drop = csp_ntoh32(msg.if_stats.drop); + msg.if_stats.autherr = csp_ntoh32(msg.if_stats.autherr); + msg.if_stats.frame = csp_ntoh32(msg.if_stats.frame); + msg.if_stats.txbytes = csp_ntoh32(msg.if_stats.txbytes); + msg.if_stats.rxbytes = csp_ntoh32(msg.if_stats.rxbytes); + msg.if_stats.irq = csp_ntoh32(msg.if_stats.irq); + + printf("%-5s tx: %05"PRIu32" rx: %05"PRIu32" txe: %05"PRIu32" rxe: %05"PRIu32"\r\n" + " drop: %05"PRIu32" autherr: %05"PRIu32 " frame: %05"PRIu32"\r\n" + " txb: %"PRIu32" rxb: %"PRIu32"\r\n\r\n", + msg.if_stats.interface, msg.if_stats.tx, msg.if_stats.rx, msg.if_stats.tx_error, msg.if_stats.rx_error, msg.if_stats.drop, + msg.if_stats.autherr, msg.if_stats.frame, msg.if_stats.txbytes, msg.if_stats.rxbytes); + + return GS_OK; +} + +static int cmd_cmp_peek(gs_command_context_t *ctx) +{ + if ((ctx->argc != 4) && (ctx->argc != 5)) + return GS_ERROR_ARG; + + uint8_t node; + uint32_t timeout; + int res = parse_node_timeout(ctx, 1, &node, 4, &timeout); + if (res) { + return res; + } + + uint32_t addr; + if (gs_string_to_uint32(ctx->argv[2], &addr)) { + return GS_ERROR_ARG; + } + + uint32_t len; + if (gs_string_to_uint32(ctx->argv[3], &len)) { + return GS_ERROR_ARG; + } + if (len > CSP_CMP_PEEK_MAX_LEN) { + return GS_ERROR_RANGE; + } + + printf("Dumping mem from node %u addr 0x%"PRIx32" len %"PRIx32" timeout %"PRIu32"\r\n", node, addr, len, timeout); + + struct csp_cmp_message msg; + msg.peek.addr = csp_hton32(addr); + msg.peek.len = len; + + int ret = csp_cmp_peek(node, timeout, &msg); + if (ret != CSP_ERR_NONE) { + printf("CSP error: %d\r\n", ret); + return gs_csp_error(ret); + } + + gs_hexdump_addr(msg.peek.data, len, GS_TYPES_UINT2PTR(addr)); + + return GS_OK; +} + +static int cmd_cmp_poke(gs_command_context_t *ctx) +{ + if ((ctx->argc != 4) && (ctx->argc != 5)) + return GS_ERROR_ARG; + + uint8_t node; + uint32_t timeout; + int res = parse_node_timeout(ctx, 1, &node, 4, &timeout); + if (res) { + return res; + } + + uint32_t addr; + if (gs_string_to_uint32(ctx->argv[2], &addr)) { + return GS_ERROR_ARG; + } + + unsigned char data[CSP_CMP_POKE_MAX_LEN]; + uint32_t len = base16_decode(ctx->argv[3], data); + if (len > CSP_CMP_PEEK_MAX_LEN) { + printf("Max length is: %u\r\n", CSP_CMP_PEEK_MAX_LEN); + return GS_ERROR_RANGE; + } + + printf("Writing to mem at node %u addr 0x%"PRIx32" len %"PRIx32" timeout %"PRIu32"\r\n", node, addr, len, timeout); + gs_hexdump_addr(data, len, GS_TYPES_UINT2PTR(addr)); + + struct csp_cmp_message msg; + msg.poke.addr = csp_hton32(addr); + msg.poke.len = len; + memcpy(msg.poke.data, data, CSP_CMP_POKE_MAX_LEN); + + int ret = csp_cmp_poke(node, timeout, &msg); + if (ret != CSP_ERR_NONE) { + printf("CSP error: %d\r\n", ret); + return gs_csp_error(ret); + } + + return GS_OK; +} + +static int cmd_cmp_clock(gs_command_context_t *ctx, uint32_t node, uint32_t timeout, const gs_timestamp_t * set) +{ + char tbuf[GS_CLOCK_ISO8601_BUFFER_LENGTH]; + struct csp_cmp_message msg; + memset(&msg, 0, sizeof(msg)); + + if (set) { + gs_clock_to_iso8601_string(set, tbuf, sizeof(tbuf)); + printf("Set time: %s (%" PRIu32 ".%09" PRIu32 " sec)\r\n", tbuf, set->tv_sec, set->tv_nsec); + msg.clock.tv_sec = csp_hton32(set->tv_sec); + msg.clock.tv_nsec = csp_hton32(set->tv_nsec); + } + + gs_timestamp_t t1, t2; + gs_clock_get_time(&t1); + int ret = csp_cmp_clock(node, timeout, &msg); + if (ret != CSP_ERR_NONE) { + return gs_csp_error(ret); + } + gs_clock_get_time(&t2); + + /* Calculate round-trip time */ + const int64_t rtt = ((uint64_t)t2.tv_sec * 1000000000 + t2.tv_nsec) - ((uint64_t)t1.tv_sec * 1000000000 + t1.tv_nsec); + + gs_timestamp_t timestamp; + timestamp.tv_sec = csp_ntoh32(msg.clock.tv_sec); + timestamp.tv_nsec = csp_ntoh32(msg.clock.tv_nsec); + + gs_clock_to_iso8601_string(×tamp, tbuf, sizeof(tbuf)); + printf("Get time: %s (%" PRIu32 ".%09" PRIu32 " sec)\r\n", tbuf, timestamp.tv_sec, timestamp.tv_nsec); + + /* Calculate time difference to local clock. This takes the round-trip + * into account, but assumes a symmetrical link */ + const int64_t remote = (uint64_t)timestamp.tv_sec * 1000000000 + timestamp.tv_nsec; + const int64_t local = (uint64_t)t1.tv_sec * 1000000000 + t1.tv_nsec + rtt / 2; + + const double diff = (remote - local) / 1000000.0; + printf("Remote is %f ms %s local time\r\n", fabs(diff), diff > 0 ? "ahead of" : "behind"); + + return GS_OK; +} + +static int cmd_cmp_clock_get(gs_command_context_t *ctx) +{ + if (ctx->argc < 2) { + return GS_ERROR_ARG; + } + + uint32_t node; + if (gs_string_to_uint32(ctx->argv[1], &node) != GS_OK) { + return GS_ERROR_ARG; + } + + uint32_t timeout = 1000; + if (ctx->argc > 2) { + if (gs_string_to_uint32(ctx->argv[2], &timeout) != GS_OK) { + return GS_ERROR_ARG; + } + } + + return cmd_cmp_clock(ctx, node, timeout, NULL); +} + +static int cmd_cmp_clock_set(gs_command_context_t *ctx) +{ + if (ctx->argc < 3) { + return GS_ERROR_ARG; + } + + uint32_t node; + if (gs_string_to_uint32(ctx->argv[1], &node) != GS_OK) { + return GS_ERROR_ARG; + } + + gs_timestamp_t ts; + if (gs_clock_from_string(ctx->argv[2], &ts) != GS_OK) { + return GS_ERROR_ARG; + } + + uint32_t timeout = 1000; + if (ctx->argc > 3) { + if (gs_string_to_uint32(ctx->argv[3], &timeout) != GS_OK) { + return GS_ERROR_ARG; + } + } + + return cmd_cmp_clock(ctx, node, timeout, &ts); +} + +static int cmd_cmp_clock_sync(gs_command_context_t *ctx) +{ + if (ctx->argc < 2) { + return GS_ERROR_ARG; + } + + uint32_t node; + if (gs_string_to_uint32(ctx->argv[1], &node) != GS_OK) { + return GS_ERROR_ARG; + } + + uint32_t timeout = 1000; + if (ctx->argc > 2) { + if (gs_string_to_uint32(ctx->argv[2], &timeout) != GS_OK) { + return GS_ERROR_ARG; + } + } + + gs_timestamp_t ts; + gs_clock_get_time(&ts); + + return cmd_cmp_clock(ctx, node, timeout, &ts); +} + +static const gs_command_t GS_COMMAND_SUB cmp_clock_commands[] = { + { + .name = "get", + .help = "Get clock on ", + .usage = " [timeout]", + .handler = cmd_cmp_clock_get, + }, + { + .name = "set", + .help = "Set time of ", + .usage = " [timeout]", + .handler = cmd_cmp_clock_set, + }, + { + .name = "sync", + .help = "Sync/set time of to time of this node", + .usage = " [timeout]", + .handler = cmd_cmp_clock_sync, + } +}; + +static const gs_command_t GS_COMMAND_SUB cmp_commands[] = { + { + .name = "ident", + .help = "Node id", + .usage = "[node] [timeout]", + .handler = cmd_cmp_ident, + },{ + .name = "route_set", + .help = "Update table", + .usage = " ", + .handler = cmd_cmp_route_set, + },{ + .name = "ifc", + .help = "Remote IFC", + .usage = " [timeout]", + .handler = cmd_cmp_ifc, + },{ + .name = "peek", + .help = "Show remote memory", + .usage = " [timeout]", + .handler = cmd_cmp_peek, + },{ + .name = "poke", + .help = "Modify remote memory", + .usage = " [timeout]", + .handler = cmd_cmp_poke, + },{ + .name = "clock", + .help = "Get/set clock", + .chain = GS_COMMAND_INIT_CHAIN(cmp_clock_commands), + } +}; + +static const gs_command_t GS_COMMAND_ROOT csp_commands[] = { + { + .name = "ping", + .help = "csp: Ping", + .usage = "[node] [timeout] [size] [opt: r|x|h|c]", + .handler = cmd_ping, + },{ + .name = "rps", + .help = "csp: Remote ps", + .usage = "[node] [timeout]", + .handler = cmd_ps, + },{ + .name = "memfree", + .help = "csp: Memory free", + .usage = "[node] [timeout]", + .handler = cmd_memfree, + },{ + .name = "buffree", + .help = "csp: Buffer free", + .usage = "[node] [timeout]", + .handler = cmd_buf_free, + },{ + .name = "reboot", + .help = "csp: Reboot", + .usage = "", + .handler = cmd_reboot, + },{ + .name = "shutdown", + .help = "csp: Shutdown", + .usage = "", + .handler = cmd_shutdown, + },{ + .name = "uptime", + .help = "csp: Uptime", + .usage = "[node] [timeout]", + .handler = cmd_uptime, + },{ + .name = "cmp", + .help = "csp: Management", + .chain = GS_COMMAND_INIT_CHAIN(cmp_commands), + }, +#ifdef CSP_DEBUG + { + .name = "route", + .help = "csp: Show routing table", + .handler = cmd_csp_route_print_table, + },{ + .name = "ifc", + .help = "csp: Show interfaces", + .handler = cmd_csp_route_print_interfaces, + },{ + .name = "conn", + .help = "csp: Show connection table", + .handler = cmd_csp_conn_print_table, + }, +#endif +#if CSP_USE_RDP + { + .name = "rdpopt", + .help = "csp: Set RDP options", + .handler = cmd_csp_rdp_set_opt, + .usage = " " + }, +#endif +}; + +gs_error_t gs_csp_register_commands(void) +{ + return GS_COMMAND_REGISTER(csp_commands); +} diff --git a/gomspace/libgscsp/src/conn.c b/gomspace/libgscsp/src/conn.c new file mode 100644 index 00000000..05e6459e --- /dev/null +++ b/gomspace/libgscsp/src/conn.c @@ -0,0 +1,22 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include <../lib/libcsp/src/csp_conn.h> // internal libcsp header + +size_t gs_csp_conn_get_open(void) +{ + size_t open = 0; + size_t max_connections; + const csp_conn_t * connections = csp_conn_get_array(&max_connections); + if (connections) { + for (unsigned int i = 0; i < max_connections; ++i) { + if (connections[i].state != CONN_CLOSED) { + ++open; + } + } + } + + // csp_conn_print_table(); + + return open; +} diff --git a/gomspace/libgscsp/src/csp.c b/gomspace/libgscsp/src/csp.c new file mode 100644 index 00000000..2367ec6a --- /dev/null +++ b/gomspace/libgscsp/src/csp.c @@ -0,0 +1,91 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include "local.h" + +void gs_csp_conf_get_defaults_embedded(gs_csp_conf_t * conf) +{ + static const gs_csp_conf_t defaults = { + .use_gs_log = true, + .use_command_line_options = true, + .csp_buffer_size = 256, // typical MTU size is 256 + .csp_buffers = 10, // in case of RDP connections, must be > RDP Windows size + .address = 1, + .hostname = "hostname", + .model = "model", + .revision = "revision", + }; + + *conf = defaults; + +#if GS_CSP_COMMAND_LINE_SUPPORT + conf->address = gs_csp_command_line_get_address(); +#endif +} + +void gs_csp_conf_get_defaults_server(gs_csp_conf_t * conf) +{ + gs_csp_conf_get_defaults_embedded(conf); + conf->csp_buffer_size = 512; + conf->csp_buffers = 400; +} + +gs_error_t gs_csp_init(const gs_csp_conf_t * conf) +{ + GS_CHECK_ARG(conf != NULL); + + if (conf->use_gs_log) { + gs_csp_log_init(); + } + + int res = csp_buffer_init(conf->csp_buffers, conf->csp_buffer_size); + if (res != CSP_ERR_NONE) { + log_error("%s: csp_buffer_init(buffers: %u, size: %u) failed, CSP error: %d, error: %d", + __FUNCTION__, (unsigned int) conf->csp_buffers, (unsigned int) conf->csp_buffer_size, res, gs_csp_error(res)); + return gs_csp_error(res); + } + + csp_set_hostname(conf->hostname); + csp_set_model(conf->model); + csp_set_revision(conf->revision); + + uint8_t csp_address = conf->address; +#if GS_CSP_COMMAND_LINE_SUPPORT + if (gs_csp_command_line_is_address_set()) { + csp_address = gs_csp_command_line_get_address(); + } +#endif + + res = csp_init(csp_address); + if (res != CSP_ERR_NONE) { + log_error("%s: csp_init(address: %u) failed, CSP error: %d, error: %d", + __FUNCTION__, conf->address, res, gs_csp_error(res)); + return gs_csp_error(res); + } + +#if GS_CSP_COMMAND_LINE_SUPPORT + if (conf->use_command_line_options) { + gs_error_t error = gs_csp_command_line_configure_interfaces(); + if (error) { + log_error("%s: gs_csp_command_line_configure_interfaces() failed, error: %d", + __FUNCTION__, error); + return error; + } + } +#endif + + return GS_OK; +} + +bool gs_csp_is_address_valid(uint8_t address) +{ + if (address < 1) { + return false; + } + if (address >= 33) { + return false; + } + return true; +} diff --git a/gomspace/libgscsp/src/drivers/can/can.c b/gomspace/libgscsp/src/drivers/can/can.c new file mode 100644 index 00000000..dc19d1a7 --- /dev/null +++ b/gomspace/libgscsp/src/drivers/can/can.c @@ -0,0 +1,106 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include + +#include +#include +#include +#include +#include +#include + +#define NO_OF_CAN_CHANNELS 2 +#define MAX_NAME_LENGTH 10 // It says in csp_types.h, that it should be below 10 bytes + +// change default log group +#define LOG_DEFAULT gs_can_log + +typedef struct { + // self reference device handle + uint8_t can_ch; + // CSP interface name + char interface_name[MAX_NAME_LENGTH]; + // CSP interface + csp_iface_t interface; +} gs_csp_can_interface_t; + +static gs_csp_can_interface_t csp_can_interfaces[NO_OF_CAN_CHANNELS]; + +static void gs_csp_can_rxdata_callback_isr(int hdl, + uint32_t canMsgId, + bool extendedMsgId, + const void * data, + size_t data_size, + uint32_t nowMs, + void * user_data, + gs_context_switch_t * cswitch) +{ + csp_can_rx(&csp_can_interfaces[hdl].interface, canMsgId, data, data_size, &cswitch->task_woken); +} + +// Required by libcsp +int csp_can_tx_frame(csp_iface_t *interface, uint32_t id, const uint8_t * data, uint8_t dlc) +{ + return gs_can_send_extended(((gs_csp_can_interface_t *)interface->driver)->can_ch, id, data, dlc, 1000); +} + +gs_error_t gs_csp_can_init2(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, bool set_default_route, csp_iface_t ** csp_if) +{ + GS_CHECK_HANDLE(device < NO_OF_CAN_CHANNELS); + gs_csp_can_interface_t * interface = &csp_can_interfaces[device]; + + // Register/subscribe to CAN frames for CSP + const uint32_t can_id = CFP_MAKE_DST(csp_get_address()); + const uint32_t can_mask = CFP_MAKE_DST((1 << CFP_HOST_SIZE) - 1); + + log_debug("%s(%u): id=0x%" PRIx32 ", mask=0x%" PRIx32, __FUNCTION__, device, can_id, can_mask); + + if (gs_string_empty(name)) { + name = GS_CSP_CAN_DEFAULT_IF_NAME; + } + if (strlen(name) >= MAX_NAME_LENGTH) { + return GS_ERROR_ARG; + } + + if (csp_iflist_get_by_name(name)) { + log_error("%s(%u): name: [%s] - already exists", __FUNCTION__, device, name); + return GS_ERROR_EXIST; + } + + // hook CAN into CSP + GS_STRNCPY(interface->interface_name, name); + interface->interface.name = interface->interface_name; + interface->interface.nexthop = csp_can_tx; + interface->interface.mtu = mtu; + interface->interface.driver = interface; + + csp_iflist_add(&interface->interface); + + if (csp_if) { + *csp_if = &interface->interface; + } + + gs_error_t error = gs_can_set_extended_filter_mask(0, can_id, can_mask, gs_csp_can_rxdata_callback_isr, NULL); + if (error) { + log_error("%s: gs_can_set_extended_filter_mask() failed, error: %s", __FUNCTION__, gs_error_string(error)); + return error; + } + + error = gs_can_start(device); + if (error) { + log_error("%s: gs_can_start() failed, error: %s", __FUNCTION__, gs_error_string(error)); + return error; + } + + if (set_default_route) { + // Route all to CAN + csp_rtable_set(0, 0, &interface->interface, CSP_NODE_MAC); + } + + return GS_OK; +} + +gs_error_t gs_csp_can_init(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, csp_iface_t ** csp_if) +{ + return gs_csp_can_init2(device, csp_addr, mtu, name, true, csp_if); +} diff --git a/gomspace/libgscsp/src/drivers/i2c/i2c.c b/gomspace/libgscsp/src/drivers/i2c/i2c.c new file mode 100644 index 00000000..c40cd9c8 --- /dev/null +++ b/gomspace/libgscsp/src/drivers/i2c/i2c.c @@ -0,0 +1,77 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#include +#if !defined(__linux__) +#include +#endif + +#define E_FAIL -19 // The CSP I2C driver evaluates any other value than -1 as fail + +#define I2C_FRAME_OVERHEAD (sizeof(i2c_frame_t) - sizeof(((i2c_frame_t *)0)->data)) + +static void gs_csp_i2c_rxdata_callback_isr(uint8_t handle, const uint8_t * rx, size_t rx_length, gs_context_switch_t * cswitch) +{ + i2c_frame_t * frame = (i2c_frame_t *) (rx - I2C_FRAME_OVERHEAD); + frame->len = rx_length; +#if (__linux__) + csp_i2c_rx(frame, NULL); +#else + csp_i2c_rx(frame, &cswitch->task_woken); +#endif +} + +static void * gs_csp_i2c_get_buffer(uint8_t handle) +{ + void * buff = csp_buffer_get_isr(I2C_MTU); + if (buff != NULL) { + buff = ((uint8_t *)buff) + I2C_FRAME_OVERHEAD; + } + return buff; +} + +/** + CSP send function, required by libcsp + */ +int i2c_send(int handle, i2c_frame_t * frame, uint16_t timeout) +{ + int res_tx = gs_i2c_master_transaction(handle, frame->dest, frame->data, frame->len, 0, 0, timeout); + if (res_tx == GS_OK) { + csp_buffer_free(frame); + return E_NO_ERR; + } else { + return E_FAIL; + } +} + +/** + CSP init function, required by libcsp + */ +int i2c_init(int handle, int mode, uint8_t addr, uint16_t speed, int queue_len_tx, int queue_len_rx, + i2c_callback_t callback) +{ + if (gs_i2c_slave_set_rx(handle, gs_csp_i2c_rxdata_callback_isr) != GS_OK) { + return E_FAIL; + } + if (gs_i2c_slave_set_get_rx_buf(handle, gs_csp_i2c_get_buffer, I2C_MTU) != GS_OK) { + return E_FAIL; + } + if (gs_i2c_slave_start(handle) != GS_OK) { + return E_FAIL; + } + return E_NO_ERR; +} + +gs_error_t gs_csp_i2c_init(uint8_t device, uint8_t csp_addr) +{ + int dummy_speed = 0; // Speed not used + + /* Calls CSP I2C init, which has the I2C interface instance + From here the above "i2c_init" is called */ + return gs_csp_error(csp_i2c_init(csp_addr, device, dummy_speed)); +} diff --git a/gomspace/libgscsp/src/drivers/kiss/kiss.c b/gomspace/libgscsp/src/drivers/kiss/kiss.c new file mode 100644 index 00000000..c3357f7d --- /dev/null +++ b/gomspace/libgscsp/src/drivers/kiss/kiss.c @@ -0,0 +1,36 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +static csp_iface_t csp_if_kiss; +static uint8_t uart_csp_device; + +static void usart_rx_callback(void * user_data, const uint8_t * data, size_t data_size, gs_context_switch_t * cswitch) +{ + csp_kiss_rx(&csp_if_kiss, (uint8_t *)data, data_size, cswitch); +} + +static void csp_kiss_putc(char c) +{ + gs_uart_write(uart_csp_device, -1, c); +} + +static void csp_kiss_discard(char c, void *pxTaskWoken) +{ + // Do nothing with discarded characters +} + +gs_error_t gs_csp_kiss_init(uint8_t device) +{ + static csp_kiss_handle_t csp_kiss_driver; + static const char * kiss_name = "KISS"; + csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_kiss, CSP_NODE_MAC); + + csp_kiss_init(&csp_if_kiss, &csp_kiss_driver, csp_kiss_putc, csp_kiss_discard, kiss_name); + + uart_csp_device = device; + + return gs_uart_set_rx_callback(device, usart_rx_callback, NULL); +} diff --git a/gomspace/libgscsp/src/error.c b/gomspace/libgscsp/src/error.c new file mode 100644 index 00000000..45777e31 --- /dev/null +++ b/gomspace/libgscsp/src/error.c @@ -0,0 +1,54 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +gs_error_t gs_csp_error(int csp_error) +{ + switch (csp_error) { + case CSP_ERR_NONE: /* No error */ + return GS_OK; + + case CSP_ERR_NOMEM: /* Not enough memory */ + return GS_ERROR_ALLOC; + + case CSP_ERR_INVAL: /* Invalid argument */ + return GS_ERROR_ARG; + + case CSP_ERR_TIMEDOUT: /* Operation timed out */ + return GS_ERROR_TIMEOUT; + + case CSP_ERR_USED: /* Resource already in use */ + return GS_ERROR_IN_USE; + + case CSP_ERR_NOTSUP: /* Operation not supported */ + return GS_ERROR_NOT_SUPPORTED; + + case CSP_ERR_BUSY: /* Device or resource busy */ + return GS_ERROR_BUSY; + + case CSP_ERR_ALREADY: /* Connection already in progress */ + return GS_ERROR_ALREADY_IN_PROGRESS; + + case CSP_ERR_RESET: /* Connection reset */ + return GS_ERROR_CONNECTION_RESET; + + case CSP_ERR_NOBUFS: /* No more buffer space available */ + return GS_ERROR_NO_BUFFERS; + + case CSP_ERR_TX: /* Transmission failed */ + case CSP_ERR_DRIVER: /* Error in driver layer */ + return GS_ERROR_IO; + + case CSP_ERR_AGAIN: + return GS_ERROR_AGAIN; + + case CSP_ERR_HMAC: /* HMAC failed */ + case CSP_ERR_XTEA: /* XTEA failed */ + case CSP_ERR_CRC32: /* CRC32 failed */ + return GS_ERROR_DATA; + + default: + break; + } + return csp_error; +} diff --git a/gomspace/libgscsp/src/freertos/cpu.c b/gomspace/libgscsp/src/freertos/cpu.c new file mode 100644 index 00000000..a17fd62b --- /dev/null +++ b/gomspace/libgscsp/src/freertos/cpu.c @@ -0,0 +1,8 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +void cpu_reset(void) +{ + gs_sys_reset(GS_SYS_RESET_CSP); +} diff --git a/gomspace/libgscsp/src/linux/command_line.c b/gomspace/libgscsp/src/linux/command_line.c new file mode 100644 index 00000000..7c2b9bec --- /dev/null +++ b/gomspace/libgscsp/src/linux/command_line.c @@ -0,0 +1,265 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include "../local.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IF_NAME "if" + +#define DEFAULT_CAN_DEVICE "can0" + +#define DEFAULT_KISS_IF_NAME "KISS" +#define DEFAULT_KISS_DEVICE "/dev/ttyUSB0" +#define KISS_SPEED "speed" +#define DEFAULT_KISS_SPEED 500000 + +#define DEFAULT_ZMQ_SERVER "localhost" + +#define DEFAULT_I2C_DEVICE "0" + +#define CSP_ADDRESS_NOT_SET 255 +#define DEFAULT_CSP_ADDRESS 8 + +static uint8_t csp_address = CSP_ADDRESS_NOT_SET; +static const char * csp_can_device = NULL; +static const char * csp_kiss_device = NULL; +static const char * csp_i2c_device = NULL; +static const char * csp_zmq_server = NULL; +static const char * csp_rtable = NULL; + +static int parser(int key, char *arg, struct argp_state *state) +{ +switch (key) { + case 'a': + return gs_string_to_uint8(arg, &csp_address); + + case 'c': + if (csp_can_device) { + return GS_ERROR_IN_USE; + } + if (arg) { + csp_can_device = arg; + } else { + csp_can_device = DEFAULT_CAN_DEVICE; + } + break; + + case 'k': + if (csp_kiss_device) { + return GS_ERROR_IN_USE; + } + if (arg) { + csp_kiss_device = arg; + } else { + csp_kiss_device = DEFAULT_KISS_DEVICE; + } + break; + + case 'i': + if (csp_i2c_device) { + return GS_ERROR_IN_USE; + } + if (arg) { + csp_i2c_device = arg; + } else { + csp_i2c_device = DEFAULT_I2C_DEVICE; + } + break; + + case 'z': + if (csp_zmq_server) { + return GS_ERROR_IN_USE; + } + if (arg) { + csp_zmq_server = arg; + } else { + csp_zmq_server = DEFAULT_ZMQ_SERVER; + } + break; + + case 'R': + csp_rtable = arg; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static const struct argp_option options[] = { + { + .name = "csp-address", + .key = 'a', + .arg = "ADDR", + .flags = 0, + .doc = "Set address, default: " GS_DEF2STRING(DEFAULT_CSP_ADDRESS) + }, + { + .name = "csp-rtable", + .key = 'R', + .arg = "RTABLE", + .flags = 0, + .doc = "Set routing table\nRTABLE=
/ [mac]\nExample: \"0/0 ZMQHUB 24, 24/2 ZMQHUB\"" + }, +#if (CSP_USE_CAN) + { + .name = "csp-can", + .key = 'c', + .arg = "DEVICE", + .flags = OPTION_ARG_OPTIONAL, + .doc = "Add CAN interface\nDEVICE=" DEFAULT_CAN_DEVICE + }, +#endif +#if (CSP_USE_KISS) + { + .name = "csp-kiss", + .key = 'k', + .arg = "DEVICE", + .flags = OPTION_ARG_OPTIONAL, + .doc = "Add KISS over UART interface\nDEVICE=" DEFAULT_KISS_DEVICE "," IF_NAME "=" DEFAULT_KISS_IF_NAME","KISS_SPEED"=" GS_DEF2STRING(DEFAULT_KISS_SPEED) + }, +#endif +#if (CSP_USE_I2C) + { + .name = "csp-i2c", + .key = 'i', + .arg = "DEVICE", + .flags = OPTION_ARG_OPTIONAL, + .doc = "Add I2C interface\nDEVICE=0,"GS_I2C_COMMAND_LINE_SPEED"=" GS_DEF2STRING(GS_I2C_DEFAULT_BPS) "," GS_I2C_COMMAND_LINE_ADDRESS "=1," GS_I2C_COMMAND_LINE_DEVICE "=" GS_DEF2STRING(GS_I2C_ALL_DEVICES) + }, +#endif +#if (CSP_USE_ZMQHUB) + { + .name = "csp-zmq", + .key = 'z', + .arg = "SERVER", + .flags = OPTION_ARG_OPTIONAL, + .doc = "Add ZMQ interface\nSERVER=" DEFAULT_ZMQ_SERVER + }, +#endif + { + .flags = OPTION_DOC, + .name = "Examples:" +#if (CSP_USE_CAN) + "\n CAN: configure address 10 and CAN interface can0:" + "\n $ -a10 -ccan0" +#endif +#if (CSP_USE_KISS) + "\n KISS: configure address 10 and uart on /dev/ttyUSB0 at baudrate 500000:" + "\n $ -a10 -k/dev/ttyUSB0,speed=500000" +#endif +#if (CSP_USE_I2C) + "\n I2C: configure address 10 and I2C Aardvark dongle with id 2238384015, speed 400K:" + "\n $ -a10 -i2238384015,speed=400000" +#endif +#if (CSP_USE_ZMQHUB) + "\n ZMQ: configure address 10 and ZMQ proxy on localhost:" + "\n $ -a10 -zlocalhost" +#endif + }, + {0} +}; + +static const struct argp argp = {.options = options, .parser = parser}; + +const struct argp_child gs_csp_command_line_options = {.argp = &argp, .header = "CSP"}; + +gs_error_t gs_csp_command_line_configure_interfaces(void) +{ +#if (CSP_USE_KISS) + // KISS - only here, because the embedded init functions are stubbed in libemul + if (csp_kiss_device) { + static char device[50]; + static char ifname[50]; + uint32_t speed; + int res = gs_string_get_suboption_string(csp_kiss_device, NULL, DEFAULT_KISS_DEVICE, device, sizeof(device)); + res |= gs_string_get_suboption_string(csp_kiss_device, IF_NAME, DEFAULT_KISS_IF_NAME, ifname, sizeof(ifname)); + res |= gs_string_get_suboption_uint32(csp_kiss_device, KISS_SPEED, DEFAULT_KISS_SPEED, &speed); + if (res == GS_OK) { + static csp_iface_t csp_if_kiss; + static csp_kiss_handle_t csp_kiss_driver; + csp_kiss_init(&csp_if_kiss, &csp_kiss_driver, usart_putc, usart_insert, ifname); + struct usart_conf conf = {.device = device, .baudrate = speed}; + usart_init(&conf); + void my_usart_rx(uint8_t * buf, int len, void * pxTaskWoken) { + csp_kiss_rx(&csp_if_kiss, buf, len, pxTaskWoken); + } + usart_set_callback(my_usart_rx); + } + } +#endif + +#if (CSP_USE_CAN) + // CAN - only here, because the embedded init functions are stubbed in libemul + if (csp_can_device) { + char device[50]; + int res = gs_string_get_suboption_string(csp_can_device, NULL, DEFAULT_CAN_DEVICE, device, sizeof(device)); + if (res == GS_OK) { + csp_can_socketcan_init(device, 0, 0); + } + } +#endif + +#if (CSP_USE_ZMQHUB) + // ZMQ - currently ZMQ is only supported on Linux, and therefor handled here + if (csp_zmq_server) { + char server[50]; + int res = gs_string_get_suboption_string(csp_zmq_server, NULL, DEFAULT_ZMQ_SERVER, server, sizeof(server)); + if (res == GS_OK) { + csp_zmqhub_init(csp_get_address(), server); + } + } +#endif + +#if (CSP_USE_I2C) + // I2C + if (csp_i2c_device) { + uint8_t device = 0; + gs_string_get_suboption_uint8(csp_i2c_device, GS_I2C_COMMAND_LINE_DEVICE, GS_I2C_ALL_DEVICES, &device); + if (device == GS_I2C_ALL_DEVICES) { + device = 0; + } + + char modified_options[300]; + snprintf(modified_options, sizeof(modified_options), "%s,%s=%u", csp_i2c_device, GS_I2C_COMMAND_LINE_ADDRESS, csp_get_address()); + gs_error_t error = gs_function_invoke("i2c", modified_options); + if (error) { + log_error("Failed to initialize I2C adapter, error: %s", gs_error_string(error)); + } else { + error = gs_csp_i2c_init(device, csp_get_address()); + if (error) { + log_error("gs_csp_i2c_init(%u, %u) failed, error: %s", device, csp_get_address(), gs_error_string(error)); + } + } + } +#endif + + return GS_OK; +} + +bool gs_csp_command_line_is_address_set(void) +{ + return (csp_address != CSP_ADDRESS_NOT_SET); +} + +uint8_t gs_csp_command_line_get_address(void) +{ + if (gs_csp_command_line_is_address_set()) { + return csp_address; + } + return DEFAULT_CSP_ADDRESS; +} + +const char * gs_csp_command_line_get_rtable(void) +{ + return csp_rtable; +} diff --git a/gomspace/libgscsp/src/local.h b/gomspace/libgscsp/src/local.h new file mode 100644 index 00000000..5c033c14 --- /dev/null +++ b/gomspace/libgscsp/src/local.h @@ -0,0 +1,21 @@ +#ifndef GS_CSP_SRC_LOCAL_H +#define GS_CSP_SRC_LOCAL_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#if (__linux__) +#define GS_CSP_COMMAND_LINE_SUPPORT 1 +#include +#endif + +GS_LOG_GROUP_EXTERN(gs_csp_log); +#define LOG_DEFAULT gs_csp_log + +// local command line APIs +bool gs_csp_command_line_is_address_set(void); +uint8_t gs_csp_command_line_get_address(void); +const char * gs_csp_command_line_get_rtable(void); +gs_error_t gs_csp_command_line_configure_interfaces(void); + +#endif diff --git a/gomspace/libgscsp/src/log.c b/gomspace/libgscsp/src/log.c new file mode 100644 index 00000000..932e5394 --- /dev/null +++ b/gomspace/libgscsp/src/log.c @@ -0,0 +1,64 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include "local.h" + +GS_LOG_GROUP(gs_csp_log, "csp", GS_LOG_CAT_CSP, LOG_DEFAULT_MASK); + +static void gs_log_csp_debug_hook(csp_debug_level_t level, const char *format, va_list args) +{ + gs_log_level_t mapped_level; + + switch (level) { + /* Regular log levels */ + default: + case CSP_ERROR: + mapped_level = LOG_ERROR; + break; + case CSP_WARN: + mapped_level = LOG_WARNING; + break; + case CSP_INFO: + mapped_level = LOG_INFO; + break; + /* Extended log levels */ + case CSP_BUFFER: + mapped_level = LOG_TRACE; + break; + case CSP_PACKET: + mapped_level = LOG_INFO; + break; + case CSP_PROTOCOL: + mapped_level = LOG_DEBUG; + break; + case CSP_LOCK: + mapped_level = LOG_TRACE; + break; + } + + const int do_log = ((LOG_DEFAULT->mask & (1 << mapped_level)) > 0); + + if (do_log) { + /* forward to log system */ + gs_log_va(mapped_level, LOG_DEFAULT, format, args); + } +} + +gs_error_t gs_csp_log_init(void) +{ + gs_log_group_register(LOG_DEFAULT); + + csp_debug_set_level(CSP_ERROR, true); + csp_debug_set_level(CSP_WARN, true); + csp_debug_set_level(CSP_INFO, true); + csp_debug_set_level(CSP_BUFFER, true); + csp_debug_set_level(CSP_PACKET, true); + csp_debug_set_level(CSP_PROTOCOL, true); + csp_debug_set_level(CSP_LOCK, true); + + csp_debug_hook_set(gs_log_csp_debug_hook); + + return GS_OK; +} diff --git a/gomspace/libgscsp/src/router.c b/gomspace/libgscsp/src/router.c new file mode 100644 index 00000000..95f013eb --- /dev/null +++ b/gomspace/libgscsp/src/router.c @@ -0,0 +1,84 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#include +#include "../lib/libcsp/src/csp_qfifo.h" // internal libcsp header -> FIFO_TIMEOUT, csp_qfifo_wake_up() +#include <../lib/libcsp/src/csp_conn.h> // internal libcsp header +#include "local.h" + +typedef struct { + bool run; + gs_thread_t thread; +} gs_csp_router_t; + +static gs_csp_router_t gs_csp_router; + +static void * gs_csp_router_task(void *param) +{ + /* Here there be routing */ + while (gs_csp_router.run) { + csp_route_work(FIFO_TIMEOUT); + } + log_info("CSP router task terminating"); + gs_thread_exit(0); +} + +gs_error_t gs_csp_router_task_stop(void) +{ + GS_CHECK_HANDLE(gs_csp_router.run && (gs_csp_router.thread != 0)); + + // Close connections in state "RDP closing" - instead of waiting for timeout +#ifdef CSP_USE_RDP + { + size_t max_connections; + const csp_conn_t * conn = csp_conn_get_array(&max_connections); + if (conn && max_connections) { + for (unsigned int i = 0; i < max_connections; ++i, ++conn) { + if ((conn->state == CONN_OPEN) && (conn->rdp.state == RDP_CLOSE_WAIT)) { + log_info("Force close RDP %p in state closing", conn); + csp_close((csp_conn_t *) conn); + } + } + } + } +#endif + + // wait for RDP connections to close + unsigned int open = gs_csp_conn_get_open(); + if (open) { + const unsigned int MAX_TIMEOUT_MS = 30000; + log_info("Waiting up to %u mS for %u connection(s) to timeout/close ...", MAX_TIMEOUT_MS, open); + const uint32_t start_ms = gs_time_rel_ms(); + while (gs_csp_conn_get_open() && (gs_time_diff_ms(start_ms, gs_time_rel_ms()) < MAX_TIMEOUT_MS)) { + gs_time_sleep_ms(200); + } + } + + log_info("Waiting for CSP router task to stop ..."); + gs_csp_router.run = false; + csp_qfifo_wake_up(); + gs_error_t error = gs_thread_join(gs_csp_router.thread, NULL); + memset(&gs_csp_router, 0, sizeof(gs_csp_router)); + log_info("CSP router task stopped"); + return error; +} + +gs_error_t gs_csp_router_task_start(size_t stack_size, gs_thread_priority_t priority) +{ + if (gs_csp_router.run) { + return GS_ERROR_IN_USE; + } + + gs_csp_router.run = true; + gs_error_t error = gs_thread_create("RTE", gs_csp_router_task, NULL, stack_size, priority, + GS_THREAD_CREATE_JOINABLE, &gs_csp_router.thread); + if (error) { + memset(&gs_csp_router, 0, sizeof(gs_csp_router)); + } + return error; +} diff --git a/gomspace/libgscsp/src/rtable.c b/gomspace/libgscsp/src/rtable.c new file mode 100644 index 00000000..f836e3d0 --- /dev/null +++ b/gomspace/libgscsp/src/rtable.c @@ -0,0 +1,69 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include "local.h" + +// Return interface, if only one configured +static csp_iface_t * get_single_if(unsigned int * return_count) +{ + unsigned int count = 0; + csp_iface_t * found = NULL; + + for (csp_iface_t * ifc = csp_iflist_get(); ifc; ifc = ifc->next) { + if (strcasecmp(ifc->name, "LOOP") == 0) { + // ignore loopback + } else { + ++count; + found = ifc; + } + } + *return_count = count; + return found; +} + +gs_error_t gs_csp_rtable_load(const char * rtable, bool set_default_route, bool use_command_line_option) +{ + //csp_rtable_clear(); + +#if GS_CSP_COMMAND_LINE_SUPPORT + if (use_command_line_option && gs_string_empty(rtable)) { + // try rtable from command line (if set) + rtable = gs_csp_command_line_get_rtable(); + } +#endif + + if (gs_string_empty(rtable) == false) { + + if (csp_rtable_check(rtable) > 0) { + csp_rtable_load(rtable); + log_info("%s: loaded routing table [%s]", __FUNCTION__, rtable); + return GS_OK; + } + + log_warning("%s: ignoring route table: [%s] due to error(s)", __FUNCTION__, rtable); + } + + if (set_default_route) { + unsigned int count = 0; + csp_iface_t * ifc = get_single_if(&count); + if (count == 0) { + log_warning("%s: no interfaces configured", __FUNCTION__); + return GS_ERROR_NOT_FOUND; + } + + if (count > 1) { + log_warning("%s: %u interfaces configured - will not set default routes", __FUNCTION__, count); + return GS_ERROR_AMBIGUOUS; + } + + // set default route + int res = csp_route_set(CSP_DEFAULT_ROUTE, ifc, CSP_NODE_MAC); + if (res != CSP_ERR_NONE) { + log_warning("%s: failed to set default route on interface: [%s], CSP error: %d", __FUNCTION__, ifc->name, res); + return gs_csp_error(res); + } + } + + return GS_OK; +} diff --git a/gomspace/libgscsp/src/service_dispatcher.c b/gomspace/libgscsp/src/service_dispatcher.c new file mode 100644 index 00000000..507549af --- /dev/null +++ b/gomspace/libgscsp/src/service_dispatcher.c @@ -0,0 +1,213 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include +#include "../lib/libcsp/src/csp_conn.h" // internal libcsp header +#include "local.h" + +static GS_LOG_GROUP(gs_cspdispatcher_log, "cspdispatcher", GS_LOG_CAT_CSP, LOG_DEFAULT_MASK); +#undef LOG_DEFAULT +#define LOG_DEFAULT gs_cspdispatcher_log + +#define WD_TIMEOUT_SECOUNDS 30 +#define DEFAULT_TIMEOUT_MS (((WD_TIMEOUT_SECOUNDS * 1000) / 3) * 2) + +struct gs_csp_service_dispatcher { + // Configuration + const gs_csp_service_dispatcher_conf_t * conf; + // Run or stop/exit. + bool run; + // Server socket + csp_socket_t * socket; + // Software watchdog + gs_swwd_hdl_t * wd; + // Thread handle. + gs_thread_t thread; +}; + +static void * service_dispatcher_task(void * parameter) +{ + gs_csp_service_dispatcher_t handle = parameter; + + unsigned int timeout_ms = (handle->conf->callback) ? 0 : DEFAULT_TIMEOUT_MS; + + log_debug("[%s] entering connection loop, timeout: %u mS", handle->conf->name, timeout_ms); + + while (handle->run) { + if (handle->wd) { + gs_swwd_touch(handle->wd); + } + + /* Wait for incoming connection, or timeout */ + csp_conn_t * conn = csp_accept(handle->socket, timeout_ms); + + if (conn) { + unsigned int in_port = csp_conn_dport(conn); + + log_debug("[%s] new connection %p on port: %u, source: %d:%d, flags: 0x%x", + handle->conf->name, conn, in_port, csp_conn_src(conn), csp_conn_sport(conn), csp_conn_flags(conn)); + + gs_csp_service_handler_t handler; + if (in_port < handle->conf->handler_array_size) { + handler = handle->conf->handler_array[in_port]; + } else { + handler = NULL; + } + + if (handler) { + gs_error_t error = (handler)(conn); + log_debug("[%s] connection on port: %u processed by %p, error: %s", + handle->conf->name, in_port, handler, gs_error_string(error)); + } else { + log_warning("[%s] no handler on port: %u - closing connection: source: %d:%d, flags: 0x%x", + handle->conf->name, in_port, csp_conn_src(conn), csp_conn_sport(conn), csp_conn_flags(conn)); + csp_close(conn); + } + } + + if (handle->conf->callback) { + timeout_ms = handle->conf->callback(); + if (timeout_ms > DEFAULT_TIMEOUT_MS) { + timeout_ms = DEFAULT_TIMEOUT_MS; + } + } + } + + log_debug("[%s] terminating ...", handle->conf->name); + gs_thread_exit(NULL); +} + +static gs_error_t service_dispatcher_create(const gs_csp_service_dispatcher_conf_t * conf, + size_t stack_size, + gs_thread_priority_t priority, + gs_csp_service_dispatcher_t * return_handle) +{ + gs_csp_service_dispatcher_t handle = calloc(1, sizeof(*handle)); + if (handle == 0) { + return GS_ERROR_ALLOC; + } + + *return_handle = handle; + + handle->conf = conf; + + // Create watchdog + if (conf->disable_watchdog == false) { + gs_error_t error = gs_swwd_register(&handle->wd, WD_TIMEOUT_SECOUNDS, NULL, NULL, conf->name); + if (error) { + log_error("[%s] gs_swwd_register(%s, %u) failed, error: %d", + conf->name, conf->name, WD_TIMEOUT_SECOUNDS, error); + handle->wd = NULL; + return error; + } + } + + // Open "server" socket + handle->socket = csp_socket(conf->socket_options); + if (handle->socket == NULL) { + log_error("[%s] csp_socket(0) failed", + conf->name); + return GS_ERROR_ALLOC; + } + + // Bind to port(s) to socket + for (unsigned int i = 0; i < conf->handler_array_size; ++i) { + if (conf->handler_array[i]) { + int res = csp_bind(handle->socket, i); + if (res) { + log_error("[%s] csp_bind(socket: %p, port: %u) failed, result: %d", + conf->name, handle->socket, i, res); + return GS_ERROR_IN_USE; + } + } + } + + // Bind on "any" port? + if (conf->bind_any) { + int res = csp_bind(handle->socket, CSP_ANY); + if (res) { + log_error("[%s] csp_bind(socket: %p, port: %u) failed, result: %d", + conf->name, handle->socket, CSP_ANY, res); + return GS_ERROR_IN_USE; + } + } + + // Create listen backlog + { + size_t backlog = conf->listen_backlog ? conf->listen_backlog : 10; + int res = csp_listen(handle->socket, backlog); + if (res) { + log_error("[%s] csp_listen(%p, %zu) failed, result: %d", + conf->name, handle->socket, backlog, res); + return GS_ERROR_UNKNOWN; + } + } + + // Launch thread + handle->run = true; + gs_error_t error = gs_thread_create(handle->conf->name, service_dispatcher_task, handle, stack_size, priority, + GS_THREAD_CREATE_JOINABLE, &handle->thread); + if (error) { + handle->thread = 0; + } + + return error; +} + +gs_error_t gs_csp_service_dispatcher_create(const gs_csp_service_dispatcher_conf_t * conf, + size_t stack_size, + gs_thread_priority_t priority, + gs_csp_service_dispatcher_t * return_handle) +{ + GS_CHECK_ARG(conf != NULL); + + gs_log_group_register(gs_cspdispatcher_log); + + gs_csp_service_dispatcher_t handle; + gs_error_t error = service_dispatcher_create(conf, stack_size, priority, &handle); + if (error) { + //gs_csp_service_dispatcher_destroy(handle); + handle = NULL; + } + + if (return_handle) { + *return_handle = handle; + } + + return error; +} + +gs_error_t gs_csp_service_dispatcher_wake_up(gs_csp_service_dispatcher_t handle) +{ + GS_CHECK_HANDLE(handle && handle->socket && handle->socket->socket); + csp_packet_t * packet = NULL; + int res = csp_queue_enqueue(handle->socket->socket, &packet, 0); + return (res == CSP_QUEUE_OK) ? GS_OK : GS_ERROR_FULL; +} + +gs_error_t gs_csp_service_dispatcher_destroy(gs_csp_service_dispatcher_t handle) +{ + GS_CHECK_HANDLE(handle && handle->conf); + + log_debug("[%s] stopping dispatcher ...", handle->conf->name); + + handle->run = false; + if (handle->thread) { + gs_csp_service_dispatcher_wake_up(handle); + gs_thread_join(handle->thread, NULL); + } + + csp_close(handle->socket); + + if (handle->wd) { + gs_swwd_deregister(&handle->wd); + } + + memset(handle, 0, sizeof(*handle)); + free(handle); + + return GS_OK; +} diff --git a/gomspace/libgscsp/src/service_handler.c b/gomspace/libgscsp/src/service_handler.c new file mode 100644 index 00000000..b602847d --- /dev/null +++ b/gomspace/libgscsp/src/service_handler.c @@ -0,0 +1,86 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include + +// callback for processing packets on a connection. +typedef void (*csp_service_packet_handler_t)(csp_conn_t * conn, csp_packet_t * packet); + +// Process all packets on the connectio and close it when done. +static gs_error_t call_csp_packet_handler(csp_conn_t * conn, csp_service_packet_handler_t handler) +{ + csp_packet_t *packet; + while ((packet = csp_read(conn, 0))) { + (handler)(conn, packet); + } + csp_close(conn); + return GS_OK; +} + +gs_error_t gs_csp_cmp_service_handler(csp_conn_t * conn) +{ + return call_csp_packet_handler(conn, csp_service_handler); +} + +gs_error_t gs_csp_ping_service_handler(csp_conn_t * conn) +{ + return call_csp_packet_handler(conn, csp_service_handler); +} + +gs_error_t gs_csp_ps_service_handler(csp_conn_t * conn) +{ + return call_csp_packet_handler(conn, csp_service_handler); +} + +static void memfree(csp_conn_t * conn, csp_packet_t * packet) +{ + uint32_t mem_free = 0; + + gs_mem_ram_type_t ram_type = gs_mem_get_ram_default(); + gs_mem_ram_stat_t ram_stat; + if(gs_mem_get_ram_stat(ram_type, &ram_stat) == GS_OK) { + mem_free = ram_stat.available; + } + + mem_free = util_hton32(mem_free); + memcpy(packet->data, &mem_free, sizeof(mem_free)); + packet->length = sizeof(mem_free); + + if (!csp_send(conn, packet, 0)) { + csp_buffer_free(packet); + } +} + +gs_error_t gs_csp_mem_free_service_handler(csp_conn_t * conn) +{ + return call_csp_packet_handler(conn, memfree); +} + +gs_error_t gs_csp_reboot_service_handler(csp_conn_t * conn) +{ + return call_csp_packet_handler(conn, csp_service_handler); +} + +gs_error_t gs_csp_buf_free_service_handler(csp_conn_t * conn) +{ + return call_csp_packet_handler(conn, csp_service_handler); +} + +static void uptime(csp_conn_t * conn, csp_packet_t * packet) +{ + uint32_t time = gs_time_uptime(); + time = util_hton32(time); + memcpy(packet->data, &time, sizeof(time)); + packet->length = sizeof(time); + + if (!csp_send(conn, packet, 0)) { + csp_buffer_free(packet); + } +} + +gs_error_t gs_csp_uptime_service_handler(csp_conn_t * conn) +{ + return call_csp_packet_handler(conn, uptime); +} diff --git a/gomspace/libgscsp/src/transaction.c b/gomspace/libgscsp/src/transaction.c new file mode 100644 index 00000000..96ba262a --- /dev/null +++ b/gomspace/libgscsp/src/transaction.c @@ -0,0 +1,67 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include + +gs_error_t gs_csp_transaction_persistent(csp_conn_t * conn, uint32_t timeout, const void * tx_buf, + size_t tx_len, void * rx_buf, size_t rx_max_len, size_t * rx_len) +{ + GS_CHECK_HANDLE(conn != NULL); + + size_t size = (rx_max_len > tx_len) ? rx_max_len : tx_len; + csp_packet_t * packet = csp_buffer_get(size); + if (packet == NULL) { + return GS_ERROR_ALLOC; + } + + /* Copy the request */ + if (tx_len > 0 && tx_buf != NULL) { + memcpy(packet->data, tx_buf, tx_len); + } + + packet->length = tx_len; + + if (!csp_send(conn, packet, timeout)) { + csp_buffer_free(packet); + return GS_ERROR_IO; + } + + /* If no reply is expected, return now */ + if (rx_max_len == 0) { + return GS_OK; + } + + packet = csp_read(conn, timeout); + if (packet == NULL) { + return GS_ERROR_IO; + } + + gs_error_t return_val; + if (rx_max_len >= packet->length) { + size = packet->length; + return_val = GS_OK; + } else { + csp_log_error("Reply length %u, buffer only %u", packet->length, rx_max_len); + size = rx_max_len; + return_val = GS_ERROR_OVERFLOW; + } + memcpy(rx_buf, packet->data, size); + *rx_len = packet->length; + csp_buffer_free(packet); + return return_val; +} + +gs_error_t gs_csp_transaction2(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, const void * tx_buf, + size_t tx_len, void * rx_buf, size_t rx_max_len, size_t * rx_len, uint32_t opts) +{ + csp_conn_t * conn = csp_connect(prio, dest, port, 0, opts); + if (conn == NULL) { + return GS_ERROR_HANDLE; + } + + gs_error_t res = gs_csp_transaction_persistent(conn, timeout, tx_buf, tx_len, rx_buf, rx_max_len, rx_len); + + csp_close(conn); + + return res; +} diff --git a/gomspace/libgscsp/wscript b/gomspace/libgscsp/wscript new file mode 100644 index 00000000..a78d7f56 --- /dev/null +++ b/gomspace/libgscsp/wscript @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# encoding: utf-8 +# Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. + +import gs_gcc +import gs_doc +from waflib.Build import BuildContext + +APPNAME = 'gscsp' + + +def libcsp_with_os(ctx): + if ctx.gs_is_linux(): + return 'posix' + if ctx.gs_is_freertos(): + return 'freertos' + return None + + +def libcsp_with_driver_usart(ctx): + if ctx.gs_is_linux(): + return 'linux' + return None + + +def options(ctx): + ctx.load('gs_gcc gs_doc') + gs_gcc.gs_recurse(ctx) + + +def configure(ctx): + ctx.load('gs_gcc gs_doc') + + ctx.env.append_unique('FILES_GSCSP', 'src/*.c') + ctx.env.append_unique('USE_GSCSP', ['csp', 'csp_h', 'util']) + + if ctx.options.enable_if_i2c: + ctx.env.append_unique('FILES_GSCSP', 'src/drivers/i2c/*.c') + + if ctx.gs_is_freertos(): + ctx.env.append_unique('FILES_GSCSP', 'src/drivers/can/*.c') + ctx.env.append_unique('FILES_GSCSP', 'src/drivers/kiss/*.c') + ctx.env.append_unique('FILES_GSCSP', 'src/freertos/*.c') + ctx.env.append_unique('USE_GSCSP', ['embed']) + + if ctx.gs_is_linux(): + ctx.env.append_unique('FILES_GSCSP', 'src/linux/*.c') + + # libcsp options + ctx.options.with_os = libcsp_with_os(ctx) + ctx.options.with_driver_usart = libcsp_with_driver_usart(ctx) + bindings = True if (ctx.gs_is_linux() and not ctx.gs_is_build_disabled(['shlib', 'csp_shlib'])) else False + ctx.options.enable_bindings = bindings + ctx.options.enable_python3_bindings = bindings + ctx.options.disable_stlib = True + ctx.options.enable_crc32 = True + ctx.options.with_connection_so = ctx.options.with_connection_so | 0x0040 # always CRC32, disable CSP_O_NOCRC32 + + if ctx.options.enable_if_can and ctx.options.enable_can_socketcan: + ctx.check_cc(lib='socketcan', mandatory=True) + + ctx.gs_add_doxygen(input=['include', 'lib/libcsp/include']) + + gs_gcc.gs_recurse(ctx) + + +def build(ctx): + gs_gcc.gs_recurse(ctx) + + public_include = ctx.gs_include(name=APPNAME, + includes=['include']) + + ctx.gs_objects(source=ctx.path.ant_glob(ctx.env.FILES_GSCSP), + target=APPNAME, + use=ctx.env.USE_GSCSP + [public_include]) + + ctx.gs_shlib(source=ctx.path.ant_glob(ctx.env.FILES_GSCSP), + target=APPNAME, + gs_prefix='', # make library libgscsp + gs_use_shlib=ctx.env.USE_GSCSP + [public_include]) + + ctx.gs_python_bindings(source=ctx.path.ant_glob('src/bindings/python/pygscsp.c'), + target=APPNAME, + gs_prefix='', # make library libgscsp + gs_use_shlib=ctx.env.USE_GSCSP + [APPNAME, public_include], + package='libgscsp') + + +def doc(ctx): + gs_doc.add_task_library_doc(ctx, keyvalues={ + 'gs_prod_name': 'lib'+APPNAME, + 'gs_prod_desc': 'GomSpace CSP extension', + }) + + +class Doc(BuildContext): + cmd = fun = 'doc' + + +def gs_dist(ctx): + gs_gcc.gs_recurse(ctx) + ctx.add_default_files(source_module=True) + ctx.add_files(ctx.path.ant_glob(['lib/libcsp/**/*'])) + ctx.add_license_file("CSP", "lib/libcsp/COPYING") diff --git a/gomspace/libp60_client/include/p60.h b/gomspace/libp60_client/include/p60.h new file mode 100644 index 00000000..186d43f8 --- /dev/null +++ b/gomspace/libp60_client/include/p60.h @@ -0,0 +1,48 @@ +#ifndef _P60_H_ +#define _P60_H_ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#define P60_PORT_RPARAM 7 +#define P60_PORT_GNDWDT_RESET 9 +#define P60_PORT_CMDCONTROL 10 +#define P60_PORT_GSSB_SERVICE 15 +#define P60_PORT_GSCRIPT 22 + +/** FRAM MEMORY MAP */ +#define P60_FRAM_BOARD 0x0000 + +/** FRAM FILENAMES */ +#define P60_FNO_BOARD 0 +#define P60_FNO_BOARD_DFL 4 + +#define P60_FRAM_WP_BEGIN (0x1000) +#define P60_FRAM_WP_END (0x1C00 - 1) + +/** GND WD FRAM ADDR **/ +#define P60_FRAM_GNDWDT 0x1F00 + +/** PARAM INDEX MAP */ +#define P60_BOARD_PARAM 0 + +#define DEVICE_FM24CL64B 0 + +typedef enum { + UNKNOWN_RST = 0, + GND_WDT_RST, + I2C_WDT_RST, + CAN_WDT_RST, + EXT_HARD_RST, + EXT_SOFT_RST, +} p60_reset_cause_t; + +extern const uint8_t board_fallback_type; +extern const uint8_t csp_fallback_addr; +extern const uint8_t board_rs422_mode; + +extern void module_init_early(void); +extern void module_init(void); +extern void wdt_gnd_clear(void); +extern uint16_t command_control(uint8_t *packet, uint16_t length); +extern void module_task(void * pvParameters); + +#endif /* _P60_H_ */ diff --git a/gomspace/libp60_client/include/p60_board.h b/gomspace/libp60_client/include/p60_board.h new file mode 100644 index 00000000..2abd906d --- /dev/null +++ b/gomspace/libp60_client/include/p60_board.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + * NanoCom firmware + * + */ + +#ifndef P60_PARAM_H_ +#define P60_PARAM_H_ + +#include +#include + +/** + * Define memory space + */ +#define P60_BOARD_UID 0x00 +#define P60_BOARD_TYPE 0x10 +#define P60_BOARD_REV 0x11 +#define P60_BOARD_CSP_ADDR 0x12 +#define P60_BOARD_I2C_ADDR 0x13 +#define P60_BOARD_I2C_SPEED_KHZ 0x14 +#define P60_BOARD_CAN_SPEED_KHZ 0x16 +#define P60_BOARD_KISS_ENABLE 0x18 +#define P60_BOARD_RS422_MODE 0x19 +#define P60_BOARD_RS422_SPEED_KHZ 0x1C +#define P60_BOARD_RTABLE_STR 0x20 //! This one is 0x60 = 96 bytes +#define P60_BOARD_RTABLE_STR_SIZE 0x60 + +/** Define the memory size */ +#define P60_BOARD_PARAM_SIZE 0x80 + +extern const param_table_t p60_config[]; +extern const int p60_config_count; + +#endif /* P60_PARAM_H_ */ diff --git a/gomspace/libp60_client/include/power_if.h b/gomspace/libp60_client/include/power_if.h new file mode 100644 index 00000000..6762d1ec --- /dev/null +++ b/gomspace/libp60_client/include/power_if.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + * NanoPower firmware + * + */ + +#ifndef POWER_IF_H_ +#define POWER_IF_H_ + +#include + +#define POWER_IF_SET 1 +#define POWER_IF_GET 2 +#define POWER_IF_LIST 3 + +#define POWER_IF_STATUS_OK 0 +#define POWER_IF_STATUS_ERROR 1 + +#define POWER_IF_NAME_LEN 8 + +typedef struct __attribute__((packed)) { + uint8_t ch_idx; + uint8_t mode; + uint16_t on_cnt; + uint16_t off_cnt; + uint16_t cur_lu_lim; + uint16_t cur_lim; + uint16_t voltage; + int16_t current; + uint16_t latchup; + char name[POWER_IF_NAME_LEN]; +} power_if_ch_status_t; + +typedef struct __attribute__((packed)) { + uint8_t ch_idx; + uint8_t mode; + char name[8]; +} power_if_list_t; + +typedef struct __attribute__((packed)) { + uint8_t cmd; + uint8_t status; + power_if_ch_status_t ch_status; +} power_if_cmd_request_t; + +typedef struct __attribute__((packed)) { + uint8_t cmd; + uint8_t status; + power_if_ch_status_t ch_status; +} power_if_cmd_response_t; + +typedef struct __attribute__((packed)) { + uint8_t cmd; + uint8_t status; + uint8_t count; + power_if_list_t list[16]; +} power_if_cmd_list_response_t; + +int p60_power_if_cmd(uint8_t node, uint8_t port, uint32_t timeout, uint8_t cmd, void * ch_status_p); +uint8_t p60_power_if_get_ch_idx(char * ch_name, uint8_t * ch_no, uint8_t ch_no_max); + +#endif /* POWER_IF_H_ */ diff --git a/gomspace/libp60_client/src/cmd/power_if_cmd.c b/gomspace/libp60_client/src/cmd/power_if_cmd.c new file mode 100644 index 00000000..9851f912 --- /dev/null +++ b/gomspace/libp60_client/src/cmd/power_if_cmd.c @@ -0,0 +1,147 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +static uint8_t power_if_port = 10; +static uint32_t power_if_timeout = 5000; + +static int cmd_power_if_port(struct command_context * ctx) { + if (ctx->argc < 2) { + printf("Current port is %d\n", power_if_port); + return CMD_ERROR_NONE; + } + power_if_port = atoi(ctx->argv[1]); + return CMD_ERROR_NONE; +} + +static int cmd_power_if_timeout(struct command_context *ctx) { + if (ctx->argc < 2) { + printf("Current timeout is %"PRIu32"\n", power_if_timeout); + return CMD_ERROR_NONE; + } + if (sscanf(command_args(ctx), "%"SCNu32, &power_if_timeout) != 1) + return CMD_ERROR_SYNTAX; + if (power_if_timeout > 30000) { + printf("Timeout set to high, limited to 30000 ms\n"); + power_if_timeout = 30000; + } + printf("Timeout set to %"PRIu32"\n", power_if_timeout); + return CMD_ERROR_NONE; +} + +static int cmd_power_if_set_get(struct command_context * ctx) { + power_if_ch_status_t ch_status; + + if (ctx->argc < 3) { + return CMD_ERROR_SYNTAX; + } + uint8_t node = atoi(ctx->argv[1]); + memset(&ch_status, 0, sizeof(ch_status)); + strncpy(ch_status.name, ctx->argv[2], 7); + ch_status.name[7] = 0; + char * cmd = ctx->argv[0]; + if (!strcmp(cmd, "status") && (ctx->argc == 3)) { + if (!p60_power_if_cmd(node, power_if_port, power_if_timeout, POWER_IF_GET, &ch_status)) { + return CMD_ERROR_FAIL; + } + } else { + if (!strcmp(cmd, "on")) { + ch_status.mode = 1; + } else if (!strcmp(cmd, "off")) { + ch_status.mode = 0; + } + ch_status.on_cnt = (ctx->argc > 3) ? atoi(ctx->argv[3]) : 0; + ch_status.off_cnt = (ctx->argc > 4) ? atoi(ctx->argv[4]) : 0; + if (!p60_power_if_cmd(node, power_if_port, power_if_timeout, POWER_IF_SET, &ch_status)) { + return CMD_ERROR_FAIL; + } + } + printf("Node %u, Output channel '%s' (%u) is %s\r\n", node, ch_status.name, ch_status.ch_idx, (ch_status.mode ? "ON": "OFF")); + printf(" ch_idx: %u\r\n", ch_status.ch_idx); + printf(" mode: %u\r\n", ch_status.mode); + printf(" on_cnt: %u\r\n", ch_status.on_cnt); + printf(" off_cnt: %u\r\n", ch_status.off_cnt); + printf(" cur_lu_lim: %u\r\n", ch_status.cur_lu_lim); + printf(" cur_lim: %u\r\n", ch_status.cur_lim); + printf(" voltage: %u\r\n", ch_status.voltage); + printf(" current: %d\r\n", ch_status.current); + printf(" latchup: %u\r\n", ch_status.latchup); + + return CMD_ERROR_NONE; +} + +static int cmd_power_if_list(struct command_context * ctx) { + if (ctx->argc < 2) { + return CMD_ERROR_SYNTAX; + } + uint8_t node = atoi(ctx->argv[1]); + power_if_cmd_list_response_t ch_list; + if (!p60_power_if_cmd(node, power_if_port, power_if_timeout, POWER_IF_LIST, &ch_list)) { + return CMD_ERROR_FAIL; + } + printf("ch name status\r\n"); + for (uint8_t ch = 0; ch < ch_list.count; ch++) { + printf("%2u %-8s %s\r\n", ch_list.list[ch].ch_idx, ch_list.list[ch].name, ch_list.list[ch].mode ? "ON": "OFF"); + } + return CMD_ERROR_NONE; +} + +command_t power_if_commands[] = { + { + .name = "port", + .help = "Set power interface port (default is 10)", + .usage = "", + .handler = cmd_power_if_port, + }, + { + .name = "timeout", + .help = "Set power interface timeout in milliseconds", + .usage = "", + .handler = cmd_power_if_timeout, + }, + { + .name = "status", + .help = "Get power channel status", + .usage = " ", + .handler = cmd_power_if_set_get, + }, + { + .name = "on", + .help = "Turn power channel on", + .usage = " [ ]", + .handler = cmd_power_if_set_get, + }, + { + .name = "off", + .help = "Turn power channel off", + .usage = " off [ ]", + .handler = cmd_power_if_set_get, + }, + { + .name = "list", + .help = "Get list power channels", + .usage = "", + .handler = cmd_power_if_list, + }, +}; + +command_t __root_command power_if_root_command[] = { + { + .name = "power", + .help = "client: NanoPower P60", + .chain = INIT_CHAIN(power_if_commands), + } +}; + +void cmd_power_if_setup(void) { + command_register(power_if_root_command); +} diff --git a/gomspace/libp60_client/src/p60_client.c b/gomspace/libp60_client/src/p60_client.c new file mode 100644 index 00000000..76e1a905 --- /dev/null +++ b/gomspace/libp60_client/src/p60_client.c @@ -0,0 +1,33 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + * NanoCom firmware + * + */ + +#include +#include +#include +#include + +#include +#include + +/** + * Setup info about board configuration parameters + */ +const param_table_t p60_config[] = { + {.name = "uid", .addr = P60_BOARD_UID, .type = PARAM_STRING, .size = 16}, + {.name = "type", .addr = P60_BOARD_TYPE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "rev", .addr = P60_BOARD_REV, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "csp_addr", .addr = P60_BOARD_CSP_ADDR, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "i2c_addr", .addr = P60_BOARD_I2C_ADDR, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "i2c_speed", .addr = P60_BOARD_I2C_SPEED_KHZ, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, + {.name = "can_speed", .addr = P60_BOARD_CAN_SPEED_KHZ, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, + {.name = "kiss_en", .addr = P60_BOARD_KISS_ENABLE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "rs422_mode", .addr = P60_BOARD_RS422_MODE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "rs422_speed", .addr = P60_BOARD_RS422_SPEED_KHZ, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, + {.name = "csp_rtable", .addr = P60_BOARD_RTABLE_STR, .type = PARAM_STRING, .size = P60_BOARD_RTABLE_STR_SIZE}, + +}; + +const int p60_config_count = sizeof(p60_config) / sizeof(p60_config[0]); diff --git a/gomspace/libp60_client/src/power_if.c b/gomspace/libp60_client/src/power_if.c new file mode 100644 index 00000000..e9266ca0 --- /dev/null +++ b/gomspace/libp60_client/src/power_if.c @@ -0,0 +1,91 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + * NanoPower firmware + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +uint8_t p60_power_if_get_ch_idx(char * ch_name, uint8_t * ch_no, uint8_t ch_no_max) { + + uint8_t result = 1; + uint8_t len = strlen(ch_name); + for (int i = 0; i < len; i++) { + if (!isdigit(ch_name[i])) { + result = 0; + break; + } + } + if (result) { + *ch_no = atoi(ch_name); + if (*ch_no >= ch_no_max) { + result = 0; + } + } + return result; +} + +int p60_power_if_cmd(uint8_t node, uint8_t port, uint32_t timeout, uint8_t cmd, void * ch_status_p) { + + power_if_cmd_request_t req; + + if ((cmd == POWER_IF_SET) || (cmd == POWER_IF_GET)) { + power_if_cmd_response_t resp; + power_if_ch_status_t * ch_status = (power_if_ch_status_t *)ch_status_p; + if (cmd == POWER_IF_SET) { + req.cmd = POWER_IF_SET; + req.ch_status.mode = ch_status->mode; + req.ch_status.on_cnt = csp_hton16(ch_status->on_cnt); + req.ch_status.off_cnt = csp_hton16(ch_status->off_cnt); + } else { + req.cmd = POWER_IF_GET; + req.ch_status.mode = 0; + req.ch_status.on_cnt = 0; + req.ch_status.off_cnt = 0; + } + ch_status->name[POWER_IF_NAME_LEN - 1] = 0; + strcpy(req.ch_status.name, ch_status->name); + if (csp_transaction(CSP_PRIO_HIGH, node, port, timeout, &req, sizeof(power_if_cmd_request_t), &resp, sizeof(power_if_cmd_response_t))) { + if ((resp.cmd == POWER_IF_SET) || (resp.cmd == POWER_IF_GET)) { + if (resp.status == POWER_IF_STATUS_OK) { + ch_status->ch_idx = resp.ch_status.ch_idx; + ch_status->mode = resp.ch_status.mode; + ch_status->on_cnt = csp_ntoh16(resp.ch_status.on_cnt); + ch_status->off_cnt = csp_ntoh16(resp.ch_status.off_cnt); + ch_status->cur_lu_lim = csp_ntoh16(resp.ch_status.cur_lu_lim); + ch_status->cur_lim = csp_ntoh16(resp.ch_status.cur_lim); + ch_status->voltage = csp_ntoh16(resp.ch_status.voltage); + ch_status->current = csp_ntoh16(resp.ch_status.current); + ch_status->latchup = csp_ntoh16(resp.ch_status.latchup); + strncpy(ch_status->name, resp.ch_status.name, POWER_IF_NAME_LEN - 1); + /* Ensure zero termination*/ + ch_status->name[POWER_IF_NAME_LEN - 1] = 0; + return 1; + } + } + } + } else if (cmd == POWER_IF_LIST) { + power_if_cmd_list_response_t * ch_list = (power_if_cmd_list_response_t *)ch_status_p; + req.cmd = POWER_IF_LIST; + req.ch_status.mode = 0; + req.ch_status.on_cnt = 0; + req.ch_status.off_cnt = 0; + req.ch_status.name[0] = 0; + if (csp_transaction(CSP_PRIO_HIGH, node, port, timeout, &req, sizeof(power_if_cmd_request_t), ch_list, sizeof(power_if_cmd_list_response_t))) { + if ((ch_list->cmd == POWER_IF_LIST) && (ch_list->status == POWER_IF_STATUS_OK)) { + return 1; + } + } + } + + return 0; +} diff --git a/gomspace/libp60_client/wscript b/gomspace/libp60_client/wscript new file mode 100644 index 00000000..dc4dcf8a --- /dev/null +++ b/gomspace/libp60_client/wscript @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# encoding: utf-8 +# Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. + +APPNAME = 'p60_client' + + +def options(ctx): + gr = ctx.add_option_group('NanoPower-P60 library client options') + gr.add_option('--disable-libp60-cmd', action='store_true', help='Disable client cmd code for NanoPower-P60 library') + + +def configure(ctx): + ctx.env.append_unique('FILES_LIBP60_CLIENT', ['src/*.c']) + if not ctx.options.disable_libp60_cmd: + ctx.env.append_unique('FILES_LIBP60_CLIENT', ['src/cmd/*.c']) + + +def build(ctx): + public_include = APPNAME + '_h' + ctx(export_includes=['include'], name=public_include) + ctx.objects(source=ctx.path.ant_glob(ctx.env.FILES_LIBP60_CLIENT), + target=APPNAME, + use=['csp', 'gosh', 'param', 'param_client', 'util', public_include]) + + +def gs_dist(ctx): + ctx.add_default_files(source_module=True) diff --git a/gomspace/libutil/include/deprecated/gs/gosh/command/command.h b/gomspace/libutil/include/deprecated/gs/gosh/command/command.h new file mode 100644 index 00000000..540afea4 --- /dev/null +++ b/gomspace/libutil/include/deprecated/gs/gosh/command/command.h @@ -0,0 +1,49 @@ +#ifndef GS_GOSH_COMMAND_COMMAND_H +#define GS_GOSH_COMMAND_COMMAND_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + Legacy header file - use gs/util/gosh/command.h +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CMD_ERROR_NONE GS_OK +#define CMD_ERROR_FAIL GS_ERROR_UNKNOWN +#define CMD_ERROR_SYNTAX GS_ERROR_ARG +#define CMD_ERROR_NOMEM GS_ERROR_ALLOC +#define CMD_ERROR_INVALID GS_ERROR_DATA +#define CMD_ERROR_NOTFOUND GS_ERROR_NOT_FOUND + +#define CMD_HIDDEN GS_COMMAND_FLAG_HIDDEN + +#define __root_command GS_COMMAND_ROOT +#define __sub_command GS_COMMAND_SUB + +#define INIT_CHAIN(__list) GS_COMMAND_INIT_CHAIN(__list) +#define command_register(__cmd) GS_COMMAND_REGISTER(__cmd) + +typedef struct command command_t; + +static inline const char * command_args(gs_command_context_t *ctx) +{ + return gs_command_args(ctx); +} + +static inline int command_run(char *line) +{ + gs_error_t result = GS_OK; + gs_error_t error = gs_command_run(line, &result); + if (error == GS_OK) { + return result; + } + return error; +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h b/gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h new file mode 100644 index 00000000..e0e40329 --- /dev/null +++ b/gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h @@ -0,0 +1,22 @@ +#ifndef GS_GOSH_GOSH_GETOPT_H +#define GS_GOSH_GOSH_GETOPT_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + Legacy header file - use gs/util/gosh/getopt.h +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline int gosh_getopt(gs_command_context_t *ctx, const char *opts) +{ + return gs_command_getopt(ctx, opts); +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/deprecated/gs/gosh/util/console.h b/gomspace/libutil/include/deprecated/gs/gosh/util/console.h new file mode 100644 index 00000000..a8d1c94d --- /dev/null +++ b/gomspace/libutil/include/deprecated/gs/gosh/util/console.h @@ -0,0 +1,43 @@ +#ifndef GS_GOSH_UTIL_CONSOLE_H +#define GS_GOSH_UTIL_CONSOLE_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + Legacy header file - use gs/util/gosh/console.h +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline int console_init(void) +{ + return gs_console_init(); +} + +static inline int console_exit(void) +{ + return gs_console_exit(); +} + +static inline void console_set_hostname(const char *host) +{ + gs_console_set_prompt(host); +} + +static inline void console_clear(void) +{ + gs_console_clear(); +} + +static inline void console_update(void) +{ + gs_console_update(); +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/deprecated/util/color_printf.h b/gomspace/libutil/include/deprecated/util/color_printf.h new file mode 100644 index 00000000..a2129460 --- /dev/null +++ b/gomspace/libutil/include/deprecated/util/color_printf.h @@ -0,0 +1,26 @@ +#ifndef DEPRECATED_UTIL_COLOR_PRINTF_H +#define DEPRECATED_UTIL_COLOR_PRINTF_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +typedef enum color_printf_e { + /* Colors */ + COLOR_COLORS = GS_COLOR_COLORS, + COLOR_NONE = GS_COLOR_NONE, + COLOR_BLACK = GS_COLOR_BLACK, + COLOR_RED = GS_COLOR_RED, + COLOR_GREEN = GS_COLOR_GREEN, + COLOR_YELLOW = GS_COLOR_YELLOW, + COLOR_BLUE = GS_COLOR_BLUE, + COLOR_MAGENTA = GS_COLOR_MAGENTA, + COLOR_CYAN = GS_COLOR_CYAN, + COLOR_WHITE = GS_COLOR_WHITE, + /* Attributes */ + COLOR_ATTRS = GS_COLOR_ATTRS, + COLOR_BOLD = GS_COLOR_BOLD, +} color_printf_t; + +#define color_printf gs_color_printf + +#endif diff --git a/gomspace/libutil/include/gs/uthash/utarray.h b/gomspace/libutil/include/gs/uthash/utarray.h new file mode 100644 index 00000000..145f3631 --- /dev/null +++ b/gomspace/libutil/include/gs/uthash/utarray.h @@ -0,0 +1,231 @@ +/* +Copyright (c) 2008-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +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. +*/ + +/* a dynamic array implementation using macros + */ +#ifndef UTARRAY_H +#define UTARRAY_H + +#define UTARRAY_VERSION 1.9.9 + +#ifdef __GNUC__ +#define _UNUSED_ __attribute__ ((__unused__)) +#else +#define _UNUSED_ +#endif + +#include /* size_t */ +#include /* memset, etc */ +#include /* exit */ + +#define oom() exit(-1) + +typedef void (ctor_f)(void *dst, const void *src); +typedef void (dtor_f)(void *elt); +typedef void (init_f)(void *elt); +typedef struct { + size_t sz; + init_f *init; + ctor_f *copy; + dtor_f *dtor; +} UT_icd; + +typedef struct { + unsigned i,n;/* i: index of next available slot, n: num slots */ + UT_icd icd; /* initializer, copy and destructor functions */ + char *d; /* n slots of size icd->sz*/ +} UT_array; + +#define utarray_init(a,_icd) do { \ + memset(a,0,sizeof(UT_array)); \ + (a)->icd=*_icd; \ +} while(0) + +#define utarray_done(a) do { \ + if ((a)->n) { \ + if ((a)->icd.dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ + } \ + } \ + free((a)->d); \ + } \ + (a)->n=0; \ +} while(0) + +#define utarray_new(a,_icd) do { \ + a=(UT_array*)malloc(sizeof(UT_array)); \ + utarray_init(a,_icd); \ +} while(0) + +#define utarray_free(a) do { \ + utarray_done(a); \ + free(a); \ +} while(0) + +#define utarray_reserve(a,by) do { \ + if (((a)->i+by) > ((a)->n)) { \ + while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \ + if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd.sz)) == NULL) oom(); \ + } \ +} while(0) + +#define utarray_push_back(a,p) do { \ + utarray_reserve(a,1); \ + if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \ + else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \ +} while(0) + +#define utarray_pop_back(a) do { \ + if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \ + else { (a)->i--; } \ +} while(0) + +#define utarray_extend_back(a) do { \ + utarray_reserve(a,1); \ + if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \ + else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \ + (a)->i++; \ +} while(0) + +#define utarray_len(a) ((a)->i) + +#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL) +#define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd.sz*(j) ))) + +#define utarray_insert(a,p,j) do { \ + if (j > (a)->i) utarray_resize(a,j); \ + utarray_reserve(a,1); \ + if ((j) < (a)->i) { \ + memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd.sz)); \ + } \ + if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \ + else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \ + (a)->i++; \ +} while(0) + +#define utarray_inserta(a,w,j) do { \ + if (utarray_len(w) == 0) break; \ + if (j > (a)->i) utarray_resize(a,j); \ + utarray_reserve(a,utarray_len(w)); \ + if ((j) < (a)->i) { \ + memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \ + _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd.sz)); \ + } \ + if ((a)->icd.copy) { \ + size_t _ut_i; \ + for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \ + (a)->icd.copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \ + } \ + } else { \ + memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \ + utarray_len(w)*((a)->icd.sz)); \ + } \ + (a)->i += utarray_len(w); \ +} while(0) + +#define utarray_resize(dst,num) do { \ + size_t _ut_i; \ + if (dst->i > (size_t)(num)) { \ + if ((dst)->icd.dtor) { \ + for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \ + (dst)->icd.dtor(utarray_eltptr(dst,_ut_i)); \ + } \ + } \ + } else if (dst->i < (size_t)(num)) { \ + utarray_reserve(dst,num-dst->i); \ + if ((dst)->icd.init) { \ + for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \ + (dst)->icd.init(utarray_eltptr(dst,_ut_i)); \ + } \ + } else { \ + memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd.sz*(num-dst->i)); \ + } \ + } \ + dst->i = num; \ +} while(0) + +#define utarray_concat(dst,src) do { \ + utarray_inserta((dst),(src),utarray_len(dst)); \ +} while(0) + +#define utarray_erase(a,pos,len) do { \ + if ((a)->icd.dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < len; _ut_i++) { \ + (a)->icd.dtor(utarray_eltptr((a),pos+_ut_i)); \ + } \ + } \ + if ((a)->i > (pos+len)) { \ + memmove( _utarray_eltptr((a),pos), _utarray_eltptr((a),pos+len), \ + (((a)->i)-(pos+len))*((a)->icd.sz)); \ + } \ + (a)->i -= (len); \ +} while(0) + +#define utarray_renew(a,u) do { \ + if (a) utarray_clear(a); \ + else utarray_new((a),(u)); \ +} while(0) + +#define utarray_clear(a) do { \ + if ((a)->i > 0) { \ + if ((a)->icd.dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ + } \ + } \ + (a)->i = 0; \ + } \ +} while(0) + +#define utarray_sort(a,cmp) do { \ + qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \ +} while(0) + +#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp) + +#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL) +#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL)) +#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL)) +#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL) +#define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(size_t)(a)->icd.sz) : -1) + +/* last we pre-define a few icd for common utarrays of ints and strings */ +static void utarray_str_cpy(void *dst, const void *src) { + char **_src = (char**)src, **_dst = (char**)dst; + *_dst = (*_src == NULL) ? NULL : strdup(*_src); +} +static void utarray_str_dtor(void *elt) { + char **eltc = (char**)elt; + if (*eltc) free(*eltc); +} +static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor}; +static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL}; +static const UT_icd ut_ptr_icd _UNUSED_ = {sizeof(void*),NULL,NULL,NULL}; + +#endif /* UTARRAY_H */ diff --git a/gomspace/libutil/include/gs/uthash/uthash.h b/gomspace/libutil/include/gs/uthash/uthash.h new file mode 100644 index 00000000..c8c6d25c --- /dev/null +++ b/gomspace/libutil/include/gs/uthash/uthash.h @@ -0,0 +1,960 @@ +/* +Copyright (c) 2003-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +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. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#include /* memcmp,strlen */ +#include /* ptrdiff_t */ +#include /* exit() */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define DECLTYPE(x) +#endif +#elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__) +#define NO_DECLTYPE +#define DECLTYPE(x) +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while(0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while(0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */ +#if defined (_WIN32) +#if defined(_MSC_VER) && _MSC_VER >= 1600 +#include +#elif defined(__WATCOMC__) +#include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif +#else +#include +#endif + +#define UTHASH_VERSION 1.9.9 + +#ifndef uthash_fatal +#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ +#endif +#ifndef uthash_malloc +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#endif +#ifndef uthash_free +#define uthash_free(ptr,sz) free(ptr) /* free fcn */ +#endif + +#ifndef uthash_noexpand_fyi +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#endif +#ifndef uthash_expand_fyi +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#endif + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhe */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + out=NULL; \ + if (head) { \ + unsigned _hf_bkt,_hf_hashv; \ + HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ + keyptr,keylen,out); \ + } \ + } \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) +#define HASH_BLOOM_MAKE(tbl) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ + memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ +} while (0) + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0) + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#else +#define HASH_BLOOM_MAKE(tbl) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#define HASH_BLOOM_BYTELEN 0 +#endif + +#define HASH_MAKE_TABLE(hh,head) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ + sizeof(UT_hash_table)); \ + if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl->buckets, 0, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ +} while(0) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add) + +#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ +do { \ + replaced=NULL; \ + HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced); \ + if (replaced!=NULL) { \ + HASH_DELETE(hh,head,replaced); \ + }; \ + HASH_ADD(hh,head,fieldname,keylen_in,add); \ +} while(0) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_bkt; \ + (add)->hh.next = NULL; \ + (add)->hh.key = (char*)(keyptr); \ + (add)->hh.keylen = (unsigned)(keylen_in); \ + if (!(head)) { \ + head = (add); \ + (head)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh,head); \ + } else { \ + (head)->hh.tbl->tail->next = (add); \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail = &((add)->hh); \ + } \ + (head)->hh.tbl->num_items++; \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ + (add)->hh.hashv, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ + HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ + HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ + HASH_FSCK(hh,head); \ +} while(0) + +#define HASH_TO_BKT( hashv, num_bkts, bkt ) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1)); \ +} while(0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ +do { \ + struct UT_hash_handle *_hd_hh_del; \ + if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + head = NULL; \ + } else { \ + unsigned _hd_bkt; \ + _hd_hh_del = &((delptr)->hh); \ + if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ + (head)->hh.tbl->tail = \ + (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho); \ + } \ + if ((delptr)->hh.prev) { \ + ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ + } else { \ + DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ + } \ + if (_hd_hh_del->next) { \ + ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \ + (head)->hh.tbl->hho))->prev = \ + _hd_hh_del->prev; \ + } \ + HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh,head); \ +} while (0) + + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ + HASH_FIND(hh,head,findstr,(unsigned)strlen(findstr),out) +#define HASH_ADD_STR(head,strfield,add) \ + HASH_ADD(hh,head,strfield[0],strlen(add->strfield),add) +#define HASH_REPLACE_STR(head,strfield,add,replaced) \ + HASH_REPLACE(hh,head,strfield[0],(unsigned)strlen(add->strfield),add,replaced) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_REPLACE_INT(head,intfield,add,replaced) \ + HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ + HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head) \ +do { \ + struct UT_hash_handle *_thh; \ + if (head) { \ + unsigned _bkt_i; \ + unsigned _count; \ + char *_prev; \ + _count = 0; \ + for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ + unsigned _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("invalid hh_prev %p, actual %p\n", \ + _thh->hh_prev, _prev ); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("invalid bucket count %u, actual %u\n", \ + (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid hh item count %u, actual %u\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + /* traverse hh in app order; check next/prev integrity, count */ \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev !=(char*)(_thh->prev)) { \ + HASH_OOPS("invalid prev %p, actual %p\n", \ + _thh->prev, _prev ); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ + (head)->hh.tbl->hho) : NULL ); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid app item count %u, actual %u\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ +#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hb_keylen=keylen; \ + char *_hb_key=(char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen--) { (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; } \ + bkt = (hashv) & (num_bkts-1); \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _sx_i; \ + char *_hs_key=(char*)(key); \ + hashv = 0; \ + for(_sx_i=0; _sx_i < keylen; _sx_i++) \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + bkt = hashv & (num_bkts-1); \ +} while (0) +/* FNV-1a variation */ +#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _fn_i; \ + char *_hf_key=(char*)(key); \ + hashv = 2166136261UL; \ + for(_fn_i=0; _fn_i < keylen; _fn_i++) { \ + hashv = hashv ^ _hf_key[_fn_i]; \ + hashv = hashv * 16777619; \ + } \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _ho_i; \ + char *_ho_key=(char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + unsigned char *_hj_key=(unsigned char*)(key); \ + hashv = 0xfeedbeef; \ + _hj_i = _hj_j = 0x9e3779b9; \ + _hj_k = (unsigned)(keylen); \ + while (_hj_k >= 12) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12; \ + } \ + hashv += keylen; \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ + case 5: _hj_j += _hj_key[4]; \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned char *_sfh_key=(unsigned char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = keylen; \ + \ + int _sfh_rem = _sfh_len & 3; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabe; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = (uint32_t)(get16bits (_sfh_key+2)) << 11 ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)] << 18); \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * MurmurHash uses the faster approach only on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) +#define MUR_GETBLOCK(p,i) p[i] +#else /* non intel */ +#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) +#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) +#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) +#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) +#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) +#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) +#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) +#else /* assume little endian non-intel */ +#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) +#endif +#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ + (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ + (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ + MUR_ONE_THREE(p)))) +#endif +#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define MUR_FMIX(_h) \ +do { \ + _h ^= _h >> 16; \ + _h *= 0x85ebca6b; \ + _h ^= _h >> 13; \ + _h *= 0xc2b2ae35l; \ + _h ^= _h >> 16; \ +} while(0) + +#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ +do { \ + const uint8_t *_mur_data = (const uint8_t*)(key); \ + const int _mur_nblocks = (keylen) / 4; \ + uint32_t _mur_h1 = 0xf88D5353; \ + uint32_t _mur_c1 = 0xcc9e2d51; \ + uint32_t _mur_c2 = 0x1b873593; \ + uint32_t _mur_k1 = 0; \ + const uint8_t *_mur_tail; \ + const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ + int _mur_i; \ + for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ + _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + \ + _mur_h1 ^= _mur_k1; \ + _mur_h1 = MUR_ROTL32(_mur_h1,13); \ + _mur_h1 = _mur_h1*5+0xe6546b64; \ + } \ + _mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ + _mur_k1=0; \ + switch((keylen) & 3) { \ + case 3: _mur_k1 ^= _mur_tail[2] << 16; \ + case 2: _mur_k1 ^= _mur_tail[1] << 8; \ + case 1: _mur_k1 ^= _mur_tail[0]; \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + _mur_h1 ^= _mur_k1; \ + } \ + _mur_h1 ^= (keylen); \ + MUR_FMIX(_mur_h1); \ + hashv = _mur_h1; \ + bkt = hashv & (num_bkts-1); \ +} while(0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* key comparison function; return 0 if keys equal */ +#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ +do { \ + if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ + else out=NULL; \ + while (out) { \ + if ((out)->hh.keylen == keylen_in) { \ + if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \ + } \ + if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \ + else out = NULL; \ + } \ +} while(0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,addhh) \ +do { \ + head.count++; \ + (addhh)->hh_next = head.hh_head; \ + (addhh)->hh_prev = NULL; \ + if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ + (head).hh_head=addhh; \ + if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ + && (addhh)->tbl->noexpand != 1) { \ + HASH_EXPAND_BUCKETS((addhh)->tbl); \ + } \ +} while(0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(hh,head,hh_del) \ + (head).count--; \ + if ((head).hh_head == hh_del) { \ + (head).hh_head = hh_del->hh_next; \ + } \ + if (hh_del->hh_prev) { \ + hh_del->hh_prev->hh_next = hh_del->hh_next; \ + } \ + if (hh_del->hh_next) { \ + hh_del->hh_next->hh_prev = hh_del->hh_prev; \ + } + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(tbl) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ + memset(_he_new_buckets, 0, \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + tbl->ideal_chain_maxlen = \ + (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ + ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ + tbl->nonideal_items = 0; \ + for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ + { \ + _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ + if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ + tbl->nonideal_items++; \ + _he_newbkt->expand_mult = _he_newbkt->count / \ + tbl->ideal_chain_maxlen; \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ + _he_thh; \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + tbl->num_buckets *= 2; \ + tbl->log2_num_buckets++; \ + tbl->buckets = _he_new_buckets; \ + tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ + (tbl->ineff_expands+1) : 0; \ + if (tbl->ineff_expands > 1) { \ + tbl->noexpand=1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ +} while(0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ + _hs_psize++; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + if (! (_hs_q) ) break; \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ + if (_hs_psize == 0) { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ + _hs_e = _hs_p; \ + if (_hs_p){ \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + } \ + _hs_psize--; \ + } else if (( \ + cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ + ) <= 0) { \ + _hs_e = _hs_p; \ + if (_hs_p){ \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + } \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail ) { \ + _hs_tail->next = ((_hs_e) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + if (_hs_e) { \ + _hs_e->prev = ((_hs_tail) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ + } \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + if (_hs_tail){ \ + _hs_tail->next = NULL; \ + } \ + if ( _hs_nmerges <= 1 ) { \ + _hs_looping=0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2; \ + } \ + HASH_FSCK(hh,head); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt=NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if (src) { \ + for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ + if (!dst) { \ + DECLTYPE_ASSIGN(dst,_elt); \ + HASH_MAKE_TABLE(hh_dst,dst); \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ + (dst)->hh_dst.tbl->num_items++; \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst,dst); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if (head) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)=NULL; \ + } \ +} while(0) + +#define HASH_OVERHEAD(hh,head) \ + ((head) ? ( \ + (size_t)((((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + (sizeof(UT_hash_table)) + \ + (HASH_BLOOM_BYTELEN)))) : 0) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1 +#define HASH_BLOOM_SIGNATURE 0xb12220f2 + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + char bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/gomspace/libutil/include/gs/uthash/utlist.h b/gomspace/libutil/include/gs/uthash/utlist.h new file mode 100644 index 00000000..b5f3f04c --- /dev/null +++ b/gomspace/libutil/include/gs/uthash/utlist.h @@ -0,0 +1,757 @@ +/* +Copyright (c) 2007-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +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. +*/ + +#ifndef UTLIST_H +#define UTLIST_H + +#define UTLIST_VERSION 1.9.9 + +#include + +/* + * This file contains macros to manipulate singly and doubly-linked lists. + * + * 1. LL_ macros: singly-linked lists. + * 2. DL_ macros: doubly-linked lists. + * 3. CDL_ macros: circular doubly-linked lists. + * + * To use singly-linked lists, your structure must have a "next" pointer. + * To use doubly-linked lists, your structure must "prev" and "next" pointers. + * Either way, the pointer to the head of the list must be initialized to NULL. + * + * ----------------.EXAMPLE ------------------------- + * struct item { + * int id; + * struct item *prev, *next; + * } + * + * struct item *list = NULL: + * + * int main() { + * struct item *item; + * ... allocate and populate item ... + * DL_APPEND(list, item); + * } + * -------------------------------------------------- + * + * For doubly-linked lists, the append and delete macros are O(1) + * For singly-linked lists, append and delete are O(n) but prepend is O(1) + * The sort macro is O(n log(n)) for all types of single/double/circular lists. + */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ code), this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#ifdef _MSC_VER /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define LDECLTYPE(x) decltype(x) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define LDECLTYPE(x) char* +#endif +#elif defined(__ICCARM__) +#define NO_DECLTYPE +#define LDECLTYPE(x) char* +#else /* GNU, Sun and other compilers */ +#define LDECLTYPE(x) __typeof(x) +#endif + +/* for VS2008 we use some workarounds to get around the lack of decltype, + * namely, we always reassign our tmp variable to the list head if we need + * to dereference its prev/next pointers, and save/restore the real head.*/ +#ifdef NO_DECLTYPE +#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } +#define _NEXT(elt,list,next) ((char*)((list)->next)) +#define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } +/* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */ +#define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } +#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } +#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } +#else +#define _SV(elt,list) +#define _NEXT(elt,list,next) ((elt)->next) +#define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to) +/* #define _PREV(elt,list,prev) ((elt)->prev) */ +#define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) +#define _RS(list) +#define _CASTASGN(a,b) (a)=(b) +#endif + +/****************************************************************************** + * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * + * Unwieldy variable names used here to avoid shadowing passed-in variables. * + *****************************************************************************/ +#define LL_SORT(list, cmp) \ + LL_SORT2(list, cmp, next) + +#define LL_SORT2(list, cmp, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + _CASTASGN(_ls_p,list); \ + list = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + } else { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + } \ + if (_ls_tail) { \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ + } else { \ + _CASTASGN(list,_ls_e); \ + } \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + if (_ls_tail) { \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ + } \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + + +#define DL_SORT(list, cmp) \ + DL_SORT2(list, cmp, prev, next) + +#define DL_SORT2(list, cmp, prev, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + _CASTASGN(_ls_p,list); \ + list = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + } else { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + } \ + if (_ls_tail) { \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ + } else { \ + _CASTASGN(list,_ls_e); \ + } \ + _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + _CASTASGN(list->prev, _ls_tail); \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + +#define CDL_SORT(list, cmp) \ + CDL_SORT2(list, cmp, prev, next) + +#define CDL_SORT2(list, cmp, prev, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + LDECLTYPE(list) _ls_oldhead; \ + LDECLTYPE(list) _tmp; \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + _CASTASGN(_ls_p,list); \ + _CASTASGN(_ls_oldhead,list); \ + list = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + _SV(_ls_q,list); \ + if (_NEXT(_ls_q,list,next) == _ls_oldhead) { \ + _ls_q = NULL; \ + } else { \ + _ls_q = _NEXT(_ls_q,list,next); \ + } \ + _RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ + } else { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ + } \ + if (_ls_tail) { \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ + } else { \ + _CASTASGN(list,_ls_e); \ + } \ + _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + _CASTASGN(list->prev,_ls_tail); \ + _CASTASGN(_tmp,list); \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list); \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + +/****************************************************************************** + * singly linked list macros (non-circular) * + *****************************************************************************/ +#define LL_PREPEND(head,add) \ + LL_PREPEND2(head,add,next) + +#define LL_PREPEND2(head,add,next) \ +do { \ + (add)->next = head; \ + head = add; \ +} while (0) + +#define LL_CONCAT(head1,head2) \ + LL_CONCAT2(head1,head2,next) + +#define LL_CONCAT2(head1,head2,next) \ +do { \ + LDECLTYPE(head1) _tmp; \ + if (head1) { \ + _tmp = head1; \ + while (_tmp->next) { _tmp = _tmp->next; } \ + _tmp->next=(head2); \ + } else { \ + (head1)=(head2); \ + } \ +} while (0) + +#define LL_APPEND(head,add) \ + LL_APPEND2(head,add,next) + +#define LL_APPEND2(head,add,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + (add)->next=NULL; \ + if (head) { \ + _tmp = head; \ + while (_tmp->next) { _tmp = _tmp->next; } \ + _tmp->next=(add); \ + } else { \ + (head)=(add); \ + } \ +} while (0) + +#define LL_DELETE(head,del) \ + LL_DELETE2(head,del,next) + +#define LL_DELETE2(head,del,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if ((head) == (del)) { \ + (head)=(head)->next; \ + } else { \ + _tmp = head; \ + while (_tmp->next && (_tmp->next != (del))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = ((del)->next); \ + } \ + } \ +} while (0) + +/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ +#define LL_APPEND_VS2008(head,add) \ + LL_APPEND2_VS2008(head,add,next) + +#define LL_APPEND2_VS2008(head,add,next) \ +do { \ + if (head) { \ + (add)->next = head; /* use add->next as a temp variable */ \ + while ((add)->next->next) { (add)->next = (add)->next->next; } \ + (add)->next->next=(add); \ + } else { \ + (head)=(add); \ + } \ + (add)->next=NULL; \ +} while (0) + +#define LL_DELETE_VS2008(head,del) \ + LL_DELETE2_VS2008(head,del,next) + +#define LL_DELETE2_VS2008(head,del,next) \ +do { \ + if ((head) == (del)) { \ + (head)=(head)->next; \ + } else { \ + char *_tmp = (char*)(head); \ + while ((head)->next && ((head)->next != (del))) { \ + head = (head)->next; \ + } \ + if ((head)->next) { \ + (head)->next = ((del)->next); \ + } \ + { \ + char **_head_alias = (char**)&(head); \ + *_head_alias = _tmp; \ + } \ + } \ +} while (0) +#ifdef NO_DECLTYPE +#undef LL_APPEND +#define LL_APPEND LL_APPEND_VS2008 +#undef LL_DELETE +#define LL_DELETE LL_DELETE_VS2008 +#undef LL_DELETE2 +#define LL_DELETE2 LL_DELETE2_VS2008 +#undef LL_APPEND2 +#define LL_APPEND2 LL_APPEND2_VS2008 +#undef LL_CONCAT /* no LL_CONCAT_VS2008 */ +#undef DL_CONCAT /* no DL_CONCAT_VS2008 */ +#endif +/* end VS2008 replacements */ + +#define LL_COUNT(head,el,counter) \ + LL_COUNT2(head,el,counter,next) \ + +#define LL_COUNT2(head,el,counter,next) \ +{ \ + counter = 0; \ + LL_FOREACH2(head,el,next){ ++counter; } \ +} + +#define LL_FOREACH(head,el) \ + LL_FOREACH2(head,el,next) + +#define LL_FOREACH2(head,el,next) \ + for(el=head;el;el=(el)->next) + +#define LL_FOREACH_SAFE(head,el,tmp) \ + LL_FOREACH_SAFE2(head,el,tmp,next) + +#define LL_FOREACH_SAFE2(head,el,tmp,next) \ + for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) + +#define LL_SEARCH_SCALAR(head,out,field,val) \ + LL_SEARCH_SCALAR2(head,out,field,val,next) + +#define LL_SEARCH_SCALAR2(head,out,field,val,next) \ +do { \ + LL_FOREACH2(head,out,next) { \ + if ((out)->field == (val)) break; \ + } \ +} while(0) + +#define LL_SEARCH(head,out,elt,cmp) \ + LL_SEARCH2(head,out,elt,cmp,next) + +#define LL_SEARCH2(head,out,elt,cmp,next) \ +do { \ + LL_FOREACH2(head,out,next) { \ + if ((cmp(out,elt))==0) break; \ + } \ +} while(0) + +#define LL_REPLACE_ELEM(head, el, add) \ +do { \ + LDECLTYPE(head) _tmp; \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + (add)->next = (el)->next; \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + _tmp = head; \ + while (_tmp->next && (_tmp->next != (el))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (add); \ + } \ + } \ +} while (0) + +#define LL_PREPEND_ELEM(head, el, add) \ +do { \ + LDECLTYPE(head) _tmp; \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + (add)->next = (el); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + _tmp = head; \ + while (_tmp->next && (_tmp->next != (el))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (add); \ + } \ + } \ +} while (0) \ + + +/****************************************************************************** + * doubly linked list macros (non-circular) * + *****************************************************************************/ +#define DL_PREPEND(head,add) \ + DL_PREPEND2(head,add,prev,next) + +#define DL_PREPEND2(head,add,prev,next) \ +do { \ + (add)->next = head; \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev = (add); \ + } else { \ + (add)->prev = (add); \ + } \ + (head) = (add); \ +} while (0) + +#define DL_APPEND(head,add) \ + DL_APPEND2(head,add,prev,next) + +#define DL_APPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev->next = (add); \ + (head)->prev = (add); \ + (add)->next = NULL; \ + } else { \ + (head)=(add); \ + (head)->prev = (head); \ + (head)->next = NULL; \ + } \ +} while (0) + +#define DL_CONCAT(head1,head2) \ + DL_CONCAT2(head1,head2,prev,next) + +#define DL_CONCAT2(head1,head2,prev,next) \ +do { \ + LDECLTYPE(head1) _tmp; \ + if (head2) { \ + if (head1) { \ + _tmp = (head2)->prev; \ + (head2)->prev = (head1)->prev; \ + (head1)->prev->next = (head2); \ + (head1)->prev = _tmp; \ + } else { \ + (head1)=(head2); \ + } \ + } \ +} while (0) + +#define DL_DELETE(head,del) \ + DL_DELETE2(head,del,prev,next) + +#define DL_DELETE2(head,del,prev,next) \ +do { \ + assert((del)->prev != NULL); \ + if ((del)->prev == (del)) { \ + (head)=NULL; \ + } else if ((del)==(head)) { \ + (del)->next->prev = (del)->prev; \ + (head) = (del)->next; \ + } else { \ + (del)->prev->next = (del)->next; \ + if ((del)->next) { \ + (del)->next->prev = (del)->prev; \ + } else { \ + (head)->prev = (del)->prev; \ + } \ + } \ +} while (0) + +#define DL_COUNT(head,el,counter) \ + DL_COUNT2(head,el,counter,next) \ + +#define DL_COUNT2(head,el,counter,next) \ +{ \ + counter = 0; \ + DL_FOREACH2(head,el,next){ ++counter; } \ +} + +#define DL_FOREACH(head,el) \ + DL_FOREACH2(head,el,next) + +#define DL_FOREACH2(head,el,next) \ + for(el=head;el;el=(el)->next) + +/* this version is safe for deleting the elements during iteration */ +#define DL_FOREACH_SAFE(head,el,tmp) \ + DL_FOREACH_SAFE2(head,el,tmp,next) + +#define DL_FOREACH_SAFE2(head,el,tmp,next) \ + for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) + +/* these are identical to their singly-linked list counterparts */ +#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR +#define DL_SEARCH LL_SEARCH +#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 +#define DL_SEARCH2 LL_SEARCH2 + +#define DL_REPLACE_ELEM(head, el, add) \ +do { \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + (add)->next = (el)->next; \ + if ((el)->next == NULL) { \ + (add)->prev = (add); \ + } else { \ + (add)->prev = (el)->prev; \ + (add)->next->prev = (add); \ + } \ + } else { \ + (add)->next = (el)->next; \ + (add)->prev = (el)->prev; \ + (add)->prev->next = (add); \ + if ((el)->next == NULL) { \ + (head)->prev = (add); \ + } else { \ + (add)->next->prev = (add); \ + } \ + } \ +} while (0) + +#define DL_PREPEND_ELEM(head, el, add) \ +do { \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->prev->next = (add); \ + } \ +} while (0) \ + + +/****************************************************************************** + * circular doubly linked list macros * + *****************************************************************************/ +#define CDL_PREPEND(head,add) \ + CDL_PREPEND2(head,add,prev,next) + +#define CDL_PREPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (add)->prev->next = (add); \ + } else { \ + (add)->prev = (add); \ + (add)->next = (add); \ + } \ +(head)=(add); \ +} while (0) + +#define CDL_DELETE(head,del) \ + CDL_DELETE2(head,del,prev,next) + +#define CDL_DELETE2(head,del,prev,next) \ +do { \ + if ( ((head)==(del)) && ((head)->next == (head))) { \ + (head) = 0L; \ + } else { \ + (del)->next->prev = (del)->prev; \ + (del)->prev->next = (del)->next; \ + if ((del) == (head)) (head)=(del)->next; \ + } \ +} while (0) + +#define CDL_COUNT(head,el,counter) \ + CDL_COUNT2(head,el,counter,next) \ + +#define CDL_COUNT2(head, el, counter,next) \ +{ \ + counter = 0; \ + CDL_FOREACH2(head,el,next){ ++counter; } \ +} + +#define CDL_FOREACH(head,el) \ + CDL_FOREACH2(head,el,next) + +#define CDL_FOREACH2(head,el,next) \ + for(el=head;el;el=((el)->next==head ? 0L : (el)->next)) + +#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ + CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) + +#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \ + for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ + (el) && ((tmp2)=(el)->next, 1); \ + ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) + +#define CDL_SEARCH_SCALAR(head,out,field,val) \ + CDL_SEARCH_SCALAR2(head,out,field,val,next) + +#define CDL_SEARCH_SCALAR2(head,out,field,val,next) \ +do { \ + CDL_FOREACH2(head,out,next) { \ + if ((out)->field == (val)) break; \ + } \ +} while(0) + +#define CDL_SEARCH(head,out,elt,cmp) \ + CDL_SEARCH2(head,out,elt,cmp,next) + +#define CDL_SEARCH2(head,out,elt,cmp,next) \ +do { \ + CDL_FOREACH2(head,out,next) { \ + if ((cmp(out,elt))==0) break; \ + } \ +} while(0) + +#define CDL_REPLACE_ELEM(head, el, add) \ +do { \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + if ((el)->next == (el)) { \ + (add)->next = (add); \ + (add)->prev = (add); \ + (head) = (add); \ + } else { \ + (add)->next = (el)->next; \ + (add)->prev = (el)->prev; \ + (add)->next->prev = (add); \ + (add)->prev->next = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } \ + } \ +} while (0) + +#define CDL_PREPEND_ELEM(head, el, add) \ +do { \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + (add)->prev->next = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } \ +} while (0) \ + +#endif /* UTLIST_H */ + diff --git a/gomspace/libutil/include/gs/uthash/utstring.h b/gomspace/libutil/include/gs/uthash/utstring.h new file mode 100644 index 00000000..867442c8 --- /dev/null +++ b/gomspace/libutil/include/gs/uthash/utstring.h @@ -0,0 +1,393 @@ +/* +Copyright (c) 2008-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +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. +*/ + +/* a dynamic string implementation using macros + */ +#ifndef UTSTRING_H +#define UTSTRING_H + +#define UTSTRING_VERSION 1.9.9 + +#ifdef __GNUC__ +#define _UNUSED_ __attribute__ ((__unused__)) +#else +#define _UNUSED_ +#endif + +#include +#include +#include +#include +#define oom() exit(-1) + +typedef struct { + char *d; + size_t n; /* allocd size */ + size_t i; /* index of first unused byte */ +} UT_string; + +#define utstring_reserve(s,amt) \ +do { \ + if (((s)->n - (s)->i) < (size_t)(amt)) { \ + (s)->d = (char*)realloc((s)->d, (s)->n + amt); \ + if ((s)->d == NULL) oom(); \ + (s)->n += amt; \ + } \ +} while(0) + +#define utstring_init(s) \ +do { \ + (s)->n = 0; (s)->i = 0; (s)->d = NULL; \ + utstring_reserve(s,100); \ + (s)->d[0] = '\0'; \ +} while(0) + +#define utstring_done(s) \ +do { \ + if ((s)->d != NULL) free((s)->d); \ + (s)->n = 0; \ +} while(0) + +#define utstring_free(s) \ +do { \ + utstring_done(s); \ + free(s); \ +} while(0) + +#define utstring_new(s) \ +do { \ + s = (UT_string*)calloc(sizeof(UT_string),1); \ + if (!s) oom(); \ + utstring_init(s); \ +} while(0) + +#define utstring_renew(s) \ +do { \ + if (s) { \ + utstring_clear(s); \ + } else { \ + utstring_new(s); \ + } \ +} while(0) + +#define utstring_clear(s) \ +do { \ + (s)->i = 0; \ + (s)->d[0] = '\0'; \ +} while(0) + +#define utstring_bincpy(s,b,l) \ +do { \ + utstring_reserve((s),(l)+1); \ + if (l) memcpy(&(s)->d[(s)->i], b, l); \ + (s)->i += l; \ + (s)->d[(s)->i]='\0'; \ +} while(0) + +#define utstring_concat(dst,src) \ +do { \ + utstring_reserve((dst),((src)->i)+1); \ + if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \ + (dst)->i += (src)->i; \ + (dst)->d[(dst)->i]='\0'; \ +} while(0) + +#define utstring_len(s) ((unsigned)((s)->i)) + +#define utstring_body(s) ((s)->d) + +_UNUSED_ static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) { + int n; + va_list cp; + while (1) { +#ifdef _WIN32 + cp = ap; +#else + va_copy(cp, ap); +#endif + n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp); + va_end(cp); + + if ((n > -1) && ((size_t) n < (s->n-s->i))) { + s->i += n; + return; + } + + /* Else try again with more space. */ + if (n > -1) utstring_reserve(s,n+1); /* exact */ + else utstring_reserve(s,(s->n)*2); /* 2x */ + } +} +#ifdef __GNUC__ +/* support printf format checking (2=the format string, 3=start of varargs) */ +static void utstring_printf(UT_string *s, const char *fmt, ...) + __attribute__ (( format( printf, 2, 3) )); +#endif +_UNUSED_ static void utstring_printf(UT_string *s, const char *fmt, ...) { + va_list ap; + va_start(ap,fmt); + utstring_printf_va(s,fmt,ap); + va_end(ap); +} + +/******************************************************************************* + * begin substring search functions * + ******************************************************************************/ +/* Build KMP table from left to right. */ +_UNUSED_ static void _utstring_BuildTable( + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + + i = 0; + j = i - 1; + P_KMP_Table[i] = j; + while (i < (long) P_NeedleLen) + { + while ( (j > -1) && (P_Needle[i] != P_Needle[j]) ) + { + j = P_KMP_Table[j]; + } + i++; + j++; + if (i < (long) P_NeedleLen) + { + if (P_Needle[i] == P_Needle[j]) + { + P_KMP_Table[i] = P_KMP_Table[j]; + } + else + { + P_KMP_Table[i] = j; + } + } + else + { + P_KMP_Table[i] = j; + } + } + + return; +} + + +/* Build KMP table from right to left. */ +_UNUSED_ static void _utstring_BuildTableR( + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + + i = P_NeedleLen - 1; + j = i + 1; + P_KMP_Table[i + 1] = j; + while (i >= 0) + { + while ( (j < (long) P_NeedleLen) && (P_Needle[i] != P_Needle[j]) ) + { + j = P_KMP_Table[j + 1]; + } + i--; + j--; + if (i >= 0) + { + if (P_Needle[i] == P_Needle[j]) + { + P_KMP_Table[i + 1] = P_KMP_Table[j + 1]; + } + else + { + P_KMP_Table[i + 1] = j; + } + } + else + { + P_KMP_Table[i + 1] = j; + } + } + + return; +} + + +/* Search data from left to right. ( Multiple search mode. ) */ +_UNUSED_ static long _utstring_find( + const char *P_Haystack, + size_t P_HaystackLen, + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + long V_FindPosition = -1; + + /* Search from left to right. */ + i = j = 0; + while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) ) + { + while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) ) + { + i = P_KMP_Table[i]; + } + i++; + j++; + if (i >= (int)P_NeedleLen) + { + /* Found. */ + V_FindPosition = j - i; + break; + } + } + + return V_FindPosition; +} + + +/* Search data from right to left. ( Multiple search mode. ) */ +_UNUSED_ static long _utstring_findR( + const char *P_Haystack, + size_t P_HaystackLen, + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + long V_FindPosition = -1; + + /* Search from right to left. */ + j = (P_HaystackLen - 1); + i = (P_NeedleLen - 1); + while ( (j >= 0) && (j >= i) ) + { + while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) ) + { + i = P_KMP_Table[i + 1]; + } + i--; + j--; + if (i < 0) + { + /* Found. */ + V_FindPosition = j + 1; + break; + } + } + + return V_FindPosition; +} + + +/* Search data from left to right. ( One time search mode. ) */ +_UNUSED_ static long utstring_find( + UT_string *s, + long P_StartPosition, /* Start from 0. -1 means last position. */ + const char *P_Needle, + size_t P_NeedleLen) +{ + long V_StartPosition; + long V_HaystackLen; + long *V_KMP_Table; + long V_FindPosition = -1; + + if (P_StartPosition < 0) + { + V_StartPosition = s->i + P_StartPosition; + } + else + { + V_StartPosition = P_StartPosition; + } + V_HaystackLen = s->i - V_StartPosition; + if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) + { + V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); + if (V_KMP_Table != NULL) + { + _utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table); + + V_FindPosition = _utstring_find(s->d + V_StartPosition, + V_HaystackLen, + P_Needle, + P_NeedleLen, + V_KMP_Table); + if (V_FindPosition >= 0) + { + V_FindPosition += V_StartPosition; + } + + free(V_KMP_Table); + } + } + + return V_FindPosition; +} + + +/* Search data from right to left. ( One time search mode. ) */ +_UNUSED_ static long utstring_findR( + UT_string *s, + long P_StartPosition, /* Start from 0. -1 means last position. */ + const char *P_Needle, + size_t P_NeedleLen) +{ + long V_StartPosition; + long V_HaystackLen; + long *V_KMP_Table; + long V_FindPosition = -1; + + if (P_StartPosition < 0) + { + V_StartPosition = s->i + P_StartPosition; + } + else + { + V_StartPosition = P_StartPosition; + } + V_HaystackLen = V_StartPosition + 1; + if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) + { + V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); + if (V_KMP_Table != NULL) + { + _utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table); + + V_FindPosition = _utstring_findR(s->d, + V_HaystackLen, + P_Needle, + P_NeedleLen, + V_KMP_Table); + + free(V_KMP_Table); + } + } + + return V_FindPosition; +} +/******************************************************************************* + * end substring search functions * + ******************************************************************************/ + +#endif /* UTSTRING_H */ diff --git a/gomspace/libutil/include/gs/util/base16.h b/gomspace/libutil/include/gs/util/base16.h new file mode 100644 index 00000000..0fddccc5 --- /dev/null +++ b/gomspace/libutil/include/gs/util/base16.h @@ -0,0 +1,90 @@ +#ifndef GS_UTIL_BASE16_H +#define GS_UTIL_BASE16_H +/* + * Copyright (C) 2010 Michael Brown . + * + * This program 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 2 of the + * License, or any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/** + @file + + Encoding and decoding base16 arrays to and from strings. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Calculate length of base16-encoded data + + @param raw_len Raw data length + @return Encoded string length (excluding NUL) +*/ +static inline size_t base16_encoded_len(size_t raw_len) +{ + return (2 * raw_len); +} + +/** + Calculate maximum length of base16-decoded string + @param encoded Encoded string + @return Maximum length of raw data +*/ +static inline size_t base16_decoded_max_len(const char *encoded) +{ + return ((strlen(encoded) + 1) / 2); +} + +/** + Base16-encode data + + The buffer must be the correct length for the encoded string. Use + something like + + char buf[ base16_encoded_len ( len ) + 1 ]; + + (the +1 is for the terminating NUL) to provide a buffer of the + correct size. + + @param raw Raw data + @param len Length of raw data + @param encoded Buffer for encoded string +*/ +void base16_encode(const uint8_t *raw, size_t len, char *encoded); + +/** + Base16-decode data + + The buffer must be large enough to contain the decoded data. Use + something like + + char buf[ base16_decoded_max_len ( encoded ) ]; + + to provide a buffer of the correct size. + + @param encoded Encoded string + @param raw Raw data + @return Length of raw data, or negative error (gs_error_t) +*/ +int base16_decode(const char *encoded, uint8_t *raw); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/bytebuffer.h b/gomspace/libutil/include/gs/util/bytebuffer.h new file mode 100644 index 00000000..ad727e01 --- /dev/null +++ b/gomspace/libutil/include/gs/util/bytebuffer.h @@ -0,0 +1,173 @@ +#ifndef GS_UTIL_BYTEBUFFER_h +#define GS_UTIL_BYTEBUFFER_h +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Byte buffer provides formatting/serialzing of text/binary data. The buffer keeps track of used space, and prevents overrun. + + The current buffer state can be checked using gs_bytebuffer_state(). + + @dontinclude bytebuffer/bytebuffer_test.c + @skip TEST_gs_bytebuffer_use_case + @until } +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Buffer handle. + Never access handle members directly. +*/ +typedef struct { + /** + Internal: Pointer to user supplied buffer. + @see gs_bytebuffer_init() + */ + uint8_t * buffer; + /** + Internal: Size of user supplied buffer. + @see gs_bytebuffer_init() + */ + size_t size; + /** + Internal: Number of bytes used. + */ + size_t used; + /** + Internal: FUTURE: Committed used + */ + size_t committed_used; + /** + Internal: flags to keep track of buffer state. + */ + uint8_t flags; +} gs_bytebuffer_t; + +/** + Initialize buffer. + + @param[in] bb handle. + @param[in] buffer user supplied buffer of \a buffer_size size (bytes). If NULL, the buffer will keep track of required bytes. + @param[in] buffer_size size of \a buffer. + @return_gs_error_t +*/ +gs_error_t gs_bytebuffer_init(gs_bytebuffer_t * bb, void * buffer, size_t buffer_size); + +/** + Insert data using vprintf. + + @param[in] bb handle. + @param[in] format printf syntax for formatting data + @param[in] ap variable argument list. +*/ +void gs_bytebuffer_vprintf(gs_bytebuffer_t * bb, const char * format, va_list ap); + +/** + Insert data using printf. + + @param[in] bb handle. + @param[in] format printf syntax for formatting data +*/ +void gs_bytebuffer_printf(gs_bytebuffer_t * bb, const char * format, ...) __attribute__ ((format (__printf__, 2, 3))); + +/** + Append data to buffer. + + @param[in] bb handle. + @param[in] data data to append to buffer. + @param[in] length length of data (bytes). +*/ +void gs_bytebuffer_append(gs_bytebuffer_t * bb, const void * data, size_t length); + +/** + Append string to buffer. + + @param[in] bb handle. + @param[in] string string to append to buffer. +*/ +void gs_bytebuffer_append_string(gs_bytebuffer_t * bb, const char * string); + +/** + Append string to buffer. + + @param[in] bb handle. + @param[in] string string to append to buffer. + @param[in] max_length max characters to append from \a string. +*/ +void gs_bytebuffer_append_string_max(gs_bytebuffer_t * bb, const char * string, size_t max_length); + +/** + Return buffer as string - enforcing NUL termination. + + This will always add a NUL termination (zero), which may lead to overflow/truncation of the string. + The NUL termination is NOT added to \a used count. + + @param[in] bb handle. + @param[out] error optional, state of buffer - see gs_bytebuffer_error(). + @return C-string (NUL terminated) +*/ +char * gs_bytebuffer_get_as_string(gs_bytebuffer_t * bb, gs_error_t * error); + +/** + Return buffer state. + + @param[in] bb handle. + @return GS_ERROR_OVERFLOW if data has been truncated. + @return GS_ERROR_DATA in case of error during formatting. + @return_gs_error_t +*/ +gs_error_t gs_bytebuffer_get_state(gs_bytebuffer_t * bb); + +/** + Return buffer (user supplied). + + @param[in] bb handle. +*/ +static inline void * gs_bytebuffer_get_buffer(gs_bytebuffer_t * bb) +{ + return bb->buffer; +} + +/** + Return buffer size (user supplied). + + @param[in] bb handle. + @return buffer size +*/ +static inline size_t gs_bytebuffer_get_size(gs_bytebuffer_t * bb) +{ + return bb->size; +} + +/** + Return number of free bytes. + + @param[in] bb handle. + @return number of free bytes. +*/ +static inline size_t gs_bytebuffer_get_free(gs_bytebuffer_t * bb) +{ + return (bb->size) ? (bb->size - bb->used) : 0; +} + +/** + Return number of used bytes. + + @param[in] bb handle. + @return used bytes. +*/ +static inline size_t gs_bytebuffer_get_used(gs_bytebuffer_t * bb) +{ + return bb->used; +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/byteorder.h b/gomspace/libutil/include/gs/util/byteorder.h new file mode 100644 index 00000000..3d2d6bef --- /dev/null +++ b/gomspace/libutil/include/gs/util/byteorder.h @@ -0,0 +1,341 @@ +#ifndef GS_UTIL_BYTEORDER_H +#define GS_UTIL_BYTEORDER_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Convert numbers between host and network order. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Convert value from host order to network order + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_htons(uint16_t value); + +/** + Convert value from network order to host order + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_ntohs(uint16_t value); + +/** + Convert value from host order to network order + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_htonl(uint32_t value); + +/** + Convert value from network order to host order + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_ntohl(uint32_t value); + +/** + Convert value from host order to network order + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_hton16(uint16_t value); + +/** + Convert value from host order to network order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_hton16_array(const uint16_t * from, uint16_t * to, size_t count); + +/** + Convert value from network order to host order + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_ntoh16(uint16_t value); + +/** + Convert value from network order to host order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_ntoh16_array(const uint16_t * from, uint16_t * to, size_t count); + +/** + Convert value from host order to network order + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_hton32(uint32_t value); + +/** + Convert value from host order to network order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_hton32_array(const uint32_t * from, uint32_t * to, size_t count); + +/** + Convert value from network order to host order + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_ntoh32(uint32_t value); + +/** + Convert value from network order to host order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_ntoh32_array(const uint32_t * from, uint32_t * to, size_t count); + +/** + Convert value from host order to network order + @param[in] value value to convert. + @return converted value. +*/ +uint64_t util_hton64(uint64_t value); + +/** + Convert value from host order to network order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_hton64_array(const uint64_t * from, uint64_t * to, size_t count); + +/** + Convert value from network order to host order + @param[in] value value to convert. + @return converted value. +*/ +uint64_t util_ntoh64(uint64_t value); + +/** + Convert value from network order to host order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_ntoh64_array(const uint64_t * from, uint64_t * to, size_t count); + +/** + Convert value from host order to network order + @param[in] value value to convert. + @return converted value. +*/ +float util_htonflt(float value); + +/** + Convert value from host order to network order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_htonflt_array(const float * from, float * to, size_t count); + +/** + Convert value from network order to host order + @param[in] value value to convert. + @return converted value. +*/ +float util_ntohflt(float value); + +/** + Convert value from network order to host order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_ntohflt_array(const float * from, float * to, size_t count); + +/** + Convert value from host order to network order + @param[in] value value to convert. + @return converted value. +*/ +double util_htondbl(double value); + +/** + Convert value from host order to network order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_htondbl_array(const double * from, double * to, size_t count); + +/** + Convert value from network order to host order + @param[in] value value to convert. + @return converted value. +*/ +double util_ntohdbl(double value); + +/** + Convert value from network order to host order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_ntohdbl_array(const double * from, double * to, size_t count); + +/** + Convert value from host order to big endian. + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_htobe16(uint16_t value); + +/** + Convert value from host order to little endian. + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_htole16(uint16_t value); + +/** + Convert value from big endian to host order. + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_betoh16(uint16_t value); + +/** + Convert value from little endian to host order. + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_letoh16(uint16_t value); + +/** + Convert value from host order to big endian. + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_htobe32(uint32_t value); + +/** + Convert value from host order to little endian. + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_htole32(uint32_t value); + +/** + Convert value from big endian to host order. + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_betoh32(uint32_t value); + +/** + Convert value from little endian to host order. + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_letoh32(uint32_t value); + +/** + Convert value from host order to big endian. + @param[in] value value to convert. + @return converted value. +*/ +uint64_t util_htobe64(uint64_t value); + +/** + Convert value from host order to little endian. + @param[in] value value to convert. + @return converted value. +*/ +uint64_t util_htole64(uint64_t value); + +/** + Convert value from big endian to host order. + @param[in] value value to convert. + @return converted value. +*/ +uint64_t util_betoh64(uint64_t value); + +/** + Convert value from little endian to host order. + @param[in] value value to convert. + @return converted value. +*/ +uint64_t util_letoh64(uint64_t value); + +/** + Byte swap. + @param[in] value value to byteswap. + @return swapped value +*/ +uint16_t gs_bswap_16(uint16_t value); + +/** + Byte swap array. + @param[in] from from address. + @param[out] to to address. + @param[in] count element count. +*/ +void gs_bswap_16_array(const uint16_t * from, uint16_t * to, size_t count); + +/** + Byte swap. + @param[in] value value to byteswap. + @return swapped value +*/ +uint32_t gs_bswap_32(uint32_t value); + +/** + Byte swap array. + @param[in] from from address. + @param[out] to to address. + @param[in] count element count. +*/ +void gs_bswap_32_array(const uint32_t * from, uint32_t * to, size_t count); + +/** + Byte swap. + @param[in] value value to byteswap. + @return swapped value +*/ +uint64_t gs_bswap_64(uint64_t value); + +/** + Byte swap array. + @param[in] from from address. + @param[out] to to address. + @param[in] count element count. +*/ +void gs_bswap_64_array(const uint64_t * from, uint64_t * to, size_t count); + +/** + Byte swap. + @param[in] value value to byteswap. + @return swapped value +*/ +float gs_bswap_float(float value); + +/** + Byte swap array. + @param[in] from from address. + @param[out] to to address. + @param[in] count element count. +*/ +void gs_bswap_float_array(const float * from, float * to, size_t count); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/check.h b/gomspace/libutil/include/gs/util/check.h new file mode 100644 index 00000000..23920161 --- /dev/null +++ b/gomspace/libutil/include/gs/util/check.h @@ -0,0 +1,54 @@ +#ifndef GS_UTIL_CHECK_H +#define GS_UTIL_CHECK_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Argument checking. + + Logs can be enabled through a define. +*/ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if (GS_CHECK_LOG) +#define GS_CHECK_HANDLE(check) if (!(check)) { log_error("Invalid handle - assert: " GS_DEF2STRING(check)); return GS_ERROR_HANDLE;} +#define GS_CHECK_ARG(check) if (!(check)) { log_error("Invalid argument - assert: " GS_DEF2STRING(check)); return GS_ERROR_ARG;} +#define GS_CHECK_SUPPORTED(check) if (!(check)) { log_error("Not supported - assert: " GS_DEF2STRING(check)); return GS_ERROR_NOT_SUPPORTED;} +#define GS_CHECK_RANGE(check) if (!(check)) { log_error("Invalid range - assert: " GS_DEF2STRING(check)); return GS_ERROR_RANGE;} +#else +/** + Perform evalution of 'check' and return GS_ERROR_HANDLE if not 'true'. +*/ +#define GS_CHECK_HANDLE(check) if (!(check)) { return GS_ERROR_HANDLE;} +/** + Perform evalution of 'check' and return GS_ERROR_ARG if not 'true'. +*/ +#define GS_CHECK_ARG(check) if (!(check)) { return GS_ERROR_ARG;} +/** + Perform evalution of 'check' and return GS_ERROR_NOT_SUPPORTED if not 'true'. +*/ +#define GS_CHECK_SUPPORTED(check) if (!(check)) { return GS_ERROR_NOT_SUPPORTED;} +/** + Perform evalution of 'check' and return GS_ERROR_RANGE if not 'true'. +*/ +#define GS_CHECK_RANGE(check) if (!(check)) { return GS_ERROR_RANGE;} +#endif + +/** + Assert on 'value'. + + @deprecated use GS_STATIC_ASSERT() +*/ +#define GS_CHECK_STATIC_ASSERT(condition, name) GS_STATIC_ASSERT(condition, name) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/clock.h b/gomspace/libutil/include/gs/util/clock.h new file mode 100644 index 00000000..1d4a9548 --- /dev/null +++ b/gomspace/libutil/include/gs/util/clock.h @@ -0,0 +1,88 @@ +#ifndef GS_UTIL_CLOCK_H +#define GS_UTIL_CLOCK_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Get/set time (including RTC), convert to/from string. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Returns real time/clock (UTC - time since Epoch/1970). + + If the platform supports a Real Time Clock, the RTC is normally read on first call. An offset is calculated for the relative clock, which + then is used to calculate the actual time. + + @note clock_get_time() is proto-typed in libcsp as weak, but with different argument which MUST match gs_timestamp_t. + @param[out] time user allocated buffer, contaning the current UTC time. +*/ +void gs_clock_get_time(gs_timestamp_t * time); + +/** + Set real time/clock (UTC). + If the platform supports a Real Time Clock, the RTC is also updated. + @param[in] time UTC time. + @return_gs_error_t +*/ +gs_error_t gs_clock_set_time(const gs_timestamp_t * time); + +/** + Returns elapsed time since some unspecified starting point. + @param[out] time user allocated buffer, receives elapsed time. + @see gs_time_rel_ms() +*/ +void gs_clock_get_monotonic(gs_timestamp_t * time); + +/** + Returns number of elapsed nano-seconds since some unspecified starting point. + @return nano-seconds. +*/ +uint64_t gs_clock_get_nsec(void); + +/** + Buffer length for containing full ISO8601 timestamp - including zero (0) termination. +*/ +#define GS_CLOCK_ISO8601_BUFFER_LENGTH 21 + +/** + Convert UTC to a ISO8601 string. + ISO8601 timestamp: 2017-03-30T06:20:45Z + @param[in] utc_time UTC time. + @param[out] buffer user allocated buffer. + @param[in] buffer_size size of \a buf. + @return_gs_error_t +*/ +gs_error_t gs_clock_to_iso8601_string(const gs_timestamp_t * utc_time, char * buffer, size_t buffer_size); + +/** + Convert UTC to a ISO8601 string. + ISO8601 timestamp: 2017-03-30T06:20:45Z + @param[in] utc_sec UTC seconds. + @param[out] buffer user allocated buffer. + @param[in] buffer_size size of \a buf. + @return_gs_error_t +*/ +gs_error_t gs_clock_to_iso8601_string2(uint32_t utc_sec, char * buffer, size_t buffer_size); + +/** + Convert string (UTC time) to timstamp. + Parse string as: + 1. \.\ - number of seconds elapsed since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). + 2. YYYY-MM-DDTHH:MM:SSZ - ISO8601 + @param[in] str time + @param[out] ts time + @return_gs_error_t +*/ +gs_error_t gs_clock_from_string(const char * str, gs_timestamp_t * ts); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/conf_util.h b/gomspace/libutil/include/gs/util/conf_util.h new file mode 100644 index 00000000..55831fb5 --- /dev/null +++ b/gomspace/libutil/include/gs/util/conf_util.h @@ -0,0 +1,10 @@ +#ifndef W_INCLUDE_CONF_UTIL_H_WAF +#define W_INCLUDE_CONF_UTIL_H_WAF + +#define UTIL_LITTLE_ENDIAN 1 +/* #undef UTIL_BIG_ENDIAN */ +#define GS_CONSOLE_HISTORY_LEN 10 +#define GS_CONSOLE_INPUT_LEN 100 +/* #undef GS_LOG_ENABLE_ISR_LOGS */ + +#endif /* W_INCLUDE_CONF_UTIL_H_WAF */ diff --git a/gomspace/libutil/include/gs/util/crc32.h b/gomspace/libutil/include/gs/util/crc32.h new file mode 100644 index 00000000..f2be6775 --- /dev/null +++ b/gomspace/libutil/include/gs/util/crc32.h @@ -0,0 +1,55 @@ +#ifndef GS_UTIL_CRC32_H +#define GS_UTIL_CRC32_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + CRC32 checksumes. + + https://en.wikipedia.org/wiki/Cyclic_redundancy_check. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Return init/seed value for CRC-32. + @return initial/seed value for CRC-32, using 0xffffffff. + @see gs_crc32_update(), gs_crc32_finalize() +*/ +uint32_t gs_crc32_init(void); + +/** + Update CRC-32. + @param[in] crc current CRC-32 + @param[in] block start of memory block. + @param[in] length length of \a block. + @return updated CRC-32. + @see gs_crc32_init(), gs_crc32_finalize() +*/ +uint32_t gs_crc32_update(uint32_t crc, const void * block, size_t length); + +/** + Return finalized CRC-32. + @param[in] crc Checksum is finalized by xor'ing 0xffffffff. + @return finalized CRC-32. + @see gs_crc32_init(), gs_crc32_update() +*/ +uint32_t gs_crc32_finalize(uint32_t crc); + +/** + Return finalized CRC-32 on amemory block. + + @param[in] block block to calculate CRC-32 on. + @param[in] length length/size of \a block. + @return finalized CRC-32. +*/ +uint32_t gs_crc32(const void *block, size_t length); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/crc8.h b/gomspace/libutil/include/gs/util/crc8.h new file mode 100644 index 00000000..99b14d0a --- /dev/null +++ b/gomspace/libutil/include/gs/util/crc8.h @@ -0,0 +1,55 @@ +#ifndef GS_UTIL_CRC8_H +#define GS_UTIL_CRC8_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + CRC8 checksumes. + + https://en.wikipedia.org/wiki/Cyclic_redundancy_check. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Return init/seed value for CRC-8. + @return initial/seed value for CRC-8, using 0xff. + @see gs_crc8_update(), gs_crc8_finalize() +*/ +uint8_t gs_crc8_init(void); + +/** + Update CRC-8. + @param[in] crc current CRC-8 + @param[in] block start of memory block. + @param[in] length length of \a block. + @return updated CRC-8. + @see gs_crc8_init(), gs_crc8_finalize() +*/ +uint8_t gs_crc8_update(uint8_t crc, const void * block, size_t length); + +/** + Return finalized CRC-8. + @param[in] crc Checksum is finalized by xor'ing 0xffffffff. + @return finalized CRC-8. + @see gs_crc8_init(), gs_crc8_update() +*/ +uint8_t gs_crc8_finalize(uint8_t crc); + +/** + Return finalized CRC-8 on amemory block. + + @param[in] block block to calculate CRC-8 on. + @param[in] length length/size of \a block. + @return finalized CRC-8. +*/ +uint8_t gs_crc8(const void *block, size_t length); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/delay.h b/gomspace/libutil/include/gs/util/delay.h new file mode 100644 index 00000000..d205b48c --- /dev/null +++ b/gomspace/libutil/include/gs/util/delay.h @@ -0,0 +1,42 @@ +#ifndef GS_UTIL_DELAY_H +#define GS_UTIL_DELAY_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Delay execution. + + @note Most implementations uses busy waiting. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Delay for number of microseconds. + @note Linux doesn't busy wait. + @param us Number of microseconds to wait +*/ +void gs_delay_us(uint32_t us); + +/** + Return current counter used for us delays + @return timestamp in us +*/ +uint16_t gs_delay_ts_get(void); + +/** + Wait until delay has passed since timestamp + + @param[in] ts Timestamp in us + @param[in] delay The requested delay since ts +*/ +void gs_delay_from_ts(uint16_t ts, uint16_t delay); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/can/can.h b/gomspace/libutil/include/gs/util/drivers/can/can.h new file mode 100644 index 00000000..27f7acd5 --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/can/can.h @@ -0,0 +1,122 @@ +#ifndef GS_UTIL_DRIVERS_CAN_CAN_H +#define GS_UTIL_DRIVERS_CAN_CAN_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + CAN interface. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Default log group for CAN driver. +*/ +GS_LOG_GROUP_EXTERN(gs_can_log); + +/** + Bit-rate (default). +*/ +#define GS_CAN_DEFAULT_BPS 1000000 + +/** + Callback for handling received data (from CAN driver). + @param[in] device hardware device + @param[in] canMsgId standard or extended message id. + @param[in] extendedMsgId \a true if extended id, \a false if standard id. + @param[in] data pointer to data. + @param[in] data_size size of data. + @param[in] nowMs current relative time in mS. + @param[in] user_data user data. + @param[in] cswitch If called from within an ISR (embedded platform), this will none NULL. +*/ +typedef void (*gs_can_rxdata_callback_t)(int hdl, + uint32_t canMsgId, + bool extendedMsgId, + const void * data, + size_t data_size, + uint32_t nowMs, + void * user_data, + gs_context_switch_t * cswitch); + +/** + Send CAN message with standard id (11 bits). + @param[in] device hardware device + @param[in] canMsgId standard CAN message id. + @param[in] data pointer to data. + @param[in] data_size size of data. + @param[in] timeout_ms timeout in mS. + @return GS_ERROR_FULL if Tx queue is full + @return_gs_error_t +*/ +gs_error_t gs_can_send_standard(uint8_t device, uint32_t canMsgId, const void * data, size_t data_size, int timeout_ms); + +/** + Send CAN message with exended id (29 bits). + @param[in] device hardware device + @param[in] canExtMsgId exteneded message id. + @param[in] data pointer to data. + @param[in] data_size size of data. + @param[in] timeout_ms timeout in mS. + @return GS_ERROR_FULL if Tx queue is full + @return_gs_error_t +*/ +gs_error_t gs_can_send_extended(uint8_t device, uint32_t canExtMsgId, const void * data, size_t data_size, int timeout_ms); + +/** + Set filter and callback for standard message id. + @param[in] device hardware device + @param[in] canMsgId standard message id. + @param[in] mask filter mask. + @param[in] rx_callback callback function. + @param[in] rx_user_data user data provided in callback. + @return GS_ERROR_FULL if all message id slots are used. + @return_gs_error_t +*/ +gs_error_t gs_can_set_standard_filter_mask(uint8_t device, uint32_t canMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * rx_user_data); + +/** + Set filter and callback for extended message id. + @param[in] device hardware device + @param[in] canExtMsgId extended message id. + @param[in] mask filter mask. + @param[in] rx_callback callback function. + @param[in] rx_user_data user data provided in callback. + @return GS_ERROR_FULL if all message id slots are used. + @return_gs_error_t +*/ +gs_error_t gs_can_set_extended_filter_mask(uint8_t device, uint32_t canExtMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * rx_user_data); + +/** + Stop CAN layer. + If a CAN transceiver is present and controlled, it will be disabled. + @param[in] device hardware device + @return_gs_error_t +*/ +gs_error_t gs_can_stop(uint8_t device); + +/** + Start CAN layer. + Clear all buffers and start CAN. + If a CAN transceiver is present and controlled, it will be enabled. + @param[in] device hardware device + @return_gs_error_t +*/ +gs_error_t gs_can_start(uint8_t device); + +/** + Get current CAN layer error state. + @param[in] device hardware device + @param[out] restart_required \a true if CAN layer should be re-started. Pass NULL, if not wanted. + @return_gs_error_t +*/ +gs_error_t gs_can_error_state(uint8_t device, bool * restart_required); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/gpio/gpio.h b/gomspace/libutil/include/gs/util/drivers/gpio/gpio.h new file mode 100644 index 00000000..ff2803c0 --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/gpio/gpio.h @@ -0,0 +1,91 @@ +#ifndef GS_UTIL_DRIVERS_GPIO_GPIO_H +#define GS_UTIL_DRIVERS_GPIO_GPIO_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + GPIO interface provides a generic interface toward hardware GPIO's. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + GPIO definition. +*/ +typedef struct { + //! Chip/group/port number which the GPIO belongs to. + uint16_t port; + //! The pin number of the GPIO. + uint16_t pin; +} gs_gpio_t; + +/** + GPIO interrupt function. +*/ +typedef void (*gs_gpio_isr_t)(gs_context_switch_t * cswitch); + +/** + Configuration for interrupt related to a GPIO. +*/ +typedef struct { + //! True if it shall trigger on rising edge. + bool rising_edge; + //! True if it shall trigger on falling edge. + bool falling_edge; + //! True if it shall have high priority (if nested isr supported). + bool high_priority; + //! ISR to be called on trigger. + gs_gpio_isr_t isr; +} gs_interrupt_conf_t; + +/** + GPIO get value + + @param[in] gpio The gpio to read + @param[in] value Returned GPIO value (true/false = High/Low) + @return_gs_error_t +*/ +gs_error_t gs_gpio_get(gs_gpio_t gpio, bool *value); + +/** + GPIO get value without error check + + @param[in] gpio The gpio to read + @return GPIO value (true/false = High/Low) +*/ +bool gs_gpio_get_nc(gs_gpio_t gpio); + +/** + GPIO set value + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @return_gs_error_t +*/ +gs_error_t gs_gpio_set(gs_gpio_t gpio, bool value); + +/** + GPIO set value without error check + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) +*/ +void gs_gpio_set_nc(gs_gpio_t gpio, bool value); + +/** + Initialize GPIO as an external interrupt pin. + + @param[in] gpio The gpio to configure + @param[in] conf Configuration of interrupt pin + @return_gs_error_t + */ +gs_error_t gs_gpio_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/i2c/common.h b/gomspace/libutil/include/gs/util/drivers/i2c/common.h new file mode 100644 index 00000000..895847d3 --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/i2c/common.h @@ -0,0 +1,88 @@ +#ifndef GS_UTIL_DRIVERS_I2C_COMMON_H +#define GS_UTIL_DRIVERS_I2C_COMMON_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Common (master and slave) I2C definitions. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Default log group for I2C driver. +*/ +GS_LOG_GROUP_EXTERN(gs_i2c_log); + +/** + I2C mode. +*/ +typedef enum { + //! Master mode + GS_I2C_MASTER = 0, + //! Multimaster mode + GS_I2C_MULTI_MASTER = 1, + //! Slave mode + GS_I2C_SLAVE = 2, +} gs_i2c_mode_t; + +/** + Cross-platform I2C configuration. +*/ +typedef struct { + //! Data order, True: MSB first, False: LSB first (default = True) + bool data_order_msb; + //! Device mode (master, multimaster, or slave) + gs_i2c_mode_t mode; + //! Address of node in multimaster and slave mode (not used in master mode) + uint16_t addr; + //! Bits per second (default is #GS_I2C_DEFAULT_BPS) + uint32_t bps; + //! Address size in bits, 7, 8 or 10 bits (default/prefered is #GS_I2C_DEFAULT_ADDRESS_SIZE) + uint8_t addrbits; +} gs_i2c_config_t; + +/** + Cross-platform I2C configuration. + @deprecated use gs_i2c_config_t. +*/ +typedef gs_i2c_config_t gs_i2c_bus_config_t; + +/** + Default bit-rate. +*/ +#define GS_I2C_DEFAULT_BPS 100000 + +/** + Default address size. +*/ +#define GS_I2C_DEFAULT_ADDRESS_SIZE 7 + +/** + Default data order (MSB). +*/ +#define GS_I2C_DEFAULT_DATA_ORDER_MSB 1 + +/** + Speed (command line sub-option). +*/ +#define GS_I2C_COMMAND_LINE_SPEED "speed" + +/** + Device (command line sub-option). +*/ +#define GS_I2C_COMMAND_LINE_DEVICE "device" + +/** + Address (command line sub-option). +*/ +#define GS_I2C_COMMAND_LINE_ADDRESS "address" + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/i2c/master.h b/gomspace/libutil/include/gs/util/drivers/i2c/master.h new file mode 100644 index 00000000..169d5d2a --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/i2c/master.h @@ -0,0 +1,32 @@ +#ifndef GS_UTIL_DRIVERS_I2C_MASTER_H +#define GS_UTIL_DRIVERS_I2C_MASTER_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + I2C master interface. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Perform transaction to I2C slave. + @param[in] device hardware device (bus) + @param[in] addr slave address + @param[in] tx transmit buffer + @param[in] txlen number of bytes to transmit + @param[out] rx receive buffer - can be NULL. + @param[in] rxlen number of bytes to receive. + @param[in] timeout_ms timeout in milliseconds, primarily for locking the I2C channel. + @return_gs_error_t +*/ +gs_error_t gs_i2c_master_transaction(uint8_t device, uint8_t addr, const void * tx, size_t txlen, void * rx, size_t rxlen, int timeout_ms); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/i2c/slave.h b/gomspace/libutil/include/gs/util/drivers/i2c/slave.h new file mode 100644 index 00000000..540000e3 --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/i2c/slave.h @@ -0,0 +1,79 @@ +#ifndef GS_UTIL_DRIVERS_I2C_SLAVE_H +#define GS_UTIL_DRIVERS_I2C_SLAVE_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + I2C slave interface. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Start/enable I2C bus reception. + + Reception should not automatically be enabled by their init() functions, as this will complicate adding additional layers/hooks. + + @param[in] device I2C bus (handle) + @return_gs_error_t +*/ +gs_error_t gs_i2c_slave_start(uint8_t device); + +/** + Rx callback. + + Function called when data has been received on the bus (I2C write operation complete). + + @param[in] device I2C bus (handle). + @param[in] rx receive buffer. + @param[in] rx_length number of bytes received. + @param_cswitch +*/ +typedef void (* gs_i2c_slave_receive_t)(uint8_t device, const uint8_t * rx, size_t rx_length, gs_context_switch_t * cswitch); + +/** + Set rx callback. + + @param[in] device I2C bus (handle). + @param[in] rx Rx callback. + @return_gs_error_t +*/ +gs_error_t gs_i2c_slave_set_rx(uint8_t device, gs_i2c_slave_receive_t rx); + +/** + Get rx buffer callback. + + Function called from driver, for getting a pointer to the rx buffer. + + @param[in] device I2C bus (handle). +*/ +typedef void * (* gs_i2c_slave_get_rx_buf_t)(uint8_t device); + +/** + Set rx buffer get callback. + + @param[in] device I2C bus (handle). + @param[in] get_rx_buf get rx buffer callback. + @param[in] buf_length length of buffer retrieved with this callback. + @return_gs_error_t +*/ +gs_error_t gs_i2c_slave_set_get_rx_buf(uint8_t device, gs_i2c_slave_get_rx_buf_t get_rx_buf, size_t buf_length); + +/** + Set response data. + + @param[in] device I2C bus (handle). + @param[in] tx pointer to data. NOTE: data is not copied due to performance, so data must stay valid until the response has been sent. + @param[in] tx_length length of data. + @return_gs_error_t +*/ +gs_error_t gs_i2c_slave_set_response(uint8_t device, const uint8_t * tx, size_t tx_length); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/spi/common.h b/gomspace/libutil/include/gs/util/drivers/spi/common.h new file mode 100644 index 00000000..069a346e --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/spi/common.h @@ -0,0 +1,66 @@ +#ifndef GS_UTIL_DRIVERS_SPI_COMMON_H +#define GS_UTIL_DRIVERS_SPI_COMMON_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Common (master and slave) SPI definitions. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Default log group for SPI driver. +*/ +GS_LOG_GROUP_EXTERN(gs_spi_log); + +/** + SPI mode - clock polarity and phase. +*/ +typedef enum { + /** + Polarity = 0, Phase = 0 (default). + */ + GS_SPI_MODE_CPOL0_CPHA0 = 0, + /** + Polarity = 0, Phase = 1. + */ + GS_SPI_MODE_CPOL0_CPHA1 = 1, + /** + Polarity = 1, Phase = 0. + */ + GS_SPI_MODE_CPOL1_CPHA0 = 2, + /** + Polarity = 1, Phase = 1. + */ + GS_SPI_MODE_CPOL1_CPHA1 = 3 +} gs_spi_mode_t; + +/** + Default bit-rate. +*/ +#define GS_SPI_DEFAULT_BPS 400000 + +/** + Speed (command line sub-option). +*/ +#define GS_SPI_COMMAND_LINE_SPEED "speed" + +/** + Slave (command line sub-option). +*/ +#define GS_SPI_COMMAND_LINE_SLAVE "slave" + +/** + Device (command line sub-option). +*/ +#define GS_SPI_COMMAND_LINE_DEVICE "device" + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/spi/master.h b/gomspace/libutil/include/gs/util/drivers/spi/master.h new file mode 100644 index 00000000..986f1ce4 --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/spi/master.h @@ -0,0 +1,95 @@ +#ifndef GS_UTIL_DRIVERS_SPI_MASTER_H +#define GS_UTIL_DRIVERS_SPI_MASTER_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + SPI master interface. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Cross-platform master SPI configuration. +*/ +typedef struct { + /** + Data order, \a True: MSB first, \a False: LSB first + Default: \a True. + */ + bool data_order_msb; + /** + Bits per second. + Default: #GS_SPI_DEFAULT_BPS. + */ + uint32_t bps; + /** + Mode, specifying polarity and phase. + Default: #GS_SPI_MODE_CPOL0_CPHA0. + */ + gs_spi_mode_t mode; + /** + Character size in bits, 8-16 bits. + Default: 8 bits (prefered). + */ + uint8_t bits; +} gs_spi_master_slave_config_t; + +/** + Single master transaction. +*/ +typedef struct { + /** + Pointer to tx data, or NULL if no tx. + */ + const void *tx; + /** + Pointer to rx buffer, or NULL if no rx. + */ + void *rx; + /** + Size/length of rx/tx (bytes). + */ + size_t size; +} gs_spi_master_trans_t; + +/** + Close/free slave. + Freeing resources associated with the slave. + @param[in] slave SPI slave + @return_gs_error_t +*/ +gs_error_t gs_spi_master_close_slave(uint8_t slave); + +/** + Perform transaction to/from a pre-configured SPI slave. + Basically for i < size: send tx[i] and receive rx[i]. + @note: 8 bit SPI character size required! + @param[in] slave SPI slave + @param[in] tx tx buffer + @param[out] rx rx buffer - can be NULL. + @param[in] size number of to send and also receive. + @param[in] timeout_ms timeout in milliseconds, primarily for locking the SPI device. + @return_gs_error_t +*/ +gs_error_t gs_spi_master_transaction(uint8_t slave, const void * tx, void * rx, size_t size, int timeout_ms); + +/** + Perform N transaction to/from a pre-configured SPI slave within one chip selection + @note: 8 bit SPI character size required! + @param[in] slave SPI slave + @param[in] trans Pointer to transactions + @param[in] count Number of transactions (rx and/or tx) to complete + @param[in] timeout_ms timeout in milliseconds, primarily for locking the SPI device. + @return_gs_error_t +*/ +gs_error_t gs_spi_master_transactions(uint8_t slave, gs_spi_master_trans_t *trans, size_t count, int timeout_ms); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/spi/slave.h b/gomspace/libutil/include/gs/util/drivers/spi/slave.h new file mode 100644 index 00000000..0be02a8e --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/spi/slave.h @@ -0,0 +1,84 @@ +#ifndef GS_UTIL_DRIVERS_SPI_SLAVE_H +#define GS_UTIL_DRIVERS_SPI_SLAVE_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + SPI slave interface. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Cross-platform slave SPI configuration. +*/ +typedef struct { + /** + Data order, \a True: MSB first, \a False: LSB first + Default: \a True. + */ + bool data_order_msb; + /** + Mode, specifying polarity and phase. + Default: #GS_SPI_MODE_CPOL0_CPHA0. + */ + gs_spi_mode_t mode; + /** + Character size in bits, 8-16 bits. + Default: 8 bits (prefered). + */ + uint8_t bits; +} gs_spi_slave_config_t; + +/** + Start/enable SPI device reception. + + Reception should not automatically be enabled by their init() functions, as this will complicate adding additional layers/hooks. + + @param[in] device SPI device (handle) + @return_gs_error_t +*/ +gs_error_t gs_spi_slave_start(uint8_t device); + +/** + Rx callback. + + Function called as data is recevied on the device. + + @param[in] device SPI device (handle). + @param[in] rx_buffer Pointer to start of rx buffer. + @param[in] rx number of bytes received so far. + @param[in] new_request \a true on the first callback of new data, \a false on receiving additional data during same \a chip-select. Can be used to bring receiver back in sync with new request. + @param_cswitch + @return total number of bytes to receive before next call back. Return 0 to ignore rest of data - no additional call backs will be done for current SPI transaction. +*/ +typedef uint8_t (* gs_spi_slave_receive_t)(uint8_t device, const uint8_t * rx_buffer, size_t rx, bool new_request, gs_context_switch_t * cswitch); + +/** + Set rx callback. + + @param[in] device SPI device (handle). + @param[in] rx Rx callback. + @return_gs_error_t +*/ +gs_error_t gs_spi_slave_set_rx(uint8_t device, gs_spi_slave_receive_t rx); + +/** + Set response data. + + @param[in] device SPI device (handle). + @param[in] offset offset (in bytes) for the response, counted from start of request, i.e. offset of 2 means data will be sent as the 3rd byte. + @param[in] tx pointer to data. NOTE: data is not copied due to performance, so data must stay valid until the response has been sent. + @param[in] size size of data. + @return_gs_error_t +*/ +gs_error_t gs_spi_slave_set_response(uint8_t device, size_t offset, const uint8_t * tx, size_t size); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/sys/memory.h b/gomspace/libutil/include/gs/util/drivers/sys/memory.h new file mode 100644 index 00000000..ca3862df --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/sys/memory.h @@ -0,0 +1,92 @@ +#ifndef GS_UTIL_DRIVERS_SYS_MEMORY_H +#define GS_UTIL_DRIVERS_SYS_MEMORY_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Cross platform memory status API. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + RAM status + Containing different size parameters describing RAM usage. + All sizes are in bytes. + If a parameter is not available/supported on a specific platform, the parameter is set to -1. + */ +typedef struct { + //! total size of RAM + long total; + //! max available RAM for allocation after initialization of of global/static variables + long max_available; + //! available RAM at runtime for dynamic allocation + long available; + //! Lowest registered available RAM since boot + long min_available; +} gs_mem_ram_stat_t; + +/** + RAM types + Defines the different RAM types (external/internal) supported on + the various platforms. + */ +typedef enum { + GS_MEM_RAM_TYPE_INTERNAL = 0,//!< Internal RAM type + GS_MEM_RAM_TYPE_EXTERNAL //!< External RAM type +} gs_mem_ram_type_t; + +/** + Get status of internal RAM + + @param[out] ram_stat RAM status, each member of struct is -1 if not supported on specific platform + @return_gs_error_t + */ +gs_error_t gs_mem_get_int_ram_stat(gs_mem_ram_stat_t * ram_stat); + +/** + Get status of external RAM + + @param[out] ram_stat RAM status, each member of struct is -1 if not supported on specific platform + @return_gs_error_t + */ +gs_error_t gs_mem_get_ext_ram_stat(gs_mem_ram_stat_t * ram_stat); + + +/** + Get status of selected RAM + + @param[in] type RAM type to query status for + @param[out] ram_stat RAM status, each member of struct is -1 if not supported on specific platform + @return_gs_error_t + */ +gs_error_t gs_mem_get_ram_stat(gs_mem_ram_type_t type, gs_mem_ram_stat_t * ram_stat); + + +/** + Get default RAM type + + returns the default RAM type used for allocations (Heap). + @return gs_mem_ram_type_t + */ +gs_mem_ram_type_t gs_mem_get_ram_default(); + + +/** + Print RAM status. + + @param[in] ram_stat RAM status + @param[in] out output stream + @return_gs_error_t + */ +gs_error_t gs_mem_print_ram_stat(gs_mem_ram_stat_t * ram_stat, FILE * out); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/watchdog/device.h b/gomspace/libutil/include/gs/util/drivers/watchdog/device.h new file mode 100644 index 00000000..613e511e --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/watchdog/device.h @@ -0,0 +1,61 @@ +#ifndef GS_UTIL_DRIVERS_HW_WATCHDOG_H +#define GS_UTIL_DRIVERS_HW_WATCHDOG_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Hardward watchdog (HWWD) device interface. + + Hardware Watchdog interface which provides a generic interface towards + any HWWD. Most HWWD implementation should be able to fit behind + this interface, with just a small "adaption" layer needed. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Hardware watchdog driver interface. +*/ +typedef struct gs_watchdog_dev_ops gs_watchdog_dev_ops_t; + +/** + Hardware watchdog (HWWD) device structure + + Structure that describes the HWWD device and holds + the parameters needed for storing e.g. timeout values etc. +*/ +typedef struct gs_watchdog_device { + int id; /**< An ID for the HWWD device - This is currently not used. */ + const gs_watchdog_dev_ops_t *ops; /**< Pointer to ops struct defining the operations a HWWD device supports. */ + unsigned int timeout; /**< The timeout value that the HWWD device should be configured with. */ + unsigned int pretimeout; /**< The pretimeout (if supported) by the HWWD device */ + unsigned int min_timeout; /**< Minimum timeout value supported by the HWWD device */ + unsigned int max_timeout; /**< Maximum timeout value supported by the HWWD device */ + void *driver_data; /**< Pointer to driver specific data can be used by the HWWD driver impl. */ +} gs_watchdog_device_t; + +/** + Hardware watchdog driver interface. +*/ +struct gs_watchdog_dev_ops +{ + /* mandatory operations */ + gs_error_t (*start)(gs_watchdog_device_t *); /**< Starts the HWWD device */ + gs_error_t (*stop)(gs_watchdog_device_t *); /**< Stops the HWWD device */ + gs_error_t (*ping)(gs_watchdog_device_t *); /**< Polls the HWWD device and restart count-down */ + /* optional operations */ + gs_error_t (*set_timeout)(gs_watchdog_device_t *, unsigned int); /**< (Optional) Set timeout of the HWWD device */ + gs_error_t (*set_pretimeout)(gs_watchdog_device_t *, unsigned int); /**< (Optional) Set Pre-timeout of the HWWD device */ + gs_error_t (*restart)(gs_watchdog_device_t *); /**< (Optional) Restart the HWWD device */ + unsigned int (*get_timeleft)(gs_watchdog_device_t *); /**< (Optional) Get time left until HWWD device times out. */ + int (*status)(gs_watchdog_device_t *); /**< (Optional) Reads status of the HWWD device */ +}; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/endian.h b/gomspace/libutil/include/gs/util/endian.h new file mode 100644 index 00000000..8e931d8a --- /dev/null +++ b/gomspace/libutil/include/gs/util/endian.h @@ -0,0 +1,53 @@ +#ifndef GS_UTIL_ENDIAN_H +#define GS_UTIL_ENDIAN_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Detecting endian type. +*/ + +// generated by waf configure, defines either UTIL_BIG_ENDIAN or UTIL_LITTLE_ENDIAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if !UTIL_BIG_ENDIAN && !UTIL_LITTLE_ENDIAN + #error No endian defined +#endif +#if UTIL_BIG_ENDIAN && UTIL_LITTLE_ENDIAN + #error Both big and little endian defined +#endif + +#include + +/** + Returns \a true if platform is big endian. +*/ +static inline bool gs_endian_big(void) +{ +#if (UTIL_BIG_ENDIAN) + return true; +#else + return false; +#endif +} + +/** + Returns \a true if platform is little endian. +*/ +static inline bool gs_endian_little(void) +{ +#if (UTIL_LITTLE_ENDIAN) + return true; +#else + return false; +#endif +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/error.h b/gomspace/libutil/include/gs/util/error.h new file mode 100644 index 00000000..d1743165 --- /dev/null +++ b/gomspace/libutil/include/gs/util/error.h @@ -0,0 +1,199 @@ +#ifndef GS_UTIL_ERROR_H +#define GS_UTIL_ERROR_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Common error code definitions. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Common/generic error codes. + Based on POSIX \a errno values, but negative instead of positive. +*/ +typedef enum gs_error_t { + /** + Success - ok (POSIX). + */ + GS_OK = 0, + /** + Operation not permitted (POSIX.1: EPERM). + */ + GS_ERROR_PERM = -1, + /** + Interrupted system call (or Interrupted function call) (POSIX: EINTR). + */ + GS_ERROR_INTR = -4, + /** + Input/output error (POSIX.1: EIO) + */ + GS_ERROR_IO = -5, + /** + Resource temporarily unavailable (may be the same value as EWOULDBLOCK) (POSIX.1: EAGAIN). + */ + GS_ERROR_AGAIN = -11, + /** + Cannot allocate memory (or Not enough space) (POSIX.1: ENOMEM). + */ + GS_ERROR_ALLOC = -12, + /** + Permission denied (POSIX.1: EACCES). + */ + GS_ERROR_ACCESS = -13, + /** + Device or resource busy (POSIX.1: EBUSY). + */ + GS_ERROR_BUSY = -16, + /** + File exists (POSIX.1-2001: EEXIST). + */ + GS_ERROR_EXIST = -17, + /** + Invalid argument (POSIX.1: EINVAL). + */ + GS_ERROR_ARG = -22, + /** + Function not implemented (POSIX.1: ENOSYS) + */ + GS_ERROR_NOT_IMPLEMENTED = -38, + /** + Value too large to be stored in data type (POSIX.1: EOVERFLOW). + Example: trying to put 50 characters into a 10 character array. + @see GS_ERROR_RANGE. + */ + GS_ERROR_OVERFLOW = -75, + /** + Operation not supported (POSIX.1: ENOTSUP) + */ + GS_ERROR_NOT_SUPPORTED = -95, + /** + Address already in use (POSIX.1: EADDRINUSE). + */ + GS_ERROR_IN_USE = -98, + /** + Connection reset (POSIX.1-2001: ECONNRESET). + */ + GS_ERROR_CONNECTION_RESET = -104, + /** + No buffer space available (POSIX.1 (XSI STREAMS option): ENOBUFS). + */ + GS_ERROR_NO_BUFFERS = -105, + /** + Timeout (POSIX.1-2001: ETIMEDOUT). + */ + GS_ERROR_TIMEOUT = -110, + /** + Connection already in progress (POSIX.1-2001: EALREADY). + */ + GS_ERROR_ALREADY_IN_PROGRESS = -114, + + /** + Handle error (GOMspace). + */ + GS_ERROR_HANDLE = -2000, // from errno.h: #define __ELASTERROR 2000 /* Users can add values starting here */ + /** + Not found (GOMspace). + */ + GS_ERROR_NOT_FOUND = -2001, + /** + Full (GOMspace). + */ + GS_ERROR_FULL = -2002, + /** + Range error (GOMspace). + Example: specifying 120 hours, where only 0-23 is valid. + @see GS_ERROR_OVERFLOW + */ + GS_ERROR_RANGE = -2003, + /** + Data error (GOMspace). + */ + GS_ERROR_DATA = -2004, + /** + Unknown error (GOMspace). + @note avoid use - use specific error to improve debugging/troubleshooting. + */ + GS_ERROR_UNKNOWN = -2005, + /** + No data available (GOMspace). + */ + GS_ERROR_NO_DATA = -2006, + /** + Stale data - not updated (GOMspace). + */ + GS_ERROR_STALE = -2007, + /** + Type error (GOMspace). + */ + GS_ERROR_TYPE = -2008, + /** + Ambiguous error (GOMspace). + */ + GS_ERROR_AMBIGUOUS = -2009, + /** + State error (GOMspace). + */ + GS_ERROR_STATE = -2010, + +} gs_error_t; + +/** + * Convert an error code to a string. + * Uses standard POSIX strerror() under the hood. + * @param[in] error error to convert. If negative (e.g. \a gs_error_t), it is first converted to a positive value. + * @return string usefull for logging purposes (should not be used for programatically processing). + */ +const char * gs_error_string(int error); + +/** + Convert standard POSIX \a errno to gs_error_t. + @param[in] error POSIX error code (errno). + @return convert error code, by simply converting to a negative number. +*/ +gs_error_t gs_error(int error); + +#if (GS_UTIL_DEPRECATED_ERROR_CODES) +/** + Legacy error definitions. + @deprecated Use standard gs_error_t codes - these defines are only kept, so very old code (not yet update to use #gs_error_t) can compile. + @{ +*/ +#define E_NO_ERR -1 +#define E_NO_DEVICE -2 +#define E_MALLOC_FAIL -3 +#define E_THREAD_FAIL -4 +#define E_NO_QUEUE -5 +#define E_INVALID_BUF_SIZE -6 +#define E_INVALID_PARAM -7 +#define E_NO_SS -8 +#define E_GARBLED_BUFFER -9 +#define E_FLASH_ERROR -10 +#define E_BOOT_SER -13 +#define E_BOOT_DEBUG -14 +#define E_BOOT_FLASH -15 +#define E_TIMEOUT -16 +#define E_NO_BUFFER -17 +#define E_OUT_OF_MEM -18 +#define E_FAIL -19 +/** @} */ + +/** + Converts legacy error definitions to string. + @deprecated Use standard gs_error_t codes - this function is only kept, so very old code (not yet update to use #gs_error_t) can compile. + @param[in] code error code + @return string describing the error. +*/ +const char * error_string(int code) __attribute__((deprecated)); + +#endif // GS_UTIL_DEPRECATED_ERROR_CODES + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/fletcher.h b/gomspace/libutil/include/gs/util/fletcher.h new file mode 100644 index 00000000..5b24c23c --- /dev/null +++ b/gomspace/libutil/include/gs/util/fletcher.h @@ -0,0 +1,89 @@ +#ifndef GS_UTIL_FLETCHER_H +#define GS_UTIL_FLETCHER_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Fletcher16 checksum, +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Fletcher16 checksum (read using copy function). + + Data is read from \a data, using the specified \a memcpyfcn function. + + @param[in] data data. + @param[in] size number of \a data bytes. + @param[in] memcpyfcn memory copy function. If NULL is specified, standard memcpy will be used. + @returns fletcher16 checksum +*/ +uint16_t gs_fletcher16_memcpy(const void * data, size_t size, void * (*memcpyfcn)(void *, const void *, size_t)); + +/** + Fletcher16 checksum (read from program memory). + + AVR8: reads from program memory. + Other architectures: identical to gs_fletcher16(). + + @param[in] data_in data. + @param[in] size number of \a data bytes. + @returns fletcher16 checksum +*/ +uint16_t gs_fletcher16_P(const void * data_in, size_t size); + +/** + Fletcher16 checksum. + + @param[in] data data. + @param[in] size number of \a data bytes. + @returns fletcher16 checksum +*/ +uint16_t gs_fletcher16(const void * data, size_t size); + +/** + Fletcher16 working set. + @see gs_fletcher16_init(), gs_fletcher16_update(), gs_fletcher16_finalize() +*/ +typedef struct { + /** + Sum1 - internal. + */ + uint16_t sum1; + /** + Sum2 - internal. + */ + uint16_t sum2; +} gs_fletcher16_t; + +/** + Initialize fletcher16 working set. + @param[in] f16 working set. +*/ +void gs_fletcher16_init(gs_fletcher16_t * f16); + +/** + Update fletcher16 checksum. + @param[in] f16 working set. + @param[in] data data. + @param[in] size number of \a data bytes. +*/ +void gs_fletcher16_update(gs_fletcher16_t * f16, const void * data, size_t size); + +/** + Finalize fletcher16 checksum and return it. + + @param[in] f16 working set. + @returns fletcher16 checksum +*/ +uint16_t gs_fletcher16_finalize(gs_fletcher16_t * f16); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/function_scheduler.h b/gomspace/libutil/include/gs/util/function_scheduler.h new file mode 100644 index 00000000..229c5031 --- /dev/null +++ b/gomspace/libutil/include/gs/util/function_scheduler.h @@ -0,0 +1,79 @@ +#ifndef GS_UTIL_FUNCTION_SCHEDULER +#define GS_UTIL_FUNCTION_SCHEDULER +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Function scheduler. + + Simple framework for invoking functions at intervals. + + Instead of creating a lot of tasks (which uses memory), this framework can be used to schedule execution of functions at specified intervals. + + Once setup, calling gs_function_scheduler_execute_ms() will execute all functions timed out and return the time, until the next function has + to be executed or max timeout specified (or max wait time supported on the platform). + + The API supports multiple schedulers, but is not thread-safe. + + @note Do NOT use for time critical control, as the actual time interval is influenced by the host thread and other scheduled functions. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Scheduler handle. +*/ +typedef struct gs_function_scheduler gs_function_scheduler_t; + +/** + Function callback. + + @return timeout in mS until next callback. +*/ +typedef uint32_t (*gs_function_scheduler_function_t)(void * user_data); + +/** + Initialize scheduler. + Memory is allocated once for \a max_entries. + @param[in] max_timeout_ms max timeout in mS. + @param[in] max_entries max number of entries for this scheduler. + @param[out] scheduler reference to created scheduler. + @return_gs_error_t +*/ +gs_error_t gs_function_scheduler_create(uint32_t max_timeout_ms, unsigned int max_entries, gs_function_scheduler_t ** scheduler); + +/** + Free scheduler (release resources). + @param[in] scheduler scheduler. + @return_gs_error_t +*/ +gs_error_t gs_function_scheduler_destroy(gs_function_scheduler_t * scheduler); + +/** + Execute scheduled function(s) and returns number of mS until next execute must be called again. + + @note Return type is \a int to prevent overflow on platforms where int is less than 32 bits. + + @param[in] scheduler scheduler. + @return next timeout in mS. +*/ +int gs_function_scheduler_execute_ms(gs_function_scheduler_t * scheduler); + +/** + Register function to be executed at mS intervals. + @param[in] scheduler scheduler. + @param[in] first_timeout_ms mS until first execution. + @param[in] func function to execute. + @param[in] user_data function user data. + @return_gs_error_t +*/ +gs_error_t gs_function_scheduler_register_ms(gs_function_scheduler_t * scheduler, uint32_t first_timeout_ms, gs_function_scheduler_function_t func, void * user_data); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/gosh/command.h b/gomspace/libutil/include/gs/util/gosh/command.h new file mode 100644 index 00000000..8187152e --- /dev/null +++ b/gomspace/libutil/include/gs/util/gosh/command.h @@ -0,0 +1,503 @@ +#ifndef GS_UTIL_GOSH_COMMAND_H +#define GS_UTIL_GOSH_COMMAND_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Command framework. + + Provides a simple way of organizing commands in a hierarchy. A command is a text string mapping to a function - supporting arguments. +*/ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Max langth of a command (including NUL termination). +*/ +#define GS_COMMAND_MAX_LEN_COMMAND 20 + +/** + Flag for hiding command in help and tab-complete. +*/ +#define GS_COMMAND_FLAG_HIDDEN 0x02 + +/** + 'root' command attribute. + + On embedded (none Linux) systems, it is prefered to store as much as possible in \a program memory, in order to save RAM. + This is accomplished by tagging all \a root commands with this attribute, which instructs the linker to put all commands in a named + section. This section is then through the linker-script, placed in \a program memory. + The command framework can read commands directly from this section, and therefore doesn't need an RAM to maintain the list. + + The gs_command_register() must still be called for all \a root commands, which ensures that the linker doesn't throw away the + command objects, due to missing code reference. + + On a Linux system, the commands are not group in a section. Instead gs_command_register() dynamicly builds a list with the commands. + + @see gs_command_register() +*/ +#if (__linux__ == 0) +#define GS_COMMAND_ROOT __attribute__ ((section(".commands"))) +#else +#define GS_COMMAND_ROOT +#endif + +/** + Sub command attribute, + + Only necesasry on AVR8, due to its memory model. +*/ +#define GS_COMMAND_SUB GS_PGM_OBJECT + +/** + Macro for initializing command chains. +*/ +#define GS_COMMAND_INIT_CHAIN(__list) {.list = __list, .count = GS_ARRAY_SIZE(__list)} + +/** + Macro for registering commands. + + @see gs_command_register() +*/ +#define GS_COMMAND_REGISTER(__cmd) gs_command_register(__cmd, GS_ARRAY_SIZE(__cmd)) + +/** + Command reference. + @note Use gs_command_t instead of 'struct command'. +*/ +typedef struct command gs_command_t; + +/** + Commands context reference + @note Use gs_command_context_t instead of struct command_context + */ +typedef struct command_context gs_command_context_t; + +/** + Command output interface +*/ +typedef struct command_io_functions { + /** + Function interface for setting result + @param output_ctx pointer to output context for the given impl. + @param group Group name specifies the group that a given key/value pair belongs to. + @param key key name + @param value string value of the result + @return_gs_error_t + */ + gs_error_t (*set_result)(gs_command_context_t *ctx, const char *group, const char *key, const char *value); + /** + Function interface for flushing results. Used by the command handler to ensure output/results + are flushed to stdout/File or any other receiver of the output. + @param output_ctx pointer to output context for the given impl. + @return_gs_error_t + */ + gs_error_t (*flush)(gs_command_context_t *ctx); + /** + Function interface for waiting for key/input + @param output_ctx pointer to output context for the given impl. + @param ch pointer to character returned by function + @param timeout_ms maximum time to wait of the character. + @return_gs_error_t + */ + gs_error_t (*wait_for_key)(gs_command_context_t *ctx, int *ch, int timeout_ms); +} gs_command_io_functions_t; + + + +/** + Command context for executing a command. +*/ +struct command_context { + /** + Input (raw) command line, including arguments. + */ + const char * command_line; + + /** + Command being executed. + */ + const gs_command_t * command; + + /** + Number of arguments (standard argc style). + */ + int argc; + + /** + Argument array (standard argv style). + */ + char **argv; + + /** + FILE handle for capturing stdout from command. + */ + FILE* out; + + /** + getopt variable. + */ + int optind; + + /** + getopt variable. + */ + int optopt; + + /** + getopt variable. + */ + char *optarg; + + /** + getopt variable. + */ + int optsp; + + /** + Function interface for I/O operations + */ + const gs_command_io_functions_t *io_functions; + + /** + Pointer for storing the context used by the I/O functions + */ + void * io_ctx; +}; + +/** + Command logging call-back + + logs information on the command called. + @param[in] cmd_line command line string + @param[in] ret return code from command execution framework + @param[in] cmd_ret return code from the executed command + @param[in] start time_stamp when command execution started. + @param[in] end time_stamp when command execution completed. + @param[in] ctx context pointer for the logger. + @return_gs_error_t +*/ +typedef gs_error_t (*gs_command_log_t)(const char *cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t start, gs_timestamp_t end, void * ctx); + +/** + Command handler. +*/ +typedef int (*gs_command_handler_t)(gs_command_context_t * ctx); + +/** + Completer call-back (tab complete). + + @param[in] ctx command context. + @param[in] arg_to_complete argument to complete + @return #GS_OK Found at least 1 match. + The \a completer is expected to have completed more of the command line. + If the framework detects multiple matches, the framework will proceed as if #GS_ERROR_AMBIGUOUS was returned. + The framework doesn't expect anything to be printed to \a out, but will update/refresh the console line. + @return #GS_ERROR_AMBIGUOUS Ambiguous - multiple matches or force the framework to show help. + The \a completer may have extended/completed more of the command line. + The framework expects the \a completer to have printed to \a out, and will show help/usage for the command on a new line. + @return #GS_ERROR_NOT_FOUND (or others) No matches found or no more arguments to complete. + The framewrok doesn't expect anything to be printed to \a out, and will not update the console. +*/ +typedef gs_error_t (*gs_command_completer_t)(gs_command_context_t * ctx, int arg_to_complete); + +/** + Add token - helper to 'tab complete' argument(s). + + @param[in] ctx command context. + @param[in] token possible completion - the API will find the common part. + @param[in] exact \a true if \a token is an exact match - all other added tokens will be ignored. + @return number of tokens added. +*/ +unsigned int gs_command_completer_add_token(gs_command_context_t * ctx, const char * token, bool exact); + +/** + Chain element for chaning sub-commands. +*/ +typedef struct { + /** + Command list. + */ + const gs_command_t * list; + /** + Number of commands in the \a list. + */ + unsigned int count; +} gs_command_chain_t; + +/** + Signals no command arguments in command definition, see mandatory arguments. +*/ +#define GS_COMMAND_NO_ARGS 255 + +/** + Command definition. +*/ +struct command { +#if (__AVR__) + char name[GS_COMMAND_MAX_LEN_COMMAND]; + char help[50]; + char usage[50]; +#else + /** + Name. + */ + const char * const name; + /** + Help text. + */ + const char * const help; + /** + Usage text. + */ + const char * const usage; +#endif + /** + Command handler - the "actual command function". + */ + gs_command_handler_t handler; +#if (__AVR__ == 0) + /** + Completer function - helps completing an argument. + */ + gs_command_completer_t completer; +#endif + /** + Sub-command (if any). + */ + gs_command_chain_t chain; + /** + Mode/flags. + See #GS_COMMAND_FLAG_HIDDEN. + */ + unsigned int mode; + /** + Number of mandatory (minimum) arguments. + + @note Due to backwards compatibility, 0 (zero) cannot be used to signal no arguments - use #GS_COMMAND_NO_ARGS instead, if command doesn't take any arguments (mandatory or optional). + */ + uint8_t mandatory_args; + /** + Number of optional arguments. + */ + uint8_t optional_args; + /** + Filler for future use. + */ + uint8_t filler[2]; +}; + +/** + Returns the arguments as a string, where arguments are separated by spaces. + @param ctx command context. + @return Pointer to concatenated arguments +*/ +const char * gs_command_args(gs_command_context_t *ctx); + +/** + Execute command. + @deprecated Replaced by gs_command_execute & gs_command_execute_stdio + + Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return + result is stored in \a command_result. + + @param[in] command Command to execute, including arguments separated by spaces. + @param[out] command_result Result returned by \a command (if executed). Use \a NULL to ignore result. + @return #GS_ERROR_NOT_FOUND if command wasn't found. + @return #GS_ERROR_ARG if number of argumenets exceeds \a mandatory + \a optional count. + @return_gs_error_t +*/ +gs_error_t gs_command_run(const char * command, gs_error_t * command_result); + +/** + Execute command. + + Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return + result is stored in \a command_result. + + @param[in] command Command to execute, including arguments separated by spaces. + @param[out] command_result Result returned by \a command (if executed). Use \a NULL to ignore result. + @param[in] out output (FILE) stream + @param[in] iof Pointer to function interface of IO operations + @param[in] iof_ctx Pointer to context used by the IO function interface + @return #GS_ERROR_NOT_FOUND if command wasn't found. + @return #GS_ERROR_ARG if number of argumenets exceeds \a mandatory + \a optional count. + @return_gs_error_t +*/ +gs_error_t gs_command_execute(const char * command, gs_error_t * command_result, FILE *out, const gs_command_io_functions_t * iof, void * iof_ctx); + +/** + Execute command. + + Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return + result is stored in \a command_result. The results are printed on stdout and input captured on stdin. + + @param[in] command Command to execute, including arguments separated by spaces. + @param[out] command_result Result from command. Use \a NULL to ignore result. + @return #GS_OK if command was executed - result returned in \a command_result. Otherwise an error indicating why the command wasn't executed. +*/ +gs_error_t gs_command_execute_stdio(const char * command, gs_error_t * command_result); + +/** + Set output + + Sets output from command, using the io function struct in ctx. + + @param[in] ctx the command context + @param[in] group a string specifying the group of the result. Leave blank if not used. + @param[in] key a string specifying the key/name of the result variable. + @param[in] value a string representation of the result value. + @return_gs_error_t +*/ +gs_error_t gs_command_set_output(gs_command_context_t *ctx, const char* group, const char* key, const char* value); + +/** + Set output + + Sets output from command using printf formatting, using the io function struct in ctx. + + @param[in] ctx the command context + @param[in] group a string specifying the group of the result. Leave blank if not used. + @param[in] key a string specifying the key/name of the result variable. + @param[in] format printf syntax for formatting data + @return_gs_error_t +*/ +gs_error_t gs_command_set_output_printf(gs_command_context_t *ctx, const char* group, const char* key, const char * format, ...); + +/** + Flush output/Results + + Instruct the command output stream & results to be flushed from it's buffers. + + @param[in] ctx the command context + @return_gs_error_t +*/ +gs_error_t gs_command_flush_output(gs_command_context_t *ctx); + +/** + Wait for any key input + + Instruct the command input stream to wait for any key. + + @param[in] ctx the command context + @param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milliseconds. + @return true if command should proceed (either because of key press present or if no input stream available) +*/ +bool gs_command_wait_any_key(gs_command_context_t *ctx, int timeout_ms); + +/** + Wait for key input + + Instruct the io stream to wait for a key, and return the pressed key in ch. + + @param[in] ctx the command context + @param[out] ch the character that was read on the input stream + @param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milliseconds. + @return #GS_OK if key was read + @return #GS_ERROR_HANDLE if no input stream is present + @return #GS_ERROR_TIMEOUT on timeout. +*/ +gs_error_t gs_command_wait_key(gs_command_context_t *ctx, int* ch, int timeout_ms); + +/** + Register commands. + + gs_command_init() must be called prior to registering any commands. + + See #GS_COMMAND_ROOT for details. + + @param[in] cmds Pointer to command array + @param[in] cmd_count Number of commands in command array + @return_gs_error_t +*/ +gs_error_t gs_command_register(const gs_command_t * cmds, size_t cmd_count); + +/** + Initialize command system and register default commands. + + Registers following commands: gs_log_register_commands() and gs_command_register_default_commands(). + + @param[in] min_stack_size Minimum stack size required for executing commands. The stack size will be used by other sub-systems such as gs_console, g-script. Stack size may be ignored on some platforms, e.g. Linux. + @return_gs_error_t + @see gs_command_init_no_commands() +*/ +gs_error_t gs_command_init(size_t min_stack_size); + +/** + Initialize command system (without any default commands). + + @param[in] min_stack_size Minimum stack size required for executing commands. The stack size will be used by other sub-systems such as gs_console, g-script. Stack size may be ignored on some platforms, e.g. Linux. + @return_gs_error_t + @see gs_command_init() +*/ +gs_error_t gs_command_init_no_commands(size_t min_stack_size); + + +/** + Register a call-back used for logging of command execution. + + @param[in] log_cb the logging call back. + @param[in] log_ctx pointer to context data. Set to NULL if not used. + @return_gs_error_t +*/ +gs_error_t gs_command_register_logger(gs_command_log_t log_cb, void *log_ctx); + +/** + Default implementation of the command logger, that can be used if no other + custom command logger is provided by the system. + + @param[in] cmd_line command line string + @param[in] ret return code provided by the command execution function. + @param[in] cmd_ret return code provided by the executed command. + @param[in] t_start time stamp when command execution started. + @param[in] t_end time stamp when command execution completed. + @param[in] log_ctx context for the command logger. + @return_gs_error_t +*/ +gs_error_t gs_command_logger_default(const char* cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t t_start, gs_timestamp_t t_end, void * log_ctx); + +/** + Return minimum stack size. + @return minimm stack size required for executing commands. The minimum stack size is set by call to gs_command_init(). +*/ +size_t gs_command_get_stack_size(void); + +/** + Register set of default commands. + @return_gs_error_t +*/ +gs_error_t gs_command_register_default_commands(void); + +/** + Split line into argc/argv. + + @param[in] line line to split - the line will be chop up into argv. + @param[out] argc argc count. + @param[out] argv argv array. + @param[in] max_argc max argv elements. + @return \a true if successfull, else \a false. +*/ +bool gs_command_build_argv(char *line, int *argc, char **argv, int max_argc); + +/** + Parse options. + + Adapted from AT&T public domain source from: + http://www.informatica.co.cr/unix-source-code/research/1985/1103.html + + @param[in] ctx command context. + @param[in] opts options + @return option character +*/ +int gs_command_getopt(gs_command_context_t *ctx, const char *opts); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/gosh/console.h b/gomspace/libutil/include/gs/util/gosh/console.h new file mode 100644 index 00000000..e0c9c42a --- /dev/null +++ b/gomspace/libutil/include/gs/util/gosh/console.h @@ -0,0 +1,123 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +#ifndef GS_UTIL_GOSH_CONSOLE_H +#define GS_UTIL_GOSH_CONSOLE_H +/** + @file + + Console (stdin/stdout) interface for running commands. + + This assumes a VT102 terminal emulator, and tries to fix some of minicom's quirks with e.g. home/end keys. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Initialize the API and console. + + @deprecated version 3.4, use gs_console_start() + + @return_gs_error_t +*/ +gs_error_t gs_console_init(void); + +/** + Restores terminal settings (only relevant on Linux). + + @deprecated version 3.4, this is handled by an installed exit-handler in gs_console_start(). + + @return_gs_error_t +*/ +gs_error_t gs_console_exit(void); + +/** + Set console prompt. + + @param[in] prompt user prompt - the API only stores the pointer, so do not modify/delete content. NULL or empty string is ignored (no change). +*/ +void gs_console_set_prompt(const char * prompt); + +/** + Clear the console screen +*/ +void gs_console_clear(void); + +/** + Update console. +*/ +void gs_console_update(void); + +/** + Create console thread. + + The console thread reads from stdin and writes to stdout. + + The thread is created with low priority, #GS_THREAD_PRIORITY_LOW. + + @deprecated version 3.4, use gs_console_start() + + @param[out] handle handle to created thread - thread will be created joinable if supported by platform. Use NULL, if not wanted. + @return_gs_error_t +*/ +gs_error_t gs_console_create_thread(gs_thread_t * handle); + +/** + Create console thread with priority. + + The console thread reads from stdin and writes to stdout. + + @deprecated version 3.4, use gs_console_start() + + @param[in] priority thread priority, normally #GS_THREAD_PRIORITY_LOW. + @param[out] handle handle to created thread - thread will be created joinable if supported by platform. Use NULL, if not wanted. + @return_gs_error_t +*/ +gs_error_t gs_console_create_thread_with_priority(gs_thread_priority_t priority, gs_thread_t * handle); + +/** + @anchor GS_CONSOLE_F + @defgroup GS_CONSOLE_F Console flags. + Use with gs_console_start() to configure behaviour. + @{ +*/ +/** + Linux only: no signal handlers installed (e.g. to catch SIG_TERM). + @see gs_console_start() +*/ +#define GS_CONSOLE_F_NO_SIGNAL_HANDLER 0x0001 +/** @} */ + +/** + Start console thread (priority: #GS_THREAD_PRIORITY_LOW). + + The console thread reads from stdin and writes to stdout. The thread is created with low priority, #GS_THREAD_PRIORITY_LOW. + + Linux: Changes terminal settings and installs an atexit() handler to restore the settings, Signal handlers will be installed to catch SIG_TERM -> exit() and ignore SIG_INT (controlled by option on command line) - unless #GS_CONSOLE_F_NO_SIGNAL_HANDLER is specified. + + @param[in] prompt set console prompt by calling gs_console_set_prompt(). + @param[in] flags configure behaviour, see @ref GS_CONSOLE_F definitions. + @return #GS_ERROR_EXIST if console thread already created. + @return_gs_error_t +*/ +gs_error_t gs_console_start(const char * prompt, uint32_t flags); + +/** + Stop (and join with) console thread. + + @note This is only supported on Linux. + + The thread is interrupted using pthread_cancel(), which does not guarantee \a clean shutdown if the thread is busy executing a command. + + @return #GS_ERROR_NOT_SUPPORTED if not supported on current platform. + @return #GS_ERROR_HANDLE if no console has been started with gs_console_start(). + @return_gs_error_t +*/ +gs_error_t gs_console_stop(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/hexdump.h b/gomspace/libutil/include/gs/util/hexdump.h new file mode 100644 index 00000000..43a085e5 --- /dev/null +++ b/gomspace/libutil/include/gs/util/hexdump.h @@ -0,0 +1,53 @@ +#ifndef GS_UTIL_HEXDUMP_H +#define GS_UTIL_HEXDUMP_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Dump memory as hex numbers and ascii characters. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Dump memory to an output stream. + @param[in] src memory address. + @param[in] len number of bytes to dump. + @param[in] disp_addr display address, used instead of \a src. + @param[in] out output stream. +*/ +void gs_hexdump_to_stream(const void * src, size_t len, const void * disp_addr, FILE* out); + +/** + Dump memory on stdout. + + @param[in] src memory address. + @param[in] len number of bytes to dump. +*/ +static inline void gs_hexdump(const void *src, size_t len) +{ + gs_hexdump_to_stream(src, len, src, stdout); +} + +/** + Dump memory on stdout. + @param[in] src memory address. + @param[in] len number of bytes to dump. + @param[in] disp_addr display address, used instead of \a src. +*/ +static inline void gs_hexdump_addr(const void * src, size_t len, const void * disp_addr) +{ + gs_hexdump_to_stream(src, len, disp_addr, stdout); +} + +#ifdef __cplusplus +} +#endif +#endif + + diff --git a/gomspace/libutil/include/gs/util/linux/argp.h b/gomspace/libutil/include/gs/util/linux/argp.h new file mode 100644 index 00000000..b8eff835 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/argp.h @@ -0,0 +1,40 @@ +#ifndef GS_UTIL_LINUX_ARGP_H +#define GS_UTIL_LINUX_ARGP_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Extensions to GNU argp parser (convenience functions). +*/ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Wrapper for argp_parse. + + This function will call exit/terminate the process, if parsing fails. + + \a argv may be re-organized. + + @param[in] argp argp struct. + @param[in] argc argument count, i.e. standard argc. + @param[in] argv argument array, i.e. standard argv. + @param[in] flags future use. + @param[out] arg_index first unparsed option (-> argv modified). + @param[in] revision program revision, e.g. 3.0.1-12-g0cf1b59+. +*/ +void gs_argp_parse(const struct argp * argp, + int argc, char ** argv, + unsigned int flags, int * arg_index, + const char * revision); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/command_line.h b/gomspace/libutil/include/gs/util/linux/command_line.h new file mode 100644 index 00000000..d9dbc3a3 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/command_line.h @@ -0,0 +1,42 @@ +#ifndef GS_UTIL_LINUX_COMMAND_LINE_H +#define GS_UTIL_LINUX_COMMAND_LINE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Command line support. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Command line options for ignoring CTRL-C +*/ +extern const struct argp_child gs_console_command_line_ignore_ctrlc_argp; + +/** + Command line options for adding -h (help). +*/ +const struct argp_child gs_help_command_line_argp; + +/** + Return if ctrl-c ignored on command line. + @return \a true i ctrl-c ignored. +*/ +bool gs_command_line_ignore_ctrlc(void); + +/** + Return program name based on argv[0]. + @param[in] argv expected to be argv[0] amd point to the program name (possibly with full path). + @return program name. +*/ +const char * gs_command_line_program_name(const char * argv); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/can/can.h b/gomspace/libutil/include/gs/util/linux/drivers/can/can.h new file mode 100644 index 00000000..f04b3f83 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/drivers/can/can.h @@ -0,0 +1,29 @@ +#ifndef GS_UTIL_LINUX_DRIVERS_CAN_CAN_H +#define GS_UTIL_LINUX_DRIVERS_CAN_CAN_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Linux CAN interface. + + @note Only 1 filter/mask can be set, using gs_can_set_standard_filter_mask() or gs_can_set_extended_filter_mask() +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Open and initialize a CAN handle. + @param[in] ifname name of CAN interface. + @param[out] handle opened CAN handle. + @return_gs_error_t +*/ +gs_error_t gs_can_open(const char * ifname, int * handle); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h new file mode 100644 index 00000000..f04cc1f5 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h @@ -0,0 +1,146 @@ +#ifndef GS_UTIL_LINUX_DRIVERS_GPIO_H +#define GS_UTIL_LINUX_DRIVERS_GPIO_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + @brief GPIO interface + + GPIO interface provides a generic interface where specific GPIO drivers can be plugged in. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + GomSpace linux driver GPIO get value + + @param[in] gpio The gpio to read + @param[in] value Returned GPIO value (true/false = High/Low) + @param[in] driver_data data to specific driver + + @return_gs_error_t +*/ +typedef gs_error_t (*gs_gpio_get_t)(gs_gpio_t gpio, bool *value, void * driver_data); + +/** + GomSpace linux driver GPIO get value without error check + + @param[in] gpio The gpio to read + @param[in] driver_data data to specific driver + + @return GPIO value (true/false = High/Low) +*/ +typedef bool (*gs_gpio_get_nc_t)(gs_gpio_t gpio, void * driver_data); + +/** + GomSpace linux driver GPIO set value + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @param[in] driver_data data to specific driver + + @return_gs_error_t +*/ +typedef gs_error_t (*gs_gpio_set_t)(gs_gpio_t gpio, bool value, void * driver_data); + +/** + GomSpace linux driver GPIO set value without error check + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @param[in] driver_data data to specific driver +*/ +typedef void (*gs_gpio_set_nc_t)(gs_gpio_t gpio, bool value, void * driver_data); + +/** + GomSpace linux driver initialize GPIO as an external interrupt pin + + @param[in] gpio The gpio to configure + @param[in] conf Configuration of interrupt pin + @param[in] driver_data data to specific driver + + @return_gs_error_t + */ +typedef gs_error_t (*gs_gpio_init_as_interrupt_t)(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data); + + +/** + Every port. + */ +#define GS_GPIO_ALL_PORTS UINT16_MAX + +/** + Every pin. + */ +#define GS_GPIO_ALL_PINS UINT16_MAX + +/** + GPIO driver. + */ +typedef struct { + /** + Function for handling GPIO get. + */ + gs_gpio_get_t get_handler; + /** + Function for handling GPIO get no check. + */ + gs_gpio_get_nc_t get_nc_handler; + /** + Function for handling GPIO set. + */ + gs_gpio_set_t set_handler; + /** + Function for handling GPIO set no check. + */ + gs_gpio_set_nc_t set_nc_handler; + /** + Function for handling GPIO initialize as interrupt. + */ + gs_gpio_init_as_interrupt_t init_as_interrupt_handler; +} gs_gpio_driver_t; + + +/** + GPIO driver entry + */ +typedef struct { + /** + GPIO port, to which the driver is used (if GS_GPIO_ALL_PORTS, then all ports uses this driver). + */ + uint16_t port; + /** + GPIO pin, to which the driver is used (if GS_GPIO_ALL_PINS, then all pins uses this driver). + */ + uint16_t pin; + /** + GPIO driver. + */ + const gs_gpio_driver_t * driver; + /** + Driver specific data. + */ + void * driver_data; +} gs_gpio_driver_entry_t; + +/** + Register a driver. + + A specific driver can be assigned to a port and pin or it can be assigned to all pins and/or all ports. + + The latest registered driver, which fit the GPIO, is the one used. + + @param[in] driver_entry driver and configuration to be registered + @return_gs_error_t + */ +gs_error_t gs_gpio_register_driver(const gs_gpio_driver_entry_t * driver_entry); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h new file mode 100644 index 00000000..0f95e5aa --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h @@ -0,0 +1,91 @@ +#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_SYSFS_H_ +#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_SYSFS_H_ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + @brief Linux GPIO driver based on sysfs. + This driver needs to be registered in the generic GPIO linux driver @see 'gs/util/linux/drivers/gpio/gpio.h' +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + GPIO sysfs driver data. + + @note Driver takes no driver data, so a NULL pointer is valid +*/ +typedef void * gs_gpio_sysfs_driver_data_t; + +/** + GPIO sysfs driver interface. +*/ +extern const gs_gpio_driver_t gs_gpio_sysfs_driver; + +/** + GPIO sysfs initialize + + @param[in] gpio The gpio to initialize + @param[in] output Direction of pin (True/False = Output/Input) + @param[in] init_value Pin state if configured as output (True/False = High/Low) + @param[in] active_low if set pin is configured as active low (so a gs_gpio_sysfs_set with 1 will actually set value low) + @return_gs_error_t + */ +gs_error_t gs_gpio_sysfs_initialize(gs_gpio_t gpio, bool output, bool init_value, bool active_low); + +/** + GPIO sysfs get value + + @param[in] gpio The gpio to read + @param[in] value Returned GPIO value (true/false = High/Low) + @param[in] driver_data data to driver (not used) + @return_gs_error_t +*/ +gs_error_t gs_gpio_sysfs_get(gs_gpio_t gpio, bool *value, void * driver_data); + +/** + GPIO sysfs get value without error check + + @param[in] gpio The gpio to read + @param[in] driver_data data to driver (not used) + @return GPIO value (true/false = High/Low) +*/ +bool gs_gpio_sysfs_get_nc(gs_gpio_t gpio, void * driver_data); + +/** + GPIO sysfs set value + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @param[in] driver_data data to driver (not used) + @return_gs_error_t +*/ +gs_error_t gs_gpio_sysfs_set(gs_gpio_t gpio, bool value, void * driver_data); + +/** + GPIO sysfs set value without error check + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @param[in] driver_data data to driver (not used) +*/ +void gs_gpio_sysfs_set_nc(gs_gpio_t gpio, bool value, void * driver_data); + +/** + Initialize GPIO sysfs as an external interrupt pin + + @param[in] gpio The gpio to configure + @param[in] conf Configuration of interrupt pin + @param[in] driver_data data to driver (not used) + @return_gs_error_t + */ +gs_error_t gs_gpio_sysfs_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h new file mode 100644 index 00000000..e61b70a4 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h @@ -0,0 +1,125 @@ +#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_VIRTUAL_H_ +#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_VIRTUAL_H_ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + @brief Linux GPIO driver to be used in unit tests. + This driver needs to be registered in the generic GPIO linux driver @see 'gs/util/linux/drivers/gpio/gpio.h' +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + GPIO virtual driver data. + + @note Driver takes no driver data, so a NULL pointer is valid +*/ +typedef void * gs_gpio_virtual_driver_data_t; + +/** + GPIO virtual driver interface. +*/ +extern const gs_gpio_driver_t gs_gpio_virtual_driver; + +/** + GPIO virtual driver entry, where all ports and pins are routed to virtual driver + */ +extern const gs_gpio_driver_entry_t gs_gpio_virtual_driver_entry_all; + +/** + GPIO virtual initialize + + @param[in] gpio The gpio to initialize + @param[in] output Direction of pin (True/False = Output/Input) + @param[in] value Pin state if configured as output (True/False = High/Low) + @return_gs_error_t + */ +gs_error_t gs_gpio_virtual_initialize(gs_gpio_t gpio, bool output, bool value); + +/** + GPIO virtual get value + + @param[in] gpio The gpio to read + @param[in] value Returned GPIO value (true/false = High/Low) + @param[in] driver_data data to driver (not used) + @return_gs_error_t +*/ +gs_error_t gs_gpio_virtual_get(gs_gpio_t gpio, bool *value, void * driver_data); + +/** + GPIO virtual get value without error check + + @param[in] gpio The gpio to read + @param[in] driver_data data to driver (not used) + @return GPIO value (true/false = High/Low) +*/ +bool gs_gpio_virtual_get_nc(gs_gpio_t gpio, void * driver_data); + +/** + GPIO virtual set value + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @param[in] driver_data data to driver (not used) + @return_gs_error_t +*/ +gs_error_t gs_gpio_virtual_set(gs_gpio_t gpio, bool value, void * driver_data); + +/** + GPIO virtual set value without error check + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @param[in] driver_data data to driver (not used) +*/ +void gs_gpio_virtual_set_nc(gs_gpio_t gpio, bool value, void * driver_data); + +/** + Initialize GPIO virtual as an external interrupt pin + + @param[in] gpio The gpio to configure + @param[in] conf Configuration of interrupt pin + @param[in] driver_data data to driver (not used) + @return_gs_error_t + */ +gs_error_t gs_gpio_virtual_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data); + +/** + Force set a pin + + This sets a pin regardless if it is configured as input, output or interrupt + If the pin is configured as interrupt, the registered ISR's will be called within this function, + if the transition matches (rising/falling) + + @note This function is specific to this driver and is should not be registered. + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @return_gs_error_t + */ +gs_error_t gs_gpio_virtual_force_set(gs_gpio_t gpio, bool value); + +/** + Get transitions + + This gives the number of transitions ((high -> low) + (low -> high)), + since last time this function was called at this pin. This function resets the counter of the pin. + An even number means, that the pin has the same state as it was initialized to. + + @note This function is specific to this driver and should not be registered + + @param[in] gpio The gpio, of which transitions are given + @param[out] transitions Number of transitions + @return + */ +gs_error_t gs_gpio_virtual_get_transistions(gs_gpio_t gpio, uint32_t * transitions); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h b/gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h new file mode 100644 index 00000000..858c26a2 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h @@ -0,0 +1,198 @@ +#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_I2C_I2C_H_ +#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_I2C_I2C_H_ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + @brief Linux I2C plugin driver +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + GomSpace linux driver I2C master transaction. + + @see 'gs/util/drivers/i2c/master.h' + + @param[in] device I2C device + @param[in] addr I2C address + @param[in] tx tx buffer + @param[in] txlen bytes to be sent + @param[out] rx rx buffer + @param[in] rxlen bytes to be received + @param[in] timeout_ms timeout in milliseconds + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (* gs_i2c_master_transaction_t)(uint8_t device, uint8_t addr, const void * tx, size_t txlen, + void * rx, size_t rxlen, int timeout_ms, void * driver_data); + +/** + GomSpace linux driver I2C slave start. + + @see 'gs/util/drivers/i2c/slave.h' + + @param[in] device I2C device + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (* gs_i2c_slave_start_t)(uint8_t device, void * driver_data); + +/** + GomSpace linux driver I2C set rx callback + + @see 'gs/util/drivers/i2c/slave.h' + + @param[in] device I2C device + @param[in] rx rx callback + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (* gs_i2c_slave_set_rx_t)(uint8_t device, gs_i2c_slave_receive_t rx, void * driver_data); + +/** + GomSpace linux driver I2C slave set 'get_rx_buffer' callback. + + @see 'gs/util/drivers/i2c/slave.h' + + @param[in] device I2C device + @param[in] get_rx_buf get_rx_buf callback + @param[in] buf_length length of buffer received by calling callback + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (* gs_i2c_slave_set_get_rx_buf_t)(uint8_t device, gs_i2c_slave_get_rx_buf_t get_rx_buf, size_t buf_length, void * driver_data); + +/** + GomSpace linux driver I2C slave set slave response. + + @see 'gs/util/drivers/i2c/slave.h' + + @param[in] device I2C device + @param[in] tx tx buffer + @param[in] tx_length bytes to be send + @param[in] driver_data data to specific driver + @return_gs_error_t +*/ +typedef gs_error_t (* gs_i2c_slave_set_response_t)(uint8_t device, const uint8_t * tx, size_t tx_length, void * driver_data); + +/** + Every I2C device ([0 : 254]). + */ +#define GS_I2C_ALL_DEVICES 255 + +/** + Every I2C address (0 : 127]). + */ +#define GS_I2C_ALL_ADDR 255 + +/** + I2C master driver. + */ +typedef struct { + /** + Function for handling master transactions. + */ + gs_i2c_master_transaction_t master_transaction_handler; +} gs_i2c_master_driver_t; + + +/** + I2C master driver entry + */ +typedef struct { + /** + I2C device, to which the driver is used (if GS_I2C_ALL_DEVICES, then all devices uses this driver). + */ + uint8_t device; + /** + I2C addr, to which the driver is used (if GS_I2C_ALL_ADDR, then all addr on given device uses this driver). + */ + uint8_t addr; + /** + I2C master driver. + */ + const gs_i2c_master_driver_t * driver; + /** + Driver specific data. + */ + void * driver_data; +} gs_i2c_master_driver_entry_t; + + +/** + I2C slave driver + */ +typedef struct { + /** + Function for handling slave start. + */ + gs_i2c_slave_start_t start_handler; + /** + Function for handling the 'setting of rx callback'. + */ + gs_i2c_slave_set_rx_t set_rx_handler; + /** + Function for handling setting of an 'rx buff get' function. + */ + gs_i2c_slave_set_get_rx_buf_t set_get_rx_buf_handler; + /** + Function for handling 'set response'. + */ + gs_i2c_slave_set_response_t set_response_handler; +} gs_i2c_slave_driver_t; + + +/** + I2C slave driver entry. + */ +typedef struct { + /** + I2C device, to which the driver is used (if GS_I2C_ALL_DEVICES, then all devices uses this driver). + */ + uint8_t device; + /** + I2C slave driver. + */ + const gs_i2c_slave_driver_t * driver; + /** + Driver specific data. + */ + void * driver_data; +} gs_i2c_slave_driver_entry_t; + + +/** + Register a master driver. + + A specific driver can be assigned to a specific address and device + or it can be registered to every address on a device or every address on every device. + + The latest registered driver, which fit the device an address, is the one used. + + @param[in] driver_entry driver and configuration to be registered + @return_gs_error_t + */ +gs_error_t gs_i2c_master_register_driver(const gs_i2c_master_driver_entry_t * driver_entry); + +/** + Register a slave driver + + A specific driver can be assigned to a specific device or a driver can be assigned to every device. + + The latest registered driver, which fit the device, is the one used. + + @param[in] driver_entry driver and configuration to be registered + @return_gs_error_t + */ +gs_error_t gs_i2c_slave_register_driver(const gs_i2c_slave_driver_entry_t * driver_entry); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h b/gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h new file mode 100644 index 00000000..24e5ae22 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h @@ -0,0 +1,175 @@ +#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_SPI_SPI_H_ +#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_SPI_SPI_H_ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Linux SPI plugin driver +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Linux driver SPI master transactions. + + @see 'gs/util/drivers/spi/master.h' + + @param[in] slave SPI slave + @param[in] trans Pointer to transactions + @param[in] count Number of transactions (rx and/or tx) to complete + @param[in] timeout_ms timeout in milliseconds, primarily for locking the SPI device. + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (*gs_spi_master_transactions_t)(uint8_t slave, gs_spi_master_trans_t *trans, size_t count, + int timeout_ms, void * driver_data); + +/** + Linux driver SPI slave start. + + @see 'gs/util/drivers/spi/slave.h' + + @param[in] device SPI device (handle) + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (* gs_spi_slave_start_t)(uint8_t device, void * driver_data); + +/** + Linux driver SPI set rx callback + + @see 'gs/util/drivers/spi/slave.h' + + @param[in] device SPI device (handle). + @param[in] rx Rx callback. + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (* gs_spi_slave_set_rx_t)(uint8_t device, gs_spi_slave_receive_t rx, void * driver_data); + +/** + Linux driver SPI slave set slave response. + + @see 'gs/util/drivers/spi/slave.h' + + @param[in] device SPI device (handle). + @param[in] offset offset (in bytes) for the response, counted from start of request, i.e. offset of 2 means data will be sent as the 3rd byte. + @param[in] tx pointer to data. NOTE: data is not copied due to performance, so data must stay valid until the response has been sent. + @param[in] size size of data. + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (* gs_spi_slave_set_response_t)(uint8_t device, size_t offset, const uint8_t * tx, size_t size, void * driver_data); + +/** + Every SPI slave ([0 : 254]). + */ +#define GS_SPI_ALL_SLAVES 255 + +/** + Every SPI device (0 : 254]). + */ +#define GS_SPI_ALL_DEVICES 255 + + +/** + SPI master driver. + */ +typedef struct { + /** + Function for handling master transactions. + */ + gs_spi_master_transactions_t master_transactions_handler; +} gs_spi_master_driver_t; + + +/** + SPI master driver entry + */ +typedef struct { + /** + SPI slave, to which the driver is used (if #GS_SPI_ALL_SLAVES, then all slaves uses this driver). + */ + uint8_t slave; + /** + SPI master driver. + */ + const gs_spi_master_driver_t * driver; + /** + Driver specific data. + */ + void * driver_data; +} gs_spi_master_driver_entry_t; + + +/** + SPI slave driver + */ +typedef struct { + /** + Function for handling slave start. + */ + gs_spi_slave_start_t start_handler; + /** + Function for handling the 'setting of rx callback'. + */ + gs_spi_slave_set_rx_t set_rx_handler; + /** + Function for handling 'set response'. + */ + gs_spi_slave_set_response_t set_response_handler; +} gs_spi_slave_driver_t; + + +/** + SPI slave driver entry. + */ +typedef struct { + /** + SPI device, to which the driver is used (if #GS_SPI_ALL_DEVICES, then all devices uses this driver). + */ + uint8_t device; + /** + SPI slave driver. + */ + const gs_spi_slave_driver_t * driver; + /** + Driver specific data. + */ + void * driver_data; +} gs_spi_slave_driver_entry_t; + + +/** + Register a master driver. + + A specific driver can be assigned to a slave or it can be assigned to every slave. + + The latest registered driver, which fit the slave, is the one used. + + @param[in] driver_entry driver and configuration to be registered + @return_gs_error_t + */ +gs_error_t gs_spi_master_register_driver(const gs_spi_master_driver_entry_t * driver_entry); + +/** + Register a slave driver + + A specific driver can be assigned to a specific device or a driver can be assigned to every device. + + The latest registered driver, which fit the device, is the one used. + + @param[in] driver_entry driver and configuration to be registered + @return_gs_error_t + */ +gs_error_t gs_spi_slave_register_driver(const gs_spi_slave_driver_entry_t * driver_entry); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/exitcode.h b/gomspace/libutil/include/gs/util/linux/exitcode.h new file mode 100644 index 00000000..35e89f06 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/exitcode.h @@ -0,0 +1,40 @@ +#ifndef GS_UTIL_LINUX_EXITCODE_H +#define GS_UTIL_LINUX_EXITCODE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + "standard" Linux exit codes. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Program completed ok (from stdlib.h) +*/ +#define GS_EXITCODE_OK EXIT_SUCCESS + +/** + Program terminated due to an error (from stdlib.h). +*/ +#define GS_EXITCODE_ERROR EXIT_FAILURE + +/** + Program terminated due to invalid usage, eg argument (from sysexits.h). +*/ +#define GS_EXITCODE_USAGE EX_USAGE + +/** + Program terminated due to a signal (from [TLDP](http://www.tldp.org/LDP/abs/html/exitcodes.html)). +*/ +#define GS_EXITCODE_SIGNAL(sig) (128 + sig) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/function.h b/gomspace/libutil/include/gs/util/linux/function.h new file mode 100644 index 00000000..b918993d --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/function.h @@ -0,0 +1,49 @@ +#ifndef GS_UTIL_LINUX_FUNCTION_H +#define GS_UTIL_LINUX_FUNCTION_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Function interface - invokes a function by name. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Function prototype. + @param[in] arg argument provided to gs_function_invoke(). + @return_gs_error_t +*/ +typedef gs_error_t (*gs_function_t)(void * arg); + +/** + Register \a function by name. + + @param[in] short_name short name for function, used by gs_function_invoke() to find function to invoke. + @param[in] long_name long name (unique) for function, used by gs_function_invoke() to find function to invoke. + @param[in] function function to be invoked by gs_function_invoke() + @return #GS_ERROR_FULL if registry is full. + @return_gs_error_t +*/ +gs_error_t gs_function_register(const char * short_name, const char * long_name, gs_function_t function); + +/** + Invoke \a function by name. + + The return value is from the registered function, except for #GS_ERROR_NOT_IMPLEMENTED. + + @param[in] name registered function name. + @param[in] arg argument for function. + @return #GS_ERROR_NOT_IMPLEMENTED if the \a name isn't found. + @return_gs_error_t +*/ +gs_error_t gs_function_invoke(const char * name, void * arg); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/rtc.h b/gomspace/libutil/include/gs/util/linux/rtc.h new file mode 100644 index 00000000..fa063f76 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/rtc.h @@ -0,0 +1,28 @@ +#ifndef GS_UTIL_LINUX_RTC_H +#define GS_UTIL_LINUX_RTC_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Real Time Clock interface (linux). +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Register Real Time Clock interface. + @note Setting the RTC will normally require special permission. + @param[in] get if true, get will be registered. + @param[in] set if true, set will be registered. + @return_gs_error_t +*/ +gs_error_t gs_rtc_register_linux(bool get, bool set); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/signal.h b/gomspace/libutil/include/gs/util/linux/signal.h new file mode 100644 index 00000000..b3c280e7 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/signal.h @@ -0,0 +1,40 @@ +#ifndef GS_UTIL_LINUX_SIGNAL_H +#define GS_UTIL_LINUX_SIGNAL_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Signal helpers - catch and ignore. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Standard Linux signal handler. +*/ +typedef void (*gs_signal_handler)(int signal, siginfo_t *si, void *context); + +/** + Register/catch signal and invoke handler. + @param[in] signal signal to catch. + @param[in] handler signal handler. If \a handler is NULL, a default handler will be invoked, which calls exit(#GS_EXITCODE_SIGNAL + signal). + @return_gs_error_t +*/ +gs_error_t gs_signal_catch(int signal, gs_signal_handler handler); + +/** + Ignore signal + @param[in] signal signal to ignore. + @return_gs_error_t +*/ +gs_error_t gs_signal_ignore(int signal); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/sysfs_helper.h b/gomspace/libutil/include/gs/util/linux/sysfs_helper.h new file mode 100644 index 00000000..ad05a6fe --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/sysfs_helper.h @@ -0,0 +1,30 @@ +#ifndef GS_UTIL_SYSFS_HELPER_H +#define GS_UTIL_SYSFS_HELPER_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Sysfs interface. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Sysfs write (GPIO). +*/ +gs_error_t gs_sysfs_write_file(const char *path, const char *value); + +/** + Sysfs read (GPIO). +*/ +gs_error_t gs_sysfs_read_file(const char *path, char *value, size_t len); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/log.h b/gomspace/libutil/include/gs/util/log.h new file mode 100644 index 00000000..13659adf --- /dev/null +++ b/gomspace/libutil/include/gs/util/log.h @@ -0,0 +1,15 @@ +#ifndef GS_UTIL_LOG_H +#define GS_UTIL_LOG_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Log interface. + + The log interface supports logging to different group. + + Logging is done through groups (domains), which can runtime be re-configured with level. +*/ +#include + +#endif diff --git a/gomspace/libutil/include/gs/util/log/appender/appender.h b/gomspace/libutil/include/gs/util/log/appender/appender.h new file mode 100644 index 00000000..29a0c140 --- /dev/null +++ b/gomspace/libutil/include/gs/util/log/appender/appender.h @@ -0,0 +1,189 @@ +#ifndef GS_UTIL_LOG_APPENDER_APPENDER_H +#define GS_UTIL_LOG_APPENDER_APPENDER_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Log Appender interface. + + The log appender interface supports logging to different "stores". + Logging is done through groups, which can be registered to different log appenders. + Each log appender has it's own filter (level mask). + Examples of log appenders could be: console, file, vmem, ... +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + Log appender (forward declaration) + All log groups log to one or more appenders. The Log appender is responsible + for putting the actual log data to a store/console or some other log medium. +*/ +typedef struct gs_log_appender gs_log_appender_t; + +/** + Log appender record iterator callback function + + @param[in] ctx context data for iterator. + @param[in] level log level of record being iterated + @param[in] ts timestamp of record being iterated + @param[in] group group string (zero terminated) of record being iterated + @param[in] msg message string (zero terminated) of record being iterated + @return true/false: Return false to discontinue iteration. +*/ +typedef bool (*gs_log_record_iterator_t)(void *ctx, gs_log_level_t level, const gs_timestamp_t *ts, const char *group, const char *msg); + +/** + Log appender driver interface +*/ +typedef struct { + /** appender init function */ + gs_error_t (*init)(gs_log_appender_t *appender); + /** appender function */ + void (*append)(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va); + /** appender function for isr context */ + void (*append_isr)(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va); + /** appender function for getting appender details string */ + void (*info)(gs_log_appender_t *appender, char * info_str, uint8_t str_size); + /** appender function for iterating stored appenders log history */ + void (*hist)(gs_log_appender_t *appender, void * ctx, gs_log_record_iterator_t iter); + /** appender function for clearing it's log history */ + void (*clear)(gs_log_appender_t *appender); + /** appender function for flushing cached log entries to it's store. + This is only relevant for appenders implementing a log cache. */ + void (*flush)(gs_log_appender_t *appender); +} gs_log_appender_driver_t; + +/** + Log appender + All log groups log to one or more appenders. The Log appender is responsible + for putting the actual log data to a store/console or some other log medium. +*/ +struct gs_log_appender { + /** Name of the appender */ + const char * name; + /** appender driver interface */ + const gs_log_appender_driver_t * drv; + /** appender driver configuration data */ + const void * drv_config; + /** appender driver data - dynamic/internal data */ + void * drv_data; + /** appender level mask */ + uint8_t mask; +}; + +/** + Register an appender for the given log group. + All logging, where the mask matches the groups \a level_mask, will be forwarded to this appender. + + @param[in] group_name Name of the group. + @param[in] appender_name Name of appender to register for this group. + @return gs_error_t +*/ +gs_error_t gs_log_group_register_appender(const char * group_name, const char * appender_name); + +/** + Log appender iterator callback function + + @param[in] ctx context data for iterator. + @param[in] appender log appender being iterated + + @return true/false: Return false to discontinue iteration. +*/ +typedef bool (*gs_log_appender_iterator_t)(void *ctx, gs_log_appender_t * appender); + +/** + Iterate all or specific log appender(s). + + @param[in] name name of log appender, or NULL/\"all\" for all groups. + @param[in] ctx user context data. + @param[in] iter iterator, return \a true to continue, \a false to break iteration. + @return_gs_error_t +*/ +gs_error_t gs_log_appender_iterate(const char * name, void * ctx, gs_log_appender_iterator_t iter); + +/** + Iterate registered appenders for a specific group. + + @param[in] group log group to iterate appenders on. + @param[in] ctx user context data. + @param[in] iter appender iterator, return \a true to continue, \a false to break iteration. + @return gs_error_t +*/ +gs_error_t gs_log_group_appender_iterate(gs_log_group_t * group, void * ctx, gs_log_appender_iterator_t iter); + +/** + Register log appender. + + The log appender will be registered and initialized (if the appender has en init function, see #gs_log_appender_driver_t) + + The appender will not be attached to any log groups. For registering an appender to a group, use gs_log_group_register_appender() + + @param[in] appender appender - must stay in memory during the life-time of the application + @return_gs_error_t +*/ +gs_error_t gs_log_appender_register(gs_log_appender_t *appender); + +/** + Add log appender(s). + + The log appender will be registered and initialized (if the appender has en init function, see #gs_log_appender_driver_t) + + The appender will not be attached to any log groups. For registering an appender to a group, use gs_log_group_register_appender() + + @deprecated impossible to determine which appender fails, use gs_log_appender_register() + @param[in] appenders array of appender(s) - must stay in memory during the life-time of the application + @param[in] count array count - number of appenders. + @return_gs_error_t +*/ +gs_error_t gs_log_appender_add(gs_log_appender_t *appenders, uint16_t count); + +/** + Set log appender level mask. + + @param[in] appender_name log appender name + @param[in] mask level mask to set. + @return_gs_error_t +*/ +gs_error_t gs_log_appender_set_level_mask(const char * appender_name, uint8_t mask); + +/** + Get log appender level mask. + + @param[in] appender_name log appender name + @param[out] mask returned current level mask. + @return_gs_error_t +*/ +gs_error_t gs_log_appender_get_level_mask(const char * appender_name, uint8_t *mask); + +/** + Iterate log history for all or specific log appender. + + @param[in] name name of log appender, or NULL/\"all\" for all appenders. + @param[in] ctx user context data for iterator. + @param[in] iter iterator, return \a true to continue, \a false to break iteration. + @return gs_error_t +*/ +gs_error_t gs_log_appender_history_iterate(const char * name, void * ctx, gs_log_record_iterator_t iter); + +/** + Flush all log appenders data to storage. + + This will call the flush API (if implemented) for all log appenders + available on the system. This should be called on regular basis from + a system thread to ensure all cached data is correctly flushed to their + stores. + + @return gs_error_t +*/ +gs_error_t gs_log_appender_flush_all(); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/log/appender/console.h b/gomspace/libutil/include/gs/util/log/appender/console.h new file mode 100644 index 00000000..37f63fc5 --- /dev/null +++ b/gomspace/libutil/include/gs/util/log/appender/console.h @@ -0,0 +1,57 @@ +#ifndef GS_UTIL_LOG_APPENDER_CONSOLE_H +#define GS_UTIL_LOG_APPENDER_CONSOLE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Console log appender - logs to stdout. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Log appender for console + + This log appender is the standard appender which is always available + on any system. The appender should be registered to the root group, + in order to get console/stdio logs. +*/ +extern gs_log_appender_t gs_log_appender_console; + +/** + Log appender for console callback type + + This callback function can be used for registering a user defined logger function if + the default can not be used for the given system. + + @param[in] appender pointer to the console appender. + @param[in] level log level for log message + @param[in] group log group for log message + @param[in] ts timestamp for log message + @param[in] format format of message in printf style + @param[in] va variable argument list in printf style + + @return void +*/ +typedef void (*gs_log_appender_console_cb_t)(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va); + +/** + Set Log appender for console callback + + When set, the given callback is called instead of the default console log function. + To revert back to the default console log function, call this function with NULL as parameter. + + @param[in] cb callback to use for console logging. + + @return gs_error_t +*/ +gs_error_t gs_log_appender_console_set_cb(gs_log_appender_console_cb_t cb); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/log/appender/simple_file.h b/gomspace/libutil/include/gs/util/log/appender/simple_file.h new file mode 100644 index 00000000..ab2537a6 --- /dev/null +++ b/gomspace/libutil/include/gs/util/log/appender/simple_file.h @@ -0,0 +1,41 @@ +#ifndef GS_UTIL_LOG_APPENDER_SIMPLE_FILE_H +#define GS_UTIL_LOG_APPENDER_SIMPLE_FILE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Simple log-file appender. +*/ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Simple File Log Appender driver configuration +*/ +typedef struct gs_log_appender_simple_file_config { + /** + Name of file to create/write logs to + */ + const char *filename; + /** + Truncate the file, when opening the log file. + */ + bool truncate; + /** + Uee local time stamps when logging to log file, otherwise UTC. + */ + bool use_local_time; +} gs_log_appender_simple_file_config_t; + +/** + Log appender for file. +*/ +extern const gs_log_appender_driver_t gs_log_appender_simple_file_driver; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/log/log.h b/gomspace/libutil/include/gs/util/log/log.h new file mode 100644 index 00000000..53470a75 --- /dev/null +++ b/gomspace/libutil/include/gs/util/log/log.h @@ -0,0 +1,853 @@ +#ifndef GS_UTIL_LOG_LOG_H +#define GS_UTIL_LOG_LOG_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Log interface. + + Logging is done through groups (domains), where the level mask can be changed runtime. +*/ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Name of the root log group +*/ +#define GS_LOG_GROUP_ROOT "root" + +/** + Log levels. + + The levels can easily be mapped to standard syslog severity levels (https://en.wikipedia.org/wiki/Syslog). +*/ +typedef enum { + /** + Trace (more detailed than \a debug). + + syslog: maps to \a debug (or \a trace if supported). + */ + GS_LOG_TRACE = 0, + /** + Debug. + + syslog: maps to \a debug. + */ + GS_LOG_DEBUG = 1, + /** + Informational. + + syslog: maps to \a informational. + */ + GS_LOG_INFO = 2, + /** + Normal but significant conditions. + + syslog: maps to \a notice. + */ + GS_LOG_NOTICE = 3, + /** + Warning. + + syslog: maps to \a warning. + */ + GS_LOG_WARNING = 4, + /** + Error. + + syslog: maps to \a error. + */ + GS_LOG_ERROR = 5, + + /** + Trace (more detailed than \a debug). + @deprecated use #GS_LOG_TRACE + */ + LOG_TRACE = GS_LOG_TRACE, + /** + Debug. + @deprecated use #GS_LOG_DEBUG + */ + LOG_DEBUG = GS_LOG_DEBUG, + /** + Informational. + @deprecated use #GS_LOG_INFO + */ + LOG_INFO = GS_LOG_INFO, + /** + Normal but significant conditions. + @deprecated use #GS_LOG_NOTICE + */ + LOG_NOTICE = GS_LOG_NOTICE, + /** + Warning. + @deprecated use #GS_LOG_WARNING + */ + LOG_WARNING = GS_LOG_WARNING, + /** + Error. + @deprecated use #GS_LOG_ERROR + */ + LOG_ERROR = GS_LOG_ERROR, +} gs_log_level_t; + +/** + Log categories. + + The category is a way of grouping information about which sub-systems have logged. It is primarily used in the \a + telemetry table, to indicate what sub-systems have logged an \a error or \a warning - indicating a possible problem. + + Up to 32 categories are supported (stored in a uint32). + + Categories should be unique within a single node. However, nothing happens if categories clashes - it will only be more difficult to determine what part of the system logged. + + Standard categories are defined from #GS_LOG_CAT_1 and up. Products or mission specific software should start from #GS_LOG_CAT_32 and down. +*/ +typedef enum { + //! Standard, used for #GS_LOG_CAT_DEFAULT + GS_LOG_CAT_1 = 1 << 0, + //! Standard, used for #GS_LOG_CAT_DRIVER + GS_LOG_CAT_2 = 1 << 1, + //! Standard, used for #GS_LOG_CAT_CSP + GS_LOG_CAT_3 = 1 << 2, + //! Standard, used for #GS_LOG_CAT_PARAM + GS_LOG_CAT_4 = 1 << 3, + //! Standard, used for #GS_LOG_CAT_FILE_SYSTEM + GS_LOG_CAT_5 = 1 << 4, + //! Standard, used for #GS_LOG_CAT_COMMAND + GS_LOG_CAT_6 = 1 << 5, + //! Standard, used for #GS_LOG_CAT_HK + GS_LOG_CAT_7 = 1 << 6, + //! Standard, used for #GS_LOG_CAT_FP + GS_LOG_CAT_8 = 1 << 7, + //! Standard, used for #GS_LOG_CAT_ADCS + GS_LOG_CAT_9 = 1 << 8, + GS_LOG_CAT_10 = 1 << 9, + GS_LOG_CAT_11 = 1 << 10, + GS_LOG_CAT_12 = 1 << 11, + GS_LOG_CAT_13 = 1 << 12, + GS_LOG_CAT_14 = 1 << 13, + GS_LOG_CAT_15 = 1 << 14, + GS_LOG_CAT_16 = 1 << 15, +#if (__AVR__ == 0) + GS_LOG_CAT_17 = 1 << 16, + GS_LOG_CAT_18 = 1 << 17, + GS_LOG_CAT_19 = 1 << 18, + GS_LOG_CAT_20 = 1 << 19, + GS_LOG_CAT_21 = 1 << 20, + GS_LOG_CAT_22 = 1 << 21, + GS_LOG_CAT_23 = 1 << 22, + GS_LOG_CAT_24 = 1 << 23, + GS_LOG_CAT_25 = 1 << 24, + GS_LOG_CAT_26 = 1 << 25, + GS_LOG_CAT_27 = 1 << 26, + GS_LOG_CAT_28 = 1 << 27, + GS_LOG_CAT_29 = 1 << 28, + GS_LOG_CAT_30 = 1 << 29, + GS_LOG_CAT_31 = 1 << 30, + //! Product or mission specific - start here and down + GS_LOG_CAT_32 = 1 << 31, +#endif +} gs_log_category_t; + +/** + @defgroup reserved_log_categories Reserved/assigned log categories. + These categories are assigned/reserved for certain sub-systems. + @{ +*/ + /** + Default, used if nothing else fits. + */ +#define GS_LOG_CAT_DEFAULT GS_LOG_CAT_1 + /** + Driver layer. + */ +#define GS_LOG_CAT_DRIVER GS_LOG_CAT_2 + /** + CSP. + */ +#define GS_LOG_CAT_CSP GS_LOG_CAT_3 + /** + Parameter system. + */ +#define GS_LOG_CAT_PARAM GS_LOG_CAT_4 + /** + File system. + */ +#define GS_LOG_CAT_FILE_SYSTEM GS_LOG_CAT_5 + /** + Command framework and execution. + */ +#define GS_LOG_CAT_COMMAND GS_LOG_CAT_6 + /** + Housekeeping System. + */ +#define GS_LOG_CAT_HK GS_LOG_CAT_7 + /** + Flight Planner. + */ +#define GS_LOG_CAT_FP GS_LOG_CAT_8 + /** + ADCS + */ +#define GS_LOG_CAT_ADCS GS_LOG_CAT_9 +/** @} */ + +struct gs_log_list; /* forward declared private log list struct */ +/** + Log list type (private) + + Private gs_log_list type. +*/ +typedef struct gs_log_list gs_log_list_t; + +/** + Log group. + All logs are logged to a \a group. The group contains the current log level mask, + which controls whether the log is carried through or not. +*/ +typedef struct { + /** + Name of log group. + */ + const char * name; + /** + Category, see #gs_log_category_t. + */ + uint32_t category; + /** + Current level mask, see #gs_log_level_t. + */ + uint8_t mask; + /** + Is group additive, if \a true (default) logging will be done on both root appenders and this groups appenders - if \a false, logging will only be done to this groups appenders. + */ + bool additivity; + /** + Private list of appenders. + */ + gs_log_list_t * appenders; +#if (__AVR__) + uint16_t dummy_align; +#endif +} gs_log_group_t; + +/** + Log masks (levels converted to mask). + @{ +*/ +/** + Trace level enabled. +*/ +#define GS_LOG_TRACE_MASK (1 << GS_LOG_TRACE) +/** + Debug level enabled. +*/ +#define GS_LOG_DEBUG_MASK (1 << GS_LOG_DEBUG) +/** + Info level enabled. +*/ +#define GS_LOG_INFO_MASK (1 << GS_LOG_INFO) +/** + Notice level enabled. +*/ +#define GS_LOG_NOTICE_MASK (1 << GS_LOG_NOTICE) +/** + Warning level enabled. +*/ +#define GS_LOG_WARNING_MASK (1 << GS_LOG_WARNING) +/** + Error level enabled. +*/ +#define GS_LOG_ERROR_MASK (1 << GS_LOG_ERROR) +/** + All levels enabled. +*/ +#define GS_LOG_ALL_MASK (GS_LOG_TRACE_MASK | GS_LOG_DEBUG_MASK | GS_LOG_INFO_MASK | GS_LOG_NOTICE_MASK | GS_LOG_WARNING_MASK | GS_LOG_ERROR_MASK) +/** + Default levels enabled - #GS_LOG_ERROR, #GS_LOG_WARNING and #GS_LOG_NOTICE. +*/ +#define GS_LOG_DEFAULT_MASK (GS_LOG_ERROR_MASK | GS_LOG_WARNING_MASK | GS_LOG_NOTICE_MASK) +/** + Trace level enabled. + @deprecated use #GS_LOG_TRACE_MASK +*/ +#define LOG_TRACE_MASK GS_LOG_TRACE_MASK +/** + Debug level enabled. + @deprecated use #GS_LOG_DEBUG_MASK +*/ +#define LOG_DEBUG_MASK GS_LOG_DEBUG_MASK +/** + Info level enabled. + @deprecated use #GS_LOG_INFO_MASK +*/ +#define LOG_INFO_MASK GS_LOG_INFO_MASK +/** + Notice level enabled. + @deprecated use #GS_LOG_NOTICE_MASK +*/ +#define LOG_NOTICE_MASK GS_LOG_NOTICE_MASK +/** + Warning level enabled. + @deprecated use #GS_LOG_WARNING_MASK +*/ +#define LOG_WARNING_MASK GS_LOG_WARNING_MASK +/** + Error level enabled. + @deprecated use #GS_LOG_ERROR_MASK +*/ +#define LOG_ERROR_MASK GS_LOG_ERROR_MASK +/** + All levels enabled. + @deprecated use #GS_LOG_ALL_MASK +*/ +#define LOG_ALL_MASK GS_LOG_ALL_MASK +/** + Default levels enabled - #GS_LOG_ERROR, #GS_LOG_WARNING and #GS_LOG_NOTICE. + @deprecated use #GS_LOG_DEFAULT_MASK +*/ +#define LOG_DEFAULT_MASK GS_LOG_DEFAULT_MASK +/**@}*/ + +/** + Define/Create a log group. + + @note name clash: This defines a variable, which potentially is \a global, meaning possibility of name clashes. Therefore log group should always + be prefixed with something that makes it fairly unique, i.e. component name. Example: gs_a3200dock_log - log group used by liba3200dock library. + + @param[in] group name of variables created. See note above about name clash. + @param[in] name_in display name + @param[in] cat_in log group category + @param[in] level_mask log level mask. +*/ +#define GS_LOG_GROUP(group, name_in, cat_in, level_mask) \ + gs_log_group_t group##_s = {.name = name_in, .category = cat_in, \ + .mask = level_mask, .additivity = true, \ + .appenders = NULL}; \ + gs_log_group_t * group = &group##_s + +/** + Define log group with initial mask for \a print and \a store. + + @note name clash: This defines a variable, which potentially is \a global, meaning possibility of name clashes. Therefore log group should always + be prefixed with something that makes it fairly unique, i.e. component name. Example: gs_a3200dock_log - log group used by liba3200dock library. + + @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(...) instead. + + @param[in] group name of variables created. See note above about name clash. + @param[in] name_in display name + @param[in] print_mask enable mask for \a print. + @param[in] store_mask enable mask for \a store. +*/ +#define LOG_GROUP_MASKED(group, name_in, print_mask, store_mask) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, (print_mask | store_mask)) + +/** + Declare log group as external (defined else where). + + @param[in] group the log group variable defined elsewhere. +*/ +#define GS_LOG_GROUP_EXTERN(group) extern gs_log_group_t * group + +/** + Define log group - levels are #GS_LOG_DEFAULT_MASK + + @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(..) instead. +*/ +#define LOG_GROUP(group, name_in) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, LOG_DEFAULT_MASK) + +/** + Define verbose log group - all levels are enabled (#GS_LOG_ALL_MASK) + + @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(..) instead. +*/ +#define LOG_GROUP_VERBOSE(group, name_in) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, LOG_ALL_MASK) + +/** + Define silent log group - all levels are disabled. + + @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(..) instead. +*/ +#define LOG_GROUP_SILENT(group, name_in) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, 0) + +/** + Declare log group as external (defined else where). + + @deprecated use #GS_LOG_GROUP_EXTERN(...) instead. +*/ +#define LOG_GROUP_EXTERN(group) GS_LOG_GROUP_EXTERN(group) + +/** + Default log group. + This can be overridden by a define +*/ +extern gs_log_group_t * LOG_DEFAULT; + +/** + Initializes the log system. + + @param[in] with_console_appender Enable/Disable console log appender + @return_gs_error_t +*/ +gs_error_t gs_log_init(bool with_console_appender); + +/** + Set log group level mask. + + @param[in] group_name log group name + @param[in] mask level mask to set. + @return_gs_error_t +*/ +gs_error_t gs_log_group_set_level_mask(const char * group_name, uint8_t mask); + +/** + Get log group level mask. + + @param[in] group_name log group name + @param[out] mask returned current level mask. + @return_gs_error_t +*/ +gs_error_t gs_log_group_get_level_mask(const char * group_name, uint8_t *mask); + +/** + Log group iterator callback function + + @param[in] ctx context data for iterator. + @param[in] group log group being iterated. + + @return true/false: Return false to discontinue iteration. +*/ +typedef bool (*gs_log_group_iterator_t)(void *ctx, gs_log_group_t * group); + +/** + Iterate all or specific log group(s). + + @param[in] group_name name of log group, or NULL/\"all\" for all groups. + @param[in] ctx user context data. + @param[in] iter iterator, return \a true to continue, \a false to break iteration. + @return_gs_error_t +*/ +gs_error_t gs_log_group_iterate(const char * group_name, void * ctx, gs_log_group_iterator_t iter); + +/** + Register a log group in the log system. + + The log group will be added to a system wide list of log groups, enabling list and set of level. + + @note The group must remain valid during the life-time of the application. + + @param[in] group The log group to be added to the system. + @return_gs_error_t +*/ +gs_error_t gs_log_group_register(gs_log_group_t *group); + +/** + Register a log group in the log system. + + @note The group must stay in memory during the life-time of the application + @see gs_log_group_register() + @param[in] group The log group to be added to the system. + @return_gs_error_t +*/ +static inline gs_error_t gs_log_group_add(gs_log_group_t *group) +{ + return gs_log_group_register(group); +} + +/** + Checks if a level is enabled on a log group + + @param[in] group The log group to check. + @param[in] level The log level to check if it's set on the group. + @return bool (true if enabled / false if not enabled) +*/ +bool gs_log_group_is_level_enabled(gs_log_group_t *group, gs_log_level_t level); + +/** + Convert string to log level. + + @param[in] str log level. + @param[out] return_level converted log level. + @return_gs_error_t +*/ +gs_error_t gs_log_string_to_level(const char * str, gs_log_level_t * return_level); + +/** + Convert level to single character. + + @param[in] level log level + @return single character representing the \a level. +*/ +char gs_log_level_to_char(gs_log_level_t level); + + +/** + Register Log commands. + @return_gs_error_t +*/ +gs_error_t gs_log_register_commands(void); + +/** + Generic log. + @note This function should not be called directly, use log macros. + + @param level log level + @param group log group. If NULL, the \a default log group will be used. + @param format Format string (printf style). +*/ +void gs_log(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) __attribute__ ((format (__printf__, 3, 4))); + +/** + Generic log from ISR. + @note This function should not be called directly, use log macros. + + @param level log level + @param group log group. If NULL, the \a default log group will be used. + @param format Format string (printf style). +*/ +void gs_log_isr(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) __attribute__ ((format (__printf__, 3, 4))); + +/** + Generic log (va_list). + @note This function should not be called directly, use log macros. + + @param level log level + @param group log group. If NULL, the \a default log group will be used. + @param format Format string (printf style). + @param args arguments for \a format. +*/ +void gs_log_va(gs_log_level_t level, gs_log_group_t * group, const char * format, va_list args); + +/** + Enable/disable color in \a print logs. + Default is \a enabled/true. + + @param[in] color \a true to enable color, \a false disable color. +*/ +void gs_log_set_print_color(bool color); + +/** + Level to color (begin). + + @param[in] level log level. + @return color string. +*/ +const char * gs_log_level_to_color_begin(gs_log_level_t level); + +/** + Level to color (end). + + @return color string. +*/ +const char * gs_log_level_to_color_end(void); + +/** + Take a level as input an create a level mask enabling all + levels with priority >= level. + + If level is e.g. LOG_INFO, the mask will enable Error, Warn & Info. + + * @param level the log level. + * @return level mask + */ +uint8_t gs_log_level_to_mask(gs_log_level_t level); + +/** + Convert string to log mask. + + Format: [+-]level[,[+-]level] + + + add level, - remove level. + + @param[in] str log mask + @param[in] current_mask current mask, used when input format contains + or -. + @param[out] return_mask converted log mask. + @return_gs_error_t +*/ +gs_error_t gs_log_string_to_mask(const char *str, uint8_t current_mask, uint8_t * return_mask); + +#if !(__DOXYGEN__) +/** + Internal macro for checking if log is enabled, before making log. +*/ +#define __gs_log(level, group, format, ...) \ + if (group->mask & (1 << level)) { \ + gs_log(level, group, GS_PGM_STR(format), ##__VA_ARGS__); \ + } + +/** + Internal macro for checking if log is enabled for isr, before making log. +*/ +#define __gs_log_isr(level, group, format, ...) \ + if (group->mask & (1 << level)) { \ + gs_log_isr(level, group, GS_PGM_STR(format), ##__VA_ARGS__); \ + } + +/** + Internal macro used for performing a log only once. + @note This creates a \a static \a variable. +*/ +#define __gs_log_once(level, group, format, ...) \ + ({ \ + static bool print_once; \ + if (!print_once) { \ + print_once = true; \ + __gs_log(level, group, format, ##__VA_ARGS__); \ + } \ + }) +#endif // __DOXYGEN__ + +/** + Default compile-time enabling/disabling of all levels + Unless levels are individually defined, this will be the default value. +*/ +#if !defined(GS_LOG_DISABLE_ALL) +#define GS_LOG_DISABLE_ALL 0 +#endif + +/** + Disable \a error level compile-time by defining a value > 0 +*/ +#if !defined(GS_LOG_DISABLE_ERROR) +#define GS_LOG_DISABLE_ERROR GS_LOG_DISABLE_ALL +#endif + +/** + Disable \a warning level compile-time by defining a value > 0 +*/ +#if !defined(GS_LOG_DISABLE_WARNING) +#define GS_LOG_DISABLE_WARNING GS_LOG_DISABLE_ALL +#endif + +/** + Disable \a notice level compile-time by defining a value > 0 +*/ +#if !defined(GS_LOG_DISABLE_NOTICE) +#define GS_LOG_DISABLE_NOTICE GS_LOG_DISABLE_ALL +#endif + +/** + Disable \a info level compile-time by defining a value > 0 +*/ +#if !defined(GS_LOG_DISABLE_INFO) +#define GS_LOG_DISABLE_INFO GS_LOG_DISABLE_ALL +#endif + +/** + Disable \a debug level compile-time by defining a value > 0 +*/ +#if !defined(GS_LOG_DISABLE_DEBUG) +#define GS_LOG_DISABLE_DEBUG GS_LOG_DISABLE_ALL +#endif + +/** + Disable \a trace level compile-time by defining a value > 0 +*/ +#if !defined(GS_LOG_DISABLE_TRACE) +#define GS_LOG_DISABLE_TRACE GS_LOG_DISABLE_ALL +#endif + +/** + Log \a error to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_error(format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log(LOG_ERROR, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a error from ISR to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_error_isr(format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log_isr(LOG_ERROR, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a error to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_error_group(group, format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log(LOG_ERROR, (group), format, ##__VA_ARGS__); } + +/** + Log \a error only once to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_error_once(format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log_once(LOG_ERROR, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a error only once to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_error_once_group(group, format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log_once(LOG_ERROR, (group), format, ##__VA_ARGS__); } + +/** + Log \a warning to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_warning(format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log(LOG_WARNING, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a warning from ISR to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_warning_isr(format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log_isr(LOG_WARNING, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a warning to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_warning_group(group, format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log(LOG_WARNING, (group), format, ##__VA_ARGS__); } + +/** + Log \a warning only once to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_warning_once(format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log_once(LOG_WARNING, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a warning only once to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_warning_once_group(group, format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log_once(LOG_WARNING, (group), format, ##__VA_ARGS__); } + +/** + Log \a notice to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_notice(format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log(LOG_NOTICE, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a notice from ISR to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_notice_isr(format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log_isr(LOG_NOTICE, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a notice to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_notice_group(group, format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log(LOG_NOTICE, (group), format, ##__VA_ARGS__); } + +/** + Log \a notice only once to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_notice_once(format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log_once(LOG_NOTICE, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a notice only once to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_notice_once_group(group, format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log_once(LOG_NOTICE, (group), format, ##__VA_ARGS__); } + +/** + Log \a info to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_info(format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log(LOG_INFO, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a info from ISR to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_info_isr(format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log_isr(LOG_INFO, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a info to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_info_group(group, format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log(LOG_INFO, (group), format, ##__VA_ARGS__); } + +/** + Log \a info only once to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_info_once(format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log_once(LOG_INFO, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a info only once to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_info_once_group(group, format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log_once(LOG_INFO, (group), format, ##__VA_ARGS__); } + +/** + Log \a debug to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_debug(format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log(LOG_DEBUG, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a debug from ISR to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_debug_isr(format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log_isr(LOG_DEBUG, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a debug to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_debug_group(group, format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log(LOG_DEBUG, (group), format, ##__VA_ARGS__); } + +/** + Log \a debug only once to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_debug_once(format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log_once(LOG_DEBUG, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a debug only once to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_debug_once_group(group, format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log_once(LOG_DEBUG, (group), format, ##__VA_ARGS__); } + +/** + Log \a trace to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_trace(format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log(LOG_TRACE, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a trace from ISR to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_trace_isr(format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log_isr(LOG_TRACE, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a trace to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_trace_group(group, format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log(LOG_TRACE, (group), format, ##__VA_ARGS__); } + +/** + Log \a trace only once to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_trace_once(format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log_once(LOG_TRACE, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a trace only once to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_trace_once_group(group, format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log_once(LOG_TRACE, (group), format, ##__VA_ARGS__); } + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/minmax.h b/gomspace/libutil/include/gs/util/minmax.h new file mode 100644 index 00000000..4b9edf74 --- /dev/null +++ b/gomspace/libutil/include/gs/util/minmax.h @@ -0,0 +1,67 @@ +#ifndef GS_UTIL_MINMAX_H +#define GS_UTIL_MINMAX_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Min/max utilities. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Return minimum value. + @param[in] x value + @param[in] y value + @return the lowest value of the input parameters. +*/ +#define gs_min(x,y) ({ \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + _x < _y ? _x : _y; }) + +/** + Return maximum value. + @param[in] x value + @param[in] y value + @return the maximum value of the input parameters. +*/ +#define gs_max(x,y) ({ \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + _x > _y ? _x : _y; }) + +/** + Return minimum value. + @param[in] x value + @param[in] y value + @param[in] z value + @return the lowest value of the input parameters. +*/ +#define gs_min3(x,y,z) gs_min(gs_min((x),(y)), (z)) + +/** + Return maximum value. + @param[in] x value + @param[in] y value + @param[in] z value + @return the maximum value of the input parameters. +*/ +#define gs_max3(x,y,z) gs_max(gs_max((x),(y)), (z)) + +/** + Clamp value within min/max. + @param[in] x value + @param[in] _max max value + @param[in] _min min value + @return value between min and max. +*/ +#define gs_clamp(x, _min, _max) ({ \ + gs_min(gs_max((x), (_min)), (_max)); }) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/mutex.h b/gomspace/libutil/include/gs/util/mutex.h new file mode 100644 index 00000000..b5a411f7 --- /dev/null +++ b/gomspace/libutil/include/gs/util/mutex.h @@ -0,0 +1,63 @@ +#ifndef GS_UTIL_MUTEX_H +#define GS_UTIL_MUTEX_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Mutex (recursive). + + The mutex API wraps POSIX \a pthread_mutex and FreeRTOS \a mutex. + + @note Mutex can not be used from within an ISR routine - use gs_sem instead. +*/ + +#include +#if __linux__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if __linux__ +/** + Mutex handle. +*/ +typedef pthread_mutex_t * gs_mutex_t; +#else +typedef struct gs_freertos_mutex_t * gs_mutex_t; +#endif + +/** + Create mutex. + @param[out] mutex handle. + @return error code. +*/ +gs_error_t gs_mutex_create(gs_mutex_t * mutex); + +/** + Destroy mutex - free resources. + @param[in] mutex handle. + @return error code. +*/ +gs_error_t gs_mutex_destroy(gs_mutex_t mutex); + +/** + Lock mutex. + @param[in] mutex handle. + @return error code. +*/ +gs_error_t gs_mutex_lock(gs_mutex_t mutex); + +/** + Unlock mutex. + @param[in] mutex handle. + @return error code. +*/ +gs_error_t gs_mutex_unlock(gs_mutex_t mutex); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/pgm.h b/gomspace/libutil/include/gs/util/pgm.h new file mode 100644 index 00000000..04e39013 --- /dev/null +++ b/gomspace/libutil/include/gs/util/pgm.h @@ -0,0 +1,162 @@ +#ifndef GS_UTIL_PROGMEM_H +#define GS_UTIL_PROGMEM_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Macros for handling special memory access. + + On most targets/processors, constant data/strings are located in the program space and can be read in the same way as data in the data space. + However, on a few targets (e.g. avr/avr8), data/strings must be marked in a special way in order to go into the program space, see #GS_PGM_STR() + + Using following macros, will make it easier to make cross-platform code and avoid \#if/\#endif. + These macros should only be used where the code also needs to run on avr/avr8. + + @note Including this header on avr/avr8 will REDEFINE printf!. + + http://www.atmel.com/webdoc/avrlibcreferencemanual/group__avr__pgmspace.html. + http://www.nongnu.org/avr-libc/user-manual/pgmspace.html. +*/ + +#include +#if defined(__AVR__) +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__AVR__) || (__DOXYGEN__) +/** + Special program/data memory handling. +*/ +#define GS_PGM 1 + +/** + Place object in program space (must be const). + Example: static const uint8_t data8[] GS_PGM_OBJECT = {1, 255}; +*/ +#define GS_PGM_OBJECT PROGMEM + +/** + Place const string in program space. + By default the string goes into data, uses thereby uses up space. + Once the string is placed in program space, xx_P functions must be used to access them - see #GS_PGM_PRINTF. + @note printf is re-defined by including this header +*/ +#define GS_PGM_STR(str) PSTR(str) + +/** + Read uint8 from program space (near). +*/ +#define GS_PGM_UINT8(value) pgm_read_byte(&(value)) + +/** + Read uint8 from program space using a pointer (near). +*/ +#define GS_PGM_UINT8_BY_PTR(value) pgm_read_byte(value) + +/** + Read word from program space (near). +*/ +#define GS_PGM_UINT16(value) pgm_read_word(&(value)) +/** + Read word from program space using a pointer (near). +*/ +#define GS_PGM_UINT16_BY_PTR(value) pgm_read_word(value) + +/** + Read dword from program space (near). +*/ +#define GS_PGM_UINT32(value) pgm_read_dword(&(value)) +/** + Read word from program space using a pointer (near). +*/ +#define GS_PGM_UINT32_BY_PTR(value) pgm_read_dword(value) + +/** + Memcpy from program space (near). + @param[in] dst destination. + @param[in] src source - program space. + @param[in] n number of bytes to copy +*/ +#define GS_PGM_MEMCPY(dst, src, n) memcpy_P(dst, src, n) + +/** + String compare (program space) + @param[in] s1 string 1 + @param[in] s2 string 2 - program space. + @param[in] n max number of bytes to compare +*/ +#define GS_PGM_STRNCMP(s1,s2,n) strncmp_P(s1, s2, n) + +/** + String compare (program space) + @param[in] s1 string 1 + @param[in] s2 string 2 - program space. + @param[in] n max number of bytes to compare +*/ +#define GS_PGM_STRNCASECMP(s1,s2,n) strncasecmp_P(s1, s2, n) + +/** + String formatting character for referencing a string placed in programs space. +*/ +#define GS_PGM_FMT_STR "S" + +/** + printf (format string in program space). + Example: print \a param->name (from prgram space) and \a value from data space, using a format string in program space. + GS_PGM_PRINTF(GS_PGM_STR("%"GS_PGM_FMT_STR", %d"), param->name, value) +*/ +#define GS_PGM_PRINTF(format, ...) printf_P(format, ##__VA_ARGS__) + +/** + vprintf (format string in program space). +*/ +#define GS_PGM_VPRINTF(format, va) vfprintf_P(stdout, format, va) + +/** + snprintf (format string in program space). +*/ +#define GS_PGM_SNPRINTF(buf, bufsize, format, ...) snprintf_P(buf, bufsize, format, ##__VA_ARGS__) + +/** + vsnprintf (format string in program space). +*/ +#define GS_PGM_VSNPRINTF(buf, bufsize, format, va) vsnprintf_P(buf, bufsize, format, va) + +/** + redefines printf (puts format string in program space) + */ +#undef printf +#define printf(format, ...) GS_PGM_PRINTF(GS_PGM_STR(format), ## __VA_ARGS__) + +#else + +#undef GS_PGM + +#define GS_PGM_OBJECT +#define GS_PGM_STR(str) (str) +#define GS_PGM_UINT8(value) (value) +#define GS_PGM_UINT8_BY_PTR(value) (*(value)) +#define GS_PGM_UINT16(value) (value) +#define GS_PGM_UINT16_BY_PTR(value) (*(value)) +#define GS_PGM_UINT32(value) (value) +#define GS_PGM_UINT32_BY_PTR(value) (*(value)) +#define GS_PGM_MEMCPY(dst, src, size) memcpy(dst, src, size) +#define GS_PGM_STRNCMP(s1,pgmstr,size) strncmp(s1, pgmstr, size) +#define GS_PGM_STRNCASECMP(s1,pgmstr,size) strncasecmp(s1, pgmstr, size) + +#define GS_PGM_FMT_STR "s" +#define GS_PGM_PRINTF(format, ...) printf(format, ## __VA_ARGS__) +#define GS_PGM_VPRINTF(format, va) vprintf(format, va) +#define GS_PGM_SNPRINTF(buf, bufsize, format, ...) snprintf(buf, bufsize, format, ##__VA_ARGS__) +#define GS_PGM_VSNPRINTF(buf, bufsize, format, va) vsnprintf(buf, bufsize, format, va) + +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/queue.h b/gomspace/libutil/include/gs/util/queue.h new file mode 100644 index 00000000..43b7e9ae --- /dev/null +++ b/gomspace/libutil/include/gs/util/queue.h @@ -0,0 +1,102 @@ +#ifndef GS_UTIL_QUEUE_H +#define GS_UTIL_QUEUE_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Queue. + + The queue API wraps FreeRTOS \a queue. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if __linux__ +/** + Queue handle. +*/ +typedef struct gs_pthread_queue * gs_queue_t; +#else +typedef struct gs_freertos_queue_t * gs_queue_t; +#endif + +/** + Create queue. + + @param[in] items max number of items on the queue. + @param[in] item_size size of item (bytes). + @param[out] queue created queue. + @return_gs_error_t +*/ +gs_error_t gs_queue_create(size_t items, size_t item_size, gs_queue_t * queue); + +/** + Destroy queue - free resources. + + @param[in] queue handle. + @return_gs_error_t +*/ +gs_error_t gs_queue_destroy(gs_queue_t queue); + +/** + Enqueue object on queue. + @param[in] queue handle. + @param[in] value pointer to object, size specified at gs_queue_create(). + @param_int_timeout_ms + @return_gs_error_timeout + @return_gs_error_t +*/ +gs_error_t gs_queue_enqueue(gs_queue_t queue, const void *value, int timeout_ms); + +/** + Enqueue object on queue from within an ISR. + @param[in] queue handle. + @param[in] value pointer to object, size specified at gs_queue_create(). + @param[in] cswitch context switch. + @return GS_ERROR_FULL if queue is full. + @return_gs_error_t +*/ +gs_error_t gs_queue_enqueue_isr(gs_queue_t queue, const void * value, gs_context_switch_t * cswitch); + +/** + Dequeue object from queue. + @param[in] queue handle. + @param[out] buf element - size specified in gs_queue_create(). + @param_int_timeout_ms + @return_gs_error_timeout + @return_gs_error_t +*/ +gs_error_t gs_queue_dequeue(gs_queue_t queue, int timeout_ms, void *buf); + +/** + Dequeue object from queue from within an ISR. + @param[in] queue handle. + @param[in] cswitch context switch. + @param[out] buf element - size specified in gs_queue_create(). + @return GS_ERROR_NOT_FOUND if no elements in queue. + @return_gs_error_t +*/ +gs_error_t gs_queue_dequeue_isr(gs_queue_t queue, gs_context_switch_t * cswitch, void * buf); + +/** + Return queue size. + @param[in] queue handle. + @return queue size +*/ +unsigned int gs_queue_size(gs_queue_t queue); + +/** + Return queue size from within an ISR. + @param[in] queue handle. + @return queue size +*/ +unsigned int gs_queue_size_isr(gs_queue_t queue); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/rtc.h b/gomspace/libutil/include/gs/util/rtc.h new file mode 100644 index 00000000..b1988925 --- /dev/null +++ b/gomspace/libutil/include/gs/util/rtc.h @@ -0,0 +1,62 @@ +#ifndef GS_UTIL_RTC_H +#define GS_UTIL_RTC_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Real Time Clock interface. + + The RTC driver is used by gs_clock_get_time() and gs_clock_set_time(). +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Platform supporting RTC must register the driver, before the rest of the system can access it. + @see gs_rtc_register() +*/ +typedef struct { + /** + Call-back for getting RTC time. + @param[out] time user allocated struct for returning time. + */ + gs_error_t (*get_time)(void * driver_data, gs_timestamp_t * time); + /** + Call-back for setting RTC time. + @param[in] time user allocated struct for returning time. + */ + gs_error_t (*set_time)(void * driver_data, const gs_timestamp_t * time); +} gs_rtc_driver_t; + +/** + Register RTC driver. + @param[in] driver driver - data/struct must remain valid as long as registered. + @param[in] driver_data driver specific data, forwarded to driver when set/get is called. + @return_gs_error_t +*/ +gs_error_t gs_rtc_register(const gs_rtc_driver_t * driver, void * driver_data); + +/** + Return GS_OK if RTC is supported. +*/ +gs_error_t gs_rtc_supported(void); + +/** + Set RTC. +*/ +gs_error_t gs_rtc_get_time(gs_timestamp_t * time); + +/** + Get RTC. +*/ +gs_error_t gs_rtc_set_time(const gs_timestamp_t * time); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/sem.h b/gomspace/libutil/include/gs/util/sem.h new file mode 100644 index 00000000..4afd4d7d --- /dev/null +++ b/gomspace/libutil/include/gs/util/sem.h @@ -0,0 +1,75 @@ +#ifndef GS_UTIL_SEM_H +#define GS_UTIL_SEM_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Semaphore. + + The semaphore API wraps POSIX \a semaphore and FreeRTOS \a counted semaphore. + + Main difference is that FreeRTOS uses different API calls, when called from within + an ISR routine. +*/ + +#include +#if __linux__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if __linux__ +/** + Semaphore handle. +*/ +typedef sem_t * gs_sem_t; +#else +typedef struct gs_freertos_sem_t * gs_sem_t; +#endif + +/** + Create semaphore. + @param[in] initialValue initial value. + @param[out] sem created semaphore. + @return_gs_error_t +*/ +gs_error_t gs_sem_create(unsigned int initialValue, gs_sem_t * sem); + +/** + Destroy semaphore - free resources. + @param[in] sem handle. + @return_gs_error_t +*/ +gs_error_t gs_sem_destroy(gs_sem_t sem); + +/** + Wait for semaphore to be signaled. + @param[in] sem handle. + @param_int_timeout_ms + @return_gs_error_timeout + @return_gs_error_t +*/ +gs_error_t gs_sem_wait(gs_sem_t sem, int timeout_ms); + +/** + Post/signal semaphore. + @param[in] sem handle. + @return_gs_error_t +*/ +gs_error_t gs_sem_post(gs_sem_t sem); + +/** + Post/signal semaphore from within a ISR. + @param[in] sem handle. + @param[in] cswitch context switch. + @return_gs_error_t +*/ +gs_error_t gs_sem_post_isr(gs_sem_t sem, gs_context_switch_t * cswitch); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/stdio.h b/gomspace/libutil/include/gs/util/stdio.h new file mode 100644 index 00000000..992d4dda --- /dev/null +++ b/gomspace/libutil/include/gs/util/stdio.h @@ -0,0 +1,117 @@ +#ifndef GS_UTIL_STDIO_H +#define GS_UTIL_STDIO_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + GomSpace extensions to standard \a stdio.h. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Put character on stdout. +*/ +gs_error_t gs_stdio_putchar(int ch); + +/** + Read character from stdin with timeout. + @param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milli seconds. + @param[out] ch character read. If NULL, one character from stdin is still consumed - but nothing returned. + @return GS_ERROR_TIMEOUT on timeout + @return_gs_error_t +*/ +gs_error_t gs_stdio_getchar_timed(int timeout_ms, int *ch); + +/** + Read character from stdin. + Blocks until a character is available. + @param[out] ch character read. If NULL, one character from stdin is still consumed - but nothing returned. + @return_gs_error_t +*/ +static inline gs_error_t gs_stdio_getchar(int * ch) +{ + return gs_stdio_getchar_timed(-1, ch); +} + +/** + Read characters from stdin. + Blocks until all characters are read. + @param[in,out] buf user supplied buffer for receiving characters. + @param[in] n number of characters to read. + @return_gs_error_t +*/ +gs_error_t gs_stdio_get(char * buf, size_t n); + +/** + Write characters to stdout. + Blocks until characters are written. + @param[in] buf characters to write. + @param[in] n number of characters to write. + @param[in] text if \a true, new lines (\\n) are converted to \\r\\n. + @return_gs_error_t +*/ +gs_error_t gs_stdio_put(const char * buf, size_t n, bool text); + +/** + Pattern for printing a byte as binary. + @see GS_STDIO_BYTETOBINARY() +*/ +#define GS_STDIO_BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d" + +/** + Macro for splitting a byte info 'bits'. +*/ +#define GS_STDIO_BYTETOBINARY(byte) \ + (byte & 0x80 ? 1 : 0), \ + (byte & 0x40 ? 1 : 0), \ + (byte & 0x20 ? 1 : 0), \ + (byte & 0x10 ? 1 : 0), \ + (byte & 0x08 ? 1 : 0), \ + (byte & 0x04 ? 1 : 0), \ + (byte & 0x02 ? 1 : 0), \ + (byte & 0x01 ? 1 : 0) + +/** + Color definitions for gs_color_printf() + @see gs_color_printf() +*/ +typedef enum { + /** + Colors. + */ + GS_COLOR_COLORS = 0x00ff, + GS_COLOR_NONE = 0, + GS_COLOR_BLACK = 1, + GS_COLOR_RED = 2, + GS_COLOR_GREEN = 3, + GS_COLOR_YELLOW = 4, + GS_COLOR_BLUE = 5, + GS_COLOR_MAGENTA = 6, + GS_COLOR_CYAN = 7, + GS_COLOR_WHITE = 8, + /** + Attributes + */ + GS_COLOR_ATTRS = 0xff00, + GS_COLOR_BOLD = 0x100, +} gs_color_printf_t; + +/** + Printf with colors on stdout. + + Using the standard terminal escape sequences for setting the color. + @param[in] color color settings. + @param[in] format standard printf format string. +*/ +void gs_color_printf(gs_color_printf_t color, const char * format, ...) __attribute__ ((format (__printf__, 2, 3))); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/string.h b/gomspace/libutil/include/gs/util/string.h new file mode 100644 index 00000000..034af8c6 --- /dev/null +++ b/gomspace/libutil/include/gs/util/string.h @@ -0,0 +1,391 @@ +#ifndef GS_UTIL_STRING_H +#define GS_UTIL_STRING_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + String utilitizes. + + All string parsing functions will return #GS_OK if the string was parsed entirely. + If the string contains characters that are not part of the selected base, the functions will return #GS_ERROR_DATA. + If the value parsed is bigger than the output type, the functions will return #GS_ERROR_OVERFLOW. + Spaces are ignored by all functions. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Macro helper for concatening tokens. +*/ +#define GS_STRINGZ(x) #x + +/** + Stringify a preprocessing token. +*/ +#define GS_DEF2STRING(x) GS_STRINGZ(x) + +/** + * Strncpy (using size of destination) and forced zero termination. + */ +#define GS_STRNCPY(dst,src) strncpy(dst,src,GS_ARRAY_SIZE(dst));dst[GS_ARRAY_SIZE(dst)-1] = 0 + +/** + Convert string to int32 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_int32(const char * string, int32_t * value); + +/** + Convert string to uint32 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_uint32(const char * string, uint32_t * value); + +/** + Convert string to int64 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_int64(const char * string, int64_t * value); + +/** + Convert string to uint64 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_uint64(const char * string, uint64_t * value); + +/** + Convert string to int8 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 12 (decimal), 0x12 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_int8(const char * string, int8_t * value); + +/** + Convert string to uint8 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 12 (decimal), 0x12 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_uint8(const char * string, uint8_t * value); + +/** + Convert string to int16 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_int16(const char * string, int16_t * value); + +/** + Convert string to uint16 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_uint16(const char * string, uint16_t * value); + +/** + Convert string to uint32 (hexadecimal). + Accepts: hexadecimal (no leading 0x), e.g. a123, A123. + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_hex_to_uint32(const char * string, uint32_t * value); + +/** + Convert string to uint64 (hexadecimal). + Accepts: hexadecimal (no leading 0x), e.g. a123, A123. + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_hex_to_uint64(const char * string, uint64_t * value); + +/** + Convert string to boolean. + Accepts: true, false, on, off, 1, 0 (ignores case) + @param[in] string string to convert. + @param[out] pvalue converted value + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_bool(const char * string, bool * pvalue); + +/** + Convert string to float. + @param[in] string string to convert. + @param[out] pvalue converted value + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_float(const char * string, float * pvalue); + +/** + Convert string to double. + @param[in] string string to convert. + @param[out] pvalue converted value + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_double(const char * string, double * pvalue); + +/** + Return string for boolean value (true or false). + @param[in] value value + @return \a 'true' if input is true, else \a 'false'. +*/ +const char * gs_string_from_bool(bool value); + +/** + Convert string to pointer (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_pointer(const char * string, void ** value); + +/** + Format size as Bytes, Kilo or Mega. + + Output examples: \a 512.0B, \a 1.0K and \a 1.0M. + + @param[in] size size in bytes + @param[out] buffer formatted size + @param[in] buffer_size size of \a buf + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +char * gs_string_bytesize(long size, char *buffer, size_t buffer_size); + +/** + GS implementation of gcc's strtol + Instead of setting errno this function takes a pointer to err which is set + the same way as with gcc's strtol + + @param[in] nptr input string + @param[out] endptr the pointer to the end of the string parsed + @param[in] base number system (10 or 16) + @param[out] err return value if overflow + @return converted value +*/ +int32_t gs_string_strto32int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); + +/** + GS implementation of gcc's strtoul + Instead of setting errno this function takes a pointer to err which is set + the same way as with gcc's strtoul + + @param[in] nptr input string + @param[out] endptr the pointer to the end of the string parsed + @param[in] base number system (10 or 16) + @param[out] err return value if overflow + @return converted value +*/ +uint64_t gs_string_strto64uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); + +/** + GS implementation of gcc's strtoul + Instead of setting errno this function takes a pointer to err which is set + the same way as with gcc's strtoul + + @param[in] nptr input string + @param[out] endptr the pointer to the end of the string parsed + @param[in] base number system (10 or 16) + @param[out] err return value if overflow + @return converted value +*/ +int64_t gs_string_strto64int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); + +/** + GS implementation of gcc's strtoul + Instead of setting errno this function takes a pointer to err which is set + the same way as with gcc's strtoul + + @param[in] nptr input string + @param[out] endptr the pointer to the end of the string parsed + @param[in] base number system (10 or 16) + @param[out] err return value if overflow + @return converted value +*/ +uint32_t gs_string_strto32uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); + +/** + Returns pointer to first none-space character. + + @param[in] string string + @return NULL if \a string is NULL, otherwise first none-space character. +*/ +const char * gs_string_skip_leading_spaces(const char * string); + +/** + Check if a string is NULL or empty. + + @param[in] string string + @return true if string is empty or NULL. +*/ +bool gs_string_empty(const char * string); + +/** + Case-insentive wilcard match (similiar to fnmatch). + + Supports following wildcard(s): + - * (asterix) zero or more characters. + + This may be extended in future versions and will not be considered a break of the API. + + @param[in] pattern pattern to match against \a string. + @param[in] string string to match against \a pattern + @return \a true if match, else \ false +*/ +bool gs_string_match(const char * pattern, const char * string); + +/** + Returns \a true if string contains wildcards. + + @param[in] string string to check for wildcards. + @return \a true if string contains wildcards recognized by gs_string_match(). +*/ +bool gs_string_has_wildcards(const char * string); + +/** + Trim string in buffer by removing leading/trailing white space. + + Uses isspace(c). + + @param[in] buffer buffer to trim. + @param[in] buffer_size size of \a buffer. +*/ +void gs_string_trim(char * buffer, size_t buffer_size); + +/** + Returns \a true if string ends with endswith. + + @param[in] string string to check + @param[in] endswith string that string should end with + @return \a true if string endswith endswith +*/ +bool gs_string_endswith(const char * string, const char * endswith); + +/** + Extract suboption from a string. + + @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". + @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). + @param[out] buf user buffer for returning value of sub-option. + @param[in] buf_size size of \a buf user buffer. + @return_gs_error_t +*/ +gs_error_t gs_string_get_suboption(const char * options, const char * suboption, char * buf, size_t buf_size); + +/** + Extract suboption (as string) from a string. + + @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". + @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). + @param[in] def default value, returned if sub-option isn't found. + @param[out] buf user buffer for returning value of sub-option. + @param[in] buf_size size of \a buf user buffer. + @return If the sub-option isn't found, the \a def default value will be copied to \a buf and #GS_OK will be returned. + @return_gs_error_t +*/ +gs_error_t gs_string_get_suboption_string(const char * options, const char * suboption, const char * def, char * buf, size_t buf_size); + +/** + Extract suboption (as uint8) from a string. + + @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". + @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). + @param[in] def default value, returned if sub-option isn't found. + @param[out] value user supplied buffer for returning the value. + @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. + @return_gs_error_t +*/ +gs_error_t gs_string_get_suboption_uint8(const char * options, const char * suboption, uint8_t def, uint8_t * value); + +/** + Extract suboption (as uint16) from a string. + + @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". + @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). + @param[in] def default value, returned if sub-option isn't found. + @param[out] value user supplied buffer for returning the value. + @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. + @return_gs_error_t +*/ +gs_error_t gs_string_get_suboption_uint16(const char * options, const char * suboption, uint16_t def, uint16_t * value); + +/** + Extract suboption (as uint32) from a string. + + @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". + @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). + @param[in] def default value, returned if sub-option isn't found. + @param[out] value user supplied buffer for returning the value. + @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. + @return_gs_error_t +*/ +gs_error_t gs_string_get_suboption_uint32(const char * options, const char * suboption, uint32_t def, uint32_t * value); + +/** + Extract suboption (as bool) from a string. + + @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". + @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). + @param[in] def default value, returned if sub-option isn't found. + @param[out] value user supplied buffer for returning the value. + @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. + @return_gs_error_t +*/ +gs_error_t gs_string_get_suboption_bool(const char * options, const char * suboption, bool def, bool * value); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/test/cmocka.h b/gomspace/libutil/include/gs/util/test/cmocka.h new file mode 100644 index 00000000..43648627 --- /dev/null +++ b/gomspace/libutil/include/gs/util/test/cmocka.h @@ -0,0 +1,136 @@ +#ifndef GS_UTIL_TEST_CMOCKA_H +#define GS_UTIL_TEST_CMOCKA_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Cmocka extensions. + + Official site for cmocka https://cmocka.org. +*/ + +#include + +// cmocka +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if !(__DOXYGEN__) +// internal helpers - use macros +void _gs_assert_int_equal(const intptr_t a, const intptr_t b, bool equal, const char * const file, const int line); +void _gs_assert_uint_equal(const uintptr_t a, const uintptr_t b, bool equal, bool hex, const char * const file, const int line); +void _gs_assert_error_equal(const int a, const int b, bool equal, const char * const file, const int line); +void _gs_assert_float_equal(const float a, const float b, const float diff, bool equal, const char * const file, const int line); +void _gs_assert_double_equal(const double a, const double b, const double diff, bool equal, const char * const file, const int line); +#endif + +/** + Assert int (print value as signed). +*/ +#define GS_ASSERT_INT_EQUAL(a,b) _gs_assert_int_equal((intptr_t) (a), (intptr_t) (b), true, __FILE__, __LINE__) +/** + Assert unsigned int (print value as unsigned). +*/ +#define GS_ASSERT_UINT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, false, __FILE__, __LINE__) +/** + Assert int (print value as hex). +*/ +#define GS_ASSERT_XINT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, true, __FILE__, __LINE__) +/** + Assert #gs_error_t (print value and error text). +*/ +#define GS_ASSERT_ERROR_EQUAL(a,b) _gs_assert_error_equal(a, b, true, __FILE__, __LINE__) +/** + Assert #GS_OK (print value and error text). +*/ +#define GS_ASSERT_ERROR_OK(a) _gs_assert_error_equal(a, GS_OK, true, __FILE__, __LINE__) +/** + Assert float (print value as signed). +*/ +#define GS_ASSERT_FLOAT_EQUAL(a,b,diff) _gs_assert_float_equal(a, b, diff, true, __FILE__, __LINE__) +/** + Assert double (print value as signed). +*/ +#define GS_ASSERT_DOUBLE_EQUAL(a,b,diff) _gs_assert_double_equal(a, b, diff, true, __FILE__, __LINE__) + +/** + Assert int (print value as signed). +*/ +#define GS_ASSERT_INT_NOT_EQUAL(a,b) _gs_assert_int_equal((intptr_t) (a), (intptr_t) (b), false, __FILE__, __LINE__) +/** + Assert unsigned int (print value as unsigned). +*/ +#define GS_ASSERT_UINT_NOT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), false, false, __FILE__, __LINE__) +/** + Assert int (print value as hex). +*/ +#define GS_ASSERT_XINT_NOT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), false, true, __FILE__, __LINE__) +/** + Assert #GS_OK (print value and error text). +*/ +#define GS_ASSERT_ERROR_NOT_EQUAL(a,b) _gs_assert_error_equal(a, b, false, __FILE__, __LINE__) + +/** + Code reference. +*/ +#define GS_REF() __FILE__,__LINE__ +/** + Assert int with code reference (print value as signed). +*/ +#define GS_ASSERT_INT_EQUAL_REF(a,b,file,line) _gs_assert_int_equal((intptr_t) (a), (intptr_t) (b), true, file, file, line) +/** + Assert unsigned int with code reference (print value as unsigned). +*/ +#define GS_ASSERT_UINT_EQUAL_REF(a,b,file,line) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, false, file, line) +/** + Assert int with code reference (print value as hex). +*/ +#define GS_ASSERT_XINT_EQUAL_REF(a,b,file,line) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, true, file, line) +/** + Assert #gs_error_t with code reference (print value and error text). +*/ +#define GS_ASSERT_ERROR_EQUAL_REF(a,b,file,line) _gs_assert_error_equal(a, b, true, file, line) +/** + Assert #GS_OK with code reference (print value and error text). +*/ +#define GS_ASSERT_ERROR_OK_REF(a,file,line) _gs_assert_error_equal(a, GS_OK, true, file, line) + +/** + Run \a cmocka test group. + + @param[in] name name of test. If name is \a tests and GS_TEST_NAME is set, GS_TEST_NAME will be used instead. + @param[in] tests array of tests. + @param[in] num_tests number of tests. + @param[in] setup setup function, can be NULL. + @param[in] teardown teardown function, can be NULL. + @return 0 on success. +*/ +static inline int gs_cmocka_run_group_tests(const char *name, + const struct CMUnitTest * const tests, + const size_t num_tests, + CMFixtureFunction setup, + CMFixtureFunction teardown) +{ +#ifdef GS_TEST_NAME // set by buildtools::gs_test_cmocka.py + if (strcasecmp(name, "tests") == 0) { + name = GS_DEF2STRING(GS_TEST_NAME); + } +#endif + return _cmocka_run_group_tests(name, tests, num_tests, setup, teardown); +} + +#ifdef GS_TEST_NAME +// hi-jack cmocka's macro +#undef cmocka_run_group_tests +#define cmocka_run_group_tests(tests, setup, teardown) gs_cmocka_run_group_tests(GS_DEF2STRING(tests), tests, GS_ARRAY_SIZE(tests), setup, teardown) +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/test/command.h b/gomspace/libutil/include/gs/util/test/command.h new file mode 100644 index 00000000..d2227017 --- /dev/null +++ b/gomspace/libutil/include/gs/util/test/command.h @@ -0,0 +1,80 @@ +#ifndef GS_UTIL_TEST_COMMAND_H +#define GS_UTIL_TEST_COMMAND_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Command Test framework. + + Provides a simple way of unit-testing/validating commands. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Validate command execution. + + Runs a commands and validates the output/results agains the inputs. + Asserts if the results does not match. + + @param[in] cmd command (including arguments) to execute. + @param[in] ret expected return code from the command execution framework. + @param[in] cmd_ret expected return code from the commands handler. This is only validated if (ret = GS_OK). + @param[in] std_in string with expected command input. + @param[in] std_out string with expected command output. Wildcards (*\/?) are supported. + @param[in] file string with file name. + @param[in] line string with line no. + @return void +*/ +void _gs_assert_command_validate(const char *cmd, gs_error_t ret, gs_error_t cmd_ret, const char *std_in, const char *std_out, const char * const file, const int line); + +/** + Validate command results returned from last command execution. + Asserts if the results does not match. + + @param[in] no the result no to verify. + @param[in] group string with expected group id. Wildcards (*\/?) are supported. + @param[in] key string with expected key. Wildcards (*\/?) are supported. + @param[in] value string with expected value. Wildcards (*\/?) are supported. + @param[in] file string with file name. + @param[in] line string with line no. + @return void +*/ +void _gs_assert_command_validate_last_result(unsigned int no, const char *group, const char *key, const char *value, const char * const file, const int line); + +/** + Validate command execution. + + Runs a commands and validates the output/results agains the inputs. + Asserts if the results does not match. + + @param[in] cmd command (including arguments) to execute. + @param[in] ret expected return code from the command execution framework. + @param[in] cmd_ret expected return code from the commands handler. This is only validated if (ret = GS_OK). + @param[in] std_in string with expected command input. + @param[in] std_out string with expected command output. Wildcards (*\/?) are supported. + @return void +*/ +#define GS_ASSERT_COMMAND(cmd,ret,cmd_ret,std_in,std_out) _gs_assert_command_validate(cmd,ret,cmd_ret,std_in,std_out, __FILE__, __LINE__); + +/** + Validate command results returned from last command execution. + Asserts if the results does not match. + + @param[in] no the result no to verify. + @param[in] group string with expected group id. Wildcards (*\/?) are supported. + @param[in] key string with expected key. Wildcards (*\/?) are supported. + @param[in] value string with expected value. Wildcards (*\/?) are supported. + @return void +*/ +#define GS_ASSERT_COMMAND_RESULT(no,group,key,value) _gs_assert_command_validate_last_result(no,group,key,value, __FILE__, __LINE__); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/test/log.h b/gomspace/libutil/include/gs/util/test/log.h new file mode 100644 index 00000000..13322953 --- /dev/null +++ b/gomspace/libutil/include/gs/util/test/log.h @@ -0,0 +1,88 @@ +#ifndef GS_UTIL_TEST_LOG_H +#define GS_UTIL_TEST_LOG_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Log Test framework. + + Provides a simple way of veriyfing logs generated during unit-testing. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Assert log count - internal helper function. +*/ +void gs_assert_log_count(int level, unsigned int count, const char * file, int line); + +/** + Assert log messag and count - internal helper function. +*/ +void gs_assert_log(unsigned int stack_index, unsigned int count, gs_log_level_t level, const char * pattern, const char * file, int line); + +/** + Initialize framework, by installing a callback for \a print. + @param[in] verbose of \a true, logs will be printed on stdout. +*/ +void gs_test_log_init(bool verbose); + +/** + Clear log stats. +*/ +void gs_test_log_clear(void); + +/** + Assert number of error logs. +*/ +#define GS_ASSERT_LOG_ERROR(cnt) gs_assert_log_count(LOG_ERROR, cnt, __FILE__, __LINE__); + +/** + Assert number of warning logs. +*/ +#define GS_ASSERT_LOG_WARNING(cnt) gs_assert_log_count(LOG_WARNING, cnt, __FILE__, __LINE__); + +/** + Assert number of notice logs. +*/ +#define GS_ASSERT_LOG_NOTICE(cnt) gs_assert_log_count(LOG_NOTICE, cnt, __FILE__, __LINE__); + +/** + Assert number of info logs. +*/ +#define GS_ASSERT_LOG_INFO(cnt) gs_assert_log_count(LOG_INFO, cnt, __FILE__, __LINE__); + +/** + Assert number of debug logs. +*/ +#define GS_ASSERT_LOG_DEBUG(cnt) gs_assert_log_count(LOG_DEBUG, cnt, __FILE__, __LINE__); + +/** + Assert number of trace logs. +*/ +#define GS_ASSERT_LOG_TRACE(cnt) gs_assert_log_count(LOG_TRACE, cnt, __FILE__, __LINE__); + +/** + Assert number of all logs. +*/ +#define GS_ASSERT_LOG_ALL(cnt) gs_assert_log_count(-1, cnt, __FILE__, __LINE__); + +/** + Assert/find number of entries matching level and pattern. +*/ +#define GS_ASSERT_LOG(count,level,pattern) gs_assert_log(-1, count, level, pattern, __FILE__, __LINE__) + +/** + Assert log at stack index against matching level and pattern. +*/ +#define GS_ASSERT_LOG_AT(stack_index,level,pattern) gs_assert_log(stack_index, 1, level, pattern, __FILE__, __LINE__) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/thread.h b/gomspace/libutil/include/gs/util/thread.h new file mode 100644 index 00000000..37340818 --- /dev/null +++ b/gomspace/libutil/include/gs/util/thread.h @@ -0,0 +1,173 @@ +#ifndef GS_UTIL_THREAD_H +#define GS_UTIL_THREAD_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Thread/task API based on POSIX standard. + + The thread API wraps POSIX \a pthread and FreeRTOS \a task. +*/ + +#include +#if __linux__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if __linux__ +/** + Thread handle. +*/ +typedef pthread_t gs_thread_t; +#else +typedef struct gs_freertos_task_t * gs_thread_t; +#endif + +/** + Type used to declare thread stack buffer for gs_thread_create_with_stack. +*/ +typedef uint32_t gs_stack_type_t; + +/** + Thread priorities. + These values are mapped to platform specific values. +*/ +typedef enum { + /** + Idle (lowest) priority. + Typical use: Not much - runs when nothing else runs. + FreeRTOS: Idle thread. + */ + GS_THREAD_PRIORITY_IDLE = 5, + /** + Low priority. + Typical use: Service applications, e.g. servicing requests from the outside. + GOMspace: housekeeping, GOSH. + */ + GS_THREAD_PRIORITY_LOW = 10, + /** + Normal priority. + Typical use: Control - the primary application(s). + */ + GS_THREAD_PRIORITY_NORMAL = 15, + /** + High priority. + Typical use: Drivers off loading data from hardware to software buffers. + GOMspace: csp_route_task. + */ + GS_THREAD_PRIORITY_HIGH = 20, + /** + High priority. + Typical use: Very time critical threads. No long, time consuming processing. + FreeRTOS: Timer thread. + */ + GS_THREAD_PRIORITY_CRITICAL = 25, +} gs_thread_priority_t; + +/** + Thread function. +*/ +typedef void * (*gs_thread_func_t)(void * parameter); + +/** + Create thread as joinable. + @note only supported on linux. The thread must be joined to free all resources. +*/ +#define GS_THREAD_CREATE_JOINABLE 0x0001 + +/** + Create thread (or task on some platforms). + + pthread/Posix supports exit value and join, FreeRTOS supports neither (perhaps in the future), so API is designed after Posix. + + FreeRTOS: a thread must always terminate with a call to gs_thread_exit(). + linux: a thread is by default created detached, unless #GS_THREAD_CREATE_JOINABLE is specified. + + @param[in] name name of thread. Ignored on Linux. + @param[in] func function for thread to execute. + @param[in] parameter parameter parsed to the thread function. + @param[in] stack_size number of bytes to allocate for stack - not used/supported on all platforms. Ignored on Linux. + @param[in] priority thread priority. Ignored on Linux. + @param[in] flags flags to control creation, see #GS_THREAD_CREATE_JOINABLE. + @param[out] handle handle to the created thread, use NULL if not wanted. + @return_gs_error_t +*/ +gs_error_t gs_thread_create(const char * const name, + gs_thread_func_t func, + void * parameter, + size_t stack_size, + gs_thread_priority_t priority, + uint32_t flags, + gs_thread_t * handle); + +/** + Create thread (or task on some platforms) with user supplied buffer for stack. + + pthread/Posix supports exit value and join, FreeRTOS supports neither (perhaps in the future), so API is designed after Posix. + + FreeRTOS: a thread must always terminate with a call to gs_thread_exit(). + FreeRTOS v9.0 must be compiled with configSUPPORT_STATIC_ALLOCTION set to 1 - otherwise warning log is printed and user supplied + stack buffer is discarded + linux: a thread is by default created detached, unless #GS_THREAD_CREATE_JOINABLE is specified. + stack_buf is ignored. + + @param[in] name name of thread. Ignored on Linux. + @param[in] func function for thread to execute. + @param[in] parameter parameter parsed to the thread function. + @param[in] stack_size size of the user supplied stack buffer - not used/supported on all platforms. Ignored on Linux. + @param[in] stack_buf User supplied stack buffer - not used/supported on all platforms. Ignored on Linux. + @param[in] priority thread priority. Ignored on Linux. + @param[in] flags flags to control creation, see #GS_THREAD_CREATE_JOINABLE. + @param[out] handle handle to the created thread, use NULL if not wanted. + @return_gs_error_t +*/ +gs_error_t gs_thread_create_with_stack(const char * const name, + gs_thread_func_t func, + void * parameter, + size_t stack_size, + gs_stack_type_t *stack_buf, + gs_thread_priority_t priority, + uint32_t flags, + gs_thread_t * handle); + +/** + Exit current thread. + @param[in] exit_value exit value. +*/ +void gs_thread_exit(void * exit_value) __attribute__ ((noreturn)); + +/** + Sleep for X milli-seconds. + @note FreeRTOS: minimum sleep time depends on ticks per milli-second. A thread is suspended minimum 1 tick - unless \a time_ms is 0, in which case yield is called. + @deprecated use gs_time_sleep_ms() + @param[in] time_ms milli-seconds to sleep. +*/ +void gs_thread_sleep_ms(uint32_t time_ms); + +/** + Join with a terminated thread. + + @note Only supported on Linux and primarily used for testing. + @note This is not based on pthread_cancel(), so the user must have signaled the thread to stop - otherwise this will hang forever. + + @param[in] thread handle. + @param[out] return_retval return value from thread, use NULL if not wanted. + @return_gs_error_t +*/ +gs_error_t gs_thread_join(gs_thread_t thread, void ** return_retval); + +/** + Block thread forever. + + Primarily used in Linux applications main() to block main thread. +*/ +void gs_thread_block(void) __attribute__ ((noreturn)); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/time.h b/gomspace/libutil/include/gs/util/time.h new file mode 100644 index 00000000..d4425906 --- /dev/null +++ b/gomspace/libutil/include/gs/util/time.h @@ -0,0 +1,95 @@ +#ifndef GS_UTIL_TIME_H +#define GS_UTIL_TIME_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Releative time. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Converts minutes to seconds. +*/ +#define GS_TIME_MINS_TO_SECS(m) (m * 60) + +/** + Converts hours to seconds. +*/ +#define GS_TIME_HOURS_TO_SECS(h) (h * GS_TIME_MINS_TO_SECS(60)) + +/** + Converts days to seconds. +*/ +#define GS_TIME_DAYS_TO_SECS(d) (d * GS_TIME_HOURS_TO_SECS(24)) + +/** + Return relative time (milli seconds). + @note This will eventually wrap on all platforms - platform must wrap on 32 bit. + @return relativ milli seconds +*/ +uint32_t gs_time_rel_ms(void); + +/** + Return relative time (milli seconds). + @note This will eventually wrap on all platforms - platform must wrap on 32 bit. + @return relativ milli seconds +*/ +uint32_t gs_time_rel_ms_isr(void); + +/** + Returns seconds since process started. + @note On some platforms (e.g. Linux), first call will set offset and + first call it therefor not thread-safe. + @return seconds since boot (or process startup). +*/ +uint32_t gs_time_uptime(void); + +/** + Return time difference, compensating for time wrap due to 32 bit. + @note the function can not detect multiple time wraps, so function using it should + take action within 32 bit time. + @param[in] ref_ms reference time. + @param[in] now_ms current time. + @returns ms difference, compensating for time wrapping (if now_ms is less than ref_ms). +*/ +uint32_t gs_time_diff_ms(uint32_t ref_ms, uint32_t now_ms); + +/** + Sleep for X milli-seconds. + No busy waiting. + @note FreeRTOS: minimum sleep time depends on ticks per second. Suspends execution for minimum 1 tick - unless \a time is 0, in which case yield is called. + @param[in] time_ms milli-seconds to sleep. +*/ +void gs_time_sleep_ms(uint32_t time_ms); + +/** + Sleep X milli-seconds relative to reference. + + This sleep function uses a reference \a ref_ms to compensate for variance in processing time. + + No busy waiting. + + @param[in,out] ref_ms time reference. + @param[in] sleep_ms how many milli-seconds to sleep - relative to reference. + @return \a true if sleep time relative to last reference couldn't be done (reference reset), \a false if normal sleep was done. +*/ +bool gs_time_sleep_until_ms(uint32_t * ref_ms, uint32_t sleep_ms); + +/** + Sleep for X nano-seconds. + No busy waiting. + @note FreeRTOS: minimum sleep time depends on ticks per second. Suspends execution for minimum 1 tick - unless \a time is 0, in which case yield is called. + @param[in] time_ns nano-seconds to sleep. +*/ +void gs_time_sleep_ns(uint64_t time_ns); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/timestamp.h b/gomspace/libutil/include/gs/util/timestamp.h new file mode 100644 index 00000000..80fef6da --- /dev/null +++ b/gomspace/libutil/include/gs/util/timestamp.h @@ -0,0 +1,73 @@ +#ifndef GS_UTIL_TIMESTAMP_H +#define GS_UTIL_TIMESTAMP_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Timestamp utilities, for add, subtract, compare, copy, etc. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Number of nano seconds per second. +*/ +#define GS_TIMESTAMP_NSEC_PER_SEC 1000000000 + +/** + Portable time structure. + + Stanadard timespec_t is non-portable, so this structure must be used instead +*/ +typedef struct { + /** Seconds. */ + uint32_t tv_sec; + /** Nano seconds. */ + uint32_t tv_nsec; +} gs_timestamp_t; + +/** + @deprecated Use gs_timestamp_t +*/ +typedef gs_timestamp_t timestamp_t; + +/** + Add 2 timestamp's (t1 = t1 + t2). + @param[in,out] t1 timestamp + @param[in] t2 timestamp. + @return 0 on success, otherwise -1 +*/ +int timestamp_add(gs_timestamp_t * t1, const gs_timestamp_t * t2); + +/** + Subtract 2 timestamp's (t1 = t1 - t2) + @param[in,out] t1 timestamp + @param[in] t2 timestamp. + @return 0 on success, otherwise -1 +*/ +int timestamp_diff(gs_timestamp_t * t1, const gs_timestamp_t * t2); + +/** + Check if t2 is greate than t1. + @param[in] t1 time to compare + @param[in] t2 time to compare + @return 1 if t2 > t1, else 0. -1 on bad arguments. +*/ +int timestamp_ge(const gs_timestamp_t * t1, const gs_timestamp_t * t2); + +/** + Copy timestamp. + @param[in] from from timestamp + @param[out] to to timestamp + @return 0 on success, otherwise -1 +*/ +int timestamp_copy(const gs_timestamp_t * from, gs_timestamp_t * to); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/types.h b/gomspace/libutil/include/gs/util/types.h new file mode 100644 index 00000000..2c0d0597 --- /dev/null +++ b/gomspace/libutil/include/gs/util/types.h @@ -0,0 +1,114 @@ +#ifndef GS_UTIL_TYPES_H +#define GS_UTIL_TYPES_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Base type definitions and functions. + + In some rare cases, it is impossible to make code that works on all platforms. In these cases the following defines may be used to + exclude/include code: + | define | Platform | + | :----: | :---- | + | \_\_AVR\_\_ | 8 bit, e.g. atmega1281, atmega2560, attiny25, attiny44, attiny84 | + | \_\_linux\_\_ | 32/64 bit, Linux based | + + +*/ + +#include // intXX_t +#include // bool +#include // size_t + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Control static declaration at compile time. + Allows unit tests to access internal functions or variables. + @note Static declared variables are initialized to zero by the compiler - BUT if you use GS_NO_STATIC instead of static, they will not be initialized. +*/ +#if GS_NO_STATIC +#define GS_STATIC +#else +#define GS_STATIC static +#endif + +/** + Convert integer to pointer. +*/ +#define GS_TYPES_INT2PTR(value) ((void*)(intptr_t)(value)) + +/** + Convert integer to pointer. +*/ +#define GS_TYPES_UINT2PTR(value) ((void*)(uintptr_t)(value)) + +/** + Convert pointer to integer. +*/ +#define GS_TYPES_PTR2INT(value) ((intptr_t)(void*)(value)) + +/** + Convert pointer to integer. +*/ +#define GS_TYPES_PTR2UINT(value) ((uintptr_t)(void*)(value)) + +/** + Assert on 'value'. + + Example: + GS_STATIC_ASSERT(sizeof(int) >= 2, int_must_be_at_least_16bit); + fails if size of (int) is less than 2 bytes. +*/ +#define GS_STATIC_ASSERT(condition, name) typedef char name[(condition) ? 1 : -1] + +/** + Context switch state. + Used by FreeRTOS when waking a higher priority task/thread from within an ISR. + The actual struct is defined in libembed. +*/ +typedef struct gs_context_switch gs_context_switch_t; + +/** + Return element count of array. +*/ +#define GS_ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) + +/** + Address union. +*/ +typedef union { + /** + Normal address pointer. + */ + void* p; + /** + Address pointer as an unsigned value. + */ + uintptr_t u; +} gs_address_t; + +/** + @cond HIDDEN_SYMBOLS + Compile check size of primitives (just to be sure, that they are what we expect). +*/ +GS_STATIC_ASSERT(sizeof(gs_address_t) == sizeof(void*), unexpected_address_void_pointer_size); +GS_STATIC_ASSERT(sizeof(gs_address_t) == sizeof(uintptr_t), unexpected_address_uintptr_size); +GS_STATIC_ASSERT(sizeof(bool) == sizeof(uint8_t), unexpected_bool_size); +GS_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), unexpected_float_size); +#if (__AVR__) +// avr/avr8 is 8 bit +GS_STATIC_ASSERT(sizeof(int) == sizeof(int16_t), unexpected_int_size_on_avr8); +#else +// rest should be 32 or 64 bit +GS_STATIC_ASSERT(sizeof(int) == sizeof(int32_t), unexpected_int_size); +GS_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t), unexpected_double_size); +#endif +/** @endcond */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/unistd.h b/gomspace/libutil/include/gs/util/unistd.h new file mode 100644 index 00000000..a8b65845 --- /dev/null +++ b/gomspace/libutil/include/gs/util/unistd.h @@ -0,0 +1,32 @@ +#ifndef GS_UTIL_UNISTD_H +#define GS_UTIL_UNISTD_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + GomSpace extensions to standard \a unistd.h. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Get current working directory. + + @note Linux uses standard getcwd(). + + @param[out] buf user supplied buffer for returning path. + @param[in] bufsize size of \a buf. + @return #GS_ERROR_NOT_FOUND if no current directory is set. + @return #GS_ERROR_RANGE if \a buf is too small + @return_gs_error_t +*/ +gs_error_t gs_getcwd(char * buf, size_t bufsize); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/vmem.h b/gomspace/libutil/include/gs/util/vmem.h new file mode 100644 index 00000000..19576a63 --- /dev/null +++ b/gomspace/libutil/include/gs/util/vmem.h @@ -0,0 +1,194 @@ +#ifndef GS_UTIL_VMEM_H +#define GS_UTIL_VMEM_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Virtual memory interface. + + The API provides support for accessing different hardware components using a common API, by providing a component specific driver. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Virtual memory mapping. +*/ +typedef struct gs_vmem gs_vmem_t; + +/** + VMEM driver write. + + @param[in] vmem vmem entry. + @param[in] to Address where to write data to. + @param[in] from Address where to write data from. + @param[in] size Number of bytes to write. + @return_gs_error_t +*/ +typedef gs_error_t (*gs_vmem_write_function_t)(const gs_vmem_t * vmem, void* to, const void * from, size_t size); + +/** + VMEM driver read. + + @param[in] vmem vmem entry. + @param[in] to Address where to read data to. + @param[in] from Address where to read data from. + @param[in] size Number of bytes to read. + @return_gs_error_t +*/ +typedef gs_error_t (*gs_vmem_read_function_t)(const gs_vmem_t * vmem, void* to, const void * from, size_t size); + +/** + VMEM driver lock. + + @param[in] vmem vmem entry. + @param[in] on Enable/Disable lock. + @return_gs_error_t +*/ +typedef gs_error_t (*gs_vmem_lock_function_t)(const gs_vmem_t * vmem, bool on); + +/** + VMEM driver information. + + Return relevant information for the VMEM driver. + + @param[in] vmem vmem entry. + @param[in] buffer user allocated buffer for returning information. + @param[in] buffer_size size (length) of \a buffer. + @return_gs_error_t +*/ +typedef gs_error_t (*gs_vmem_info_function_t)(const gs_vmem_t * vmem, char * buffer, size_t buffer_size); + +/** + VMEM driver interface. +*/ +typedef struct { + /** + Write function. + */ + const gs_vmem_write_function_t write; + /** + Read function. + */ + const gs_vmem_read_function_t read; + /** + Lock function. + */ + const gs_vmem_lock_function_t lock; + /** + Information function. + */ + const gs_vmem_info_function_t info; +} gs_vmem_driver_t; + +/** + Virtual memory mapping. + + @note Call gs_vmem_set_map() for registering mappings. +*/ +struct gs_vmem { + /** + Logical name of enry. + */ + const char *const name; + /** + Virtual memory start. + */ + gs_address_t virtmem; + /** + Physical memory start. + This address only makes sense for the VMEM driver. + */ + gs_address_t physmem; + /** + Size of memory block. + */ + const size_t size; + /** + Driver function. + */ + const gs_vmem_driver_t* drv; + /** + Driver data. + */ + const void* drv_data; +}; + +/** + Set VMEM mapping. + Must be done for the API to work. + @param[in] map VMEM mapping table, must be terminated with an NULL entry. + @return_gs_error_t +*/ +gs_error_t gs_vmem_set_map(const gs_vmem_t * map); + +/** + Return VMEM map. +*/ +const gs_vmem_t * gs_vmem_get_map(void); + +/** + Print all VMEM entries to stdout. + @param[in] out output stream + @return_gs_error_t +*/ +gs_error_t gs_vmem_list(FILE * out); + +/** + Get VMEM entry by name. + @param[in] name name of VMEM entry. + @return VMEM mapping or NULL if not found. +*/ +const gs_vmem_t * gs_vmem_get_by_name(const char * name); + +/** + Lock/un-lock VMEM area. + @param[in] name name of VMEM entry. + @param[in] on Enable/Disable lock. + @return GS_ERROR_NOT_FOUND area not found. + @return GS_ERROR_NOT_SUPPORTED if locking isn't supported. + @return_gs_error_t +*/ +gs_error_t gs_vmem_lock_by_name(const char * name, bool on); + +/** + Lock/un-lock all VMEM areas. + @param[in] on lock on or off. + @return_gs_error_t +*/ +gs_error_t gs_vmem_lock_all(bool on); + +/** + memcpy on VMEM. + @note if no VMEM entries are found, a normal memcpy is called with the provided pointers. + @param[in] to to location. + @param[in] from from location. + @param[in] size number of bytes to copy. +*/ +void* gs_vmem_cpy(void* to, const void* from, size_t size); + +/** + Macro for calling gs_vmem_cpy(). +*/ +#define GS_VMEM_CPY(to, from, size) gs_vmem_cpy(to, from, size) + +/** + Macro for calling gs_vmem_cpy(). + @deprecated Use gs_vmem_cpy() directly. +*/ +#define VMEM_CPY(to, from, size) gs_vmem_cpy(to, from, size) + +/** + Register VMEM commands. + @return_gs_error_t +*/ +gs_error_t gs_vmem_register_commands(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/watchdog/watchdog.h b/gomspace/libutil/include/gs/util/watchdog/watchdog.h new file mode 100644 index 00000000..30d2bd30 --- /dev/null +++ b/gomspace/libutil/include/gs/util/watchdog/watchdog.h @@ -0,0 +1,143 @@ +#ifndef GS_UTIL_WATCHDOG_WATCHDOG_H +#define GS_UTIL_WATCHDOG_WATCHDOG_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Software watchdog client interface. + + The software watchdog (SWWD) enables having multiple instances of a Watchdog. + The software watchdog manages the HW watchdog, and will ultimately + trigger the HW watchdog, if one or more clients are not servicing the + software watchdog. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Software Watchdog handle +*/ +typedef struct gs_swwd_hdl gs_swwd_hdl_t; + +/** + Software watchdog callback function. + + Called by the SWWD upon timeout. + @param[in] userdata user data provided on gs_swwd_register() +*/ +typedef void (*gs_swwd_callback_function_t)(void * userdata); + +/** + Watchdog timeout action. +*/ +typedef enum { + /** + Reset system on timeout (stops touching the hardware watchdog). + Once the watchdog has timeout, the watchdog cannot be re-activated. + */ + GS_SWWD_TIMEOUT_ACTION_RESET = 0, + /** + Log 'warning' on timeout, but otherwise ignore the timeout. + The watchdog can re-activated by touching the watchdog again. + */ + GS_SWWD_TIMEOUT_ACTION_LOG = 1, +} gs_swwd_timeout_action_t; + +/** + Create the software watchdog back-end. + + Only one SWWD back-end can exist at any given time. + + @param[in] max_clients The maximum number of Software Watchog clients supported. + @param[in] dev The HW Watchdog device to use. + @return_gs_error_t +*/ +gs_error_t gs_swwd_create(uint32_t max_clients, gs_watchdog_device_t *dev); + +/** + Destroy the Software Watchdog back-end (and stop the SWWD monitor task if started). + + @param[in] timeout_s Maximum number of seconds to allow this operation to complete. + @return_gs_error_t +*/ +gs_error_t gs_swwd_destroy(uint32_t timeout_s); + +/** + Check for expired software watchdog clients. This function is only to be used if the + SWWD monitor task is not started. Otherwise the SWWD task will handle this in the back- + ground. I.e: + - In passive mode this function must be called periodically to check for expired + clients, and service the HW watchdog. + - In active mode this function is called in background by the SWWD monitor task. + + The interval between these checks should be much less that the HW watchdog + timeout period, to ensure that the HW Watchdog is correctly serviced. + Calling this e.g. every 1-3 seconds will be a good default. + + @param[out] num_expired The number of SW Watchog clients currently expired. + @return_gs_error_t +*/ +gs_error_t gs_swwd_check_expired_clients(uint32_t *num_expired); + +/** + Register/create a new software watchdog instance + + @param[out] wdt_handle A reference to software watchdog handle + @param[in] timeout Timeout in seconds. + @param[in] callback Callback function which is called on timeout. NULL if unused. + @param[in] userdata Pointer to user data used in the callback function. Ignored if callback is NULL. + @param[in] client_name A descriptive name given by the user in order to identify the watchdog/client - the pointer must remain valid as long as the watchdog is registered. + @param[in] action what action to take, when/if the watchdog times out. + @return_gs_error_t +*/ +gs_error_t gs_swwd_register_with_action(gs_swwd_hdl_t ** wdt_handle, uint32_t timeout, gs_swwd_callback_function_t callback, void * userdata, const char *client_name, gs_swwd_timeout_action_t action); + +/** + Register/create a software watchdog with action \a reset on timeout. + + @param[out] wdt_handle A reference to software watchdog handle + @param[in] timeout Timeout in seconds before the software watchdog fires. + @param[in] callback Callback function which is called on timeout. NULL if unused. + @param[in] userdata Pointer to user data used in the callback function. Ignored if callback is NULL. + @param[in] client_name A descriptive name given by the user in order to identify the watchdog/client - the pointer must remain valid as long as the watchdog is registered. + @return_gs_error_t +*/ +static inline gs_error_t gs_swwd_register(gs_swwd_hdl_t ** wdt_handle, uint32_t timeout, gs_swwd_callback_function_t callback, void * userdata, const char *client_name) +{ + return gs_swwd_register_with_action(wdt_handle, timeout, callback, userdata, client_name, GS_SWWD_TIMEOUT_ACTION_RESET); +} + +/** + De-Register a Software Watchdog instance + + @param[in] wdt_handle A software watchdog handle + @return_gs_error_t +*/ +gs_error_t gs_swwd_deregister(gs_swwd_hdl_t ** wdt_handle); + +/** + Touch Software Watchdog to reset the timer + + @param[in] wdt_handle A software watchdog handle + @return_gs_error_t +*/ +gs_error_t gs_swwd_touch(gs_swwd_hdl_t * wdt_handle); + +/** + Set timeout of the Software Watchdog. + + @param[in] wdt_handle A software watchdog handle + @param[in] timeout Timeout in seconds before the SWWD fires. + @return_gs_error_t +*/ +gs_error_t gs_swwd_set_timeout(gs_swwd_hdl_t * wdt_handle, uint32_t timeout); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/watchdog/watchdog_task.h b/gomspace/libutil/include/gs/util/watchdog/watchdog_task.h new file mode 100644 index 00000000..833f1511 --- /dev/null +++ b/gomspace/libutil/include/gs/util/watchdog/watchdog_task.h @@ -0,0 +1,45 @@ +#ifndef GS_UTIL_WATCHDOG_WATCHDOG_TASK_H +#define GS_UTIL_WATCHDOG_WATCHDOG_TASK_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Software Watchdog server/task interface + + The Software Watchdog task implements the core (backend) functionality of the the software watchdog. + The Client API for the SW watchdog is implemented in watchdog.h + + @note This API is not thread safe! +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Start the Software Watchdog monitor task if the SWWD is to be used as a + separate task (active mode). + In this case the SWWD task will monitor expired clients in the background + and the polling API gs_swwd_check_expired_clients() needs not to be called by + the user. + + @return_gs_error_t +*/ + +gs_error_t gs_swwd_monitor_task_start(); + +/** + Stops the Software Watchdog monitor task + + @param[in] timeout_s Maximum number of seconds to allow this operation to complete. + + @return_gs_error_t +*/ +gs_error_t gs_swwd_monitor_task_stop(uint32_t timeout_s); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/zip/zip.h b/gomspace/libutil/include/gs/util/zip/zip.h new file mode 100644 index 00000000..04c87974 --- /dev/null +++ b/gomspace/libutil/include/gs/util/zip/zip.h @@ -0,0 +1,62 @@ +#ifndef LIBUTIL_ZIP_ZIP_UTILS_H +#define LIBUTIL_ZIP_ZIP_UTILS_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Compress/decompress API based on zlib compressed data format specification standards. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + Compress file. + + @param[in] src file to be compressed. + @param[out] dest compressed output file. + @return_gs_error_t +*/ +int gs_zip_compress_file(const char *src, const char *dest); + +/** + Decompress file. + + @param[in] src file to be secompressed. + @param[out] dest decompressed output file. + @return_gs_error_t +*/ +int gs_zip_decompress_file(const char *src, const char *dest); + +/** + Compress data. + + @param[in] src pointer to the data to be compressed. + @param[in] src_len size of the data. + @param[out] dest pointer to the compressed data. + @param[out] dest_len pointer to the size of the compressed data. + @return_gs_error_t +*/ +int gs_zip_compress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t *dest_len); + +/** + Decompress data. + + @param[in] src pointer to the data to be decompressed. + @param[in] src_len size of the data. + @param[out] dest pointer to the decompressed data. + @param[out] dest_len size of the destination memory area. + @param[out] decomp_len pointer to the size of the decompressed data. + @return_gs_error_t +*/ +int gs_zip_decompress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t dest_len, uint32_t *decomp_len); + + +#ifdef __cplusplus +} +#endif +#endif /* LIBUTIL_ZIP_ZIP_UTILS_H */ diff --git a/gomspace/libutil/src/base16.c b/gomspace/libutil/src/base16.c new file mode 100644 index 00000000..da3a83c6 --- /dev/null +++ b/gomspace/libutil/src/base16.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010 Michael Brown . + * + * This program 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 2 of the + * License, or any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +void base16_encode(const uint8_t * raw, size_t len, char *encoded) +{ + const uint8_t *raw_bytes = raw; + char *encoded_bytes = encoded; + size_t remaining = len; + + for (; remaining--; encoded_bytes += 2) + snprintf(encoded_bytes, 3, "%02X", *(raw_bytes++)); + +} + +int base16_decode(const char *encoded, uint8_t *raw) +{ + uint8_t *raw_bytes = raw; + if (encoded) { + const char *encoded_bytes = encoded; + char buf[3]; + char *endp; + + while (encoded_bytes[0]) { + if (!encoded_bytes[1]) { + log_error("Base16-encoded string \"%s\" has invalid length\n", + encoded); + return GS_ERROR_ARG; + } + memcpy(buf, encoded_bytes, 2); + buf[2] = '\0'; + *(raw_bytes++) = (uint8_t) strtoul(buf, &endp, 16); + if (*endp != '\0') { + log_error("Base16-encoded string \"%s\" has invalid byte \"%s\"\n", + encoded, buf); + return GS_ERROR_ARG; + } + encoded_bytes += 2; + } + } + return (int)(raw_bytes - raw); +} diff --git a/gomspace/libutil/src/bindings/python/pyutil.c b/gomspace/libutil/src/bindings/python/pyutil.c new file mode 100644 index 00000000..b2924ba6 --- /dev/null +++ b/gomspace/libutil/src/bindings/python/pyutil.c @@ -0,0 +1,73 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +#if PY_MAJOR_VERSION == 3 +#define IS_PY3 +#endif + +/** + * Helpers + */ + +static PyObject* pyutil_get_clock_time(PyObject *self, PyObject *args) { + gs_timestamp_t ts; + gs_clock_get_time(&ts); + return Py_BuildValue("II", ts.tv_sec, ts.tv_nsec); +} + + +static PyObject* pyutil_error_string(PyObject *self, PyObject *args) +{ + int error; + if (!PyArg_ParseTuple(args, "i", &error)) + { + Py_RETURN_NONE; + } + return Py_BuildValue("s", gs_error_string(error)); +} + +static PyMethodDef methods[] = { + + /* helpers */ + {"get_clock_time", pyutil_get_clock_time, METH_NOARGS, ""}, + {"error_string", pyutil_error_string, METH_VARARGS, ""}, + + /* sentinel */ + {NULL, NULL, 0, NULL} +}; + +#ifdef IS_PY3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "libgsutil_py3", + NULL, /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, + or -1 if the module keeps state in global variables. */ + methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +#ifdef IS_PY3 +PyMODINIT_FUNC PyInit_libgsutil_py3(void) { +#else +PyMODINIT_FUNC initlibgsutil_py2(void) { +#endif + +#ifdef IS_PY3 + PyObject* m = PyModule_Create(&moduledef); +#else + Py_InitModule("libgsutil_py2", methods); +#endif + +#ifdef IS_PY3 + return m; +#endif +} + diff --git a/gomspace/libutil/src/bytebuffer.c b/gomspace/libutil/src/bytebuffer.c new file mode 100644 index 00000000..49b5a495 --- /dev/null +++ b/gomspace/libutil/src/bytebuffer.c @@ -0,0 +1,128 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +#define GS_BYTEBUFFER_F_FAILED 0x01 +#define GS_BYTEBUFFER_F_OVERRUN 0x02 + +gs_error_t gs_bytebuffer_init(gs_bytebuffer_t * bb, void * buffer, size_t buffer_size) +{ + GS_CHECK_HANDLE(bb != NULL); + memset(bb, 0, sizeof(*bb)); + if (buffer) { + if (buffer_size < 2) { + // must always have room for NUL termination. + return GS_ERROR_ARG; + } + bb->buffer = buffer; + bb->size = buffer_size; + } else { + // dry run - don't insert anything in buffer, but increment used + } + + return GS_OK; +} + +void gs_bytebuffer_vprintf(gs_bytebuffer_t * bb, const char * format, va_list ap) +{ + int res; + if (bb->buffer == NULL) { + // dry run + char buf[3]; + res = vsnprintf(buf, 0, format, ap); + if (res >= 0) { + bb->used += res; + } + } else { + const size_t free_bytes = gs_bytebuffer_get_free(bb); + res = vsnprintf((char*)&bb->buffer[bb->used], free_bytes, format, ap); + if (res > 0) { + if ((size_t)res >= free_bytes) { + // over run + bb->flags |= GS_BYTEBUFFER_F_OVERRUN; + bb->used = bb->size; + bb->buffer[bb->size - 1] = 0; + } else { + bb->used += res; + } + } + } + if (res < 0) { + bb->flags |= GS_BYTEBUFFER_F_FAILED; + } +} + +void gs_bytebuffer_printf(gs_bytebuffer_t * bb, const char * format, ...) +{ + va_list ap; + va_start(ap, format); + gs_bytebuffer_vprintf(bb, format, ap); + va_end(ap); +} + +void gs_bytebuffer_append(gs_bytebuffer_t * bb, const void * data, size_t length) +{ + if (bb->buffer == NULL) { + // dry run + bb->used += length; + } else { + const size_t free_bytes = gs_bytebuffer_get_free(bb); + if (free_bytes >= length) { + memcpy(&bb->buffer[bb->used], data, length); + bb->used += length; + } else { + memcpy(&bb->buffer[bb->used], data, free_bytes); + bb->flags |= GS_BYTEBUFFER_F_OVERRUN; + bb->used += free_bytes; + } + } +} + +void gs_bytebuffer_append_string(gs_bytebuffer_t * bb, const char * string) +{ + if (gs_string_empty(string) == false) { + gs_bytebuffer_append(bb, string, strlen(string)); + } +} + +void gs_bytebuffer_append_string_max(gs_bytebuffer_t * bb, const char * string, size_t max_length) +{ + if (gs_string_empty(string) == false) { + gs_bytebuffer_append(bb, string, strnlen(string, max_length)); + } +} + +char * gs_bytebuffer_get_as_string(gs_bytebuffer_t * bb, gs_error_t * error) +{ + if (bb && bb->buffer) { + // handle NUL termination + if (bb->used < bb->size) { + bb->buffer[bb->used] = 0; + } else { + // overrun - truncation buffer + bb->flags |= GS_BYTEBUFFER_F_OVERRUN; + bb->buffer[bb->used - 1] = 0; + } + if (error) { + *error = gs_bytebuffer_get_state(bb); + } + return (char*) bb->buffer; + } + return NULL; +} + +gs_error_t gs_bytebuffer_get_state(gs_bytebuffer_t * bb) +{ + if (bb) { + if (bb->flags & GS_BYTEBUFFER_F_FAILED) { + return GS_ERROR_DATA; + } + if (bb->flags & GS_BYTEBUFFER_F_OVERRUN) { + return GS_ERROR_OVERFLOW; + } + return GS_OK; + } + return GS_ERROR_HANDLE; +} diff --git a/gomspace/libutil/src/byteorder.c b/gomspace/libutil/src/byteorder.c new file mode 100644 index 00000000..e00c9737 --- /dev/null +++ b/gomspace/libutil/src/byteorder.c @@ -0,0 +1,323 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include + +/* Convert 16-bit number from host byte order to network byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_hton16(uint16_t h16) { +#if UTIL_BIG_ENDIAN + return h16; + +#elif UTIL_LITTLE_ENDIAN + return (uint16_t)(((h16 & 0xff00) >> 8) | + ((h16 & 0x00ff) << 8)); +#endif +} + +/* Convert 16-bit number from network byte order to host byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_ntoh16(uint16_t n16) { + return util_hton16(n16); +} + +/* Convert 32-bit number from host byte order to network byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_hton32(uint32_t h32) { +#if UTIL_BIG_ENDIAN + return h32; + +#elif UTIL_LITTLE_ENDIAN + return (((h32 & 0xff000000) >> 24) | + ((h32 & 0x000000ff) << 24) | + ((h32 & 0x0000ff00) << 8) | + ((h32 & 0x00ff0000) >> 8)); +#endif +} + +/* Convert 32-bit number from network byte order to host byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_ntoh32(uint32_t n32) { + return util_hton32(n32); +} + +/* Convert 64-bit number from host byte order to network byte order */ +extern inline uint64_t __attribute__ ((__const__)) util_hton64(uint64_t h64) { +#if UTIL_BIG_ENDIAN + return h64; + +#elif UTIL_LITTLE_ENDIAN + return (((h64 & 0xff00000000000000LL) >> 56) | + ((h64 & 0x00000000000000ffLL) << 56) | + ((h64 & 0x00ff000000000000LL) >> 40) | + ((h64 & 0x000000000000ff00LL) << 40) | + ((h64 & 0x0000ff0000000000LL) >> 24) | + ((h64 & 0x0000000000ff0000LL) << 24) | + ((h64 & 0x000000ff00000000LL) >> 8) | + ((h64 & 0x00000000ff000000LL) << 8)); +#endif +} + +/* Convert 64-bit number from host byte order to network byte order */ +extern inline uint64_t __attribute__ ((__const__)) util_ntoh64(uint64_t n64) { + return util_hton64(n64); +} + +/* Convert float from host byte order to network byte order */ +extern inline float __attribute__ ((__const__)) util_htonflt(float f) { +#if UTIL_BIG_ENDIAN + return f; + +#elif UTIL_LITTLE_ENDIAN + union v { + float f; + uint32_t i; + }; + union v val; + val.f = f; + val.i = util_hton32(val.i); + return val.f; +#endif +} + +/* Convert float from host byte order to network byte order */ +extern inline float __attribute__ ((__const__)) util_ntohflt(float f) { + return util_htonflt(f); +} + +/* Convert double from host byte order to network byte order */ +extern inline double __attribute__ ((__const__)) util_htondbl(double d) { +#if UTIL_BIG_ENDIAN + return d; + +#elif UTIL_LITTLE_ENDIAN + union v { + double d; + uint64_t i; + }; + union v val; + val.d = d; + val.i = util_hton64(val.i); + return val.d; +#endif +} + +/* Convert float from host byte order to network byte order */ +extern inline double __attribute__ ((__const__)) util_ntohdbl(double d) { + return util_htondbl(d); +} + +/* Convert 16-bit number from host byte order to big endian byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_htobe16(uint16_t h16) { + return util_hton16(h16); +} + +/* Convert 16-bit number from host byte order to little endian byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_htole16(uint16_t h16) { +#if UTIL_LITTLE_ENDIAN + return h16; + +#elif UTIL_BIG_ENDIAN + return (uint16_t)(((h16 & 0xff00) >> 8) | + ((h16 & 0x00ff) << 8)); +#endif +} + +/* Convert 16-bit number from big endian byte order to little endian byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_betoh16(uint16_t be16) { + return util_ntoh16(be16); +} + +/* Convert 16-bit number from little endian byte order to host byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_letoh16(uint16_t le16) { + return util_htole16(le16); +} + +/* Convert 32-bit number from host byte order to big endian byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_htobe32(uint32_t h32) { + return util_hton32(h32); +} + +/* Convert 32-bit number from little endian byte order to host byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_htole32(uint32_t h32) { +#if UTIL_LITTLE_ENDIAN + return h32; + +#elif UTIL_BIG_ENDIAN + return (((h32 & 0xff000000) >> 24) | + ((h32 & 0x000000ff) << 24) | + ((h32 & 0x0000ff00) << 8) | + ((h32 & 0x00ff0000) >> 8)); +#endif +} + +/* Convert 32-bit number from big endian byte order to host byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_betoh32(uint32_t be32) { + return util_ntoh32(be32); +} + +/* Convert 32-bit number from little endian byte order to host byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_letoh32(uint32_t le32) { + return util_htole32(le32); +} + +/* Convert 64-bit number from host byte order to big endian byte order */ +extern inline uint64_t __attribute__ ((__const__)) util_htobe64(uint64_t h64) { + return util_hton64(h64); +} + +/* Convert 64-bit number from host byte order to little endian byte order */ +extern inline uint64_t __attribute__ ((__const__)) util_htole64(uint64_t h64) { +#if UTIL_LITTLE_ENDIAN + return h64; + +#elif UTIL_BIG_ENDIAN + return (((h64 & 0xff00000000000000LL) >> 56) | + ((h64 & 0x00000000000000ffLL) << 56) | + ((h64 & 0x00ff000000000000LL) >> 40) | + ((h64 & 0x000000000000ff00LL) << 40) | + ((h64 & 0x0000ff0000000000LL) >> 24) | + ((h64 & 0x0000000000ff0000LL) << 24) | + ((h64 & 0x000000ff00000000LL) >> 8) | + ((h64 & 0x00000000ff000000LL) << 8)); +#endif +} + +/* Convert 64-bit number from big endian byte order to host byte order */ +extern inline uint64_t __attribute__ ((__const__)) util_betoh64(uint64_t be64) { + return util_ntoh64(be64); +} + +/* Convert 64-bit number from little endian byte order to host byte order */ +extern inline uint64_t __attribute__ ((__const__)) util_letoh64(uint64_t le64) { + return util_htole64(le64); +} + +/* Convert 16-bit number from host byte order to network byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_htons(uint16_t h16) { + return util_hton16(h16); +} + +/* Convert 16-bit number from network byte order to host byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_ntohs(uint16_t n16) { + return util_ntoh16(n16); +} + +/* Convert 32-bit number from host byte order to network byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_htonl(uint32_t h32) { + return util_hton32(h32); +} + +/* Convert 32-bit number from network byte order to host byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_ntohl(uint32_t n32) { + return util_ntoh32(n32); +} + +#define BYTEORDER_ARRAY(convert, from, to, count) { \ + for (unsigned int i = 0; i < count; ++i, ++from, ++to) { \ + *to = convert(*from); \ + } \ + } + +void util_hton16_array(const uint16_t * from, uint16_t * to, size_t count) +{ + BYTEORDER_ARRAY(util_hton16, from, to, count); +} + +void util_hton32_array(const uint32_t * from, uint32_t * to, size_t count) +{ + BYTEORDER_ARRAY(util_hton32, from, to, count); +} + +void util_hton64_array(const uint64_t * from, uint64_t * to, size_t count) +{ + BYTEORDER_ARRAY(util_hton64, from, to, count); +} + +void util_ntoh16_array(const uint16_t * from, uint16_t * to, size_t count) +{ + BYTEORDER_ARRAY(util_ntoh16, from, to, count); +} + +void util_ntoh32_array(const uint32_t * from, uint32_t * to, size_t count) +{ + BYTEORDER_ARRAY(util_ntoh32, from, to, count); +} + +void util_ntoh64_array(const uint64_t * from, uint64_t * to, size_t count) +{ + BYTEORDER_ARRAY(util_ntoh64, from, to, count); +} + +void util_htonflt_array(const float * from, float * to, size_t count) +{ + BYTEORDER_ARRAY(util_htonflt, from, to, count); +} + +void util_ntohflt_array(const float * from, float * to, size_t count) +{ + BYTEORDER_ARRAY(util_ntohflt, from, to, count); +} + +void util_htondbl_array(const double * from, double * to, size_t count) +{ + BYTEORDER_ARRAY(util_htondbl, from, to, count); +} + +void util_ntohdbl_array(const double * from, double * to, size_t count) +{ + BYTEORDER_ARRAY(util_ntohdbl, from, to, count); +} + +uint16_t gs_bswap_16(uint16_t value) +{ + return (uint16_t)(((value & 0xff00) >> 8) | + ((value & 0x00ff) << 8)); +} + +void gs_bswap_16_array(const uint16_t * from, uint16_t * to, size_t count) +{ + BYTEORDER_ARRAY(gs_bswap_16, from, to, count); +} + +uint32_t gs_bswap_32(uint32_t value) +{ + return (((value & 0xff000000) >> 24) | + ((value & 0x000000ff) << 24) | + ((value & 0x0000ff00) << 8) | + ((value & 0x00ff0000) >> 8)); +} + +void gs_bswap_32_array(const uint32_t * from, uint32_t * to, size_t count) +{ + BYTEORDER_ARRAY(gs_bswap_32, from, to, count); +} + +uint64_t gs_bswap_64(uint64_t value) +{ + return (((value & 0xff00000000000000LL) >> 56) | + ((value & 0x00000000000000ffLL) << 56) | + ((value & 0x00ff000000000000LL) >> 40) | + ((value & 0x000000000000ff00LL) << 40) | + ((value & 0x0000ff0000000000LL) >> 24) | + ((value & 0x0000000000ff0000LL) << 24) | + ((value & 0x000000ff00000000LL) >> 8) | + ((value & 0x00000000ff000000LL) << 8)); +} + +void gs_bswap_64_array(const uint64_t * from, uint64_t * to, size_t count) +{ + BYTEORDER_ARRAY(gs_bswap_64, from, to, count); +} + +float gs_bswap_float(float value) +{ + union v { + float f; + uint32_t i; + } val; + val.f = value; + val.i = gs_bswap_32(val.i); + return val.f; +} + +void gs_bswap_float_array(const float * from, float * to, size_t count) +{ + BYTEORDER_ARRAY(gs_bswap_float, from, to, count); +} diff --git a/gomspace/libutil/src/clock.c b/gomspace/libutil/src/clock.c new file mode 100644 index 00000000..ac215df6 --- /dev/null +++ b/gomspace/libutil/src/clock.c @@ -0,0 +1,113 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include + +#if !__AVR__ +#include +#endif + +gs_error_t gs_clock_to_iso8601_string2(uint32_t utc_sec, char * buf, size_t buf_size) +{ + if ((buf == NULL) || (buf_size == 0)) { + return GS_ERROR_ARG; + } + +#if __AVR__ + int res = snprintf(buf, buf_size, "%"PRIu32"Z", utc_sec); + if ((res < 0) || ((size_t)res >= buf_size)) { + buf[buf_size - 1] = 0; + return GS_ERROR_RANGE; + } +#else + const time_t time_seconds = (time_t) utc_sec; + struct tm tm_buf; + struct tm * tm = gmtime_r(&time_seconds, &tm_buf); + if (tm == NULL) { + int res = snprintf(buf, buf_size, "%ldZ", time_seconds); + if ((res < 0) || ((size_t)res >= buf_size)) { + buf[buf_size - 1] = 0; + } + return GS_ERROR_DATA; + } + + // ISO8601 timestamp: 2017-03-30T06:20:45Z + int res = snprintf(buf, buf_size, "%04d-%02d-%02dT%02d:%02d:%02dZ", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + if ((res < 0) || ((size_t)res >= buf_size)) { + buf[buf_size - 1] = 0; + return GS_ERROR_RANGE; + } +#endif + + return GS_OK; +} + +gs_error_t gs_clock_to_iso8601_string(const gs_timestamp_t * utc_time, char * buf, size_t buf_size) +{ + if (utc_time == NULL) { + return GS_ERROR_ARG; + } + + return gs_clock_to_iso8601_string2(utc_time->tv_sec, buf, buf_size); +} + +gs_error_t gs_clock_from_string(const char * str, gs_timestamp_t * ts) +{ + if (!str || !str[0] || !ts) { + return GS_ERROR_ARG; + } + + // check for . + { + uint32_t sec; + uint32_t nsec; + int res = sscanf(str, "%" SCNu32 ".%" SCNu32, &sec, &nsec); + if (res == 2) { + ts->tv_sec = sec; + ts->tv_nsec = nsec; + return GS_OK; + } + } + +#if !__AVR__ + // check for ISO8601 + { + struct tm tm; + memset(&tm, 0, sizeof(tm)); // no daylight saving + //int res = sscanf(str, "%" SCNd32 "-%" SCNd32 "-%" SCNd32 "T%" SCNd32 ":%" SCNd32 ":%" SCNd32 "Z", + int res = sscanf(str, "%d-%d-%dT%d:%d:%dZ", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec); + if ((res == 6) && + (tm.tm_year >= 1970) && (tm.tm_year <= 2038) && + (tm.tm_mon >= 1) && (tm.tm_mon <= 12) && + (tm.tm_mday >= 1) && (tm.tm_mday <= 31) && + (tm.tm_hour >= 0) && (tm.tm_hour <= 23) && + (tm.tm_min >= 0) && (tm.tm_min <= 59) && + (tm.tm_sec >= 0) && (tm.tm_sec <= 60)) + { + tm.tm_year -= 1900; + tm.tm_mon -= 1; + +#if __linux__ + // not posix compliant + time_t sec = timegm(&tm); +#else + // embedded platforms do not have timezones/daylight-saving - so standard mktime works + time_t sec = mktime(&tm); +#endif + if (sec >= 0) { + ts->tv_sec = (uint32_t) sec; + ts->tv_nsec = 0; + return GS_OK; + } + } + } +#endif + + return GS_ERROR_DATA; +} diff --git a/gomspace/libutil/src/crc32.c b/gomspace/libutil/src/crc32.c new file mode 100644 index 00000000..90d21832 --- /dev/null +++ b/gomspace/libutil/src/crc32.c @@ -0,0 +1,79 @@ +/* + * efone - Distributed internet phone system. + * + * (c) 1999,2000 Krzysztof Dabrowski + * (c) 1999,2000 ElysiuM deeZine + * + * This program 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 + * 2 of the License, or (at your option) any later version. + * + * Based on implementation by Finn Yannick Jacobs + */ + +#include +#include + +static const uint32_t crc_tab[256] GS_PGM_OBJECT = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +#define CALC_CRC32_STEP(crc,byte) (((crc >> 8) & 0x00FFFFFF) ^ GS_PGM_UINT32_BY_PTR(&crc_tab[(crc ^ byte) & (uint32_t) 0xFF])) + +uint32_t gs_crc32_init(void) +{ + return 0xFFFFFFFF; +} + +uint32_t gs_crc32_update(uint32_t crc, const void * block, size_t length) +{ + if (block && length) { + const uint8_t * u8 = block; + for (unsigned int i = 0; i < length; i++) { + crc = CALC_CRC32_STEP(crc, *u8++); + } + } + return crc; +} + +uint32_t gs_crc32_finalize(uint32_t crc) +{ + return (crc ^ 0xFFFFFFFF); +} + +uint32_t gs_crc32(const void * block, size_t length) +{ + return gs_crc32_finalize(gs_crc32_update(gs_crc32_init(), block, length)); +} diff --git a/gomspace/libutil/src/crc8.c b/gomspace/libutil/src/crc8.c new file mode 100644 index 00000000..aa810b31 --- /dev/null +++ b/gomspace/libutil/src/crc8.c @@ -0,0 +1,68 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +static const uint8_t crc_tab[256] GS_PGM_OBJECT = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, + 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, + 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, + 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, + 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, + 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, + 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, + 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, + 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, + 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, + 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, + 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, + 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, + 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, + 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, + 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, + 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, + 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 +}; + + +#define CALC_CRC8_STEP(crc,byte) ((crc >> 8) ^ GS_PGM_UINT8_BY_PTR(&crc_tab[(crc ^ byte) & (uint8_t) 0xFF])) + +uint8_t gs_crc8_init(void) +{ + return 0xFF; +} + +uint8_t gs_crc8_update(uint8_t crc, const void * block, size_t length) +{ + if (block && length) { + const uint8_t * u8 = block; + for (unsigned int i = 0; i < length; i++) { + crc = CALC_CRC8_STEP(crc, *u8++); + } + } + return crc; +} + +uint8_t gs_crc8_finalize(uint8_t crc) +{ + return (crc ^ 0x00); +} + +uint8_t gs_crc8(const void * block, size_t length) +{ + return gs_crc8_finalize(gs_crc8_update(gs_crc8_init(), block, length)); +} diff --git a/gomspace/libutil/src/drivers/can/can.c b/gomspace/libutil/src/drivers/can/can.c new file mode 100644 index 00000000..c08eaddb --- /dev/null +++ b/gomspace/libutil/src/drivers/can/can.c @@ -0,0 +1,6 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +// deifne common log group. +GS_LOG_GROUP(gs_can_log, "can", GS_LOG_CAT_DRIVER, GS_LOG_DEFAULT_MASK); diff --git a/gomspace/libutil/src/drivers/i2c/i2c.c b/gomspace/libutil/src/drivers/i2c/i2c.c new file mode 100644 index 00000000..acd9e60e --- /dev/null +++ b/gomspace/libutil/src/drivers/i2c/i2c.c @@ -0,0 +1,6 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +// define common log group. +GS_LOG_GROUP(gs_i2c_log, "i2c", GS_LOG_CAT_DRIVER, GS_LOG_DEFAULT_MASK); diff --git a/gomspace/libutil/src/drivers/spi/spi.c b/gomspace/libutil/src/drivers/spi/spi.c new file mode 100644 index 00000000..eea8153a --- /dev/null +++ b/gomspace/libutil/src/drivers/spi/spi.c @@ -0,0 +1,6 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +// define common log group. +GS_LOG_GROUP(gs_spi_log, "spi", GS_LOG_CAT_DRIVER, GS_LOG_DEFAULT_MASK); diff --git a/gomspace/libutil/src/drivers/sys/memory.c b/gomspace/libutil/src/drivers/sys/memory.c new file mode 100644 index 00000000..365dcf4a --- /dev/null +++ b/gomspace/libutil/src/drivers/sys/memory.c @@ -0,0 +1,37 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +static const char * long_to_string(char * buf, size_t buf_size, long lvalue) +{ + if (lvalue >= 0) { + snprintf(buf, buf_size, "%ld", lvalue); + return buf; + } + return "Unknown"; +} + +gs_error_t gs_mem_get_ram_stat(gs_mem_ram_type_t type, gs_mem_ram_stat_t * ram_stat) +{ + if (type == GS_MEM_RAM_TYPE_INTERNAL) { + return gs_mem_get_int_ram_stat(ram_stat); + } else if (type == GS_MEM_RAM_TYPE_EXTERNAL) { + return gs_mem_get_ext_ram_stat(ram_stat); + } + + /* Unsupported memory type */ + return GS_ERROR_NOT_SUPPORTED; +} + +gs_error_t gs_mem_print_ram_stat(gs_mem_ram_stat_t * ram_stat, FILE * out) +{ + GS_CHECK_ARG(ram_stat != NULL); + char buf[20]; + + fprintf(out, "Total: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->total)); + fprintf(out, "Max available: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->max_available)); + fprintf(out, "Min available: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->min_available)); + fprintf(out, "Available: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->available)); + return GS_OK; +} diff --git a/gomspace/libutil/src/error.c b/gomspace/libutil/src/error.c new file mode 100644 index 00000000..57e42abd --- /dev/null +++ b/gomspace/libutil/src/error.c @@ -0,0 +1,106 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#define GS_UTIL_DEPRECATED_ERROR_CODES 1 + +#include +#include +#include +#include + +#ifdef __AVR__ +const char * gs_error_string(int error) +{ + /** + avr: const strings are not automatically stored in program space (see gs/util/pgm.h), and if stored + in program space, they require special formatting in logs (i.e. "%S"). + So we settle for simple error string, with the error nnumber - no need to change log/(s)printf etc. + @note: solution is not 100% thread/task safe. + */ + static char buffer[15]; // large enough to always keep zero termination, due to no thread/task lock + snprintf(buffer, sizeof(buffer), "%d", error); + return buffer; +} +#else +const char * gs_error_string(int error) +{ + switch (error) { + case GS_OK: return "GS_OK(0)"; + case GS_ERROR_PERM: return GS_DEF2STRING(GS_ERROR_PERM) "(-1)"; + case GS_ERROR_INTR: return GS_DEF2STRING(GS_ERROR_INTR) "(-4)"; + case GS_ERROR_IO: return GS_DEF2STRING(GS_ERROR_IO) "(-5)"; + case GS_ERROR_AGAIN: return GS_DEF2STRING(GS_ERROR_AGAIN) "(-11)"; + case GS_ERROR_ALLOC: return GS_DEF2STRING(GS_ERROR_ALLOC) "(-12)"; + case GS_ERROR_ACCESS: return GS_DEF2STRING(GS_ERROR_ACCESS) "(-13)"; + case GS_ERROR_BUSY: return GS_DEF2STRING(GS_ERROR_BUSY) "(-16)"; + case GS_ERROR_EXIST: return GS_DEF2STRING(GS_ERROR_EXIST) "(-17)"; + case GS_ERROR_ARG: return GS_DEF2STRING(GS_ERROR_ARG) "(-22)"; + case GS_ERROR_NOT_IMPLEMENTED: return GS_DEF2STRING(GS_ERROR_NOT_IMPLEMENTED) "(-38)"; + case GS_ERROR_OVERFLOW: return GS_DEF2STRING(GS_ERROR_OVERFLOW) "(-75)"; + case GS_ERROR_NOT_SUPPORTED: return GS_DEF2STRING(GS_ERROR_NOT_SUPPORTED) "(-95)"; + case GS_ERROR_IN_USE: return GS_DEF2STRING(GS_ERROR_IN_USE) "(-98)"; + case GS_ERROR_CONNECTION_RESET: return GS_DEF2STRING(GS_ERROR_CONNECTION_RESET) "(-104)"; + case GS_ERROR_NO_BUFFERS: return GS_DEF2STRING(GS_ERROR_NO_BUFFERS) "(-105)"; + case GS_ERROR_TIMEOUT: return GS_DEF2STRING(GS_ERROR_TIMEOUT) "(-110)"; + case GS_ERROR_ALREADY_IN_PROGRESS: return GS_DEF2STRING(GS_ERROR_ALREADY_IN_PROGRESS) "(-114)"; + + case GS_ERROR_HANDLE: return GS_DEF2STRING(GS_ERROR_HANDLE) "(-2000)"; + case GS_ERROR_NOT_FOUND: return GS_DEF2STRING(GS_ERROR_NOT_FOUND) "(-2001)"; + case GS_ERROR_FULL: return GS_DEF2STRING(GS_ERROR_FULL) "(-2002)"; + case GS_ERROR_RANGE: return GS_DEF2STRING(GS_ERROR_RANGE) "(-2003)"; + case GS_ERROR_DATA: return GS_DEF2STRING(GS_ERROR_DATA) "(-2004)"; + case GS_ERROR_UNKNOWN: return GS_DEF2STRING(GS_ERROR_UNKNOWN) "(-2005)"; + case GS_ERROR_NO_DATA: return GS_DEF2STRING(GS_ERROR_NO_DATA) "(-2006)"; + case GS_ERROR_STALE: return GS_DEF2STRING(GS_ERROR_STALE) "(-2007)"; + case GS_ERROR_TYPE: return GS_DEF2STRING(GS_ERROR_TYPE) "(-2008)"; + case GS_ERROR_AMBIGUOUS: return GS_DEF2STRING(GS_ERROR_AMBIGUOUS) "(-2009)"; + case GS_ERROR_STATE: return GS_DEF2STRING(GS_ERROR_STATE) "(-2010)"; + } + + // as fallback we use standard POSIX error string + const int posix_error = abs(error); + return strerror(posix_error); +} +#endif + +gs_error_t gs_error(int error) +{ + return (abs(error) * -1); +} + +#ifndef __AVR__ +const char * error_string(int code) +{ + switch (code) { + case E_NO_ERR: + return "No error"; + case E_NO_DEVICE: + return "No device"; + case E_MALLOC_FAIL: + return "Malloc fail"; + case E_THREAD_FAIL: + return "Thread failure"; + case E_NO_QUEUE: + return "No such queue"; + case E_INVALID_BUF_SIZE: + return "Invalid buffer size"; + case E_INVALID_PARAM: + return "Invalid paramater"; + case E_NO_SS: + return "No such subsystem"; + case E_GARBLED_BUFFER: + return "Rubbish in buffer"; + case E_FLASH_ERROR: + return "FLASH error"; + case E_BOOT_SER: + return "Thread boot fail: serial driver"; + case E_BOOT_DEBUG: + return "Thread boot fail: debug console"; + case E_BOOT_FLASH: + return "Thread boot fail: flash driver"; + case E_NO_BUFFER: + return "No buffer"; + default: + return "Unknown error"; + } +} +#endif diff --git a/gomspace/libutil/src/fletcher.c b/gomspace/libutil/src/fletcher.c new file mode 100644 index 00000000..a9dab265 --- /dev/null +++ b/gomspace/libutil/src/fletcher.c @@ -0,0 +1,77 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +uint16_t gs_fletcher16_memcpy(const void * data_in, size_t count, void * (*memcpyfcn)(void *, const void *, size_t)) +{ + if (memcpyfcn == NULL) { + memcpyfcn = &memcpy; + } + + uint16_t sum1 = 0; + uint16_t sum2 = 0; + + if (data_in && count) { + const uint8_t * data = data_in; + for (unsigned int idx = 0; idx < count; ++idx) { + uint8_t byte; + (*memcpyfcn)(&byte, &data[idx], 1); + sum1 = (uint16_t)((sum1 + byte) % 255); + sum2 = (uint16_t)((sum2 + sum1) % 255); + } + } + return (uint16_t)((sum2 << 8) | sum1); +} + +uint16_t gs_fletcher16_P(const void * data_in, size_t count) +{ + uint16_t sum1 = 0; + uint16_t sum2 = 0; + + if (data_in && count) { + const uint8_t * data = data_in; + for (unsigned int idx = 0; idx < count; ++idx) { + sum1 = (uint16_t)((sum1 + GS_PGM_UINT8_BY_PTR(data++)) % 255); + sum2 = (uint16_t)((sum2 + sum1) % 255); + } + } + return (uint16_t)((sum2 << 8) | sum1); +} + +uint16_t gs_fletcher16(const void * data_in, size_t size) +{ + uint16_t sum1 = 0; + uint16_t sum2 = 0; + + if (data_in && size) { + const uint8_t * data = data_in; + for (unsigned int idx = 0; idx < size; ++idx) { + sum1 = (uint16_t)((sum1 + (*data++)) % 255); + sum2 = (uint16_t)((sum2 + sum1) % 255); + } + } + return (uint16_t)((sum2 << 8) | sum1); +} + +void gs_fletcher16_init(gs_fletcher16_t * f16) +{ + f16->sum1 = f16->sum2 = 0; +} + +void gs_fletcher16_update(gs_fletcher16_t * f16, const void * data_in, size_t size) +{ + if (f16 && data_in && size) { + const uint8_t * data = data_in; + for (unsigned int idx = 0; idx < size; ++idx) { + f16->sum1 = (uint16_t)((f16->sum1 + (*data++)) % 255); + f16->sum2 = (uint16_t)((f16->sum2 + f16->sum1) % 255); + } + } +} + +uint16_t gs_fletcher16_finalize(gs_fletcher16_t * f16) +{ + return (uint16_t)((f16->sum2 << 8) | f16->sum1); +} diff --git a/gomspace/libutil/src/function_scheduler.c b/gomspace/libutil/src/function_scheduler.c new file mode 100644 index 00000000..a89c8db2 --- /dev/null +++ b/gomspace/libutil/src/function_scheduler.c @@ -0,0 +1,111 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include + +#include +#include +#include +#include +#include +#include + +typedef struct { + // function to call + gs_function_scheduler_function_t function; + // function's user data + void * user_data; + // timeout in mS + uint32_t timeout_ms; + // last execution time in mS + uint32_t last_exec_ms; +} gs_function_scheduler_entry_t; + +struct gs_function_scheduler { + // Max timeout in mS + uint32_t max_timeout_ms; + // allocated entries + unsigned int max_entries; + // entries + gs_function_scheduler_entry_t * entries; +}; + +GS_CHECK_STATIC_ASSERT(sizeof(int) >= 2, int_must_be_at_least_16bit); + +gs_error_t gs_function_scheduler_create(uint32_t max_timeout_ms, unsigned int max_entries, gs_function_scheduler_t ** return_scheduler) +{ + GS_CHECK_ARG(max_timeout_ms <= INT_MAX); + GS_CHECK_ARG(max_entries > 0); + GS_CHECK_ARG(return_scheduler != NULL); + + gs_function_scheduler_entry_t * entries = calloc(max_entries, sizeof(*entries)); + if (entries == NULL) { + return GS_ERROR_ALLOC; + } + + gs_function_scheduler_t * scheduler = calloc(1, sizeof(*scheduler)); + if (scheduler == NULL) { + free (entries); + return GS_ERROR_ALLOC; + } + + scheduler->max_timeout_ms = max_timeout_ms; + scheduler->entries = entries; + scheduler->max_entries = max_entries; + + *return_scheduler = scheduler; + + return GS_OK; +} + +gs_error_t gs_function_scheduler_destroy(gs_function_scheduler_t * scheduler) +{ + GS_CHECK_HANDLE(scheduler); + free(scheduler->entries); + free(scheduler); + return GS_OK; +} + +gs_error_t gs_function_scheduler_register_ms(gs_function_scheduler_t * scheduler, + uint32_t first_timeout_ms, gs_function_scheduler_function_t func, void * user_data) +{ + GS_CHECK_HANDLE(scheduler != NULL); + GS_CHECK_ARG(func != NULL); + + gs_function_scheduler_entry_t * entry = scheduler->entries; + for (unsigned int i = 0; i < scheduler->max_entries; ++i, ++entry) { + if (entry->function == NULL) { + entry->function = func; + entry->user_data = user_data; + entry->timeout_ms = first_timeout_ms; + entry->last_exec_ms = gs_time_rel_ms(); + return GS_OK; + } + } + + return GS_ERROR_FULL; +} + +int gs_function_scheduler_execute_ms(gs_function_scheduler_t * scheduler) +{ + uint32_t timeout_ms = 5000; // max timeout to ensure gs_time_rel_ms() works correctly (wrapping more than once is bad) + + if (scheduler) { + timeout_ms = scheduler->max_timeout_ms; + uint32_t now_ms = gs_time_rel_ms(); + + gs_function_scheduler_entry_t * entry = scheduler->entries; + for (unsigned int i = 0; i < scheduler->max_entries; ++i, ++entry) { + if (entry->function) { + uint32_t elapsed = gs_time_diff_ms(entry->last_exec_ms, now_ms); + if (elapsed >= entry->timeout_ms) { + entry->timeout_ms = (entry->function)(entry->user_data); + entry->last_exec_ms = now_ms = gs_time_rel_ms(); + elapsed = 0; + } + timeout_ms = gs_min(timeout_ms, (entry->timeout_ms - elapsed)); + } + } + } + + return (int)((timeout_ms < INT_MAX) ? timeout_ms : INT_MAX); +} diff --git a/gomspace/libutil/src/gosh/command.c b/gomspace/libutil/src/gosh/command.c new file mode 100644 index 00000000..b68d6c82 --- /dev/null +++ b/gomspace/libutil/src/gosh/command.c @@ -0,0 +1,754 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include "command_local.h" + +#include +#include + +#include // register commands +#include // register commands +#include +#include +#include "../lock.h" + +#define MAX_ARGC 30 + +#ifdef __AVR__ +#include +#define cmd_strcmp strcmp_P +#define cmd_strncmp strncmp_P +#define cmd_strlen strlen_P +#define cmd_strcpy strcpy_P +#define cmd_read_ptr(ptr) ((void *) pgm_read_word(ptr)) +#define cmd_read_int(ptr) pgm_read_word(ptr) +#else +#define cmd_strcmp strcmp +#define cmd_strncmp strncmp +#define cmd_strlen strlen +#define cmd_strcpy strcpy +#define cmd_read_ptr(ptr) *ptr +#define cmd_read_int(ptr) *ptr +#endif + +// define common command log group. +static GS_LOG_GROUP(gs_command_log, "command", GS_LOG_CAT_COMMAND, LOG_DEFAULT_MASK | LOG_INFO_MASK); +#define LOG_DEFAULT gs_command_log + +/** + Compile check that size of gs_command_t is multiplum of 4. +*/ +GS_STATIC_ASSERT((sizeof(gs_command_t) % 4) == 0, gs_command_t_is_not_a_multiplum_of_4); + +// Private context +typedef struct process_context { + // command context - must be first, as it is used to access private context (same address) + gs_command_context_t context; + // process function + gs_error_t (*process)(const gs_command_t * const cmds, int cmd_count, int arg_offset, struct process_context * pc); + // command error + gs_error_t error; + // only exact match (space after last argument) + bool requires_exact_match; + // first command match + const gs_command_t * cmd; + // number of hits when hunting commands, completion etc. + unsigned int hits; + // complete result + struct { + char * line; + size_t token_start; + } complete; +} private_context_t; + +// command block +typedef struct gs_command_block { + //! Pointer to command block. + const gs_command_t * commands; + //! Number of commands in command block. + size_t count; + //! Reference to next command block. + struct gs_command_block * next; +} gs_command_block_t; + +// commands +static gs_command_block_t g_commands; + +// minimum stack size in bytes. +static size_t g_stack_size; + +// command logger callback +static gs_command_log_t g_command_logger = NULL; +static void * g_command_logger_ctx = NULL; + +static gs_error_t command_stdio_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value) +{ + static const char* printed_group_header = NULL; + /* Print Group header if Group string is non-empty */ + if ((group != NULL) && (group[0] != '\0')) { + if (printed_group_header != group) { + fprintf(ctx->out, "%s:\r\n", group); + printed_group_header = group; + } + } + /* Print ": " if key string is non-empty */ + if (key != NULL) { + if (key[0] != '\0') { + if ((group != NULL) && (group[0] != '\0')) { + fprintf(ctx->out, " %s: ", key); + } else { + fprintf(ctx->out, "%s: ", key); + } + } + } + fprintf(ctx->out, "%s\r\n", value); + return GS_OK; +} + +gs_error_t gs_command_stdio_flush(gs_command_context_t *ctx) +{ + fflush(ctx->out); + return GS_OK; +} + +gs_error_t gs_command_stdio_wait_for_key(gs_command_context_t *ctx, int *ch, int timeout_ms) +{ + return gs_stdio_getchar_timed(timeout_ms, ch); +} + +static const gs_command_io_functions_t stdio_functions = { + .set_result = command_stdio_set_result, + .flush = gs_command_stdio_flush, + .wait_for_key = gs_command_stdio_wait_for_key +}; + +const char * gs_command_args(gs_command_context_t *ctx) +{ + if (ctx->argc > 1) { + // find first matching argument (= starts with) - this is not 100% and doesn't handle arguments with spaces (quoted) + const char * arg = ctx->command_line; + while (arg && arg[0]) { + if (strncmp(arg, ctx->argv[1], strlen(ctx->argv[1])) == 0) { + return arg; + } + // skip argument + for (; *arg && (*arg != ' '); ++arg); + // skip spaces + // cppcheck-suppress redundantCondition + for (; *arg && (*arg == ' '); ++arg); + } + } + return ""; +} + +bool gs_command_build_argv(char *line, int *argc, char **argv, int max_argc) +{ + // Skip spaces + for (; line && *line && isspace((unsigned int)*line); ++line); + + *argc = 0; + argv[*argc] = line; + + char quote = 0; + + while (*line) { + // check for quote's: ' or " + if ((*line == '\'') || (*line == '\"')) { + if (quote == 0) { + quote = *line; + argv[*argc]++; + } else if (quote == *line) { + quote = 0; + *line = '\0'; + } + } + // check for whitespace and no quotes active + else if (isspace((unsigned int)*line) && quote == 0) { + /* Delete space */ + *line++ = '\0'; + + // skip spaces + for (; *line && isspace((unsigned int)*line); ++line); + + /* If there is more data, we have another argument */ + if (*line) { + (*argc)++; + if (*argc >= max_argc) { + return false; + } + argv[*argc] = line; + } + + continue; + } + + line++; + } + + (*argc)++; + if (*argc >= max_argc) { + return false; + } + + // According to C11 section 5.1.2.2.1, argv[argc] must be NULL + argv[*argc] = NULL; + + // Check for invalid number of quotes + return (quote == 0) ? true : false; +} + +static inline gs_error_t command_logger(const char *cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t ts, gs_timestamp_t te) +{ + gs_lock_lock(); + gs_command_log_t logger = g_command_logger; + void * log_ctx = g_command_logger_ctx; + gs_lock_unlock(); + + if (logger) { + return logger(cmd_line, ret, cmd_ret, ts, te, log_ctx); + } + return GS_OK; +} + +static gs_error_t command_execute(const gs_command_t * const cmds, int cmd_count, int arg_offset, private_context_t * pc) +{ + for (int i = 0; i < cmd_count; i++) { + const gs_command_t * cmd = &cmds[i]; + + if (cmd_strcmp(pc->context.argv[arg_offset], cmd->name) == 0) { + // check for sub-commands + const gs_command_t * list = (void*) cmd_read_ptr(&cmd->chain.list); + if (list) { + ++arg_offset; + if (arg_offset >= pc->context.argc) { + return GS_ERROR_TYPE; + } + return command_execute(list, cmd_read_int(&cmd->chain.count), arg_offset, pc); + } + + gs_command_handler_t handler = (void *) cmd_read_ptr(&cmd->handler); + if (handler == NULL) { + return GS_ERROR_NOT_IMPLEMENTED; + } + + pc->context.argc -= arg_offset; + pc->context.argv = &pc->context.argv[arg_offset]; + pc->context.command = cmd; + + // check arguments - if specified + if (cmd->mandatory_args || cmd->optional_args) { + const int min_args = (cmd->mandatory_args == GS_COMMAND_NO_ARGS) ? 0 : cmd->mandatory_args; + const int args = (pc->context.argc - 1); + if (args < min_args) { + return GS_ERROR_ARG; + } + if (args > (min_args + cmd->optional_args)) { + return GS_ERROR_ARG; + } + } + + pc->error = handler(&pc->context); + return GS_OK; // command was excecuted + } + } + + return GS_ERROR_NOT_FOUND; +} + +static gs_error_t command_process(private_context_t * pc) +{ + const char * command = gs_string_skip_leading_spaces(pc->context.command_line); + + // Make copy of string, because command parser mangles destroys it + const size_t command_len = strlen(command); + char command_copy[command_len + 1]; + strcpy(command_copy, command); + + if (command_len && command[command_len-1] == ' ') { + pc->requires_exact_match = true; + } + + pc->context.optsp = 1; + pc->context.optind = 1; + pc->context.optopt = '?'; + pc->context.command_line = command; + + // split into arguments + char *argv[MAX_ARGC + 1]; + if (gs_command_build_argv(command_copy, &pc->context.argc, argv, MAX_ARGC + 1) == false) { + return GS_ERROR_ARG; + } + pc->context.argv = argv; + + gs_error_t error = GS_ERROR_NOT_FOUND; + for (const gs_command_block_t * block = &g_commands; block && (error == GS_ERROR_NOT_FOUND); block = block->next) { + if (block->commands) { + error = (pc->process)(block->commands, block->count, 0, pc); + } + } + + return error; +} + +gs_error_t gs_command_run(const char * command, gs_error_t * return_command_result) +{ + return gs_command_execute_stdio(command, return_command_result); +} + +gs_error_t gs_command_execute_stdio(const char * command, gs_error_t * return_command_result) +{ + return gs_command_execute(command, return_command_result, stdout, &stdio_functions, NULL); +} + +gs_error_t gs_command_execute(const char * command, gs_error_t * return_command_result, FILE *out, + const gs_command_io_functions_t *iof, void *iof_ctx) +{ + command = gs_string_skip_leading_spaces(command); + GS_CHECK_ARG(gs_string_empty(command) == false); + + private_context_t pc = { + .process = command_execute, + .error = GS_OK, + .context = { + .command_line = command, + .out = out, + .io_functions = iof, + .io_ctx = iof_ctx, + } + }; + gs_timestamp_t tm_start, tm_end; + gs_clock_get_time(&tm_start); + gs_error_t error = command_process(&pc); + gs_clock_get_time(&tm_end); + command_logger(pc.context.command_line, error, pc.error, tm_start, tm_end); + if ((error == GS_OK) && return_command_result) { + *return_command_result = pc.error; + } + return error; +} + +gs_error_t gs_command_set_output(gs_command_context_t *ctx, const char* group, const char* key, const char* value) +{ + GS_CHECK_ARG(ctx); + + if (ctx->io_functions && ctx->io_functions->set_result) { + return ctx->io_functions->set_result(ctx, group, key, value); + } + + /* If no IO-function set - ignore the data and send Success */ + return GS_OK; +} + +gs_error_t gs_command_set_output_printf(gs_command_context_t *ctx, const char* group, const char* key, const char * format, ...) +{ + GS_CHECK_ARG(ctx); + + if (ctx->io_functions && ctx->io_functions->set_result) + { + va_list args; + va_start(args, format); + char value[256]; + int size = vsnprintf(value, sizeof(value), format, args); + va_end(args); + + /* Don't allow to set truncated results - Return error in this case */ + if (size >= (int)sizeof(value)) { + return GS_ERROR_ALLOC; + } + + return ctx->io_functions->set_result(ctx, group, key, value); + } + + /* If no IO-function set - ignore the data and send Success */ + return GS_OK; +} + +gs_error_t gs_command_flush_output(gs_command_context_t *ctx) +{ + GS_CHECK_ARG(ctx); + + if (ctx->io_functions && ctx->io_functions->flush) { + return ctx->io_functions->flush(ctx); + } + + /* If no IO-function set - ignore the data and send Success */ + return GS_OK; +} + +bool gs_command_wait_any_key(gs_command_context_t *ctx, int timeout_ms) +{ + int ch; + gs_error_t ret = gs_command_wait_key(ctx, &ch, timeout_ms); + + if (ret == GS_ERROR_TIMEOUT) { + return false; + } + + /* Ensure that a commands handler will not stall if IO function if not available etc. + False will only be returned in case of a positive timeout */ + return true; +} + +gs_error_t gs_command_wait_key(gs_command_context_t *ctx, int* ch, int timeout_ms) +{ + if (ctx && ctx->io_functions && ctx->io_functions->wait_for_key) + { + return ctx->io_functions->wait_for_key(ctx, ch, timeout_ms); + } + + /* If no IO-function set set return GS_ERROR_HANDLE */ + return GS_ERROR_HANDLE; +} + +unsigned int gs_command_completer_add_token(gs_command_context_t * ctx, const char * token, bool exact) +{ + private_context_t * pc = (private_context_t *) ctx; + char * line = &pc->complete.line[pc->complete.token_start]; + + if (token == NULL) { + // mark any pending partial token as exact + if ((line[0] == 0) || (pc->hits != 1)) { + return pc->hits; + } + exact = true; + } + + if (exact) { + if (token) { + strcpy(line, token); + } + strcat(line, " "); + pc->complete.token_start = strlen(pc->complete.line); + pc->hits = 1; + } else { + if (pc->hits == 0) { + strcpy(line, token); + } else { + for (; *line && *token && (*line == *token); ++line, ++token); + *line = 0; + } + ++pc->hits; + } + + return pc->hits; +} + +static unsigned int command_complete_add(private_context_t * pc, const gs_command_t * cmd, bool exact) +{ + if (cmd) { + pc->cmd = cmd; + return gs_command_completer_add_token(&pc->context, cmd->name, exact); + } else { + return gs_command_completer_add_token(&pc->context, NULL, exact); + } +} + +static gs_error_t command_complete(const gs_command_t * const cmds, int cmd_count, int arg_offset, private_context_t * pc) +{ + if (arg_offset > 0) { + // command we are looking for must be in this block + pc->hits = 0; + } + pc->cmd = NULL; + bool exact_match = false; + + for (int i = 0; i < cmd_count; i++) { + const gs_command_t * cmd = &cmds[i]; + + if (cmd_read_int(&cmd->mode) & GS_COMMAND_FLAG_HIDDEN) { + continue; + } + + if (gs_string_empty(pc->context.argv[arg_offset])) { + // exceeding known token(s) - partial match + command_complete_add(pc, cmd, false); + continue; + } + + if (pc->requires_exact_match || ((arg_offset+1) < pc->context.argc)) { + // must be an exact match + if (cmd_strcmp(pc->context.argv[arg_offset], cmd->name) == 0) { + command_complete_add(pc, cmd, true); + exact_match = true; + break; + } + } else if (cmd_strncmp(pc->context.argv[arg_offset], cmd->name, + strlen(pc->context.argv[arg_offset])) == 0) { + // partial match + command_complete_add(pc, cmd, false); + } + } + + if (exact_match || ((arg_offset > 0) && (pc->hits == 1))) { + command_complete_add(pc, NULL, true); + + if (strlen(pc->complete.line) > strlen(pc->context.command_line)) { + return GS_OK; + } + + if (pc->cmd->chain.list) { + return command_complete(pc->cmd->chain.list, pc->cmd->chain.count, arg_offset+1, pc); + } + + // command arguments + pc->context.argc -= arg_offset; + pc->context.argv = &pc->context.argv[arg_offset]; + pc->context.command = pc->cmd; + + // add the "already" completed ones + int arg_to_complete = 1; + for (; arg_to_complete < (pc->context.argc - 1); ++arg_to_complete) { + gs_command_completer_add_token(&pc->context, pc->context.argv[arg_to_complete], true); + } + // add the last - if its completed (space after) + if ((arg_to_complete < pc->context.argc) && pc->requires_exact_match) { + // cppcheck-suppress unreadVariable - not used on __AVR__ because it doesn't support 'completer' + gs_command_completer_add_token(&pc->context, pc->context.argv[arg_to_complete], true); + ++arg_to_complete; + } + +#if (__AVR__ == 0) + if (pc->cmd->completer) { + pc->hits = 0; + (pc->cmd->completer)(&pc->context, arg_to_complete); + } else +#endif + { + pc->hits = 1; // no completer - assume single hit + } + + return GS_OK; // only used for breaking loop + } + + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_command_complete(char *line, size_t max_line_length, FILE* out) +{ + const size_t line_len = strlen(line); + char buffer[max_line_length]; + buffer[0] = 0; + private_context_t pc = { + .process = command_complete, + .context = { + .command_line = line, + .out = out, + }, + .complete = { + .line = buffer, + }, + }; + command_process(&pc); + gs_command_completer_add_token(&pc.context, NULL, true); + if (strlen(buffer) > line_len ) { + strcpy(line, buffer); + } + switch (pc.hits) { + case 0: + return GS_ERROR_NOT_FOUND; + case 1: + return GS_OK; + default: + return GS_ERROR_AMBIGUOUS; + } +} + +static void command_help_print(const gs_command_t * const cmd, private_context_t * pc) +{ + if (pc->hits == 1) { + if (cmd->help) { + fprintf(pc->context.out, "%s\r\n", cmd->help); + } + if (cmd->chain.count == 0) { + fprintf(pc->context.out, "usage: %s %s\r\n", cmd->name, cmd->usage ? cmd->usage : ""); + } else { + for (unsigned int i = 0; i < cmd->chain.count; ++i) { + const gs_command_t * scmd = &cmd->chain.list[i]; + + if (scmd->mode & GS_COMMAND_FLAG_HIDDEN) { + continue; + } + fprintf(pc->context.out, " %-19s %s\r\n", scmd->name, scmd->help ? scmd->help : ""); + } + } + } else { + fprintf(pc->context.out, " %-19s %s\r\n", cmd->name, cmd->help ? cmd->help : ""); + } +} + +static void command_help_hit(const gs_command_t * const cmd, private_context_t * pc) +{ + pc->error = GS_OK; + ++pc->hits; + if (pc->hits == 1) { + // single hit so far - hold off printing until we know if we get more + pc->cmd = cmd; + } else { + if (pc->cmd) { + command_help_print(pc->cmd, pc); + pc->cmd = NULL; + } + command_help_print(cmd, pc); + } +} + +static gs_error_t command_help(const gs_command_t * const cmds, int cmd_count, int arg_offset, private_context_t * pc) +{ + for (int i = 0; i < cmd_count; i++) { + const gs_command_t * cmd = &cmds[i]; + + if (cmd_read_int(&cmd->mode) & GS_COMMAND_FLAG_HIDDEN) { + continue; + } + + if (pc->requires_exact_match || ((arg_offset+1) < pc->context.argc)) { + // must be an exact match + if (cmd_strcmp(pc->context.argv[arg_offset], cmd->name) == 0) { + const gs_command_t * list = (void*) cmd_read_ptr(&cmd->chain.list); + if (list && ((arg_offset+1) < pc->context.argc)) { + return command_help(list, cmd_read_int(&cmd->chain.count), arg_offset+1, pc); + } + command_help_hit(cmd, pc); + } + + } else if (cmd_strncmp(pc->context.argv[arg_offset], cmd->name, + strlen(pc->context.argv[arg_offset])) == 0) { + command_help_hit(cmd, pc); + } + } + + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_command_show_help(const char * command, FILE* out) +{ + private_context_t pc = { + .process = command_help, + .error = GS_ERROR_NOT_FOUND, + .context = { + .command_line = command, + .out = out, + } + }; + gs_error_t error = command_process(&pc); + if (pc.cmd) { + command_help_print(pc.cmd, &pc); + error = GS_OK; + } else if ((error == GS_ERROR_NOT_FOUND) && pc.hits) { + error = GS_OK; + } + return error; +} + +gs_error_t gs_command_register(const gs_command_t * commands, size_t count) +{ + GS_CHECK_ARG(commands != NULL); + GS_CHECK_ARG(count > 0); + + gs_error_t error = GS_OK; + + gs_lock_lock(); + { + // check if command block already installed + gs_command_block_t * last_block = NULL; + for (gs_command_block_t * block = &g_commands; block; block = block->next) { + if (block->commands) { + const gs_command_t * cmd = block->commands; + // loop through because it may be in the linked blocks + for (size_t i = 0; i < block->count; ++i, ++cmd) { + if (cmd == commands) { + error = GS_ERROR_EXIST; + break; + } + } + } + last_block = block; + } + + if (error == GS_OK) { + gs_command_block_t * block = calloc(1, sizeof(*block)); + if (block) { + // Insert command last, so lock isn't needed when accessing commands + block->commands = commands; + block->count = count; + block->next = NULL; + last_block->next = block; + } else { + error = GS_ERROR_ALLOC; + } + } + } + gs_lock_unlock(); + + return (error != GS_ERROR_EXIST) ? error : GS_OK; +} + +size_t gs_command_get_stack_size(void) +{ + return g_stack_size; +} + +gs_error_t gs_command_init_no_commands(size_t stack_size) +{ + g_stack_size = stack_size; + + gs_error_t error = gs_lock_init(); + if (error) { + return error; + } + + gs_log_group_register(gs_command_log); + +#if (__linux__ == 0) + // look up static linked commands - only embedded (= none linux) systems + gs_command_block_t * block = &g_commands; + extern volatile unsigned int __command_start __attribute__ ((__weak__)); + extern volatile unsigned int __command_end __attribute__ ((__weak__)); + if (&__command_start) { + block->count = ((ptrdiff_t)&__command_end - (ptrdiff_t)&__command_start) / sizeof(gs_command_t); + block->commands = (gs_command_t *) &__command_start; + } +#endif + + return GS_OK; +} + +gs_error_t gs_command_init(size_t stack_size) +{ + gs_error_t error = gs_command_init_no_commands(stack_size); + if (error == GS_OK) { + // register default commands + gs_command_register_default_commands(); + gs_log_register_commands(); + } + return error; +} + +gs_error_t gs_command_logger_default(const char* cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t t_start, gs_timestamp_t t_end, void *log_ctx) +{ + (void)log_ctx; + + timestamp_diff(&t_end, &t_start); + if (ret == GS_OK) { + log_info_group(gs_command_log, "'%s' returned '%s' [" + "t: <%04"PRIu32".%06"PRIu32">, dt: <%01"PRIu32".%06"PRIu32">]", + cmd_line, gs_error_string(cmd_ret), + t_start.tv_sec, t_start.tv_nsec/1000, t_end.tv_sec, t_end.tv_nsec/1000); + } else { + log_info_group(gs_command_log, "'%s' could not be run, returned '%s' [" + "t: <%04"PRIu32".%06"PRIu32">]", + cmd_line, gs_error_string(ret), + t_start.tv_sec, t_start.tv_nsec/1000); + } + return GS_OK; +} + +gs_error_t gs_command_register_logger(gs_command_log_t log_cb, void *log_ctx) +{ + gs_lock_lock(); + g_command_logger = log_cb; + g_command_logger_ctx = log_ctx; + gs_lock_unlock(); + + return GS_OK; +} + diff --git a/gomspace/libutil/src/gosh/command_local.h b/gomspace/libutil/src/gosh/command_local.h new file mode 100644 index 00000000..69f715e1 --- /dev/null +++ b/gomspace/libutil/src/gosh/command_local.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +/** + Command I/O function - flush stdout. +*/ +gs_error_t gs_command_stdio_flush(gs_command_context_t *ctx); + +/** + Command I/O function - wait for a key. +*/ +gs_error_t gs_command_stdio_wait_for_key(gs_command_context_t *ctx, int *ch, int timeout_ms); + +/** + Complete command. + @param[in] line command line to complete + @param[in] max \a length (size) + @param[in] out output stream, e.g. stdout +*/ +gs_error_t gs_command_complete(char *line, size_t max_line_length, FILE* out); + +/** + Show help. + @param line command line to show help for. + @param out output stream, e.g. stdout +*/ +gs_error_t gs_command_show_help(const char * command, FILE * out); + +/** + Change console mode. + @param[in] mode console mode, 'cci' + @return_gs_error_t +*/ +int gs_console_change_mode(const char * mode); diff --git a/gomspace/libutil/src/gosh/console.c b/gomspace/libutil/src/gosh/console.c new file mode 100644 index 00000000..99b04aac --- /dev/null +++ b/gomspace/libutil/src/gosh/console.c @@ -0,0 +1,758 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + The console interface provides support for executing commands over stdout (typically a serial port). + + The connection can run in 2 modes: + - normal, standard GOSH interface (Human Machine Interface), echo characters, prompt, etc. + - cci, Computer Computer Interface. Simple text interface, but with tagged output format - easier to parse by a computer. +*/ +#include "console_local.h" +#include "command_local.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include // console defines set through Waf options + +#if (__linux__) +#include +#include +#include +#include +#endif + +/* Max history length (elements) */ +#ifndef GS_CONSOLE_HISTORY_LEN +#define GS_CONSOLE_HISTORY_LEN 10 +#endif + +/* Max input length */ +#ifndef GS_CONSOLE_INPUT_LEN +#define GS_CONSOLE_INPUT_LEN 100 +#endif + +#define CONTROL(X) ((X) - '@') + +typedef enum { + CONSOLE_NORMAL = 0, + CONSOLE_ESCAPE = 1, + CONSOLE_PRE_ESCAPE = 2, +} console_escape_t; + +static const char hash_prompt[] = "\033[1;30m # "; + +static const char backspace_char = '\b'; +static const char space_char = ' '; +static const char cr_char = '\r'; +static const char nl_char = '\n'; + +static const char * user_prompt = "gosh"; + +static console_escape_t escape = CONSOLE_NORMAL; + +#if (GS_CONSOLE_HISTORY_LEN > 0) +static int history_elements; +static int history_cur; +static int history_browse; +static char history[GS_CONSOLE_HISTORY_LEN][GS_CONSOLE_INPUT_LEN+1]; +#endif + +static int size; +static int pos; +static char buf[GS_CONSOLE_INPUT_LEN+1]; +static gs_thread_t console_thread; + +#if (__linux__) +static bool termios_changed; +static struct termios old_stdin; +static struct termios old_stdout; +#endif + +static gs_mutex_t g_cci_lock; // Lock for protecting stdout for async output, e.g. log messages +static gs_error_t command_io_cci_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value); +static const gs_command_io_functions_t cci_io_functions = { + .set_result = command_io_cci_set_result, + .flush = gs_command_stdio_flush, + .wait_for_key = gs_command_stdio_wait_for_key, +}; +#define CCI_START_TAG "[X[" +#define CCI_END_TAG "]X]" + +static void gs_console_write(const char *str, int length) +{ + for (int i = 0; i < length; i++) { + putchar(str[i]); + } +} + +static void gs_console_prompt(void) +{ + static const char col_start[] = "\033[1;32m"; + static const char col_end[] = "\033[0m"; + + gs_console_write(col_start, sizeof(col_start) - 1); + gs_console_write(user_prompt, strlen(user_prompt)); + gs_console_write(hash_prompt, sizeof(hash_prompt) - 1); + gs_console_write(col_end, sizeof(col_end) - 1); +} + +void gs_console_set_prompt(const char * _prompt) +{ + if (gs_string_empty(_prompt) == false) { + user_prompt = _prompt; + } +} + +static void gs_console_reset(void) +{ + pos = size = 0; + buf[pos] = 0; + gs_console_prompt(); +} + +static void gs_console_rewind(void) +{ + int plen = strlen(hash_prompt) + strlen(user_prompt); + gs_console_write(&cr_char, 1); + while (size-- + plen) { + gs_console_write(&space_char, 1); + } + pos = size = 0; + gs_console_write(&cr_char, 1); +} + +void gs_console_clear(void) +{ + static const char clear[] = "\033[H\033[2J"; + gs_console_write(clear, sizeof(clear) - 1); + gs_console_rewind(); + gs_console_reset(); +} + +void gs_console_update(void) +{ + gs_console_rewind(); + gs_console_prompt(); + pos = size = strlen(buf); + gs_console_write(buf, size); +} + +#if (GS_CONSOLE_HISTORY_LEN > 0) + +static void gs_console_history_add(void) +{ + strncpy(history[history_cur], buf, GS_CONSOLE_INPUT_LEN); + history[history_cur][GS_CONSOLE_INPUT_LEN] = 0; + + history_browse = 0; + history_cur = (history_cur + 1) % GS_CONSOLE_HISTORY_LEN; + + if (history_elements < GS_CONSOLE_HISTORY_LEN) { + history_elements++; + } +} + +static void gs_console_last_line(void) +{ + if (history_elements < 1) { + return; + } + + if (history_browse >= history_elements) { + return; + } + + gs_console_rewind(); + history_browse++; + strcpy(buf, history[(history_cur - history_browse + GS_CONSOLE_HISTORY_LEN) % GS_CONSOLE_HISTORY_LEN]); + gs_console_update(); +} + +static void gs_console_next_line(void) +{ + if (history_elements < 1) { + return; + } + + if (history_browse < 1) { + return; + } + + gs_console_rewind(); + history_browse--; + if (history_browse > 0) { + strcpy(buf, history[(history_cur - history_browse + GS_CONSOLE_HISTORY_LEN) % GS_CONSOLE_HISTORY_LEN]); + } else { + buf[0] = '\0'; + } + gs_console_update(); +} + +#endif + +static void gs_console_forward_char(void) +{ + if (pos < size) { + gs_console_write(&buf[pos], 1); + pos++; + } +} + +static void gs_console_end_of_line(void) +{ + while (pos < size) { + gs_console_forward_char(); + } +} + +static void gs_console_backward_char(void) +{ + if (pos > 0) { + pos--; + gs_console_write(&backspace_char, 1); + } +} + +static void gs_console_beginning_of_line(void) +{ + while (pos) { + gs_console_backward_char(); + } +} + +static void gs_console_newline(void) +{ + gs_console_write(&cr_char, 1); + gs_console_write(&nl_char, 1); +} + +static bool gs_command_not_empty(const char *ibuf) +{ + while (*ibuf) { + if (!isblank((int) *ibuf++)) { + return true; + } + } + return false; +} + +static void show_help(const char * command) +{ + gs_error_t error = gs_command_show_help(command, stdout); + if (error) { + printf("Could not show help for \'%s\': %s (%d)\r\n", command, gs_error_string(error), error); + } +} + +static void gs_console_execute(void) +{ + gs_console_newline(); + buf[GS_CONSOLE_INPUT_LEN] = 0; // ensure 0 termination + if (size > 0 && gs_command_not_empty(buf)) { +#if (GS_CONSOLE_HISTORY_LEN > 0) + gs_console_history_add(); +#endif + gs_error_t result = GS_OK; + gs_error_t error = gs_command_execute_stdio(buf, &result); + if (error == GS_ERROR_TYPE) { + show_help(buf); + } else if (error == GS_ERROR_NOT_FOUND) { + printf("Unknown command \'%s\'\r\n", buf); + } else if (error == GS_ERROR_ARG) { + show_help(buf); + } else if (error) { + printf("Command \'%s\' did not execute: %s (%d)\r\n", buf, gs_error_string(error), error); + } else if (result == GS_ERROR_ARG) { + show_help(buf); + } else if (result) { + printf("Command \'%s\' executed, but returned error: %s (%d)\r\n", buf, gs_error_string(result), result); + } + } + gs_console_reset(); +} + +static void gs_console_complete(void) +{ + /* We don't expand in the middle of a line */ + if (size != pos) { + return; + } + + const size_t old_buf_len = strlen(buf); + gs_error_t ret = gs_command_complete(buf, sizeof(buf), stdout); + if ((ret == GS_OK) && (old_buf_len == strlen(buf))) { + // completed (again) and no change - show help + ret = GS_ERROR_AMBIGUOUS; + } + switch (ret) { + case GS_ERROR_AMBIGUOUS: + gs_console_newline(); + show_help(buf); + gs_console_update(); + break; + case GS_OK: + gs_console_update(); + break; + default: + case GS_ERROR_NOT_FOUND: + break; + } +} + +static void gs_console_insert(char c) +{ + int i; + int diff = size - pos; + + if (size >= GS_CONSOLE_INPUT_LEN) { + return; + } + + memmove(&buf[pos + 1], &buf[pos], diff); + buf[pos] = c; + + gs_console_write(&buf[pos], diff + 1); + for (i = 0; i < diff; i++) { + gs_console_write(&backspace_char, 1); + } + + size++; + pos++; + buf[size] = '\0'; +} + +static void gs_console_insert_overwrite(char c) +{ + buf[pos++] = c; + + if (pos > size) { + size++; + } + + gs_console_write(&c, 1); +} + +static void gs_console_delete(void) +{ + int i; + int diff = size - pos; + + /* Nothing to delete */ + if (size == pos) { + return; + } + + size--; + memmove(&buf[pos], &buf[pos + 1], diff - 1); + buf[size] = '\0'; + + gs_console_write(&buf[pos], diff - 1); + gs_console_write(&space_char, 1); + for (i = 0; i < diff; i++) { + gs_console_write(&backspace_char, 1); + } +} + +static void gs_console_backspace(void) +{ + if (pos < 1) { + return; + } + + gs_console_backward_char(); + gs_console_delete(); +} + +static void gs_console_kill_line(void) +{ + int i; + int diff; + + diff = size - pos; + + if (diff == 0) { + return; + } + + for (i = 0; i < diff; i++) { + gs_console_write(&space_char, 1); + } + for (i = 0; i < diff; i++) { + gs_console_write(&backspace_char, 1); + } + + memset(&buf[pos], 0, diff); + size = pos; +} + +static void gs_console_kill_line_from_beginning(void) +{ + gs_console_beginning_of_line(); + gs_console_kill_line(); +} + +static void gs_console_backward_kill_word(void) +{ + while (pos > 0 && buf[pos - 1] == ' ') { + gs_console_backspace(); + } + while (pos > 0 && buf[pos - 1] != ' ') { + gs_console_backspace(); + } +} + +static void gs_console_transpose_chars(void) +{ + char c1, c2; + + if (size < 2 || pos < 1) { + return; + } + + if (pos == size) { + c1 = buf[pos - 1]; + c2 = buf[pos - 2]; + + gs_console_backward_char(); + gs_console_backward_char(); + gs_console_insert_overwrite(c1); + gs_console_insert_overwrite(c2); + } else { + c1 = buf[pos]; + c2 = buf[pos - 1]; + + gs_console_backward_char(); + gs_console_insert_overwrite(c1); + gs_console_insert_overwrite(c2); + } +} + +static void gs_console_normal(char c) +{ + switch (c) { + case CONTROL('A'): + gs_console_beginning_of_line(); + break; + case CONTROL('B'): + gs_console_backward_char(); + break; + case CONTROL('C'): + // Either ignored or handled through signals + break; + case CONTROL('D'): + gs_console_delete(); + break; + case CONTROL('E'): + gs_console_end_of_line(); + break; + case CONTROL('F'): + gs_console_forward_char(); + break; + case CONTROL('K'): + gs_console_kill_line(); + break; + case CONTROL('L'): + gs_console_clear(); + break; +#if (GS_CONSOLE_HISTORY_LEN > 0) + case CONTROL('N'): + gs_console_next_line(); + break; + case CONTROL('P'): + gs_console_last_line(); + break; +#endif + case CONTROL('T'): + gs_console_transpose_chars(); + break; + case CONTROL('U'): + gs_console_kill_line_from_beginning(); + break; + case CONTROL('W'): + gs_console_backward_kill_word(); + break; + case CONTROL('Z'): + // We cannot suspend + break; + case CONTROL('H'): + case 0x7f: + gs_console_backspace(); + break; + case '\r': + case '\n': + gs_console_execute(); + break; + case '\t': + gs_console_complete(); + break; + case '\033': + escape = CONSOLE_ESCAPE; + break; + default: + if (escape == CONSOLE_ESCAPE) { + if ((c == '[') || (c == 'O')) { + c = getchar(); + if (c == 'F') + gs_console_end_of_line(); + if (c == 'H') + gs_console_beginning_of_line(); +#if (GS_CONSOLE_HISTORY_LEN > 0) + if (c == 'A') + gs_console_last_line(); + if (c == 'B') + gs_console_next_line(); +#endif + if (c == 'C') + gs_console_forward_char(); + if (c == 'D') + gs_console_backward_char(); + if (c == '1') + if (getchar() == '~') + gs_console_beginning_of_line(); + if (c == '3') + if (getchar() == '~') + gs_console_delete(); + } + escape = CONSOLE_NORMAL; + break; + } + + if (isprint((unsigned char) c)) { + gs_console_insert(c); + } + + break; + } +} + +static gs_error_t command_io_cci_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value) +{ + gs_mutex_lock(g_cci_lock); + { + printf(CCI_START_TAG "cmd_res,%s,%s,%s" CCI_END_TAG, group, key, value); + } + gs_mutex_unlock(g_cci_lock); + return GS_OK; +} + +static void gs_console_cci_log(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) +{ + va_list my_va; + va_copy(my_va, va); + + gs_mutex_lock(g_cci_lock); + { + printf(CCI_START_TAG "log,%04"PRIu32".%06"PRIu32",%c,%s,", ts->tv_sec, ts->tv_nsec / 1000, gs_log_level_to_char(level), group->name); + vprintf(format, my_va); + printf(CCI_END_TAG "\r\n"); + } + gs_mutex_unlock(g_cci_lock); + + va_end(my_va); +} + +static void gs_console_cci(char c) +{ + switch (c) { + case CONTROL('C'): + case CONTROL('L'): + size = 0; + buf[0] = 0; + break; + case '\r': + case '\n': + buf[GS_CONSOLE_INPUT_LEN] = 0; // ensure 0 termination + if (size > 0 && gs_command_not_empty(buf)) { + static unsigned int seq; // simple sequence number keep incrementing + + gs_mutex_lock(g_cci_lock); + ++seq; + printf(CCI_START_TAG "cmd_exec_begin,%u,%s" CCI_END_TAG "\r\n", seq, buf); + gs_mutex_unlock(g_cci_lock); + + gs_error_t result = GS_OK; + gs_error_t error = gs_command_execute(buf, &result, stdout, &cci_io_functions, NULL); + + gs_mutex_lock(g_cci_lock); + printf(CCI_START_TAG "cmd_exec_end,%u,%d,%d" CCI_END_TAG "\r\n", seq, error, result); + gs_mutex_unlock(g_cci_lock); + } + size = 0; + buf[0] = 0; + break; + default: + if (isprint((unsigned char) c) && (size < GS_CONSOLE_INPUT_LEN)) { + buf[size++] = c; + buf[size] = 0; + } + break; + } +} + +// Currrent mode handler, switch by sending command +static void (*console_handler)(char c) = gs_console_normal; + +int gs_console_change_mode(const char * mode) +{ + if (strcasecmp(mode, "cci") == 0) { + gs_error_t error = GS_OK; + if (console_handler != gs_console_cci) { + error = gs_mutex_create(&g_cci_lock); + if (error == GS_OK) { + gs_log_appender_console_set_cb(gs_console_cci_log); + console_handler = gs_console_cci; // change console handler + } + } + return error; + } + return GS_ERROR_NOT_SUPPORTED; +} + +static void * gs_console_thread(void * param) +{ + gs_console_reset(); + while (1) { + char c = getchar(); + console_handler(c); + } + + gs_thread_exit(NULL); +} + +gs_error_t gs_console_exit(void) +{ +#if (__linux__) + if (termios_changed) { + tcsetattr(STDIN_FILENO, TCSANOW, &old_stdin); + tcsetattr(STDOUT_FILENO, TCSANOW, &old_stdout); + } +#endif + return GS_OK; +} + +#if (__linux__) +static inline void exithandler(void) +{ + printf("\n"); + gs_console_exit(); +} +#endif + +static gs_error_t gs_console_init2(uint32_t flags) +{ +#if (__linux__) + // save current stdio setting, for restoring when terminating process + tcgetattr(STDIN_FILENO, &old_stdin); + tcgetattr(STDOUT_FILENO, &old_stdout); + + // change stdin settings + { + struct termios new = old_stdin; + new.c_iflag &= ~(IGNCR | ICRNL); + new.c_lflag &= ~(ECHO | ICANON | IEXTEN); + new.c_cc[VTIME]=0; + new.c_cc[VMIN]=1; + tcsetattr(STDIN_FILENO, TCSANOW, &new); + } + // change stdout settings + { + struct termios new = old_stdout; + new.c_iflag &= ~(IGNCR | ICRNL); + new.c_lflag &= ~(ECHO | ICANON | IEXTEN); + new.c_cc[VTIME]=0; + new.c_cc[VMIN]=1; + tcsetattr(STDOUT_FILENO, TCSANOW, &new); + } + + termios_changed = true; + + // add exit-handler to restore original termianl settings + atexit(exithandler); + + // install signal handlers to ensure terminal settings are restored + if ((flags & GS_CONSOLE_F_NO_SIGNAL_HANDLER) == 0) { + // install signal handler(s) to ensure atexit() is called + gs_signal_catch(SIGTERM, NULL); + + if (gs_command_line_ignore_ctrlc() == false) { + gs_signal_catch(SIGINT, NULL); + } + } +#endif + +#if (__AVR__ == 0) + /** This is very important on AVR32 */ + setvbuf(stdin, NULL, _IONBF, 0); + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); +#endif + return GS_OK; +} + +gs_error_t gs_console_init() +{ + return gs_console_init2(0); +} + +static gs_error_t _console_create_thread(gs_thread_priority_t priority, gs_thread_t * handle, uint32_t thread_create_flags) +{ + gs_error_t error = gs_thread_create("CONSOLE", + gs_console_thread, NULL, + gs_command_get_stack_size(), + priority, + thread_create_flags, + handle); + if (error == GS_OK) { + // give thread a few moments to print prompt + gs_time_sleep_ms(20); + } + return error; +} + +gs_error_t gs_console_create_thread(gs_thread_t * handle) +{ + return _console_create_thread(GS_THREAD_PRIORITY_LOW, handle, 0); +} + +gs_error_t gs_console_create_thread_with_priority(gs_thread_priority_t priority, gs_thread_t * handle) +{ + return _console_create_thread(priority, handle, 0); +} + +gs_error_t gs_console_start(const char * prompt, uint32_t flags) +{ + if (console_thread) { + return GS_ERROR_EXIST; + } + + gs_console_init2(flags); + gs_console_set_prompt(prompt); + + return _console_create_thread(GS_THREAD_PRIORITY_LOW, &console_thread, GS_THREAD_CREATE_JOINABLE); +} + +gs_error_t gs_console_stop(void) +{ + if (console_thread == 0) { + return GS_ERROR_HANDLE; + } +#if (__linux__) + if (pthread_cancel(console_thread) != 0) { + return GS_ERROR_IO; + } + gs_error_t error = gs_thread_join(console_thread, NULL); + if (error == GS_OK) { + console_thread = 0; + } + return error; +#else + return GS_ERROR_NOT_SUPPORTED; +#endif +} diff --git a/gomspace/libutil/src/gosh/console_local.h b/gomspace/libutil/src/gosh/console_local.h new file mode 100644 index 00000000..1332e732 --- /dev/null +++ b/gomspace/libutil/src/gosh/console_local.h @@ -0,0 +1,10 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +/** + Change console mode. + @param[in] mode console mode, 'rgosh', 'normal' + @return_gs_error_t +*/ +int gs_console_change_mode(const char * mode); diff --git a/gomspace/libutil/src/gosh/default_commands.c b/gomspace/libutil/src/gosh/default_commands.c new file mode 100644 index 00000000..fb535318 --- /dev/null +++ b/gomspace/libutil/src/gosh/default_commands.c @@ -0,0 +1,277 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include "command_local.h" +#include "console_local.h" + +#include + +#if defined(__linux__) +#include +#include +#endif + +#include +#include +#include +#include +#include + +static int cmd_help(gs_command_context_t * context) +{ + return gs_command_show_help(gs_command_args(context), context->out); +} + +static int cmd_sleep(gs_command_context_t * context) +{ + uint32_t sleep_ms; + gs_error_t error = gs_string_to_uint32(context->argv[1], &sleep_ms); + if (error) { + return error; + } + + gs_time_sleep_ms(sleep_ms); + + return GS_OK; +} + +static int cmd_watch(gs_command_context_t * context, bool check_error) +{ + uint32_t sleep_ms; + gs_error_t error = gs_string_to_uint32(context->argv[1], &sleep_ms); + if (error) { + return error; + } + + fprintf(context->out, "Execution delay: %" PRIu32 "\r\n", sleep_ms); + + char * new_command = strstr(gs_command_args(context), " "); + if (new_command == NULL) { + return GS_ERROR_ARG; + } else { + new_command = new_command + 1; + } + + fprintf(context->out, "Command: %s\r\n", new_command); + + while(1) { + + gs_error_t cmd_result; + error = gs_command_execute(new_command, &cmd_result, context->out, context->io_functions, context->io_ctx); + if (error) { + return error; + } + if (check_error && cmd_result) { + return cmd_result; + } + + if (gs_stdio_getchar_timed(sleep_ms, NULL) != GS_ERROR_TIMEOUT) { + break; + } + } + + return GS_OK; +} + +static int cmd_watch_nocheck(gs_command_context_t * context) +{ + return cmd_watch(context, false); +} + +static int cmd_watch_check(gs_command_context_t * context) +{ + return cmd_watch(context, true); +} + +#define CONTROL(X) ((X) - '@') + +static int cmd_batch(gs_command_context_t * ctx) +{ + char c; + int quit = 0, execute = 0; + unsigned int batch_size = 100; + unsigned int batch_input = 0; + unsigned int batch_count = 0; + char * batch[20] = {}; + printf("Type each command followed by enter, hit ctrl+e to end typing, ctrl+x to cancel:\r\n"); + + /* Wait for ^q to quit. */ + while (quit == 0) { + + /* Get character */ + c = getchar(); + + switch (c) { + + /* CTRL + X */ + case 0x18: + quit = 1; + break; + + /* CTRL + E */ + case 0x05: + execute = 1; + quit = 1; + break; + + /* Backspace */ + case CONTROL('H'): + case 0x7f: + if (batch_input > 0) { + putchar('\b'); + putchar(' '); + putchar('\b'); + batch_input--; + } + break; + + case '\r': + putchar('\r'); + putchar('\n'); + if ((batch[batch_count] != NULL) && (batch_input < batch_size)) + batch[batch_count][batch_input++] = '\r'; + if ((batch[batch_count] != NULL) && (batch_input < batch_size)) + batch[batch_count][batch_input++] = '\0'; + batch_count++; + batch_input = 0; + if (batch_count == 20) + quit = 1; + break; + + default: + putchar(c); + if (batch[batch_count] == NULL) { + batch[batch_count] = calloc(GS_CONSOLE_INPUT_LEN+1, 1); + } + + if ((batch[batch_count] != NULL) && (batch_input < batch_size)) + batch[batch_count][batch_input++] = c; + break; + } + } + + if (execute) { + printf("\r\n"); + for (unsigned int i = 0; i <= batch_count; i++) { + if (batch[i]) + printf("[%02u] %s\r\n", i, batch[i]); + } + printf("Press ctrl+e to execute, or any key to abort\r\n"); + c = getchar(); + if (c != 0x05) + execute = 0; + } + + /* Run/Free batch job */ + for (unsigned int i = 0; i <= batch_count; i++) { + if (execute && batch[i]) { + printf("EXEC [%02u] %s\r\n", i, batch[i]); + gs_command_run(batch[i], NULL); + } + free(batch[i]); + } + + return GS_OK; +} + +#if defined(__linux__) +static int cmd_exit(gs_command_context_t * context) +{ + gs_console_exit(); + exit(EXIT_SUCCESS); + return GS_OK; +} +#endif + +static int cmd_clock(gs_command_context_t * ctx) +{ + if (ctx->argc > 1) { + gs_timestamp_t ts; + gs_error_t error = gs_clock_from_string(ctx->argv[1], &ts); + if (error) { + return GS_ERROR_ARG; + } + error = gs_clock_set_time(&ts); + if (error) { + fprintf(ctx->out, "Failed to set time, error=%s\r\n", gs_error_string(error)); + return GS_ERROR_DATA; + } + } + + timestamp_t clock; + gs_clock_get_monotonic(&clock); + fprintf(ctx->out, "monotonic: %10"PRIu32".%09"PRIu32" sec\r\n", clock.tv_sec, clock.tv_nsec); + gs_command_set_output_printf(ctx, "", "monotonic", "%10"PRIu32".%09"PRIu32"", clock.tv_sec, clock.tv_nsec); + + char tbuf[25]; + gs_clock_get_time(&clock); + gs_clock_to_iso8601_string(&clock, tbuf, sizeof(tbuf)); + fprintf(ctx->out, "realtime: %10"PRIu32".%09"PRIu32" sec -> %s\r\n", clock.tv_sec, clock.tv_nsec, tbuf); + gs_command_set_output_printf(ctx, "", "realtime", "%10"PRIu32".%09"PRIu32"", clock.tv_sec, clock.tv_nsec); + + return GS_OK; +} + +static int cmd_console_mode(gs_command_context_t * ctx) +{ + return gs_console_change_mode(ctx->argv[1]); +} + +static const gs_command_t GS_COMMAND_ROOT cmd_default[] = { + { + .name = "help", + .help = "Show help", + .usage = "[command[ subcommand[ arg ...]]]", + .handler = cmd_help, + .optional_args = 100, + },{ + .name = "sleep", + .help = "Sleep X ms", + .usage = "", + .handler = cmd_sleep, + .mandatory_args = 1, + },{ + .name = "watch", + .help = "Run commands at intervals (abort with key)", + .usage = " [arg ...]", + .handler = cmd_watch_nocheck, + .mandatory_args = 2, + .optional_args = 100, + },{ + .name = "watch_check", + .help = "Like 'watch', but abort if command fails", + .usage = " ", + .handler = cmd_watch_check, + .mandatory_args = 2, + .optional_args = 100, + },{ + .name = "batch", + .help = "Run multiple commands", + .handler = cmd_batch, + .mode = GS_COMMAND_FLAG_HIDDEN, + },{ + .name = "clock", + .help = "Get/set system clock", + .usage = "[ | ]", + .handler = cmd_clock, + .optional_args = 1, + },{ + .name = "console_mode", + .help = "Console mode(s): cci", + .usage = "", + .handler = cmd_console_mode, + .mode = GS_COMMAND_FLAG_HIDDEN, + .mandatory_args = 1, + }, +#if defined(__linux__) + { + .name = "exit", + .help = "Exit program", + .handler = cmd_exit, + }, +#endif +}; + +gs_error_t gs_command_register_default_commands(void) +{ + return GS_COMMAND_REGISTER(cmd_default); +} diff --git a/gomspace/libutil/src/gosh/getopt.c b/gomspace/libutil/src/gosh/getopt.c new file mode 100644 index 00000000..81055bef --- /dev/null +++ b/gomspace/libutil/src/gosh/getopt.c @@ -0,0 +1,55 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include + +#include +#include +#include + +int gs_command_getopt(gs_command_context_t *ctx, const char *opts) +{ + int c; + char *cp; + + if (ctx->optsp == 1) { + if (ctx->optind >= ctx->argc || + ctx->argv[ctx->optind][0] != '-' || + ctx->argv[ctx->optind][1] == '\0') { + return EOF; + } else if (!strcmp(ctx->argv[ctx->optind], "--")) { + ctx->optind++; + return EOF; + } + } + + ctx->optopt = c = ctx->argv[ctx->optind][ctx->optsp]; + if (c == ':' || (cp = strchr(opts, c)) == NULL) { + printf("illegal option -- %c\r\n", c); + if (ctx->argv[ctx->optind][++ctx->optsp] == '\0') { + ctx->optind++; + ctx->optsp = 1; + } + return '?'; + } + + if (*++cp == ':') { + if (ctx->argv[ctx->optind][ctx->optsp+1] != '\0') { + ctx->optarg = &ctx->argv[ctx->optind++][ctx->optsp+1]; + } else if(++ctx->optind >= ctx->argc) { + printf("option requires an argument -- %c\r\n", c); + ctx->optsp = 1; + return '?'; + } else { + ctx->optarg = ctx->argv[ctx->optind++]; + } + ctx->optsp = 1; + } else { + if (ctx->argv[ctx->optind][++ctx->optsp] == '\0') { + ctx->optsp = 1; + ctx->optind++; + } + ctx->optarg = NULL; + } + + return c; +} diff --git a/gomspace/libutil/src/hexdump.c b/gomspace/libutil/src/hexdump.c new file mode 100644 index 00000000..7330ef91 --- /dev/null +++ b/gomspace/libutil/src/hexdump.c @@ -0,0 +1,92 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include + +static void print_disp_addr02(FILE * out, uintptr_t disp_addr) +{ + fprintf(out, "0x%02"PRIx32" : ", (uint32_t) disp_addr); +} +static void print_disp_addr04(FILE * out, uintptr_t disp_addr) +{ + fprintf(out, "0x%04"PRIx32" : ", (uint32_t) disp_addr); +} +static void print_disp_addrxx(FILE * out, uintptr_t disp_addr) +{ +#if defined(PRIx64) + fprintf(out, "0x%08"PRIx64" : ", (uint64_t) disp_addr); +#else + fprintf(out, "0x%08"PRIx32" : ", (uint32_t) disp_addr); +#endif +} + +void gs_hexdump_to_stream(const void * in_src, size_t len, const void * in_disp_addr, FILE* out) +{ + volatile const uint8_t * src = in_src; + uintptr_t disp_addr = GS_TYPES_PTR2UINT(in_disp_addr); + const uintptr_t end_disp_addr = disp_addr + len; + + // work-rounds for not printing NIL (if address 0), align addresses, not supporting %zx, %*x or %08p on all platforms + void (*print_addr)(FILE * out, uintptr_t disp_addr); + if (end_disp_addr <= 0xff) { + print_addr = print_disp_addr02; + } else if (end_disp_addr <= 0xffff) { + print_addr = print_disp_addr04; + } else { + print_addr = print_disp_addrxx; + } + + print_addr(out, disp_addr); + + size_t i = 0; + size_t j = 0; + size_t k = 0; + char text[17]; + for(; i < len; ++i) { + const uint8_t ch = *src++; + ++disp_addr; + + // hex + fprintf(out, "%02x ", ch); + ++j; + if (j == 8) { + fprintf(out, " "); + } + + // printable + if ((ch < 32) || (ch > 126)) { + text[k] = '.'; + } else { + text[k] = (char) ch; + } + ++k; + text[k] = 0; + + // newline? + if(j >= 16) { + fprintf(out, "|%-16.16s|\r\n", text); + j = 0; + k = 0; + text[k] = 0; + + if (i < (len - 1)) { + print_addr(out, disp_addr); + } + } + } + if ((i == 0) || (i % 16)) { + if (j) { + // something was printed - show textual + for (; j < 16; j++) { + if (j == 7) { + fprintf(out, " "); + } + fprintf(out, " "); + } + fprintf(out, "|%-16.16s|", text); + } + fprintf(out, "\r\n"); + } +} diff --git a/gomspace/libutil/src/linux/argp.c b/gomspace/libutil/src/linux/argp.c new file mode 100644 index 00000000..e9156595 --- /dev/null +++ b/gomspace/libutil/src/linux/argp.c @@ -0,0 +1,34 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +void gs_argp_parse(const struct argp * argp, + int argc, char ** argv, + unsigned int flags, int * return_arg_index, + const char * revision) +{ + if (gs_string_empty(revision) == false) { + argp_program_version = revision; + } + + int arg_index = 0; + int res = argp_parse(argp, argc, argv, 0, &arg_index, 0); + if (res) { + printf("Failed to parse argument/option (result: %d)\n", res); + exit(GS_EXITCODE_USAGE); + } + + if ((return_arg_index == NULL) && (arg_index < argc)) { + // application doesn't expect unhandled arguments + for (int i = arg_index; i < argc; ++i) { + printf("Unhandled/unknown argument: [%s]\n", argv[i]); + } + exit(GS_EXITCODE_USAGE); + } + + if (return_arg_index) { + *return_arg_index = arg_index; + } +} diff --git a/gomspace/libutil/src/linux/clock.c b/gomspace/libutil/src/linux/clock.c new file mode 100644 index 00000000..191aac25 --- /dev/null +++ b/gomspace/libutil/src/linux/clock.c @@ -0,0 +1,68 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include + +void gs_clock_get_time(gs_timestamp_t * time) +{ + struct timespec now; + clock_gettime(CLOCK_REALTIME, &now); + + time->tv_sec = (uint32_t) now.tv_sec; + time->tv_nsec = (uint32_t) now.tv_nsec; +} + +gs_error_t gs_clock_set_time(const gs_timestamp_t * time) +{ + struct timespec now; + now.tv_sec = time->tv_sec; + now.tv_nsec = time->tv_nsec; + + int res = clock_settime(CLOCK_REALTIME, &now); + if (res != 0) { + return gs_error(errno); + } + + gs_error_t error = GS_OK; + if (gs_rtc_supported() == GS_OK) { + error = gs_rtc_set_time(time); + } + + return error; +} + +void gs_clock_get_monotonic(gs_timestamp_t * time) +{ + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + time->tv_sec = (uint32_t) now.tv_sec; + time->tv_nsec = (uint32_t) now.tv_nsec; +} + +uint64_t gs_clock_get_nsec(void) +{ + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + return (((uint64_t)now.tv_sec) * GS_TIMESTAMP_NSEC_PER_SEC) + ((uint64_t)now.tv_nsec); +} + +/** + Required by libcsp. + Proto-typed in ./libcsp/include/csp/arch/csp_clock.h, but with different argumet! + + __attribute__((weak)) extern void clock_get_time(csp_timestamp_t * time); + __attribute__((weak)) extern void clock_set_time(csp_timestamp_t * time); +*/ +void clock_get_time(gs_timestamp_t * time) +{ + gs_clock_get_time(time); +} + +void clock_set_time(const gs_timestamp_t * time) +{ + gs_clock_set_time(time); +} diff --git a/gomspace/libutil/src/linux/command_line.c b/gomspace/libutil/src/linux/command_line.c new file mode 100644 index 00000000..e95cd602 --- /dev/null +++ b/gomspace/libutil/src/linux/command_line.c @@ -0,0 +1,76 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +#define KEY_IGNORE_CTRLC 200 + +static bool ignore_ctrlc; + +static int parser(int key, char *arg, struct argp_state *state) +{ + switch (key) { + case KEY_IGNORE_CTRLC: + ignore_ctrlc = true; + gs_signal_ignore(SIGINT); + break; + + case 'h': + argp_help(state->root_argp, state->out_stream, ARGP_HELP_STD_HELP, state->name); + exit(0); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static const struct argp_option options[] = { + { + .name = "ignore-ctrlc", + .key = KEY_IGNORE_CTRLC, + .doc = "Ignore/disable CTRL-C" + }, + {0} +}; + +static const struct argp argp_console = {.options = options, .parser = parser}; + +const struct argp_child gs_console_command_line_ignore_ctrlc_argp = {.argp = &argp_console}; + +bool gs_command_line_ignore_ctrlc(void) +{ + return ignore_ctrlc; +} + +static const struct argp_option help_options[] = { + { + .name = "help", + .key = 'h', + .doc = "Give this help list" + }, + {0} +}; + +static const struct argp gs_argp_help = {.options = help_options, .parser = parser}; + +const struct argp_child gs_help_command_line_argp = {.argp = &gs_argp_help}; + +const char * gs_command_line_program_name(const char * argv) +{ + if (gs_string_empty(argv) == false) { + const char * name = strrchr(argv, '/'); + if (name) { + // skip slash + ++name; + if (gs_string_empty(name) == false) { + return name; + } + } else { + return argv; + } + } + return ""; +} diff --git a/gomspace/libutil/src/linux/cwd.c b/gomspace/libutil/src/linux/cwd.c new file mode 100644 index 00000000..1cfe373d --- /dev/null +++ b/gomspace/libutil/src/linux/cwd.c @@ -0,0 +1,28 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +gs_error_t gs_getcwd(char * buf, size_t bufsize) +{ + if (buf && bufsize) { + char * wd = getcwd(buf, bufsize); + if (wd) { + return GS_OK; + } + switch(errno) { + case ENAMETOOLONG: + case ERANGE: + return GS_ERROR_RANGE; + + case EACCES: + case ENOENT: + return GS_ERROR_NOT_FOUND; + + default: + break; + } + } + return GS_ERROR_ARG; +} diff --git a/gomspace/libutil/src/linux/delay.c b/gomspace/libutil/src/linux/delay.c new file mode 100644 index 00000000..f0a39081 --- /dev/null +++ b/gomspace/libutil/src/linux/delay.c @@ -0,0 +1,22 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +void gs_delay_us(uint32_t time_us) +{ + uint64_t ns = time_us; + ns *= 1000LL; + gs_time_sleep_ns(ns); +} + +uint16_t gs_delay_ts_get(void) +{ + return 0; +} + +void gs_delay_from_ts(uint16_t ts, uint16_t delay) +{ + +} diff --git a/gomspace/libutil/src/linux/drivers/can/can.c b/gomspace/libutil/src/linux/drivers/can/can.c new file mode 100644 index 00000000..40a6b8c8 --- /dev/null +++ b/gomspace/libutil/src/linux/drivers/can/can.c @@ -0,0 +1,308 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + // true if handle is in use + bool inuse; + + // opened socket + int can_socket; + + // receiver thread + gs_thread_t rxthread; + + // received data callback + gs_can_rxdata_callback_t rx_callback; + void * user_data; + +} gs_can_handle_t; + +#define MAX_CAN_HANDLES 10 +static gs_can_handle_t can_handles[MAX_CAN_HANDLES]; + +static int gs_can_alloc_handle(void) +{ + int handle_id; + for (handle_id = 0; (handle_id < MAX_CAN_HANDLES) && (can_handles[handle_id].inuse == true); ++handle_id); + + if (handle_id < MAX_CAN_HANDLES) { + gs_can_handle_t * handle = &can_handles[handle_id]; + memset(handle, 0, sizeof(*handle)); + handle->inuse = true; + handle->can_socket = -1; + } + + return handle_id; +} + +static inline gs_can_handle_t * gs_can_handle(uint8_t hdl) +{ + if (hdl >= MAX_CAN_HANDLES) { + return NULL; + } + if (can_handles[hdl].inuse == false) { + return NULL; + } + return &can_handles[hdl]; +} + +static void * gs_can_rx_thread(void * parameter) +{ + int hdl = (int) GS_TYPES_PTR2INT(parameter); + + log_debug("%s: running, hdl: %d", __FUNCTION__, hdl); + + gs_can_handle_t * handle = gs_can_handle(hdl); + if (handle == NULL) { + log_error("%s: CAN handle: %d is invalid or not opened", __FUNCTION__, hdl); + gs_thread_exit(NULL); + } + + while (1) { + /* Read CAN frame */ + struct can_frame frame; + ssize_t nbytes = read(handle->can_socket, &frame, sizeof(frame)); + if (nbytes < 0) { + log_error("%s: read() on socket failed, error: %s", __FUNCTION__, strerror(errno)); + continue; + } + + if (nbytes != sizeof(frame)) { + log_warning("%s: read() returned incomplete CAN frame of %d bytes - ignoring frame", __FUNCTION__, (int) nbytes); + continue; + } + + /* Frame type */ + if (frame.can_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) { + /* Drop error and remote frames */ + log_warning("%s: discarding ERR/RTR frame, can_id: 0x%x", __FUNCTION__, frame.can_id); + continue; + } + + const bool extId = (frame.can_id & CAN_EFF_FLAG) ? true : false; + if (extId) { + frame.can_id &= CAN_EFF_MASK; + } else { + frame.can_id &= CAN_SFF_MASK; + } + handle->rx_callback(hdl, frame.can_id, extId, frame.data, frame.can_dlc, gs_time_rel_ms(), handle->user_data, false); + } + + /* We should never reach this point */ + return NULL; +} + +static gs_error_t gs_can_send(uint8_t hdl, uint32_t canMsgId, bool extended, const void * data, size_t data_size, int timeout_ms) +{ + gs_can_handle_t * handle = gs_can_handle(hdl); + if (handle == NULL) { + return GS_ERROR_HANDLE; + } + + if ((data == NULL) || (data_size > 8)) { + log_error("%s: invalid data: %p, data_size: %u", __FUNCTION__, (void*) data, (unsigned int) data_size); + return GS_ERROR_ARG; + } + + struct can_frame frame; + memset(&frame, 0, sizeof(frame)); + frame.can_id = canMsgId; + if (extended) { + frame.can_id |= CAN_EFF_FLAG; + } + + memcpy(frame.data, data, data_size); + + frame.can_dlc = (uint8_t) data_size; + + const int DELAY_MS = 10; + while (write(handle->can_socket, &frame, sizeof(frame)) != sizeof(frame)) { + if ((timeout_ms > 0) && (errno == ENOBUFS)) { + // Wait a bit and try again + gs_thread_sleep_ms(DELAY_MS); + timeout_ms -= DELAY_MS; + } else { + gs_error_t gserror = gs_error(errno); + log_error("%s: write() failed, error: %s", __FUNCTION__, gs_error_string(gserror)); + return gserror; + } + } + + return GS_OK; +} + +gs_error_t gs_can_send_standard(uint8_t hdl, uint32_t canMsgId, const void * data, size_t data_size, int timeout_ms) +{ + return gs_can_send(hdl, canMsgId, false, data, data_size, timeout_ms); +} + +gs_error_t gs_can_send_extended(uint8_t hdl, uint32_t canExtMsgId, const void * data, size_t data_size, int timeout_ms) +{ + return gs_can_send(hdl, canExtMsgId, true, data, data_size, timeout_ms); +} + +static void gs_can_close(gs_can_handle_t * handle) +{ + if (handle->can_socket >= 0) { + close(handle->can_socket); + } + + // free instance - must be the last thing done, no lock needed + handle->inuse = false; +} + +gs_error_t gs_can_open(const char * ifname, int * return_handle) +{ + if ((ifname == NULL) || (ifname[0] == 0) || (return_handle == NULL)) { + log_error("%s: invalid CAN interface name", __FUNCTION__); + return GS_ERROR_ARG; + } + + int handle_id = gs_can_alloc_handle(); + if (handle_id >= MAX_CAN_HANDLES) { + log_error("%s: no free handles", __FUNCTION__); + return GS_ERROR_FULL; + } + gs_can_handle_t * handle = &can_handles[handle_id]; + + /* Create socket */ + if ((handle->can_socket = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { + gs_error_t gserror = gs_error(errno); + log_error("%s: socket() failed, error: %s", __FUNCTION__, gs_error_string(gserror)); + gs_can_close(handle); + return gserror; + } + + /* Locate interface */ + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1); + if (ioctl(handle->can_socket, SIOCGIFINDEX, &ifr) < 0) { + gs_error_t gserror = gs_error(errno); + log_error("%s: ioctl(ifname: [%s]) failed, error: %s", __FUNCTION__, ifr.ifr_name, gs_error_string(gserror)); + gs_can_close(handle); + return gserror; + } + + /* Bind the socket to CAN interface */ + struct sockaddr_can addr; + memset(&addr, 0, sizeof(addr)); + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + if (bind(handle->can_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + gs_error_t gserror = gs_error(errno); + log_error("%s: bind() failed, error: %s", __FUNCTION__, gs_error_string(gserror)); + gs_can_close(handle); + return gserror; + } + + *return_handle = handle_id; + + return GS_OK; +} + +static gs_error_t gs_can_set_filter_mask(uint8_t hdl, bool extended, uint32_t canMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * user_data) +{ + gs_can_handle_t * handle = gs_can_handle(hdl); + if (handle == NULL) { + return GS_ERROR_HANDLE; + } + + if (extended) { + if ((canMsgId > CAN_EFF_MASK) || (mask > CAN_EFF_MASK)) { + return GS_ERROR_ARG; + } + } else { + if ((canMsgId > CAN_SFF_MASK) || (mask > CAN_SFF_MASK)) { + return GS_ERROR_ARG; + } + } + + handle->rx_callback = rx_callback; + handle->user_data = user_data; + + struct can_filter filter; + filter.can_id = canMsgId; + filter.can_mask = mask; + if (extended == false) { + filter.can_mask |= (CAN_EFF_MASK & ~CAN_SFF_MASK); + } + + if (setsockopt(handle->can_socket, SOL_CAN_RAW, CAN_RAW_FILTER, &filter, sizeof(filter)) < 0) { + gs_error_t gserror = gs_error(errno); + log_error("%s: setsockopt(id: 0x%x, mask: 0x%x) failed, error: %s", __FUNCTION__, canMsgId, mask, gs_error_string(gserror)); + return gserror; + } + + return GS_OK; +} + +gs_error_t gs_can_set_standard_filter_mask(uint8_t hdl, uint32_t canMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * user_data) +{ + return gs_can_set_filter_mask(hdl, false, canMsgId, mask, rx_callback, user_data); +} + +gs_error_t gs_can_set_extended_filter_mask(uint8_t hdl, uint32_t canExtMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * user_data) +{ + return gs_can_set_filter_mask(hdl, true, canExtMsgId, mask, rx_callback, user_data); +} + +gs_error_t gs_can_start(uint8_t hdl) +{ + gs_can_handle_t * handle = gs_can_handle(hdl); + if (handle == NULL) { + return GS_ERROR_HANDLE; + } + + if (handle->rxthread) { + return GS_OK; + } + + /* Create receiver thread */ + gs_error_t gserror = gs_thread_create("rxcan", gs_can_rx_thread, GS_TYPES_INT2PTR(hdl), 0, GS_THREAD_PRIORITY_HIGH, 0, &handle->rxthread); + if (gserror) { + log_error("s: gs_thread_create() failed, error: %s", gs_error_string(gserror)); + return gserror; + } + + return GS_OK; +} + +gs_error_t gs_can_stop(uint8_t hdl) +{ + gs_can_handle_t * handle = gs_can_handle(hdl); + if (handle == NULL) { + return GS_ERROR_HANDLE; + } + + return GS_ERROR_NOT_IMPLEMENTED; +} + +gs_error_t gs_can_error_state(uint8_t hdl, bool * restart_required) +{ + gs_can_handle_t * handle = gs_can_handle(hdl); + if (handle == NULL) { + return GS_ERROR_HANDLE; + } + + if (restart_required) { + *restart_required = false; + } + + // missing error state check on CAN layer + + return GS_OK; +} diff --git a/gomspace/libutil/src/linux/drivers/gpio/gpio.c b/gomspace/libutil/src/linux/drivers/gpio/gpio.c new file mode 100644 index 00000000..484c6a58 --- /dev/null +++ b/gomspace/libutil/src/linux/drivers/gpio/gpio.c @@ -0,0 +1,102 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +#define MAX_DRIVERS 20 + +typedef struct { + gs_gpio_driver_entry_t entry; + bool in_use; +} gs_gpio_driver_handle_t; + +static gs_gpio_driver_handle_t gpio_drivers[MAX_DRIVERS]; +static uint8_t max_index_in_use = 0; + + +static inline gs_gpio_driver_entry_t * gs_find_driver_entry(gs_gpio_t * gpio) +{ + gs_gpio_driver_handle_t * handle; + for (int i = max_index_in_use; i >= 0; i--) { + handle = &gpio_drivers[i]; + if (((gpio->pin == handle->entry.pin) || (handle->entry.pin == GS_GPIO_ALL_PINS)) && + ((gpio->port == handle->entry.port) || (handle->entry.port == GS_GPIO_ALL_PORTS)) && + (handle->in_use == true)) { + return &handle->entry; + } + } + return NULL; +} + +gs_error_t gs_gpio_get(gs_gpio_t gpio, bool *value) +{ + gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); + if (driver_entry) { + if (driver_entry->driver->get_handler) { + return driver_entry->driver->get_handler(gpio, value, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +bool gs_gpio_get_nc(gs_gpio_t gpio) +{ + gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); + if (driver_entry) { + if (driver_entry->driver->get_nc_handler) { + return driver_entry->driver->get_nc_handler(gpio, driver_entry->driver_data); + } + } + return false; +} + +gs_error_t gs_gpio_set(gs_gpio_t gpio, bool value) +{ + gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); + if (driver_entry) { + if (driver_entry->driver->set_handler) { + return driver_entry->driver->set_handler(gpio, value, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +void gs_gpio_set_nc(gs_gpio_t gpio, bool value) +{ + gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); + if (driver_entry) { + if (driver_entry->driver->set_nc_handler) { + driver_entry->driver->set_nc_handler(gpio, value, driver_entry->driver_data); + } + } +} + +gs_error_t gs_gpio_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf) +{ + gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); + if (driver_entry) { + if (driver_entry->driver->init_as_interrupt_handler) { + return driver_entry->driver->init_as_interrupt_handler(gpio, conf, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_gpio_register_driver(const gs_gpio_driver_entry_t * driver_entry) +{ + GS_CHECK_ARG(driver_entry != NULL); + GS_CHECK_ARG(driver_entry->driver != NULL); + + gs_gpio_driver_handle_t * handle; + for (uint8_t i = 0; i < MAX_DRIVERS; i++) { + handle = &gpio_drivers[i]; + if (handle->in_use == false) { + handle->entry = *driver_entry; + handle->in_use = true; + max_index_in_use = i; + return GS_OK; + } + } + /* Not enough space in buffer */ + return GS_ERROR_FULL; +} diff --git a/gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c b/gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c new file mode 100644 index 00000000..57efd042 --- /dev/null +++ b/gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c @@ -0,0 +1,145 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + @brief GPIO Implementation for Linux of the GPIO API in libutil. + + The GPIO driver provides a simple interface toward driving HW GPIO's. +*/ + +#include + +#include +#include +#include +#include + +#include + +#include + +gs_error_t gs_gpio_sysfs_initialize(gs_gpio_t gpio, bool output,bool init_value, bool active_low) +{ + char gpio_pin_str[6]; + snprintf(gpio_pin_str, sizeof(gpio_pin_str), "%d", gpio.pin); + + /* Try to unexport first */ + gs_sysfs_write_file("/sys/class/gpio/unexport", gpio_pin_str); + + if (gs_sysfs_write_file("/sys/class/gpio/export", gpio_pin_str) != GS_OK) + { + log_warning("failed to export GPIO %s: %s", gpio_pin_str, strerror(errno)); + return GS_ERROR_NOT_SUPPORTED; + } + + char gpio_sys_fname[128]; + snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/active_low", gpio.pin); + const char * active_low_str = active_low ? "1" : "0"; + + if (gs_sysfs_write_file(gpio_sys_fname, active_low_str) != GS_OK) + { + log_warning("failed to set GPIO %d active_low: %s", gpio.pin, strerror(errno)); + return GS_ERROR_NOT_SUPPORTED; + } + + snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/direction", gpio.pin); + + /* Glitch-free output set (high/low makes pin an output and sets value to 1/0 respectively)*/ + const char * dir = output ? (init_value ? "high" : "low") : "in"; + + if (gs_sysfs_write_file(gpio_sys_fname, dir) != GS_OK) + { + log_warning("failed to set GPIO %d direction: %s", gpio.pin, strerror(errno)); + return GS_ERROR_NOT_SUPPORTED; + } + + return GS_OK; +} + +gs_error_t gs_gpio_sysfs_get(gs_gpio_t gpio, bool *value, void * driver_data) +{ + char gpio_sys_fname[128]; + snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); + + if (access(gpio_sys_fname, R_OK) != 0) + { + log_error("GPIO %d not initialized - Can't read the input.", gpio.pin); + return GS_ERROR_ACCESS; + } + + char value_str[10]; + gs_error_t ret = gs_sysfs_read_file(gpio_sys_fname, value_str, sizeof(value_str)); + if (ret == GS_OK) + { + if (strcmp(value_str, "1") == 0) + *value = true; + else + *value = false; + } + + return ret; +} + +bool gs_gpio_sysfs_get_nc(gs_gpio_t gpio, void * driver_data) +{ + char gpio_sys_fname[128]; + snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); + + if (access(gpio_sys_fname, R_OK) != 0) + { + log_error("GPIO %d not initialized - Can't read the input.", gpio.pin); + return 0; + } + + char value_str[10]; + gs_sysfs_read_file(gpio_sys_fname, value_str, sizeof(value_str)); + + if (strncmp(value_str, "1", 10) == 0) { + return true; + } else { + return false; + } +} + +gs_error_t gs_gpio_sysfs_set(gs_gpio_t gpio, bool value, void * driver_data) +{ + const char *value_str = value ? "1" : "0"; + + char gpio_sys_fname[128]; + snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); + if (access(gpio_sys_fname, W_OK) == 0) + { + return gs_sysfs_write_file(gpio_sys_fname, value_str); + } + + log_error("GPIO %d not initialized - Can't set the output.", gpio.pin); + return GS_ERROR_ACCESS; +} + +void gs_gpio_sysfs_set_nc(gs_gpio_t gpio, bool value, void * driver_data) +{ + const char *value_str = value ? "1" : "0"; + + char gpio_sys_fname[128]; + snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); + if (access(gpio_sys_fname, W_OK) == 0) + { + gs_sysfs_write_file(gpio_sys_fname, value_str); + return; + } + log_error("GPIO %d not initialized - Can't set the output.", gpio.pin); +} + +gs_error_t gs_gpio_sysfs_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data) +{ + return GS_ERROR_NOT_IMPLEMENTED; +} + +const gs_gpio_driver_t gs_gpio_sysfs_driver = { + .get_handler = gs_gpio_sysfs_get, + .get_nc_handler = gs_gpio_sysfs_get_nc, + .set_handler = gs_gpio_sysfs_set, + .set_nc_handler = gs_gpio_sysfs_set_nc, + .init_as_interrupt_handler = gs_gpio_sysfs_init_as_interrupt, +}; + diff --git a/gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c b/gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c new file mode 100644 index 00000000..ce20c885 --- /dev/null +++ b/gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c @@ -0,0 +1,171 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +#define MAX_VPINS 500 + +#define FALLING_EDGE_FLAG 0x1 +#define RISING_EDGE_FLAG 0x2 + +typedef struct { + gs_gpio_t gpio; + bool output; + bool value; + bool in_use; + gs_gpio_isr_t isr; + uint8_t edge_flags; + uint32_t transistions; +} gs_gpio_virtual_t; + +static gs_gpio_virtual_t vpins[MAX_VPINS]; + +gs_error_t gs_gpio_virtual_initialize(gs_gpio_t gpio, bool output, bool value) +{ + gs_gpio_virtual_t * pin; + for (uint16_t i = 0; i < MAX_VPINS; i++) { + pin = &vpins[i]; + if ((!pin->in_use) || ((pin->gpio.pin == gpio.pin) && (pin->gpio.port == gpio.port))) { + pin->gpio = gpio; + pin->output = output; + pin->value = value; + pin->in_use = true; + return GS_OK; + } + } + return GS_ERROR_FULL; +} + +static gs_gpio_virtual_t * find_vpin(gs_gpio_t * gpio) +{ + gs_gpio_virtual_t * pin; + for (uint16_t i = 0; i < MAX_VPINS; i++) { + pin = &vpins[i]; + if (pin->gpio.pin == gpio->pin) { + if (pin->gpio.port == gpio->port) { + if (pin->in_use) { + return pin; + } + } + } + } + return NULL; +} + +gs_error_t gs_gpio_virtual_get(gs_gpio_t gpio, bool *value, void * driver_data) +{ + gs_gpio_virtual_t * pin = find_vpin(&gpio); + if (pin) { + *value = pin->value; + return GS_OK; + } + return GS_ERROR_NOT_FOUND; +} + +bool gs_gpio_virtual_get_nc(gs_gpio_t gpio, void * driver_data) +{ + gs_gpio_virtual_t * pin = find_vpin(&gpio); + if (pin) { + return pin->value; + } + return false; +} + +gs_error_t gs_gpio_virtual_set(gs_gpio_t gpio, bool value, void * driver_data) +{ + gs_gpio_virtual_t * pin = find_vpin(&gpio); + if (pin) { + if (pin->output) { + if (pin->value != value) { + pin->value = value; + pin->transistions++; + } + return GS_OK; + } + return GS_ERROR_PERM; + } + return GS_ERROR_NOT_FOUND; +} + +void gs_gpio_virtual_set_nc(gs_gpio_t gpio, bool value, void * driver_data) +{ + gs_gpio_virtual_t * pin = find_vpin(&gpio); + if (pin) { + if (pin->output) { + if (pin->value != value) { + pin->value = value; + pin->transistions++; + } + } + } +} + +gs_error_t gs_gpio_virtual_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data) +{ + gs_gpio_virtual_t * pin; + for (uint16_t i = 0; i < MAX_VPINS; i++) { + pin = &vpins[i]; + if ((!pin->in_use) || ((pin->gpio.pin == gpio.pin) && (pin->gpio.port == gpio.port))) { + pin->gpio = gpio; + pin->output = false; + pin->value = 0; + pin->in_use = true; + pin->isr = conf->isr; + if (conf->falling_edge) { + pin->edge_flags |= FALLING_EDGE_FLAG; + } + if (conf->rising_edge) { + pin->edge_flags |= RISING_EDGE_FLAG; + } + return GS_OK; + } + } + return GS_ERROR_FULL; +} + +gs_error_t gs_gpio_virtual_force_set(gs_gpio_t gpio, bool value) +{ + gs_gpio_virtual_t * pin = find_vpin(&gpio); + if (pin) { + bool old_value = pin->value; + if (old_value != value) { + pin->value = value; + pin->transistions++; + if (pin->isr) { + if ((old_value == false) && (pin->edge_flags & RISING_EDGE_FLAG)) { + pin->isr(NULL); + } else if ((old_value == true) && (pin->edge_flags & FALLING_EDGE_FLAG)) { + pin->isr(NULL); + } + } + } + return GS_OK; + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_gpio_virtual_get_transistions(gs_gpio_t gpio, uint32_t * transitions) +{ + gs_gpio_virtual_t * pin = find_vpin(&gpio); + if (pin) { + *transitions = pin->transistions; + pin->transistions = 0; + return GS_OK; + } + return GS_ERROR_NOT_FOUND; +} + +const gs_gpio_driver_t gs_gpio_virtual_driver = { + .get_handler = gs_gpio_virtual_get, + .get_nc_handler = gs_gpio_virtual_get_nc, + .set_handler = gs_gpio_virtual_set, + .set_nc_handler = gs_gpio_virtual_set_nc, + .init_as_interrupt_handler = gs_gpio_virtual_init_as_interrupt, +}; + + +const gs_gpio_driver_entry_t gs_gpio_virtual_driver_entry_all = { + .port = GS_GPIO_ALL_PORTS, + .pin = GS_GPIO_ALL_PINS, + .driver = &gs_gpio_virtual_driver, + .driver_data = NULL, +}; diff --git a/gomspace/libutil/src/linux/drivers/i2c/i2c.c b/gomspace/libutil/src/linux/drivers/i2c/i2c.c new file mode 100644 index 00000000..679ae3f7 --- /dev/null +++ b/gomspace/libutil/src/linux/drivers/i2c/i2c.c @@ -0,0 +1,144 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +#define MAX_DRIVERS 20 +#define HIGHEST_I2C_ADDR 127 + +typedef struct { + gs_i2c_master_driver_entry_t entry; + bool in_use; +} gs_i2c_master_driver_handle_t; + +typedef struct { + gs_i2c_slave_driver_entry_t entry; + bool in_use; +} gs_i2c_slave_driver_handle_t; + +static gs_i2c_master_driver_handle_t master_drivers[MAX_DRIVERS]; +static gs_i2c_slave_driver_handle_t slave_drivers[MAX_DRIVERS]; + +static uint8_t max_index_master_in_use = 0; +static uint8_t max_index_slave_in_use = 0; + +gs_error_t gs_i2c_master_transaction(uint8_t device, uint8_t addr, const void * tx, + size_t txlen, + void * rx, + size_t rxlen, + int timeout_ms) +{ + GS_CHECK_RANGE(addr <= HIGHEST_I2C_ADDR); + gs_i2c_master_driver_handle_t * handle; + for (int i = max_index_master_in_use; i >= 0; i--) { + handle = &master_drivers[i]; + if (((device == handle->entry.device) || (handle->entry.device == GS_I2C_ALL_DEVICES)) + && ((addr == handle->entry.addr) || (handle->entry.addr == GS_I2C_ALL_ADDR)) + && (handle->in_use == true)) { + if (handle->entry.driver->master_transaction_handler) { + return handle->entry.driver->master_transaction_handler(device, addr, tx, txlen, rx, rxlen, timeout_ms, handle->entry.driver_data); + } + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_i2c_master_register_driver(const gs_i2c_master_driver_entry_t * driver_entry) +{ + GS_CHECK_ARG(driver_entry != NULL); + GS_CHECK_ARG(driver_entry->driver != NULL); + + GS_CHECK_RANGE((driver_entry->addr == GS_I2C_ALL_ADDR) || (driver_entry->addr <= HIGHEST_I2C_ADDR)); + + gs_i2c_master_driver_handle_t * handle; + for (uint8_t i = 0; i < MAX_DRIVERS; i++) { + handle = &master_drivers[i]; + if (handle->in_use == false) { + handle->entry = *driver_entry; + handle->in_use = true; + max_index_master_in_use = i; + return GS_OK; + } + } + + /* Not enough space in buffer */ + return GS_ERROR_FULL; +} + +static inline gs_i2c_slave_driver_entry_t * gs_slave_find_driver_entry(uint8_t device) +{ + gs_i2c_slave_driver_handle_t * handle; + for (int i = max_index_slave_in_use; i >= 0; i--) { + handle = &slave_drivers[i]; + if (((device == handle->entry.device) || (handle->entry.device == GS_I2C_ALL_DEVICES)) + && (handle->in_use == true)) { + return &handle->entry; + } + } + return NULL; +} + +gs_error_t gs_i2c_slave_start(uint8_t device) +{ + gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); + if (driver_entry) { + if (driver_entry->driver->start_handler) { + return driver_entry->driver->start_handler(device, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_i2c_slave_set_rx(uint8_t device, gs_i2c_slave_receive_t rx) +{ + gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); + if (driver_entry) { + if (driver_entry->driver->set_rx_handler) { + return driver_entry->driver->set_rx_handler(device, rx, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_i2c_slave_set_get_rx_buf(uint8_t device, gs_i2c_slave_get_rx_buf_t get_rx_buf, size_t buf_length) +{ + gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); + if (driver_entry) { + if (driver_entry->driver->set_get_rx_buf_handler) { + return driver_entry->driver->set_get_rx_buf_handler(device, get_rx_buf, buf_length, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_i2c_slave_set_response(uint8_t device, const uint8_t * tx, size_t tx_length) +{ + gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); + if (driver_entry) { + if (driver_entry->driver->set_response_handler) { + return driver_entry->driver->set_response_handler(device, tx, tx_length, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_i2c_slave_register_driver(const gs_i2c_slave_driver_entry_t * driver_entry) +{ + GS_CHECK_ARG(driver_entry != NULL); + GS_CHECK_ARG(driver_entry->driver != NULL); + + gs_i2c_slave_driver_handle_t * handle; + for (uint8_t i = 0; i < MAX_DRIVERS; i++) { + handle = &slave_drivers[i]; + if (handle->in_use == false) { + handle->entry = *driver_entry; + handle->in_use = true; + max_index_slave_in_use = i; + return GS_OK; + } + } + + /* Not enough space in buffer */ + return GS_ERROR_FULL; +} diff --git a/gomspace/libutil/src/linux/drivers/spi/spi.c b/gomspace/libutil/src/linux/drivers/spi/spi.c new file mode 100644 index 00000000..6756482c --- /dev/null +++ b/gomspace/libutil/src/linux/drivers/spi/spi.c @@ -0,0 +1,137 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +#define MAX_DRIVERS 20 + +typedef struct { + gs_spi_master_driver_entry_t entry; + bool in_use; +} gs_spi_master_driver_handle_t; + +typedef struct { + gs_spi_slave_driver_entry_t entry; + bool in_use; +} gs_spi_slave_driver_handle_t; + +static gs_spi_master_driver_handle_t master_drivers[MAX_DRIVERS]; +static gs_spi_slave_driver_handle_t slave_drivers[MAX_DRIVERS]; + +static uint8_t max_index_master_in_use = 0; +static uint8_t max_index_slave_in_use = 0; + +static inline gs_spi_master_driver_entry_t * gs_master_find_driver_entry(uint8_t slave) +{ + gs_spi_master_driver_handle_t * handle; + for (int i = max_index_master_in_use; i >= 0; i--) { + handle = &master_drivers[i]; + if (((slave == handle->entry.slave) || (handle->entry.slave == GS_SPI_ALL_SLAVES)) && (handle->in_use == true)) { + return &handle->entry; + } + } + return NULL; +} + +gs_error_t gs_spi_master_transaction(uint8_t slave, const void * tx, void * rx, size_t size, int timeout_ms) +{ + gs_spi_master_trans_t trans = {.tx = tx, .rx = rx, .size = size}; + return gs_spi_master_transactions(slave, &trans, 1, timeout_ms); +} + +gs_error_t gs_spi_master_transactions(uint8_t slave, gs_spi_master_trans_t *trans, size_t count, int timeout_ms) +{ + gs_spi_master_driver_entry_t * driver_entry = gs_master_find_driver_entry(slave); + if (driver_entry) { + if (driver_entry->driver->master_transactions_handler) { + return driver_entry->driver->master_transactions_handler(slave, trans, count, timeout_ms, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_spi_master_register_driver(const gs_spi_master_driver_entry_t * driver_entry) +{ + GS_CHECK_ARG(driver_entry != NULL); + GS_CHECK_ARG(driver_entry->driver != NULL); + + gs_spi_master_driver_handle_t * handle; + for (uint8_t i = 0; i < MAX_DRIVERS; i++) { + handle = &master_drivers[i]; + if (handle->in_use == false) { + handle->entry = *driver_entry; + handle->in_use = true; + max_index_master_in_use = i; + return GS_OK; + } + } + + /* Not enough space in buffer */ + return GS_ERROR_FULL; +} + +static inline gs_spi_slave_driver_entry_t * gs_slave_find_driver_entry(uint8_t device) +{ + gs_spi_slave_driver_handle_t * handle; + for (int i = max_index_slave_in_use; i >= 0; i--) { + handle = &slave_drivers[i]; + if (((device == handle->entry.device) || (handle->entry.device == GS_SPI_ALL_DEVICES)) + && (handle->in_use == true)) { + return &handle->entry; + } + } + return NULL; +} + +gs_error_t gs_spi_slave_start(uint8_t device) +{ + gs_spi_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); + if (driver_entry) { + if (driver_entry->driver->start_handler) { + return driver_entry->driver->start_handler(device, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_spi_slave_set_rx(uint8_t device, gs_spi_slave_receive_t rx) +{ + gs_spi_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); + if (driver_entry) { + if (driver_entry->driver->set_rx_handler) { + return driver_entry->driver->set_rx_handler(device, rx, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_spi_slave_set_response(uint8_t device, size_t offset, const uint8_t * tx, size_t size) +{ + gs_spi_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); + if (driver_entry) { + if (driver_entry->driver->set_response_handler) { + return driver_entry->driver->set_response_handler(device, offset, tx, size, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_spi_slave_register_driver(const gs_spi_slave_driver_entry_t * driver_entry) +{ + GS_CHECK_ARG(driver_entry != NULL); + GS_CHECK_ARG(driver_entry->driver != NULL); + + gs_spi_slave_driver_handle_t * handle; + for (uint8_t i = 0; i < MAX_DRIVERS; i++) { + handle = &slave_drivers[i]; + if (handle->in_use == false) { + handle->entry = *driver_entry; + handle->in_use = true; + max_index_slave_in_use = i; + return GS_OK; + } + } + /* Not enough space in buffer */ + return GS_ERROR_FULL; +} diff --git a/gomspace/libutil/src/linux/drivers/sys/memory.c b/gomspace/libutil/src/linux/drivers/sys/memory.c new file mode 100644 index 00000000..8def9988 --- /dev/null +++ b/gomspace/libutil/src/linux/drivers/sys/memory.c @@ -0,0 +1,30 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +gs_error_t gs_mem_get_int_ram_stat(gs_mem_ram_stat_t * ram_stat) +{ + return GS_ERROR_NOT_SUPPORTED; +} + +gs_error_t gs_mem_get_ext_ram_stat(gs_mem_ram_stat_t * ram_stat) +{ + struct sysinfo info; + int res = sysinfo(&info); + if (res != GS_OK) { + return res; + } + + ram_stat->total = info.totalram; + ram_stat->max_available = -1; + ram_stat->min_available = -1; + ram_stat->available = info.freeram; + + return GS_OK; +} + +gs_mem_ram_type_t gs_mem_get_ram_default() +{ + return GS_MEM_RAM_TYPE_EXTERNAL; +} diff --git a/gomspace/libutil/src/linux/function.c b/gomspace/libutil/src/linux/function.c new file mode 100644 index 00000000..9e0f7c0f --- /dev/null +++ b/gomspace/libutil/src/linux/function.c @@ -0,0 +1,41 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +typedef struct { + const char * short_name; + const char * long_name; + gs_function_t function; +} gs_function_register_t; + +static gs_function_register_t registry[10]; + +gs_error_t gs_function_register(const char * short_name, const char * long_name, gs_function_t function) +{ + for (unsigned int i = 0; i < GS_ARRAY_SIZE(registry); ++i) { + gs_function_register_t * cb = ®istry[i]; + if ((cb->short_name == NULL) && (cb->long_name == NULL)) { + cb->short_name = short_name; + cb->long_name = long_name; + cb->function = function; + return GS_OK; + } + } + return GS_ERROR_FULL; +} + +gs_error_t gs_function_invoke(const char * name, void * arg) +{ + for (unsigned int i = 0; i < GS_ARRAY_SIZE(registry); ++i) { + gs_function_register_t * cb = ®istry[i]; + if ((gs_string_empty(cb->short_name) == false) && (strcasecmp(cb->short_name, name) == 0)) { + return (cb->function)(arg); + } + if ((gs_string_empty(cb->long_name) == false) && (strcasecmp(cb->long_name, name) == 0)) { + return (cb->function)(arg); + } + } + + return GS_ERROR_NOT_IMPLEMENTED; +} diff --git a/gomspace/libutil/src/linux/mutex.c b/gomspace/libutil/src/linux/mutex.c new file mode 100644 index 00000000..00336510 --- /dev/null +++ b/gomspace/libutil/src/linux/mutex.c @@ -0,0 +1,59 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +gs_error_t gs_mutex_create(gs_mutex_t * mutex) +{ + if (mutex == NULL) { + return GS_ERROR_ARG; + } + + *mutex = malloc(sizeof(pthread_mutex_t)); + if (*mutex == NULL) { + return GS_ERROR_ALLOC; + } + + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + int res = pthread_mutex_init(*mutex, &attr); + if (res < 0) { + res = gs_error(errno); + free(*mutex); + } + + return res; +} + +gs_error_t gs_mutex_destroy(gs_mutex_t mutex) +{ + int res = GS_OK; + if (mutex) { + res = pthread_mutex_destroy(mutex); + if (res < 0) { + res = gs_error(errno); + } + free(mutex); + } + return res; +} + +gs_error_t gs_mutex_lock(gs_mutex_t mutex) +{ + int res = pthread_mutex_lock(mutex); + if (res < 0) { + res = gs_error(errno); + } + return res; +} + +gs_error_t gs_mutex_unlock(gs_mutex_t mutex) +{ + int res = pthread_mutex_unlock(mutex); + if (res < 0) { + res = gs_error(errno); + } + return res; +} diff --git a/gomspace/libutil/src/linux/queue.c b/gomspace/libutil/src/linux/queue.c new file mode 100644 index 00000000..cb477f70 --- /dev/null +++ b/gomspace/libutil/src/linux/queue.c @@ -0,0 +1,217 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + * Inspired by c-pthread-queue by Matthew Dickinson + * http://code.google.com/p/c-pthread-queue/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PTHREAD_QUEUE_ARG GS_ERROR_ARG +#define PTHREAD_QUEUE_EMPTY GS_ERROR_NOT_FOUND +#define PTHREAD_QUEUE_FULL GS_ERROR_FULL +#define PTHREAD_QUEUE_TIMEOUT GS_ERROR_TIMEOUT +#define PTHREAD_QUEUE_OK GS_OK + +typedef struct gs_pthread_queue { + uint8_t * buffer; + size_t size; + size_t item_size; + size_t items; + size_t in; + size_t out; + pthread_mutex_t mutex; + pthread_cond_t cond_full; + pthread_cond_t cond_empty; +} pthread_queue_t; + +static pthread_queue_t * pthread_queue_create(size_t length, size_t item_size) +{ + pthread_queue_t * q = malloc(sizeof(pthread_queue_t)); + + if (q != NULL) { + q->buffer = malloc(length*item_size); + if (q->buffer != NULL) { + q->size = length; + q->item_size = item_size; + q->items = 0; + q->in = 0; + q->out = 0; + if (pthread_mutex_init(&(q->mutex), NULL) || pthread_cond_init(&(q->cond_full), NULL) || pthread_cond_init(&(q->cond_empty), NULL)) { + free(q->buffer); + free(q); + q = NULL; + } + } else { + free(q); + q = NULL; + } + } + + return q; +} + +static void pthread_queue_delete(pthread_queue_t * q) +{ + if (q) { + free(q->buffer); + free(q); + } +} + +static int pthread_queue_enqueue(pthread_queue_t * queue, const void * value, uint32_t timeout) +{ + /* Calculate timeout */ + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts)) { + return PTHREAD_QUEUE_ARG; + } + + uint32_t sec = timeout / 1000; + uint32_t nsec = (timeout - 1000 * sec) * 1000000; + + ts.tv_sec += sec; + + if (ts.tv_nsec + nsec > 1000000000) + ts.tv_sec++; + + ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; + + /* Get queue lock */ + pthread_mutex_lock(&(queue->mutex)); + + while (queue->items == queue->size) { + int ret = -1; + if (timeout) { + ret = pthread_cond_timedwait(&(queue->cond_full), &(queue->mutex), &ts); + } + if (ret) { + pthread_mutex_unlock(&(queue->mutex)); + return PTHREAD_QUEUE_TIMEOUT; + } + } + + /* Coby object from input buffer */ + memcpy(queue->buffer+(queue->in * queue->item_size), value, queue->item_size); + queue->items++; + queue->in = (queue->in + 1) % queue->size; + pthread_mutex_unlock(&(queue->mutex)); + + /* Nofify blocked threads */ + pthread_cond_broadcast(&(queue->cond_empty)); + + return PTHREAD_QUEUE_OK; +} + +static int pthread_queue_dequeue(pthread_queue_t * queue, void * buf, uint32_t timeout) +{ + /* Calculate timeout */ + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts)) { + return PTHREAD_QUEUE_ARG; + } + + uint32_t sec = timeout / 1000; + uint32_t nsec = (timeout - 1000 * sec) * 1000000; + + ts.tv_sec += sec; + + if (ts.tv_nsec + nsec > 1000000000) + ts.tv_sec++; + + ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; + + /* Get queue lock */ + pthread_mutex_lock(&(queue->mutex)); + while (queue->items == 0) { + int ret = -1; + if (timeout) { + ret = pthread_cond_timedwait(&(queue->cond_empty), &(queue->mutex), &ts); + } + if (ret) { + pthread_mutex_unlock(&(queue->mutex)); + return PTHREAD_QUEUE_TIMEOUT; + } + } + + /* Coby object to output buffer */ + memcpy(buf, queue->buffer+(queue->out * queue->item_size), queue->item_size); + queue->items--; + queue->out = (queue->out + 1) % queue->size; + pthread_mutex_unlock(&(queue->mutex)); + + /* Nofify blocked threads */ + pthread_cond_broadcast(&(queue->cond_full)); + + return PTHREAD_QUEUE_OK; +} + +static size_t pthread_queue_items(pthread_queue_t * queue) +{ + pthread_mutex_lock(&(queue->mutex)); + size_t items = queue->items; + pthread_mutex_unlock(&(queue->mutex)); + return items; +} + +gs_error_t gs_queue_create(size_t items, size_t item_size, gs_queue_t * queue) +{ + if (queue == NULL) { + return GS_ERROR_ARG; + } + pthread_queue_t * q = pthread_queue_create(items, item_size); + if (q == NULL) { + return GS_ERROR_ALLOC; + } + *queue = q; + return GS_OK; +} + +gs_error_t gs_queue_destroy(gs_queue_t queue) +{ + pthread_queue_delete(queue); + return GS_OK; +} + +gs_error_t gs_queue_enqueue(gs_queue_t queue, const void *value, int timeout_ms) +{ + return pthread_queue_enqueue(queue, value, (timeout_ms >= 0) ? timeout_ms : INT_MAX); +} + +gs_error_t gs_queue_enqueue_isr(gs_queue_t queue, const void * value, gs_context_switch_t * cswitch) +{ + (void) cswitch; + gs_error_t error = gs_queue_enqueue(queue, value, 0); + return (error != GS_ERROR_TIMEOUT) ? error : GS_ERROR_FULL; +} + +gs_error_t gs_queue_dequeue(gs_queue_t queue, int timeout_ms, void *buf) +{ + return pthread_queue_dequeue(queue, buf, (timeout_ms >= 0) ? timeout_ms : INT_MAX); +} + +gs_error_t gs_queue_dequeue_isr(gs_queue_t queue, gs_context_switch_t * cswitch, void *buf) +{ + (void) cswitch; + gs_error_t error = gs_queue_dequeue(queue, 0, buf); + return (error != GS_ERROR_TIMEOUT) ? error : GS_ERROR_NOT_FOUND; +} + +unsigned int gs_queue_size(gs_queue_t queue) +{ + if (queue) { + return pthread_queue_items(queue); + } + return 0; +} + +unsigned int gs_queue_size_isr(gs_queue_t queue) +{ + return gs_queue_size(queue); +} diff --git a/gomspace/libutil/src/linux/rtc.c b/gomspace/libutil/src/linux/rtc.c new file mode 100644 index 00000000..ff241d58 --- /dev/null +++ b/gomspace/libutil/src/linux/rtc.c @@ -0,0 +1,78 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +static gs_error_t gs_rtc_get(void * driver_data, gs_timestamp_t * return_time) +{ + if (return_time == NULL) { + return GS_ERROR_ARG; + } + + return_time->tv_sec = 0; + return_time->tv_nsec = 0; + + int fd = open("/dev/rtc", O_RDONLY | O_CLOEXEC); + if (fd < 0) { + return gs_error(errno); + } + + struct tm tm; + memset(&tm, 0, sizeof(tm)); + int res = ioctl(fd, RTC_RD_TIME, &tm); + close(fd); + if (res < 0) { + return gs_error(errno); + } + + time_t time = mktime(&tm); + if (time < 0) { + return GS_ERROR_DATA; + } + + return_time->tv_sec = (uint32_t) time; + + return GS_OK; +} + +static gs_error_t gs_rtc_set(void * driver_data, const gs_timestamp_t * set_time) +{ + if (set_time == NULL) { + return GS_ERROR_ARG; + } + + int fd = open("/dev/rtc", O_RDONLY | O_CLOEXEC); + if (fd < 0) { + return gs_error(errno); + } + + const time_t now = set_time->tv_sec; + struct tm tm; + gmtime_r(&now, &tm); + int res = ioctl(fd, RTC_SET_TIME, &tm); + close(fd); + if (res < 0) { + return gs_error(errno); + } + + return GS_OK; +} + +gs_error_t gs_rtc_register_linux(bool get, bool set) +{ + static gs_rtc_driver_t rtc_driver; + if (get) { + rtc_driver.get_time = gs_rtc_get; + } + if (set) { + rtc_driver.set_time = gs_rtc_set; + } + return gs_rtc_register(&rtc_driver, NULL); +} diff --git a/gomspace/libutil/src/linux/sem.c b/gomspace/libutil/src/linux/sem.c new file mode 100644 index 00000000..b4d2c09d --- /dev/null +++ b/gomspace/libutil/src/linux/sem.c @@ -0,0 +1,89 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include + +gs_error_t gs_sem_create(unsigned int initialValue, gs_sem_t * sem) +{ + if (sem == NULL) { + return GS_ERROR_ARG; + } + + *sem = malloc(sizeof(sem_t)); + if (*sem == NULL) { + return GS_ERROR_ALLOC; + } + + int res = sem_init(*sem, 0, initialValue); + if (res < 0) { + res = gs_error(errno); + free(*sem); + } + + return res; +} + +gs_error_t gs_sem_destroy(gs_sem_t sem) +{ + int res = GS_OK; + if (sem) { + res = sem_destroy(sem); + if (res < 0) { + res = gs_error(errno); + } + free(sem); + } + return res; +} + +gs_error_t gs_sem_wait(gs_sem_t sem, int timeout_ms) +{ + int res; + + if (timeout_ms < 0) { + res = sem_wait(sem); + } else { + struct timespec ts; + res = clock_gettime(CLOCK_REALTIME, &ts); + if (res == 0) { + const uint32_t ms = (uint32_t)timeout_ms; + uint32_t sec = ms / 1000; + uint32_t nsec = (ms - (1000 * sec)) * 1000000; + + ts.tv_sec += sec; + + if (ts.tv_nsec + nsec >= 1000000000) { + ts.tv_sec++; + } + + ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; + + res = sem_timedwait(sem, &ts); + } + } + if (res < 0) { + res = gs_error(errno); + } + return res; +} + +gs_error_t gs_sem_post(gs_sem_t sem) +{ + int res = sem_post(sem); + if (res < 0) { + res = gs_error(errno); + } + return res; +} + +gs_error_t gs_sem_post_isr(gs_sem_t sem, gs_context_switch_t * cswitch) +{ + (void) cswitch; + int res = sem_post(sem); + if (res < 0) { + res = gs_error(errno); + } + return res; +} diff --git a/gomspace/libutil/src/linux/signal.c b/gomspace/libutil/src/linux/signal.c new file mode 100644 index 00000000..826bc325 --- /dev/null +++ b/gomspace/libutil/src/linux/signal.c @@ -0,0 +1,38 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +static void gs_signal_default_handler(int signo, siginfo_t *si, void *context) +{ + exit(GS_EXITCODE_SIGNAL(signo)); // ensure atexit are invoked +} + +gs_error_t gs_signal_catch(int signal, gs_signal_handler handler) +{ + if (handler == NULL) { + handler = gs_signal_default_handler; + } + struct sigaction sa = { .sa_flags = SA_SIGINFO, + .sa_sigaction = handler}; + if (sigemptyset(&sa.sa_mask)) { + return GS_ERROR_UNKNOWN; + } + if (sigaction(signal, &sa, NULL)) { + return GS_ERROR_UNKNOWN; + } + return GS_OK; +} + +gs_error_t gs_signal_ignore(int signal) +{ + struct sigaction sa = { .sa_flags = 0, + .sa_handler = SIG_IGN}; // handle signal by ignoring + if (sigemptyset(&sa.sa_mask)) { + return GS_ERROR_UNKNOWN; + } + if (sigaction(signal, &sa, NULL)) { + return GS_ERROR_UNKNOWN; + } + return GS_OK; +} diff --git a/gomspace/libutil/src/linux/stdio.c b/gomspace/libutil/src/linux/stdio.c new file mode 100644 index 00000000..0fa052b7 --- /dev/null +++ b/gomspace/libutil/src/linux/stdio.c @@ -0,0 +1,36 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +gs_error_t gs_stdio_putchar(int ch) +{ + const int res = putchar(ch); + if (res < 0) { + return GS_ERROR_IO; + } + return GS_OK; +} + +gs_error_t gs_stdio_getchar_timed(int timeout_ms, int * ch) +{ + struct pollfd fds = {STDIN_FILENO, POLLIN, 0}; + const int res = poll(&fds, 1, timeout_ms); + + if (res == 0) { + return GS_ERROR_TIMEOUT; + } + + if ((res > 0) && (fds.revents & POLLIN)) { + int tmp = getchar(); + if (tmp >= 0) { + if (ch) { + *ch = tmp; + } + return GS_OK; + } + } + + return GS_ERROR_IO; +} diff --git a/gomspace/libutil/src/linux/sysfs_helper.c b/gomspace/libutil/src/linux/sysfs_helper.c new file mode 100644 index 00000000..2cdb390a --- /dev/null +++ b/gomspace/libutil/src/linux/sysfs_helper.c @@ -0,0 +1,48 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +gs_error_t gs_sysfs_write_file(const char *path, const char *value) +{ + log_trace("sysfs: write %s to %s", value, path); + + int fd = open(path, O_WRONLY); + if (fd < 0) { + return GS_ERROR_HANDLE; + } + + size_t len = strlen(value); + ssize_t bytes = write(fd, value, len); + close(fd); + if (bytes < 0) { + return GS_ERROR_NO_DATA; + } + + return (len == (size_t)bytes) ? GS_OK : GS_ERROR_NO_DATA; +} + +gs_error_t gs_sysfs_read_file(const char *path, char *value, size_t len) +{ + log_trace("sysfs: read %s", path); + + int fd = open(path, O_RDONLY); + if (fd < 0) { + return GS_ERROR_HANDLE; + } + + ssize_t bytes = read(fd, value, len); + close(fd); + if (bytes < 0) { + return GS_ERROR_DATA; + } + + return GS_OK; +} diff --git a/gomspace/libutil/src/linux/thread.c b/gomspace/libutil/src/linux/thread.c new file mode 100644 index 00000000..43de1815 --- /dev/null +++ b/gomspace/libutil/src/linux/thread.c @@ -0,0 +1,89 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +gs_error_t gs_thread_create(const char * const name, + gs_thread_func_t func, + void * parameter, + size_t stack_size, + gs_thread_priority_t priority, + uint32_t flags, + gs_thread_t * return_handle) +{ + gs_time_uptime(); // force initialize of static offset + + pthread_attr_t attr; + int res = pthread_attr_init(&attr); + if (res) { + return GS_ERROR_ALLOC; + } + + if (flags & GS_THREAD_CREATE_JOINABLE) { + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + } else { + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + } + + gs_thread_t handle; + res = pthread_create(&handle, &attr, func, parameter); + pthread_attr_destroy(&attr); + if (res) { + return GS_ERROR_ALLOC; + } + + if (return_handle) { + *return_handle = handle; + } + + return GS_OK; +} + +gs_error_t gs_thread_create_with_stack(const char * const name, + gs_thread_func_t func, + void * parameter, + size_t stack_size, + gs_stack_type_t *stack, + gs_thread_priority_t priority, + uint32_t flags, + gs_thread_t * return_handle) +{ + return gs_thread_create(name, func, parameter, stack_size, priority, flags, return_handle); +} + +void gs_thread_exit(void * exitValue) +{ + pthread_exit(exitValue); +} + +void gs_thread_sleep_ms(uint32_t time_ms) +{ + gs_time_sleep_ms(time_ms); +} + +gs_error_t gs_thread_join(gs_thread_t thread, void ** return_retval) +{ + gs_error_t error = GS_ERROR_ARG; + void * retval = 0; + if (thread) { + int res = pthread_join(thread, &retval); + if (res == 0) { + error = GS_OK; + } else { + retval = 0; + } + } + if (return_retval) { + *return_retval = retval; + } + return error; +} + +void gs_thread_block(void) +{ + /* Wait here forever */ + for (;;) { + gs_time_sleep_ms(10000); + } +} diff --git a/gomspace/libutil/src/linux/time.c b/gomspace/libutil/src/linux/time.c new file mode 100644 index 00000000..46377feb --- /dev/null +++ b/gomspace/libutil/src/linux/time.c @@ -0,0 +1,53 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +uint32_t gs_time_rel_ms(void) +{ + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { + return 0; + } + + return (uint32_t)((ts.tv_sec * 1000) + (ts.tv_nsec/1000000)); +} + +uint32_t gs_time_rel_ms_isr(void) +{ + return gs_time_rel_ms(); +} + +static uint32_t uptime_offset = 0; +uint32_t gs_time_uptime(void) +{ + uint32_t seconds; + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { + seconds = 0; + } else { + seconds = (uint32_t) ts.tv_sec; + } + if (uptime_offset == 0) { + uptime_offset = seconds; + } + return (seconds - uptime_offset); +} + +void gs_time_sleep_ns(uint64_t time_ns) +{ + struct timespec ts; + ts.tv_sec = (time_ns / GS_TIMESTAMP_NSEC_PER_SEC); + ts.tv_nsec = (time_ns % GS_TIMESTAMP_NSEC_PER_SEC); + + // improvement: check return code (INTR) and use remaining. + nanosleep(&ts, NULL); +} + +void gs_time_sleep_ms(uint32_t time_ms) +{ + uint64_t ns = time_ms; + ns *= 1000000LL; + gs_time_sleep_ns( ns); +} diff --git a/gomspace/libutil/src/lock.c b/gomspace/libutil/src/lock.c new file mode 100644 index 00000000..76be91bd --- /dev/null +++ b/gomspace/libutil/src/lock.c @@ -0,0 +1,30 @@ +/* Copyright (c) 2013-2019 GomSpace A/S. All rights reserved. */ + +#include "lock.h" +#include + +static gs_mutex_t gs_lock; + +gs_error_t gs_lock_init(void) +{ + if (gs_lock == NULL) { + return gs_mutex_create(&gs_lock); + } + return GS_OK; +} + +gs_error_t gs_lock_lock(void) +{ + if (gs_lock == NULL) { + gs_error_t error = gs_lock_init(); + if (error) { + return error; + } + } + return gs_mutex_lock(gs_lock); +} + +gs_error_t gs_lock_unlock(void) +{ + return gs_mutex_unlock(gs_lock); +} diff --git a/gomspace/libutil/src/lock.h b/gomspace/libutil/src/lock.h new file mode 100644 index 00000000..b22841e8 --- /dev/null +++ b/gomspace/libutil/src/lock.h @@ -0,0 +1,14 @@ +/* Copyright (c) 2013-2019 GomSpace A/S. All rights reserved. */ +/** + @file + + Basic/core locking. + + Use for rare read/write locking, e.g. protecting register/de-regsiter functions. +*/ + +#include + +gs_error_t gs_lock_init(void); +gs_error_t gs_lock_lock(void); +gs_error_t gs_lock_unlock(void); diff --git a/gomspace/libutil/src/log/appender/console.c b/gomspace/libutil/src/log/appender/console.c new file mode 100644 index 00000000..818248b3 --- /dev/null +++ b/gomspace/libutil/src/log/appender/console.c @@ -0,0 +1,88 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +// generated by waf configure -> GS_LOG_ENABLE_ISR_LOGS +#include + +static gs_log_appender_console_cb_t g_console_log_cb = NULL; +static gs_mutex_t g_log_console_mutex = NULL; + +gs_error_t gs_log_console_append_init(gs_log_appender_t *appender) +{ + gs_error_t ret = GS_OK; + if (g_log_console_mutex == NULL) { + ret = gs_mutex_create(&g_log_console_mutex); + if (ret != GS_OK) { + g_log_console_mutex = NULL; + } + } + return ret; +} + +static void gs_log_console_append_isr(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) +{ + va_list my_va; + va_copy(my_va, va); + + const char * color = gs_log_level_to_color_begin(level); + const char * end_color = gs_log_level_to_color_end(); + const char clevel = gs_log_level_to_char(level); + + // print log + printf("%s%04"PRIu32".%06"PRIu32" %c %s: ", color, ts->tv_sec, ts->tv_nsec / 1000, clevel, group->name); + GS_PGM_VPRINTF(format, my_va); + printf("%s\r\n", end_color); + + va_end(my_va); +} + +static void gs_log_console_append(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) +{ + if (g_console_log_cb) + return g_console_log_cb(appender, level, group, ts, format, va); + + if (g_log_console_mutex) { + gs_mutex_lock(g_log_console_mutex); + } + + gs_log_console_append_isr(appender, level, group, ts, format, va); + + if (g_log_console_mutex) { + gs_mutex_unlock(g_log_console_mutex); + } +} + +static void gs_log_console_append_get_info(gs_log_appender_t *appender, char *info_str, uint8_t str_size) +{ + if (!info_str) { + return; + } + + snprintf(info_str, str_size, "Prints on stdout"); +} + +gs_error_t gs_log_appender_console_set_cb(gs_log_appender_console_cb_t cb) +{ + g_console_log_cb = cb; + return GS_OK; +} + +static const gs_log_appender_driver_t console_appender_driver = { + .init = gs_log_console_append_init, + .append = gs_log_console_append, +#ifdef GS_LOG_ENABLE_ISR_LOGS + .append_isr = gs_log_console_append_isr, +#else + .append_isr = 0, +#endif + .info = gs_log_console_append_get_info, +}; + +gs_log_appender_t gs_log_appender_console = { + .name = "console", + .drv = &console_appender_driver, + .drv_config = 0, + .mask = LOG_ALL_MASK, +}; diff --git a/gomspace/libutil/src/log/appender/simple_file.c b/gomspace/libutil/src/log/appender/simple_file.c new file mode 100644 index 00000000..f74a19e7 --- /dev/null +++ b/gomspace/libutil/src/log/appender/simple_file.c @@ -0,0 +1,117 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#ifndef __AVR__ +#include +#include +#include + +#include +#include + +typedef struct simple_file_drv_data { + FILE *fp; + gs_mutex_t mutex; +} simple_file_drv_data_t; + +static gs_error_t gs_log_simple_file_init(gs_log_appender_t *appender) +{ + const gs_log_appender_simple_file_config_t *config = appender->drv_config; + + if (config == NULL || gs_string_empty(config->filename)) { + return GS_ERROR_ARG; + } + + simple_file_drv_data_t *drv_data = appender->drv_data; + if (drv_data == NULL) { + drv_data = calloc(1, sizeof(*drv_data)); + if (drv_data == NULL) { + return GS_ERROR_ALLOC; + } + } + + /* If file is already open - Close it first */ + if (drv_data->fp) { + gs_mutex_lock(drv_data->mutex); + fclose(drv_data->fp); + drv_data->fp = NULL; + gs_mutex_unlock(drv_data->mutex); + gs_mutex_destroy(drv_data->mutex); + } + + const char * mode = config->truncate ? "w" : "a"; + + drv_data->fp = fopen(config->filename, mode); + if (drv_data->fp == NULL) { + log_error("%s: failed to open log-file: [%s], mode: %s", __FUNCTION__, config->filename, mode); + free(drv_data); + drv_data = 0; + return GS_ERROR_IO; + } + + gs_mutex_create(&drv_data->mutex); + appender->drv_data = drv_data; /* Set driver data on appender */ + return GS_OK; +} + +static void gs_log_simple_file_append(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) +{ + va_list my_va; + va_copy(my_va, va); + + const gs_log_appender_simple_file_config_t *config = appender->drv_config; + simple_file_drv_data_t *drv_data = appender->drv_data; + if (drv_data == 0) { + va_end(my_va); + return; + } + + const char clevel = gs_log_level_to_char(level); + + const time_t t = ts->tv_sec; + struct tm result; + const char * tzone; + if (config->use_local_time) { + localtime_r(&t, &result); + tzone = ""; + } else { + gmtime_r(&t, &result); + tzone = "Z"; + } + + if (drv_data->mutex) { + gs_mutex_lock(drv_data->mutex); + } + { + fprintf(drv_data->fp, "%04d-%02d-%02d %02d:%02d:%02d.%06"PRIu32"%s %c %s: ", + result.tm_year + 1900, result.tm_mon + 1, result.tm_mday, + result.tm_hour, result.tm_min, result.tm_sec, + ts->tv_nsec / 1000, tzone, clevel, group->name); + vfprintf(drv_data->fp, format, my_va); + fprintf(drv_data->fp, "\r\n"); + fflush(drv_data->fp); + } + if (drv_data->mutex) { + gs_mutex_unlock(drv_data->mutex); + } + + va_end(my_va); +} + +static void gs_log_simple_file_append_info(gs_log_appender_t *appender, char *info_str, uint8_t str_size) +{ + if (!info_str) { + return; + } + + const gs_log_appender_simple_file_config_t *config = appender->drv_config; + snprintf(info_str, str_size, "Writes to file \"%s\"", config->filename); +} + +const gs_log_appender_driver_t gs_log_appender_simple_file_driver = { + .init = gs_log_simple_file_init, + .append = gs_log_simple_file_append, + .append_isr = 0, + .info = gs_log_simple_file_append_info, +}; + +#endif diff --git a/gomspace/libutil/src/log/commands.c b/gomspace/libutil/src/log/commands.c new file mode 100644 index 00000000..85ac7ae5 --- /dev/null +++ b/gomspace/libutil/src/log/commands.c @@ -0,0 +1,392 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include "local.h" +#include + + +// iterator context +typedef struct { + gs_command_context_t * ctx; + gs_log_group_t * first; + gs_log_appender_t * first_appender; + bool completer; + bool detailed; +} iter_group_t; + +#define FORMAT_BUF_SIZE 10 +static const char * format_mask(uint8_t mask, char * buf) +{ + snprintf(buf, FORMAT_BUF_SIZE, "%c%c%c%c%c%c", + (mask & LOG_ERROR_MASK) ? 'E' : '.', + (mask & LOG_WARNING_MASK) ? 'W' : '.', + (mask & LOG_NOTICE_MASK) ? 'N' : '.', + (mask & LOG_INFO_MASK) ? 'I' : '.', + (mask & LOG_DEBUG_MASK) ? 'D' : '.', + (mask & LOG_TRACE_MASK) ? 'T' : '.'); + return buf; +} + +static bool iter_print_group_appenders(void * ctx_in, gs_log_appender_t * appender) +{ + gs_bytebuffer_t *bb = ctx_in; + gs_bytebuffer_printf(bb, "%s,", appender->name); + return true; +} + +static bool iter_print_group(void * ctx_in, gs_log_group_t * group) +{ + iter_group_t * ctx = ctx_in; + char level_mask[FORMAT_BUF_SIZE]; + if (!ctx->completer) { + char appender_str[128] = "\0"; + gs_bytebuffer_t bb; + gs_bytebuffer_init(&bb, appender_str, sizeof(appender_str)); + gs_log_group_appender_iterate(group, &bb, iter_print_group_appenders); + if (ctx->detailed) { + gs_command_set_output_printf(ctx->ctx, group->name, "category", "0x%08x", group->category); + gs_command_set_output_printf(ctx->ctx, group->name, "mask", "%-6s (0x%02x)", format_mask(group->mask, level_mask), group->mask); + gs_command_set_output_printf(ctx->ctx, group->name, "appenders", appender_str); + } else { + gs_command_set_output_printf(ctx->ctx, NULL, NULL, "%-15s %-6s %s", group->name, format_mask(group->mask, level_mask), appender_str); + } + } else { + fprintf(ctx->ctx->out, " %-15s %-6s\r\n", + group->name, + format_mask(group->mask, level_mask)); + } + return true; +} + +static int cmd_log_group_list(gs_command_context_t * ctx) +{ + iter_group_t iter = {.ctx = ctx, .completer = false}; + + if (ctx->argc > 1) { + iter.detailed = true; + gs_log_group_iterate(ctx->argv[1], &iter, iter_print_group); + } else { + fprintf(ctx->out, "Group Mask Appenders\r\n"); + gs_log_group_iterate("*", &iter, iter_print_group); + } + return GS_OK; +} + +static bool iter_print_appender(void * ctx_in, gs_log_appender_t * appender) +{ + iter_group_t * ctx = ctx_in; + char level_mask[FORMAT_BUF_SIZE]; + if (!ctx->completer) { + if (ctx->detailed) { + gs_command_set_output_printf(ctx->ctx, appender->name, "mask", "%-6s (0x%02x)", format_mask(appender->mask, level_mask), appender->mask); + + if (appender->drv->info) { + char info_str[100]; + appender->drv->info(appender, info_str, sizeof(info_str)); + gs_command_set_output(ctx->ctx, appender->name, "info", info_str); + } + } else { + gs_command_set_output_printf(ctx->ctx, NULL, NULL, "%-15s %-6s", appender->name, format_mask(appender->mask, level_mask)); + } + } else { + fprintf(ctx->ctx->out, " %-15s %-6s\r\n", + appender->name, + format_mask(appender->mask, level_mask)); + } + return true; +} + +static int cmd_log_appender_list(gs_command_context_t * ctx) +{ + iter_group_t iter = {.ctx = ctx, .completer = false}; + + if (ctx->argc > 1) { + iter.detailed = true; + gs_log_appender_iterate(ctx->argv[1], &iter, iter_print_appender); + } else { + fprintf(ctx->out, "Appender Mask\r\n"); + gs_log_appender_iterate("*", &iter, iter_print_appender); + } + return GS_OK; +} + +typedef gs_error_t (*log_get_mask_t)(const char *name, uint8_t* mask); +typedef gs_error_t (*log_set_mask_t)(const char *name, uint8_t mask); + +static int cmd_log_mask_handler(gs_command_context_t * ctx, log_get_mask_t get_mask, log_set_mask_t set_mask) +{ + /* strtok writes to the string, so we need to duplicate it to avoid writing to read-only memory */ + char strbuf[100]; + GS_STRNCPY(strbuf, ctx->argv[1]); + + char * saveptr = NULL; + char * token = strtok_r(strbuf, ",", &saveptr); + gs_error_t error = GS_OK; + while (token && (error == GS_OK)) { + + uint8_t old_mask = 0; + if (gs_log_is_group_all(token) == false) { + error = get_mask(token, &old_mask); + } + if (error == GS_OK) { + uint8_t new_mask = 0; + error = gs_log_string_to_mask(ctx->argv[2], old_mask, &new_mask); + if (error == GS_OK) { + error = set_mask(token, new_mask); + } + } + + token = strtok_r(NULL, ",", &saveptr); + } + + return error; +} + +static int cmd_log_group_mask(gs_command_context_t * ctx) +{ + return cmd_log_mask_handler(ctx, gs_log_group_get_level_mask, gs_log_group_set_level_mask); +} + +static int cmd_log_appender_mask(gs_command_context_t * ctx) +{ + return cmd_log_mask_handler(ctx, gs_log_appender_get_level_mask, gs_log_appender_set_level_mask); +} + + +#ifndef __AVR__ +static bool iter_log_completer(void *ctx_in, gs_log_group_t * group) +{ + iter_group_t * ctx = ctx_in; + unsigned int hits = gs_command_completer_add_token(ctx->ctx, group->name, false); + if (hits == 1) { + ctx->first = group; + } else { + if (hits == 2) { + fprintf(ctx->ctx->out, "\r\n"); + iter_print_group(ctx, ctx->first); + } + iter_print_group(ctx, group); + } + return true; +} + +static gs_error_t cmd_log_group_completer(gs_command_context_t * ctx, int arg_to_complete) +{ + if (arg_to_complete == 1) { + iter_group_t iter = {.ctx = ctx, .completer = true}; + char name[50]; + snprintf(name, sizeof(name), "%s*", (ctx->argc > 1) ? ctx->argv[1] : ""); + gs_log_group_iterate(name, &iter, iter_log_completer); + return GS_OK; + } + return GS_ERROR_AMBIGUOUS; +} + +static bool iter_log_appender_completer(void *ctx_in, gs_log_appender_t * appender) +{ + iter_group_t * ctx = ctx_in; + unsigned int hits = gs_command_completer_add_token(ctx->ctx, appender->name, false); + if (hits == 1) { + ctx->first_appender = appender; + } else { + if (hits == 2) { + fprintf(ctx->ctx->out, "\r\n"); + iter_print_appender(ctx, ctx->first_appender); + } + iter_print_appender(ctx, appender); + } + return true; +} + +static gs_error_t cmd_log_appender_completer(gs_command_context_t * ctx, int arg_to_complete) +{ + if (arg_to_complete == 1) { + iter_group_t iter = {.ctx = ctx, .completer = true}; + char name[50]; + snprintf(name, sizeof(name), "%s*", (ctx->argc > 1) ? ctx->argv[1] : ""); + gs_log_appender_iterate(name, &iter, iter_log_appender_completer); + return GS_OK; + } + return GS_ERROR_AMBIGUOUS; +} +#endif + +typedef struct { + gs_command_context_t *cmd_ctx; + unsigned int count; +} hist_ctx_t; + +static bool appender_history_iter(void *ctx, gs_log_level_t level, const gs_timestamp_t *ts, const char *group, const char *msg) +{ + hist_ctx_t * hist_ctx = ctx; + + /* Break iteration if history record count is reached. */ + if (hist_ctx->count-- == 0) { + return false; + } + + gs_command_set_output_printf(hist_ctx->cmd_ctx, NULL, NULL, + "%s%04"PRIu32".%06"PRIu32" %c %s: %s%s", + gs_log_level_to_color_begin(level), + ts->tv_sec, ts->tv_nsec/1000, + gs_log_level_to_char(level), + group, + msg, + gs_log_level_to_color_end()); + + return true; +} + +static int cmd_log_appender_hist(gs_command_context_t * ctx) +{ + hist_ctx_t hist_ctx = {.cmd_ctx = ctx, .count = 20}; + if (ctx->argc == 3) { + hist_ctx.count = atoi(ctx->argv[2]); + } + + return gs_log_appender_history_iterate(ctx->argv[1], &hist_ctx, appender_history_iter); +} + + +static bool iter_log_group_find(void* ctx_in, gs_log_group_t *group) +{ + gs_log_group_t **grp = ctx_in; + *grp = group; + return false; +} + +static int cmd_log_insert(gs_command_context_t * ctx) +{ + gs_log_group_t *log_group = NULL; + gs_error_t error = gs_log_group_iterate(ctx->argv[1], &log_group, iter_log_group_find); + if (error != GS_OK) { + return error; + } + + gs_log_level_t level; + error = gs_log_string_to_level(ctx->argv[2], &level); + if (error == GS_OK) { + gs_log(level, log_group, GS_PGM_STR("%s"), ctx->argv[3]); + } + + return error; +} + +static int cmd_log_color(gs_command_context_t * ctx) +{ + bool color; + gs_error_t error = gs_string_to_bool(ctx->argv[1], &color); + if (error == GS_OK) { + gs_log_set_print_color(color); + } + + return error; +} + +static const gs_command_t GS_COMMAND_SUB cmd_log_group_cmds[] = { + { + .name = "list", + .help = "list log groups", + .usage = "[group]", +#ifndef __AVR__ + .completer = cmd_log_group_completer, +#endif + .handler = cmd_log_group_list, + .mandatory_args = GS_COMMAND_NO_ARGS, + .optional_args = 1, + },{ + .name = "mask", + .help = "Set log group mask(s): e|w|i|d|t|stand|all|non", + .usage = "[,group] <[+-]level>[,level]", +#ifndef __AVR__ + .completer = cmd_log_group_completer, +#endif + .handler = cmd_log_group_mask, + .mandatory_args = 2, + },{ + .name = "insert", + .help = "Log message", + .usage = " ", +#ifndef __AVR__ + .completer = cmd_log_group_completer, +#endif + .handler = cmd_log_insert, + .mandatory_args = 3, + },{ + .name = "color", + .help = "Enable/disable color logs (stdout)", + .usage = "", + .handler = cmd_log_color, + .mandatory_args = 1, + } +}; + +static const gs_command_t GS_COMMAND_SUB cmd_log_appender_cmds[] = { + { + .name = "list", + .help = "list log appenders", + .usage = "[appender]", +#ifndef __AVR__ + .completer = cmd_log_appender_completer, +#endif + .handler = cmd_log_appender_list, + .mandatory_args = GS_COMMAND_NO_ARGS, + .optional_args = 1, + }, { + .name = "mask", + .help = "Set log appender mask(s): e|w|i|d|t|stand|all|non", + .usage = "[,appender] <[+-]level>[,level]", +#ifndef __AVR__ + .completer = cmd_log_appender_completer, +#endif + .handler = cmd_log_appender_mask, + .mandatory_args = 2, + }, { + .name = "hist", + .help = "Show log appender history", + .usage = " [cnt]", +#ifndef __AVR__ + .completer = cmd_log_appender_completer, +#endif + .handler = cmd_log_appender_hist, + .mandatory_args = 1, + .optional_args = 1, + } +}; + +static const gs_command_t GS_COMMAND_SUB cmd_log_cmds[] = { + { + .name = "group", + .help = "log group commands", + .chain = GS_COMMAND_INIT_CHAIN(cmd_log_group_cmds), + }, { + .name = "appender", + .help = "log appender commands", + .chain = GS_COMMAND_INIT_CHAIN(cmd_log_appender_cmds), + } +}; + +static const gs_command_t GS_COMMAND_ROOT cmd_log[] = { + { + .name = "log", + .help = "log: Log system", + .chain = GS_COMMAND_INIT_CHAIN(cmd_log_cmds) + },{ + .name = "debug", + .help = "Set Log group mask(s): e|w|n|i|d|t|stand|all|off", + .usage = "[,group] <[+-]level>[,level]", +#ifndef __AVR__ + .completer = cmd_log_group_completer, +#endif + .handler = cmd_log_group_mask, + .mandatory_args = 2, + }, +}; + +gs_error_t gs_log_register_commands(void) +{ + return GS_COMMAND_REGISTER(cmd_log); +} diff --git a/gomspace/libutil/src/log/local.h b/gomspace/libutil/src/log/local.h new file mode 100644 index 00000000..654577c8 --- /dev/null +++ b/gomspace/libutil/src/log/local.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +struct gs_log_list { + union { + gs_log_group_t * group; + gs_log_appender_t *appender; + } data; + struct gs_log_list * next; +}; + +/** + De-register appender for the given log group. + + @note The de-register function is not safe when logging is active, this function + is mostly for test and should only be used in product code with extreme caution. + If logging is still not active, this function can be used safely. + + @param[in] group_name Name of the group. + @param[in] appender_name Name of appender to de-register for this group. + @return gs_error_t +*/ +gs_error_t gs_log_group_deregister_appender(const char * group_name, const char * appender_name); + +bool gs_log_is_group_all(const char * name); diff --git a/gomspace/libutil/src/log/log.c b/gomspace/libutil/src/log/log.c new file mode 100644 index 00000000..16865900 --- /dev/null +++ b/gomspace/libutil/src/log/log.c @@ -0,0 +1,705 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include "local.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "../lock.h" +#include + +#define MASK_SET 0 +#define MASK_AND 1 +#define MASK_OR 2 + +// use color in log print +static bool g_print_no_color; + +// Log Group list +GS_STATIC gs_log_list_t g_log_groups = { .data = { .group = 0} }; + +// Log Appender list +GS_STATIC gs_log_list_t g_log_appenders = { .data = { .appender = 0} }; + +// Root Log Appenders - used for holding a appender list +GS_STATIC gs_log_group_t g_log_group_root = {.name = GS_LOG_GROUP_ROOT}; + +// Default log group - always present. +GS_LOG_GROUP(LOG_DEFAULT, "default", GS_LOG_CAT_DEFAULT, LOG_ERROR_MASK | LOG_WARNING_MASK | LOG_NOTICE_MASK | LOG_INFO_MASK); + +bool gs_log_is_group_all(const char * name) +{ + return (name && ((strcasecmp(name, "*") == 0) || (strcasecmp(name, "all") == 0))); +} + +static bool iter_set_level_mask(void * ctx_in, gs_log_group_t * group) +{ + uint8_t * level_mask = ctx_in; + group->mask = *level_mask; + return true; +} + +gs_error_t gs_log_group_set_level_mask(const char * group_name, uint8_t mask) +{ + if (gs_string_empty(group_name)) { + return GS_ERROR_HANDLE; + } + + return gs_log_group_iterate(group_name, &mask, iter_set_level_mask); +} + +static bool iter_get_level_mask(void * ctx_in, gs_log_group_t * group) +{ + uint8_t * level_mask = ctx_in; + *level_mask = group->mask; + return true; +} + +gs_error_t gs_log_group_get_level_mask(const char * group_name, uint8_t *mask) +{ + if (gs_string_empty(group_name)) { + return GS_ERROR_HANDLE; + } + + gs_error_t error = gs_log_group_iterate(group_name, mask, iter_get_level_mask); + return error; +} + +gs_error_t gs_log_string_to_level(const char * str, gs_log_level_t * return_level) +{ + if (gs_string_empty(str)) { + return GS_ERROR_ARG; + } + + const size_t len = strlen(str); + gs_log_level_t level; + + if (strncasecmp(str, "trace", len) == 0) { + level = LOG_TRACE; + } else if (strncasecmp(str, "debug", len) == 0) { + level = LOG_DEBUG; + } else if (strncasecmp(str, "informational", len) == 0) { + level = LOG_INFO; + } else if (strncasecmp(str, "notice", len) == 0) { + level = LOG_NOTICE; + } else if (strncasecmp(str, "warning", len) == 0) { + level = LOG_WARNING; + } else if (strncasecmp(str, "error", len) == 0) { + level = LOG_ERROR; + } else { + return GS_ERROR_DATA; + } + + if (return_level) { + *return_level = level; + } + + return GS_OK; +} + +char gs_log_level_to_char(gs_log_level_t level) +{ + switch (level) { + case LOG_TRACE: return 'T'; + case LOG_DEBUG: return 'D'; + case LOG_INFO: return 'I'; + case LOG_NOTICE: return 'N'; + case LOG_WARNING: return 'W'; + case LOG_ERROR: return 'E'; + default: return '?'; + } +} + +gs_error_t gs_log_string_to_mask(const char *str, uint8_t old, uint8_t * return_mask) +{ + GS_CHECK_ARG(gs_string_empty(str) == false); + + char strbuf[50]; // copy buf, coz strtok will mess it up + GS_STRNCPY(strbuf, str); + + char *saveptr = NULL; + char *token = strtok_r(strbuf, ",", &saveptr); + while (token) { + // check for +xxx (add), -xxxx (remove), xxxx (set) + int op = MASK_SET; + if (*token == '+') { + op = MASK_OR; + token++; + } else if (*token == '-') { + op = MASK_AND; + token++; + } + + const unsigned int token_length = strlen(token); + if (token_length < 1) { + return GS_ERROR_DATA; + } + + /* Check mask */ + uint8_t mask; + gs_log_level_t level; + if (gs_log_string_to_level(token, &level) == GS_OK) { + // actual level + if (op == MASK_SET) { + // set all level bits equal or lover + mask = LOG_ALL_MASK & ~((1 << level) - 1); + } else { + mask = (1 << level); + } + } else if (!strncasecmp(token, "default", token_length)) { // legacy - conflicts with 'de(bug)' + mask = LOG_DEFAULT_MASK; + op = MASK_SET; + } else if (!strncasecmp(token, "standard", token_length)) { + mask = LOG_DEFAULT_MASK; + op = MASK_SET; + } else if (!strncasecmp(token, "all", token_length)) { + mask = LOG_ALL_MASK; + op = MASK_SET; + } else if (!strncasecmp(token, "off", token_length)) { + mask = 0; + op = MASK_SET; + } else if (!strncasecmp(token, "none", token_length)) { // legacy - conflicts with 'no(tice)' + mask = 0; + op = MASK_SET; + } else if (gs_string_to_uint8(token, &mask) == GS_OK) { + op = MASK_SET; + } else { + return GS_ERROR_DATA; + } + + /* Apply operation */ + if (op == MASK_OR) { + old |= mask; + } else if (op == MASK_AND) { + old &= ~mask; + } else if (op == MASK_SET) { + old = mask; + } + + token = strtok_r(NULL, ",", &saveptr); + } + + if (return_mask) { + *return_mask = old; + } + + return GS_OK; +} + +/** + All functions must call this initialization function, to ensure log is initialized. +*/ +static gs_error_t gs_log_init_internal(void) +{ + if (g_log_groups.data.group == NULL) { + return gs_log_init(true); + } + return GS_OK; +} + +gs_error_t gs_log_group_iterate(const char * group_name, void * ctx, gs_log_group_iterator_t iter) +{ + const bool all = (gs_string_empty(group_name) || gs_log_is_group_all(group_name)); + bool found = false; + + for (gs_log_list_t *node = &g_log_groups; node; node = node->next) { + if (node->data.group) { + if (all || gs_string_match(group_name, node->data.group->name)) { + found = true; + bool cont = iter(ctx, node->data.group); + if (cont == false) { + return GS_OK; + } + } + } + } + + return found ? GS_OK : GS_ERROR_NOT_FOUND; +} + +static gs_error_t gs_log_group_register_internal(gs_log_group_t *group) +{ + // check if appender is already in the list and find last node + gs_log_list_t * parent = &g_log_groups; // there will always be at least 1 group -> default + for (; parent; parent = parent->next) { + if ((parent->data.group == group) || (strcasecmp(group->name, parent->data.group->name) == 0)) { + return GS_ERROR_EXIST; + } + if (parent->next == NULL) { + break; + } + } + + gs_log_list_t * new_group_node = calloc(1, sizeof(*new_group_node)); + if (new_group_node == NULL) { + return GS_ERROR_ALLOC; + } + + new_group_node->data.group = group; + + // add to list - must be done last, iterating list can be done without locking + parent->next = new_group_node; + + return GS_OK; +} + +gs_error_t gs_log_group_register(gs_log_group_t *group) +{ + GS_CHECK_ARG(group != NULL); + GS_CHECK_ARG(gs_string_empty(group->name) == false); + + gs_log_init_internal(); + + gs_lock_lock(); + gs_error_t error = gs_log_group_register_internal(group); + gs_lock_unlock(); + + return error; +} + + +bool gs_log_group_is_level_enabled(gs_log_group_t *group, gs_log_level_t level) +{ + return ((group->mask & level) > 0); +} + +gs_error_t gs_log_appender_iterate(const char * name, void * ctx, gs_log_appender_iterator_t iter) +{ + const bool all = (gs_string_empty(name) || gs_log_is_group_all(name)); + bool found = false; + + /* Iterate the dynamically registered log appenders: */ + for (gs_log_list_t *node = &g_log_appenders; node; node = node->next) { + if (node->data.appender) { + if (all || gs_string_match(name, node->data.appender->name)) { + found = true; + bool cont = iter(ctx, node->data.appender); + if (cont == false) { + return GS_OK; + } + } + } + } + + return found ? GS_OK : GS_ERROR_NOT_FOUND; +} + +struct gs_log_history_ctx { + gs_log_record_iterator_t iter; + void *ctx; +}; + +static bool gs_log_history_iterator(void* ctx, gs_log_appender_t *appender) +{ + struct gs_log_history_ctx *hist_ctx = ctx; + if (appender->drv->hist) { + appender->drv->hist(appender, hist_ctx->ctx, hist_ctx->iter); + } + return true; +} + +gs_error_t gs_log_appender_history_iterate(const char * name, void * ctx, gs_log_record_iterator_t iter) +{ + struct gs_log_history_ctx hist_ctx = {.iter=iter, .ctx = ctx}; + + return gs_log_appender_iterate(name, &hist_ctx, gs_log_history_iterator); +} + +static gs_error_t gs_log_appender_register_internal(gs_log_appender_t *appender) +{ + if (g_log_appenders.data.appender == NULL) { + // first appender + g_log_appenders.data.appender = appender; + + if (appender->drv->init) { + gs_error_t error = appender->drv->init(appender); + if (error) { + g_log_appenders.data.appender = NULL; + return error; + } + } + + return GS_OK; + } + + // check if appender is already in the list and find last node + gs_log_list_t * parent = &g_log_appenders; + for (; parent; parent = parent->next) { + if ((parent->data.appender == appender) || (strcasecmp(parent->data.appender->name, appender->name) == 0)) { + return GS_ERROR_EXIST; + } + if (parent->next == NULL) { + break; + } + } + + gs_log_list_t *new_appender = calloc(1, sizeof(*new_appender)); + if (new_appender == NULL) { + return GS_ERROR_ALLOC; + } + + new_appender->data.appender = appender; + + if (appender->drv->init) { + gs_error_t error = appender->drv->init(appender); + if (error) { + free(new_appender); + return error; + } + } + + // add to list - must be done last, iterating list can be done without locking + parent->next = new_appender; + + return GS_OK; +} + +gs_error_t gs_log_appender_register(gs_log_appender_t *appender) +{ + GS_CHECK_ARG(appender != NULL); + GS_CHECK_ARG(gs_string_empty(appender->name) == false); + GS_CHECK_ARG(appender->drv != NULL); + GS_CHECK_ARG(appender->drv->append != NULL); + + gs_log_init_internal(); + + gs_lock_lock(); + gs_error_t error = gs_log_appender_register_internal(appender); + gs_lock_unlock(); + + return error; +} + +gs_error_t gs_log_appender_add(gs_log_appender_t *appender, uint16_t count) +{ + GS_CHECK_ARG(appender != NULL); + GS_CHECK_ARG(count != 0); + + gs_error_t error = GS_OK; + for (uint16_t i = 0; i < count; i++) { + gs_error_t tmp_error = gs_log_appender_register(&appender[i]); + if ((error == GS_OK) && tmp_error) { + error = tmp_error; + } + } + + return error; +} + +static bool iter_set_appender_level_mask(void * ctx_in, gs_log_appender_t * appender) +{ + uint8_t * level_mask = ctx_in; + appender->mask = *level_mask; + return true; +} + +gs_error_t gs_log_appender_set_level_mask(const char * appender_name, uint8_t mask) +{ + if (gs_string_empty(appender_name)) { + return GS_ERROR_HANDLE; + } + + return gs_log_appender_iterate(appender_name, &mask, iter_set_appender_level_mask); +} + +static bool iter_get_appender_level_mask(void * ctx_in, gs_log_appender_t * appender) +{ + uint8_t * level_mask = ctx_in; + *level_mask = appender->mask; + return true; +} + +gs_error_t gs_log_appender_get_level_mask(const char * appender_name, uint8_t *mask) +{ + if (gs_string_empty(appender_name)) { + return GS_ERROR_HANDLE; + } + + return gs_log_appender_iterate(appender_name, mask, iter_get_appender_level_mask); +} + +// Appender register/de-register iterator context +typedef struct { + gs_log_appender_t *appender; + gs_error_t ret; +} iter_group_appender_t; + +static bool iter_log_appender_add(void *ctx, gs_log_group_t *group) +{ + iter_group_appender_t* in = ctx; + + gs_log_list_t * last_elem = group->appenders; + for (gs_log_list_t *elem = group->appenders; elem; elem = elem->next) { + last_elem = elem; + if (elem->data.appender == in->appender) { + in->ret = GS_ERROR_EXIST; + return true; + } + } + + in->ret = GS_ERROR_ALLOC; + gs_log_list_t *new_appender = calloc(1, sizeof(*new_appender)); + if (new_appender) { + new_appender->data.appender = in->appender; + new_appender->next = 0; + if (last_elem != NULL) { + last_elem->next = new_appender; + } else { + group->appenders = new_appender; + } + in->ret = GS_OK; + } + + return true; +} + +gs_error_t gs_log_group_register_appender(const char * group_name, const char * appender_name) +{ + gs_log_appender_t *appender = NULL; + for (gs_log_list_t *elem = &g_log_appenders; elem; elem = elem->next) { + if (elem->data.appender) { + if (strcasecmp(elem->data.appender->name, appender_name) == 0) { + appender = elem->data.appender; + break; + } + } + } + if (NULL == appender) { + return GS_ERROR_NOT_FOUND; + } + + iter_group_appender_t ctx = {.appender = appender, .ret = GS_OK}; + + gs_error_t ret = GS_OK; + if (strcasecmp(group_name, GS_LOG_GROUP_ROOT) == 0) { + iter_log_appender_add(&ctx, &g_log_group_root); + } else { + ret = gs_log_group_iterate(group_name, &ctx, iter_log_appender_add); + } + + if (ret == GS_OK) { + ret = ctx.ret; + } + + return ret; +} + +static bool iter_log_appender_remove(void *ctx, gs_log_group_t *group) +{ + iter_group_appender_t* in = ctx; + in->ret = GS_ERROR_NOT_FOUND; + + gs_log_list_t * last_elem = group->appenders; + for (gs_log_list_t *elem = group->appenders; elem; elem = elem->next) { + if (elem->data.appender == in->appender) { + if (elem == group->appenders) { + group->appenders = elem->next; + } + last_elem->next = elem->next; + free(elem); + in->ret = GS_OK; + break; + } + last_elem = elem; + } + + return true; +} + +gs_error_t gs_log_group_deregister_appender(const char * group_name, const char * appender_name) +{ + gs_log_appender_t *appender = NULL; + for (gs_log_list_t *elem = &g_log_appenders; elem; elem = elem->next) { + if (elem->data.appender) { + if (strcasecmp(elem->data.appender->name, appender_name) == 0) { + appender = elem->data.appender; + break; + } + } + } + if (NULL == appender) { + return GS_ERROR_NOT_FOUND; + } + + iter_group_appender_t ctx = {.appender = appender, .ret = GS_OK}; + + gs_error_t ret; + if (strcasecmp(group_name, GS_LOG_GROUP_ROOT) == 0) { + ret = iter_log_appender_remove(&ctx, &g_log_group_root); + } else { + ret = gs_log_group_iterate(group_name, &ctx, iter_log_appender_remove); + } + + if (ret == GS_OK) { + ret = ctx.ret; + } + + return ret; +} + +gs_error_t gs_log_group_appender_iterate(gs_log_group_t * group, void * ctx, gs_log_appender_iterator_t iter) +{ + GS_CHECK_ARG(group != NULL); + + bool found = false; + for (gs_log_list_t *elem = group->appenders; elem; elem = elem->next) { + found = true; + iter(ctx, elem->data.appender); + } + + /* Iterate root appenders */ + for (gs_log_list_t *elem = g_log_group_root.appenders; elem; elem = elem->next) { + found = true; + iter(ctx, elem->data.appender); + } + + return found ? GS_OK : GS_ERROR_NOT_FOUND; +} + +static inline void gs_log_process_appenders(const gs_log_list_t * it, gs_log_level_t level, + const gs_log_group_t * group, gs_timestamp_t* ts, bool from_isr, const char * format, va_list va) +{ + for (; it; it = it->next) { + gs_log_appender_t* appender = it->data.appender; + + if ((appender->mask & (1 << level)) == 0) { + continue; + } + + if (from_isr == false) { + // log from none ISR context + appender->drv->append(appender, level, group, ts, format, va); + + } else if (appender->drv->append_isr) { + // log from ISR (Interrupt Service Routine) context + appender->drv->append_isr(appender, level, group, ts, format, va); + } + } +} + +static inline void gs_log_common_va(gs_log_level_t level, gs_log_group_t * group, bool from_isr, const char * format, va_list va) +{ + // get time as soon as possible + gs_timestamp_t ts; + gs_clock_get_time(&ts); + + // only needed if someone call function directly - otherwise the log macro has set it to a valid group + if (group == NULL) { + group = LOG_DEFAULT; + } + + // check level mask for current group (this will nearly always be true, because the log macro has done the checking + if (group->mask & (1 << level)) { + + // legacy - if log hasn't been initialized, this will initialize with console output enabled. + gs_log_init_internal(); + + if (group->appenders) { + gs_log_process_appenders(group->appenders, level, group, &ts, from_isr, format, va); + } + + if (group->additivity) { + /* Call root appenders */ + gs_log_process_appenders(g_log_group_root.appenders, level, group, &ts, from_isr, format, va); + } + } +} + +void gs_log(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) +{ + va_list va_args; + va_start(va_args, format); + gs_log_common_va(level, group, false, format, va_args); + va_end(va_args); +} + +void gs_log_isr(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) +{ + va_list va_args; + va_start(va_args, format); + gs_log_common_va(level, group, true, format, va_args); + va_end(va_args); +} + +void gs_log_va(gs_log_level_t level, gs_log_group_t * group, const char * format, va_list args) +{ + gs_log_common_va(level, group, false, format, args); +} + +void gs_log_set_print_color(bool color) +{ + g_print_no_color = (color == false); +} + +const char * gs_log_level_to_color_begin(gs_log_level_t level) +{ + if (g_print_no_color) { + return ""; + } + + switch (level) { + case LOG_ERROR: return "\E[1;31m"; // Red + case LOG_WARNING: return "\E[0;33m"; // Yellow + case LOG_NOTICE: + case LOG_INFO: return "\E[0;32m"; // Green + case LOG_DEBUG: return "\E[0;34m"; // Blue + default: + case LOG_TRACE: return "\E[0;35m"; // Magenta + } +} + +const char * gs_log_level_to_color_end(void) +{ + if (g_print_no_color) { + return ""; + } + + return "\E[0m"; +} + +uint8_t gs_log_level_to_mask(gs_log_level_t level) +{ + /* Enable all levels with priority above the set level */ + uint8_t level_mask = (0xFF << level) & LOG_ALL_MASK; + return level_mask; +} + +static bool iter_flush_appender(void * ctx_in, gs_log_appender_t * appender) +{ + if (appender->drv->flush) { + appender->drv->flush(appender); + } + return true; +} + +gs_error_t gs_log_appender_flush_all() +{ + return gs_log_appender_iterate("", NULL, iter_flush_appender); +} + +gs_error_t gs_log_init(bool with_console_appender) +{ + gs_error_t error = GS_OK; + + gs_lock_init(); // ignore result, this is the log system + + if (g_log_groups.data.group == NULL) { + + // default log group -> mark log as initialized + g_log_groups.data.group = LOG_DEFAULT; + + // register console log appender + if (with_console_appender) { + error = gs_log_appender_register(&gs_log_appender_console); + if (error == GS_OK) { + error = gs_log_group_register_appender(GS_LOG_GROUP_ROOT, gs_log_appender_console.name); + } + } + } + + return error; +} diff --git a/gomspace/libutil/src/rtc.c b/gomspace/libutil/src/rtc.c new file mode 100644 index 00000000..160df778 --- /dev/null +++ b/gomspace/libutil/src/rtc.c @@ -0,0 +1,42 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include + +static const gs_rtc_driver_t * rtc_driver; +static void * rtc_driver_data; + +gs_error_t gs_rtc_register(const gs_rtc_driver_t * driver, void * driver_data) +{ + rtc_driver = driver; + rtc_driver_data = driver_data; + return GS_OK; +} + +gs_error_t gs_rtc_supported(void) +{ + return rtc_driver ? GS_OK : GS_ERROR_NOT_SUPPORTED; +} + +gs_error_t gs_rtc_get_time(gs_timestamp_t * time) +{ + if (time == NULL) { + return GS_ERROR_ARG; + } + + if (rtc_driver && rtc_driver->get_time) { + return rtc_driver->get_time(rtc_driver_data, time); + } + return GS_ERROR_NOT_SUPPORTED; +} + +gs_error_t gs_rtc_set_time(const gs_timestamp_t * time) +{ + if (time == NULL) { + return GS_ERROR_ARG; + } + + if (rtc_driver && rtc_driver->set_time) { + return rtc_driver->set_time(rtc_driver_data, time); + } + return GS_ERROR_NOT_SUPPORTED; +} diff --git a/gomspace/libutil/src/stdio.c b/gomspace/libutil/src/stdio.c new file mode 100644 index 00000000..c723f8fe --- /dev/null +++ b/gomspace/libutil/src/stdio.c @@ -0,0 +1,81 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include + +gs_error_t gs_stdio_get(char * buf, size_t len) +{ + while (len > 0) { + int ch; + gs_error_t error = gs_stdio_getchar(&ch); + if (error) { + return error; + } + *buf++ = ch; + --len; + } + + return GS_OK; +} + +gs_error_t gs_stdio_put(const char * buf, size_t len, bool text) +{ + while (len > 0) { + if ((*buf == '\n') && text) { + gs_stdio_putchar('\r'); + } + gs_stdio_putchar(*buf++); + --len; + } + + return GS_OK; +} + +void gs_color_printf(gs_color_printf_t color_arg, const char * format, ...) +{ + va_list args; + va_start(args, format); + + if ((color_arg & GS_COLOR_ATTRS) == GS_COLOR_BOLD) { + printf("\033[1;"); + } else { + printf("\033[0;"); + } + + switch(color_arg & GS_COLOR_COLORS) { + case GS_COLOR_NONE: + printf("0m"); + break; + case GS_COLOR_BLACK: + printf("30m"); + break; + case GS_COLOR_RED: + printf("31m"); + break; + case GS_COLOR_GREEN: + printf("32m"); + break; + case GS_COLOR_YELLOW: + printf("33m"); + break; + case GS_COLOR_BLUE: + printf("34m"); + break; + case GS_COLOR_MAGENTA: + printf("35m"); + break; + case GS_COLOR_CYAN: + printf("36m"); + break; + case GS_COLOR_WHITE: + printf("37m"); + break; + default: + break; + } + + vprintf(format, args); + printf("\033[0m"); + + va_end(args); +} diff --git a/gomspace/libutil/src/string.c b/gomspace/libutil/src/string.c new file mode 100644 index 00000000..31419fd0 --- /dev/null +++ b/gomspace/libutil/src/string.c @@ -0,0 +1,746 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#if (__AVR__ == 0) +#include +#endif + +#ifndef GS_STRING_GET_SUBOPTION_UNIT_TEST +#define GS_STRING_GET_SUBOPTION_UNIT_TEST 0 +#endif + +const char * gs_string_skip_leading_spaces(const char * string) +{ + if (string) { + for (; *string == ' '; ++string); + } + return string; +} + +gs_error_t gs_string_to_int32(const char * string, int32_t * return_value) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (!(isdigit((int)string[0]) || (string[0] == '-'))) { + return GS_ERROR_DATA; + } + + int32_t tmp; + uint8_t base = 10; + + // check for hexadecimal notation + if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) + { + base = 16; + } + + const char *desired_end = string + strlen(string); + // The desired end should point to that last non-space char in the string + while ((isspace((int)desired_end[0]) || (desired_end[0] == '\0')) && (desired_end > string)) + { + desired_end--; + } + char *end; + gs_error_t err = GS_OK; + tmp = gs_string_strto32int(string, &end, base, &err); + if (err != GS_OK) + { + return err; + } + if (desired_end != end-1) + { + return GS_ERROR_DATA; + } + + if (return_value) + { + *return_value = tmp; + } + + return GS_OK; +} + +gs_error_t gs_string_to_int8(const char * string, int8_t * return_value) +{ + int32_t value; + gs_error_t error = gs_string_to_int32(string, &value); + if (error == GS_OK) { + if ((value >= INT8_MIN) && (value <= INT8_MAX)) { + if (return_value) { + *return_value = (int8_t) value; + } + } else { + error = GS_ERROR_OVERFLOW; + } + } + return error; +} + +gs_error_t gs_string_to_uint8(const char * string, uint8_t * return_value) +{ + uint32_t value; + gs_error_t error = gs_string_to_uint32(string, &value); + if (error == GS_OK) { + if (value <= UINT8_MAX) { + if (return_value) { + *return_value = (uint8_t) value; + } + } else { + error = GS_ERROR_OVERFLOW; + } + } + return error; +} + +gs_error_t gs_string_to_int16(const char * string, int16_t * return_value) +{ + int32_t value; + gs_error_t error = gs_string_to_int32(string, &value); + if (error == GS_OK) { + if ((value >= INT16_MIN) && (value <= INT16_MAX)) { + if (return_value) { + *return_value = (int16_t) value; + } + } else { + error = GS_ERROR_OVERFLOW; + } + } + return error; +} + +gs_error_t gs_string_to_uint16(const char * string, uint16_t * return_value) +{ + uint32_t value; + gs_error_t error = gs_string_to_uint32(string, &value); + if (error == GS_OK) { + if (value <= UINT16_MAX) { + if (return_value) { + *return_value = (uint16_t) value; + } + } else { + error = GS_ERROR_OVERFLOW; + } + } + return error; +} + +gs_error_t gs_string_to_uint32(const char * string, uint32_t * return_value) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (!isdigit((int)string[0])) { + return GS_ERROR_DATA; + } + + uint32_t tmp; + uint8_t base = 10; + + // check for hexadecimal notation + if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) + { + base = 16; + } + const char *desired_end = string + strlen(string); + // The desired end should point to that last non-space char in the string + while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) + { + desired_end--; + } + char *end; + gs_error_t err = GS_OK; + tmp = gs_string_strto32uint(string, &end, base, &err); + + if (err != GS_OK) + { + return err; + } + if (desired_end != end-1) + { + return GS_ERROR_DATA; + } + + + if (return_value) { + *return_value = tmp; + } + + return GS_OK; +} + +gs_error_t gs_string_to_uint64(const char * string, uint64_t * return_value) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (!isdigit((int)string[0])) + { + return GS_ERROR_DATA; + } + + uint64_t tmp; + uint8_t base = 10; + + // check for hexadecimal notation + if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) { + base = 16; + } + const char *desired_end = string + strlen(string); + // The desired end should point to that last non-space char in the string + while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) + { + desired_end--; + } + char *end; + gs_error_t err = GS_OK; + tmp = gs_string_strto64uint(string, &end, base, &err); + if (err != GS_OK) + { + return err; + } + + if (desired_end != end-1) + { + return GS_ERROR_DATA; + } + + + if (return_value) { + *return_value = tmp; + } + + return GS_OK; +} + +gs_error_t gs_string_to_int64(const char * string, int64_t * return_value) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (!(isdigit((int)string[0]) || (string[0] == '-'))) + { + return GS_ERROR_DATA; + } + + int64_t tmp; + uint8_t base = 10; + + // check for hexadecimal notation + if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) { + base = 16; + } + const char *desired_end = string + strlen(string); + // The desired end should point to that last non-space char in the string + while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) + { + desired_end--; + } + char *end; + gs_error_t err = GS_OK; + tmp = gs_string_strto64int(string, &end, base, &err); + if (err != GS_OK) + { + return err; + } + + if (desired_end != end-1) + { + return GS_ERROR_DATA; + } + + + if (return_value) { + *return_value = tmp; + } + + return GS_OK; +} + +gs_error_t gs_string_hex_to_uint32(const char * string, uint32_t * return_value) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (!isxdigit((int)string[0])) { + return GS_ERROR_DATA; + } + + const char *desired_end = string + strlen(string); + // The desired end should point to that last non-space char in the string + while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) + { + desired_end--; + } + char *end; + gs_error_t err = GS_OK; + uint32_t tmp = gs_string_strto32uint(string, &end, 16, &err); + + if (err != GS_OK) + { + return err; + } + if (desired_end != end-1) + { + return GS_ERROR_DATA; + } + + if (return_value) { + *return_value = tmp; + } + + return GS_OK; +} + +gs_error_t gs_string_hex_to_uint64(const char * string, uint64_t * return_value) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (!isxdigit((int)string[0])) + { + return GS_ERROR_DATA; + } + + const char *desired_end = string + strlen(string); + // The desired end should point to that last non-space char in the string + while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) + { + desired_end--; + } + char *end; + gs_error_t err = GS_OK; + uint64_t tmp = gs_string_strto64uint(string, &end, 16, &err); + if (err != GS_OK) + { + return err; + } + + if (desired_end != end-1) + { + return GS_ERROR_DATA; + } + + if (return_value) { + *return_value = tmp; + } + + return GS_OK; +} + +#if (__AVR__ == 0) +gs_error_t gs_string_to_float(const char * string, float * pvalue) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (gs_string_empty(string)) { + return GS_ERROR_DATA; + } + + // float strtof(const char *nptr, char **endptr); + char * endp = NULL; + float tmp = strtof(string, &endp); + //if ((endp == NULL) || (gs_string_empty(gs_string_skip_leading_spaces(endp)) == false) || (string == endp)) { + if ((endp == NULL) || (gs_string_empty(gs_string_skip_leading_spaces(endp)) == false) || (string == endp) || isinf(tmp)) { + return GS_ERROR_DATA; + } + + if (pvalue) { + *pvalue = tmp; + } + + return GS_OK; +} + +gs_error_t gs_string_to_double(const char * string, double * pvalue) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (gs_string_empty(string)) { + return GS_ERROR_DATA; + } + + // double strtod(const char *nptr, char **endptr); + char * endp = NULL; + double tmp = strtod(string, &endp); + if ((endp == NULL) || (gs_string_empty(gs_string_skip_leading_spaces(endp)) == false) || isinf(tmp)) { + return GS_ERROR_DATA; + } + + if (pvalue) { + *pvalue = tmp; + } + + return GS_OK; +} +#endif + +#define GS_STRING_BOOL_TRUE "true" +#define GS_STRING_BOOL_FALSE "false" + +const char * gs_string_from_bool(bool value) +{ + if (value) { + return GS_STRING_BOOL_TRUE; + } else { + return GS_STRING_BOOL_FALSE; + } +} + +gs_error_t gs_string_to_bool(const char * string, bool * return_value) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + if (string[0] == 0) { + return GS_ERROR_DATA; + } + + bool value = false; + if (strcasecmp(string, GS_STRING_BOOL_TRUE) == 0) { + value = true; + } else if (strcasecmp(string, GS_STRING_BOOL_FALSE) == 0) { + value = false; + } else if (strcasecmp(string, "on") == 0) { + value = true; + } else if (strcasecmp(string, "off") == 0) { + value = false; + } else if (strcasecmp(string, "1") == 0) { + value = true; + } else if (strcasecmp(string, "0") == 0) { + value = false; + } else if (strcasecmp(string, "yes") == 0) { + value = true; + } else if (strcasecmp(string, "no") == 0) { + value = false; + } else { + return GS_ERROR_DATA; + } + + if (return_value) { + *return_value = value; + } + + return GS_OK; +} + +char * gs_string_bytesize(long n, char *buf, size_t buf_size) +{ + char postfix = 'B'; + double size = (double) n; + if (n >= 1048576) { + size /= 1048576.0; + postfix = 'M'; + } else if (n >= 1024) { + size /= 1024.0; + postfix = 'K'; + } + snprintf(buf, buf_size, "%.1f%c", size, postfix); + return buf; +} + +gs_error_t gs_string_to_pointer(const char * string, void ** value) +{ +#if __LP64__ + uint64_t tmp; + gs_error_t error = gs_string_to_uint64(string, &tmp); + if ((error == GS_OK) && value) { + *value = GS_TYPES_UINT2PTR(tmp); + } + return error; +#else + uint32_t tmp; + gs_error_t error = gs_string_to_uint32(string, &tmp); + if ((error == GS_OK) && value) { + *value = GS_TYPES_UINT2PTR(tmp); + } + return error; +#endif +} + +bool gs_string_empty(const char * string) +{ + if ((string == NULL) || (string[0] == 0)) { + return true; + } + return false; +} + +bool gs_string_match(const char * pattern, const char * string) +{ + if (string && pattern) { + while (*string || *pattern) { + int p = tolower((int)*pattern); + int s = tolower((int)*string); + + if (*pattern == '*') { + ++pattern; + p = tolower((int)*pattern); + for (; *string && (tolower((int)*string) != p); ++string); + s = tolower((int)*string); + } + + if (s != p) { + return false; + } + + if (s) { + ++string; + } + if (p) { + ++pattern; + } + } + if ((*string == 0) && (*pattern == 0)) { + return true; + } + } + return false; +} + +bool gs_string_has_wildcards(const char * string) +{ + if (strchr(string, '*')) { + return true; + } + // future wildcard + //if (strchr(str, '?')) { + // return true; + //} + return false; +} + +void gs_string_trim(char * buffer, size_t buffer_size) +{ + // remove trailing stuff + int len = strnlen(buffer, buffer_size); + if (len) { + for (int i = (len - 1); i >= 0; --i) { + if (isspace((int)buffer[i])) { + buffer[i] = 0; + } else { + break; + } + } + } + + char * start; + for (start = buffer; *start && isspace((int)*start); ++start); + if (*start && (start != buffer)) { + // move chars up + for (; *start; ++start) { + *buffer++ = *start; + } + *buffer = 0; + } +} + +bool gs_string_endswith(const char * string, const char * endswith) +{ + if (string == NULL || endswith == NULL) { + return false; + } + + int str_len = strlen(string); + int endswith_len = strlen(endswith); + + return (str_len >= endswith_len) && + (0 == strcmp(string + (str_len-endswith_len), endswith)); +} + +static size_t suboption_len(const char * ref, const char * end) +{ + if (ref) { + size_t len = (end) ? ((size_t)(end - ref)) : strlen(ref); + for (; len && (ref[len - 1] == ' '); --len); + return len; + } + return 0; +} + +static gs_error_t suboption_copy(const char * data, size_t len, char * buf, size_t buf_size, gs_error_t error) +{ + if (len >= buf_size) { + error = GS_ERROR_OVERFLOW; + len = (buf_size - 1); + } + + if (data == NULL) { + len = 0; + } else { + strncpy(buf, data, len); + } + + buf[len] = 0; + + return error; +} + +gs_error_t gs_string_get_suboption(const char * options, const char * suboption, char * buf, size_t buf_size) +{ + GS_CHECK_ARG(options != NULL); + GS_CHECK_ARG((buf != NULL) && (buf_size > 0)); + + const char * next = options; + for (;next;) { + const char * key = next; + if (*key == ',') { + key = NULL; // no key-value + } + next = strchr(next, ','); + + const char * value = NULL; + if (key) { + for (; *key == ' '; ++key); + + value = strchr(key, '='); + if (value == NULL) { + // no value + } else if (next && (value >= next)) { + // no value + value = NULL; + } + } + + const unsigned int key_len = suboption_len(key, value ? value : next); + + if (value) { + if (*value == '=') { + ++value; + } + for (; *value == ' '; ++value); + } + + const unsigned int value_len = suboption_len(value, next); + + if (GS_STRING_GET_SUBOPTION_UNIT_TEST) { // -> #define + printf(" key=[%.*s], len=%u, value=[%.*s], len=%u, next=[%s]\n", + key_len, key ? key : "", key_len, + value_len, value ? value : "", value_len, + next ? next : ""); + } + + // if suboption is empty, it means get value of first element - ignoring any key + if (gs_string_empty(suboption)) { + if (value) { + return suboption_copy(value, value_len, buf, buf_size, GS_OK); + } + if (key) { + return suboption_copy(key, key_len, buf, buf_size, GS_OK); + } + return suboption_copy(NULL, 0, buf, buf_size, GS_OK); // empty + } + + if ((key_len == strlen(suboption)) && (strncasecmp(key, suboption, key_len) == 0)) { + return suboption_copy(value, value_len, buf, buf_size, GS_OK); + } + + if (next) { + ++next; + if (next[0] == 0) { + next = NULL; + } + } + } + + // not found - return default + return suboption_copy(NULL, 0, buf, buf_size, GS_ERROR_NOT_FOUND); +} + +static const char * _suboption_name(const char * suboption) +{ + if (gs_string_empty(suboption)) { + return "first suboption"; + } + return suboption; +} + +#define _get_suboption(_type) \ + char buf[20]; \ + gs_error_t error = gs_string_get_suboption(options, suboption, buf, sizeof(buf)); \ + if (error == GS_OK) { \ + error = gs_string_to_##_type(buf, value); \ + } \ + if (error) { \ + if (error == GS_ERROR_NOT_FOUND) { \ + error = GS_OK; \ + } else { \ + log_error("Failed to extract suboption [%s] from [%s], error: %d", _suboption_name(suboption), options, error); \ + } \ + *value = def; \ + } \ + return error; \ + +gs_error_t gs_string_get_suboption_uint8(const char * options, const char * suboption, uint8_t def, uint8_t * value) +{ + _get_suboption(uint8) +} + +gs_error_t gs_string_get_suboption_uint16(const char * options, const char * suboption, uint16_t def, uint16_t * value) +{ + _get_suboption(uint16) +} + +gs_error_t gs_string_get_suboption_uint32(const char * options, const char * suboption, uint32_t def, uint32_t * value) +{ + _get_suboption(uint32) +} + +gs_error_t gs_string_get_suboption_string(const char * options, const char * suboption, const char * def, char * buf, size_t buf_size) +{ + gs_error_t error = gs_string_get_suboption(options, suboption, buf, buf_size); + if (error) { + if (error == GS_ERROR_NOT_FOUND) { + error = GS_OK; + } + error = suboption_copy(def, def ? strlen(def) : 0, buf, buf_size, error); + } + return error; +} + +gs_error_t gs_string_get_suboption_bool(const char * options, const char * suboption, bool def, bool * value) +{ + char buf[20]; + gs_error_t error = gs_string_get_suboption(options, suboption, buf, sizeof(buf)); + if (error == GS_OK) { + if (gs_string_empty(buf) || (suboption && (strcasecmp(suboption, buf) == 0))) { + // this means 'true', a=21,active,a=22 + *value = true; + } else { + error = gs_string_to_bool(buf, value); + } + } + if (error) { + if (error == GS_ERROR_NOT_FOUND) { + error = GS_OK; + } else { + log_error("Failed to extract suboption [%s] from [%s], error: %d", _suboption_name(suboption), options, error); + } + *value = def; + } + return error; +} diff --git a/gomspace/libutil/src/strtoint.c b/gomspace/libutil/src/strtoint.c new file mode 100644 index 00000000..152eff39 --- /dev/null +++ b/gomspace/libutil/src/strtoint.c @@ -0,0 +1,399 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * 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. [rescinded 22 July 1999] + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + +@deftypefn Supplemental {long int} strtol (const char *@var{string}, @ + char **@var{endptr}, int @var{base}) +@deftypefnx Supplemental {unsigned long int} strtoul (const char *@var{string}, @ + char **@var{endptr}, int @var{base}) + +The @code{strtol} function converts the string in @var{string} to a +long integer value according to the given @var{base}, which must be +between 2 and 36 inclusive, or be the special value 0. If @var{base} +is 0, @code{strtol} will look for the prefixes @code{0} and @code{0x} +to indicate bases 8 and 16, respectively, else default to base 10. +When the base is 16 (either explicitly or implicitly), a prefix of +@code{0x} is allowed. The handling of @var{endptr} is as that of +@code{strtod} above. The @code{strtoul} function is the same, except +that the converted value is unsigned. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#include +#include +#include + +/* + * Convert a string to a long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +int32_t gs_string_strto32int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) +{ + register const char *s = nptr; + register uint32_t acc; + register int c; + register uint32_t cutoff; + register int neg = 0, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + do + { + c = *s++; + } while (isspace(c)); + if (c == '-') + { + neg = 1; + c = *s++; + } else if (c == '+') + { + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) + { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + { + base = c == '0' ? 8 : 10; + } + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? -(uint32_t)INT32_MIN : INT32_MAX; + cutlim = cutoff % (uint32_t)base; + cutoff /= (uint32_t)base; + for (acc = 0, any = 0;; c = *s++) + { + if (isdigit(c)) + { + c -= '0'; + } + else if (isalpha(c)) + { + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + } + else + { + break; + } + if (c >= base) + { + break; + } + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + { + any = -1; + } + else + { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) + { + acc = neg ? INT32_MIN : INT32_MAX; + *err = GS_ERROR_OVERFLOW; + } else if (neg) + { + acc = -acc; + } + if (endptr != 0) + { + *endptr = (char *) (any ? s - 1 : nptr); + } + return (acc); +} + + +/* + * Convert a string to an unsigned long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +uint32_t gs_string_strto32uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) +{ + register const char *s = nptr; + register uint32_t acc; + register int32_t c; + register uint32_t cutoff; + register int32_t neg = 0, any, cutlim; + + /* + * See strtol for comments as to the logic used. + */ + do + { + c = *s++; + } while (isspace(c)); + if (c == '-') + { + neg = 1; + c = *s++; + } else if (c == '+') + { + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) + { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + { + base = c == '0' ? 8 : 10; + } + cutoff = (uint32_t)UINT32_MAX / (uint32_t)base; + cutlim = (uint32_t)UINT32_MAX % (uint32_t)base; + for (acc = 0, any = 0;; c = *s++) + { + if (isdigit(c)) + { + c -= '0'; + } + else if (isalpha(c)) + { + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + } + else + { + break; + } + if (c >= base) + { + break; + } + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + { + any = -1; + } + else + { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) + { + acc = UINT32_MAX; + *err = GS_ERROR_OVERFLOW; + } else if (neg) + { + acc = -acc; + } + if (endptr != 0) + { + *endptr = (char *) (any ? s - 1 : nptr); + } + return (acc); +} + + +int64_t gs_string_strto64int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) +{ + register const char *s = nptr; + register uint64_t acc; + register int32_t c; + register uint64_t cutoff; + register int32_t neg = 0, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? -(uint64_t)INT64_MIN : INT64_MAX; + cutlim = cutoff % (uint64_t)base; + cutoff /= (uint64_t)base; + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? INT64_MIN : INT64_MAX; + *err = GS_ERROR_OVERFLOW; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} + + +/* + * Convert a string to an unsigned long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ + +uint64_t gs_string_strto64uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) +{ + register const char *s = nptr; + register uint64_t acc; + register int32_t c; + register uint64_t cutoff; + register int32_t neg = 0, any, cutlim; + + /* + * See strtol for comments as to the logic used. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + cutoff = (uint64_t)UINT64_MAX / (uint64_t)base; + cutlim = (uint64_t)UINT64_MAX % (uint64_t)base; + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = UINT64_MAX; + *err = GS_ERROR_OVERFLOW; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} diff --git a/gomspace/libutil/src/test/cmocka.c b/gomspace/libutil/src/test/cmocka.c new file mode 100644 index 00000000..c3c5d171 --- /dev/null +++ b/gomspace/libutil/src/test/cmocka.c @@ -0,0 +1,63 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +void cm_print_error(const char * const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); + +#define EQUAL_TO_STRING(equal) (equal ? "!=" : "==") + +void _gs_assert_int_equal(const intptr_t left, const intptr_t right, bool equal, const char * const file, const int line) +{ + const bool cmp_equal = left == right; + if (cmp_equal != equal) { + cm_print_error("%ld %s %ld\n", left, EQUAL_TO_STRING(equal), right); + + _fail(file, line); + } +} + +void _gs_assert_uint_equal(const uintptr_t left, const uintptr_t right, bool equal, bool hex, const char * const file, const int line) +{ + const bool cmp_equal = left == right; + if (cmp_equal != equal) { + if(hex) { + cm_print_error("0x%lx %s 0x%lx\n", left, EQUAL_TO_STRING(equal), right); + } else { + cm_print_error("%lu %s %lu\n", left, EQUAL_TO_STRING(equal), right); + } + + _fail(file, line); + } +} + +void _gs_assert_error_equal(const int left, const int right, bool equal, const char * const file, const int line) +{ + const bool cmp_equal = left == right; + if (cmp_equal != equal) { + cm_print_error("%d(%s) %s %d(%s)\n", left, gs_error_string(left), EQUAL_TO_STRING(equal), right, gs_error_string(right)); + + _fail(file, line); + } +} + +void _gs_assert_float_equal(const float left, const float right, const float diff, bool equal, const char * const file, const int line) +{ + const bool cmp_equal = (fabsf(left - right) < diff); + if (cmp_equal != equal) { + cm_print_error("%e %s %e\n", left, EQUAL_TO_STRING(equal), right); + + _fail(file, line); + } +} + +void _gs_assert_double_equal(const double left, const double right, const double diff, bool equal, const char * const file, const int line) +{ + const bool cmp_equal = (fabsf(left - right) < diff); + if (cmp_equal != equal) { + cm_print_error("%e %s %e\n", left, EQUAL_TO_STRING(equal), right); + + _fail(file, line); + } +} diff --git a/gomspace/libutil/src/test/command.c b/gomspace/libutil/src/test/command.c new file mode 100644 index 00000000..e9678523 --- /dev/null +++ b/gomspace/libutil/src/test/command.c @@ -0,0 +1,176 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include +#include + +void cm_print_error(const char * const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); + +struct results { + char group[32]; + char key[32]; + char value[128]; +}; + +static FILE* g_output_file = 0; +static char g_stdout_buf[10000]; +static char g_stdin_buf[1000]; +static uint16_t g_stdin_idx; + +static struct results g_results[100]; +static uint32_t g_results_count = 0; + + +static gs_error_t test_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value) +{ + if (g_results_count >= GS_ARRAY_SIZE(g_results)) { + return GS_ERROR_ALLOC; + } + + if (group) { + strncpy(g_results[g_results_count].group, group, sizeof(g_results[0].group)); + } + if (key) { + strncpy(g_results[g_results_count].key, key, sizeof(g_results[0].key)); + } + if (value) { + strncpy(g_results[g_results_count].value, value, sizeof(g_results[0].value)); + } + g_results_count++; + return GS_OK; +} + +static gs_error_t test_flush(gs_command_context_t *ctx) +{ + fflush(ctx->out); + return GS_OK; +} + +static gs_error_t test_wait_for_key(gs_command_context_t *ctx, int *ch, int timeout_ms) +{ + if (g_stdin_buf[g_stdin_idx] == 0) { + gs_time_sleep_ms(timeout_ms); + return GS_ERROR_TIMEOUT; + } + + *ch = g_stdin_buf[g_stdin_idx]; + g_stdin_idx++; + return GS_OK; +} + +static gs_command_io_functions_t g_test_io_functions = { + .set_result = test_set_result, + .flush = test_flush, + .wait_for_key = test_wait_for_key, +}; + + +static gs_error_t prepare_validation(const char *input) +{ + g_results_count = 0; + memset(g_stdout_buf, 0, sizeof(g_stdout_buf)); + memset(g_stdin_buf, 0, sizeof(g_stdin_buf)); + g_stdin_idx = 0; + + if (input != NULL) { + memcpy(g_stdin_buf, input, strlen(input)); + } + + g_output_file = fmemopen(g_stdout_buf, sizeof(g_stdout_buf) - 1, "w"); + if (!g_output_file) { + return GS_ERROR_ALLOC; + } + + return GS_OK; +} + +static bool match(const char *first, const char * second) +{ + return (fnmatch(first, second, 0) == 0); +} + +static gs_error_t do_validation(const char *expected) +{ + fclose(g_output_file); + + if (expected == NULL) + return GS_OK; + + if (!match(expected, g_stdout_buf)) + { + return GS_ERROR_DATA; + } + return GS_OK; +} + + +void _gs_assert_command_validate(const char *cmd, gs_error_t ret, gs_error_t cmd_ret, const char *std_in, const char *std_out, + const char * const file, const int line) +{ + if (prepare_validation(std_in) != GS_OK) + { + cm_print_error("Validation function failed to allocate it's resources\n"); + _fail(file, line); + } + + gs_error_t _ret; + gs_error_t _command_ret = GS_OK; + _ret = gs_command_execute(cmd, &_command_ret, g_output_file, &g_test_io_functions, NULL); + + if (_ret != ret) { + cm_print_error("Return: %d(%s) != %d(%s)\n", _ret, gs_error_string(_ret), ret, gs_error_string(ret)); + _fail(file, line); + } + + if (_ret == GS_OK) /* Only check CMD return if command execution succeeded */ + { + if (_command_ret != cmd_ret) { + cm_print_error("Command return: %d(%s) != %d(%s)\n", _command_ret, gs_error_string(_command_ret), + cmd_ret, gs_error_string(cmd_ret)); + _fail(file, line); + } + } + + if (do_validation(std_out) != GS_OK) + { + //cm_print_error("Stdout != : \n%s\n!=\n%s\n", g_stdout_buf, std_out); + printf("Stdout != : \n%s\n!=\n%s\n", g_stdout_buf, std_out); + _fail(file, line); + } + + return; +} + +void _gs_assert_command_validate_last_result(unsigned int no, const char *group, const char *key, const char *value, + const char * const file, const int line) +{ + if (no >= g_results_count) + { + cm_print_error("Result no: %d not available. Only %d results returned from command\n", no, g_results_count); + _fail(file, line); + } + + if (group) { + if (!match(group, g_results[no].group)) { + cm_print_error("group: %s != %s\n", group, g_results[no].group); + _fail(file, line); + } + } + if (key) { + if (!match(key, g_results[no].key)) { + cm_print_error("key: %s != %s\n", key, g_results[no].key); + _fail(file, line); + } + } + if (value) { + if (!match(value, g_results[no].value)) { + cm_print_error("value: %s != %s\n", value, g_results[no].value); + _fail(file, line); + } + } + + return; +} diff --git a/gomspace/libutil/src/test/log.c b/gomspace/libutil/src/test/log.c new file mode 100644 index 00000000..ba7671e1 --- /dev/null +++ b/gomspace/libutil/src/test/log.c @@ -0,0 +1,165 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// cmocka +void cm_print_error(const char * const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); + +static gs_mutex_t g_lock; + +#define GS_TEST_LOG_MAX_LEVELS 6 +#define GS_TEST_LOG_MAX_LOG_MESSAGES 200 + +typedef struct { + // Overall count per log level. + unsigned int count[GS_TEST_LOG_MAX_LEVELS]; + // Log messages. + struct { + // Level. + gs_log_level_t level; + // Format log message. + char msg[150]; + } logs[GS_TEST_LOG_MAX_LOG_MESSAGES]; + // Index of next entry in \a logs. + unsigned int next_log; +} gs_test_log_stats_t; + +static gs_test_log_stats_t gs_test_log_stats; + +static void log_callback(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t * group, const gs_timestamp_t * ts, const char * format, va_list va) +{ + gs_mutex_lock(g_lock); + gs_test_log_stats.count[level]++; + + { + gs_bytebuffer_t bb; + gs_bytebuffer_init(&bb, + gs_test_log_stats.logs[gs_test_log_stats.next_log].msg, + sizeof(gs_test_log_stats.logs[gs_test_log_stats.next_log].msg)); + + va_list my_va; + va_copy(my_va, va); + gs_bytebuffer_printf(&bb, "%s: ", group->name); + gs_bytebuffer_vprintf(&bb, format, my_va); + va_end(my_va); + gs_bytebuffer_get_as_string(&bb, NULL); // ensure NUL termination + gs_test_log_stats.logs[gs_test_log_stats.next_log].level = level; + + ++gs_test_log_stats.next_log; + if (gs_test_log_stats.next_log >= GS_TEST_LOG_MAX_LOG_MESSAGES) { + gs_test_log_stats.next_log = 0; + } + gs_test_log_stats.logs[gs_test_log_stats.next_log].msg[0] = 0; // clear next entry + gs_test_log_stats.logs[gs_test_log_stats.next_log].level = GS_TEST_LOG_MAX_LEVELS; + } + + gs_mutex_unlock(g_lock); +} + +static gs_log_appender_driver_t g_log_test_appender_driver = { + .init = 0, + .append = log_callback, + .append_isr = log_callback, +}; + +static gs_log_appender_t g_log_test_appender = { + .name = "test_appender", + .drv = &g_log_test_appender_driver, + .drv_config = NULL, + .drv_data = NULL, + .mask = LOG_ALL_MASK, +}; + +void gs_test_log_init(bool verbose) +{ + gs_log_init(true); + + if (g_lock == NULL) { + GS_ASSERT_ERROR_EQUAL(gs_mutex_create(&g_lock), GS_OK); + + /* Add/Register appender - Only first time that init is called. */ + gs_log_appender_add(&g_log_test_appender, 1); + gs_log_group_register_appender("root", "test_appender"); + } + if (verbose) { + gs_log_appender_set_level_mask("console", LOG_ALL_MASK); + } else { + gs_log_appender_set_level_mask("console", 0); + } + + gs_test_log_clear(); +} + +void gs_test_log_clear(void) +{ + gs_mutex_lock(g_lock); + memset(&gs_test_log_stats, 0, sizeof(gs_test_log_stats)); + gs_mutex_unlock(g_lock); +} + +void gs_assert_log_count(int level, unsigned int count, const char * file, int line) +{ + if (level < 0) { + unsigned int tot = 0; + for (int i = 0; i < GS_TEST_LOG_MAX_LEVELS; ++i) { + tot += gs_test_log_stats.count[i]; + } + if (tot != count) { + cm_print_error("Unexpected total log count: %u != %u\n", tot, count); + _fail(file, line); + } + } else if (level >= GS_TEST_LOG_MAX_LEVELS) { + cm_print_error("Unknown log level: %d - valid levels 0 - %d\n", level, GS_TEST_LOG_MAX_LEVELS - 1); + _fail(file, line); + } else if (gs_test_log_stats.count[level] != count) { + cm_print_error("Unexpected log count: %u != %u\n", gs_test_log_stats.count[level], count); + _fail(file, line); + } +} + +void gs_assert_log(unsigned int stack_index, unsigned int count, gs_log_level_t level, const char * pattern, const char * file, int line) +{ + if (stack_index == UINT32_MAX) { + // loop through all logs + unsigned int next = gs_test_log_stats.next_log; + unsigned int hits = 0; + for (unsigned int i = next - 1; i != next; --i) { + if (i >= GS_TEST_LOG_MAX_LOG_MESSAGES) { + i = (GS_TEST_LOG_MAX_LOG_MESSAGES - 1); + } + if ((gs_test_log_stats.logs[i].level == level) && (gs_test_log_stats.logs[i].msg[0])) { + if (fnmatch(pattern, gs_test_log_stats.logs[i].msg, 0) == 0) { + ++hits; + } + } + } + if (hits != count) { + cm_print_error("Unexpected log count: %u != %u\n", hits, count); + _fail(file, line); + } + } else if (stack_index >= GS_TEST_LOG_MAX_LOG_MESSAGES) { + cm_print_error("Invalid stack_index: %u - valid 0 - %d\n", stack_index, GS_TEST_LOG_MAX_LOG_MESSAGES - 1); + _fail(file, line); + } else { + unsigned int i = (((gs_test_log_stats.next_log + GS_TEST_LOG_MAX_LOG_MESSAGES) - 1 - stack_index) % GS_TEST_LOG_MAX_LOG_MESSAGES); + if ((gs_test_log_stats.logs[i].level == level) && + (gs_test_log_stats.logs[i].msg[0]) && + (fnmatch(pattern, gs_test_log_stats.logs[i].msg, 0) == 0)) { + // match + } else { + cm_print_error("[%c][%s] != [%c][%s]\n", + gs_log_level_to_char(gs_test_log_stats.logs[i].level), gs_test_log_stats.logs[i].msg, + gs_log_level_to_char(level), pattern); + _fail(file, line); + } + } +} diff --git a/gomspace/libutil/src/time.c b/gomspace/libutil/src/time.c new file mode 100644 index 00000000..123f5994 --- /dev/null +++ b/gomspace/libutil/src/time.c @@ -0,0 +1,28 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include + +uint32_t gs_time_diff_ms(uint32_t ref_ms, uint32_t now_ms) +{ + if (now_ms >= ref_ms) { + return (now_ms - ref_ms); + } + + // assuming time wrapped at max uint32_t + return ((UINT32_MAX - ref_ms) + now_ms); +} + +bool gs_time_sleep_until_ms(uint32_t * ref_ms, uint32_t sleep_ms) +{ + const uint32_t now = gs_time_rel_ms(); + *ref_ms += sleep_ms; // this is expected to be in the future + uint32_t ms = gs_time_diff_ms(now, *ref_ms); + if (ms > sleep_ms) { + // we are behind - catch up, could be bad seed or too long processing + *ref_ms = now; + gs_time_sleep_ms(0); // yield - let others have a go + return true; + } + gs_time_sleep_ms(ms); + return false; +} diff --git a/gomspace/libutil/src/timestamp.c b/gomspace/libutil/src/timestamp.c new file mode 100644 index 00000000..2f7ee913 --- /dev/null +++ b/gomspace/libutil/src/timestamp.c @@ -0,0 +1,61 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include + +int timestamp_add(gs_timestamp_t * base, const gs_timestamp_t * add) +{ + if (!base || !add) + return -1; + + base->tv_sec += add->tv_sec; + if (base->tv_nsec + add->tv_nsec >= GS_TIMESTAMP_NSEC_PER_SEC) { + base->tv_sec++; + base->tv_nsec = (base->tv_nsec + add->tv_nsec) % GS_TIMESTAMP_NSEC_PER_SEC; + } else { + base->tv_nsec += add->tv_nsec; + } + + return 0; +} + +int timestamp_diff(gs_timestamp_t * base, const gs_timestamp_t * diff) +{ + if (!base || !diff) + return -1; + + base->tv_sec -= diff->tv_sec; + if (base->tv_nsec >= diff->tv_nsec) { + base->tv_nsec -= diff->tv_nsec; + } else { + base->tv_sec--; + base->tv_nsec = (base->tv_nsec + GS_TIMESTAMP_NSEC_PER_SEC) - diff->tv_nsec; + } + + return 0; +} + +/* Test is timestamp is greater or equal */ +int timestamp_ge(const gs_timestamp_t * base, const gs_timestamp_t * test) +{ + if (!base || !test) + return -1; + + if (test->tv_sec > base->tv_sec || + (test->tv_sec == base->tv_sec && + test->tv_nsec > base->tv_nsec)) { + return 1; + } + + return 0; +} + +int timestamp_copy(const gs_timestamp_t * from, gs_timestamp_t * to) +{ + if (!from || !to) + return -1; + + to->tv_sec = from->tv_sec; + to->tv_nsec = from->tv_nsec; + + return 0; +} diff --git a/gomspace/libutil/src/vmem/commands.c b/gomspace/libutil/src/vmem/commands.c new file mode 100644 index 00000000..06a37af4 --- /dev/null +++ b/gomspace/libutil/src/vmem/commands.c @@ -0,0 +1,123 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +static int cmd_vmem_read(gs_command_context_t * ctx) +{ + if (gs_vmem_get_map() == NULL) { + return GS_ERROR_NOT_FOUND; + } + + void * addr; + if (gs_string_to_pointer(ctx->argv[1], &addr)) { + return GS_ERROR_ARG; + } + + uint32_t length; + if (gs_string_to_uint32(ctx->argv[2], &length)) { + return GS_ERROR_ARG; + } + + char data[length]; + void* to = gs_vmem_cpy(data, addr, length); + if (to == NULL) { + return GS_ERROR_ARG; + } + + gs_hexdump_to_stream(data, length, addr, ctx->out); + + return GS_OK; +} + +static unsigned int to_int(char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'A' && c <= 'F') return 10 + c - 'A'; + if (c >= 'a' && c <= 'f') return 10 + c - 'a'; + return -1; +} + +static int cmd_vmem_write(gs_command_context_t * ctx) +{ + if (gs_vmem_get_map() == NULL) { + return GS_ERROR_NOT_FOUND; + } + + void * addr; + if (gs_string_to_pointer(ctx->argv[1], &addr)) { + return GS_ERROR_ARG; + } + + int len = strlen(ctx->argv[2]) / 2; + char data[len]; + + for (int i = 0; (i < len); ++i) { + data[i] = 16 * to_int(ctx->argv[2][2*i]) + to_int(ctx->argv[2][2*i+1]); + } + + gs_vmem_cpy(addr, data, len); + return GS_OK; +} + +static int cmd_vmem_list(gs_command_context_t * ctx) +{ + return gs_vmem_list(ctx->out); +} + +static int cmd_vmem_lock(gs_command_context_t * context) +{ + return gs_vmem_lock_by_name(context->argv[1], true); +} + +static int cmd_vmem_unlock(gs_command_context_t * context) +{ + return gs_vmem_lock_by_name(context->argv[1], false); +} + +static const gs_command_t GS_COMMAND_SUB cmd_vmem_sub[] = { + { + .name = "read", + .help = "Read from virtual memory", + .usage = " ", + .handler = cmd_vmem_read, + .mandatory_args = 2, + },{ + .name = "write", + .help = "Write to virtual memory", + .usage = " ", + .handler = cmd_vmem_write, + .mandatory_args = 2, + },{ + .name = "lock", + .help = "Lock the virtual memory", + .usage = "", + .handler = cmd_vmem_lock, + .mandatory_args = 1, + },{ + .name = "unlock", + .help = "Unlock the virtual memory", + .usage = "", + .handler = cmd_vmem_unlock, + .mandatory_args = 1, + },{ + .name = "list", + .help = "Show virtual memory mappings", + .handler = cmd_vmem_list, + .mandatory_args = GS_COMMAND_NO_ARGS, + } +}; + +static const gs_command_t GS_COMMAND_ROOT cmd_vmem[] = { + { + .name = "vmem", + .help = "Virtual memory", + .chain = GS_COMMAND_INIT_CHAIN(cmd_vmem_sub), + }, +}; + +gs_error_t gs_vmem_register_commands(void) +{ + return GS_COMMAND_REGISTER(cmd_vmem); +} diff --git a/gomspace/libutil/src/vmem/vmem.c b/gomspace/libutil/src/vmem/vmem.c new file mode 100644 index 00000000..30068a01 --- /dev/null +++ b/gomspace/libutil/src/vmem/vmem.c @@ -0,0 +1,143 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include + +static const gs_vmem_t * g_vmem_map; + +gs_error_t gs_vmem_set_map(const gs_vmem_t * map) +{ + g_vmem_map = map; + return GS_OK; +} + +const gs_vmem_t * gs_vmem_get_map(void) +{ + return g_vmem_map; +} + +gs_error_t gs_vmem_list(FILE * out) +{ + const gs_vmem_t * mem = g_vmem_map; + if (mem) { + unsigned int found = 0; + for (; mem->name; ++mem) { + if (found == 0) { + fprintf(out, "%-20s %-10s %-6s %-6s %s\r\n", "name", "virt.", "phys.", "size", "size"); + } + fprintf(out, "%-20s %p 0x%04x 0x%04x %5u\r\n", mem->name, mem->virtmem.p, (unsigned int) mem->physmem.u, (unsigned int) mem->size, (unsigned int) mem->size); + ++found; + } + if (found) { + return GS_OK; + } + } + return GS_ERROR_NOT_FOUND; +} + +const gs_vmem_t * gs_vmem_get_by_name(const char * name) +{ + if (name) { + const gs_vmem_t * mem = g_vmem_map; + if (mem) { + for (; mem->name; ++mem) { + if (strcasecmp(name, mem->name) == 0) { + return mem; + } + } + } + } + return NULL; +} + +gs_error_t gs_vmem_lock_by_name(const char * name, bool on) +{ + const gs_vmem_t * mem = gs_vmem_get_by_name(name); + if (mem) { + if (mem->drv && mem->drv->lock) { + return (mem->drv->lock)(mem, on); + } + return GS_ERROR_NOT_SUPPORTED; + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_vmem_lock_all(bool on) +{ + const gs_vmem_t * mem = g_vmem_map; + if (mem) { + unsigned int locked = 0; + for (; mem->name; ++mem) { + if (mem->drv && mem->drv->lock) { + (mem->drv->lock)(mem, on); + ++locked; + } + } + if (locked) { + return GS_OK; + } + } + return GS_ERROR_NOT_FOUND; +} + +/** + @note NO LOGGING - currently the log system uses this interface, and logging can therefor create circular/forever loops. +*/ +void * gs_vmem_cpy(void* to, const void* from, size_t size) +{ + /* Search memories */ + const gs_vmem_t *vmem_from = NULL; + const gs_vmem_t *vmem_to = NULL; + const gs_vmem_t *mem = g_vmem_map; + const gs_address_t _to = {.p = to}; + const gs_address_t _from = {.p = (void*) from}; + + if (mem) { + while(mem->size != 0) { + //printf("0x%lx 0x%lx %"PRIu32" %lu %lu\r\n", mem->start, mem->physmem_start, mem->size, to, from); + if ((_to.u >= mem->virtmem.u) && (_to.u < mem->virtmem.u + mem->size)) { + vmem_to = mem; + } + if ((_from.u >= mem->virtmem.u) && (_from.u < mem->virtmem.u + mem->size)) { + vmem_from = mem; + } + mem++; + } + } + + // VMEM -> VMEM + if (vmem_to && vmem_from) { + printf("%s: VMEM to VMEM is not supported\r\n", __FUNCTION__); + return NULL; + } + + // RAM -> VMEM + if (vmem_to) { + if ((vmem_to->drv == NULL) || (vmem_to->drv->write == NULL)) { + printf("%s: Writting to VMEM %p is not supported\r\n", __FUNCTION__, to); + return NULL; + } + gs_address_t physaddr = {.u = (_to.u - vmem_to->virtmem.u) + vmem_to->physmem.u}; + //printf("Copying from ram 0x%lx to physaddr 0x%lx %u\r\n", from, physaddr, (unsigned int) size); + vmem_to->drv->write(vmem_to, physaddr.p, from, size); + return to; + } + + // VMEM -> RAM + if (vmem_from) { + if (vmem_from->drv == NULL || (vmem_from->drv->read == NULL)) { + printf("%s: Reading from VMEM %p is not supported\r\n", __FUNCTION__, from); + return NULL; + } + gs_address_t physaddr = {.u = (_from.u - vmem_from->virtmem.u) + vmem_from->physmem.u}; + //printf("Copying from mem physaddr 0x%lx to 0x%lx %u\r\n", physaddr, to, (unsigned int) size); + vmem_from->drv->read(vmem_from, to, physaddr.p, size); + return to; + } + + // RAM -> RAM (no VMEM mapping found) + return memcpy(to, from, size); +} diff --git a/gomspace/libutil/src/watchdog/local.h b/gomspace/libutil/src/watchdog/local.h new file mode 100644 index 00000000..1dc2e0de --- /dev/null +++ b/gomspace/libutil/src/watchdog/local.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include + +typedef struct { + gs_thread_t task; + bool is_running; + bool do_stop; +} gs_swwd_monitor_task_t; + +// Return monitor task instance +gs_swwd_monitor_task_t * gs_swwd_get_monitor_task(void); + +GS_LOG_GROUP_EXTERN(gs_swwd_log); +#define LOG_DEFAULT gs_swwd_log diff --git a/gomspace/libutil/src/watchdog/monitor_task.c b/gomspace/libutil/src/watchdog/monitor_task.c new file mode 100644 index 00000000..54d7e668 --- /dev/null +++ b/gomspace/libutil/src/watchdog/monitor_task.c @@ -0,0 +1,68 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include "local.h" +#include +#include +#include + +#define GS_SWWD_CHECK_INTERVAL_MS 1000 /* Check every 1 sec. */ + +static void * gs_swwd_monitor_task(void* parameter) +{ + gs_swwd_monitor_task_t * monitor = parameter; + + log_info("monitor task started"); + + monitor->is_running = true; + + while(!monitor->do_stop) { + + gs_time_sleep_ms(GS_SWWD_CHECK_INTERVAL_MS); + + gs_swwd_check_expired_clients(NULL); + } + + monitor->is_running = false; + + log_info("monitor task exiting"); + + return NULL; +} + +gs_error_t gs_swwd_monitor_task_start(void) +{ + gs_swwd_monitor_task_t * monitor = gs_swwd_get_monitor_task(); + GS_CHECK_SUPPORTED(monitor != NULL); /* SWWD must be initialized */ + GS_CHECK_SUPPORTED(monitor->is_running == false); /* SWWD task must not already be running */ + + /* Start the monitor task */ + gs_error_t error = gs_thread_create("SWWD", gs_swwd_monitor_task, monitor, 4000, GS_THREAD_PRIORITY_HIGH, 0, &monitor->task); + if (error) { + log_error("%s: gs_thread_create() failed, error: %s", __FUNCTION__, gs_error_string(error)); + } + return error; +} + +gs_error_t gs_swwd_monitor_task_stop(uint32_t timeout_s) +{ + gs_swwd_monitor_task_t * monitor = gs_swwd_get_monitor_task(); + GS_CHECK_SUPPORTED(monitor != NULL); /* SWWD must be initialized */ + + /* Signal the task to stop */ + monitor->do_stop = true; + + /* Wait for the task to stop */ + const uint32_t timeout = GS_SWWD_CHECK_INTERVAL_MS + (timeout_s * 1000); + uint32_t tm = 0; + while(monitor->is_running && (tm < timeout)) { + gs_thread_sleep_ms(100); + tm += 100; + } + + if (monitor->is_running) { + return GS_ERROR_BUSY; + } + + return GS_OK; +} + diff --git a/gomspace/libutil/src/watchdog/watchdog.c b/gomspace/libutil/src/watchdog/watchdog.c new file mode 100644 index 00000000..867601b1 --- /dev/null +++ b/gomspace/libutil/src/watchdog/watchdog.c @@ -0,0 +1,292 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include "local.h" +#include +#include +#include +#include +#include + +#define GS_SWWD_DEFAULT_TIMEOUT 30 /* 30 second timeout */ + +// define log group and make it default +GS_LOG_GROUP(gs_swwd_log, "swwd", GS_LOG_CAT_DEFAULT, GS_LOG_DEFAULT_MASK); + +// watchdog state +typedef enum { + GS_SWWD_STATE_FREE = 0, + GS_SWWD_STATE_ACTIVE = 1, + GS_SWWD_STATE_EXPIRED = 2, +} gs_swwd_state_t; + +// watchdog client instance +struct gs_swwd_hdl { + // State + gs_swwd_state_t state; + // Last 'user' touch value - used for detecting if watchdog has been touched (avoid race condition) + uint32_t last_touch; + // Last detected touch time + uint32_t last_touch_ms; + + // User 'set' attributes + struct { + // Name + const char* name; + // Timeout - converted from seconds (given to API) to mS + uint32_t timeout_ms; + // Action when/if timeout occurs + gs_swwd_timeout_action_t action; + // callback + gs_swwd_callback_function_t cb; + // user data (for callback) + void * cb_userdata; + // Touch - incremented on each touch + uint32_t touch; + } user; +}; + +typedef struct gs_swwd { + gs_watchdog_device_t *wdev; + gs_mutex_t lock; + gs_swwd_monitor_task_t monitor; + uint32_t num_clients; + gs_swwd_hdl_t clients[0]; +} gs_swwd_t; + +static gs_swwd_t* g_swwd = NULL; + +gs_swwd_monitor_task_t * gs_swwd_get_monitor_task(void) +{ + if (g_swwd) { + return &g_swwd->monitor; + } + return NULL; +} + +gs_error_t gs_swwd_create(uint32_t max_clients, gs_watchdog_device_t * wdev) +{ + GS_CHECK_SUPPORTED(g_swwd == NULL); /* SWWD must not be initialized more than once */ + GS_CHECK_ARG(max_clients > 0); + if (wdev) { + // ping is the only mandatory + GS_CHECK_ARG((wdev->ops != NULL) && (wdev->ops->ping != NULL)); + } + + gs_log_group_register(LOG_DEFAULT); + + gs_swwd_t *swwd_obj = calloc(1, sizeof(*swwd_obj) + (sizeof(swwd_obj->clients[0]) * max_clients)); + if (swwd_obj == NULL) { + return GS_ERROR_ALLOC; + } + + if (gs_mutex_create(&(swwd_obj->lock))) { + free(swwd_obj); + return GS_ERROR_ALLOC; + } + + swwd_obj->num_clients = max_clients; + swwd_obj->wdev = wdev; + + if (wdev) { + if (wdev->ops->set_timeout) { + wdev->ops->set_timeout(wdev, (wdev->timeout > 0) ? wdev->timeout : GS_SWWD_DEFAULT_TIMEOUT); + } + if (wdev->ops->set_pretimeout) { + wdev->ops->set_pretimeout(wdev, (wdev->pretimeout > 0) ? wdev->pretimeout : (GS_SWWD_DEFAULT_TIMEOUT - (GS_SWWD_DEFAULT_TIMEOUT/10))); + } + if (wdev->ops->start) { + wdev->ops->start(wdev); + } + wdev->ops->ping(wdev); + + } else { + log_warning("%s: no watchdog device specifed - cannot reset system!", __FUNCTION__); + } + + g_swwd = swwd_obj; /* Set the task handle as the last operation */ + return GS_OK; +} + +gs_error_t gs_swwd_destroy(uint32_t timeout_s) +{ + GS_CHECK_SUPPORTED(g_swwd != NULL); + + if (gs_swwd_monitor_task_stop(timeout_s) != GS_OK) { + return GS_ERROR_BUSY; + } + + if (g_swwd->wdev && g_swwd->wdev->ops->stop) { + g_swwd->wdev->ops->stop(g_swwd->wdev); + } + + gs_mutex_destroy(g_swwd->lock); + free(g_swwd); + g_swwd = NULL; + + return GS_OK; +} + +static const char * get_action(gs_swwd_timeout_action_t action) +{ + switch (action) { + case GS_SWWD_TIMEOUT_ACTION_RESET: + return "reset"; + case GS_SWWD_TIMEOUT_ACTION_LOG: + return "log"; + } + return "unknown"; +} + +gs_error_t gs_swwd_check_expired_clients(uint32_t *num_expired) +{ + GS_CHECK_SUPPORTED(g_swwd != NULL); /* SWWD must be initialized */ + + uint32_t expired_clients_reset = 0; + uint32_t expired_clients_log = 0; + + gs_mutex_lock(g_swwd->lock); + for (uint32_t idx = 0; idx < g_swwd->num_clients; idx++) { + gs_swwd_hdl_t * wd = &g_swwd->clients[idx]; + + uint32_t now_ms = gs_time_rel_ms(); + if (wd->state == GS_SWWD_STATE_ACTIVE) { + if (wd->last_touch != wd->user.touch) { + // watchdog has been touched since last we checked - update touch time + wd->last_touch = wd->user.touch; + wd->last_touch_ms = now_ms; + } else { + const uint32_t elapsed_ms = gs_time_diff_ms(wd->last_touch_ms, now_ms); + if (elapsed_ms >= wd->user.timeout_ms) { + wd->state = GS_SWWD_STATE_EXPIRED; + + char logbuf[100]; + snprintf(logbuf, sizeof(logbuf), + "[%s] expired -> %s (elapsed %"PRIu32" mS, timeout %"PRIu32" mS)", + wd->user.name, + get_action(wd->user.action), + elapsed_ms, + wd->user.timeout_ms); + + gs_swwd_callback_function_t cb = wd->user.cb; + void * cb_userdata = wd->user.cb_userdata; + + // Unlock while doing log and callback + // - we accept the tiny risk, that client has deregistered and will be called with invalid data + gs_mutex_unlock(g_swwd->lock); + { + log_error("%s", logbuf); + if (cb) { + (cb)(cb_userdata); + } + } + gs_mutex_lock(g_swwd->lock); + } + } + } + if (wd->state == GS_SWWD_STATE_EXPIRED) { + switch (wd->user.action) { + case GS_SWWD_TIMEOUT_ACTION_RESET: + ++expired_clients_reset; + break; + case GS_SWWD_TIMEOUT_ACTION_LOG: + if (wd->last_touch != wd->user.touch) { + // its alive - reactive watchdog + wd->state = GS_SWWD_STATE_ACTIVE; + wd->last_touch = wd->user.touch; + wd->last_touch_ms = now_ms; + } else { + ++expired_clients_log; + } + break; + } + } + } + gs_mutex_unlock(g_swwd->lock); + + if ((expired_clients_reset == 0) && g_swwd->wdev) { + g_swwd->wdev->ops->ping(g_swwd->wdev); + } + + if (num_expired) { + *num_expired = (expired_clients_reset + expired_clients_log); + } + + return GS_OK; +} + +gs_error_t gs_swwd_register_with_action(gs_swwd_hdl_t ** user_wd, + uint32_t timeout_seconds, + gs_swwd_callback_function_t callback, void * userdata, + const char * name, + gs_swwd_timeout_action_t action) +{ + GS_CHECK_ARG(gs_string_empty(name) == false); + GS_CHECK_ARG(timeout_seconds > 0); + GS_CHECK_ARG(user_wd != NULL); + GS_CHECK_SUPPORTED(g_swwd != NULL); /* SWWD must be initialized */ + + gs_swwd_hdl_t * wd = NULL; + gs_mutex_lock(g_swwd->lock); + { + for (unsigned int idx = 0; idx < g_swwd->num_clients; idx++) { + if (g_swwd->clients[idx].state == GS_SWWD_STATE_FREE) { + wd = &g_swwd->clients[idx]; + memset(wd, 0, sizeof(*wd)); + + // set user stuff + wd->user.name = name; + wd->user.timeout_ms = (timeout_seconds * 1000); + wd->user.cb = callback; + wd->user.cb_userdata = userdata; + wd->user.action = action; + + // set internal stuff + wd->state = GS_SWWD_STATE_ACTIVE; + wd->last_touch_ms = gs_time_rel_ms(); + break; + } + } + } + gs_mutex_unlock(g_swwd->lock); + + *user_wd = wd; + + if (wd == NULL) { + log_error("[%s] cannot create instance due to no available handles", name); + return GS_ERROR_FULL; + } + + return GS_OK; +} + +gs_error_t gs_swwd_deregister(gs_swwd_hdl_t ** wd) +{ + GS_CHECK_SUPPORTED(g_swwd != NULL); /* SWWD must be initialized */ + GS_CHECK_ARG(wd != NULL); + GS_CHECK_HANDLE(*wd != NULL); + + gs_mutex_lock(g_swwd->lock); + memset((*wd), 0, sizeof(**wd)); + gs_mutex_unlock(g_swwd->lock); + *wd = NULL; + + return GS_OK; +} + +gs_error_t gs_swwd_touch(gs_swwd_hdl_t * wd) +{ + GS_CHECK_HANDLE(wd != NULL); + + ++wd->user.touch; + return GS_OK; +} + +gs_error_t gs_swwd_set_timeout(gs_swwd_hdl_t * wd, uint32_t timeout_seconds) +{ + GS_CHECK_ARG(timeout_seconds > 0); + GS_CHECK_HANDLE(wd != NULL); + + ++wd->user.touch; + wd->user.timeout_ms = (timeout_seconds * 1000); + return GS_OK; +} diff --git a/gomspace/libutil/src/zip/cppcheck-suppress.txt b/gomspace/libutil/src/zip/cppcheck-suppress.txt new file mode 100644 index 00000000..b23b687d --- /dev/null +++ b/gomspace/libutil/src/zip/cppcheck-suppress.txt @@ -0,0 +1,5 @@ +// we don't wanna change 3rd part code for none-critical issue +localtimeCalled:src/zip/miniz/miniz.c +utimeCalled:src/zip/miniz/miniz.c +assignIfError:src/zip/miniz/miniz.c +unreadVariable:src/zip/miniz/miniz.c diff --git a/gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES b/gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES new file mode 100644 index 00000000..cb7adb22 --- /dev/null +++ b/gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES @@ -0,0 +1,9429 @@ +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +diff --git a/src/zip/miniz/miniz.h b/src/zip/miniz/miniz.h +index 86fac4c..f92f14e 100644 +--- a/src/zip/miniz/miniz.h ++++ b/src/zip/miniz/miniz.h +@@ -447,7 +447,7 @@ typedef void *const voidpc; + #define inflate mz_inflate + #define inflateEnd mz_inflateEnd + #define uncompress mz_uncompress +-#define crc32 mz_crc32 ++// #define crc32 mz_crc32 + #define adler32 mz_adler32 + #define MAX_WBITS 15 + #define MAX_MEM_LEVEL 9 + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + +diff --git a/src/zip/miniz/miniz.c b/src/zip/miniz/miniz.c +index 67318cc..960f07c 100644 +--- a/src/zip/miniz/miniz.c ++++ b/src/zip/miniz/miniz.c +@@ -1936,6 +1936,7 @@ tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_fun + d->m_pSrc = NULL; + d->m_src_buf_left = 0; + d->m_out_buf_ofs = 0; ++ memset(d->m_dict, 0, sizeof(d->m_dict)); // Initialize array to 0's + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +@@ -2464,7 +2465,7 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_nex + } + r->m_table_sizes[2] = 19; + } +- for (; (int)r->m_type >= 0; r->m_type--) ++ for (; ((int)r->m_type) >= 0; r->m_type--) + { + int tree_next, tree_cur; + tinfl_huff_table *pTable; +@@ -3025,7 +3026,7 @@ static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) + #define MZ_DELETE_FILE remove + + #else +-#pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") ++// #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") + #ifndef MINIZ_NO_TIME + #include + #endif +@@ -3267,12 +3268,12 @@ static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) + } + + #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +-static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) ++static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) + { + #ifdef _MSC_VER + struct tm tm_struct; + struct tm *tm = &tm_struct; +- errno_t err = localtime_s(tm, &time); ++ errno_t err = localtime_s(tm, &time_); + if (err) + { + *pDOS_date = 0; +@@ -3280,7 +3281,7 @@ static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_u + return; + } + #else +- struct tm *tm = localtime(&time); ++ struct tm *tm = localtime(&time_); + #endif /* #ifdef _MSC_VER */ + + *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); +@@ -3874,7 +3875,10 @@ mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, + /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ + + if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) ++ { ++ MZ_FCLOSE(pFile); + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); ++ } + + if (!mz_zip_reader_init_internal(pZip, flags)) + { +@@ -4134,7 +4138,7 @@ static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_inde + + pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); + pField_data += sizeof(mz_uint64); +- field_data_remaining -= sizeof(mz_uint64); ++ // field_data_remaining -= sizeof(mz_uint64); + } + + break; +@@ -4219,11 +4223,11 @@ static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) + { +- mz_uint32 index; +- if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index)) ++ mz_uint32 index_; ++ if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) + return -1; + else +- return (int)index; ++ return (int)index_; + } + + mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) +@@ -5332,12 +5336,12 @@ mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) + if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) + { + mz_uint32 found_index; +- mz_zip_archive_file_stat stat; ++ mz_zip_archive_file_stat stat_; + +- if (!mz_zip_reader_file_stat(pZip, i, &stat)) ++ if (!mz_zip_reader_file_stat(pZip, i, &stat_)) + return MZ_FALSE; + +- if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index)) ++ if (!mz_zip_reader_locate_file_v2(pZip, stat_.m_filename, NULL, 0, &found_index)) + return MZ_FALSE; + + /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ +@@ -6011,6 +6015,11 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n + mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, + const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) + { ++ if(!pZip) ++ { ++ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++ } ++ + mz_uint16 method = 0, dos_time = 0, dos_date = 0; + mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; +@@ -6035,7 +6044,7 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n + level = level_and_flags & 0xF; + store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + +- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) ++ if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; +@@ -6296,6 +6305,11 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n + mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) + { ++ if(!pZip) ++ { ++ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++ } ++ + mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; + mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; + mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; +@@ -6315,7 +6329,7 @@ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, + level = level_and_flags & 0xF; + + /* Sanity checks */ +- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) ++ if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; +@@ -6828,7 +6842,7 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { +- const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); ++ // const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); + + if (field_data_size < sizeof(mz_uint64) * 2) + { +@@ -6836,8 +6850,8 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + +- local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); +- local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ ++ // local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); ++ // local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ + + found_zip64_ext_data_in_ldir = MZ_TRUE; + break; +@@ -6966,7 +6980,7 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + +- cur_src_file_ofs += n; ++ // cur_src_file_ofs += n; + cur_dst_file_ofs += n; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + +diff --git a/src/zip/miniz/miniz.h b/src/zip/miniz/miniz.h +index 68f903c..e517263 100644 +--- a/src/zip/miniz/miniz.h ++++ b/src/zip/miniz/miniz.h +@@ -203,7 +203,7 @@ mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + + #define MZ_CRC32_INIT (0) + /* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ +-mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); ++// mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + + /* Compression strategies. */ + enum +@@ -301,7 +301,7 @@ typedef struct mz_stream_s + typedef mz_stream *mz_streamp; + + /* Returns the version string of miniz.c. */ +-const char *mz_version(void); ++// const char *mz_version(void); + + /* mz_deflateInit() initializes a compressor with default options: */ + /* Parameters: */ +@@ -324,7 +324,7 @@ int mz_deflateInit(mz_streamp pStream, int level); + int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); + + /* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ +-int mz_deflateReset(mz_streamp pStream); ++// int mz_deflateReset(mz_streamp pStream); + + /* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */ + /* Parameters: */ +@@ -345,7 +345,7 @@ int mz_deflate(mz_streamp pStream, int flush); + int mz_deflateEnd(mz_streamp pStream); + + /* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ +-mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); ++// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + + /* Single-call compression functions mz_compress() and mz_compress2(): */ + /* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ +@@ -353,7 +353,7 @@ int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char * + int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); + + /* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */ +-mz_ulong mz_compressBound(mz_ulong source_len); ++// mz_ulong mz_compressBound(mz_ulong source_len); + + /* Initializes a decompressor. */ + int mz_inflateInit(mz_streamp pStream); +@@ -386,7 +386,7 @@ int mz_inflateEnd(mz_streamp pStream); + int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); + + /* Returns a string description of the specified error code, or NULL if the error code is invalid. */ +-const char *mz_error(int err); ++// const char *mz_error(int err); + + /* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */ + /* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ +@@ -436,13 +436,13 @@ typedef void *const voidpc; + #define z_stream mz_stream + #define deflateInit mz_deflateInit + #define deflateInit2 mz_deflateInit2 +-#define deflateReset mz_deflateReset ++// #define deflateReset mz_deflateReset + #define deflate mz_deflate + #define deflateEnd mz_deflateEnd +-#define deflateBound mz_deflateBound ++// #define deflateBound mz_deflateBound + #define compress mz_compress + #define compress2 mz_compress2 +-#define compressBound mz_compressBound ++// #define compressBound mz_compressBound + #define inflateInit mz_inflateInit + #define inflateInit2 mz_inflateInit2 + #define inflate mz_inflate +@@ -452,15 +452,15 @@ typedef void *const voidpc; + #define adler32 mz_adler32 + #define MAX_WBITS 15 + #define MAX_MEM_LEVEL 9 +-#define zError mz_error ++// #define zError mz_error + #define ZLIB_VERSION MZ_VERSION + #define ZLIB_VERNUM MZ_VERNUM + #define ZLIB_VER_MAJOR MZ_VER_MAJOR + #define ZLIB_VER_MINOR MZ_VER_MINOR + #define ZLIB_VER_REVISION MZ_VER_REVISION + #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION +-#define zlibVersion mz_version +-#define zlib_version mz_version() ++// #define zlibVersion mz_version ++// #define zlib_version mz_version() + #endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ + + #endif /* MINIZ_NO_ZLIB_APIS */ +@@ -501,15 +501,15 @@ typedef int mz_bool; + #define MZ_FILE FILE + #endif /* #ifdef MINIZ_NO_STDIO */ + +-#ifdef MINIZ_NO_TIME +-typedef struct mz_dummy_time_t_tag +-{ +- int m_dummy; +-} mz_dummy_time_t; +-#define MZ_TIME_T mz_dummy_time_t +-#else +-#define MZ_TIME_T time_t +-#endif ++// #ifdef MINIZ_NO_TIME ++// typedef struct mz_dummy_time_t_tag ++// { ++// int m_dummy; ++// } mz_dummy_time_t; ++// #define MZ_TIME_T mz_dummy_time_t ++// #else ++// #define MZ_TIME_T time_t ++// #endif + + #define MZ_ASSERT(x) assert(x) + +@@ -551,7 +551,7 @@ extern "C" { + + extern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); + extern void miniz_def_free_func(void *opaque, void *address); +-extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); ++// extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); + + #define MZ_UINT16_MAX (0xFFFFU) + #define MZ_UINT32_MAX (0xFFFFFFFFU) +@@ -609,11 +609,11 @@ enum + /* Function returns a pointer to the compressed data, or NULL on failure. */ + /* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */ + /* The caller must free() the returned block when it's no longer needed. */ +-void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); ++// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + + /* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ + /* Returns 0 on failure. */ +-size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); ++// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + + /* Compresses an image to a compressed PNG file in memory. */ + /* On entry: */ +@@ -625,14 +625,14 @@ size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void + /* Function returns a pointer to the compressed data, or NULL on failure. */ + /* *pLen_out will be set to the size of the PNG image file. */ + /* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */ +-void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); +-void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); ++// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); ++// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); + + /* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ + typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); + + /* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */ +-mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); ++// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + + enum + { +@@ -727,9 +727,9 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI + + /* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ + /* tdefl_compress_buffer() always consumes the entire input buffer. */ +-tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); ++// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); + +-tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); ++// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); + mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + + /* Create tdefl_compress() flags given zlib-style compression parameters. */ +@@ -741,8 +741,8 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int + /* Allocate the tdefl_compressor structure in C so that */ + /* non-C language bindings to tdefl_ API don't need to worry about */ + /* structure size and allocation mechanism. */ +-tdefl_compressor *tdefl_compressor_alloc(); +-void tdefl_compressor_free(tdefl_compressor *pComp); ++// tdefl_compressor *tdefl_compressor_alloc(); ++// void tdefl_compressor_free(tdefl_compressor *pComp); + + #ifdef __cplusplus + } +@@ -775,17 +775,17 @@ enum + /* Function returns a pointer to the decompressed data, or NULL on failure. */ + /* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */ + /* The caller must call mz_free() on the returned block when it's no longer needed. */ +-void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); ++// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + + /* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ + /* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ + #define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +-size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); ++// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + + /* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */ + /* Returns 1 on success or 0 on failure. */ + typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); +-int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); ++// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + + struct tinfl_decompressor_tag; + typedef struct tinfl_decompressor_tag tinfl_decompressor; +@@ -794,8 +794,8 @@ typedef struct tinfl_decompressor_tag tinfl_decompressor; + /* non-C language bindings to tinfl_ API don't need to worry about */ + /* structure size and allocation mechanism. */ + +-tinfl_decompressor *tinfl_decompressor_alloc(); +-void tinfl_decompressor_free(tinfl_decompressor *pDecomp); ++// tinfl_decompressor *tinfl_decompressor_alloc(); ++// void tinfl_decompressor_free(tinfl_decompressor *pDecomp); + + /* Max size of LZ dictionary. */ + #define TINFL_LZ_DICT_SIZE 32768 +@@ -896,319 +896,319 @@ struct tinfl_decompressor_tag + + /* ------------------- ZIP archive reading/writing */ + +-#ifndef MINIZ_NO_ARCHIVE_APIS ++// #ifndef MINIZ_NO_ARCHIVE_APIS + +-#ifdef __cplusplus +-extern "C" { +-#endif ++// #ifdef __cplusplus ++// extern "C" { ++// #endif + +-enum +-{ ++// enum ++// { + /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ +- MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, +- MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, +- MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 +-}; +- +-typedef struct +-{ +- /* Central directory file index. */ +- mz_uint32 m_file_index; ++// MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, ++// MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, ++// MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 ++// }; ++ ++// typedef struct ++// { ++// /* Central directory file index. */ ++// mz_uint32 m_file_index; ++ ++// /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ ++// mz_uint64 m_central_dir_ofs; ++ ++// /* These fields are copied directly from the zip's central dir. */ ++// mz_uint16 m_version_made_by; ++// mz_uint16 m_version_needed; ++// mz_uint16 m_bit_flag; ++// mz_uint16 m_method; ++ ++// #ifndef MINIZ_NO_TIME ++// MZ_TIME_T m_time; ++// #endif + +- /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ +- mz_uint64 m_central_dir_ofs; ++// /* CRC-32 of uncompressed data. */ ++// mz_uint32 m_crc32; + +- /* These fields are copied directly from the zip's central dir. */ +- mz_uint16 m_version_made_by; +- mz_uint16 m_version_needed; +- mz_uint16 m_bit_flag; +- mz_uint16 m_method; ++// /* File's compressed size. */ ++// mz_uint64 m_comp_size; + +-#ifndef MINIZ_NO_TIME +- MZ_TIME_T m_time; +-#endif ++// /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ ++// mz_uint64 m_uncomp_size; + +- /* CRC-32 of uncompressed data. */ +- mz_uint32 m_crc32; ++// /* Zip internal and external file attributes. */ ++// mz_uint16 m_internal_attr; ++// mz_uint32 m_external_attr; + +- /* File's compressed size. */ +- mz_uint64 m_comp_size; ++// /* Entry's local header file offset in bytes. */ ++// mz_uint64 m_local_header_ofs; + +- /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ +- mz_uint64 m_uncomp_size; ++// /* Size of comment in bytes. */ ++// mz_uint32 m_comment_size; + +- /* Zip internal and external file attributes. */ +- mz_uint16 m_internal_attr; +- mz_uint32 m_external_attr; ++// /* MZ_TRUE if the entry appears to be a directory. */ ++// mz_bool m_is_directory; + +- /* Entry's local header file offset in bytes. */ +- mz_uint64 m_local_header_ofs; ++// /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ ++// mz_bool m_is_encrypted; + +- /* Size of comment in bytes. */ +- mz_uint32 m_comment_size; ++// /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ ++// mz_bool m_is_supported; + +- /* MZ_TRUE if the entry appears to be a directory. */ +- mz_bool m_is_directory; ++// /* Filename. If string ends in '/' it's a subdirectory entry. */ ++// /* Guaranteed to be zero terminated, may be truncated to fit. */ ++// char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + +- /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ +- mz_bool m_is_encrypted; ++// /* Comment field. */ ++// /* Guaranteed to be zero terminated, may be truncated to fit. */ ++// char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; + +- /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ +- mz_bool m_is_supported; ++// } mz_zip_archive_file_stat; + +- /* Filename. If string ends in '/' it's a subdirectory entry. */ +- /* Guaranteed to be zero terminated, may be truncated to fit. */ +- char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; ++// typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); ++// typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); ++// typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); + +- /* Comment field. */ +- /* Guaranteed to be zero terminated, may be truncated to fit. */ +- char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; ++// struct mz_zip_internal_state_tag; ++// typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + +-} mz_zip_archive_file_stat; ++// typedef enum { ++// MZ_ZIP_MODE_INVALID = 0, ++// MZ_ZIP_MODE_READING = 1, ++// MZ_ZIP_MODE_WRITING = 2, ++// MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 ++// } mz_zip_mode; + +-typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); +-typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); +-typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); ++// typedef enum { ++// MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, ++// MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, ++// MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, ++// MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, ++ // MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ ++ // MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ ++ // MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ ++// MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, ++// MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 ++// } mz_zip_flags; + +-struct mz_zip_internal_state_tag; +-typedef struct mz_zip_internal_state_tag mz_zip_internal_state; +- +-typedef enum { +- MZ_ZIP_MODE_INVALID = 0, +- MZ_ZIP_MODE_READING = 1, +- MZ_ZIP_MODE_WRITING = 2, +- MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 +-} mz_zip_mode; +- +-typedef enum { +- MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, +- MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, +- MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, +- MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, +- MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ +- MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ +- MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ +- MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, +- MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 +-} mz_zip_flags; +- +-typedef enum { +- MZ_ZIP_TYPE_INVALID = 0, +- MZ_ZIP_TYPE_USER, +- MZ_ZIP_TYPE_MEMORY, +- MZ_ZIP_TYPE_HEAP, +- MZ_ZIP_TYPE_FILE, +- MZ_ZIP_TYPE_CFILE, +- MZ_ZIP_TOTAL_TYPES +-} mz_zip_type; ++// typedef enum { ++// MZ_ZIP_TYPE_INVALID = 0, ++// MZ_ZIP_TYPE_USER, ++// MZ_ZIP_TYPE_MEMORY, ++// MZ_ZIP_TYPE_HEAP, ++// MZ_ZIP_TYPE_FILE, ++// MZ_ZIP_TYPE_CFILE, ++// MZ_ZIP_TOTAL_TYPES ++// } mz_zip_type; + + /* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ +-typedef enum { +- MZ_ZIP_NO_ERROR = 0, +- MZ_ZIP_UNDEFINED_ERROR, +- MZ_ZIP_TOO_MANY_FILES, +- MZ_ZIP_FILE_TOO_LARGE, +- MZ_ZIP_UNSUPPORTED_METHOD, +- MZ_ZIP_UNSUPPORTED_ENCRYPTION, +- MZ_ZIP_UNSUPPORTED_FEATURE, +- MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, +- MZ_ZIP_NOT_AN_ARCHIVE, +- MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, +- MZ_ZIP_UNSUPPORTED_MULTIDISK, +- MZ_ZIP_DECOMPRESSION_FAILED, +- MZ_ZIP_COMPRESSION_FAILED, +- MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, +- MZ_ZIP_CRC_CHECK_FAILED, +- MZ_ZIP_UNSUPPORTED_CDIR_SIZE, +- MZ_ZIP_ALLOC_FAILED, +- MZ_ZIP_FILE_OPEN_FAILED, +- MZ_ZIP_FILE_CREATE_FAILED, +- MZ_ZIP_FILE_WRITE_FAILED, +- MZ_ZIP_FILE_READ_FAILED, +- MZ_ZIP_FILE_CLOSE_FAILED, +- MZ_ZIP_FILE_SEEK_FAILED, +- MZ_ZIP_FILE_STAT_FAILED, +- MZ_ZIP_INVALID_PARAMETER, +- MZ_ZIP_INVALID_FILENAME, +- MZ_ZIP_BUF_TOO_SMALL, +- MZ_ZIP_INTERNAL_ERROR, +- MZ_ZIP_FILE_NOT_FOUND, +- MZ_ZIP_ARCHIVE_TOO_LARGE, +- MZ_ZIP_VALIDATION_FAILED, +- MZ_ZIP_WRITE_CALLBACK_FAILED, +- MZ_ZIP_TOTAL_ERRORS +-} mz_zip_error; +- +-typedef struct +-{ +- mz_uint64 m_archive_size; +- mz_uint64 m_central_directory_file_ofs; +- +- /* We only support up to UINT32_MAX files in zip64 mode. */ +- mz_uint32 m_total_files; +- mz_zip_mode m_zip_mode; +- mz_zip_type m_zip_type; +- mz_zip_error m_last_error; +- +- mz_uint64 m_file_offset_alignment; +- +- mz_alloc_func m_pAlloc; +- mz_free_func m_pFree; +- mz_realloc_func m_pRealloc; +- void *m_pAlloc_opaque; +- +- mz_file_read_func m_pRead; +- mz_file_write_func m_pWrite; +- mz_file_needs_keepalive m_pNeeds_keepalive; +- void *m_pIO_opaque; +- +- mz_zip_internal_state *m_pState; +- +-} mz_zip_archive; +- +-typedef struct +-{ +- mz_zip_archive *pZip; +- mz_uint flags; +- +- int status; +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- mz_uint file_crc32; +-#endif +- mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; +- mz_zip_archive_file_stat file_stat; +- void *pRead_buf; +- void *pWrite_buf; ++// typedef enum { ++// MZ_ZIP_NO_ERROR = 0, ++// MZ_ZIP_UNDEFINED_ERROR, ++// MZ_ZIP_TOO_MANY_FILES, ++// MZ_ZIP_FILE_TOO_LARGE, ++// MZ_ZIP_UNSUPPORTED_METHOD, ++// MZ_ZIP_UNSUPPORTED_ENCRYPTION, ++// MZ_ZIP_UNSUPPORTED_FEATURE, ++// MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, ++// MZ_ZIP_NOT_AN_ARCHIVE, ++// MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, ++// MZ_ZIP_UNSUPPORTED_MULTIDISK, ++// MZ_ZIP_DECOMPRESSION_FAILED, ++// MZ_ZIP_COMPRESSION_FAILED, ++// MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, ++// MZ_ZIP_CRC_CHECK_FAILED, ++// MZ_ZIP_UNSUPPORTED_CDIR_SIZE, ++// MZ_ZIP_ALLOC_FAILED, ++// MZ_ZIP_FILE_OPEN_FAILED, ++// MZ_ZIP_FILE_CREATE_FAILED, ++// MZ_ZIP_FILE_WRITE_FAILED, ++// MZ_ZIP_FILE_READ_FAILED, ++// MZ_ZIP_FILE_CLOSE_FAILED, ++// MZ_ZIP_FILE_SEEK_FAILED, ++// MZ_ZIP_FILE_STAT_FAILED, ++// MZ_ZIP_INVALID_PARAMETER, ++// MZ_ZIP_INVALID_FILENAME, ++// MZ_ZIP_BUF_TOO_SMALL, ++// MZ_ZIP_INTERNAL_ERROR, ++// MZ_ZIP_FILE_NOT_FOUND, ++// MZ_ZIP_ARCHIVE_TOO_LARGE, ++// MZ_ZIP_VALIDATION_FAILED, ++// MZ_ZIP_WRITE_CALLBACK_FAILED, ++// MZ_ZIP_TOTAL_ERRORS ++// } mz_zip_error; ++ ++// typedef struct ++// { ++// mz_uint64 m_archive_size; ++// mz_uint64 m_central_directory_file_ofs; ++ ++// /* We only support up to UINT32_MAX files in zip64 mode. */ ++// mz_uint32 m_total_files; ++// mz_zip_mode m_zip_mode; ++// mz_zip_type m_zip_type; ++// mz_zip_error m_last_error; ++ ++// mz_uint64 m_file_offset_alignment; ++ ++// mz_alloc_func m_pAlloc; ++// mz_free_func m_pFree; ++// mz_realloc_func m_pRealloc; ++// void *m_pAlloc_opaque; ++ ++// mz_file_read_func m_pRead; ++// mz_file_write_func m_pWrite; ++// mz_file_needs_keepalive m_pNeeds_keepalive; ++// void *m_pIO_opaque; ++ ++// mz_zip_internal_state *m_pState; ++ ++// } mz_zip_archive; ++ ++// typedef struct ++// { ++// mz_zip_archive *pZip; ++// mz_uint flags; ++ ++// int status; ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// mz_uint file_crc32; ++// #endif ++// mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; ++// mz_zip_archive_file_stat file_stat; ++// void *pRead_buf; ++// void *pWrite_buf; + +- size_t out_blk_remain; ++// size_t out_blk_remain; + +- tinfl_decompressor inflator; ++// tinfl_decompressor inflator; + +-} mz_zip_reader_extract_iter_state; ++// } mz_zip_reader_extract_iter_state; + + /* -------- ZIP reading */ + + /* Inits a ZIP archive reader. */ + /* These functions read and validate the archive's central directory. */ +-mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); ++// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); + +-mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); ++// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); + +-#ifndef MINIZ_NO_STDIO ++// #ifndef MINIZ_NO_STDIO + /* Read a archive from a disk file. */ + /* file_start_ofs is the file offset where the archive actually begins, or 0. */ + /* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */ +-mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); +-mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); ++// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); ++// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); + + /* Read an archive from an already opened FILE, beginning at the current file position. */ + /* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */ + /* The FILE will NOT be closed when mz_zip_reader_end() is called. */ +-mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); +-#endif ++// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); ++// #endif + + /* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */ +-mz_bool mz_zip_reader_end(mz_zip_archive *pZip); ++// mz_bool mz_zip_reader_end(mz_zip_archive *pZip); + + /* -------- ZIP reading or writing */ + + /* Clears a mz_zip_archive struct to all zeros. */ + /* Important: This must be done before passing the struct to any mz_zip functions. */ +-void mz_zip_zero_struct(mz_zip_archive *pZip); ++// void mz_zip_zero_struct(mz_zip_archive *pZip); + +-mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); +-mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); ++// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); ++// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); + + /* Returns the total number of files in the archive. */ +-mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); ++// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); + +-mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); +-mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); +-MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); ++// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); ++// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); ++// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); + + /* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ +-size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); ++// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); + + /* Attempts to locates a file in the archive's central directory. */ + /* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ + /* Returns -1 if the file cannot be found. */ +-int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); ++// int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + /* Returns MZ_FALSE if the file cannot be found. */ +-mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex); ++// mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex); + + /* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */ + /* Note that the m_last_error functionality is not thread safe. */ +-mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); +-mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); +-mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); +-mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); +-const char *mz_zip_get_error_string(mz_zip_error mz_err); ++// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); ++// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); ++// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); ++// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); ++// const char *mz_zip_get_error_string(mz_zip_error mz_err); + + /* MZ_TRUE if the archive file entry is a directory entry. */ +-mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); ++// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); + + /* MZ_TRUE if the file is encrypted/strong encrypted. */ +-mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); ++// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); + + /* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */ +-mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); ++// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); + + /* Retrieves the filename of an archive file entry. */ + /* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */ +-mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); ++// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); + + /* Attempts to locates a file in the archive's central directory. */ + /* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ + /* Returns -1 if the file cannot be found. */ +-int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); +-int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); ++// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); ++// int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); + + /* Returns detailed information about an archive file entry. */ +-mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); ++// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); + + /* MZ_TRUE if the file is in zip64 format. */ + /* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */ +-mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); ++// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); + + /* Returns the total central directory size in bytes. */ + /* The current max supported size is <= MZ_UINT32_MAX. */ +-size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); ++// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); + + /* Extracts a archive file to a memory buffer using no memory allocation. */ + /* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ +-mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); +-mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); ++// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); ++// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + + /* Extracts a archive file to a memory buffer. */ +-mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); +-mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); ++// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); ++// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); + + /* Extracts a archive file to a dynamically allocated heap buffer. */ + /* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ + /* Returns NULL and sets the last error on failure. */ +-void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); +-void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); ++// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); ++// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); + + /* Extracts a archive file using a callback function to output the file's data. */ +-mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); +-mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); ++// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); ++// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); + + /* Extract a file iteratively */ +-mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); +-mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); +-size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); +-mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); ++// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); ++// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); ++// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); ++// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); + +-#ifndef MINIZ_NO_STDIO ++// #ifndef MINIZ_NO_STDIO + /* Extracts a archive file to a disk file and sets its last accessed and modified times. */ + /* This function only extracts files, not archive directory records. */ +-mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); +-mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); ++// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); ++// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); + + /* Extracts a archive file starting at the current position in the destination FILE stream. */ +-mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); +-mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); +-#endif ++// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); ++// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); ++// #endif + + #if 0 + /* TODO */ +@@ -1233,26 +1233,26 @@ mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pA + // mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); + + /* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ +-mz_bool mz_zip_end(mz_zip_archive *pZip); ++// mz_bool mz_zip_end(mz_zip_archive *pZip); + + /* -------- ZIP writing */ + +-#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS ++// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + + /* Inits a ZIP archive writer. */ + /*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ + /*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ +-mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); +-mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); ++// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); ++// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); + +-mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); +-mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); ++// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); ++// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); + +-#ifndef MINIZ_NO_STDIO +-mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); +-mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); +-mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); +-#endif ++// #ifndef MINIZ_NO_STDIO ++// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); ++// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); ++// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); ++// #endif + + /* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */ + /* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ +@@ -1260,33 +1260,33 @@ mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint f + /* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */ + /* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */ + /* the archive is finalized the file's central directory will be hosed. */ +-mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); +-mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); ++// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); ++// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); + + /* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */ + /* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ + /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +-mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); ++// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); + + /* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */ + /* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ +-mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +- mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); ++// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, ++// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); + +-mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +- mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, +- const char *user_extra_data_central, mz_uint user_extra_data_central_len); ++// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, ++// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, ++// const char *user_extra_data_central, mz_uint user_extra_data_central_len); + +-#ifndef MINIZ_NO_STDIO ++// #ifndef MINIZ_NO_STDIO + /* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */ + /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +-mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); ++// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + + /* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ +-mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, +- const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, +- const char *user_extra_data_central, mz_uint user_extra_data_central_len); +-#endif ++// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, ++// const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, ++// const char *user_extra_data_central, mz_uint user_extra_data_central_len); ++// #endif + + /* Adds a file to an archive by fully cloning the data from another archive. */ + /* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */ +@@ -1295,15 +1295,15 @@ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, + /* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ + /* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ + /* An archive must be manually finalized by calling this function for it to be valid. */ +-mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); ++// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); + + /* Finalizes a heap archive, returning a poiner to the heap block and its size. */ + /* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ +-mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); ++// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); + + /* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ + /* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */ +-mz_bool mz_zip_writer_end(mz_zip_archive *pZip); ++// mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + + /* -------- Misc. high-level helper functions: */ + +@@ -1311,19 +1311,19 @@ mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + /* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */ + /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ + /* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */ +-mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +-mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); ++// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); ++// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); + + /* Reads a single file from an archive into a heap block. */ + /* If pComment is not NULL, only the file with the specified comment will be extracted. */ + /* Returns NULL on failure. */ +-void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); +-void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); ++// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); ++// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); + +-#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ ++// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + +-#ifdef __cplusplus +-} +-#endif ++// #ifdef __cplusplus ++// } ++// #endif + +-#endif /* MINIZ_NO_ARCHIVE_APIS */ ++// #endif /* MINIZ_NO_ARCHIVE_APIS */ + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + +diff --git a/src/zip/miniz/miniz.c b/src/zip/miniz/miniz.c +index 9ee7635..910d4b1 100644 +--- a/src/zip/miniz/miniz.c ++++ b/src/zip/miniz/miniz.c +@@ -65,92 +65,92 @@ mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) + } + + /* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */ +-#if 0 +- mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +- { +- static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, +- 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; +- mz_uint32 crcu32 = (mz_uint32)crc; +- if (!ptr) +- return MZ_CRC32_INIT; +- crcu32 = ~crcu32; +- while (buf_len--) +- { +- mz_uint8 b = *ptr++; +- crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; +- crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; +- } +- return ~crcu32; +- } +-#else ++// #if 0 ++// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) ++// { ++// static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, ++// 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; ++// mz_uint32 crcu32 = (mz_uint32)crc; ++// if (!ptr) ++// return MZ_CRC32_INIT; ++// crcu32 = ~crcu32; ++// while (buf_len--) ++// { ++// mz_uint8 b = *ptr++; ++// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; ++// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; ++// } ++// return ~crcu32; ++// } ++// #else + /* Faster, but larger CPU cache footprint. + */ +-mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +-{ +- static const mz_uint32 s_crc_table[256] = +- { +- 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, +- 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, +- 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, +- 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, +- 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, +- 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, +- 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, +- 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, +- 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, +- 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, +- 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, +- 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, +- 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, +- 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, +- 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, +- 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, +- 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, +- 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, +- 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, +- 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, +- 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, +- 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, +- 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, +- 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, +- 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, +- 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, +- 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, +- 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, +- 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, +- 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, +- 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, +- 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, +- 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, +- 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, +- 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, +- 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, +- 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +- }; +- +- mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; +- const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; +- +- while (buf_len >= 4) +- { +- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; +- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; +- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; +- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; +- pByte_buf += 4; +- buf_len -= 4; +- } ++// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) ++// { ++// static const mz_uint32 s_crc_table[256] = ++// { ++// 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, ++// 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, ++// 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, ++// 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, ++// 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, ++// 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, ++// 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, ++// 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, ++// 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, ++// 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, ++// 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, ++// 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, ++// 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, ++// 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, ++// 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, ++// 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, ++// 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, ++// 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, ++// 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, ++// 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, ++// 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, ++// 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, ++// 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, ++// 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, ++// 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, ++// 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, ++// 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, ++// 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, ++// 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, ++// 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, ++// 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, ++// 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, ++// 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, ++// 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, ++// 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, ++// 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, ++// 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D ++// }; ++ ++// mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; ++// const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; ++ ++// while (buf_len >= 4) ++// { ++// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; ++// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; ++// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; ++// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; ++// pByte_buf += 4; ++// buf_len -= 4; ++// } + +- while (buf_len) +- { +- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; +- ++pByte_buf; +- --buf_len; +- } ++// while (buf_len) ++// { ++// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; ++// ++pByte_buf; ++// --buf_len; ++// } + +- return ~crc32; +-} +-#endif ++// return ~crc32; ++// } ++// #endif + + void mz_free(void *p) + { +@@ -167,16 +167,16 @@ void miniz_def_free_func(void *opaque, void *address) + (void)opaque, (void)address; + MZ_FREE(address); + } +-void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) +-{ +- (void)opaque, (void)address, (void)items, (void)size; +- return MZ_REALLOC(address, items * size); +-} ++// void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) ++// { ++// (void)opaque, (void)address, (void)items, (void)size; ++// return MZ_REALLOC(address, items * size); ++// } + +-const char *mz_version(void) +-{ +- return MZ_VERSION; +-} ++// const char *mz_version(void) ++// { ++// return MZ_VERSION; ++// } + + #ifndef MINIZ_NO_ZLIB_APIS + +@@ -221,14 +221,14 @@ int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, + return MZ_OK; + } + +-int mz_deflateReset(mz_streamp pStream) +-{ +- if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) +- return MZ_STREAM_ERROR; +- pStream->total_in = pStream->total_out = 0; +- tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); +- return MZ_OK; +-} ++// int mz_deflateReset(mz_streamp pStream) ++// { ++// if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) ++// return MZ_STREAM_ERROR; ++// pStream->total_in = pStream->total_out = 0; ++// tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); ++// return MZ_OK; ++// } + + int mz_deflate(mz_streamp pStream, int flush) + { +@@ -300,12 +300,12 @@ int mz_deflateEnd(mz_streamp pStream) + return MZ_OK; + } + +-mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) +-{ +- (void)pStream; +- /* This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) */ +- return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); +-} ++// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) ++// { ++// (void)pStream; ++// This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) ++// return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); ++// } + + int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) + { +@@ -342,10 +342,10 @@ int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char * + return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); + } + +-mz_ulong mz_compressBound(mz_ulong source_len) +-{ +- return mz_deflateBound(NULL, source_len); +-} ++// mz_ulong mz_compressBound(mz_ulong source_len) ++// { ++// return mz_deflateBound(NULL, source_len); ++// } + + typedef struct + { +@@ -551,22 +551,22 @@ int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char + return mz_inflateEnd(&stream); + } + +-const char *mz_error(int err) +-{ +- static struct +- { +- int m_err; +- const char *m_pDesc; +- } s_error_descs[] = +- { +- { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } +- }; +- mz_uint i; +- for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) +- if (s_error_descs[i].m_err == err) +- return s_error_descs[i].m_pDesc; +- return NULL; +-} ++// const char *mz_error(int err) ++// { ++// static struct ++// { ++// int m_err; ++// const char *m_pDesc; ++// } s_error_descs[] = ++// { ++// { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } ++// }; ++// mz_uint i; ++// for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) ++// if (s_error_descs[i].m_err == err) ++// return s_error_descs[i].m_pDesc; ++// return NULL; ++// } + + #endif /*MINIZ_NO_ZLIB_APIS */ + +@@ -1049,7 +1049,7 @@ static void tdefl_start_static_block(tdefl_compressor *d) + TDEFL_PUT_BITS(1, 2); + } + +-static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; ++static const mz_uint16 mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + + #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS + static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +@@ -1358,7 +1358,6 @@ static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p) + #endif + static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) + { +- printf("\n--------------------------------------------------- DEBUG ---------------------------------------\n"); + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; +@@ -1456,176 +1455,176 @@ static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahe + } + #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ + +-#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +-static mz_bool tdefl_compress_fast(tdefl_compressor *d) +-{ +- /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ +- mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; +- mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; +- mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; ++// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN ++// static mz_bool tdefl_compress_fast(tdefl_compressor *d) ++// { ++// /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ ++// mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; ++// mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; ++// mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + +- while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) +- { +- const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; +- mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; +- mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); +- d->m_src_buf_left -= num_bytes_to_process; +- lookahead_size += num_bytes_to_process; ++// while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) ++// { ++// const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; ++// mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; ++// mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); ++// d->m_src_buf_left -= num_bytes_to_process; ++// lookahead_size += num_bytes_to_process; + +- while (num_bytes_to_process) +- { +- mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); +- memcpy(d->m_dict + dst_pos, d->m_pSrc, n); +- if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) +- memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); +- d->m_pSrc += n; +- dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; +- num_bytes_to_process -= n; +- } ++// while (num_bytes_to_process) ++// { ++// mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); ++// memcpy(d->m_dict + dst_pos, d->m_pSrc, n); ++// if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) ++// memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); ++// d->m_pSrc += n; ++// dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; ++// num_bytes_to_process -= n; ++// } + +- dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); +- if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) +- break; ++// dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); ++// if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) ++// break; + +- while (lookahead_size >= 4) +- { +- mz_uint cur_match_dist, cur_match_len = 1; +- mz_uint8 *pCur_dict = d->m_dict + cur_pos; +- mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; +- mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; +- mz_uint probe_pos = d->m_hash[hash]; +- d->m_hash[hash] = (mz_uint16)lookahead_pos; +- +- if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) +- { +- const mz_uint16 *p = (const mz_uint16 *)pCur_dict; +- const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); +- mz_uint32 probe_len = 32; +- do +- { +- } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && +- (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); +- cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); +- if (!probe_len) +- cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; ++// while (lookahead_size >= 4) ++// { ++// mz_uint cur_match_dist, cur_match_len = 1; ++// mz_uint8 *pCur_dict = d->m_dict + cur_pos; ++// mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; ++// mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; ++// mz_uint probe_pos = d->m_hash[hash]; ++// d->m_hash[hash] = (mz_uint16)lookahead_pos; ++ ++// if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) ++// { ++// const mz_uint16 *p = (const mz_uint16 *)pCur_dict; ++// const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); ++// mz_uint32 probe_len = 32; ++// do ++// { ++// } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && ++// (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); ++// cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); ++// if (!probe_len) ++// cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + +- if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) +- { +- cur_match_len = 1; +- *pLZ_code_buf++ = (mz_uint8)first_trigram; +- *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); +- d->m_huff_count[0][(mz_uint8)first_trigram]++; +- } +- else +- { +- mz_uint32 s0, s1; +- cur_match_len = MZ_MIN(cur_match_len, lookahead_size); ++// if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) ++// { ++// cur_match_len = 1; ++// *pLZ_code_buf++ = (mz_uint8)first_trigram; ++// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); ++// d->m_huff_count[0][(mz_uint8)first_trigram]++; ++// } ++// else ++// { ++// mz_uint32 s0, s1; ++// cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + +- MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); ++// MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + +- cur_match_dist--; ++// cur_match_dist--; + +- pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); +- *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; +- pLZ_code_buf += 3; +- *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); ++// pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); ++// *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; ++// pLZ_code_buf += 3; ++// *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + +- s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; +- s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; +- d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; ++// s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; ++// s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; ++// d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + +- d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; +- } +- } +- else +- { +- *pLZ_code_buf++ = (mz_uint8)first_trigram; +- *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); +- d->m_huff_count[0][(mz_uint8)first_trigram]++; +- } ++// d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; ++// } ++// } ++// else ++// { ++// *pLZ_code_buf++ = (mz_uint8)first_trigram; ++// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); ++// d->m_huff_count[0][(mz_uint8)first_trigram]++; ++// } + +- if (--num_flags_left == 0) +- { +- num_flags_left = 8; +- pLZ_flags = pLZ_code_buf++; +- } ++// if (--num_flags_left == 0) ++// { ++// num_flags_left = 8; ++// pLZ_flags = pLZ_code_buf++; ++// } + +- total_lz_bytes += cur_match_len; +- lookahead_pos += cur_match_len; +- dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); +- cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; +- MZ_ASSERT(lookahead_size >= cur_match_len); +- lookahead_size -= cur_match_len; ++// total_lz_bytes += cur_match_len; ++// lookahead_pos += cur_match_len; ++// dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); ++// cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; ++// MZ_ASSERT(lookahead_size >= cur_match_len); ++// lookahead_size -= cur_match_len; + +- if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) +- { +- int n; +- d->m_lookahead_pos = lookahead_pos; +- d->m_lookahead_size = lookahead_size; +- d->m_dict_size = dict_size; +- d->m_total_lz_bytes = total_lz_bytes; +- d->m_pLZ_code_buf = pLZ_code_buf; +- d->m_pLZ_flags = pLZ_flags; +- d->m_num_flags_left = num_flags_left; +- if ((n = tdefl_flush_block(d, 0)) != 0) +- return (n < 0) ? MZ_FALSE : MZ_TRUE; +- total_lz_bytes = d->m_total_lz_bytes; +- pLZ_code_buf = d->m_pLZ_code_buf; +- pLZ_flags = d->m_pLZ_flags; +- num_flags_left = d->m_num_flags_left; +- } +- } ++// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ++// { ++// int n; ++// d->m_lookahead_pos = lookahead_pos; ++// d->m_lookahead_size = lookahead_size; ++// d->m_dict_size = dict_size; ++// d->m_total_lz_bytes = total_lz_bytes; ++// d->m_pLZ_code_buf = pLZ_code_buf; ++// d->m_pLZ_flags = pLZ_flags; ++// d->m_num_flags_left = num_flags_left; ++// if ((n = tdefl_flush_block(d, 0)) != 0) ++// return (n < 0) ? MZ_FALSE : MZ_TRUE; ++// total_lz_bytes = d->m_total_lz_bytes; ++// pLZ_code_buf = d->m_pLZ_code_buf; ++// pLZ_flags = d->m_pLZ_flags; ++// num_flags_left = d->m_num_flags_left; ++// } ++// } + +- while (lookahead_size) +- { +- mz_uint8 lit = d->m_dict[cur_pos]; ++// while (lookahead_size) ++// { ++// mz_uint8 lit = d->m_dict[cur_pos]; + +- total_lz_bytes++; +- *pLZ_code_buf++ = lit; +- *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); +- if (--num_flags_left == 0) +- { +- num_flags_left = 8; +- pLZ_flags = pLZ_code_buf++; +- } ++// total_lz_bytes++; ++// *pLZ_code_buf++ = lit; ++// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); ++// if (--num_flags_left == 0) ++// { ++// num_flags_left = 8; ++// pLZ_flags = pLZ_code_buf++; ++// } + +- d->m_huff_count[0][lit]++; ++// d->m_huff_count[0][lit]++; + +- lookahead_pos++; +- dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); +- cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; +- lookahead_size--; ++// lookahead_pos++; ++// dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); ++// cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ++// lookahead_size--; + +- if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) +- { +- int n; +- d->m_lookahead_pos = lookahead_pos; +- d->m_lookahead_size = lookahead_size; +- d->m_dict_size = dict_size; +- d->m_total_lz_bytes = total_lz_bytes; +- d->m_pLZ_code_buf = pLZ_code_buf; +- d->m_pLZ_flags = pLZ_flags; +- d->m_num_flags_left = num_flags_left; +- if ((n = tdefl_flush_block(d, 0)) != 0) +- return (n < 0) ? MZ_FALSE : MZ_TRUE; +- total_lz_bytes = d->m_total_lz_bytes; +- pLZ_code_buf = d->m_pLZ_code_buf; +- pLZ_flags = d->m_pLZ_flags; +- num_flags_left = d->m_num_flags_left; +- } +- } +- } ++// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ++// { ++// int n; ++// d->m_lookahead_pos = lookahead_pos; ++// d->m_lookahead_size = lookahead_size; ++// d->m_dict_size = dict_size; ++// d->m_total_lz_bytes = total_lz_bytes; ++// d->m_pLZ_code_buf = pLZ_code_buf; ++// d->m_pLZ_flags = pLZ_flags; ++// d->m_num_flags_left = num_flags_left; ++// if ((n = tdefl_flush_block(d, 0)) != 0) ++// return (n < 0) ? MZ_FALSE : MZ_TRUE; ++// total_lz_bytes = d->m_total_lz_bytes; ++// pLZ_code_buf = d->m_pLZ_code_buf; ++// pLZ_flags = d->m_pLZ_flags; ++// num_flags_left = d->m_num_flags_left; ++// } ++// } ++// } + +- d->m_lookahead_pos = lookahead_pos; +- d->m_lookahead_size = lookahead_size; +- d->m_dict_size = dict_size; +- d->m_total_lz_bytes = total_lz_bytes; +- d->m_pLZ_code_buf = pLZ_code_buf; +- d->m_pLZ_flags = pLZ_flags; +- d->m_num_flags_left = num_flags_left; +- return MZ_TRUE; +-} +-#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ ++// d->m_lookahead_pos = lookahead_pos; ++// d->m_lookahead_size = lookahead_size; ++// d->m_dict_size = dict_size; ++// d->m_total_lz_bytes = total_lz_bytes; ++// d->m_pLZ_code_buf = pLZ_code_buf; ++// d->m_pLZ_flags = pLZ_flags; ++// d->m_num_flags_left = num_flags_left; ++// return MZ_TRUE; ++// } ++// #endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + + static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) + { +@@ -1870,16 +1869,16 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +-#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +- if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && +- ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && +- ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) +- { +- if (!tdefl_compress_fast(d)) +- return d->m_prev_return_status; +- } +- else +-#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ ++// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN ++// if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && ++// ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && ++// ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) ++// { ++// if (!tdefl_compress_fast(d)) ++// return d->m_prev_return_status; ++// } ++// else ++// #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + { + if (!tdefl_compress_normal(d)) + return d->m_prev_return_status; +@@ -1904,11 +1903,11 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + } + +-tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) +-{ +- MZ_ASSERT(d->m_pPut_buf_func); +- return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +-} ++// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) ++// { ++// MZ_ASSERT(d->m_pPut_buf_func); ++// return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); ++// } + + tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) + { +@@ -1944,92 +1943,92 @@ tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_fun + return TDEFL_STATUS_OKAY; + } + +-tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) +-{ +- return d->m_prev_return_status; +-} ++// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) ++// { ++// return d->m_prev_return_status; ++// } + + mz_uint32 tdefl_get_adler32(tdefl_compressor *d) + { + return d->m_adler32; + } + +-mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +-{ +- tdefl_compressor *pComp; +- mz_bool succeeded; +- if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) +- return MZ_FALSE; +- pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +- if (!pComp) +- return MZ_FALSE; +- succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); +- succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); +- MZ_FREE(pComp); +- return succeeded; +-} ++// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) ++// { ++// tdefl_compressor *pComp; ++// mz_bool succeeded; ++// if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) ++// return MZ_FALSE; ++// pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); ++// if (!pComp) ++// return MZ_FALSE; ++// succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); ++// succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); ++// MZ_FREE(pComp); ++// return succeeded; ++// } + +-typedef struct +-{ +- size_t m_size, m_capacity; +- mz_uint8 *m_pBuf; +- mz_bool m_expandable; +-} tdefl_output_buffer; ++// typedef struct ++// { ++// size_t m_size, m_capacity; ++// mz_uint8 *m_pBuf; ++// mz_bool m_expandable; ++// } tdefl_output_buffer; + +-static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) +-{ +- tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; +- size_t new_size = p->m_size + len; +- if (new_size > p->m_capacity) +- { +- size_t new_capacity = p->m_capacity; +- mz_uint8 *pNew_buf; +- if (!p->m_expandable) +- return MZ_FALSE; +- do +- { +- new_capacity = MZ_MAX(128U, new_capacity << 1U); +- } while (new_size > new_capacity); +- pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); +- if (!pNew_buf) +- return MZ_FALSE; +- p->m_pBuf = pNew_buf; +- p->m_capacity = new_capacity; +- } +- memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); +- p->m_size = new_size; +- return MZ_TRUE; +-} ++// static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) ++// { ++// tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; ++// size_t new_size = p->m_size + len; ++// if (new_size > p->m_capacity) ++// { ++// size_t new_capacity = p->m_capacity; ++// mz_uint8 *pNew_buf; ++// if (!p->m_expandable) ++// return MZ_FALSE; ++// do ++// { ++// new_capacity = MZ_MAX(128U, new_capacity << 1U); ++// } while (new_size > new_capacity); ++// pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); ++// if (!pNew_buf) ++// return MZ_FALSE; ++// p->m_pBuf = pNew_buf; ++// p->m_capacity = new_capacity; ++// } ++// memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); ++// p->m_size = new_size; ++// return MZ_TRUE; ++// } + +-void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +-{ +- tdefl_output_buffer out_buf; +- MZ_CLEAR_OBJ(out_buf); +- if (!pOut_len) +- return MZ_FALSE; +- else +- *pOut_len = 0; +- out_buf.m_expandable = MZ_TRUE; +- if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) +- return NULL; +- *pOut_len = out_buf.m_size; +- return out_buf.m_pBuf; +-} ++// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) ++// { ++// tdefl_output_buffer out_buf; ++// MZ_CLEAR_OBJ(out_buf); ++// if (!pOut_len) ++// return MZ_FALSE; ++// else ++// *pOut_len = 0; ++// out_buf.m_expandable = MZ_TRUE; ++// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) ++// return NULL; ++// *pOut_len = out_buf.m_size; ++// return out_buf.m_pBuf; ++// } + +-size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +-{ +- tdefl_output_buffer out_buf; +- MZ_CLEAR_OBJ(out_buf); +- if (!pOut_buf) +- return 0; +- out_buf.m_pBuf = (mz_uint8 *)pOut_buf; +- out_buf.m_capacity = out_buf_len; +- if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) +- return 0; +- return out_buf.m_size; +-} ++// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) ++// { ++// tdefl_output_buffer out_buf; ++// MZ_CLEAR_OBJ(out_buf); ++// if (!pOut_buf) ++// return 0; ++// out_buf.m_pBuf = (mz_uint8 *)pOut_buf; ++// out_buf.m_capacity = out_buf_len; ++// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) ++// return 0; ++// return out_buf.m_size; ++// } + +-static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; ++static const mz_uint16 s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + + /* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */ + mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) +@@ -2060,102 +2059,102 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int + /* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at + http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. + This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ +-void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) +-{ +- /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ +- static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; +- tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +- tdefl_output_buffer out_buf; +- int i, bpl = w * num_chans, y, z; +- mz_uint32 c; +- *pLen_out = 0; +- if (!pComp) +- return NULL; +- MZ_CLEAR_OBJ(out_buf); +- out_buf.m_expandable = MZ_TRUE; +- out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); +- if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) +- { +- MZ_FREE(pComp); +- return NULL; +- } +- /* write dummy header */ +- for (z = 41; z; --z) +- tdefl_output_buffer_putter(&z, 1, &out_buf); +- /* compress image data */ +- tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); +- for (y = 0; y < h; ++y) +- { +- tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); +- tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); +- } +- if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) +- { +- MZ_FREE(pComp); +- MZ_FREE(out_buf.m_pBuf); +- return NULL; +- } +- /* write real header */ +- *pLen_out = out_buf.m_size - 41; +- { +- static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; +- mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, +- 0x0a, 0x1a, 0x0a, 0x00, 0x00, +- 0x00, 0x0d, 0x49, 0x48, 0x44, +- 0x52, 0x00, 0x00, 0x00, 0x00, +- 0x00, 0x00, 0x00, 0x00, 0x08, +- 0x00, 0x00, 0x00, 0x00, 0x00, +- 0x00, 0x00, 0x00, 0x00, 0x00, +- 0x00, 0x00, 0x49, 0x44, 0x41, +- 0x54 }; +- pnghdr[18] = (mz_uint8)(w >> 8); +- pnghdr[19] = (mz_uint8)w; +- pnghdr[22] = (mz_uint8)(h >> 8); +- pnghdr[23] = (mz_uint8)h; +- pnghdr[25] = chans[num_chans]; +- pnghdr[33] = (mz_uint8)(*pLen_out >> 24); +- pnghdr[34] = (mz_uint8)(*pLen_out >> 16); +- pnghdr[35] = (mz_uint8)(*pLen_out >> 8); +- pnghdr[36] = (mz_uint8)*pLen_out; +- c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); +- for (i = 0; i < 4; ++i, c <<= 8) +- ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); +- memcpy(out_buf.m_pBuf, pnghdr, 41); +- } +- /* write footer (IDAT CRC-32, followed by IEND chunk) */ +- if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) +- { +- *pLen_out = 0; +- MZ_FREE(pComp); +- MZ_FREE(out_buf.m_pBuf); +- return NULL; +- } +- c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); +- for (i = 0; i < 4; ++i, c <<= 8) +- (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); +- /* compute final size of file, grab compressed data buffer and return */ +- *pLen_out += 57; +- MZ_FREE(pComp); +- return out_buf.m_pBuf; +-} +-void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) +-{ ++// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) ++// { ++// /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ ++// static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; ++// tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); ++// tdefl_output_buffer out_buf; ++// int i, bpl = w * num_chans, y, z; ++// mz_uint32 c; ++// *pLen_out = 0; ++// if (!pComp) ++// return NULL; ++// MZ_CLEAR_OBJ(out_buf); ++// out_buf.m_expandable = MZ_TRUE; ++// out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); ++// if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) ++// { ++// MZ_FREE(pComp); ++// return NULL; ++// } ++// /* write dummy header */ ++// for (z = 41; z; --z) ++// tdefl_output_buffer_putter(&z, 1, &out_buf); ++// /* compress image data */ ++// tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); ++// for (y = 0; y < h; ++y) ++// { ++// tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); ++// tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); ++// } ++// if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) ++// { ++// MZ_FREE(pComp); ++// MZ_FREE(out_buf.m_pBuf); ++// return NULL; ++// } ++// /* write real header */ ++// *pLen_out = out_buf.m_size - 41; ++// { ++// static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; ++// mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, ++// 0x0a, 0x1a, 0x0a, 0x00, 0x00, ++// 0x00, 0x0d, 0x49, 0x48, 0x44, ++// 0x52, 0x00, 0x00, 0x00, 0x00, ++// 0x00, 0x00, 0x00, 0x00, 0x08, ++// 0x00, 0x00, 0x00, 0x00, 0x00, ++// 0x00, 0x00, 0x00, 0x00, 0x00, ++// 0x00, 0x00, 0x49, 0x44, 0x41, ++// 0x54 }; ++// pnghdr[18] = (mz_uint8)(w >> 8); ++// pnghdr[19] = (mz_uint8)w; ++// pnghdr[22] = (mz_uint8)(h >> 8); ++// pnghdr[23] = (mz_uint8)h; ++// pnghdr[25] = chans[num_chans]; ++// pnghdr[33] = (mz_uint8)(*pLen_out >> 24); ++// pnghdr[34] = (mz_uint8)(*pLen_out >> 16); ++// pnghdr[35] = (mz_uint8)(*pLen_out >> 8); ++// pnghdr[36] = (mz_uint8)*pLen_out; ++// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); ++// for (i = 0; i < 4; ++i, c <<= 8) ++// ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); ++// memcpy(out_buf.m_pBuf, pnghdr, 41); ++// } ++// /* write footer (IDAT CRC-32, followed by IEND chunk) */ ++// if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) ++// { ++// *pLen_out = 0; ++// MZ_FREE(pComp); ++// MZ_FREE(out_buf.m_pBuf); ++// return NULL; ++// } ++// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); ++// for (i = 0; i < 4; ++i, c <<= 8) ++// (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); ++// /* compute final size of file, grab compressed data buffer and return */ ++// *pLen_out += 57; ++// MZ_FREE(pComp); ++// return out_buf.m_pBuf; ++// } ++// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) ++// { + /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */ +- return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); +-} ++// return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); ++// } + + /* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ + /* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ + /* structure size and allocation mechanism. */ +-tdefl_compressor *tdefl_compressor_alloc() +-{ +- return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +-} ++// tdefl_compressor *tdefl_compressor_alloc() ++// { ++// return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); ++// } + +-void tdefl_compressor_free(tdefl_compressor *pComp) +-{ +- MZ_FREE(pComp); +-} ++// void tdefl_compressor_free(tdefl_compressor *pComp) ++// { ++// MZ_FREE(pComp); ++// } + + #ifdef _MSC_VER + #pragma warning(pop) +@@ -2339,12 +2338,12 @@ extern "C" { + + tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) + { +- static const int s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; +- static const int s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; +- static const int s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; +- static const int s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; ++ static const mz_uint16 s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; ++ static const mz_uint8 s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; ++ static const mz_uint16 s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; ++ static const mz_uint8 s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; + static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; +- static const int s_min_table_sizes[3] = { 257, 1, 4 }; ++ static const mz_uint16 s_min_table_sizes[3] = { 257, 1, 4 }; + + tinfl_status status = TINFL_STATUS_FAILED; + mz_uint32 num_bits, dist, counter, num_extra; +@@ -2805,94 +2804,94 @@ common_exit: + } + + /* Higher level helper functions. */ +-void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +-{ +- tinfl_decompressor decomp; +- void *pBuf = NULL, *pNew_buf; +- size_t src_buf_ofs = 0, out_buf_capacity = 0; +- *pOut_len = 0; +- tinfl_init(&decomp); +- for (;;) +- { +- size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; +- tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, +- (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); +- if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) +- { +- MZ_FREE(pBuf); +- *pOut_len = 0; +- return NULL; +- } +- src_buf_ofs += src_buf_size; +- *pOut_len += dst_buf_size; +- if (status == TINFL_STATUS_DONE) +- break; +- new_out_buf_capacity = out_buf_capacity * 2; +- if (new_out_buf_capacity < 128) +- new_out_buf_capacity = 128; +- pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); +- if (!pNew_buf) +- { +- MZ_FREE(pBuf); +- *pOut_len = 0; +- return NULL; +- } +- pBuf = pNew_buf; +- out_buf_capacity = new_out_buf_capacity; +- } +- return pBuf; +-} ++// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) ++// { ++// tinfl_decompressor decomp; ++// void *pBuf = NULL, *pNew_buf; ++// size_t src_buf_ofs = 0, out_buf_capacity = 0; ++// *pOut_len = 0; ++// tinfl_init(&decomp); ++// for (;;) ++// { ++// size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; ++// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, ++// (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); ++// if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) ++// { ++// MZ_FREE(pBuf); ++// *pOut_len = 0; ++// return NULL; ++// } ++// src_buf_ofs += src_buf_size; ++// *pOut_len += dst_buf_size; ++// if (status == TINFL_STATUS_DONE) ++// break; ++// new_out_buf_capacity = out_buf_capacity * 2; ++// if (new_out_buf_capacity < 128) ++// new_out_buf_capacity = 128; ++// pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); ++// if (!pNew_buf) ++// { ++// MZ_FREE(pBuf); ++// *pOut_len = 0; ++// return NULL; ++// } ++// pBuf = pNew_buf; ++// out_buf_capacity = new_out_buf_capacity; ++// } ++// return pBuf; ++// } + +-size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +-{ +- tinfl_decompressor decomp; +- tinfl_status status; +- tinfl_init(&decomp); +- status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); +- return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; +-} ++// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) ++// { ++// tinfl_decompressor decomp; ++// tinfl_status status; ++// tinfl_init(&decomp); ++// status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); ++// return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; ++// } + +-int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +-{ +- int result = 0; +- tinfl_decompressor decomp; +- mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); +- size_t in_buf_ofs = 0, dict_ofs = 0; +- if (!pDict) +- return TINFL_STATUS_FAILED; +- tinfl_init(&decomp); +- for (;;) +- { +- size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; +- tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, +- (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); +- in_buf_ofs += in_buf_size; +- if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) +- break; +- if (status != TINFL_STATUS_HAS_MORE_OUTPUT) +- { +- result = (status == TINFL_STATUS_DONE); +- break; +- } +- dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); +- } +- MZ_FREE(pDict); +- *pIn_buf_size = in_buf_ofs; +- return result; +-} ++// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) ++// { ++// int result = 0; ++// tinfl_decompressor decomp; ++// mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); ++// size_t in_buf_ofs = 0, dict_ofs = 0; ++// if (!pDict) ++// return TINFL_STATUS_FAILED; ++// tinfl_init(&decomp); ++// for (;;) ++// { ++// size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; ++// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, ++// (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); ++// in_buf_ofs += in_buf_size; ++// if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) ++// break; ++// if (status != TINFL_STATUS_HAS_MORE_OUTPUT) ++// { ++// result = (status == TINFL_STATUS_DONE); ++// break; ++// } ++// dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); ++// } ++// MZ_FREE(pDict); ++// *pIn_buf_size = in_buf_ofs; ++// return result; ++// } + +-tinfl_decompressor *tinfl_decompressor_alloc() +-{ +- tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); +- if (pDecomp) +- tinfl_init(pDecomp); +- return pDecomp; +-} ++// tinfl_decompressor *tinfl_decompressor_alloc() ++// { ++// tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); ++// if (pDecomp) ++// tinfl_init(pDecomp); ++// return pDecomp; ++// } + +-void tinfl_decompressor_free(tinfl_decompressor *pDecomp) +-{ +- MZ_FREE(pDecomp); +-} ++// void tinfl_decompressor_free(tinfl_decompressor *pDecomp) ++// { ++// MZ_FREE(pDecomp); ++// } + + #ifdef __cplusplus + } +@@ -2925,461 +2924,461 @@ void tinfl_decompressor_free(tinfl_decompressor *pDecomp) + **************************************************************************/ + + +-#ifndef MINIZ_NO_ARCHIVE_APIS ++// #ifndef MINIZ_NO_ARCHIVE_APIS + +-#ifdef __cplusplus +-extern "C" { +-#endif ++// #ifdef __cplusplus ++// extern "C" { ++// #endif + + /* ------------------- .ZIP archive reading */ + +-#ifdef MINIZ_NO_STDIO +-#define MZ_FILE void * +-#else +-#include ++// #ifdef MINIZ_NO_STDIO ++// #define MZ_FILE void * ++// #else ++// #include + +-#if defined(_MSC_VER) || defined(__MINGW64__) +-static FILE *mz_fopen(const char *pFilename, const char *pMode) +-{ +- FILE *pFile = NULL; +- fopen_s(&pFile, pFilename, pMode); +- return pFile; +-} +-static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) +-{ +- FILE *pFile = NULL; +- if (freopen_s(&pFile, pPath, pMode, pStream)) +- return NULL; +- return pFile; +-} +-#ifndef MINIZ_NO_TIME +-#include +-#endif +-#define MZ_FOPEN mz_fopen +-#define MZ_FCLOSE fclose +-#define MZ_FREAD fread +-#define MZ_FWRITE fwrite +-#define MZ_FTELL64 _ftelli64 +-#define MZ_FSEEK64 _fseeki64 +-#define MZ_FILE_STAT_STRUCT _stat +-#define MZ_FILE_STAT _stat +-#define MZ_FFLUSH fflush +-#define MZ_FREOPEN mz_freopen +-#define MZ_DELETE_FILE remove +-#elif defined(__MINGW32__) +-#ifndef MINIZ_NO_TIME +-#include +-#endif +-#define MZ_FOPEN(f, m) fopen(f, m) +-#define MZ_FCLOSE fclose +-#define MZ_FREAD fread +-#define MZ_FWRITE fwrite +-#define MZ_FTELL64 ftello64 +-#define MZ_FSEEK64 fseeko64 +-#define MZ_FILE_STAT_STRUCT _stat +-#define MZ_FILE_STAT _stat +-#define MZ_FFLUSH fflush +-#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +-#define MZ_DELETE_FILE remove +-#elif defined(__TINYC__) +-#ifndef MINIZ_NO_TIME +-#include +-#endif +-#define MZ_FOPEN(f, m) fopen(f, m) +-#define MZ_FCLOSE fclose +-#define MZ_FREAD fread +-#define MZ_FWRITE fwrite +-#define MZ_FTELL64 ftell +-#define MZ_FSEEK64 fseek +-#define MZ_FILE_STAT_STRUCT stat +-#define MZ_FILE_STAT stat +-#define MZ_FFLUSH fflush +-#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +-#define MZ_DELETE_FILE remove +-#elif defined(__GNUC__) && _LARGEFILE64_SOURCE +-#ifndef MINIZ_NO_TIME +-#include +-#endif +-#define MZ_FOPEN(f, m) fopen64(f, m) +-#define MZ_FCLOSE fclose +-#define MZ_FREAD fread +-#define MZ_FWRITE fwrite +-#define MZ_FTELL64 ftello64 +-#define MZ_FSEEK64 fseeko64 +-#define MZ_FILE_STAT_STRUCT stat64 +-#define MZ_FILE_STAT stat64 +-#define MZ_FFLUSH fflush +-#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) +-#define MZ_DELETE_FILE remove +-#elif defined(__APPLE__) && _LARGEFILE64_SOURCE +-#ifndef MINIZ_NO_TIME +-#include +-#endif +-#define MZ_FOPEN(f, m) fopen(f, m) +-#define MZ_FCLOSE fclose +-#define MZ_FREAD fread +-#define MZ_FWRITE fwrite +-#define MZ_FTELL64 ftello +-#define MZ_FSEEK64 fseeko +-#define MZ_FILE_STAT_STRUCT stat +-#define MZ_FILE_STAT stat +-#define MZ_FFLUSH fflush +-#define MZ_FREOPEN(p, m, s) freopen(p, m, s) +-#define MZ_DELETE_FILE remove ++// #if defined(_MSC_VER) || defined(__MINGW64__) ++// static FILE *mz_fopen(const char *pFilename, const char *pMode) ++// { ++// FILE *pFile = NULL; ++// fopen_s(&pFile, pFilename, pMode); ++// return pFile; ++// } ++// static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) ++// { ++// FILE *pFile = NULL; ++// if (freopen_s(&pFile, pPath, pMode, pStream)) ++// return NULL; ++// return pFile; ++// } ++// #ifndef MINIZ_NO_TIME ++// #include ++// #endif ++// #define MZ_FOPEN mz_fopen ++// #define MZ_FCLOSE fclose ++// #define MZ_FREAD fread ++// #define MZ_FWRITE fwrite ++// #define MZ_FTELL64 _ftelli64 ++// #define MZ_FSEEK64 _fseeki64 ++// #define MZ_FILE_STAT_STRUCT _stat ++// #define MZ_FILE_STAT _stat ++// #define MZ_FFLUSH fflush ++// #define MZ_FREOPEN mz_freopen ++// #define MZ_DELETE_FILE remove ++// #elif defined(__MINGW32__) ++// #ifndef MINIZ_NO_TIME ++// #include ++// #endif ++// #define MZ_FOPEN(f, m) fopen(f, m) ++// #define MZ_FCLOSE fclose ++// #define MZ_FREAD fread ++// #define MZ_FWRITE fwrite ++// #define MZ_FTELL64 ftello64 ++// #define MZ_FSEEK64 fseeko64 ++// #define MZ_FILE_STAT_STRUCT _stat ++// #define MZ_FILE_STAT _stat ++// #define MZ_FFLUSH fflush ++// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) ++// #define MZ_DELETE_FILE remove ++// #elif defined(__TINYC__) ++// #ifndef MINIZ_NO_TIME ++// #include ++// #endif ++// #define MZ_FOPEN(f, m) fopen(f, m) ++// #define MZ_FCLOSE fclose ++// #define MZ_FREAD fread ++// #define MZ_FWRITE fwrite ++// #define MZ_FTELL64 ftell ++// #define MZ_FSEEK64 fseek ++// #define MZ_FILE_STAT_STRUCT stat ++// #define MZ_FILE_STAT stat ++// #define MZ_FFLUSH fflush ++// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) ++// #define MZ_DELETE_FILE remove ++// #elif defined(__GNUC__) && _LARGEFILE64_SOURCE ++// #ifndef MINIZ_NO_TIME ++// #include ++// #endif ++// #define MZ_FOPEN(f, m) fopen64(f, m) ++// #define MZ_FCLOSE fclose ++// #define MZ_FREAD fread ++// #define MZ_FWRITE fwrite ++// #define MZ_FTELL64 ftello64 ++// #define MZ_FSEEK64 fseeko64 ++// #define MZ_FILE_STAT_STRUCT stat64 ++// #define MZ_FILE_STAT stat64 ++// #define MZ_FFLUSH fflush ++// #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) ++// #define MZ_DELETE_FILE remove ++// #elif defined(__APPLE__) && _LARGEFILE64_SOURCE ++// #ifndef MINIZ_NO_TIME ++// #include ++// #endif ++// #define MZ_FOPEN(f, m) fopen(f, m) ++// #define MZ_FCLOSE fclose ++// #define MZ_FREAD fread ++// #define MZ_FWRITE fwrite ++// #define MZ_FTELL64 ftello ++// #define MZ_FSEEK64 fseeko ++// #define MZ_FILE_STAT_STRUCT stat ++// #define MZ_FILE_STAT stat ++// #define MZ_FFLUSH fflush ++// #define MZ_FREOPEN(p, m, s) freopen(p, m, s) ++// #define MZ_DELETE_FILE remove ++ ++// #else ++// // #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") ++// #ifndef MINIZ_NO_TIME ++// #include ++// #endif ++// #define MZ_FOPEN(f, m) fopen(f, m) ++// #define MZ_FCLOSE fclose ++// #define MZ_FREAD fread ++// #define MZ_FWRITE fwrite ++// #ifdef __STRICT_ANSI__ ++// #define MZ_FTELL64 ftell ++// #define MZ_FSEEK64 fseek ++// #else ++// #define MZ_FTELL64 ftello ++// #define MZ_FSEEK64 fseeko ++// #endif ++// #define MZ_FILE_STAT_STRUCT stat ++// #define MZ_FILE_STAT stat ++// #define MZ_FFLUSH fflush ++// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) ++// #define MZ_DELETE_FILE remove ++// #endif /* #ifdef _MSC_VER */ ++// #endif /* #ifdef MINIZ_NO_STDIO */ ++ ++// #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) + +-#else +-// #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") +-#ifndef MINIZ_NO_TIME +-#include +-#endif +-#define MZ_FOPEN(f, m) fopen(f, m) +-#define MZ_FCLOSE fclose +-#define MZ_FREAD fread +-#define MZ_FWRITE fwrite +-#ifdef __STRICT_ANSI__ +-#define MZ_FTELL64 ftell +-#define MZ_FSEEK64 fseek +-#else +-#define MZ_FTELL64 ftello +-#define MZ_FSEEK64 fseeko +-#endif +-#define MZ_FILE_STAT_STRUCT stat +-#define MZ_FILE_STAT stat +-#define MZ_FFLUSH fflush +-#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +-#define MZ_DELETE_FILE remove +-#endif /* #ifdef _MSC_VER */ +-#endif /* #ifdef MINIZ_NO_STDIO */ ++/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ ++// enum ++// { ++// /* ZIP archive identifiers and record sizes */ ++// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, ++// MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, ++// MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, ++// MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, ++// MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, ++// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, ++ ++// /* ZIP64 archive identifier and record sizes */ ++// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, ++// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, ++// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, ++// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, ++// MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, ++// MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, ++// MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, ++// MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, ++ ++// /* Central directory header record offsets */ ++// MZ_ZIP_CDH_SIG_OFS = 0, ++// MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, ++// MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, ++// MZ_ZIP_CDH_BIT_FLAG_OFS = 8, ++// MZ_ZIP_CDH_METHOD_OFS = 10, ++// MZ_ZIP_CDH_FILE_TIME_OFS = 12, ++// MZ_ZIP_CDH_FILE_DATE_OFS = 14, ++// MZ_ZIP_CDH_CRC32_OFS = 16, ++// MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, ++// MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, ++// MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, ++// MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, ++// MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, ++// MZ_ZIP_CDH_DISK_START_OFS = 34, ++// MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, ++// MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, ++// MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, ++ ++// /* Local directory header offsets */ ++// MZ_ZIP_LDH_SIG_OFS = 0, ++// MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, ++// MZ_ZIP_LDH_BIT_FLAG_OFS = 6, ++// MZ_ZIP_LDH_METHOD_OFS = 8, ++// MZ_ZIP_LDH_FILE_TIME_OFS = 10, ++// MZ_ZIP_LDH_FILE_DATE_OFS = 12, ++// MZ_ZIP_LDH_CRC32_OFS = 14, ++// MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, ++// MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, ++// MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, ++// MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, ++// MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, ++ ++// /* End of central directory offsets */ ++// MZ_ZIP_ECDH_SIG_OFS = 0, ++// MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, ++// MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, ++// MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, ++// MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, ++// MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, ++// MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, ++// MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, ++ ++// /* ZIP64 End of central directory locator offsets */ ++// MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ ++// MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ ++// MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ ++// MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ ++ ++// /* ZIP64 End of central directory header offsets */ ++// MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ ++// MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ ++// MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ ++// MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ ++// MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ ++// MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ ++// MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ ++// MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ ++// MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ ++// MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ ++// MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, ++// MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, ++// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, ++// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, ++// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, ++// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, ++// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 ++// }; ++ ++// typedef struct ++// { ++// void *m_p; ++// size_t m_size, m_capacity; ++// mz_uint m_element_size; ++// } mz_zip_array; + +-#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) ++// struct mz_zip_internal_state_tag ++// { ++// mz_zip_array m_central_dir; ++// mz_zip_array m_central_dir_offsets; ++// mz_zip_array m_sorted_central_dir_offsets; + +-/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ +-enum +-{ +- /* ZIP archive identifiers and record sizes */ +- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, +- MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, +- MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, +- MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, +- MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, +- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, +- +- /* ZIP64 archive identifier and record sizes */ +- MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, +- MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, +- MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, +- MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, +- MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, +- MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, +- MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, +- MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, +- +- /* Central directory header record offsets */ +- MZ_ZIP_CDH_SIG_OFS = 0, +- MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, +- MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, +- MZ_ZIP_CDH_BIT_FLAG_OFS = 8, +- MZ_ZIP_CDH_METHOD_OFS = 10, +- MZ_ZIP_CDH_FILE_TIME_OFS = 12, +- MZ_ZIP_CDH_FILE_DATE_OFS = 14, +- MZ_ZIP_CDH_CRC32_OFS = 16, +- MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, +- MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, +- MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, +- MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, +- MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, +- MZ_ZIP_CDH_DISK_START_OFS = 34, +- MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, +- MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, +- MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, +- +- /* Local directory header offsets */ +- MZ_ZIP_LDH_SIG_OFS = 0, +- MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, +- MZ_ZIP_LDH_BIT_FLAG_OFS = 6, +- MZ_ZIP_LDH_METHOD_OFS = 8, +- MZ_ZIP_LDH_FILE_TIME_OFS = 10, +- MZ_ZIP_LDH_FILE_DATE_OFS = 12, +- MZ_ZIP_LDH_CRC32_OFS = 14, +- MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, +- MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, +- MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, +- MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, +- MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, +- +- /* End of central directory offsets */ +- MZ_ZIP_ECDH_SIG_OFS = 0, +- MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, +- MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, +- MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, +- MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, +- MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, +- MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, +- MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, +- +- /* ZIP64 End of central directory locator offsets */ +- MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ +- MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ +- MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ +- MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ +- +- /* ZIP64 End of central directory header offsets */ +- MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ +- MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ +- MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ +- MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ +- MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ +- MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ +- MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ +- MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ +- MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ +- MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ +- MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, +- MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, +- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, +- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, +- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, +- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, +- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 +-}; ++// /* The flags passed in when the archive is initially opened. */ ++// uint32_t m_init_flags; + +-typedef struct +-{ +- void *m_p; +- size_t m_size, m_capacity; +- mz_uint m_element_size; +-} mz_zip_array; ++// /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ ++// mz_bool m_zip64; + +-struct mz_zip_internal_state_tag +-{ +- mz_zip_array m_central_dir; +- mz_zip_array m_central_dir_offsets; +- mz_zip_array m_sorted_central_dir_offsets; ++// /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ ++// mz_bool m_zip64_has_extended_info_fields; + +- /* The flags passed in when the archive is initially opened. */ +- uint32_t m_init_flags; ++// /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ ++// MZ_FILE *m_pFile; ++// mz_uint64 m_file_archive_start_ofs; + +- /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ +- mz_bool m_zip64; ++// void *m_pMem; ++// size_t m_mem_size; ++// size_t m_mem_capacity; ++// }; + +- /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ +- mz_bool m_zip64_has_extended_info_fields; ++// #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size + +- /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ +- MZ_FILE *m_pFile; +- mz_uint64 m_file_archive_start_ofs; ++// #if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) ++// static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) ++// { ++// MZ_ASSERT(index < pArray->m_size); ++// return index; ++// } ++// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] ++// #else ++// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] ++// #endif + +- void *m_pMem; +- size_t m_mem_size; +- size_t m_mem_capacity; +-}; ++// static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) ++// { ++// memset(pArray, 0, sizeof(mz_zip_array)); ++// pArray->m_element_size = element_size; ++// } + +-#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size ++// static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); ++// memset(pArray, 0, sizeof(mz_zip_array)); ++// } + +-#if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) +-static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) +-{ +- MZ_ASSERT(index < pArray->m_size); +- return index; +-} +-#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] +-#else +-#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] +-#endif ++// static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) ++// { ++// void *pNew_p; ++// size_t new_capacity = min_new_capacity; ++// MZ_ASSERT(pArray->m_element_size); ++// if (pArray->m_capacity >= min_new_capacity) ++// return MZ_TRUE; ++// if (growing) ++// { ++// new_capacity = MZ_MAX(1, pArray->m_capacity); ++// while (new_capacity < min_new_capacity) ++// new_capacity *= 2; ++// } ++// if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) ++// return MZ_FALSE; ++// pArray->m_p = pNew_p; ++// pArray->m_capacity = new_capacity; ++// return MZ_TRUE; ++// } + +-static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) +-{ +- memset(pArray, 0, sizeof(mz_zip_array)); +- pArray->m_element_size = element_size; +-} ++// static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) ++// { ++// if (new_capacity > pArray->m_capacity) ++// { ++// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) ++// return MZ_FALSE; ++// } ++// return MZ_TRUE; ++// } + +-static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) +-{ +- pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); +- memset(pArray, 0, sizeof(mz_zip_array)); +-} ++// static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) ++// { ++// if (new_size > pArray->m_capacity) ++// { ++// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) ++// return MZ_FALSE; ++// } ++// pArray->m_size = new_size; ++// return MZ_TRUE; ++// } + +-static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) +-{ +- void *pNew_p; +- size_t new_capacity = min_new_capacity; +- MZ_ASSERT(pArray->m_element_size); +- if (pArray->m_capacity >= min_new_capacity) +- return MZ_TRUE; +- if (growing) +- { +- new_capacity = MZ_MAX(1, pArray->m_capacity); +- while (new_capacity < min_new_capacity) +- new_capacity *= 2; +- } +- if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) +- return MZ_FALSE; +- pArray->m_p = pNew_p; +- pArray->m_capacity = new_capacity; +- return MZ_TRUE; +-} ++// static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) ++// { ++// return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); ++// } + +-static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) +-{ +- if (new_capacity > pArray->m_capacity) +- { +- if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) +- return MZ_FALSE; +- } +- return MZ_TRUE; +-} ++// static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) ++// { ++// size_t orig_size = pArray->m_size; ++// if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) ++// return MZ_FALSE; ++// memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); ++// return MZ_TRUE; ++// } + +-static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) +-{ +- if (new_size > pArray->m_capacity) +- { +- if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) +- return MZ_FALSE; +- } +- pArray->m_size = new_size; +- return MZ_TRUE; +-} ++// #ifndef MINIZ_NO_TIME ++// static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) ++// { ++// struct tm tm; ++// memset(&tm, 0, sizeof(tm)); ++// tm.tm_isdst = -1; ++// tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; ++// tm.tm_mon = ((dos_date >> 5) & 15) - 1; ++// tm.tm_mday = dos_date & 31; ++// tm.tm_hour = (dos_time >> 11) & 31; ++// tm.tm_min = (dos_time >> 5) & 63; ++// tm.tm_sec = (dos_time << 1) & 62; ++// return mktime(&tm); ++// } + +-static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) +-{ +- return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); +-} ++// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS ++// static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) ++// { ++// #ifdef _MSC_VER ++// struct tm tm_struct; ++// struct tm *tm = &tm_struct; ++// errno_t err = localtime_s(tm, &time_); ++// if (err) ++// { ++// *pDOS_date = 0; ++// *pDOS_time = 0; ++// return; ++// } ++// #else ++// struct tm *tm = localtime(&time_); ++// #endif /* #ifdef _MSC_VER */ + +-static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) +-{ +- size_t orig_size = pArray->m_size; +- if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) +- return MZ_FALSE; +- memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); +- return MZ_TRUE; +-} ++// *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); ++// *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); ++// } ++// #endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ + +-#ifndef MINIZ_NO_TIME +-static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) +-{ +- struct tm tm; +- memset(&tm, 0, sizeof(tm)); +- tm.tm_isdst = -1; +- tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; +- tm.tm_mon = ((dos_date >> 5) & 15) - 1; +- tm.tm_mday = dos_date & 31; +- tm.tm_hour = (dos_time >> 11) & 31; +- tm.tm_min = (dos_time >> 5) & 63; +- tm.tm_sec = (dos_time << 1) & 62; +- return mktime(&tm); +-} ++// #ifndef MINIZ_NO_STDIO ++// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS ++// static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) ++// { ++// struct MZ_FILE_STAT_STRUCT file_stat; + +-#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +-static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +-{ +-#ifdef _MSC_VER +- struct tm tm_struct; +- struct tm *tm = &tm_struct; +- errno_t err = localtime_s(tm, &time_); +- if (err) +- { +- *pDOS_date = 0; +- *pDOS_time = 0; +- return; +- } +-#else +- struct tm *tm = localtime(&time_); +-#endif /* #ifdef _MSC_VER */ ++// /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ ++// if (MZ_FILE_STAT(pFilename, &file_stat) != 0) ++// return MZ_FALSE; + +- *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); +- *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); +-} +-#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ ++// *pTime = file_stat.st_mtime; + +-#ifndef MINIZ_NO_STDIO +-#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +-static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) +-{ +- struct MZ_FILE_STAT_STRUCT file_stat; ++// return MZ_TRUE; ++// } ++// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ + +- /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ +- if (MZ_FILE_STAT(pFilename, &file_stat) != 0) +- return MZ_FALSE; ++// static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) ++// { ++// struct utimbuf t; + +- *pTime = file_stat.st_mtime; ++// memset(&t, 0, sizeof(t)); ++// t.actime = access_time; ++// t.modtime = modified_time; + +- return MZ_TRUE; +-} +-#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ ++// return !utime(pFilename, &t); ++// } ++// #endif /* #ifndef MINIZ_NO_STDIO */ ++// #endif /* #ifndef MINIZ_NO_TIME */ + +-static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) +-{ +- struct utimbuf t; ++// static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) ++// { ++// if (pZip) ++// pZip->m_last_error = err_num; ++// return MZ_FALSE; ++// } + +- memset(&t, 0, sizeof(t)); +- t.actime = access_time; +- t.modtime = modified_time; ++// static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) ++// { ++// (void)flags; ++// if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- return !utime(pFilename, &t); +-} +-#endif /* #ifndef MINIZ_NO_STDIO */ +-#endif /* #ifndef MINIZ_NO_TIME */ ++// if (!pZip->m_pAlloc) ++// pZip->m_pAlloc = miniz_def_alloc_func; ++// if (!pZip->m_pFree) ++// pZip->m_pFree = miniz_def_free_func; ++// if (!pZip->m_pRealloc) ++// pZip->m_pRealloc = miniz_def_realloc_func; + +-static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) +-{ +- if (pZip) +- pZip->m_last_error = err_num; +- return MZ_FALSE; +-} ++// pZip->m_archive_size = 0; ++// pZip->m_central_directory_file_ofs = 0; ++// pZip->m_total_files = 0; ++// pZip->m_last_error = MZ_ZIP_NO_ERROR; + +-static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) +-{ +- (void)flags; +- if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- +- if (!pZip->m_pAlloc) +- pZip->m_pAlloc = miniz_def_alloc_func; +- if (!pZip->m_pFree) +- pZip->m_pFree = miniz_def_free_func; +- if (!pZip->m_pRealloc) +- pZip->m_pRealloc = miniz_def_realloc_func; +- +- pZip->m_archive_size = 0; +- pZip->m_central_directory_file_ofs = 0; +- pZip->m_total_files = 0; +- pZip->m_last_error = MZ_ZIP_NO_ERROR; +- +- if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- +- memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); +- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); +- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); +- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); +- pZip->m_pState->m_init_flags = flags; +- pZip->m_pState->m_zip64 = MZ_FALSE; +- pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; +- +- pZip->m_zip_mode = MZ_ZIP_MODE_READING; ++// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +- return MZ_TRUE; +-} ++// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); ++// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); ++// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); ++// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); ++// pZip->m_pState->m_init_flags = flags; ++// pZip->m_pState->m_zip64 = MZ_FALSE; ++// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; + +-static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) +-{ +- const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; +- const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); +- mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); +- mz_uint8 l = 0, r = 0; +- pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +- pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +- pE = pL + MZ_MIN(l_len, r_len); +- while (pL < pE) +- { +- if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) +- break; +- pL++; +- pR++; +- } +- return (pL == pE) ? (l_len < r_len) : (l < r); +-} ++// pZip->m_zip_mode = MZ_ZIP_MODE_READING; ++ ++// return MZ_TRUE; ++// } + ++// static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) ++// { ++// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; ++// const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); ++// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// mz_uint8 l = 0, r = 0; ++// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; ++// pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; ++// pE = pL + MZ_MIN(l_len, r_len); ++// while (pL < pE) ++// { ++// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) ++// break; ++// pL++; ++// pR++; ++// } ++// return (pL == pE) ? (l_len < r_len) : (l < r); ++// } ++/* + #define MZ_SWAP_UINT32(a, b) \ + do \ + { \ +@@ -3388,1708 +3387,1708 @@ static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pC + b = t; \ + } \ + MZ_MACRO_END +- ++*/ + /* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */ +-static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) +-{ +- mz_zip_internal_state *pState = pZip->m_pState; +- const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; +- const mz_zip_array *pCentral_dir = &pState->m_central_dir; +- mz_uint32 *pIndices; +- mz_uint32 start, end; +- const mz_uint32 size = pZip->m_total_files; +- +- if (size <= 1U) +- return; ++// static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) ++// { ++// mz_zip_internal_state *pState = pZip->m_pState; ++// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; ++// const mz_zip_array *pCentral_dir = &pState->m_central_dir; ++// mz_uint32 *pIndices; ++// mz_uint32 start, end; ++// const mz_uint32 size = pZip->m_total_files; + +- pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); ++// if (size <= 1U) ++// return; + +- start = (size - 2U) >> 1U; +- for (;;) +- { +- mz_uint64 child, root = start; +- for (;;) +- { +- if ((child = (root << 1U) + 1U) >= size) +- break; +- child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); +- if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) +- break; +- MZ_SWAP_UINT32(pIndices[root], pIndices[child]); +- root = child; +- } +- if (!start) +- break; +- start--; +- } ++// pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + +- end = size - 1; +- while (end > 0) +- { +- mz_uint64 child, root = 0; +- MZ_SWAP_UINT32(pIndices[end], pIndices[0]); +- for (;;) +- { +- if ((child = (root << 1U) + 1U) >= end) +- break; +- child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); +- if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) +- break; +- MZ_SWAP_UINT32(pIndices[root], pIndices[child]); +- root = child; +- } +- end--; +- } +-} ++// start = (size - 2U) >> 1U; ++// for (;;) ++// { ++// mz_uint64 child, root = start; ++// for (;;) ++// { ++// if ((child = (root << 1U) + 1U) >= size) ++// break; ++// child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); ++// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) ++// break; ++// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); ++// root = child; ++// } ++// if (!start) ++// break; ++// start--; ++// } + +-static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) +-{ +- mz_int64 cur_file_ofs; +- mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; +- mz_uint8 *pBuf = (mz_uint8 *)buf_u32; ++// end = size - 1; ++// while (end > 0) ++// { ++// mz_uint64 child, root = 0; ++// MZ_SWAP_UINT32(pIndices[end], pIndices[0]); ++// for (;;) ++// { ++// if ((child = (root << 1U) + 1U) >= end) ++// break; ++// child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); ++// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) ++// break; ++// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); ++// root = child; ++// } ++// end--; ++// } ++// } + +- /* Basic sanity checks - reject files which are too small */ +- if (pZip->m_archive_size < record_size) +- return MZ_FALSE; ++// static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) ++// { ++// mz_int64 cur_file_ofs; ++// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; ++// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + +- /* Find the record by scanning the file from the end towards the beginning. */ +- cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); +- for (;;) +- { +- int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); ++// /* Basic sanity checks - reject files which are too small */ ++// if (pZip->m_archive_size < record_size) ++// return MZ_FALSE; + +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) +- return MZ_FALSE; ++// /* Find the record by scanning the file from the end towards the beginning. */ ++// cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); ++// for (;;) ++// { ++// int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + +- for (i = n - 4; i >= 0; --i) +- { +- mz_uint s = MZ_READ_LE32(pBuf + i); +- if (s == record_sig) +- { +- if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) +- break; +- } +- } ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) ++// return MZ_FALSE; + +- if (i >= 0) +- { +- cur_file_ofs += i; +- break; +- } ++// for (i = n - 4; i >= 0; --i) ++// { ++// mz_uint s = MZ_READ_LE32(pBuf + i); ++// if (s == record_sig) ++// { ++// if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) ++// break; ++// } ++// } + +- /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ +- if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) +- return MZ_FALSE; ++// if (i >= 0) ++// { ++// cur_file_ofs += i; ++// break; ++// } + +- cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); +- } ++// /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ ++// if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) ++// return MZ_FALSE; + +- *pOfs = cur_file_ofs; +- return MZ_TRUE; +-} ++// cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); ++// } + +-static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) +-{ +- mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; +- mz_uint64 cdir_ofs = 0; +- mz_int64 cur_file_ofs = 0; +- const mz_uint8 *p; ++// *pOfs = cur_file_ofs; ++// return MZ_TRUE; ++// } + +- mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; +- mz_uint8 *pBuf = (mz_uint8 *)buf_u32; +- mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); +- mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +- mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; ++// static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) ++// { ++// mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; ++// mz_uint64 cdir_ofs = 0; ++// mz_int64 cur_file_ofs = 0; ++// const mz_uint8 *p; + +- mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +- mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; ++// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; ++// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; ++// mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); ++// mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; ++// mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; + +- mz_uint64 zip64_end_of_central_dir_ofs = 0; ++// mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; ++// mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; + +- /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ +- if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); ++// mz_uint64 zip64_end_of_central_dir_ofs = 0; + +- if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) +- return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); ++// /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ ++// if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +- /* Read and verify the end of central directory record. */ +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); + +- if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) +- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); ++// /* Read and verify the end of central directory record. */ ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +- if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) +- { +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) +- { +- if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) +- { +- zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); +- if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) +- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); ++// if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ++// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +- if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) +- { +- if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) +- { +- pZip->m_pState->m_zip64 = MZ_TRUE; +- } +- } +- } +- } +- } ++// if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) ++// { ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) ++// { ++// if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) ++// { ++// zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); ++// if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) ++// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +- pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); +- cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); +- num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); +- cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); +- cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); +- cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); ++// if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// { ++// if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) ++// { ++// pZip->m_pState->m_zip64 = MZ_TRUE; ++// } ++// } ++// } ++// } ++// } + +- if (pZip->m_pState->m_zip64) +- { +- mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); +- mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); +- mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); +- mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); +- mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); ++// pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); ++// cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); ++// num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); ++// cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); ++// cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); ++// cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + +- if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// if (pZip->m_pState->m_zip64) ++// { ++// mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); ++// mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); ++// mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); ++// mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); ++// mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); + +- if (zip64_total_num_of_disks != 1U) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); ++// if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- /* Check for miniz's practical limits */ +- if (zip64_cdir_total_entries > MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// if (zip64_total_num_of_disks != 1U) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +- pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; ++// /* Check for miniz's practical limits */ ++// if (zip64_cdir_total_entries > MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + +- if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; + +- cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; ++// if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + +- /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ +- if (zip64_size_of_central_directory > MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); ++// cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; + +- cdir_size = (mz_uint32)zip64_size_of_central_directory; ++// /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ ++// if (zip64_size_of_central_directory > MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +- num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); ++// cdir_size = (mz_uint32)zip64_size_of_central_directory; + +- cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); ++// num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); + +- cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); +- } ++// cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); + +- if (pZip->m_total_files != cdir_entries_on_this_disk) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); ++// cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); ++// } + +- if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); ++// if (pZip->m_total_files != cdir_entries_on_this_disk) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +- if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +- if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- pZip->m_central_directory_file_ofs = cdir_ofs; ++// if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (pZip->m_total_files) +- { +- mz_uint i, n; +- /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ +- if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || +- (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// pZip->m_central_directory_file_ofs = cdir_ofs; + +- if (sort_central_dir) +- { +- if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- } ++// if (pZip->m_total_files) ++// { ++// mz_uint i, n; ++// /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ ++// if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || ++// (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +- if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// if (sort_central_dir) ++// { ++// if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// } + +- /* Now create an index into the central directory file records, do some basic sanity checking on each record */ +- p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; +- for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) +- { +- mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; +- mz_uint64 comp_size, decomp_size, local_header_ofs; ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +- if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// /* Now create an index into the central directory file records, do some basic sanity checking on each record */ ++// p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; ++// for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) ++// { ++// mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; ++// mz_uint64 comp_size, decomp_size, local_header_ofs; + +- MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); ++// if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (sort_central_dir) +- MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; ++// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + +- comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); +- decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); +- local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); +- filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +- ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); ++// if (sort_central_dir) ++// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; + +- if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && +- (ext_data_size) && +- (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) +- { +- /* Attempt to find zip64 extended information field in the entry's extra data */ +- mz_uint32 extra_size_remaining = ext_data_size; ++// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); ++// decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); ++// local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); ++// filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + +- if (extra_size_remaining) +- { +- const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; ++// if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && ++// (ext_data_size) && ++// (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) ++// { ++// /* Attempt to find zip64 extended information field in the entry's extra data */ ++// mz_uint32 extra_size_remaining = ext_data_size; + +- do +- { +- mz_uint32 field_id; +- mz_uint32 field_data_size; ++// if (extra_size_remaining) ++// { ++// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; + +- if (extra_size_remaining < (sizeof(mz_uint16) * 2)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// do ++// { ++// mz_uint32 field_id; ++// mz_uint32 field_data_size; + +- field_id = MZ_READ_LE16(pExtra_data); +- field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); ++// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// field_id = MZ_READ_LE16(pExtra_data); ++// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + +- if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) +- { +- /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ +- pZip->m_pState->m_zip64 = MZ_TRUE; +- pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; +- break; +- } ++// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; +- extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; +- } while (extra_size_remaining); +- } +- } ++// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) ++// { ++// /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ ++// pZip->m_pState->m_zip64 = MZ_TRUE; ++// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; ++// break; ++// } + +- /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ +- if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) +- { +- if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- } ++// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; ++// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; ++// } while (extra_size_remaining); ++// } ++// } + +- disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); +- if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); ++// /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ ++// if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) ++// { ++// if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// } + +- if (comp_size != MZ_UINT32_MAX) +- { +- if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- } ++// disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); ++// if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +- bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); +- if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); ++// if (comp_size != MZ_UINT32_MAX) ++// { ++// if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// } + +- if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); ++// if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + +- n -= total_header_size; +- p += total_header_size; +- } +- } ++// if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (sort_central_dir) +- mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); ++// n -= total_header_size; ++// p += total_header_size; ++// } ++// } + +- return MZ_TRUE; +-} ++// if (sort_central_dir) ++// mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + +-void mz_zip_zero_struct(mz_zip_archive *pZip) +-{ +- if (pZip) +- MZ_CLEAR_OBJ(*pZip); +-} ++// return MZ_TRUE; ++// } + +-static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +-{ +- mz_bool status = MZ_TRUE; ++// void mz_zip_zero_struct(mz_zip_archive *pZip) ++// { ++// if (pZip) ++// MZ_CLEAR_OBJ(*pZip); ++// } + +- if (!pZip) +- return MZ_FALSE; ++// static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) ++// { ++// mz_bool status = MZ_TRUE; + +- if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) +- { +- if (set_last_error) +- pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; ++// if (!pZip) ++// return MZ_FALSE; + +- return MZ_FALSE; +- } ++// if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) ++// { ++// if (set_last_error) ++// pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; + +- if (pZip->m_pState) +- { +- mz_zip_internal_state *pState = pZip->m_pState; +- pZip->m_pState = NULL; ++// return MZ_FALSE; ++// } + +- mz_zip_array_clear(pZip, &pState->m_central_dir); +- mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); +- mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); ++// if (pZip->m_pState) ++// { ++// mz_zip_internal_state *pState = pZip->m_pState; ++// pZip->m_pState = NULL; + +-#ifndef MINIZ_NO_STDIO +- if (pState->m_pFile) +- { +- if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) +- { +- if (MZ_FCLOSE(pState->m_pFile) == EOF) +- { +- if (set_last_error) +- pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; +- status = MZ_FALSE; +- } +- } +- pState->m_pFile = NULL; +- } +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// mz_zip_array_clear(pZip, &pState->m_central_dir); ++// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); ++// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- } +- pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; ++// #ifndef MINIZ_NO_STDIO ++// if (pState->m_pFile) ++// { ++// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) ++// { ++// if (MZ_FCLOSE(pState->m_pFile) == EOF) ++// { ++// if (set_last_error) ++// pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; ++// status = MZ_FALSE; ++// } ++// } ++// pState->m_pFile = NULL; ++// } ++// #endif /* #ifndef MINIZ_NO_STDIO */ + +- return status; +-} ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// } ++// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + +-mz_bool mz_zip_reader_end(mz_zip_archive *pZip) +-{ +- return mz_zip_reader_end_internal(pZip, MZ_TRUE); +-} +-mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) +-{ +- if ((!pZip) || (!pZip->m_pRead)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return status; ++// } + +- if (!mz_zip_reader_init_internal(pZip, flags)) +- return MZ_FALSE; ++// mz_bool mz_zip_reader_end(mz_zip_archive *pZip) ++// { ++// return mz_zip_reader_end_internal(pZip, MZ_TRUE); ++// } ++// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) ++// { ++// if ((!pZip) || (!pZip->m_pRead)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- pZip->m_zip_type = MZ_ZIP_TYPE_USER; +- pZip->m_archive_size = size; ++// if (!mz_zip_reader_init_internal(pZip, flags)) ++// return MZ_FALSE; + +- if (!mz_zip_reader_read_central_dir(pZip, flags)) +- { +- mz_zip_reader_end_internal(pZip, MZ_FALSE); +- return MZ_FALSE; +- } ++// pZip->m_zip_type = MZ_ZIP_TYPE_USER; ++// pZip->m_archive_size = size; + +- return MZ_TRUE; +-} ++// if (!mz_zip_reader_read_central_dir(pZip, flags)) ++// { ++// mz_zip_reader_end_internal(pZip, MZ_FALSE); ++// return MZ_FALSE; ++// } + +-static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +-{ +- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +- size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); +- memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); +- return s; +-} ++// return MZ_TRUE; ++// } + +-mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) +-{ +- if (!pMem) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) ++// { ++// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; ++// size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); ++// memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); ++// return s; ++// } + +- if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); ++// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) ++// { ++// if (!pMem) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if (!mz_zip_reader_init_internal(pZip, flags)) +- return MZ_FALSE; ++// if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +- pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; +- pZip->m_archive_size = size; +- pZip->m_pRead = mz_zip_mem_read_func; +- pZip->m_pIO_opaque = pZip; +- pZip->m_pNeeds_keepalive = NULL; ++// if (!mz_zip_reader_init_internal(pZip, flags)) ++// return MZ_FALSE; + +-#ifdef __cplusplus +- pZip->m_pState->m_pMem = const_cast(pMem); +-#else +- pZip->m_pState->m_pMem = (void *)pMem; +-#endif ++// pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; ++// pZip->m_archive_size = size; ++// pZip->m_pRead = mz_zip_mem_read_func; ++// pZip->m_pIO_opaque = pZip; ++// pZip->m_pNeeds_keepalive = NULL; + +- pZip->m_pState->m_mem_size = size; ++// #ifdef __cplusplus ++// pZip->m_pState->m_pMem = const_cast(pMem); ++// #else ++// pZip->m_pState->m_pMem = (void *)pMem; ++// #endif + +- if (!mz_zip_reader_read_central_dir(pZip, flags)) +- { +- mz_zip_reader_end_internal(pZip, MZ_FALSE); +- return MZ_FALSE; +- } ++// pZip->m_pState->m_mem_size = size; + +- return MZ_TRUE; +-} ++// if (!mz_zip_reader_read_central_dir(pZip, flags)) ++// { ++// mz_zip_reader_end_internal(pZip, MZ_FALSE); ++// return MZ_FALSE; ++// } + +-#ifndef MINIZ_NO_STDIO +-static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +-{ +- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +- mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); ++// return MZ_TRUE; ++// } + +- file_ofs += pZip->m_pState->m_file_archive_start_ofs; ++// #ifndef MINIZ_NO_STDIO ++// static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) ++// { ++// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; ++// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + +- if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) +- return 0; ++// file_ofs += pZip->m_pState->m_file_archive_start_ofs; + +- return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); +-} ++// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) ++// return 0; + +-mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) +-{ +- return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); +-} ++// return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); ++// } + +-mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) +-{ +- mz_uint64 file_size; +- MZ_FILE *pFile; ++// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) ++// { ++// return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); ++// } + +- if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) ++// { ++// mz_uint64 file_size; ++// MZ_FILE *pFile; + +- pFile = MZ_FOPEN(pFilename, "rb"); +- if (!pFile) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); ++// if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- file_size = archive_size; +- if (!file_size) +- { +- if (MZ_FSEEK64(pFile, 0, SEEK_END)) +- { +- MZ_FCLOSE(pFile); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); +- } ++// pFile = MZ_FOPEN(pFilename, "rb"); ++// if (!pFile) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +- file_size = MZ_FTELL64(pFile); +- } ++// file_size = archive_size; ++// if (!file_size) ++// { ++// if (MZ_FSEEK64(pFile, 0, SEEK_END)) ++// { ++// MZ_FCLOSE(pFile); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); ++// } + +- /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ ++// file_size = MZ_FTELL64(pFile); ++// } + +- if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +- { +- MZ_FCLOSE(pFile); +- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); +- } ++// /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ + +- if (!mz_zip_reader_init_internal(pZip, flags)) +- { +- MZ_FCLOSE(pFile); +- return MZ_FALSE; +- } ++// if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// { ++// MZ_FCLOSE(pFile); ++// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); ++// } + +- pZip->m_zip_type = MZ_ZIP_TYPE_FILE; +- pZip->m_pRead = mz_zip_file_read_func; +- pZip->m_pIO_opaque = pZip; +- pZip->m_pState->m_pFile = pFile; +- pZip->m_archive_size = file_size; +- pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; ++// if (!mz_zip_reader_init_internal(pZip, flags)) ++// { ++// MZ_FCLOSE(pFile); ++// return MZ_FALSE; ++// } + +- if (!mz_zip_reader_read_central_dir(pZip, flags)) +- { +- mz_zip_reader_end_internal(pZip, MZ_FALSE); +- return MZ_FALSE; +- } ++// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; ++// pZip->m_pRead = mz_zip_file_read_func; ++// pZip->m_pIO_opaque = pZip; ++// pZip->m_pState->m_pFile = pFile; ++// pZip->m_archive_size = file_size; ++// pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; + +- return MZ_TRUE; +-} ++// if (!mz_zip_reader_read_central_dir(pZip, flags)) ++// { ++// mz_zip_reader_end_internal(pZip, MZ_FALSE); ++// return MZ_FALSE; ++// } + +-mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) +-{ +- mz_uint64 cur_file_ofs; ++// return MZ_TRUE; ++// } + +- if ((!pZip) || (!pFile)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); ++// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) ++// { ++// mz_uint64 cur_file_ofs; + +- cur_file_ofs = MZ_FTELL64(pFile); ++// if ((!pZip) || (!pFile)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +- if (!archive_size) +- { +- if (MZ_FSEEK64(pFile, 0, SEEK_END)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); ++// cur_file_ofs = MZ_FTELL64(pFile); + +- archive_size = MZ_FTELL64(pFile) - cur_file_ofs; ++// if (!archive_size) ++// { ++// if (MZ_FSEEK64(pFile, 0, SEEK_END)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + +- if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); +- } ++// archive_size = MZ_FTELL64(pFile) - cur_file_ofs; + +- if (!mz_zip_reader_init_internal(pZip, flags)) +- return MZ_FALSE; ++// if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); ++// } + +- pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; +- pZip->m_pRead = mz_zip_file_read_func; ++// if (!mz_zip_reader_init_internal(pZip, flags)) ++// return MZ_FALSE; + +- pZip->m_pIO_opaque = pZip; +- pZip->m_pState->m_pFile = pFile; +- pZip->m_archive_size = archive_size; +- pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; ++// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; ++// pZip->m_pRead = mz_zip_file_read_func; + +- if (!mz_zip_reader_read_central_dir(pZip, flags)) +- { +- mz_zip_reader_end_internal(pZip, MZ_FALSE); +- return MZ_FALSE; +- } ++// pZip->m_pIO_opaque = pZip; ++// pZip->m_pState->m_pFile = pFile; ++// pZip->m_archive_size = archive_size; ++// pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; + +- return MZ_TRUE; +-} ++// if (!mz_zip_reader_read_central_dir(pZip, flags)) ++// { ++// mz_zip_reader_end_internal(pZip, MZ_FALSE); ++// return MZ_FALSE; ++// } + +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// return MZ_TRUE; ++// } + +-static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) +-{ +- if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) +- return NULL; +- return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); +-} ++// #endif /* #ifndef MINIZ_NO_STDIO */ + +-mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) +-{ +- mz_uint m_bit_flag; +- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +- if (!p) +- { +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- return MZ_FALSE; +- } ++// static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) ++// { ++// if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) ++// return NULL; ++// return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); ++// } + +- m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); +- return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; +-} ++// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) ++// { ++// mz_uint m_bit_flag; ++// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); ++// if (!p) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return MZ_FALSE; ++// } + +-mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) +-{ +- mz_uint bit_flag; +- mz_uint method; ++// m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); ++// return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; ++// } + +- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +- if (!p) +- { +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- return MZ_FALSE; +- } ++// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) ++// { ++// mz_uint bit_flag; ++// mz_uint method; + +- method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +- bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); ++// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); ++// if (!p) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return MZ_FALSE; ++// } + +- if ((method != 0) && (method != MZ_DEFLATED)) +- { +- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); +- return MZ_FALSE; +- } ++// method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); ++// bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + +- if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) +- { +- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); +- return MZ_FALSE; +- } ++// if ((method != 0) && (method != MZ_DEFLATED)) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); ++// return MZ_FALSE; ++// } + +- if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) +- { +- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); +- return MZ_FALSE; +- } ++// if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); ++// return MZ_FALSE; ++// } + +- return MZ_TRUE; +-} ++// if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); ++// return MZ_FALSE; ++// } + +-mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) +-{ +- mz_uint filename_len, attribute_mapping_id, external_attr; +- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +- if (!p) +- { +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- return MZ_FALSE; +- } ++// return MZ_TRUE; ++// } + +- filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +- if (filename_len) +- { +- if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') +- return MZ_TRUE; +- } ++// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) ++// { ++// mz_uint filename_len, attribute_mapping_id, external_attr; ++// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); ++// if (!p) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return MZ_FALSE; ++// } ++ ++// filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// if (filename_len) ++// { ++// if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') ++// return MZ_TRUE; ++// } + + /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */ + /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */ + /* FIXME: Remove this check? Is it necessary - we already check the filename. */ +- attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; +- (void)attribute_mapping_id; ++// attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; ++// (void)attribute_mapping_id; + +- external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); +- if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) +- { +- return MZ_TRUE; +- } ++// external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); ++// if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) ++// { ++// return MZ_TRUE; ++// } + +- return MZ_FALSE; +-} ++// return MZ_FALSE; ++// } + +-static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) +-{ +- mz_uint n; +- const mz_uint8 *p = pCentral_dir_header; +- +- if (pFound_zip64_extra_data) +- *pFound_zip64_extra_data = MZ_FALSE; +- +- if ((!p) || (!pStat)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- +- /* Extract fields from the central directory record. */ +- pStat->m_file_index = file_index; +- pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); +- pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); +- pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); +- pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); +- pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +-#ifndef MINIZ_NO_TIME +- pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); +-#endif +- pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); +- pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); +- pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); +- pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); +- pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); +- pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); +- +- /* Copy as much of the filename and comment as possible. */ +- n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +- n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); +- memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); +- pStat->m_filename[n] = '\0'; +- +- n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); +- n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); +- pStat->m_comment_size = n; +- memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); +- pStat->m_comment[n] = '\0'; +- +- /* Set some flags for convienance */ +- pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); +- pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); +- pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); +- +- /* See if we need to read any zip64 extended information fields. */ +- /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ +- if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) +- { +- /* Attempt to find zip64 extended information field in the entry's extra data */ +- mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); ++// static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) ++// { ++// mz_uint n; ++// const mz_uint8 *p = pCentral_dir_header; + +- if (extra_size_remaining) +- { +- const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// if (pFound_zip64_extra_data) ++// *pFound_zip64_extra_data = MZ_FALSE; + +- do +- { +- mz_uint32 field_id; +- mz_uint32 field_data_size; ++// if ((!p) || (!pStat)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if (extra_size_remaining < (sizeof(mz_uint16) * 2)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// /* Extract fields from the central directory record. */ ++// pStat->m_file_index = file_index; ++// pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); ++// pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); ++// pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); ++// pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); ++// pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); ++// #ifndef MINIZ_NO_TIME ++// pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); ++// #endif ++// pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); ++// pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); ++// pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); ++// pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); ++// pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); ++// pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); ++ ++// /* Copy as much of the filename and comment as possible. */ ++// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); ++// memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); ++// pStat->m_filename[n] = '\0'; ++ ++// n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); ++// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); ++// pStat->m_comment_size = n; ++// memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); ++// pStat->m_comment[n] = '\0'; ++ ++// /* Set some flags for convienance */ ++// pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); ++// pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); ++// pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); ++ ++// /* See if we need to read any zip64 extended information fields. */ ++// /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ ++// if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) ++// { ++// /* Attempt to find zip64 extended information field in the entry's extra data */ ++// mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + +- field_id = MZ_READ_LE16(pExtra_data); +- field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); ++// if (extra_size_remaining) ++// { ++// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + +- if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// do ++// { ++// mz_uint32 field_id; ++// mz_uint32 field_data_size; + +- if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) +- { +- const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; +- mz_uint32 field_data_remaining = field_data_size; ++// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (pFound_zip64_extra_data) +- *pFound_zip64_extra_data = MZ_TRUE; ++// field_id = MZ_READ_LE16(pExtra_data); ++// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + +- if (pStat->m_uncomp_size == MZ_UINT32_MAX) +- { +- if (field_data_remaining < sizeof(mz_uint64)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- pStat->m_uncomp_size = MZ_READ_LE64(pField_data); +- pField_data += sizeof(mz_uint64); +- field_data_remaining -= sizeof(mz_uint64); +- } ++// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) ++// { ++// const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; ++// mz_uint32 field_data_remaining = field_data_size; ++ ++// if (pFound_zip64_extra_data) ++// *pFound_zip64_extra_data = MZ_TRUE; ++ ++// if (pStat->m_uncomp_size == MZ_UINT32_MAX) ++// { ++// if (field_data_remaining < sizeof(mz_uint64)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++ ++// pStat->m_uncomp_size = MZ_READ_LE64(pField_data); ++// pField_data += sizeof(mz_uint64); ++// field_data_remaining -= sizeof(mz_uint64); ++// } ++ ++// if (pStat->m_comp_size == MZ_UINT32_MAX) ++// { ++// if (field_data_remaining < sizeof(mz_uint64)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++ ++// pStat->m_comp_size = MZ_READ_LE64(pField_data); ++// pField_data += sizeof(mz_uint64); ++// field_data_remaining -= sizeof(mz_uint64); ++// } ++ ++// if (pStat->m_local_header_ofs == MZ_UINT32_MAX) ++// { ++// if (field_data_remaining < sizeof(mz_uint64)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++ ++// pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); ++// pField_data += sizeof(mz_uint64); ++// // field_data_remaining -= sizeof(mz_uint64); ++// } ++ ++// break; ++// } + +- if (pStat->m_comp_size == MZ_UINT32_MAX) +- { +- if (field_data_remaining < sizeof(mz_uint64)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; ++// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; ++// } while (extra_size_remaining); ++// } ++// } + +- pStat->m_comp_size = MZ_READ_LE64(pField_data); +- pField_data += sizeof(mz_uint64); +- field_data_remaining -= sizeof(mz_uint64); +- } ++// return MZ_TRUE; ++// } + +- if (pStat->m_local_header_ofs == MZ_UINT32_MAX) +- { +- if (field_data_remaining < sizeof(mz_uint64)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) ++// { ++// mz_uint i; ++// if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) ++// return 0 == memcmp(pA, pB, len); ++// for (i = 0; i < len; ++i) ++// if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) ++// return MZ_FALSE; ++// return MZ_TRUE; ++// } + +- pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); +- pField_data += sizeof(mz_uint64); +- // field_data_remaining -= sizeof(mz_uint64); +- } ++// static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) ++// { ++// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; ++// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// mz_uint8 l = 0, r = 0; ++// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; ++// pE = pL + MZ_MIN(l_len, r_len); ++// while (pL < pE) ++// { ++// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) ++// break; ++// pL++; ++// pR++; ++// } ++// return (pL == pE) ? (int)(l_len - r_len) : (l - r); ++// } + +- break; +- } ++// static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) ++// { ++// mz_zip_internal_state *pState = pZip->m_pState; ++// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; ++// const mz_zip_array *pCentral_dir = &pState->m_central_dir; ++// mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); ++// const uint32_t size = pZip->m_total_files; ++// const mz_uint filename_len = (mz_uint)strlen(pFilename); + +- pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; +- extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; +- } while (extra_size_remaining); +- } +- } ++// if (pIndex) ++// *pIndex = 0; + +- return MZ_TRUE; +-} ++// if (size) ++// { ++// /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ ++// /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ ++// mz_int64 l = 0, h = (mz_int64)size - 1; + +-static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) +-{ +- mz_uint i; +- if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) +- return 0 == memcmp(pA, pB, len); +- for (i = 0; i < len; ++i) +- if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) +- return MZ_FALSE; +- return MZ_TRUE; +-} ++// while (l <= h) ++// { ++// mz_int64 m = l + ((h - l) >> 1); ++// uint32_t file_index = pIndices[(uint32_t)m]; + +-static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) +-{ +- const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; +- mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); +- mz_uint8 l = 0, r = 0; +- pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +- pE = pL + MZ_MIN(l_len, r_len); +- while (pL < pE) +- { +- if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) +- break; +- pL++; +- pR++; +- } +- return (pL == pE) ? (int)(l_len - r_len) : (l - r); +-} ++// int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); ++// if (!comp) ++// { ++// if (pIndex) ++// *pIndex = file_index; ++// return MZ_TRUE; ++// } ++// else if (comp < 0) ++// l = m + 1; ++// else ++// h = m - 1; ++// } ++// } + +-static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) +-{ +- mz_zip_internal_state *pState = pZip->m_pState; +- const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; +- const mz_zip_array *pCentral_dir = &pState->m_central_dir; +- mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); +- const uint32_t size = pZip->m_total_files; +- const mz_uint filename_len = (mz_uint)strlen(pFilename); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); ++// } + +- if (pIndex) +- *pIndex = 0; ++// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) ++// { ++// mz_uint32 index_; ++// if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) ++// return -1; ++// else ++// return (int)index_; ++// } + +- if (size) +- { +- /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ +- /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ +- mz_int64 l = 0, h = (mz_int64)size - 1; ++// mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) ++// { ++// mz_uint file_index; ++// size_t name_len, comment_len; + +- while (l <= h) +- { +- mz_int64 m = l + ((h - l) >> 1); +- uint32_t file_index = pIndices[(uint32_t)m]; ++// if (pIndex) ++// *pIndex = 0; + +- int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); +- if (!comp) +- { +- if (pIndex) +- *pIndex = file_index; +- return MZ_TRUE; +- } +- else if (comp < 0) +- l = m + 1; +- else +- h = m - 1; +- } +- } ++// if ((!pZip) || (!pZip->m_pState) || (!pName)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +-} ++// /* See if we can use a binary search */ ++// if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && ++// (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && ++// ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) ++// { ++// return mz_zip_locate_file_binary_search(pZip, pName, pIndex); ++// } + +-int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) +-{ +- mz_uint32 index_; +- if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) +- return -1; +- else +- return (int)index_; +-} ++// /* Locate the entry by scanning the entire central directory */ ++// name_len = strlen(pName); ++// if (name_len > MZ_UINT16_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +-mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) +-{ +- mz_uint file_index; +- size_t name_len, comment_len; ++// comment_len = pComment ? strlen(pComment) : 0; ++// if (comment_len > MZ_UINT16_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if (pIndex) +- *pIndex = 0; ++// for (file_index = 0; file_index < pZip->m_total_files; file_index++) ++// { ++// const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); ++// mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; ++// if (filename_len < name_len) ++// continue; ++// if (comment_len) ++// { ++// mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); ++// const char *pFile_comment = pFilename + filename_len + file_extra_len; ++// if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) ++// continue; ++// } ++// if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) ++// { ++// int ofs = filename_len - 1; ++// do ++// { ++// if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) ++// break; ++// } while (--ofs >= 0); ++// ofs++; ++// pFilename += ofs; ++// filename_len -= ofs; ++// } ++// if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) ++// { ++// if (pIndex) ++// *pIndex = file_index; ++// return MZ_TRUE; ++// } ++// } + +- if ((!pZip) || (!pZip->m_pState) || (!pName)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); ++// } + +- /* See if we can use a binary search */ +- if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && +- (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && +- ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) +- { +- return mz_zip_locate_file_binary_search(pZip, pName, pIndex); +- } ++// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) ++// { ++// int status = TINFL_STATUS_DONE; ++// mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; ++// mz_zip_archive_file_stat file_stat; ++// void *pRead_buf; ++// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; ++// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; ++// tinfl_decompressor inflator; + +- /* Locate the entry by scanning the entire central directory */ +- name_len = strlen(pName); +- if (name_len > MZ_UINT16_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- comment_len = pComment ? strlen(pComment) : 0; +- if (comment_len > MZ_UINT16_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) ++// return MZ_FALSE; + +- for (file_index = 0; file_index < pZip->m_total_files; file_index++) +- { +- const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); +- mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); +- const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +- if (filename_len < name_len) +- continue; +- if (comment_len) +- { +- mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); +- const char *pFile_comment = pFilename + filename_len + file_extra_len; +- if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) +- continue; +- } +- if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) +- { +- int ofs = filename_len - 1; +- do +- { +- if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) +- break; +- } while (--ofs >= 0); +- ofs++; +- pFilename += ofs; +- filename_len -= ofs; +- } +- if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) +- { +- if (pIndex) +- *pIndex = file_index; +- return MZ_TRUE; +- } +- } ++// /* A directory or zero length file */ ++// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) ++// return MZ_TRUE; + +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +-} ++// /* Encryption and patch files are not supported. */ ++// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + +-mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +-{ +- int status = TINFL_STATUS_DONE; +- mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; +- mz_zip_archive_file_stat file_stat; +- void *pRead_buf; +- mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +- mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; +- tinfl_decompressor inflator; +- +- if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- +- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +- return MZ_FALSE; +- +- /* A directory or zero length file */ +- if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) +- return MZ_TRUE; +- +- /* Encryption and patch files are not supported. */ +- if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); +- +- /* This function only supports decompressing stored and deflate. */ +- if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); +- +- /* Ensure supplied output buffer is large enough. */ +- needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; +- if (buf_size < needed_size) +- return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); +- +- /* Read and parse the local directory entry. */ +- cur_file_ofs = file_stat.m_local_header_ofs; +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +- +- if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- +- cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +- if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- +- if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) +- { +- /* The file is stored or the caller has requested the compressed data. */ +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// /* This function only supports decompressing stored and deflate. */ ++// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) +- { +- if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) +- return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); +- } +-#endif ++// /* Ensure supplied output buffer is large enough. */ ++// needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; ++// if (buf_size < needed_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); + +- return MZ_TRUE; +- } ++// /* Read and parse the local directory entry. */ ++// cur_file_ofs = file_stat.m_local_header_ofs; ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +- /* Decompress the file either directly from memory or from a file input buffer. */ +- tinfl_init(&inflator); ++// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (pZip->m_pState->m_pMem) +- { +- /* Read directly from the archive in memory. */ +- pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; +- read_buf_size = read_buf_avail = file_stat.m_comp_size; +- comp_remaining = 0; +- } +- else if (pUser_read_buf) +- { +- /* Use a user provided read buffer. */ +- if (!user_read_buf_size) +- return MZ_FALSE; +- pRead_buf = (mz_uint8 *)pUser_read_buf; +- read_buf_size = user_read_buf_size; +- read_buf_avail = 0; +- comp_remaining = file_stat.m_comp_size; +- } +- else +- { +- /* Temporarily allocate a read buffer. */ +- read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); +- if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); ++// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) ++// { ++// /* The file is stored or the caller has requested the compressed data. */ ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +- read_buf_avail = 0; +- comp_remaining = file_stat.m_comp_size; +- } ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) ++// { ++// if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) ++// return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); ++// } ++// #endif + +- do +- { +- /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ +- size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); +- if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) +- { +- read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +- { +- status = TINFL_STATUS_FAILED; +- mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); +- break; +- } +- cur_file_ofs += read_buf_avail; +- comp_remaining -= read_buf_avail; +- read_buf_ofs = 0; +- } +- in_buf_size = (size_t)read_buf_avail; +- status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); +- read_buf_avail -= in_buf_size; +- read_buf_ofs += in_buf_size; +- out_buf_ofs += out_buf_size; +- } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); +- +- if (status == TINFL_STATUS_DONE) +- { +- /* Make sure the entire file was decompressed, and check its CRC. */ +- if (out_buf_ofs != file_stat.m_uncomp_size) +- { +- mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); +- status = TINFL_STATUS_FAILED; +- } +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) +- { +- mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); +- status = TINFL_STATUS_FAILED; +- } +-#endif +- } ++// return MZ_TRUE; ++// } + +- if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) +- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); ++// /* Decompress the file either directly from memory or from a file input buffer. */ ++// tinfl_init(&inflator); + +- return status == TINFL_STATUS_DONE; +-} ++// if (pZip->m_pState->m_pMem) ++// { ++// /* Read directly from the archive in memory. */ ++// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; ++// read_buf_size = read_buf_avail = file_stat.m_comp_size; ++// comp_remaining = 0; ++// } ++// else if (pUser_read_buf) ++// { ++// /* Use a user provided read buffer. */ ++// if (!user_read_buf_size) ++// return MZ_FALSE; ++// pRead_buf = (mz_uint8 *)pUser_read_buf; ++// read_buf_size = user_read_buf_size; ++// read_buf_avail = 0; ++// comp_remaining = file_stat.m_comp_size; ++// } ++// else ++// { ++// /* Temporarily allocate a read buffer. */ ++// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); ++// if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +-mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +-{ +- mz_uint32 file_index; +- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +- return MZ_FALSE; +- return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); +-} ++// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +-mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) +-{ +- return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); +-} ++// read_buf_avail = 0; ++// comp_remaining = file_stat.m_comp_size; ++// } + +-mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) +-{ +- return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); +-} ++// do ++// { ++// /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ ++// size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); ++// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) ++// { ++// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) ++// { ++// status = TINFL_STATUS_FAILED; ++// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); ++// break; ++// } ++// cur_file_ofs += read_buf_avail; ++// comp_remaining -= read_buf_avail; ++// read_buf_ofs = 0; ++// } ++// in_buf_size = (size_t)read_buf_avail; ++// status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); ++// read_buf_avail -= in_buf_size; ++// read_buf_ofs += in_buf_size; ++// out_buf_ofs += out_buf_size; ++// } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); ++ ++// if (status == TINFL_STATUS_DONE) ++// { ++// /* Make sure the entire file was decompressed, and check its CRC. */ ++// if (out_buf_ofs != file_stat.m_uncomp_size) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); ++// status = TINFL_STATUS_FAILED; ++// } ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); ++// status = TINFL_STATUS_FAILED; ++// } ++// #endif ++// } + +-void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) +-{ +- mz_uint64 comp_size, uncomp_size, alloc_size; +- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +- void *pBuf; ++// if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + +- if (pSize) +- *pSize = 0; ++// return status == TINFL_STATUS_DONE; ++// } + +- if (!p) +- { +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- return NULL; +- } ++// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) ++// { ++// mz_uint32 file_index; ++// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) ++// return MZ_FALSE; ++// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); ++// } + +- comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); +- uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); ++// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) ++// { ++// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); ++// } + +- alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; +- if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +- { +- mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); +- return NULL; +- } ++// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) ++// { ++// return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); ++// } + +- if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) +- { +- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- return NULL; +- } ++// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) ++// { ++// mz_uint64 comp_size, uncomp_size, alloc_size; ++// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); ++// void *pBuf; + +- if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); +- return NULL; +- } ++// if (pSize) ++// *pSize = 0; + +- if (pSize) +- *pSize = (size_t)alloc_size; +- return pBuf; +-} ++// if (!p) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return NULL; ++// } + +-void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) +-{ +- mz_uint32 file_index; +- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +- { +- if (pSize) +- *pSize = 0; +- return MZ_FALSE; +- } +- return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); +-} ++// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); ++// uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + +-mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +-{ +- int status = TINFL_STATUS_DONE; +- mz_uint file_crc32 = MZ_CRC32_INIT; +- mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; +- mz_zip_archive_file_stat file_stat; +- void *pRead_buf = NULL; +- void *pWrite_buf = NULL; +- mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +- mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; +- +- if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- +- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +- return MZ_FALSE; +- +- /* A directory or zero length file */ +- if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) +- return MZ_TRUE; +- +- /* Encryption and patch files are not supported. */ +- if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); +- +- /* This function only supports decompressing stored and deflate. */ +- if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); +- +- /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ +- cur_file_ofs = file_stat.m_local_header_ofs; +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +- +- if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- +- cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +- if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- +- /* Decompress the file either directly from memory or from a file input buffer. */ +- if (pZip->m_pState->m_pMem) +- { +- pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; +- read_buf_size = read_buf_avail = file_stat.m_comp_size; +- comp_remaining = 0; +- } +- else +- { +- read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); +- if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; ++// if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// return NULL; ++// } + +- read_buf_avail = 0; +- comp_remaining = file_stat.m_comp_size; +- } ++// if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// return NULL; ++// } + +- if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) +- { +- /* The file is stored or the caller has requested the compressed data. */ +- if (pZip->m_pState->m_pMem) +- { +- if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); ++// return NULL; ++// } + +- if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) +- { +- mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); +- status = TINFL_STATUS_FAILED; +- } +- else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +- { +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); +-#endif +- } ++// if (pSize) ++// *pSize = (size_t)alloc_size; ++// return pBuf; ++// } + +- cur_file_ofs += file_stat.m_comp_size; +- out_buf_ofs += file_stat.m_comp_size; +- comp_remaining = 0; +- } +- else +- { +- while (comp_remaining) +- { +- read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +- { +- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +- status = TINFL_STATUS_FAILED; +- break; +- } ++// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) ++// { ++// mz_uint32 file_index; ++// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) ++// { ++// if (pSize) ++// *pSize = 0; ++// return MZ_FALSE; ++// } ++// return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); ++// } + +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +- { +- file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); +- } +-#endif ++// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) ++// { ++// int status = TINFL_STATUS_DONE; ++// mz_uint file_crc32 = MZ_CRC32_INIT; ++// mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; ++// mz_zip_archive_file_stat file_stat; ++// void *pRead_buf = NULL; ++// void *pWrite_buf = NULL; ++// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; ++// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + +- if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +- { +- mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); +- status = TINFL_STATUS_FAILED; +- break; +- } ++// if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- cur_file_ofs += read_buf_avail; +- out_buf_ofs += read_buf_avail; +- comp_remaining -= read_buf_avail; +- } +- } +- } +- else +- { +- tinfl_decompressor inflator; +- tinfl_init(&inflator); ++// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) ++// return MZ_FALSE; + +- if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) +- { +- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- status = TINFL_STATUS_FAILED; +- } +- else +- { +- do +- { +- mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); +- size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); +- if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) +- { +- read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +- { +- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +- status = TINFL_STATUS_FAILED; +- break; +- } +- cur_file_ofs += read_buf_avail; +- comp_remaining -= read_buf_avail; +- read_buf_ofs = 0; +- } ++// /* A directory or zero length file */ ++// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) ++// return MZ_TRUE; + +- in_buf_size = (size_t)read_buf_avail; +- status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); +- read_buf_avail -= in_buf_size; +- read_buf_ofs += in_buf_size; ++// /* Encryption and patch files are not supported. */ ++// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + +- if (out_buf_size) +- { +- if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) +- { +- mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); +- status = TINFL_STATUS_FAILED; +- break; +- } ++// /* This function only supports decompressing stored and deflate. */ ++// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); +-#endif +- if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) +- { +- mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); +- status = TINFL_STATUS_FAILED; +- break; +- } +- } +- } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); +- } +- } ++// /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ ++// cur_file_ofs = file_stat.m_local_header_ofs; ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +- if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) +- { +- /* Make sure the entire file was decompressed, and check its CRC. */ +- if (out_buf_ofs != file_stat.m_uncomp_size) +- { +- mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); +- status = TINFL_STATUS_FAILED; +- } +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- else if (file_crc32 != file_stat.m_crc32) +- { +- mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); +- status = TINFL_STATUS_FAILED; +- } +-#endif +- } ++// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (!pZip->m_pState->m_pMem) +- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); ++// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); ++// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (pWrite_buf) +- pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); ++// /* Decompress the file either directly from memory or from a file input buffer. */ ++// if (pZip->m_pState->m_pMem) ++// { ++// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; ++// read_buf_size = read_buf_avail = file_stat.m_comp_size; ++// comp_remaining = 0; ++// } ++// else ++// { ++// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); ++// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +- return status == TINFL_STATUS_DONE; +-} ++// read_buf_avail = 0; ++// comp_remaining = file_stat.m_comp_size; ++// } + +-mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +-{ +- mz_uint32 file_index; +- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +- return MZ_FALSE; ++// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) ++// { ++// /* The file is stored or the caller has requested the compressed data. */ ++// if (pZip->m_pState->m_pMem) ++// { ++// if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +- return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); +-} ++// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); ++// status = TINFL_STATUS_FAILED; ++// } ++// else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) ++// { ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); ++// #endif ++// } + +-mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) +-{ +- mz_zip_reader_extract_iter_state *pState; +- mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +- mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; ++// cur_file_ofs += file_stat.m_comp_size; ++// out_buf_ofs += file_stat.m_comp_size; ++// comp_remaining = 0; ++// } ++// else ++// { ++// while (comp_remaining) ++// { ++// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// status = TINFL_STATUS_FAILED; ++// break; ++// } + +- /* Argument sanity check */ +- if ((!pZip) || (!pZip->m_pState)) +- return NULL; ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) ++// { ++// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); ++// } ++// #endif + +- /* Allocate an iterator status structure */ +- pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); +- if (!pState) +- { +- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- return NULL; +- } ++// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); ++// status = TINFL_STATUS_FAILED; ++// break; ++// } + +- /* Fetch file details */ +- if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } ++// cur_file_ofs += read_buf_avail; ++// out_buf_ofs += read_buf_avail; ++// comp_remaining -= read_buf_avail; ++// } ++// } ++// } ++// else ++// { ++// tinfl_decompressor inflator; ++// tinfl_init(&inflator); + +- /* Encryption and patch files are not supported. */ +- if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) +- { +- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } ++// if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// status = TINFL_STATUS_FAILED; ++// } ++// else ++// { ++// do ++// { ++// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); ++// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); ++// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) ++// { ++// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// status = TINFL_STATUS_FAILED; ++// break; ++// } ++// cur_file_ofs += read_buf_avail; ++// comp_remaining -= read_buf_avail; ++// read_buf_ofs = 0; ++// } + +- /* This function only supports decompressing stored and deflate. */ +- if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) +- { +- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } ++// in_buf_size = (size_t)read_buf_avail; ++// status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); ++// read_buf_avail -= in_buf_size; ++// read_buf_ofs += in_buf_size; + +- /* Init state - save args */ +- pState->pZip = pZip; +- pState->flags = flags; ++// if (out_buf_size) ++// { ++// if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); ++// status = TINFL_STATUS_FAILED; ++// break; ++// } ++ ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); ++// #endif ++// if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); ++// status = TINFL_STATUS_FAILED; ++// break; ++// } ++// } ++// } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); ++// } ++// } + +- /* Init state - reset variables to defaults */ +- pState->status = TINFL_STATUS_DONE; +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- pState->file_crc32 = MZ_CRC32_INIT; +-#endif +- pState->read_buf_ofs = 0; +- pState->out_buf_ofs = 0; +- pState->pRead_buf = NULL; +- pState->pWrite_buf = NULL; +- pState->out_blk_remain = 0; +- +- /* Read and parse the local directory entry. */ +- pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; +- if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +- { +- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } ++// if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) ++// { ++// /* Make sure the entire file was decompressed, and check its CRC. */ ++// if (out_buf_ofs != file_stat.m_uncomp_size) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); ++// status = TINFL_STATUS_FAILED; ++// } ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// else if (file_crc32 != file_stat.m_crc32) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); ++// status = TINFL_STATUS_FAILED; ++// } ++// #endif ++// } + +- if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +- { +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } ++// if (!pZip->m_pState->m_pMem) ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + +- pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +- if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) +- { +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } ++// if (pWrite_buf) ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + +- /* Decompress the file either directly from memory or from a file input buffer. */ +- if (pZip->m_pState->m_pMem) +- { +- pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; +- pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; +- pState->comp_remaining = pState->file_stat.m_comp_size; +- } +- else +- { +- if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) +- { +- /* Decompression required, therefore intermediate read buffer required */ +- pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); +- if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) +- { +- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } +- } +- else +- { +- /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ +- pState->read_buf_size = 0; +- } +- pState->read_buf_avail = 0; +- pState->comp_remaining = pState->file_stat.m_comp_size; +- } ++// return status == TINFL_STATUS_DONE; ++// } ++ ++// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) ++// { ++// mz_uint32 file_index; ++// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) ++// return MZ_FALSE; ++ ++// return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); ++// } ++ ++// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) ++// { ++// mz_zip_reader_extract_iter_state *pState; ++// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; ++// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; ++ ++// /* Argument sanity check */ ++// if ((!pZip) || (!pZip->m_pState)) ++// return NULL; ++ ++// /* Allocate an iterator status structure */ ++// pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); ++// if (!pState) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// return NULL; ++// } ++ ++// /* Fetch file details */ ++// if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } ++ ++// /* Encryption and patch files are not supported. */ ++// if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } ++ ++// /* This function only supports decompressing stored and deflate. */ ++// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } ++ ++// /* Init state - save args */ ++// pState->pZip = pZip; ++// pState->flags = flags; ++ ++// /* Init state - reset variables to defaults */ ++// pState->status = TINFL_STATUS_DONE; ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// pState->file_crc32 = MZ_CRC32_INIT; ++// #endif ++// pState->read_buf_ofs = 0; ++// pState->out_buf_ofs = 0; ++// pState->pRead_buf = NULL; ++// pState->pWrite_buf = NULL; ++// pState->out_blk_remain = 0; ++ ++// /* Read and parse the local directory entry. */ ++// pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; ++// if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } ++ ++// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } ++ ++// pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); ++// if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } + +- if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) +- { +- /* Decompression required, init decompressor */ +- tinfl_init( &pState->inflator ); ++// /* Decompress the file either directly from memory or from a file input buffer. */ ++// if (pZip->m_pState->m_pMem) ++// { ++// pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; ++// pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; ++// pState->comp_remaining = pState->file_stat.m_comp_size; ++// } ++// else ++// { ++// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) ++// { ++// /* Decompression required, therefore intermediate read buffer required */ ++// pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); ++// if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } ++// } ++// else ++// { ++// /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ ++// pState->read_buf_size = 0; ++// } ++// pState->read_buf_avail = 0; ++// pState->comp_remaining = pState->file_stat.m_comp_size; ++// } + +- /* Allocate write buffer */ +- if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) +- { +- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- if (pState->pRead_buf) +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } +- } ++// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) ++// { ++// /* Decompression required, init decompressor */ ++// tinfl_init( &pState->inflator ); + +- return pState; +-} ++// /* Allocate write buffer */ ++// if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// if (pState->pRead_buf) ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } ++// } + +-mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +-{ +- mz_uint32 file_index; ++// return pState; ++// } + +- /* Locate file index by name */ +- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +- return NULL; ++// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) ++// { ++// mz_uint32 file_index; + +- /* Construct iterator */ +- return mz_zip_reader_extract_iter_new(pZip, file_index, flags); +-} ++// /* Locate file index by name */ ++// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) ++// return NULL; + +-size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) +-{ +- size_t copied_to_caller = 0; ++// /* Construct iterator */ ++// return mz_zip_reader_extract_iter_new(pZip, file_index, flags); ++// } + +- /* Argument sanity check */ +- if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) +- return 0; ++// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) ++// { ++// size_t copied_to_caller = 0; + +- if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) +- { +- /* The file is stored or the caller has requested the compressed data, calc amount to return. */ +- copied_to_caller = MZ_MIN( buf_size, pState->comp_remaining ); ++// /* Argument sanity check */ ++// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) ++// return 0; + +- /* Zip is in memory....or requires reading from a file? */ +- if (pState->pZip->m_pState->m_pMem) +- { +- /* Copy data to caller's buffer */ +- memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); +- pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; +- } +- else +- { +- /* Read directly into caller's buffer */ +- if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) +- { +- /* Failed to read all that was asked for, flag failure and alert user */ +- mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); +- pState->status = TINFL_STATUS_FAILED; +- copied_to_caller = 0; +- } +- } ++// if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) ++// { ++// /* The file is stored or the caller has requested the compressed data, calc amount to return. */ ++// copied_to_caller = MZ_MIN( buf_size, pState->comp_remaining ); + +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- /* Compute CRC if not returning compressed data only */ +- if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +- pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); +-#endif ++// /* Zip is in memory....or requires reading from a file? */ ++// if (pState->pZip->m_pState->m_pMem) ++// { ++// /* Copy data to caller's buffer */ ++// memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); ++// pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; ++// } ++// else ++// { ++// /* Read directly into caller's buffer */ ++// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) ++// { ++// /* Failed to read all that was asked for, flag failure and alert user */ ++// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); ++// pState->status = TINFL_STATUS_FAILED; ++// copied_to_caller = 0; ++// } ++// } + +- /* Advance offsets, dec counters */ +- pState->cur_file_ofs += copied_to_caller; +- pState->out_buf_ofs += copied_to_caller; +- pState->comp_remaining -= copied_to_caller; +- } +- else +- { +- do +- { +- /* Calc ptr to write buffer - given current output pos and block size */ +- mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// /* Compute CRC if not returning compressed data only */ ++// if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) ++// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); ++// #endif + +- /* Calc max output size - given current output pos and block size */ +- size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); ++// /* Advance offsets, dec counters */ ++// pState->cur_file_ofs += copied_to_caller; ++// pState->out_buf_ofs += copied_to_caller; ++// pState->comp_remaining -= copied_to_caller; ++// } ++// else ++// { ++// do ++// { ++// /* Calc ptr to write buffer - given current output pos and block size */ ++// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + +- if (!pState->out_blk_remain) +- { +- /* Read more data from file if none available (and reading from file) */ +- if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) +- { +- /* Calc read size */ +- pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); +- if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) +- { +- mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); +- pState->status = TINFL_STATUS_FAILED; +- break; +- } ++// /* Calc max output size - given current output pos and block size */ ++// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + +- /* Advance offsets, dec counters */ +- pState->cur_file_ofs += pState->read_buf_avail; +- pState->comp_remaining -= pState->read_buf_avail; +- pState->read_buf_ofs = 0; +- } ++// if (!pState->out_blk_remain) ++// { ++// /* Read more data from file if none available (and reading from file) */ ++// if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) ++// { ++// /* Calc read size */ ++// pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); ++// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) ++// { ++// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); ++// pState->status = TINFL_STATUS_FAILED; ++// break; ++// } ++ ++// /* Advance offsets, dec counters */ ++// pState->cur_file_ofs += pState->read_buf_avail; ++// pState->comp_remaining -= pState->read_buf_avail; ++// pState->read_buf_ofs = 0; ++// } + +- /* Perform decompression */ +- in_buf_size = (size_t)pState->read_buf_avail; +- pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); +- pState->read_buf_avail -= in_buf_size; +- pState->read_buf_ofs += in_buf_size; ++// /* Perform decompression */ ++// in_buf_size = (size_t)pState->read_buf_avail; ++// pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); ++// pState->read_buf_avail -= in_buf_size; ++// pState->read_buf_ofs += in_buf_size; + +- /* Update current output block size remaining */ +- pState->out_blk_remain = out_buf_size; +- } ++// /* Update current output block size remaining */ ++// pState->out_blk_remain = out_buf_size; ++// } + +- if (pState->out_blk_remain) +- { +- /* Calc amount to return. */ +- size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); ++// if (pState->out_blk_remain) ++// { ++// /* Calc amount to return. */ ++// size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); + +- /* Copy data to caller's buffer */ +- memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); ++// /* Copy data to caller's buffer */ ++// memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); + +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- /* Perform CRC */ +- pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); +-#endif ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// /* Perform CRC */ ++// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); ++// #endif + +- /* Decrement data consumed from block */ +- pState->out_blk_remain -= to_copy; ++// /* Decrement data consumed from block */ ++// pState->out_blk_remain -= to_copy; + +- /* Inc output offset, while performing sanity check */ +- if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) +- { +- mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); +- pState->status = TINFL_STATUS_FAILED; +- break; +- } ++// /* Inc output offset, while performing sanity check */ ++// if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) ++// { ++// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); ++// pState->status = TINFL_STATUS_FAILED; ++// break; ++// } + +- /* Increment counter of data copied to caller */ +- copied_to_caller += to_copy; +- } +- } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); +- } ++// /* Increment counter of data copied to caller */ ++// copied_to_caller += to_copy; ++// } ++// } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); ++// } + +- /* Return how many bytes were copied into user buffer */ +- return copied_to_caller; +-} ++// /* Return how many bytes were copied into user buffer */ ++// return copied_to_caller; ++// } + +-mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) +-{ +- int status; ++// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) ++// { ++// int status; + +- /* Argument sanity check */ +- if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) +- return MZ_FALSE; ++// /* Argument sanity check */ ++// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) ++// return MZ_FALSE; + +- /* Was decompression completed and requested? */ +- if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) +- { +- /* Make sure the entire file was decompressed, and check its CRC. */ +- if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) +- { +- mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); +- pState->status = TINFL_STATUS_FAILED; +- } +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- else if (pState->file_crc32 != pState->file_stat.m_crc32) +- { +- mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); +- pState->status = TINFL_STATUS_FAILED; +- } +-#endif +- } ++// /* Was decompression completed and requested? */ ++// if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) ++// { ++// /* Make sure the entire file was decompressed, and check its CRC. */ ++// if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) ++// { ++// mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); ++// pState->status = TINFL_STATUS_FAILED; ++// } ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// else if (pState->file_crc32 != pState->file_stat.m_crc32) ++// { ++// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); ++// pState->status = TINFL_STATUS_FAILED; ++// } ++// #endif ++// } + +- /* Free buffers */ +- if (!pState->pZip->m_pState->m_pMem) +- pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); +- if (pState->pWrite_buf) +- pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); ++// /* Free buffers */ ++// if (!pState->pZip->m_pState->m_pMem) ++// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); ++// if (pState->pWrite_buf) ++// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); + +- /* Save status */ +- status = pState->status; ++// /* Save status */ ++// status = pState->status; + +- /* Free context */ +- pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); ++// /* Free context */ ++// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); + +- return status == TINFL_STATUS_DONE; +-} ++// return status == TINFL_STATUS_DONE; ++// } + +-#ifndef MINIZ_NO_STDIO +-static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) +-{ +- (void)ofs; ++// #ifndef MINIZ_NO_STDIO ++// static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) ++// { ++// (void)ofs; + +- return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); +-} ++// return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); ++// } + +-mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) +-{ +- mz_bool status; +- mz_zip_archive_file_stat file_stat; +- MZ_FILE *pFile; ++// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) ++// { ++// mz_bool status; ++// mz_zip_archive_file_stat file_stat; ++// MZ_FILE *pFile; + +- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +- return MZ_FALSE; ++// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) ++// return MZ_FALSE; + +- if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); ++// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + +- pFile = MZ_FOPEN(pDst_filename, "wb"); +- if (!pFile) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); ++// pFile = MZ_FOPEN(pDst_filename, "wb"); ++// if (!pFile) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +- status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); ++// status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); + +- if (MZ_FCLOSE(pFile) == EOF) +- { +- if (status) +- mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); ++// if (MZ_FCLOSE(pFile) == EOF) ++// { ++// if (status) ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); + +- status = MZ_FALSE; +- } ++// status = MZ_FALSE; ++// } + +-#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) +- if (status) +- mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); +-#endif ++// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) ++// if (status) ++// mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); ++// #endif + +- return status; +-} ++// return status; ++// } + +-mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) +-{ +- mz_uint32 file_index; +- if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) +- return MZ_FALSE; ++// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) ++// { ++// mz_uint32 file_index; ++// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) ++// return MZ_FALSE; + +- return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); +-} ++// return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); ++// } + +-mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) +-{ +- mz_zip_archive_file_stat file_stat; ++// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) ++// { ++// mz_zip_archive_file_stat file_stat; + +- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +- return MZ_FALSE; ++// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) ++// return MZ_FALSE; + +- if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); ++// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + +- return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); +-} ++// return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); ++// } + +-mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) +-{ +- mz_uint32 file_index; +- if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) +- return MZ_FALSE; ++// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) ++// { ++// mz_uint32 file_index; ++// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) ++// return MZ_FALSE; + +- return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); +-} +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); ++// } ++// #endif /* #ifndef MINIZ_NO_STDIO */ + + // static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) + // { +@@ -5444,1202 +5443,1202 @@ mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pA + + /* ------------------- .ZIP archive writing */ + +-#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS ++// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +-static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) +-{ +- p[0] = (mz_uint8)v; +- p[1] = (mz_uint8)(v >> 8); +-} +-static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) +-{ +- p[0] = (mz_uint8)v; +- p[1] = (mz_uint8)(v >> 8); +- p[2] = (mz_uint8)(v >> 16); +- p[3] = (mz_uint8)(v >> 24); +-} +-static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) +-{ +- mz_write_le32(p, (mz_uint32)v); +- mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); +-} ++// static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) ++// { ++// p[0] = (mz_uint8)v; ++// p[1] = (mz_uint8)(v >> 8); ++// } ++// static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) ++// { ++// p[0] = (mz_uint8)v; ++// p[1] = (mz_uint8)(v >> 8); ++// p[2] = (mz_uint8)(v >> 16); ++// p[3] = (mz_uint8)(v >> 24); ++// } ++// static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) ++// { ++// mz_write_le32(p, (mz_uint32)v); ++// mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); ++// } + +-#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) +-#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) +-#define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) ++// #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) ++// #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) ++// #define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) + +-static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +-{ +- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +- mz_zip_internal_state *pState = pZip->m_pState; +- mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); ++// static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) ++// { ++// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; ++// mz_zip_internal_state *pState = pZip->m_pState; ++// mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); + +- if (!n) +- return 0; ++// if (!n) ++// return 0; + +- /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ +- if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) +- { +- mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); +- return 0; +- } ++// /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ ++// if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); ++// return 0; ++// } + +- if (new_size > pState->m_mem_capacity) +- { +- void *pNew_block; +- size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); ++// if (new_size > pState->m_mem_capacity) ++// { ++// void *pNew_block; ++// size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); + +- while (new_capacity < new_size) +- new_capacity *= 2; ++// while (new_capacity < new_size) ++// new_capacity *= 2; + +- if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) +- { +- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- return 0; +- } ++// if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// return 0; ++// } + +- pState->m_pMem = pNew_block; +- pState->m_mem_capacity = new_capacity; +- } +- memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); +- pState->m_mem_size = (size_t)new_size; +- return n; +-} ++// pState->m_pMem = pNew_block; ++// pState->m_mem_capacity = new_capacity; ++// } ++// memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); ++// pState->m_mem_size = (size_t)new_size; ++// return n; ++// } + +-static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +-{ +- mz_zip_internal_state *pState; +- mz_bool status = MZ_TRUE; ++// static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) ++// { ++// mz_zip_internal_state *pState; ++// mz_bool status = MZ_TRUE; + +- if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) +- { +- if (set_last_error) +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- return MZ_FALSE; +- } ++// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) ++// { ++// if (set_last_error) ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return MZ_FALSE; ++// } + +- pState = pZip->m_pState; +- pZip->m_pState = NULL; +- mz_zip_array_clear(pZip, &pState->m_central_dir); +- mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); +- mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); ++// pState = pZip->m_pState; ++// pZip->m_pState = NULL; ++// mz_zip_array_clear(pZip, &pState->m_central_dir); ++// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); ++// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +-#ifndef MINIZ_NO_STDIO +- if (pState->m_pFile) +- { +- if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) +- { +- if (MZ_FCLOSE(pState->m_pFile) == EOF) +- { +- if (set_last_error) +- mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); +- status = MZ_FALSE; +- } +- } ++// #ifndef MINIZ_NO_STDIO ++// if (pState->m_pFile) ++// { ++// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) ++// { ++// if (MZ_FCLOSE(pState->m_pFile) == EOF) ++// { ++// if (set_last_error) ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); ++// status = MZ_FALSE; ++// } ++// } + +- pState->m_pFile = NULL; +- } +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// pState->m_pFile = NULL; ++// } ++// #endif /* #ifndef MINIZ_NO_STDIO */ + +- if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); +- pState->m_pMem = NULL; +- } ++// if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); ++// pState->m_pMem = NULL; ++// } + +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; +- return status; +-} ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; ++// return status; ++// } + +-mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) +-{ +- mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; ++// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) ++// { ++// mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; + +- if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +- { +- if (!pZip->m_pRead) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- } ++// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ++// { ++// if (!pZip->m_pRead) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// } + +- if (pZip->m_file_offset_alignment) +- { +- /* Ensure user specified file offset alignment is a power of 2. */ +- if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- } ++// if (pZip->m_file_offset_alignment) ++// { ++// /* Ensure user specified file offset alignment is a power of 2. */ ++// if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// } + +- if (!pZip->m_pAlloc) +- pZip->m_pAlloc = miniz_def_alloc_func; +- if (!pZip->m_pFree) +- pZip->m_pFree = miniz_def_free_func; +- if (!pZip->m_pRealloc) +- pZip->m_pRealloc = miniz_def_realloc_func; ++// if (!pZip->m_pAlloc) ++// pZip->m_pAlloc = miniz_def_alloc_func; ++// if (!pZip->m_pFree) ++// pZip->m_pFree = miniz_def_free_func; ++// if (!pZip->m_pRealloc) ++// pZip->m_pRealloc = miniz_def_realloc_func; + +- pZip->m_archive_size = existing_size; +- pZip->m_central_directory_file_ofs = 0; +- pZip->m_total_files = 0; ++// pZip->m_archive_size = existing_size; ++// pZip->m_central_directory_file_ofs = 0; ++// pZip->m_total_files = 0; + +- if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +- memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); ++// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + +- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); +- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); +- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); ++// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); ++// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); ++// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + +- pZip->m_pState->m_zip64 = zip64; +- pZip->m_pState->m_zip64_has_extended_info_fields = zip64; ++// pZip->m_pState->m_zip64 = zip64; ++// pZip->m_pState->m_zip64_has_extended_info_fields = zip64; + +- pZip->m_zip_type = MZ_ZIP_TYPE_USER; +- pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; ++// pZip->m_zip_type = MZ_ZIP_TYPE_USER; ++// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + +- return MZ_TRUE; +-} ++// return MZ_TRUE; ++// } + +-mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) +-{ +- return mz_zip_writer_init_v2(pZip, existing_size, 0); +-} ++// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) ++// { ++// return mz_zip_writer_init_v2(pZip, existing_size, 0); ++// } + +-mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) +-{ +- pZip->m_pWrite = mz_zip_heap_write_func; +- pZip->m_pNeeds_keepalive = NULL; ++// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) ++// { ++// pZip->m_pWrite = mz_zip_heap_write_func; ++// pZip->m_pNeeds_keepalive = NULL; + +- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +- pZip->m_pRead = mz_zip_mem_read_func; ++// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ++// pZip->m_pRead = mz_zip_mem_read_func; + +- pZip->m_pIO_opaque = pZip; ++// pZip->m_pIO_opaque = pZip; + +- if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) +- return MZ_FALSE; ++// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) ++// return MZ_FALSE; + +- pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; ++// pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; + +- if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) +- { +- if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) +- { +- mz_zip_writer_end_internal(pZip, MZ_FALSE); +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- } +- pZip->m_pState->m_mem_capacity = initial_allocation_size; +- } ++// if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) ++// { ++// if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) ++// { ++// mz_zip_writer_end_internal(pZip, MZ_FALSE); ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// } ++// pZip->m_pState->m_mem_capacity = initial_allocation_size; ++// } + +- return MZ_TRUE; +-} ++// return MZ_TRUE; ++// } + +-mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) +-{ +- return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); +-} ++// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) ++// { ++// return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); ++// } + +-#ifndef MINIZ_NO_STDIO +-static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +-{ +- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +- mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); ++// #ifndef MINIZ_NO_STDIO ++// static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) ++// { ++// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; ++// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + +- file_ofs += pZip->m_pState->m_file_archive_start_ofs; ++// file_ofs += pZip->m_pState->m_file_archive_start_ofs; + +- if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) +- { +- mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); +- return 0; +- } ++// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); ++// return 0; ++// } + +- return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); +-} ++// return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); ++// } + +-mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) +-{ +- return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); +-} ++// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) ++// { ++// return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); ++// } + +-mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) +-{ +- MZ_FILE *pFile; ++// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) ++// { ++// MZ_FILE *pFile; + +- pZip->m_pWrite = mz_zip_file_write_func; +- pZip->m_pNeeds_keepalive = NULL; ++// pZip->m_pWrite = mz_zip_file_write_func; ++// pZip->m_pNeeds_keepalive = NULL; + +- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +- pZip->m_pRead = mz_zip_file_read_func; ++// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ++// pZip->m_pRead = mz_zip_file_read_func; + +- pZip->m_pIO_opaque = pZip; ++// pZip->m_pIO_opaque = pZip; ++ ++// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) ++// return MZ_FALSE; ++ ++// if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) ++// { ++// mz_zip_writer_end(pZip); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); ++// } + +- if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) +- return MZ_FALSE; ++// pZip->m_pState->m_pFile = pFile; ++// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; + +- if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) +- { +- mz_zip_writer_end(pZip); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); +- } ++// if (size_to_reserve_at_beginning) ++// { ++// mz_uint64 cur_ofs = 0; ++// char buf[4096]; + +- pZip->m_pState->m_pFile = pFile; +- pZip->m_zip_type = MZ_ZIP_TYPE_FILE; ++// MZ_CLEAR_OBJ(buf); + +- if (size_to_reserve_at_beginning) +- { +- mz_uint64 cur_ofs = 0; +- char buf[4096]; ++// do ++// { ++// size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) ++// { ++// mz_zip_writer_end(pZip); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// } ++// cur_ofs += n; ++// size_to_reserve_at_beginning -= n; ++// } while (size_to_reserve_at_beginning); ++// } + +- MZ_CLEAR_OBJ(buf); ++// return MZ_TRUE; ++// } + +- do +- { +- size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) +- { +- mz_zip_writer_end(pZip); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- } +- cur_ofs += n; +- size_to_reserve_at_beginning -= n; +- } while (size_to_reserve_at_beginning); +- } ++// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) ++// { ++// pZip->m_pWrite = mz_zip_file_write_func; ++// pZip->m_pNeeds_keepalive = NULL; + +- return MZ_TRUE; +-} ++// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ++// pZip->m_pRead = mz_zip_file_read_func; + +-mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) +-{ +- pZip->m_pWrite = mz_zip_file_write_func; +- pZip->m_pNeeds_keepalive = NULL; ++// pZip->m_pIO_opaque = pZip; + +- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +- pZip->m_pRead = mz_zip_file_read_func; ++// if (!mz_zip_writer_init_v2(pZip, 0, flags)) ++// return MZ_FALSE; + +- pZip->m_pIO_opaque = pZip; ++// pZip->m_pState->m_pFile = pFile; ++// pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); ++// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; + +- if (!mz_zip_writer_init_v2(pZip, 0, flags)) +- return MZ_FALSE; ++// return MZ_TRUE; ++// } ++// #endif /* #ifndef MINIZ_NO_STDIO */ + +- pZip->m_pState->m_pFile = pFile; +- pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); +- pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; ++// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) ++// { ++// mz_zip_internal_state *pState; + +- return MZ_TRUE; +-} +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +-mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +-{ +- mz_zip_internal_state *pState; ++// if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) ++// { ++// /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ ++// if (!pZip->m_pState->m_zip64) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// } + +- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// /* No sense in trying to write to an archive that's already at the support max size */ ++// if (pZip->m_pState->m_zip64) ++// { ++// if (pZip->m_total_files == MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// } ++// else ++// { ++// if (pZip->m_total_files == MZ_UINT16_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + +- if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) +- { +- /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ +- if (!pZip->m_pState->m_zip64) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- } ++// if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); ++// } + +- /* No sense in trying to write to an archive that's already at the support max size */ +- if (pZip->m_pState->m_zip64) +- { +- if (pZip->m_total_files == MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +- } +- else +- { +- if (pZip->m_total_files == MZ_UINT16_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// pState = pZip->m_pState; + +- if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); +- } ++// if (pState->m_pFile) ++// { ++// #ifdef MINIZ_NO_STDIO ++// (void)pFilename; ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// #else ++// if (pZip->m_pIO_opaque != pZip) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- pState = pZip->m_pState; ++// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) ++// { ++// if (!pFilename) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if (pState->m_pFile) +- { +-#ifdef MINIZ_NO_STDIO +- (void)pFilename; +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +-#else +- if (pZip->m_pIO_opaque != pZip) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ ++// if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) ++// { ++// /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ ++// mz_zip_reader_end_internal(pZip, MZ_FALSE); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); ++// } ++// } + +- if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) +- { +- if (!pFilename) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// pZip->m_pWrite = mz_zip_file_write_func; ++// pZip->m_pNeeds_keepalive = NULL; ++// #endif /* #ifdef MINIZ_NO_STDIO */ ++// } ++// else if (pState->m_pMem) ++// { ++// /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ ++// if (pZip->m_pIO_opaque != pZip) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ +- if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) +- { +- /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ +- mz_zip_reader_end_internal(pZip, MZ_FALSE); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); +- } +- } ++// pState->m_mem_capacity = pState->m_mem_size; ++// pZip->m_pWrite = mz_zip_heap_write_func; ++// pZip->m_pNeeds_keepalive = NULL; ++// } ++// /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ ++// else if (!pZip->m_pWrite) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- pZip->m_pWrite = mz_zip_file_write_func; +- pZip->m_pNeeds_keepalive = NULL; +-#endif /* #ifdef MINIZ_NO_STDIO */ +- } +- else if (pState->m_pMem) +- { +- /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ +- if (pZip->m_pIO_opaque != pZip) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// /* Start writing new files at the archive's current central directory location. */ ++// /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ ++// pZip->m_archive_size = pZip->m_central_directory_file_ofs; ++// pZip->m_central_directory_file_ofs = 0; + +- pState->m_mem_capacity = pState->m_mem_size; +- pZip->m_pWrite = mz_zip_heap_write_func; +- pZip->m_pNeeds_keepalive = NULL; +- } +- /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ +- else if (!pZip->m_pWrite) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ ++// /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ ++// /* TODO: We could easily maintain the sorted central directory offsets. */ ++// mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); + +- /* Start writing new files at the archive's current central directory location. */ +- /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ +- pZip->m_archive_size = pZip->m_central_directory_file_ofs; +- pZip->m_central_directory_file_ofs = 0; ++// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + +- /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ +- /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ +- /* TODO: We could easily maintain the sorted central directory offsets. */ +- mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); ++// return MZ_TRUE; ++// } + +- pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; ++// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) ++// { ++// return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); ++// } + +- return MZ_TRUE; +-} ++/* TODO: pArchive_name is a terrible name here! */ ++// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) ++// { ++// return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); ++// } + +-mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) +-{ +- return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); +-} ++// typedef struct ++// { ++// mz_zip_archive *m_pZip; ++// mz_uint64 m_cur_archive_file_ofs; ++// mz_uint64 m_comp_size; ++// } mz_zip_writer_add_state; + +-/* TODO: pArchive_name is a terrible name here! */ +-mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) +-{ +- return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); +-} ++// static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) ++// { ++// mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; ++// if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) ++// return MZ_FALSE; + +-typedef struct +-{ +- mz_zip_archive *m_pZip; +- mz_uint64 m_cur_archive_file_ofs; +- mz_uint64 m_comp_size; +-} mz_zip_writer_add_state; ++// pState->m_cur_archive_file_ofs += len; ++// pState->m_comp_size += len; ++// return MZ_TRUE; ++// } + +-static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) +-{ +- mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; +- if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) +- return MZ_FALSE; ++// #define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) ++// #define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) ++// static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) ++// { ++// mz_uint8 *pDst = pBuf; ++// mz_uint32 field_size = 0; + +- pState->m_cur_archive_file_ofs += len; +- pState->m_comp_size += len; +- return MZ_TRUE; +-} ++// MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); ++// MZ_WRITE_LE16(pDst + 2, 0); ++// pDst += sizeof(mz_uint16) * 2; + +-#define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) +-#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) +-static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) +-{ +- mz_uint8 *pDst = pBuf; +- mz_uint32 field_size = 0; ++// if (pUncomp_size) ++// { ++// MZ_WRITE_LE64(pDst, *pUncomp_size); ++// pDst += sizeof(mz_uint64); ++// field_size += sizeof(mz_uint64); ++// } + +- MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); +- MZ_WRITE_LE16(pDst + 2, 0); +- pDst += sizeof(mz_uint16) * 2; ++// if (pComp_size) ++// { ++// MZ_WRITE_LE64(pDst, *pComp_size); ++// pDst += sizeof(mz_uint64); ++// field_size += sizeof(mz_uint64); ++// } + +- if (pUncomp_size) +- { +- MZ_WRITE_LE64(pDst, *pUncomp_size); +- pDst += sizeof(mz_uint64); +- field_size += sizeof(mz_uint64); +- } ++// if (pLocal_header_ofs) ++// { ++// MZ_WRITE_LE64(pDst, *pLocal_header_ofs); ++// pDst += sizeof(mz_uint64); ++// field_size += sizeof(mz_uint64); ++// } + +- if (pComp_size) +- { +- MZ_WRITE_LE64(pDst, *pComp_size); +- pDst += sizeof(mz_uint64); +- field_size += sizeof(mz_uint64); +- } ++// MZ_WRITE_LE16(pBuf + 2, field_size); + +- if (pLocal_header_ofs) +- { +- MZ_WRITE_LE64(pDst, *pLocal_header_ofs); +- pDst += sizeof(mz_uint64); +- field_size += sizeof(mz_uint64); +- } ++// return (mz_uint32)(pDst - pBuf); ++// } + +- MZ_WRITE_LE16(pBuf + 2, field_size); ++// static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) ++// { ++// (void)pZip; ++// memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); ++// return MZ_TRUE; ++// } + +- return (mz_uint32)(pDst - pBuf); +-} ++// static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, ++// mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, ++// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, ++// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, ++// mz_uint64 local_header_ofs, mz_uint32 ext_attributes) ++// { ++// (void)pZip; ++// memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); ++// return MZ_TRUE; ++// } + +-static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) +-{ +- (void)pZip; +- memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); +- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); +- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); +- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); +- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); +- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); +- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); +- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); +- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); +- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); +- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); +- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); +- return MZ_TRUE; +-} ++// static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, ++// const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, ++// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, ++// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, ++// mz_uint64 local_header_ofs, mz_uint32 ext_attributes, ++// const char *user_extra_data, mz_uint user_extra_data_len) ++// { ++// mz_zip_internal_state *pState = pZip->m_pState; ++// mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; ++// size_t orig_central_dir_size = pState->m_central_dir.m_size; ++// mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + +-static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, +- mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, +- mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, +- mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, +- mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +-{ +- (void)pZip; +- memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); +- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); +- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); +- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); +- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); +- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); +- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); +- return MZ_TRUE; +-} ++// if (!pZip->m_pState->m_zip64) ++// { ++// if (local_header_ofs > 0xFFFFFFFF) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); ++// } + +-static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, +- const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, +- mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, +- mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, +- mz_uint64 local_header_ofs, mz_uint32 ext_attributes, +- const char *user_extra_data, mz_uint user_extra_data_len) +-{ +- mz_zip_internal_state *pState = pZip->m_pState; +- mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; +- size_t orig_central_dir_size = pState->m_central_dir.m_size; +- mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; ++// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ ++// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +- if (!pZip->m_pState->m_zip64) +- { +- if (local_header_ofs > 0xFFFFFFFF) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); +- } ++// if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size + user_extra_data_len, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +- /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ +- if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); ++// if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || ++// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || ++// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || ++// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || ++// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || ++// (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) ++// { ++// /* Try to resize the central directory array back into its original state. */ ++// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// } + +- if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size + user_extra_data_len, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// return MZ_TRUE; ++// } + +- if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || +- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || +- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || +- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || +- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || +- (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) +- { +- /* Try to resize the central directory array back into its original state. */ +- mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- } ++// static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) ++// { ++// /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ ++// if (*pArchive_name == '/') ++// return MZ_FALSE; + +- return MZ_TRUE; +-} ++// while (*pArchive_name) ++// { ++// if ((*pArchive_name == '\\') || (*pArchive_name == ':')) ++// return MZ_FALSE; + +-static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) +-{ +- /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ +- if (*pArchive_name == '/') +- return MZ_FALSE; ++// pArchive_name++; ++// } + +- while (*pArchive_name) +- { +- if ((*pArchive_name == '\\') || (*pArchive_name == ':')) +- return MZ_FALSE; ++// return MZ_TRUE; ++// } + +- pArchive_name++; +- } ++// static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) ++// { ++// mz_uint32 n; ++// if (!pZip->m_file_offset_alignment) ++// return 0; ++// n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); ++// return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); ++// } + +- return MZ_TRUE; +-} ++// static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) ++// { ++// char buf[4096]; ++// memset(buf, 0, MZ_MIN(sizeof(buf), n)); ++// while (n) ++// { ++// mz_uint32 s = MZ_MIN(sizeof(buf), n); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +-static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) +-{ +- mz_uint32 n; +- if (!pZip->m_file_offset_alignment) +- return 0; +- n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); +- return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); +-} ++// cur_file_ofs += s; ++// n -= s; ++// } ++// return MZ_TRUE; ++// } + +-static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) +-{ +- char buf[4096]; +- memset(buf, 0, MZ_MIN(sizeof(buf), n)); +- while (n) +- { +- mz_uint32 s = MZ_MIN(sizeof(buf), n); +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, ++// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) ++// { ++// return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); ++// } + +- cur_file_ofs += s; +- n -= s; +- } +- return MZ_TRUE; +-} ++// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, ++// mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, ++// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) ++// { ++// if(!pZip) ++// { ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// } + +-mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +- mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) +-{ +- return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); +-} ++// mz_uint16 method = 0, dos_time = 0, dos_date = 0; ++// mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; ++// mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; ++// size_t archive_name_size; ++// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; ++// tdefl_compressor *pComp = NULL; ++// mz_bool store_data_uncompressed; ++// mz_zip_internal_state *pState; ++// mz_uint8 *pExtra_data = NULL; ++// mz_uint32 extra_size = 0; ++// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; ++// mz_uint16 bit_flags = 0; + +-mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, +- mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, +- const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +-{ +- if(!pZip) +- { +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- } ++// if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) ++// bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; + +- mz_uint16 method = 0, dos_time = 0, dos_date = 0; +- mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; +- mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; +- size_t archive_name_size; +- mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; +- tdefl_compressor *pComp = NULL; +- mz_bool store_data_uncompressed; +- mz_zip_internal_state *pState; +- mz_uint8 *pExtra_data = NULL; +- mz_uint32 extra_size = 0; +- mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; +- mz_uint16 bit_flags = 0; ++// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) ++// bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + +- if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) +- bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; ++// if ((int)level_and_flags < 0) ++// level_and_flags = MZ_DEFAULT_LEVEL; ++// level = level_and_flags & 0xF; ++// store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + +- if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) +- bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; ++// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if ((int)level_and_flags < 0) +- level_and_flags = MZ_DEFAULT_LEVEL; +- level = level_and_flags & 0xF; +- store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); ++// pState = pZip->m_pState; + +- if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if (pState->m_zip64) ++// { ++// if (pZip->m_total_files == MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// } ++// else ++// { ++// if (pZip->m_total_files == MZ_UINT16_MAX) ++// { ++// pState->m_zip64 = MZ_TRUE; ++// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ ++// } ++// if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) ++// { ++// pState->m_zip64 = MZ_TRUE; ++// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ ++// } ++// } + +- pState = pZip->m_pState; ++// if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if (pState->m_zip64) +- { +- if (pZip->m_total_files == MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +- } +- else +- { +- if (pZip->m_total_files == MZ_UINT16_MAX) +- { +- pState->m_zip64 = MZ_TRUE; +- /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ +- } +- if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) +- { +- pState->m_zip64 = MZ_TRUE; +- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +- } +- } ++// if (!mz_zip_writer_validate_archive_name(pArchive_name)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +- if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// #ifndef MINIZ_NO_TIME ++// if (last_modified != NULL) ++// { ++// mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); ++// } ++// else ++// { ++// MZ_TIME_T cur_time; ++// time(&cur_time); ++// mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); ++// } ++// #endif /* #ifndef MINIZ_NO_TIME */ + +- if (!mz_zip_writer_validate_archive_name(pArchive_name)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); ++// archive_name_size = strlen(pArchive_name); ++// if (archive_name_size > MZ_UINT16_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +-#ifndef MINIZ_NO_TIME +- if (last_modified != NULL) +- { +- mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); +- } +- else +- { +- MZ_TIME_T cur_time; +- time(&cur_time); +- mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); +- } +-#endif /* #ifndef MINIZ_NO_TIME */ ++// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + +- archive_name_size = strlen(pArchive_name); +- if (archive_name_size > MZ_UINT16_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); ++// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ ++// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +- num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); ++// if (!pState->m_zip64) ++// { ++// /* Bail early if the archive would obviously become too large */ ++// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size ++// + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + ++// pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len ++// + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) ++// { ++// pState->m_zip64 = MZ_TRUE; ++// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ ++// } ++// } + +- /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ +- if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); ++// if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) ++// { ++// /* Set DOS Subdirectory attribute bit. */ ++// ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; + +- if (!pState->m_zip64) +- { +- /* Bail early if the archive would obviously become too large */ +- if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size +- + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + +- pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len +- + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) +- { +- pState->m_zip64 = MZ_TRUE; +- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +- } +- } ++// /* Subdirectories cannot contain data. */ ++// if ((buf_size) || (uncomp_size)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// } + +- if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) +- { +- /* Set DOS Subdirectory attribute bit. */ +- ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; ++// /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ ++// if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +- /* Subdirectories cannot contain data. */ +- if ((buf_size) || (uncomp_size)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- } ++// if ((!store_data_uncompressed) && (buf_size)) ++// { ++// if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// } + +- /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ +- if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// return MZ_FALSE; ++// } + +- if ((!store_data_uncompressed) && (buf_size)) +- { +- if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- } ++// local_dir_header_ofs += num_alignment_padding_bytes; ++// if (pZip->m_file_offset_alignment) ++// { ++// MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); ++// } ++// cur_archive_file_ofs += num_alignment_padding_bytes; + +- if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +- return MZ_FALSE; +- } ++// MZ_CLEAR_OBJ(local_dir_header); + +- local_dir_header_ofs += num_alignment_padding_bytes; +- if (pZip->m_file_offset_alignment) +- { +- MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); +- } +- cur_archive_file_ofs += num_alignment_padding_bytes; ++// if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) ++// { ++// method = MZ_DEFLATED; ++// } + +- MZ_CLEAR_OBJ(local_dir_header); ++// if (pState->m_zip64) ++// { ++// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) ++// { ++// pExtra_data = extra_data; ++// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, ++// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); ++// } + +- if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +- { +- method = MZ_DEFLATED; +- } ++// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +- if (pState->m_zip64) +- { +- if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) +- { +- pExtra_data = extra_data; +- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +- } ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// cur_archive_file_ofs += sizeof(local_dir_header); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// } ++// cur_archive_file_ofs += archive_name_size; + +- cur_archive_file_ofs += sizeof(local_dir_header); ++// if (pExtra_data != NULL) ++// { ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- } +- cur_archive_file_ofs += archive_name_size; ++// cur_archive_file_ofs += extra_size; ++// } ++// } ++// else ++// { ++// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) ++// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); ++// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +- if (pExtra_data != NULL) +- { +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- cur_archive_file_ofs += extra_size; +- } +- } +- else +- { +- if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) +- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); +- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// cur_archive_file_ofs += sizeof(local_dir_header); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// } ++// cur_archive_file_ofs += archive_name_size; ++// } + +- cur_archive_file_ofs += sizeof(local_dir_header); ++// if (user_extra_data_len > 0) ++// { ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- } +- cur_archive_file_ofs += archive_name_size; +- } ++// cur_archive_file_ofs += user_extra_data_len; ++// } + +- if (user_extra_data_len > 0) +- { +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) ++// { ++// uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); ++// uncomp_size = buf_size; ++// if (uncomp_size <= 3) ++// { ++// level = 0; ++// store_data_uncompressed = MZ_TRUE; ++// } ++// } + +- cur_archive_file_ofs += user_extra_data_len; +- } ++// if (store_data_uncompressed) ++// { ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// } + +- if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +- { +- uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); +- uncomp_size = buf_size; +- if (uncomp_size <= 3) +- { +- level = 0; +- store_data_uncompressed = MZ_TRUE; +- } +- } ++// cur_archive_file_ofs += buf_size; ++// comp_size = buf_size; ++// } ++// else if (buf_size) ++// { ++// mz_zip_writer_add_state state; + +- if (store_data_uncompressed) +- { +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- } ++// state.m_pZip = pZip; ++// state.m_cur_archive_file_ofs = cur_archive_file_ofs; ++// state.m_comp_size = 0; + +- cur_archive_file_ofs += buf_size; +- comp_size = buf_size; +- } +- else if (buf_size) +- { +- mz_zip_writer_add_state state; ++// if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || ++// (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); ++// } + +- state.m_pZip = pZip; +- state.m_cur_archive_file_ofs = cur_archive_file_ofs; +- state.m_comp_size = 0; ++// comp_size = state.m_comp_size; ++// cur_archive_file_ofs = state.m_cur_archive_file_ofs; ++// } + +- if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || +- (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +- return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); +- } ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// pComp = NULL; + +- comp_size = state.m_comp_size; +- cur_archive_file_ofs = state.m_cur_archive_file_ofs; +- } ++// if (uncomp_size) ++// { ++// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; ++// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +- pComp = NULL; ++// MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); + +- if (uncomp_size) +- { +- mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; +- mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; ++// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); ++// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); ++// if (pExtra_data == NULL) ++// { ++// if (comp_size > MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +- MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); ++// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); ++// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); ++// } ++// else ++// { ++// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); ++// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); ++// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; ++// } + +- MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); +- MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); +- if (pExtra_data == NULL) +- { +- if (comp_size > MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) ++// return MZ_FALSE; + +- MZ_WRITE_LE32(local_dir_footer + 8, comp_size); +- MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); +- } +- else +- { +- MZ_WRITE_LE64(local_dir_footer + 8, comp_size); +- MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); +- local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; +- } ++// cur_archive_file_ofs += local_dir_footer_size; ++// } + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) +- return MZ_FALSE; ++// if (pExtra_data != NULL) ++// { ++// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, ++// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); ++// } + +- cur_archive_file_ofs += local_dir_footer_size; +- } ++// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, ++// comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, ++// user_extra_data_central, user_extra_data_central_len)) ++// return MZ_FALSE; + +- if (pExtra_data != NULL) +- { +- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +- } ++// pZip->m_total_files++; ++// pZip->m_archive_size = cur_archive_file_ofs; + +- if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, +- comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, +- user_extra_data_central, user_extra_data_central_len)) +- return MZ_FALSE; ++// return MZ_TRUE; ++// } + +- pZip->m_total_files++; +- pZip->m_archive_size = cur_archive_file_ofs; ++// #ifndef MINIZ_NO_STDIO ++// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, ++// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) ++// { ++// if(!pZip) ++// { ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// } + +- return MZ_TRUE; +-} ++// mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; ++// mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; ++// mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; ++// mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; ++// size_t archive_name_size; ++// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; ++// mz_uint8 *pExtra_data = NULL; ++// mz_uint32 extra_size = 0; ++// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; ++// mz_zip_internal_state *pState; + +-#ifndef MINIZ_NO_STDIO +-mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +- const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +-{ +- if(!pZip) +- { +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- } ++// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) ++// gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + +- mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; +- mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; +- mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; +- mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; +- size_t archive_name_size; +- mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; +- mz_uint8 *pExtra_data = NULL; +- mz_uint32 extra_size = 0; +- mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; +- mz_zip_internal_state *pState; ++// if ((int)level_and_flags < 0) ++// level_and_flags = MZ_DEFAULT_LEVEL; ++// level = level_and_flags & 0xF; + +- if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) +- gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; ++// /* Sanity checks */ ++// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if ((int)level_and_flags < 0) +- level_and_flags = MZ_DEFAULT_LEVEL; +- level = level_and_flags & 0xF; ++// pState = pZip->m_pState; + +- /* Sanity checks */ +- if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) ++// { ++// /* Source file is too large for non-zip64 */ ++// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ ++// pState->m_zip64 = MZ_TRUE; ++// } + +- pState = pZip->m_pState; ++// /* We could support this, but why? */ ++// if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) +- { +- /* Source file is too large for non-zip64 */ +- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +- pState->m_zip64 = MZ_TRUE; +- } ++// if (!mz_zip_writer_validate_archive_name(pArchive_name)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +- /* We could support this, but why? */ +- if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if (pState->m_zip64) ++// { ++// if (pZip->m_total_files == MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// } ++// else ++// { ++// if (pZip->m_total_files == MZ_UINT16_MAX) ++// { ++// pState->m_zip64 = MZ_TRUE; ++// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ ++// } ++// } + +- if (!mz_zip_writer_validate_archive_name(pArchive_name)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); ++// archive_name_size = strlen(pArchive_name); ++// if (archive_name_size > MZ_UINT16_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +- if (pState->m_zip64) +- { +- if (pZip->m_total_files == MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +- } +- else +- { +- if (pZip->m_total_files == MZ_UINT16_MAX) +- { +- pState->m_zip64 = MZ_TRUE; +- /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ +- } +- } ++// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + +- archive_name_size = strlen(pArchive_name); +- if (archive_name_size > MZ_UINT16_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); ++// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ ++// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +- num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); ++// if (!pState->m_zip64) ++// { ++// /* Bail early if the archive would obviously become too large */ ++// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE ++// + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 ++// + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) ++// { ++// pState->m_zip64 = MZ_TRUE; ++// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ ++// } ++// } + +- /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ +- if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); ++// #ifndef MINIZ_NO_TIME ++// if (pFile_time) ++// { ++// mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); ++// } ++// #endif + +- if (!pState->m_zip64) +- { +- /* Bail early if the archive would obviously become too large */ +- if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +- + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 +- + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) +- { +- pState->m_zip64 = MZ_TRUE; +- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +- } +- } ++// if (uncomp_size <= 3) ++// level = 0; + +-#ifndef MINIZ_NO_TIME +- if (pFile_time) +- { +- mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); +- } +-#endif ++// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) ++// { ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// } + +- if (uncomp_size <= 3) +- level = 0; ++// cur_archive_file_ofs += num_alignment_padding_bytes; ++// local_dir_header_ofs = cur_archive_file_ofs; + +- if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) +- { +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- } ++// if (pZip->m_file_offset_alignment) ++// { ++// MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); ++// } + +- cur_archive_file_ofs += num_alignment_padding_bytes; +- local_dir_header_ofs = cur_archive_file_ofs; ++// if (uncomp_size && level) ++// { ++// method = MZ_DEFLATED; ++// } + +- if (pZip->m_file_offset_alignment) +- { +- MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); +- } ++// MZ_CLEAR_OBJ(local_dir_header); ++// if (pState->m_zip64) ++// { ++// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) ++// { ++// pExtra_data = extra_data; ++// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, ++// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); ++// } + +- if (uncomp_size && level) +- { +- method = MZ_DEFLATED; +- } ++// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +- MZ_CLEAR_OBJ(local_dir_header); +- if (pState->m_zip64) +- { +- if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) +- { +- pExtra_data = extra_data; +- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +- } ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// cur_archive_file_ofs += sizeof(local_dir_header); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) ++// { ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// } + +- cur_archive_file_ofs += sizeof(local_dir_header); ++// cur_archive_file_ofs += archive_name_size; + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +- { +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- } ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- cur_archive_file_ofs += archive_name_size; ++// cur_archive_file_ofs += extra_size; ++// } ++// else ++// { ++// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) ++// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); ++// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- cur_archive_file_ofs += extra_size; +- } +- else +- { +- if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) +- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); +- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// cur_archive_file_ofs += sizeof(local_dir_header); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) ++// { ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// } + +- cur_archive_file_ofs += sizeof(local_dir_header); ++// cur_archive_file_ofs += archive_name_size; ++// } + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +- { +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- } ++// if (user_extra_data_len > 0) ++// { ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- cur_archive_file_ofs += archive_name_size; +- } ++// cur_archive_file_ofs += user_extra_data_len; ++// } + +- if (user_extra_data_len > 0) +- { +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (uncomp_size) ++// { ++// mz_uint64 uncomp_remaining = uncomp_size; ++// void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); ++// if (!pRead_buf) ++// { ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// } + +- cur_archive_file_ofs += user_extra_data_len; +- } ++// if (!level) ++// { ++// while (uncomp_remaining) ++// { ++// mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); ++// if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// } ++// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); ++// uncomp_remaining -= n; ++// cur_archive_file_ofs += n; ++// } ++// comp_size = uncomp_size; ++// } ++// else ++// { ++// mz_bool result = MZ_FALSE; ++// mz_zip_writer_add_state state; ++// tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); ++// if (!pComp) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// } + +- if (uncomp_size) +- { +- mz_uint64 uncomp_remaining = uncomp_size; +- void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); +- if (!pRead_buf) +- { +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- } ++// state.m_pZip = pZip; ++// state.m_cur_archive_file_ofs = cur_archive_file_ofs; ++// state.m_comp_size = 0; + +- if (!level) +- { +- while (uncomp_remaining) +- { +- mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); +- if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +- } +- uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); +- uncomp_remaining -= n; +- cur_archive_file_ofs += n; +- } +- comp_size = uncomp_size; +- } +- else +- { +- mz_bool result = MZ_FALSE; +- mz_zip_writer_add_state state; +- tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); +- if (!pComp) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- } ++// if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// } + +- state.m_pZip = pZip; +- state.m_cur_archive_file_ofs = cur_archive_file_ofs; +- state.m_comp_size = 0; ++// for (;;) ++// { ++// size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); ++// tdefl_status status; ++// tdefl_flush flush = TDEFL_NO_FLUSH; + +- if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); +- } ++// if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// break; ++// } + +- for (;;) +- { +- size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); +- tdefl_status status; +- tdefl_flush flush = TDEFL_NO_FLUSH; ++// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); ++// uncomp_remaining -= in_buf_size; + +- if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) +- { +- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +- break; +- } ++// if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) ++// flush = TDEFL_FULL_FLUSH; + +- uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); +- uncomp_remaining -= in_buf_size; ++// status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); ++// if (status == TDEFL_STATUS_DONE) ++// { ++// result = MZ_TRUE; ++// break; ++// } ++// else if (status != TDEFL_STATUS_OKAY) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); ++// break; ++// } ++// } + +- if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) +- flush = TDEFL_FULL_FLUSH; ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + +- status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); +- if (status == TDEFL_STATUS_DONE) +- { +- result = MZ_TRUE; +- break; +- } +- else if (status != TDEFL_STATUS_OKAY) +- { +- mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); +- break; +- } +- } ++// if (!result) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); ++// return MZ_FALSE; ++// } + +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// comp_size = state.m_comp_size; ++// cur_archive_file_ofs = state.m_cur_archive_file_ofs; ++// } + +- if (!result) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +- return MZ_FALSE; +- } ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); ++// } + +- comp_size = state.m_comp_size; +- cur_archive_file_ofs = state.m_cur_archive_file_ofs; +- } ++// { ++// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; ++// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + +- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +- } ++// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); ++// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); ++// if (pExtra_data == NULL) ++// { ++// if (comp_size > MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +- { +- mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; +- mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; ++// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); ++// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); ++// } ++// else ++// { ++// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); ++// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); ++// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; ++// } + +- MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); +- MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); +- if (pExtra_data == NULL) +- { +- if (comp_size > MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) ++// return MZ_FALSE; + +- MZ_WRITE_LE32(local_dir_footer + 8, comp_size); +- MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); +- } +- else +- { +- MZ_WRITE_LE64(local_dir_footer + 8, comp_size); +- MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); +- local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; +- } ++// cur_archive_file_ofs += local_dir_footer_size; ++// } + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) +- return MZ_FALSE; ++// if (pExtra_data != NULL) ++// { ++// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, ++// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); ++// } + +- cur_archive_file_ofs += local_dir_footer_size; +- } ++// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, ++// uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, ++// user_extra_data_central, user_extra_data_central_len)) ++// return MZ_FALSE; + +- if (pExtra_data != NULL) +- { +- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +- } ++// pZip->m_total_files++; ++// pZip->m_archive_size = cur_archive_file_ofs; + +- if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, +- uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, +- user_extra_data_central, user_extra_data_central_len)) +- return MZ_FALSE; ++// return MZ_TRUE; ++// } + +- pZip->m_total_files++; +- pZip->m_archive_size = cur_archive_file_ofs; ++// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) ++// { ++// MZ_FILE *pSrc_file = NULL; ++// mz_uint64 uncomp_size = 0; ++// MZ_TIME_T file_modified_time; ++// MZ_TIME_T *pFile_time = NULL; ++// mz_bool status; + +- return MZ_TRUE; +-} ++// memset(&file_modified_time, 0, sizeof(file_modified_time)); + +-mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +-{ +- MZ_FILE *pSrc_file = NULL; +- mz_uint64 uncomp_size = 0; +- MZ_TIME_T file_modified_time; +- MZ_TIME_T *pFile_time = NULL; +- mz_bool status; +- +- memset(&file_modified_time, 0, sizeof(file_modified_time)); +- +-#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) +- pFile_time = &file_modified_time; +- if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); +-#endif ++// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) ++// pFile_time = &file_modified_time; ++// if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); ++// #endif + +- pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); +- if (!pSrc_file) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); ++// pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); ++// if (!pSrc_file) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +- MZ_FSEEK64(pSrc_file, 0, SEEK_END); +- uncomp_size = MZ_FTELL64(pSrc_file); +- MZ_FSEEK64(pSrc_file, 0, SEEK_SET); ++// MZ_FSEEK64(pSrc_file, 0, SEEK_END); ++// uncomp_size = MZ_FTELL64(pSrc_file); ++// MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + +- status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); ++// status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); + +- MZ_FCLOSE(pSrc_file); ++// MZ_FCLOSE(pSrc_file); + +- return status; +-} +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// return status; ++// } ++// #endif /* #ifndef MINIZ_NO_STDIO */ + + // static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) + // { +@@ -7083,491 +7082,491 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, + // return MZ_TRUE; + // } + +-mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) +-{ +- mz_zip_internal_state *pState; +- mz_uint64 central_dir_ofs, central_dir_size; +- mz_uint8 hdr[256]; ++// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) ++// { ++// mz_zip_internal_state *pState; ++// mz_uint64 central_dir_ofs, central_dir_size; ++// mz_uint8 hdr[256]; + +- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- pState = pZip->m_pState; ++// pState = pZip->m_pState; + +- if (pState->m_zip64) +- { +- if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +- } +- else +- { +- if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +- } ++// if (pState->m_zip64) ++// { ++// if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// } ++// else ++// { ++// if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// } + +- central_dir_ofs = 0; +- central_dir_size = 0; +- if (pZip->m_total_files) +- { +- /* Write central directory */ +- central_dir_ofs = pZip->m_archive_size; +- central_dir_size = pState->m_central_dir.m_size; +- pZip->m_central_directory_file_ofs = central_dir_ofs; +- if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- +- pZip->m_archive_size += central_dir_size; +- } ++// central_dir_ofs = 0; ++// central_dir_size = 0; ++// if (pZip->m_total_files) ++// { ++// /* Write central directory */ ++// central_dir_ofs = pZip->m_archive_size; ++// central_dir_size = pState->m_central_dir.m_size; ++// pZip->m_central_directory_file_ofs = central_dir_ofs; ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- if (pState->m_zip64) +- { +- /* Write zip64 end of central directory header */ +- mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; +- +- MZ_CLEAR_OBJ(hdr); +- MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); +- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); +- MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ +- MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); +- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); +- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); +- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); +- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); +- if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- +- pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; +- +- /* Write zip64 end of central directory locator */ +- MZ_CLEAR_OBJ(hdr); +- MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); +- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); +- MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); +- if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- +- pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; +- } ++// pZip->m_archive_size += central_dir_size; ++// } + +- /* Write end of central directory record */ +- MZ_CLEAR_OBJ(hdr); +- MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); +- MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); +- MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); +- MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); +- MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); ++// if (pState->m_zip64) ++// { ++// /* Write zip64 end of central directory header */ ++// mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; ++ ++// MZ_CLEAR_OBJ(hdr); ++// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); ++// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); ++// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ ++// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); ++// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); ++// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); ++// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); ++// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; + +-#ifndef MINIZ_NO_STDIO +- if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// /* Write zip64 end of central directory locator */ ++// MZ_CLEAR_OBJ(hdr); ++// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); ++// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); ++// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; ++// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; ++// } + +- pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; +- return MZ_TRUE; +-} ++// /* Write end of central directory record */ ++// MZ_CLEAR_OBJ(hdr); ++// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); ++// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); ++// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); ++// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); ++// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); + +-mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) +-{ +- if ((!ppBuf) || (!pSize)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- *ppBuf = NULL; +- *pSize = 0; ++// #ifndef MINIZ_NO_STDIO ++// if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); ++// #endif /* #ifndef MINIZ_NO_STDIO */ + +- if ((!pZip) || (!pZip->m_pState)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; + +- if (pZip->m_pWrite != mz_zip_heap_write_func) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; ++// return MZ_TRUE; ++// } + +- if (!mz_zip_writer_finalize_archive(pZip)) +- return MZ_FALSE; ++// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) ++// { ++// if ((!ppBuf) || (!pSize)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- *ppBuf = pZip->m_pState->m_pMem; +- *pSize = pZip->m_pState->m_mem_size; +- pZip->m_pState->m_pMem = NULL; +- pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; ++// *ppBuf = NULL; ++// *pSize = 0; + +- return MZ_TRUE; +-} ++// if ((!pZip) || (!pZip->m_pState)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +-mz_bool mz_zip_writer_end(mz_zip_archive *pZip) +-{ +- return mz_zip_writer_end_internal(pZip, MZ_TRUE); +-} ++// if (pZip->m_pWrite != mz_zip_heap_write_func) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +-#ifndef MINIZ_NO_STDIO +-mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +-{ +- return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); +-} ++// if (!mz_zip_writer_finalize_archive(pZip)) ++// return MZ_FALSE; + +-mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) +-{ +- mz_bool status, created_new_archive = MZ_FALSE; +- mz_zip_archive zip_archive; +- struct MZ_FILE_STAT_STRUCT file_stat; +- mz_zip_error actual_err = MZ_ZIP_NO_ERROR; ++// *ppBuf = pZip->m_pState->m_pMem; ++// *pSize = pZip->m_pState->m_mem_size; ++// pZip->m_pState->m_pMem = NULL; ++// pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + +- mz_zip_zero_struct(&zip_archive); +- if ((int)level_and_flags < 0) +- level_and_flags = MZ_DEFAULT_LEVEL; ++// return MZ_TRUE; ++// } + +- if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) +- { +- if (pErr) +- *pErr = MZ_ZIP_INVALID_PARAMETER; +- return MZ_FALSE; +- } ++// mz_bool mz_zip_writer_end(mz_zip_archive *pZip) ++// { ++// return mz_zip_writer_end_internal(pZip, MZ_TRUE); ++// } + +- if (!mz_zip_writer_validate_archive_name(pArchive_name)) +- { +- if (pErr) +- *pErr = MZ_ZIP_INVALID_FILENAME; +- return MZ_FALSE; +- } ++// #ifndef MINIZ_NO_STDIO ++// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) ++// { ++// return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); ++// } + +- /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ +- /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ +- if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) +- { +- /* Create a new archive. */ +- if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) +- { +- if (pErr) +- *pErr = zip_archive.m_last_error; +- return MZ_FALSE; +- } ++// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) ++// { ++// mz_bool status, created_new_archive = MZ_FALSE; ++// mz_zip_archive zip_archive; ++// struct MZ_FILE_STAT_STRUCT file_stat; ++// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + +- created_new_archive = MZ_TRUE; +- } +- else +- { +- /* Append to an existing archive. */ +- if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) +- { +- if (pErr) +- *pErr = zip_archive.m_last_error; +- return MZ_FALSE; +- } ++// mz_zip_zero_struct(&zip_archive); ++// if ((int)level_and_flags < 0) ++// level_and_flags = MZ_DEFAULT_LEVEL; + +- if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) +- { +- if (pErr) +- *pErr = zip_archive.m_last_error; ++// if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) ++// { ++// if (pErr) ++// *pErr = MZ_ZIP_INVALID_PARAMETER; ++// return MZ_FALSE; ++// } + +- mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); ++// if (!mz_zip_writer_validate_archive_name(pArchive_name)) ++// { ++// if (pErr) ++// *pErr = MZ_ZIP_INVALID_FILENAME; ++// return MZ_FALSE; ++// } + +- return MZ_FALSE; +- } +- } ++// /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ ++// /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ ++// if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) ++// { ++// /* Create a new archive. */ ++// if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) ++// { ++// if (pErr) ++// *pErr = zip_archive.m_last_error; ++// return MZ_FALSE; ++// } + +- status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); +- actual_err = zip_archive.m_last_error; ++// created_new_archive = MZ_TRUE; ++// } ++// else ++// { ++// /* Append to an existing archive. */ ++// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) ++// { ++// if (pErr) ++// *pErr = zip_archive.m_last_error; ++// return MZ_FALSE; ++// } + +- /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ +- if (!mz_zip_writer_finalize_archive(&zip_archive)) +- { +- if (!actual_err) +- actual_err = zip_archive.m_last_error; ++// if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) ++// { ++// if (pErr) ++// *pErr = zip_archive.m_last_error; + +- status = MZ_FALSE; +- } ++// mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); + +- if (!mz_zip_writer_end_internal(&zip_archive, status)) +- { +- if (!actual_err) +- actual_err = zip_archive.m_last_error; ++// return MZ_FALSE; ++// } ++// } + +- status = MZ_FALSE; +- } ++// status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); ++// actual_err = zip_archive.m_last_error; + +- if ((!status) && (created_new_archive)) +- { +- /* It's a new archive and something went wrong, so just delete it. */ +- int ignoredStatus = MZ_DELETE_FILE(pZip_filename); +- (void)ignoredStatus; +- } ++// /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ ++// if (!mz_zip_writer_finalize_archive(&zip_archive)) ++// { ++// if (!actual_err) ++// actual_err = zip_archive.m_last_error; + +- if (pErr) +- *pErr = actual_err; ++// status = MZ_FALSE; ++// } + +- return status; +-} ++// if (!mz_zip_writer_end_internal(&zip_archive, status)) ++// { ++// if (!actual_err) ++// actual_err = zip_archive.m_last_error; + +-void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) +-{ +- mz_uint32 file_index; +- mz_zip_archive zip_archive; +- void *p = NULL; ++// status = MZ_FALSE; ++// } + +- if (pSize) +- *pSize = 0; ++// if ((!status) && (created_new_archive)) ++// { ++// /* It's a new archive and something went wrong, so just delete it. */ ++// int ignoredStatus = MZ_DELETE_FILE(pZip_filename); ++// (void)ignoredStatus; ++// } + +- if ((!pZip_filename) || (!pArchive_name)) +- { +- if (pErr) +- *pErr = MZ_ZIP_INVALID_PARAMETER; ++// if (pErr) ++// *pErr = actual_err; + +- return NULL; +- } ++// return status; ++// } + +- mz_zip_zero_struct(&zip_archive); +- if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) +- { +- if (pErr) +- *pErr = zip_archive.m_last_error; ++// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) ++// { ++// mz_uint32 file_index; ++// mz_zip_archive zip_archive; ++// void *p = NULL; + +- return NULL; +- } ++// if (pSize) ++// *pSize = 0; + +- if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) +- { +- p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); +- } ++// if ((!pZip_filename) || (!pArchive_name)) ++// { ++// if (pErr) ++// *pErr = MZ_ZIP_INVALID_PARAMETER; + +- mz_zip_reader_end_internal(&zip_archive, p != NULL); ++// return NULL; ++// } + +- if (pErr) +- *pErr = zip_archive.m_last_error; ++// mz_zip_zero_struct(&zip_archive); ++// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) ++// { ++// if (pErr) ++// *pErr = zip_archive.m_last_error; + +- return p; +-} ++// return NULL; ++// } + +-void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) +-{ +- return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); +-} ++// if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) ++// { ++// p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); ++// } ++ ++// mz_zip_reader_end_internal(&zip_archive, p != NULL); ++ ++// if (pErr) ++// *pErr = zip_archive.m_last_error; ++ ++// return p; ++// } ++ ++// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) ++// { ++// return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); ++// } + +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// #endif /* #ifndef MINIZ_NO_STDIO */ + +-#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ ++// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + + /* ------------------- Misc utils */ + +-mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) +-{ +- return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; +-} ++// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) ++// { ++// return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; ++// } + +-mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) +-{ +- return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; +-} ++// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) ++// { ++// return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; ++// } + +-mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) +-{ +- mz_zip_error prev_err; ++// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) ++// { ++// mz_zip_error prev_err; + +- if (!pZip) +- return MZ_ZIP_INVALID_PARAMETER; ++// if (!pZip) ++// return MZ_ZIP_INVALID_PARAMETER; + +- prev_err = pZip->m_last_error; ++// prev_err = pZip->m_last_error; + +- pZip->m_last_error = err_num; +- return prev_err; +-} ++// pZip->m_last_error = err_num; ++// return prev_err; ++// } + +-mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) +-{ +- if (!pZip) +- return MZ_ZIP_INVALID_PARAMETER; ++// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) ++// { ++// if (!pZip) ++// return MZ_ZIP_INVALID_PARAMETER; + +- return pZip->m_last_error; +-} ++// return pZip->m_last_error; ++// } + +-mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) +-{ +- return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); +-} ++// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) ++// { ++// return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); ++// } + +-mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) +-{ +- mz_zip_error prev_err; ++// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) ++// { ++// mz_zip_error prev_err; + +- if (!pZip) +- return MZ_ZIP_INVALID_PARAMETER; ++// if (!pZip) ++// return MZ_ZIP_INVALID_PARAMETER; + +- prev_err = pZip->m_last_error; ++// prev_err = pZip->m_last_error; + +- pZip->m_last_error = MZ_ZIP_NO_ERROR; +- return prev_err; +-} ++// pZip->m_last_error = MZ_ZIP_NO_ERROR; ++// return prev_err; ++// } + +-const char *mz_zip_get_error_string(mz_zip_error mz_err) +-{ +- switch (mz_err) +- { +- case MZ_ZIP_NO_ERROR: +- return "no error"; +- case MZ_ZIP_UNDEFINED_ERROR: +- return "undefined error"; +- case MZ_ZIP_TOO_MANY_FILES: +- return "too many files"; +- case MZ_ZIP_FILE_TOO_LARGE: +- return "file too large"; +- case MZ_ZIP_UNSUPPORTED_METHOD: +- return "unsupported method"; +- case MZ_ZIP_UNSUPPORTED_ENCRYPTION: +- return "unsupported encryption"; +- case MZ_ZIP_UNSUPPORTED_FEATURE: +- return "unsupported feature"; +- case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: +- return "failed finding central directory"; +- case MZ_ZIP_NOT_AN_ARCHIVE: +- return "not a ZIP archive"; +- case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: +- return "invalid header or archive is corrupted"; +- case MZ_ZIP_UNSUPPORTED_MULTIDISK: +- return "unsupported multidisk archive"; +- case MZ_ZIP_DECOMPRESSION_FAILED: +- return "decompression failed or archive is corrupted"; +- case MZ_ZIP_COMPRESSION_FAILED: +- return "compression failed"; +- case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: +- return "unexpected decompressed size"; +- case MZ_ZIP_CRC_CHECK_FAILED: +- return "CRC-32 check failed"; +- case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: +- return "unsupported central directory size"; +- case MZ_ZIP_ALLOC_FAILED: +- return "allocation failed"; +- case MZ_ZIP_FILE_OPEN_FAILED: +- return "file open failed"; +- case MZ_ZIP_FILE_CREATE_FAILED: +- return "file create failed"; +- case MZ_ZIP_FILE_WRITE_FAILED: +- return "file write failed"; +- case MZ_ZIP_FILE_READ_FAILED: +- return "file read failed"; +- case MZ_ZIP_FILE_CLOSE_FAILED: +- return "file close failed"; +- case MZ_ZIP_FILE_SEEK_FAILED: +- return "file seek failed"; +- case MZ_ZIP_FILE_STAT_FAILED: +- return "file stat failed"; +- case MZ_ZIP_INVALID_PARAMETER: +- return "invalid parameter"; +- case MZ_ZIP_INVALID_FILENAME: +- return "invalid filename"; +- case MZ_ZIP_BUF_TOO_SMALL: +- return "buffer too small"; +- case MZ_ZIP_INTERNAL_ERROR: +- return "internal error"; +- case MZ_ZIP_FILE_NOT_FOUND: +- return "file not found"; +- case MZ_ZIP_ARCHIVE_TOO_LARGE: +- return "archive is too large"; +- case MZ_ZIP_VALIDATION_FAILED: +- return "validation failed"; +- case MZ_ZIP_WRITE_CALLBACK_FAILED: +- return "write calledback failed"; +- default: +- break; +- } ++// const char *mz_zip_get_error_string(mz_zip_error mz_err) ++// { ++// switch (mz_err) ++// { ++// case MZ_ZIP_NO_ERROR: ++// return "no error"; ++// case MZ_ZIP_UNDEFINED_ERROR: ++// return "undefined error"; ++// case MZ_ZIP_TOO_MANY_FILES: ++// return "too many files"; ++// case MZ_ZIP_FILE_TOO_LARGE: ++// return "file too large"; ++// case MZ_ZIP_UNSUPPORTED_METHOD: ++// return "unsupported method"; ++// case MZ_ZIP_UNSUPPORTED_ENCRYPTION: ++// return "unsupported encryption"; ++// case MZ_ZIP_UNSUPPORTED_FEATURE: ++// return "unsupported feature"; ++// case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: ++// return "failed finding central directory"; ++// case MZ_ZIP_NOT_AN_ARCHIVE: ++// return "not a ZIP archive"; ++// case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: ++// return "invalid header or archive is corrupted"; ++// case MZ_ZIP_UNSUPPORTED_MULTIDISK: ++// return "unsupported multidisk archive"; ++// case MZ_ZIP_DECOMPRESSION_FAILED: ++// return "decompression failed or archive is corrupted"; ++// case MZ_ZIP_COMPRESSION_FAILED: ++// return "compression failed"; ++// case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: ++// return "unexpected decompressed size"; ++// case MZ_ZIP_CRC_CHECK_FAILED: ++// return "CRC-32 check failed"; ++// case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: ++// return "unsupported central directory size"; ++// case MZ_ZIP_ALLOC_FAILED: ++// return "allocation failed"; ++// case MZ_ZIP_FILE_OPEN_FAILED: ++// return "file open failed"; ++// case MZ_ZIP_FILE_CREATE_FAILED: ++// return "file create failed"; ++// case MZ_ZIP_FILE_WRITE_FAILED: ++// return "file write failed"; ++// case MZ_ZIP_FILE_READ_FAILED: ++// return "file read failed"; ++// case MZ_ZIP_FILE_CLOSE_FAILED: ++// return "file close failed"; ++// case MZ_ZIP_FILE_SEEK_FAILED: ++// return "file seek failed"; ++// case MZ_ZIP_FILE_STAT_FAILED: ++// return "file stat failed"; ++// case MZ_ZIP_INVALID_PARAMETER: ++// return "invalid parameter"; ++// case MZ_ZIP_INVALID_FILENAME: ++// return "invalid filename"; ++// case MZ_ZIP_BUF_TOO_SMALL: ++// return "buffer too small"; ++// case MZ_ZIP_INTERNAL_ERROR: ++// return "internal error"; ++// case MZ_ZIP_FILE_NOT_FOUND: ++// return "file not found"; ++// case MZ_ZIP_ARCHIVE_TOO_LARGE: ++// return "archive is too large"; ++// case MZ_ZIP_VALIDATION_FAILED: ++// return "validation failed"; ++// case MZ_ZIP_WRITE_CALLBACK_FAILED: ++// return "write calledback failed"; ++// default: ++// break; ++// } + +- return "unknown error"; +-} ++// return "unknown error"; ++// } + + /* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */ +-mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) +-{ +- if ((!pZip) || (!pZip->m_pState)) +- return MZ_FALSE; ++// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) ++// { ++// if ((!pZip) || (!pZip->m_pState)) ++// return MZ_FALSE; + +- return pZip->m_pState->m_zip64; +-} ++// return pZip->m_pState->m_zip64; ++// } + +-size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) +-{ +- if ((!pZip) || (!pZip->m_pState)) +- return 0; ++// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) ++// { ++// if ((!pZip) || (!pZip->m_pState)) ++// return 0; + +- return pZip->m_pState->m_central_dir.m_size; +-} ++// return pZip->m_pState->m_central_dir.m_size; ++// } + +-mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) +-{ +- return pZip ? pZip->m_total_files : 0; +-} ++// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) ++// { ++// return pZip ? pZip->m_total_files : 0; ++// } + +-mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) +-{ +- if (!pZip) +- return 0; +- return pZip->m_archive_size; +-} ++// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) ++// { ++// if (!pZip) ++// return 0; ++// return pZip->m_archive_size; ++// } + +-mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) +-{ +- if ((!pZip) || (!pZip->m_pState)) +- return 0; +- return pZip->m_pState->m_file_archive_start_ofs; +-} ++// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) ++// { ++// if ((!pZip) || (!pZip->m_pState)) ++// return 0; ++// return pZip->m_pState->m_file_archive_start_ofs; ++// } + +-MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) +-{ +- if ((!pZip) || (!pZip->m_pState)) +- return 0; +- return pZip->m_pState->m_pFile; +-} ++// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) ++// { ++// if ((!pZip) || (!pZip->m_pState)) ++// return 0; ++// return pZip->m_pState->m_pFile; ++// } + +-size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) +-{ +- if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) ++// { ++// if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); +-} ++// return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); ++// } + +-mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) +-{ +- mz_uint n; +- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +- if (!p) +- { +- if (filename_buf_size) +- pFilename[0] = '\0'; +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- return 0; +- } +- n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +- if (filename_buf_size) +- { +- n = MZ_MIN(n, filename_buf_size - 1); +- memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); +- pFilename[n] = '\0'; +- } +- return n + 1; +-} ++// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) ++// { ++// mz_uint n; ++// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); ++// if (!p) ++// { ++// if (filename_buf_size) ++// pFilename[0] = '\0'; ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return 0; ++// } ++// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// if (filename_buf_size) ++// { ++// n = MZ_MIN(n, filename_buf_size - 1); ++// memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); ++// pFilename[n] = '\0'; ++// } ++// return n + 1; ++// } + +-mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) +-{ +- return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); +-} ++// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) ++// { ++// return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); ++// } + +-mz_bool mz_zip_end(mz_zip_archive *pZip) +-{ +- if (!pZip) +- return MZ_FALSE; +- +- if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) +- return mz_zip_reader_end(pZip); +-#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +- else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) +- return mz_zip_writer_end(pZip); +-#endif ++// mz_bool mz_zip_end(mz_zip_archive *pZip) ++// { ++// if (!pZip) ++// return MZ_FALSE; + +- return MZ_FALSE; +-} ++// if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) ++// return mz_zip_reader_end(pZip); ++// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS ++// else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) ++// return mz_zip_writer_end(pZip); ++// #endif + +-#ifdef __cplusplus +-} +-#endif ++// return MZ_FALSE; ++// } ++ ++// #ifdef __cplusplus ++// } ++// #endif + +-#endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ ++// #endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ diff --git a/gomspace/libutil/src/zip/miniz/miniz.c b/gomspace/libutil/src/zip/miniz/miniz.c new file mode 100644 index 00000000..910d4b1f --- /dev/null +++ b/gomspace/libutil/src/zip/miniz/miniz.c @@ -0,0 +1,7572 @@ +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +#include "miniz.h" + +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- zlib-style API's */ + +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) +{ + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); + size_t block_len = buf_len % 5552; + if (!ptr) + return MZ_ADLER32_INIT; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) + s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + return (s2 << 16) + s1; +} + +/* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */ +// #if 0 +// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +// { +// static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, +// 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; +// mz_uint32 crcu32 = (mz_uint32)crc; +// if (!ptr) +// return MZ_CRC32_INIT; +// crcu32 = ~crcu32; +// while (buf_len--) +// { +// mz_uint8 b = *ptr++; +// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; +// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; +// } +// return ~crcu32; +// } +// #else +/* Faster, but larger CPU cache footprint. + */ +// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +// { +// static const mz_uint32 s_crc_table[256] = +// { +// 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, +// 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, +// 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, +// 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, +// 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, +// 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, +// 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, +// 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, +// 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, +// 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, +// 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, +// 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, +// 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, +// 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, +// 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, +// 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, +// 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, +// 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, +// 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, +// 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, +// 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, +// 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, +// 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, +// 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, +// 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, +// 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, +// 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, +// 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, +// 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, +// 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, +// 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, +// 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, +// 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, +// 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, +// 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, +// 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, +// 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +// }; + +// mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; +// const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; + +// while (buf_len >= 4) +// { +// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; +// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; +// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; +// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; +// pByte_buf += 4; +// buf_len -= 4; +// } + +// while (buf_len) +// { +// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; +// ++pByte_buf; +// --buf_len; +// } + +// return ~crc32; +// } +// #endif + +void mz_free(void *p) +{ + MZ_FREE(p); +} + +void *miniz_def_alloc_func(void *opaque, size_t items, size_t size) +{ + (void)opaque, (void)items, (void)size; + return MZ_MALLOC(items * size); +} +void miniz_def_free_func(void *opaque, void *address) +{ + (void)opaque, (void)address; + MZ_FREE(address); +} +// void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) +// { +// (void)opaque, (void)address, (void)items, (void)size; +// return MZ_REALLOC(address, items * size); +// } + +// const char *mz_version(void) +// { +// return MZ_VERSION; +// } + +#ifndef MINIZ_NO_ZLIB_APIS + +int mz_deflateInit(mz_streamp pStream, int level) +{ + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); +} + +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) +{ + tdefl_compressor *pComp; + mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + + if (!pStream) + return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) + pStream->zalloc = miniz_def_alloc_func; + if (!pStream->zfree) + pStream->zfree = miniz_def_free_func; + + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pComp; + + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) + { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } + + return MZ_OK; +} + +// int mz_deflateReset(mz_streamp pStream) +// { +// if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) +// return MZ_STREAM_ERROR; +// pStream->total_in = pStream->total_out = 0; +// tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); +// return MZ_OK; +// } + +int mz_deflate(mz_streamp pStream, int flush) +{ + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; + + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) + return MZ_STREAM_ERROR; + if (!pStream->avail_out) + return MZ_BUF_ERROR; + + if (flush == MZ_PARTIAL_FLUSH) + flush = MZ_SYNC_FLUSH; + + if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + + orig_total_in = pStream->total_in; + orig_total_out = pStream->total_out; + for (;;) + { + tdefl_status defl_status; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + + defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); + + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (defl_status < 0) + { + mz_status = MZ_STREAM_ERROR; + break; + } + else if (defl_status == TDEFL_STATUS_DONE) + { + mz_status = MZ_STREAM_END; + break; + } + else if (!pStream->avail_out) + break; + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) + { + if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) + break; + return MZ_BUF_ERROR; /* Can't make forward progress without some input. + */ + } + } + return mz_status; +} + +int mz_deflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) +// { +// (void)pStream; +// This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) +// return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); +// } + +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) +{ + int status; + mz_stream stream; + memset(&stream, 0, sizeof(stream)); + + /* In case mz_ulong is 64-bits (argh I hate longs). */ + if ((source_len | *pDest_len) > 0xFFFFFFFFU) + return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_deflateInit(&stream, level); + if (status != MZ_OK) + return status; + + status = mz_deflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_deflateEnd(&stream); + return (status == MZ_OK) ? MZ_BUF_ERROR : status; + } + + *pDest_len = stream.total_out; + return mz_deflateEnd(&stream); +} + +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); +} + +// mz_ulong mz_compressBound(mz_ulong source_len) +// { +// return mz_deflateBound(NULL, source_len); +// } + +typedef struct +{ + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; + int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; +} inflate_state; + +int mz_inflateInit2(mz_streamp pStream, int window_bits) +{ + inflate_state *pDecomp; + if (!pStream) + return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) + pStream->zalloc = miniz_def_alloc_func; + if (!pStream->zfree) + pStream->zfree = miniz_def_free_func; + + pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); + if (!pDecomp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pDecomp; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + + return MZ_OK; +} + +int mz_inflateInit(mz_streamp pStream) +{ + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); +} + +int mz_inflate(mz_streamp pStream, int flush) +{ + inflate_state *pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + + if ((!pStream) || (!pStream->state)) + return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) + flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; + + pState = (inflate_state *)pStream->state; + if (pState->m_window_bits > 0) + decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; + + first_call = pState->m_first_call; + pState->m_first_call = 0; + if (pState->m_last_status < 0) + return MZ_DATA_ERROR; + + if (pState->m_has_flushed && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); + + if ((flush == MZ_FINISH) && (first_call)) + { + /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */ + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) + { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + /* flush != MZ_FINISH then we must assume there's more input. */ + if (flush != MZ_FINISH) + decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + + if (pState->m_dict_avail) + { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + } + + for (;;) + { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + + pState->m_dict_avail = (mz_uint)out_bytes; + + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + + if (status < 0) + return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */ + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */ + else if (flush == MZ_FINISH) + { + /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */ + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */ + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } + else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } + + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; +} + +int mz_inflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + mz_stream stream; + int status; + memset(&stream, 0, sizeof(stream)); + + /* In case mz_ulong is 64-bits (argh I hate longs). */ + if ((source_len | *pDest_len) > 0xFFFFFFFFU) + return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_inflateInit(&stream); + if (status != MZ_OK) + return status; + + status = mz_inflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_inflateEnd(&stream); + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; + } + *pDest_len = stream.total_out; + + return mz_inflateEnd(&stream); +} + +// const char *mz_error(int err) +// { +// static struct +// { +// int m_err; +// const char *m_pDesc; +// } s_error_descs[] = +// { +// { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } +// }; +// mz_uint i; +// for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) +// if (s_error_descs[i].m_err == err) +// return s_error_descs[i].m_pDesc; +// return NULL; +// } + +#endif /*MINIZ_NO_ZLIB_APIS */ + +#ifdef __cplusplus +} +#endif + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + + + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- Low-level Compression (independent from all decompression API's) */ + +/* Purposely making these tables static for faster init and thread safety. */ +static const mz_uint16 s_tdefl_len_sym[256] = + { + 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, + 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285 + }; + +static const mz_uint8 s_tdefl_len_extra[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 + }; + +static const mz_uint8 s_tdefl_small_dist_sym[512] = + { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 + }; + +static const mz_uint8 s_tdefl_small_dist_extra[512] = + { + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7 + }; + +static const mz_uint8 s_tdefl_large_dist_sym[128] = + { + 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 + }; + +static const mz_uint8 s_tdefl_large_dist_extra[128] = + { + 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 + }; + +/* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. */ +typedef struct +{ + mz_uint16 m_key, m_sym_index; +} tdefl_sym_freq; +static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) +{ + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; + tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; + MZ_CLEAR_OBJ(hist); + for (i = 0; i < num_syms; i++) + { + mz_uint freq = pSyms0[i].m_key; + hist[freq & 0xFF]++; + hist[256 + ((freq >> 8) & 0xFF)]++; + } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) + total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) + { + const mz_uint32 *pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) + { + offsets[i] = cur_ofs; + cur_ofs += pHist[i]; + } + for (i = 0; i < num_syms; i++) + pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; + { + tdefl_sym_freq *t = pCur_syms; + pCur_syms = pNew_syms; + pNew_syms = t; + } + } + return pCur_syms; +} + +/* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */ +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) +{ + int root, leaf, next, avbl, used, dpth; + if (n == 0) + return; + else if (n == 1) + { + A[0].m_key = 1; + return; + } + A[0].m_key += A[1].m_key; + root = 0; + leaf = 2; + for (next = 1; next < n - 1; next++) + { + if (leaf >= n || A[root].m_key < A[leaf].m_key) + { + A[next].m_key = A[root].m_key; + A[root++].m_key = (mz_uint16)next; + } + else + A[next].m_key = A[leaf++].m_key; + if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) + { + A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); + A[root++].m_key = (mz_uint16)next; + } + else + A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); + } + A[n - 2].m_key = 0; + for (next = n - 3; next >= 0; next--) + A[next].m_key = A[A[next].m_key].m_key + 1; + avbl = 1; + used = dpth = 0; + root = n - 2; + next = n - 1; + while (avbl > 0) + { + while (root >= 0 && (int)A[root].m_key == dpth) + { + used++; + root--; + } + while (avbl > used) + { + A[next--].m_key = (mz_uint16)(dpth); + avbl--; + } + avbl = 2 * used; + dpth++; + used = 0; + } +} + +/* Limits canonical Huffman code table's max code size. */ +enum +{ + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 +}; +static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) +{ + int i; + mz_uint32 total = 0; + if (code_list_len <= 1) + return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) + pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) + total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) + { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) + if (pNum_codes[i]) + { + pNum_codes[i]--; + pNum_codes[i + 1] += 2; + break; + } + total--; + } +} + +static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) +{ + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; + mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; + MZ_CLEAR_OBJ(num_codes); + if (static_table) + { + for (i = 0; i < table_len; i++) + num_codes[d->m_huff_code_sizes[table_num][i]]++; + } + else + { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; + int num_used_syms = 0; + const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) + if (pSym_count[i]) + { + syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; + syms0[num_used_syms++].m_sym_index = (mz_uint16)i; + } + + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); + tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + + for (i = 0; i < num_used_syms; i++) + num_codes[pSyms[i].m_key]++; + + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); + + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); + MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) + d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } + + next_code[1] = 0; + for (j = 0, i = 2; i <= code_size_limit; i++) + next_code[i] = j = ((j + num_codes[i - 1]) << 1); + + for (i = 0; i < table_len; i++) + { + mz_uint rev_code = 0, code, code_size; + if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) + continue; + code = next_code[code_size]++; + for (l = code_size; l > 0; l--, code >>= 1) + rev_code = (rev_code << 1) | (code & 1); + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } +} + +#define TDEFL_PUT_BITS(b, l) \ + do \ + { \ + mz_uint bits = b; \ + mz_uint len = l; \ + MZ_ASSERT(bits <= ((1U << len) - 1U)); \ + d->m_bit_buffer |= (bits << d->m_bits_in); \ + d->m_bits_in += len; \ + while (d->m_bits_in >= 8) \ + { \ + if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ + *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ + d->m_bit_buffer >>= 8; \ + d->m_bits_in -= 8; \ + } \ + } \ + MZ_MACRO_END + +#define TDEFL_RLE_PREV_CODE_SIZE() \ + { \ + if (rle_repeat_count) \ + { \ + if (rle_repeat_count < 3) \ + { \ + d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + while (rle_repeat_count--) \ + packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ + } \ + else \ + { \ + d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 16; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ + } \ + rle_repeat_count = 0; \ + } \ + } + +#define TDEFL_RLE_ZERO_CODE_SIZE() \ + { \ + if (rle_z_count) \ + { \ + if (rle_z_count < 3) \ + { \ + d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ + while (rle_z_count--) \ + packed_code_sizes[num_packed_code_sizes++] = 0; \ + } \ + else if (rle_z_count <= 10) \ + { \ + d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 17; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ + } \ + else \ + { \ + d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 18; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ + } \ + rle_z_count = 0; \ + } \ + } + +static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + +static void tdefl_start_dynamic_block(tdefl_compressor *d) +{ + int num_lit_codes, num_dist_codes, num_bit_lengths; + mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; + mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; + + d->m_huff_count[0][256] = 1; + + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) + if (d->m_huff_code_sizes[0][num_lit_codes - 1]) + break; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) + if (d->m_huff_code_sizes[1][num_dist_codes - 1]) + break; + + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; + num_packed_code_sizes = 0; + rle_z_count = 0; + rle_repeat_count = 0; + + memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) + { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) + { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); + packed_code_sizes[num_packed_code_sizes++] = code_size; + } + else if (++rle_repeat_count == 6) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + + TDEFL_PUT_BITS(2, 2); + + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); + + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) + if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) + break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); + TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) + TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + + for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;) + { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; + MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) + TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); + } +} + +static void tdefl_start_static_block(tdefl_compressor *d) +{ + mz_uint i; + mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + + for (i = 0; i <= 143; ++i) + *p++ = 8; + for (; i <= 255; ++i) + *p++ = 9; + for (; i <= 279; ++i) + *p++ = 7; + for (; i <= 287; ++i) + *p++ = 8; + + memset(d->m_huff_code_sizes[1], 5, 32); + + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + + TDEFL_PUT_BITS(1, 2); +} + +static const mz_uint16 mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + mz_uint8 *pOutput_buf = d->m_pOutput_buf; + mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; + +#define TDEFL_PUT_BITS_FAST(b, l) \ + { \ + bit_buffer |= (((mz_uint64)(b)) << bits_in); \ + bits_in += (l); \ + } + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + + if (flags & 1) + { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + /* This sequence coaxes MSVC into using cmov's vs. jmp's. */ + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; + + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + } + + if (pOutput_buf >= d->m_pOutput_buf_end) + return MZ_FALSE; + + *(mz_uint64 *)pOutput_buf = bit_buffer; + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } + +#undef TDEFL_PUT_BITS_FAST + + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; + + while (bits_in) + { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#else +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + if (flags & 1) + { + mz_uint sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + if (match_dist < 512) + { + sym = s_tdefl_small_dist_sym[match_dist]; + num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } + else + { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; + num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; + } + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS */ + +static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) +{ + if (static_block) + tdefl_start_static_block(d); + else + tdefl_start_dynamic_block(d); + return tdefl_compress_lz_codes(d); +} + +static int tdefl_flush_block(tdefl_compressor *d, int flush) +{ + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8 *pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; + + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; + + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) + { + TDEFL_PUT_BITS(0x78, 8); + TDEFL_PUT_BITS(0x01, 8); + } + + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + + pSaved_output_buf = d->m_pOutput_buf; + saved_bit_buf = d->m_bit_buffer; + saved_bits_in = d->m_bits_in; + + if (!use_raw_block) + comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); + + /* If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. */ + if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) + { + mz_uint i; + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) + { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) + { + TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); + } + } + /* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. */ + else if (!comp_block_succeeded) + { + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } + + if (flush) + { + if (flush == TDEFL_FINISH) + { + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) + { + mz_uint i, a = d->m_adler32; + for (i = 0; i < 4; i++) + { + TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); + a <<= 8; + } + } + } + else + { + mz_uint i, z = 0; + TDEFL_PUT_BITS(0, 3); + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, z ^= 0xFFFF) + { + TDEFL_PUT_BITS(z & 0xFFFF, 16); + } + } + } + + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; + d->m_total_lz_bytes = 0; + d->m_block_index++; + + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) + { + if (d->m_pPut_buf_func) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } + else if (pOutput_buf_start == d->m_output_buf) + { + int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) + { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } + else + { + d->m_out_buf_ofs += n; + } + } + + return d->m_output_flush_remaining; +} + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES +#ifdef MINIZ_UNALIGNED_USE_MEMCPY +static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8* p) +{ + mz_uint16 ret; + memcpy(&ret, p, sizeof(mz_uint16)); + return ret; +} +static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p) +{ + mz_uint16 ret; + memcpy(&ret, p, sizeof(mz_uint16)); + return ret; +} +#else +#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) +#define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p) +#endif +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + mz_uint16 s01 = TDEFL_READ_UNALIGNED_WORD2(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) + return; + for (;;) + { + for (;;) + { + if (--num_probes_left == 0) + return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) + break; + q = (const mz_uint16 *)(d->m_dict + probe_pos); + if (TDEFL_READ_UNALIGNED_WORD2(q) != s01) + continue; + p = s; + probe_len = 32; + do + { + } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && + (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); + if (!probe_len) + { + *pMatch_dist = dist; + *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN); + break; + } + else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len) + { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) + break; + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } +} +#else +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint8 *s = d->m_dict + pos, *p, *q; + mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) + return; + for (;;) + { + for (;;) + { + if (--num_probes_left == 0) + return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) + break; + p = s; + q = d->m_dict + probe_pos; + for (probe_len = 0; probe_len < max_match_len; probe_len++) + if (*p++ != *q++) + break; + if (probe_len > match_len) + { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = probe_len) == max_match_len) + return; + c0 = d->m_dict[pos + match_len]; + c1 = d->m_dict[pos + match_len - 1]; + } + } +} +#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ + +// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +// static mz_bool tdefl_compress_fast(tdefl_compressor *d) +// { +// /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ +// mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; +// mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; +// mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + +// while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) +// { +// const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; +// mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; +// mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); +// d->m_src_buf_left -= num_bytes_to_process; +// lookahead_size += num_bytes_to_process; + +// while (num_bytes_to_process) +// { +// mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); +// memcpy(d->m_dict + dst_pos, d->m_pSrc, n); +// if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) +// memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); +// d->m_pSrc += n; +// dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; +// num_bytes_to_process -= n; +// } + +// dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); +// if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) +// break; + +// while (lookahead_size >= 4) +// { +// mz_uint cur_match_dist, cur_match_len = 1; +// mz_uint8 *pCur_dict = d->m_dict + cur_pos; +// mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; +// mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; +// mz_uint probe_pos = d->m_hash[hash]; +// d->m_hash[hash] = (mz_uint16)lookahead_pos; + +// if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) +// { +// const mz_uint16 *p = (const mz_uint16 *)pCur_dict; +// const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); +// mz_uint32 probe_len = 32; +// do +// { +// } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && +// (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); +// cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); +// if (!probe_len) +// cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + +// if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) +// { +// cur_match_len = 1; +// *pLZ_code_buf++ = (mz_uint8)first_trigram; +// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); +// d->m_huff_count[0][(mz_uint8)first_trigram]++; +// } +// else +// { +// mz_uint32 s0, s1; +// cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + +// MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + +// cur_match_dist--; + +// pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); +// *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; +// pLZ_code_buf += 3; +// *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + +// s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; +// s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; +// d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + +// d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; +// } +// } +// else +// { +// *pLZ_code_buf++ = (mz_uint8)first_trigram; +// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); +// d->m_huff_count[0][(mz_uint8)first_trigram]++; +// } + +// if (--num_flags_left == 0) +// { +// num_flags_left = 8; +// pLZ_flags = pLZ_code_buf++; +// } + +// total_lz_bytes += cur_match_len; +// lookahead_pos += cur_match_len; +// dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); +// cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; +// MZ_ASSERT(lookahead_size >= cur_match_len); +// lookahead_size -= cur_match_len; + +// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) +// { +// int n; +// d->m_lookahead_pos = lookahead_pos; +// d->m_lookahead_size = lookahead_size; +// d->m_dict_size = dict_size; +// d->m_total_lz_bytes = total_lz_bytes; +// d->m_pLZ_code_buf = pLZ_code_buf; +// d->m_pLZ_flags = pLZ_flags; +// d->m_num_flags_left = num_flags_left; +// if ((n = tdefl_flush_block(d, 0)) != 0) +// return (n < 0) ? MZ_FALSE : MZ_TRUE; +// total_lz_bytes = d->m_total_lz_bytes; +// pLZ_code_buf = d->m_pLZ_code_buf; +// pLZ_flags = d->m_pLZ_flags; +// num_flags_left = d->m_num_flags_left; +// } +// } + +// while (lookahead_size) +// { +// mz_uint8 lit = d->m_dict[cur_pos]; + +// total_lz_bytes++; +// *pLZ_code_buf++ = lit; +// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); +// if (--num_flags_left == 0) +// { +// num_flags_left = 8; +// pLZ_flags = pLZ_code_buf++; +// } + +// d->m_huff_count[0][lit]++; + +// lookahead_pos++; +// dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); +// cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; +// lookahead_size--; + +// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) +// { +// int n; +// d->m_lookahead_pos = lookahead_pos; +// d->m_lookahead_size = lookahead_size; +// d->m_dict_size = dict_size; +// d->m_total_lz_bytes = total_lz_bytes; +// d->m_pLZ_code_buf = pLZ_code_buf; +// d->m_pLZ_flags = pLZ_flags; +// d->m_num_flags_left = num_flags_left; +// if ((n = tdefl_flush_block(d, 0)) != 0) +// return (n < 0) ? MZ_FALSE : MZ_TRUE; +// total_lz_bytes = d->m_total_lz_bytes; +// pLZ_code_buf = d->m_pLZ_code_buf; +// pLZ_flags = d->m_pLZ_flags; +// num_flags_left = d->m_num_flags_left; +// } +// } +// } + +// d->m_lookahead_pos = lookahead_pos; +// d->m_lookahead_size = lookahead_size; +// d->m_dict_size = dict_size; +// d->m_total_lz_bytes = total_lz_bytes; +// d->m_pLZ_code_buf = pLZ_code_buf; +// d->m_pLZ_flags = pLZ_flags; +// d->m_num_flags_left = num_flags_left; +// return MZ_TRUE; +// } +// #endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + +static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) +{ + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); + if (--d->m_num_flags_left == 0) + { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + d->m_huff_count[0][lit]++; +} + +static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) +{ + mz_uint32 s0, s1; + + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); + + d->m_total_lz_bytes += match_len; + + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); + d->m_pLZ_code_buf += 3; + + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); + if (--d->m_num_flags_left == 0) + { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + + if (match_len >= TDEFL_MIN_MATCH_LEN) + d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; +} + +static mz_bool tdefl_compress_normal(tdefl_compressor *d) +{ + const mz_uint8 *pSrc = d->m_pSrc; + size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; + + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) + { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + /* Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. */ + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) + { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) + { + mz_uint8 c = *pSrc++; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + ins_pos++; + } + } + else + { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) + { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + break; + + /* Simple lazy/greedy parsing state machine. */ + len_to_move = 1; + cur_match_dist = 0; + cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); + cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) + { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) + { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; + while (cur_match_len < d->m_lookahead_size) + { + if (d->m_dict[cur_pos + cur_match_len] != c) + break; + cur_match_len++; + } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) + cur_match_len = 0; + else + cur_match_dist = 1; + } + } + else + { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) + { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) + { + if (cur_match_len > d->m_saved_match_len) + { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[cur_pos]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + } + else + { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; + d->m_saved_match_len = 0; + } + } + else if (!cur_match_dist) + tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + /* Move the lookahead forward by len_to_move bytes. */ + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); + /* Check if it's time to flush the current LZ codes to the internal output buffer. */ + if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) + { + int n; + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } + + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + return MZ_TRUE; +} + +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) +{ + if (d->m_pIn_buf_size) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + } + + if (d->m_pOut_buf_size) + { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; + + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } + + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) +{ + if (!d) + { + if (pIn_buf_size) + *pIn_buf_size = 0; + if (pOut_buf_size) + *pOut_buf_size = 0; + return TDEFL_STATUS_BAD_PARAM; + } + + d->m_pIn_buf = pIn_buf; + d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; + d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); + d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; + + if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) + { + if (pIn_buf_size) + *pIn_buf_size = 0; + if (pOut_buf_size) + *pOut_buf_size = 0; + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); + + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +// if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && +// ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && +// ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) +// { +// if (!tdefl_compress_fast(d)) +// return d->m_prev_return_status; +// } +// else +// #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + { + if (!tdefl_compress_normal(d)) + return d->m_prev_return_status; + } + + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) + d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); + + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) + { + if (tdefl_flush_block(d, flush) < 0) + return d->m_prev_return_status; + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) + { + MZ_CLEAR_OBJ(d->m_hash); + MZ_CLEAR_OBJ(d->m_next); + d->m_dict_size = 0; + } + } + + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); +} + +// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) +// { +// MZ_ASSERT(d->m_pPut_buf_func); +// return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +// } + +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + d->m_pPut_buf_func = pPut_buf_func; + d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); + d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; + d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) + MZ_CLEAR_OBJ(d->m_hash); + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; + d->m_pOutput_buf_end = d->m_output_buf; + d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; + d->m_adler32 = 1; + d->m_pIn_buf = NULL; + d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; + d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; + d->m_pSrc = NULL; + d->m_src_buf_left = 0; + d->m_out_buf_ofs = 0; + memset(d->m_dict, 0, sizeof(d->m_dict)); // Initialize array to 0's + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +} + +// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) +// { +// return d->m_prev_return_status; +// } + +mz_uint32 tdefl_get_adler32(tdefl_compressor *d) +{ + return d->m_adler32; +} + +// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +// { +// tdefl_compressor *pComp; +// mz_bool succeeded; +// if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) +// return MZ_FALSE; +// pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +// if (!pComp) +// return MZ_FALSE; +// succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); +// succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); +// MZ_FREE(pComp); +// return succeeded; +// } + +// typedef struct +// { +// size_t m_size, m_capacity; +// mz_uint8 *m_pBuf; +// mz_bool m_expandable; +// } tdefl_output_buffer; + +// static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) +// { +// tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; +// size_t new_size = p->m_size + len; +// if (new_size > p->m_capacity) +// { +// size_t new_capacity = p->m_capacity; +// mz_uint8 *pNew_buf; +// if (!p->m_expandable) +// return MZ_FALSE; +// do +// { +// new_capacity = MZ_MAX(128U, new_capacity << 1U); +// } while (new_size > new_capacity); +// pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); +// if (!pNew_buf) +// return MZ_FALSE; +// p->m_pBuf = pNew_buf; +// p->m_capacity = new_capacity; +// } +// memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); +// p->m_size = new_size; +// return MZ_TRUE; +// } + +// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +// { +// tdefl_output_buffer out_buf; +// MZ_CLEAR_OBJ(out_buf); +// if (!pOut_len) +// return MZ_FALSE; +// else +// *pOut_len = 0; +// out_buf.m_expandable = MZ_TRUE; +// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) +// return NULL; +// *pOut_len = out_buf.m_size; +// return out_buf.m_pBuf; +// } + +// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +// { +// tdefl_output_buffer out_buf; +// MZ_CLEAR_OBJ(out_buf); +// if (!pOut_buf) +// return 0; +// out_buf.m_pBuf = (mz_uint8 *)pOut_buf; +// out_buf.m_capacity = out_buf_len; +// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) +// return 0; +// return out_buf.m_size; +// } + +static const mz_uint16 s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + +/* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */ +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) +{ + mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) + comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + + if (!level) + comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) + comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) + comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) + comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) + comp_flags |= TDEFL_RLE_MATCHES; + + return comp_flags; +} + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) */ +#endif + +/* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at + http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. + This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ +// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) +// { +// /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ +// static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; +// tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +// tdefl_output_buffer out_buf; +// int i, bpl = w * num_chans, y, z; +// mz_uint32 c; +// *pLen_out = 0; +// if (!pComp) +// return NULL; +// MZ_CLEAR_OBJ(out_buf); +// out_buf.m_expandable = MZ_TRUE; +// out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); +// if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) +// { +// MZ_FREE(pComp); +// return NULL; +// } +// /* write dummy header */ +// for (z = 41; z; --z) +// tdefl_output_buffer_putter(&z, 1, &out_buf); +// /* compress image data */ +// tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); +// for (y = 0; y < h; ++y) +// { +// tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); +// tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); +// } +// if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) +// { +// MZ_FREE(pComp); +// MZ_FREE(out_buf.m_pBuf); +// return NULL; +// } +// /* write real header */ +// *pLen_out = out_buf.m_size - 41; +// { +// static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; +// mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, +// 0x0a, 0x1a, 0x0a, 0x00, 0x00, +// 0x00, 0x0d, 0x49, 0x48, 0x44, +// 0x52, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x08, +// 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x49, 0x44, 0x41, +// 0x54 }; +// pnghdr[18] = (mz_uint8)(w >> 8); +// pnghdr[19] = (mz_uint8)w; +// pnghdr[22] = (mz_uint8)(h >> 8); +// pnghdr[23] = (mz_uint8)h; +// pnghdr[25] = chans[num_chans]; +// pnghdr[33] = (mz_uint8)(*pLen_out >> 24); +// pnghdr[34] = (mz_uint8)(*pLen_out >> 16); +// pnghdr[35] = (mz_uint8)(*pLen_out >> 8); +// pnghdr[36] = (mz_uint8)*pLen_out; +// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); +// for (i = 0; i < 4; ++i, c <<= 8) +// ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); +// memcpy(out_buf.m_pBuf, pnghdr, 41); +// } +// /* write footer (IDAT CRC-32, followed by IEND chunk) */ +// if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) +// { +// *pLen_out = 0; +// MZ_FREE(pComp); +// MZ_FREE(out_buf.m_pBuf); +// return NULL; +// } +// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); +// for (i = 0; i < 4; ++i, c <<= 8) +// (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); +// /* compute final size of file, grab compressed data buffer and return */ +// *pLen_out += 57; +// MZ_FREE(pComp); +// return out_buf.m_pBuf; +// } +// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) +// { + /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */ +// return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); +// } + +/* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ +/* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ +// tdefl_compressor *tdefl_compressor_alloc() +// { +// return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +// } + +// void tdefl_compressor_free(tdefl_compressor *pComp) +// { +// MZ_FREE(pComp); +// } + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#ifdef __cplusplus +} +#endif +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- Low-level Decompression (completely independent from all compression API's) */ + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN \ + switch (r->m_state) \ + { \ + case 0: +#define TINFL_CR_RETURN(state_index, result) \ + do \ + { \ + status = result; \ + r->m_state = state_index; \ + goto common_exit; \ + case state_index:; \ + } \ + MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) \ + do \ + { \ + for (;;) \ + { \ + TINFL_CR_RETURN(state_index, result); \ + } \ + } \ + MZ_MACRO_END +#define TINFL_CR_FINISH } + +#define TINFL_GET_BYTE(state_index, c) \ + do \ + { \ + while (pIn_buf_cur >= pIn_buf_end) \ + { \ + TINFL_CR_RETURN(state_index, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \ + } \ + c = *pIn_buf_cur++; \ + } \ + MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) \ + do \ + { \ + mz_uint c; \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) \ + do \ + { \ + if (num_bits < (mz_uint)(n)) \ + { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) \ + do \ + { \ + if (num_bits < (mz_uint)(n)) \ + { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + b = bit_buf & ((1 << (n)) - 1); \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END + +/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */ +/* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */ +/* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */ +/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */ +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do \ + { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) \ + { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) \ + break; \ + } \ + else if (num_bits > TINFL_FAST_LOOKUP_BITS) \ + { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do \ + { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); \ + if (temp >= 0) \ + break; \ + } \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < 15); + +/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */ +/* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */ +/* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */ +/* The slow path is only executed at the very end of the input buffer. */ +/* v1.16: The original macro handled the case at the very end of the passed-in input buffer, but we also need to handle the case where the user passes in 1+zillion bytes */ +/* following the deflate data and our non-conservative read-ahead path won't kick in here on this code. This is much trickier. */ +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \ + do \ + { \ + int temp; \ + mz_uint code_len, c; \ + if (num_bits < 15) \ + { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) \ + { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } \ + else \ + { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ + pIn_buf_cur += 2; \ + num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ + code_len = temp >> 9, temp &= 511; \ + else \ + { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do \ + { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while (temp < 0); \ + } \ + sym = temp; \ + bit_buf >>= code_len; \ + num_bits -= code_len; \ + } \ + MZ_MACRO_END + +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) +{ + static const mz_uint16 s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; + static const mz_uint8 s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; + static const mz_uint16 s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; + static const mz_uint8 s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; + static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + static const mz_uint16 s_min_table_sizes[3] = { 257, 1, 4 }; + + tinfl_status status = TINFL_STATUS_FAILED; + mz_uint32 num_bits, dist, counter, num_extra; + tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + + /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */ + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) + { + *pIn_buf_size = *pOut_buf_size = 0; + return TINFL_STATUS_BAD_PARAM; + } + + num_bits = r->m_num_bits; + bit_buf = r->m_bit_buf; + dist = r->m_dist; + counter = r->m_counter; + num_extra = r->m_num_extra; + dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; + r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_GET_BYTE(1, r->m_zhdr0); + TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); + if (counter) + { + TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); + } + } + + do + { + TINFL_GET_BITS(3, r->m_final, 3); + r->m_type = r->m_final >> 1; + if (r->m_type == 0) + { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) + { + if (num_bits) + TINFL_GET_BITS(6, r->m_raw_header[counter], 8); + else + TINFL_GET_BYTE(7, r->m_raw_header[counter]); + } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) + { + TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); + } + while ((counter) && (num_bits)) + { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) + { + size_t n; + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); + } + while (pIn_buf_cur >= pIn_buf_end) + { + TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); + pIn_buf_cur += n; + pOut_buf_cur += n; + counter -= (mz_uint)n; + } + } + else if (r->m_type == 3) + { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } + else + { + if (r->m_type == 1) + { + mz_uint8 *p = r->m_tables[0].m_code_size; + mz_uint i; + r->m_table_sizes[0] = 288; + r->m_table_sizes[1] = 32; + TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for (i = 0; i <= 143; ++i) + *p++ = 8; + for (; i <= 255; ++i) + *p++ = 9; + for (; i <= 279; ++i) + *p++ = 7; + for (; i <= 287; ++i) + *p++ = 8; + } + else + { + for (counter = 0; counter < 3; counter++) + { + TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); + r->m_table_sizes[counter] += s_min_table_sizes[counter]; + } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); + for (counter = 0; counter < r->m_table_sizes[2]; counter++) + { + mz_uint s; + TINFL_GET_BITS(14, s, 3); + r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; + } + r->m_table_sizes[2] = 19; + } + for (; ((int)r->m_type) >= 0; r->m_type--) + { + int tree_next, tree_cur; + tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; + pTable = &r->m_tables[r->m_type]; + MZ_CLEAR_OBJ(total_syms); + MZ_CLEAR_OBJ(pTable->m_look_up); + MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) + total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; + next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) + { + used_syms += total_syms[i]; + next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); + } + if ((65536 != total) && (used_syms > 1)) + { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) + { + mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; + if (!code_size) + continue; + cur_code = next_code[code_size]++; + for (l = code_size; l > 0; l--, cur_code >>= 1) + rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) + { + mz_int16 k = (mz_int16)((code_size << 9) | sym_index); + while (rev_code < TINFL_FAST_LOOKUP_SIZE) + { + pTable->m_look_up[rev_code] = k; + rev_code += (1 << code_size); + } + continue; + } + if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) + { + pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) + { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) + { + pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + else + tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); + pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) + { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) + { + mz_uint s; + TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); + if (dist < 16) + { + r->m_len_codes[counter++] = (mz_uint8)dist; + continue; + } + if ((dist == 16) && (!counter)) + { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; + TINFL_GET_BITS(18, s, num_extra); + s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); + counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) + { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); + TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for (;;) + { + mz_uint8 *pSrc; + for (;;) + { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) + { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) + break; + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)counter; + } + else + { + int sym2; + mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 4; + num_bits += 32; + } +#else + if (num_bits < 15) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; + do + { + sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + counter = sym2; + bit_buf >>= code_len; + num_bits -= code_len; + if (counter & 256) + break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; + do + { + sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + bit_buf >>= code_len; + num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) + { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) + break; + + num_extra = s_length_extra[counter - 257]; + counter = s_length_base[counter - 257]; + if (num_extra) + { + mz_uint extra_bits; + TINFL_GET_BITS(25, extra_bits, num_extra); + counter += extra_bits; + } + + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; + dist = s_dist_base[dist]; + if (num_extra) + { + mz_uint extra_bits; + TINFL_GET_BITS(27, extra_bits, num_extra); + dist += extra_bits; + } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) + { + while (counter--) + { + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) + { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do + { + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) + { + if (counter) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + do + { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; + pSrc += 3; + } while ((int)(counter -= 3) > 2); + if ((int)counter > 0) + { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + + /* Ensure byte alignment and put back any bytes from the bitbuf if we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ + /* I'm being super conservative here. A number of simplifications can be made to the byte alignment part, and the Adler32 check shouldn't ever need to worry about reading from the bitbuf now. */ + TINFL_SKIP_BITS(32, num_bits & 7); + while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) + { + --pIn_buf_cur; + num_bits -= 8; + } + bit_buf &= (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); + MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */ + + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + for (counter = 0; counter < 4; ++counter) + { + mz_uint s; + if (num_bits) + TINFL_GET_BITS(41, s, 8); + else + TINFL_GET_BYTE(42, s); + r->m_z_adler32 = (r->m_z_adler32 << 8) | s; + } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + + TINFL_CR_FINISH + +common_exit: + /* As long as we aren't telling the caller that we NEED more input to make forward progress: */ + /* Put back any bytes from the bitbuf in case we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ + /* We need to be very careful here to NOT push back any bytes we definitely know we need to make forward progress, though, or we'll lock the caller up into an inf loop. */ + if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) && (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS)) + { + while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) + { + --pIn_buf_cur; + num_bits -= 8; + } + } + r->m_num_bits = num_bits; + r->m_bit_buf = bit_buf & (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); + r->m_dist = dist; + r->m_counter = counter; + r->m_num_extra = num_extra; + r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; + *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) + { + const mz_uint8 *ptr = pOut_buf_next; + size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; + size_t block_len = buf_len % 5552; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) + s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; + if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) + status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +/* Higher level helper functions. */ +// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +// { +// tinfl_decompressor decomp; +// void *pBuf = NULL, *pNew_buf; +// size_t src_buf_ofs = 0, out_buf_capacity = 0; +// *pOut_len = 0; +// tinfl_init(&decomp); +// for (;;) +// { +// size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; +// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, +// (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); +// if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) +// { +// MZ_FREE(pBuf); +// *pOut_len = 0; +// return NULL; +// } +// src_buf_ofs += src_buf_size; +// *pOut_len += dst_buf_size; +// if (status == TINFL_STATUS_DONE) +// break; +// new_out_buf_capacity = out_buf_capacity * 2; +// if (new_out_buf_capacity < 128) +// new_out_buf_capacity = 128; +// pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); +// if (!pNew_buf) +// { +// MZ_FREE(pBuf); +// *pOut_len = 0; +// return NULL; +// } +// pBuf = pNew_buf; +// out_buf_capacity = new_out_buf_capacity; +// } +// return pBuf; +// } + +// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +// { +// tinfl_decompressor decomp; +// tinfl_status status; +// tinfl_init(&decomp); +// status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); +// return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; +// } + +// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +// { +// int result = 0; +// tinfl_decompressor decomp; +// mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); +// size_t in_buf_ofs = 0, dict_ofs = 0; +// if (!pDict) +// return TINFL_STATUS_FAILED; +// tinfl_init(&decomp); +// for (;;) +// { +// size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; +// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, +// (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); +// in_buf_ofs += in_buf_size; +// if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) +// break; +// if (status != TINFL_STATUS_HAS_MORE_OUTPUT) +// { +// result = (status == TINFL_STATUS_DONE); +// break; +// } +// dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); +// } +// MZ_FREE(pDict); +// *pIn_buf_size = in_buf_ofs; +// return result; +// } + +// tinfl_decompressor *tinfl_decompressor_alloc() +// { +// tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); +// if (pDecomp) +// tinfl_init(pDecomp); +// return pDecomp; +// } + +// void tinfl_decompressor_free(tinfl_decompressor *pDecomp) +// { +// MZ_FREE(pDecomp); +// } + +#ifdef __cplusplus +} +#endif +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * Copyright 2016 Martin Raiber + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + +// #ifndef MINIZ_NO_ARCHIVE_APIS + +// #ifdef __cplusplus +// extern "C" { +// #endif + +/* ------------------- .ZIP archive reading */ + +// #ifdef MINIZ_NO_STDIO +// #define MZ_FILE void * +// #else +// #include + +// #if defined(_MSC_VER) || defined(__MINGW64__) +// static FILE *mz_fopen(const char *pFilename, const char *pMode) +// { +// FILE *pFile = NULL; +// fopen_s(&pFile, pFilename, pMode); +// return pFile; +// } +// static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) +// { +// FILE *pFile = NULL; +// if (freopen_s(&pFile, pPath, pMode, pStream)) +// return NULL; +// return pFile; +// } +// #ifndef MINIZ_NO_TIME +// #include +// #endif +// #define MZ_FOPEN mz_fopen +// #define MZ_FCLOSE fclose +// #define MZ_FREAD fread +// #define MZ_FWRITE fwrite +// #define MZ_FTELL64 _ftelli64 +// #define MZ_FSEEK64 _fseeki64 +// #define MZ_FILE_STAT_STRUCT _stat +// #define MZ_FILE_STAT _stat +// #define MZ_FFLUSH fflush +// #define MZ_FREOPEN mz_freopen +// #define MZ_DELETE_FILE remove +// #elif defined(__MINGW32__) +// #ifndef MINIZ_NO_TIME +// #include +// #endif +// #define MZ_FOPEN(f, m) fopen(f, m) +// #define MZ_FCLOSE fclose +// #define MZ_FREAD fread +// #define MZ_FWRITE fwrite +// #define MZ_FTELL64 ftello64 +// #define MZ_FSEEK64 fseeko64 +// #define MZ_FILE_STAT_STRUCT _stat +// #define MZ_FILE_STAT _stat +// #define MZ_FFLUSH fflush +// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) +// #define MZ_DELETE_FILE remove +// #elif defined(__TINYC__) +// #ifndef MINIZ_NO_TIME +// #include +// #endif +// #define MZ_FOPEN(f, m) fopen(f, m) +// #define MZ_FCLOSE fclose +// #define MZ_FREAD fread +// #define MZ_FWRITE fwrite +// #define MZ_FTELL64 ftell +// #define MZ_FSEEK64 fseek +// #define MZ_FILE_STAT_STRUCT stat +// #define MZ_FILE_STAT stat +// #define MZ_FFLUSH fflush +// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) +// #define MZ_DELETE_FILE remove +// #elif defined(__GNUC__) && _LARGEFILE64_SOURCE +// #ifndef MINIZ_NO_TIME +// #include +// #endif +// #define MZ_FOPEN(f, m) fopen64(f, m) +// #define MZ_FCLOSE fclose +// #define MZ_FREAD fread +// #define MZ_FWRITE fwrite +// #define MZ_FTELL64 ftello64 +// #define MZ_FSEEK64 fseeko64 +// #define MZ_FILE_STAT_STRUCT stat64 +// #define MZ_FILE_STAT stat64 +// #define MZ_FFLUSH fflush +// #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) +// #define MZ_DELETE_FILE remove +// #elif defined(__APPLE__) && _LARGEFILE64_SOURCE +// #ifndef MINIZ_NO_TIME +// #include +// #endif +// #define MZ_FOPEN(f, m) fopen(f, m) +// #define MZ_FCLOSE fclose +// #define MZ_FREAD fread +// #define MZ_FWRITE fwrite +// #define MZ_FTELL64 ftello +// #define MZ_FSEEK64 fseeko +// #define MZ_FILE_STAT_STRUCT stat +// #define MZ_FILE_STAT stat +// #define MZ_FFLUSH fflush +// #define MZ_FREOPEN(p, m, s) freopen(p, m, s) +// #define MZ_DELETE_FILE remove + +// #else +// // #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") +// #ifndef MINIZ_NO_TIME +// #include +// #endif +// #define MZ_FOPEN(f, m) fopen(f, m) +// #define MZ_FCLOSE fclose +// #define MZ_FREAD fread +// #define MZ_FWRITE fwrite +// #ifdef __STRICT_ANSI__ +// #define MZ_FTELL64 ftell +// #define MZ_FSEEK64 fseek +// #else +// #define MZ_FTELL64 ftello +// #define MZ_FSEEK64 fseeko +// #endif +// #define MZ_FILE_STAT_STRUCT stat +// #define MZ_FILE_STAT stat +// #define MZ_FFLUSH fflush +// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) +// #define MZ_DELETE_FILE remove +// #endif /* #ifdef _MSC_VER */ +// #endif /* #ifdef MINIZ_NO_STDIO */ + +// #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) + +/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ +// enum +// { +// /* ZIP archive identifiers and record sizes */ +// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, +// MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, +// MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, +// MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, +// MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, +// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, + +// /* ZIP64 archive identifier and record sizes */ +// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, +// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, +// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, +// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, +// MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, +// MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, +// MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, +// MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, + +// /* Central directory header record offsets */ +// MZ_ZIP_CDH_SIG_OFS = 0, +// MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, +// MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, +// MZ_ZIP_CDH_BIT_FLAG_OFS = 8, +// MZ_ZIP_CDH_METHOD_OFS = 10, +// MZ_ZIP_CDH_FILE_TIME_OFS = 12, +// MZ_ZIP_CDH_FILE_DATE_OFS = 14, +// MZ_ZIP_CDH_CRC32_OFS = 16, +// MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, +// MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, +// MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, +// MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, +// MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, +// MZ_ZIP_CDH_DISK_START_OFS = 34, +// MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, +// MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, +// MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, + +// /* Local directory header offsets */ +// MZ_ZIP_LDH_SIG_OFS = 0, +// MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, +// MZ_ZIP_LDH_BIT_FLAG_OFS = 6, +// MZ_ZIP_LDH_METHOD_OFS = 8, +// MZ_ZIP_LDH_FILE_TIME_OFS = 10, +// MZ_ZIP_LDH_FILE_DATE_OFS = 12, +// MZ_ZIP_LDH_CRC32_OFS = 14, +// MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, +// MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, +// MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, +// MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, +// MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, + +// /* End of central directory offsets */ +// MZ_ZIP_ECDH_SIG_OFS = 0, +// MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, +// MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, +// MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, +// MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, +// MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, +// MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, +// MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, + +// /* ZIP64 End of central directory locator offsets */ +// MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ +// MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ +// MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ +// MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ + +// /* ZIP64 End of central directory header offsets */ +// MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ +// MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ +// MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ +// MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ +// MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ +// MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ +// MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ +// MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ +// MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ +// MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ +// MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, +// MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, +// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, +// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, +// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, +// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, +// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 +// }; + +// typedef struct +// { +// void *m_p; +// size_t m_size, m_capacity; +// mz_uint m_element_size; +// } mz_zip_array; + +// struct mz_zip_internal_state_tag +// { +// mz_zip_array m_central_dir; +// mz_zip_array m_central_dir_offsets; +// mz_zip_array m_sorted_central_dir_offsets; + +// /* The flags passed in when the archive is initially opened. */ +// uint32_t m_init_flags; + +// /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ +// mz_bool m_zip64; + +// /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ +// mz_bool m_zip64_has_extended_info_fields; + +// /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ +// MZ_FILE *m_pFile; +// mz_uint64 m_file_archive_start_ofs; + +// void *m_pMem; +// size_t m_mem_size; +// size_t m_mem_capacity; +// }; + +// #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size + +// #if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) +// static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) +// { +// MZ_ASSERT(index < pArray->m_size); +// return index; +// } +// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] +// #else +// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] +// #endif + +// static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) +// { +// memset(pArray, 0, sizeof(mz_zip_array)); +// pArray->m_element_size = element_size; +// } + +// static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); +// memset(pArray, 0, sizeof(mz_zip_array)); +// } + +// static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) +// { +// void *pNew_p; +// size_t new_capacity = min_new_capacity; +// MZ_ASSERT(pArray->m_element_size); +// if (pArray->m_capacity >= min_new_capacity) +// return MZ_TRUE; +// if (growing) +// { +// new_capacity = MZ_MAX(1, pArray->m_capacity); +// while (new_capacity < min_new_capacity) +// new_capacity *= 2; +// } +// if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) +// return MZ_FALSE; +// pArray->m_p = pNew_p; +// pArray->m_capacity = new_capacity; +// return MZ_TRUE; +// } + +// static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) +// { +// if (new_capacity > pArray->m_capacity) +// { +// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) +// return MZ_FALSE; +// } +// return MZ_TRUE; +// } + +// static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) +// { +// if (new_size > pArray->m_capacity) +// { +// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) +// return MZ_FALSE; +// } +// pArray->m_size = new_size; +// return MZ_TRUE; +// } + +// static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) +// { +// return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); +// } + +// static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) +// { +// size_t orig_size = pArray->m_size; +// if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) +// return MZ_FALSE; +// memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); +// return MZ_TRUE; +// } + +// #ifndef MINIZ_NO_TIME +// static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) +// { +// struct tm tm; +// memset(&tm, 0, sizeof(tm)); +// tm.tm_isdst = -1; +// tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; +// tm.tm_mon = ((dos_date >> 5) & 15) - 1; +// tm.tm_mday = dos_date & 31; +// tm.tm_hour = (dos_time >> 11) & 31; +// tm.tm_min = (dos_time >> 5) & 63; +// tm.tm_sec = (dos_time << 1) & 62; +// return mktime(&tm); +// } + +// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +// static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +// { +// #ifdef _MSC_VER +// struct tm tm_struct; +// struct tm *tm = &tm_struct; +// errno_t err = localtime_s(tm, &time_); +// if (err) +// { +// *pDOS_date = 0; +// *pDOS_time = 0; +// return; +// } +// #else +// struct tm *tm = localtime(&time_); +// #endif /* #ifdef _MSC_VER */ + +// *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); +// *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); +// } +// #endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ + +// #ifndef MINIZ_NO_STDIO +// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +// static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) +// { +// struct MZ_FILE_STAT_STRUCT file_stat; + +// /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ +// if (MZ_FILE_STAT(pFilename, &file_stat) != 0) +// return MZ_FALSE; + +// *pTime = file_stat.st_mtime; + +// return MZ_TRUE; +// } +// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ + +// static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) +// { +// struct utimbuf t; + +// memset(&t, 0, sizeof(t)); +// t.actime = access_time; +// t.modtime = modified_time; + +// return !utime(pFilename, &t); +// } +// #endif /* #ifndef MINIZ_NO_STDIO */ +// #endif /* #ifndef MINIZ_NO_TIME */ + +// static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) +// { +// if (pZip) +// pZip->m_last_error = err_num; +// return MZ_FALSE; +// } + +// static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) +// { +// (void)flags; +// if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (!pZip->m_pAlloc) +// pZip->m_pAlloc = miniz_def_alloc_func; +// if (!pZip->m_pFree) +// pZip->m_pFree = miniz_def_free_func; +// if (!pZip->m_pRealloc) +// pZip->m_pRealloc = miniz_def_realloc_func; + +// pZip->m_archive_size = 0; +// pZip->m_central_directory_file_ofs = 0; +// pZip->m_total_files = 0; +// pZip->m_last_error = MZ_ZIP_NO_ERROR; + +// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); +// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); +// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); +// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); +// pZip->m_pState->m_init_flags = flags; +// pZip->m_pState->m_zip64 = MZ_FALSE; +// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; + +// pZip->m_zip_mode = MZ_ZIP_MODE_READING; + +// return MZ_TRUE; +// } + +// static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) +// { +// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; +// const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); +// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// mz_uint8 l = 0, r = 0; +// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +// pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +// pE = pL + MZ_MIN(l_len, r_len); +// while (pL < pE) +// { +// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) +// break; +// pL++; +// pR++; +// } +// return (pL == pE) ? (l_len < r_len) : (l < r); +// } +/* +#define MZ_SWAP_UINT32(a, b) \ + do \ + { \ + mz_uint32 t = a; \ + a = b; \ + b = t; \ + } \ + MZ_MACRO_END +*/ +/* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */ +// static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) +// { +// mz_zip_internal_state *pState = pZip->m_pState; +// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; +// const mz_zip_array *pCentral_dir = &pState->m_central_dir; +// mz_uint32 *pIndices; +// mz_uint32 start, end; +// const mz_uint32 size = pZip->m_total_files; + +// if (size <= 1U) +// return; + +// pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + +// start = (size - 2U) >> 1U; +// for (;;) +// { +// mz_uint64 child, root = start; +// for (;;) +// { +// if ((child = (root << 1U) + 1U) >= size) +// break; +// child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); +// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) +// break; +// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); +// root = child; +// } +// if (!start) +// break; +// start--; +// } + +// end = size - 1; +// while (end > 0) +// { +// mz_uint64 child, root = 0; +// MZ_SWAP_UINT32(pIndices[end], pIndices[0]); +// for (;;) +// { +// if ((child = (root << 1U) + 1U) >= end) +// break; +// child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); +// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) +// break; +// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); +// root = child; +// } +// end--; +// } +// } + +// static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) +// { +// mz_int64 cur_file_ofs; +// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; +// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + +// /* Basic sanity checks - reject files which are too small */ +// if (pZip->m_archive_size < record_size) +// return MZ_FALSE; + +// /* Find the record by scanning the file from the end towards the beginning. */ +// cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); +// for (;;) +// { +// int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) +// return MZ_FALSE; + +// for (i = n - 4; i >= 0; --i) +// { +// mz_uint s = MZ_READ_LE32(pBuf + i); +// if (s == record_sig) +// { +// if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) +// break; +// } +// } + +// if (i >= 0) +// { +// cur_file_ofs += i; +// break; +// } + +// /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ +// if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) +// return MZ_FALSE; + +// cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); +// } + +// *pOfs = cur_file_ofs; +// return MZ_TRUE; +// } + +// static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) +// { +// mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; +// mz_uint64 cdir_ofs = 0; +// mz_int64 cur_file_ofs = 0; +// const mz_uint8 *p; + +// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; +// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; +// mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); +// mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +// mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; + +// mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +// mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; + +// mz_uint64 zip64_end_of_central_dir_ofs = 0; + +// /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ +// if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +// if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) +// return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); + +// /* Read and verify the end of central directory record. */ +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +// if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) +// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +// if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) +// { +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) +// { +// if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) +// { +// zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); +// if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) +// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +// if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) +// { +// if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) +// { +// pZip->m_pState->m_zip64 = MZ_TRUE; +// } +// } +// } +// } +// } + +// pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); +// cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); +// num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); +// cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); +// cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); +// cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + +// if (pZip->m_pState->m_zip64) +// { +// mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); +// mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); +// mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); +// mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); +// mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); + +// if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if (zip64_total_num_of_disks != 1U) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +// /* Check for miniz's practical limits */ +// if (zip64_cdir_total_entries > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + +// pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; + +// if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + +// cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; + +// /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ +// if (zip64_size_of_central_directory > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +// cdir_size = (mz_uint32)zip64_size_of_central_directory; + +// num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); + +// cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); + +// cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); +// } + +// if (pZip->m_total_files != cdir_entries_on_this_disk) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +// if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +// if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// pZip->m_central_directory_file_ofs = cdir_ofs; + +// if (pZip->m_total_files) +// { +// mz_uint i, n; +// /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ +// if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || +// (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// if (sort_central_dir) +// { +// if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +// /* Now create an index into the central directory file records, do some basic sanity checking on each record */ +// p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; +// for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) +// { +// mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; +// mz_uint64 comp_size, decomp_size, local_header_ofs; + +// if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + +// if (sort_central_dir) +// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; + +// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); +// decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); +// local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); +// filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + +// if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && +// (ext_data_size) && +// (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) +// { +// /* Attempt to find zip64 extended information field in the entry's extra data */ +// mz_uint32 extra_size_remaining = ext_data_size; + +// if (extra_size_remaining) +// { +// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; + +// do +// { +// mz_uint32 field_id; +// mz_uint32 field_data_size; + +// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// field_id = MZ_READ_LE16(pExtra_data); +// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + +// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) +// { +// /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ +// pZip->m_pState->m_zip64 = MZ_TRUE; +// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; +// break; +// } + +// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; +// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; +// } while (extra_size_remaining); +// } +// } + +// /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ +// if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) +// { +// if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// } + +// disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); +// if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +// if (comp_size != MZ_UINT32_MAX) +// { +// if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// } + +// bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); +// if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + +// if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// n -= total_header_size; +// p += total_header_size; +// } +// } + +// if (sort_central_dir) +// mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + +// return MZ_TRUE; +// } + +// void mz_zip_zero_struct(mz_zip_archive *pZip) +// { +// if (pZip) +// MZ_CLEAR_OBJ(*pZip); +// } + +// static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +// { +// mz_bool status = MZ_TRUE; + +// if (!pZip) +// return MZ_FALSE; + +// if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) +// { +// if (set_last_error) +// pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; + +// return MZ_FALSE; +// } + +// if (pZip->m_pState) +// { +// mz_zip_internal_state *pState = pZip->m_pState; +// pZip->m_pState = NULL; + +// mz_zip_array_clear(pZip, &pState->m_central_dir); +// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); +// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +// #ifndef MINIZ_NO_STDIO +// if (pState->m_pFile) +// { +// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) +// { +// if (MZ_FCLOSE(pState->m_pFile) == EOF) +// { +// if (set_last_error) +// pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; +// status = MZ_FALSE; +// } +// } +// pState->m_pFile = NULL; +// } +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// } +// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + +// return status; +// } + +// mz_bool mz_zip_reader_end(mz_zip_archive *pZip) +// { +// return mz_zip_reader_end_internal(pZip, MZ_TRUE); +// } +// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) +// { +// if ((!pZip) || (!pZip->m_pRead)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (!mz_zip_reader_init_internal(pZip, flags)) +// return MZ_FALSE; + +// pZip->m_zip_type = MZ_ZIP_TYPE_USER; +// pZip->m_archive_size = size; + +// if (!mz_zip_reader_read_central_dir(pZip, flags)) +// { +// mz_zip_reader_end_internal(pZip, MZ_FALSE); +// return MZ_FALSE; +// } + +// return MZ_TRUE; +// } + +// static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +// { +// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +// size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); +// memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); +// return s; +// } + +// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) +// { +// if (!pMem) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +// if (!mz_zip_reader_init_internal(pZip, flags)) +// return MZ_FALSE; + +// pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; +// pZip->m_archive_size = size; +// pZip->m_pRead = mz_zip_mem_read_func; +// pZip->m_pIO_opaque = pZip; +// pZip->m_pNeeds_keepalive = NULL; + +// #ifdef __cplusplus +// pZip->m_pState->m_pMem = const_cast(pMem); +// #else +// pZip->m_pState->m_pMem = (void *)pMem; +// #endif + +// pZip->m_pState->m_mem_size = size; + +// if (!mz_zip_reader_read_central_dir(pZip, flags)) +// { +// mz_zip_reader_end_internal(pZip, MZ_FALSE); +// return MZ_FALSE; +// } + +// return MZ_TRUE; +// } + +// #ifndef MINIZ_NO_STDIO +// static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +// { +// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + +// file_ofs += pZip->m_pState->m_file_archive_start_ofs; + +// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) +// return 0; + +// return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); +// } + +// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) +// { +// return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); +// } + +// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) +// { +// mz_uint64 file_size; +// MZ_FILE *pFile; + +// if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pFile = MZ_FOPEN(pFilename, "rb"); +// if (!pFile) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +// file_size = archive_size; +// if (!file_size) +// { +// if (MZ_FSEEK64(pFile, 0, SEEK_END)) +// { +// MZ_FCLOSE(pFile); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); +// } + +// file_size = MZ_FTELL64(pFile); +// } + +// /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ + +// if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +// { +// MZ_FCLOSE(pFile); +// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); +// } + +// if (!mz_zip_reader_init_internal(pZip, flags)) +// { +// MZ_FCLOSE(pFile); +// return MZ_FALSE; +// } + +// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; +// pZip->m_pRead = mz_zip_file_read_func; +// pZip->m_pIO_opaque = pZip; +// pZip->m_pState->m_pFile = pFile; +// pZip->m_archive_size = file_size; +// pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; + +// if (!mz_zip_reader_read_central_dir(pZip, flags)) +// { +// mz_zip_reader_end_internal(pZip, MZ_FALSE); +// return MZ_FALSE; +// } + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) +// { +// mz_uint64 cur_file_ofs; + +// if ((!pZip) || (!pFile)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +// cur_file_ofs = MZ_FTELL64(pFile); + +// if (!archive_size) +// { +// if (MZ_FSEEK64(pFile, 0, SEEK_END)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + +// archive_size = MZ_FTELL64(pFile) - cur_file_ofs; + +// if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); +// } + +// if (!mz_zip_reader_init_internal(pZip, flags)) +// return MZ_FALSE; + +// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; +// pZip->m_pRead = mz_zip_file_read_func; + +// pZip->m_pIO_opaque = pZip; +// pZip->m_pState->m_pFile = pFile; +// pZip->m_archive_size = archive_size; +// pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; + +// if (!mz_zip_reader_read_central_dir(pZip, flags)) +// { +// mz_zip_reader_end_internal(pZip, MZ_FALSE); +// return MZ_FALSE; +// } + +// return MZ_TRUE; +// } + +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) +// { +// if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) +// return NULL; +// return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); +// } + +// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) +// { +// mz_uint m_bit_flag; +// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +// if (!p) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// return MZ_FALSE; +// } + +// m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); +// return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; +// } + +// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) +// { +// mz_uint bit_flag; +// mz_uint method; + +// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +// if (!p) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// return MZ_FALSE; +// } + +// method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +// bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + +// if ((method != 0) && (method != MZ_DEFLATED)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); +// return MZ_FALSE; +// } + +// if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); +// return MZ_FALSE; +// } + +// if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) +// { +// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); +// return MZ_FALSE; +// } + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) +// { +// mz_uint filename_len, attribute_mapping_id, external_attr; +// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +// if (!p) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// return MZ_FALSE; +// } + +// filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// if (filename_len) +// { +// if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') +// return MZ_TRUE; +// } + + /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */ + /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */ + /* FIXME: Remove this check? Is it necessary - we already check the filename. */ +// attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; +// (void)attribute_mapping_id; + +// external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); +// if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) +// { +// return MZ_TRUE; +// } + +// return MZ_FALSE; +// } + +// static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) +// { +// mz_uint n; +// const mz_uint8 *p = pCentral_dir_header; + +// if (pFound_zip64_extra_data) +// *pFound_zip64_extra_data = MZ_FALSE; + +// if ((!p) || (!pStat)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// /* Extract fields from the central directory record. */ +// pStat->m_file_index = file_index; +// pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); +// pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); +// pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); +// pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); +// pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +// #ifndef MINIZ_NO_TIME +// pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); +// #endif +// pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); +// pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); +// pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); +// pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); +// pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); +// pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + +// /* Copy as much of the filename and comment as possible. */ +// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); +// memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); +// pStat->m_filename[n] = '\0'; + +// n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); +// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); +// pStat->m_comment_size = n; +// memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); +// pStat->m_comment[n] = '\0'; + +// /* Set some flags for convienance */ +// pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); +// pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); +// pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); + +// /* See if we need to read any zip64 extended information fields. */ +// /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ +// if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) +// { +// /* Attempt to find zip64 extended information field in the entry's extra data */ +// mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + +// if (extra_size_remaining) +// { +// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + +// do +// { +// mz_uint32 field_id; +// mz_uint32 field_data_size; + +// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// field_id = MZ_READ_LE16(pExtra_data); +// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + +// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) +// { +// const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; +// mz_uint32 field_data_remaining = field_data_size; + +// if (pFound_zip64_extra_data) +// *pFound_zip64_extra_data = MZ_TRUE; + +// if (pStat->m_uncomp_size == MZ_UINT32_MAX) +// { +// if (field_data_remaining < sizeof(mz_uint64)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// pStat->m_uncomp_size = MZ_READ_LE64(pField_data); +// pField_data += sizeof(mz_uint64); +// field_data_remaining -= sizeof(mz_uint64); +// } + +// if (pStat->m_comp_size == MZ_UINT32_MAX) +// { +// if (field_data_remaining < sizeof(mz_uint64)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// pStat->m_comp_size = MZ_READ_LE64(pField_data); +// pField_data += sizeof(mz_uint64); +// field_data_remaining -= sizeof(mz_uint64); +// } + +// if (pStat->m_local_header_ofs == MZ_UINT32_MAX) +// { +// if (field_data_remaining < sizeof(mz_uint64)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); +// pField_data += sizeof(mz_uint64); +// // field_data_remaining -= sizeof(mz_uint64); +// } + +// break; +// } + +// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; +// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; +// } while (extra_size_remaining); +// } +// } + +// return MZ_TRUE; +// } + +// static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) +// { +// mz_uint i; +// if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) +// return 0 == memcmp(pA, pB, len); +// for (i = 0; i < len; ++i) +// if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) +// return MZ_FALSE; +// return MZ_TRUE; +// } + +// static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) +// { +// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; +// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// mz_uint8 l = 0, r = 0; +// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +// pE = pL + MZ_MIN(l_len, r_len); +// while (pL < pE) +// { +// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) +// break; +// pL++; +// pR++; +// } +// return (pL == pE) ? (int)(l_len - r_len) : (l - r); +// } + +// static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) +// { +// mz_zip_internal_state *pState = pZip->m_pState; +// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; +// const mz_zip_array *pCentral_dir = &pState->m_central_dir; +// mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); +// const uint32_t size = pZip->m_total_files; +// const mz_uint filename_len = (mz_uint)strlen(pFilename); + +// if (pIndex) +// *pIndex = 0; + +// if (size) +// { +// /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ +// /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ +// mz_int64 l = 0, h = (mz_int64)size - 1; + +// while (l <= h) +// { +// mz_int64 m = l + ((h - l) >> 1); +// uint32_t file_index = pIndices[(uint32_t)m]; + +// int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); +// if (!comp) +// { +// if (pIndex) +// *pIndex = file_index; +// return MZ_TRUE; +// } +// else if (comp < 0) +// l = m + 1; +// else +// h = m - 1; +// } +// } + +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +// } + +// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) +// { +// mz_uint32 index_; +// if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) +// return -1; +// else +// return (int)index_; +// } + +// mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) +// { +// mz_uint file_index; +// size_t name_len, comment_len; + +// if (pIndex) +// *pIndex = 0; + +// if ((!pZip) || (!pZip->m_pState) || (!pName)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// /* See if we can use a binary search */ +// if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && +// (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && +// ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) +// { +// return mz_zip_locate_file_binary_search(pZip, pName, pIndex); +// } + +// /* Locate the entry by scanning the entire central directory */ +// name_len = strlen(pName); +// if (name_len > MZ_UINT16_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// comment_len = pComment ? strlen(pComment) : 0; +// if (comment_len > MZ_UINT16_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// for (file_index = 0; file_index < pZip->m_total_files; file_index++) +// { +// const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); +// mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +// if (filename_len < name_len) +// continue; +// if (comment_len) +// { +// mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); +// const char *pFile_comment = pFilename + filename_len + file_extra_len; +// if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) +// continue; +// } +// if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) +// { +// int ofs = filename_len - 1; +// do +// { +// if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) +// break; +// } while (--ofs >= 0); +// ofs++; +// pFilename += ofs; +// filename_len -= ofs; +// } +// if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) +// { +// if (pIndex) +// *pIndex = file_index; +// return MZ_TRUE; +// } +// } + +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +// } + +// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +// { +// int status = TINFL_STATUS_DONE; +// mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; +// mz_zip_archive_file_stat file_stat; +// void *pRead_buf; +// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; +// tinfl_decompressor inflator; + +// if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +// return MZ_FALSE; + +// /* A directory or zero length file */ +// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) +// return MZ_TRUE; + +// /* Encryption and patch files are not supported. */ +// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + +// /* This function only supports decompressing stored and deflate. */ +// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + +// /* Ensure supplied output buffer is large enough. */ +// needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; +// if (buf_size < needed_size) +// return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); + +// /* Read and parse the local directory entry. */ +// cur_file_ofs = file_stat.m_local_header_ofs; +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) +// { +// /* The file is stored or the caller has requested the compressed data. */ +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) +// { +// if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) +// return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); +// } +// #endif + +// return MZ_TRUE; +// } + +// /* Decompress the file either directly from memory or from a file input buffer. */ +// tinfl_init(&inflator); + +// if (pZip->m_pState->m_pMem) +// { +// /* Read directly from the archive in memory. */ +// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; +// read_buf_size = read_buf_avail = file_stat.m_comp_size; +// comp_remaining = 0; +// } +// else if (pUser_read_buf) +// { +// /* Use a user provided read buffer. */ +// if (!user_read_buf_size) +// return MZ_FALSE; +// pRead_buf = (mz_uint8 *)pUser_read_buf; +// read_buf_size = user_read_buf_size; +// read_buf_avail = 0; +// comp_remaining = file_stat.m_comp_size; +// } +// else +// { +// /* Temporarily allocate a read buffer. */ +// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); +// if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// read_buf_avail = 0; +// comp_remaining = file_stat.m_comp_size; +// } + +// do +// { +// /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ +// size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); +// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) +// { +// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +// { +// status = TINFL_STATUS_FAILED; +// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); +// break; +// } +// cur_file_ofs += read_buf_avail; +// comp_remaining -= read_buf_avail; +// read_buf_ofs = 0; +// } +// in_buf_size = (size_t)read_buf_avail; +// status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); +// read_buf_avail -= in_buf_size; +// read_buf_ofs += in_buf_size; +// out_buf_ofs += out_buf_size; +// } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); + +// if (status == TINFL_STATUS_DONE) +// { +// /* Make sure the entire file was decompressed, and check its CRC. */ +// if (out_buf_ofs != file_stat.m_uncomp_size) +// { +// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); +// status = TINFL_STATUS_FAILED; +// } +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) +// { +// mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); +// status = TINFL_STATUS_FAILED; +// } +// #endif +// } + +// if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) +// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + +// return status == TINFL_STATUS_DONE; +// } + +// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +// { +// mz_uint32 file_index; +// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +// return MZ_FALSE; +// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); +// } + +// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) +// { +// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); +// } + +// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) +// { +// return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); +// } + +// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) +// { +// mz_uint64 comp_size, uncomp_size, alloc_size; +// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +// void *pBuf; + +// if (pSize) +// *pSize = 0; + +// if (!p) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// return NULL; +// } + +// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); +// uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + +// alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; +// if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); +// return NULL; +// } + +// if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) +// { +// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// return NULL; +// } + +// if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); +// return NULL; +// } + +// if (pSize) +// *pSize = (size_t)alloc_size; +// return pBuf; +// } + +// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) +// { +// mz_uint32 file_index; +// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +// { +// if (pSize) +// *pSize = 0; +// return MZ_FALSE; +// } +// return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); +// } + +// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +// { +// int status = TINFL_STATUS_DONE; +// mz_uint file_crc32 = MZ_CRC32_INIT; +// mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; +// mz_zip_archive_file_stat file_stat; +// void *pRead_buf = NULL; +// void *pWrite_buf = NULL; +// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + +// if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +// return MZ_FALSE; + +// /* A directory or zero length file */ +// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) +// return MZ_TRUE; + +// /* Encryption and patch files are not supported. */ +// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + +// /* This function only supports decompressing stored and deflate. */ +// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + +// /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ +// cur_file_ofs = file_stat.m_local_header_ofs; +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// /* Decompress the file either directly from memory or from a file input buffer. */ +// if (pZip->m_pState->m_pMem) +// { +// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; +// read_buf_size = read_buf_avail = file_stat.m_comp_size; +// comp_remaining = 0; +// } +// else +// { +// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); +// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// read_buf_avail = 0; +// comp_remaining = file_stat.m_comp_size; +// } + +// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) +// { +// /* The file is stored or the caller has requested the compressed data. */ +// if (pZip->m_pState->m_pMem) +// { +// if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) +// { +// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); +// status = TINFL_STATUS_FAILED; +// } +// else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +// { +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); +// #endif +// } + +// cur_file_ofs += file_stat.m_comp_size; +// out_buf_ofs += file_stat.m_comp_size; +// comp_remaining = 0; +// } +// else +// { +// while (comp_remaining) +// { +// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// status = TINFL_STATUS_FAILED; +// break; +// } + +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +// { +// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); +// } +// #endif + +// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +// { +// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); +// status = TINFL_STATUS_FAILED; +// break; +// } + +// cur_file_ofs += read_buf_avail; +// out_buf_ofs += read_buf_avail; +// comp_remaining -= read_buf_avail; +// } +// } +// } +// else +// { +// tinfl_decompressor inflator; +// tinfl_init(&inflator); + +// if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) +// { +// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// status = TINFL_STATUS_FAILED; +// } +// else +// { +// do +// { +// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); +// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); +// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) +// { +// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// status = TINFL_STATUS_FAILED; +// break; +// } +// cur_file_ofs += read_buf_avail; +// comp_remaining -= read_buf_avail; +// read_buf_ofs = 0; +// } + +// in_buf_size = (size_t)read_buf_avail; +// status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); +// read_buf_avail -= in_buf_size; +// read_buf_ofs += in_buf_size; + +// if (out_buf_size) +// { +// if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) +// { +// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); +// status = TINFL_STATUS_FAILED; +// break; +// } + +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); +// #endif +// if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) +// { +// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); +// status = TINFL_STATUS_FAILED; +// break; +// } +// } +// } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); +// } +// } + +// if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) +// { +// /* Make sure the entire file was decompressed, and check its CRC. */ +// if (out_buf_ofs != file_stat.m_uncomp_size) +// { +// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); +// status = TINFL_STATUS_FAILED; +// } +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// else if (file_crc32 != file_stat.m_crc32) +// { +// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); +// status = TINFL_STATUS_FAILED; +// } +// #endif +// } + +// if (!pZip->m_pState->m_pMem) +// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + +// if (pWrite_buf) +// pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + +// return status == TINFL_STATUS_DONE; +// } + +// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +// { +// mz_uint32 file_index; +// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +// return MZ_FALSE; + +// return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); +// } + +// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) +// { +// mz_zip_reader_extract_iter_state *pState; +// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + +// /* Argument sanity check */ +// if ((!pZip) || (!pZip->m_pState)) +// return NULL; + +// /* Allocate an iterator status structure */ +// pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); +// if (!pState) +// { +// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// return NULL; +// } + +// /* Fetch file details */ +// if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } + +// /* Encryption and patch files are not supported. */ +// if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } + +// /* This function only supports decompressing stored and deflate. */ +// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } + +// /* Init state - save args */ +// pState->pZip = pZip; +// pState->flags = flags; + +// /* Init state - reset variables to defaults */ +// pState->status = TINFL_STATUS_DONE; +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// pState->file_crc32 = MZ_CRC32_INIT; +// #endif +// pState->read_buf_ofs = 0; +// pState->out_buf_ofs = 0; +// pState->pRead_buf = NULL; +// pState->pWrite_buf = NULL; +// pState->out_blk_remain = 0; + +// /* Read and parse the local directory entry. */ +// pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; +// if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } + +// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } + +// pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +// if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } + +// /* Decompress the file either directly from memory or from a file input buffer. */ +// if (pZip->m_pState->m_pMem) +// { +// pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; +// pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; +// pState->comp_remaining = pState->file_stat.m_comp_size; +// } +// else +// { +// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) +// { +// /* Decompression required, therefore intermediate read buffer required */ +// pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); +// if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) +// { +// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } +// } +// else +// { +// /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ +// pState->read_buf_size = 0; +// } +// pState->read_buf_avail = 0; +// pState->comp_remaining = pState->file_stat.m_comp_size; +// } + +// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) +// { +// /* Decompression required, init decompressor */ +// tinfl_init( &pState->inflator ); + +// /* Allocate write buffer */ +// if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) +// { +// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// if (pState->pRead_buf) +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } +// } + +// return pState; +// } + +// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +// { +// mz_uint32 file_index; + +// /* Locate file index by name */ +// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +// return NULL; + +// /* Construct iterator */ +// return mz_zip_reader_extract_iter_new(pZip, file_index, flags); +// } + +// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) +// { +// size_t copied_to_caller = 0; + +// /* Argument sanity check */ +// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) +// return 0; + +// if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) +// { +// /* The file is stored or the caller has requested the compressed data, calc amount to return. */ +// copied_to_caller = MZ_MIN( buf_size, pState->comp_remaining ); + +// /* Zip is in memory....or requires reading from a file? */ +// if (pState->pZip->m_pState->m_pMem) +// { +// /* Copy data to caller's buffer */ +// memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); +// pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; +// } +// else +// { +// /* Read directly into caller's buffer */ +// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) +// { +// /* Failed to read all that was asked for, flag failure and alert user */ +// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); +// pState->status = TINFL_STATUS_FAILED; +// copied_to_caller = 0; +// } +// } + +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// /* Compute CRC if not returning compressed data only */ +// if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); +// #endif + +// /* Advance offsets, dec counters */ +// pState->cur_file_ofs += copied_to_caller; +// pState->out_buf_ofs += copied_to_caller; +// pState->comp_remaining -= copied_to_caller; +// } +// else +// { +// do +// { +// /* Calc ptr to write buffer - given current output pos and block size */ +// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + +// /* Calc max output size - given current output pos and block size */ +// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + +// if (!pState->out_blk_remain) +// { +// /* Read more data from file if none available (and reading from file) */ +// if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) +// { +// /* Calc read size */ +// pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); +// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) +// { +// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); +// pState->status = TINFL_STATUS_FAILED; +// break; +// } + +// /* Advance offsets, dec counters */ +// pState->cur_file_ofs += pState->read_buf_avail; +// pState->comp_remaining -= pState->read_buf_avail; +// pState->read_buf_ofs = 0; +// } + +// /* Perform decompression */ +// in_buf_size = (size_t)pState->read_buf_avail; +// pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); +// pState->read_buf_avail -= in_buf_size; +// pState->read_buf_ofs += in_buf_size; + +// /* Update current output block size remaining */ +// pState->out_blk_remain = out_buf_size; +// } + +// if (pState->out_blk_remain) +// { +// /* Calc amount to return. */ +// size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); + +// /* Copy data to caller's buffer */ +// memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); + +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// /* Perform CRC */ +// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); +// #endif + +// /* Decrement data consumed from block */ +// pState->out_blk_remain -= to_copy; + +// /* Inc output offset, while performing sanity check */ +// if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) +// { +// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); +// pState->status = TINFL_STATUS_FAILED; +// break; +// } + +// /* Increment counter of data copied to caller */ +// copied_to_caller += to_copy; +// } +// } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); +// } + +// /* Return how many bytes were copied into user buffer */ +// return copied_to_caller; +// } + +// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) +// { +// int status; + +// /* Argument sanity check */ +// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) +// return MZ_FALSE; + +// /* Was decompression completed and requested? */ +// if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) +// { +// /* Make sure the entire file was decompressed, and check its CRC. */ +// if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) +// { +// mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); +// pState->status = TINFL_STATUS_FAILED; +// } +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// else if (pState->file_crc32 != pState->file_stat.m_crc32) +// { +// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); +// pState->status = TINFL_STATUS_FAILED; +// } +// #endif +// } + +// /* Free buffers */ +// if (!pState->pZip->m_pState->m_pMem) +// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); +// if (pState->pWrite_buf) +// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); + +// /* Save status */ +// status = pState->status; + +// /* Free context */ +// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); + +// return status == TINFL_STATUS_DONE; +// } + +// #ifndef MINIZ_NO_STDIO +// static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) +// { +// (void)ofs; + +// return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); +// } + +// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) +// { +// mz_bool status; +// mz_zip_archive_file_stat file_stat; +// MZ_FILE *pFile; + +// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +// return MZ_FALSE; + +// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + +// pFile = MZ_FOPEN(pDst_filename, "wb"); +// if (!pFile) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +// status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); + +// if (MZ_FCLOSE(pFile) == EOF) +// { +// if (status) +// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); + +// status = MZ_FALSE; +// } + +// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) +// if (status) +// mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); +// #endif + +// return status; +// } + +// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) +// { +// mz_uint32 file_index; +// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) +// return MZ_FALSE; + +// return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); +// } + +// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) +// { +// mz_zip_archive_file_stat file_stat; + +// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +// return MZ_FALSE; + +// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + +// return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); +// } + +// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) +// { +// mz_uint32 file_index; +// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) +// return MZ_FALSE; + +// return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); +// } +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +// { +// mz_uint32 *p = (mz_uint32 *)pOpaque; +// (void)file_ofs; +// *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n); +// return n; +// } + +// mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) +// { +// mz_zip_archive_file_stat file_stat; +// mz_zip_internal_state *pState; +// const mz_uint8 *pCentral_dir_header; +// mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE; +// mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; +// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; +// mz_uint64 local_header_ofs = 0; +// mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32; +// mz_uint64 local_header_comp_size, local_header_uncomp_size; +// mz_uint32 uncomp_crc32 = MZ_CRC32_INIT; +// mz_bool has_data_descriptor; +// mz_uint32 local_header_bit_flags; + +// mz_zip_array file_data_array; +// mz_zip_array_init(&file_data_array, 1); + +// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (file_index > pZip->m_total_files) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pState = pZip->m_pState; + +// pCentral_dir_header = mz_zip_get_cdh(pZip, file_index); + +// if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir)) +// return MZ_FALSE; + +// /* A directory or zero length file */ +// if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size)) +// return MZ_TRUE; + +// /* Encryption and patch files are not supported. */ +// if (file_stat.m_is_encrypted) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + +// /* This function only supports stored and deflate. */ +// if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + +// if (!file_stat.m_is_supported) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + +// /* Read and parse the local directory entry. */ +// local_header_ofs = file_stat.m_local_header_ofs; +// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); +// local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +// local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); +// local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); +// local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS); +// local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); +// has_data_descriptor = (local_header_bit_flags & 8) != 0; + +// if (local_header_filename_len != strlen(file_stat.m_filename)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size) > pZip->m_archive_size) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if (!mz_zip_array_resize(pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE)) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// if (local_header_filename_len) +// { +// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE, file_data_array.m_p, local_header_filename_len) != local_header_filename_len) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// goto handle_failure; +// } + +// /* I've seen 1 archive that had the same pathname, but used backslashes in the local dir and forward slashes in the central dir. Do we care about this? For now, this case will fail validation. */ +// if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0) +// { +// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); +// goto handle_failure; +// } +// } + +// if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) +// { +// mz_uint32 extra_size_remaining = local_header_extra_len; +// const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p; + +// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// goto handle_failure; +// } + +// do +// { +// mz_uint32 field_id, field_data_size, field_total_size; + +// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// field_id = MZ_READ_LE16(pExtra_data); +// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); +// field_total_size = field_data_size + sizeof(mz_uint16) * 2; + +// if (field_total_size > extra_size_remaining) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) +// { +// const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); + +// if (field_data_size < sizeof(mz_uint64) * 2) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// goto handle_failure; +// } + +// local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); +// local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); + +// found_zip64_ext_data_in_ldir = MZ_TRUE; +// break; +// } + +// pExtra_data += field_total_size; +// extra_size_remaining -= field_total_size; +// } while (extra_size_remaining); +// } + +// /* TODO: parse local header extra data when local_header_comp_size is 0xFFFFFFFF! (big_descriptor.zip) */ +// /* I've seen zips in the wild with the data descriptor bit set, but proper local header values and bogus data descriptors */ +// if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32)) +// { +// mz_uint8 descriptor_buf[32]; +// mz_bool has_id; +// const mz_uint8 *pSrc; +// mz_uint32 file_crc32; +// mz_uint64 comp_size = 0, uncomp_size = 0; + +// mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4; + +// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size, descriptor_buf, sizeof(mz_uint32) * num_descriptor_uint32s) != (sizeof(mz_uint32) * num_descriptor_uint32s)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// goto handle_failure; +// } + +// has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID); +// pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf; + +// file_crc32 = MZ_READ_LE32(pSrc); + +// if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) +// { +// comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32)); +// uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64)); +// } +// else +// { +// comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32)); +// uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32)); +// } + +// if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); +// goto handle_failure; +// } +// } +// else +// { +// if ((local_header_crc32 != file_stat.m_crc32) || (local_header_comp_size != file_stat.m_comp_size) || (local_header_uncomp_size != file_stat.m_uncomp_size)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); +// goto handle_failure; +// } +// } + +// mz_zip_array_clear(pZip, &file_data_array); + +// if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0) +// { +// if (!mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0)) +// return MZ_FALSE; + +// /* 1 more check to be sure, although the extract checks too. */ +// if (uncomp_crc32 != file_stat.m_crc32) +// { +// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); +// return MZ_FALSE; +// } +// } + +// return MZ_TRUE; + +// handle_failure: +// mz_zip_array_clear(pZip, &file_data_array); +// return MZ_FALSE; +// } + +// mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) +// { +// mz_zip_internal_state *pState; +// uint32_t i; + +// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pState = pZip->m_pState; + +// /* Basic sanity checks */ +// if (!pState->m_zip64) +// { +// if (pZip->m_total_files > MZ_UINT16_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +// if (pZip->m_archive_size > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); +// } +// else +// { +// if (pZip->m_total_files >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +// if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); +// } + +// for (i = 0; i < pZip->m_total_files; i++) +// { +// if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) +// { +// mz_uint32 found_index; +// mz_zip_archive_file_stat stat_; + +// if (!mz_zip_reader_file_stat(pZip, i, &stat_)) +// return MZ_FALSE; + +// if (!mz_zip_reader_locate_file_v2(pZip, stat_.m_filename, NULL, 0, &found_index)) +// return MZ_FALSE; + +// /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ +// if (found_index != i) +// return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); +// } + +// if (!mz_zip_validate_file(pZip, i, flags)) +// return MZ_FALSE; +// } + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr) +// { +// mz_bool success = MZ_TRUE; +// mz_zip_archive zip; +// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + +// if ((!pMem) || (!size)) +// { +// if (pErr) +// *pErr = MZ_ZIP_INVALID_PARAMETER; +// return MZ_FALSE; +// } + +// mz_zip_zero_struct(&zip); + +// if (!mz_zip_reader_init_mem(&zip, pMem, size, flags)) +// { +// if (pErr) +// *pErr = zip.m_last_error; +// return MZ_FALSE; +// } + +// if (!mz_zip_validate_archive(&zip, flags)) +// { +// actual_err = zip.m_last_error; +// success = MZ_FALSE; +// } + +// if (!mz_zip_reader_end_internal(&zip, success)) +// { +// if (!actual_err) +// actual_err = zip.m_last_error; +// success = MZ_FALSE; +// } + +// if (pErr) +// *pErr = actual_err; + +// return success; +// } + +// #ifndef MINIZ_NO_STDIO +// mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr) +// { +// mz_bool success = MZ_TRUE; +// mz_zip_archive zip; +// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + +// if (!pFilename) +// { +// if (pErr) +// *pErr = MZ_ZIP_INVALID_PARAMETER; +// return MZ_FALSE; +// } + +// mz_zip_zero_struct(&zip); + +// if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0)) +// { +// if (pErr) +// *pErr = zip.m_last_error; +// return MZ_FALSE; +// } + +// if (!mz_zip_validate_archive(&zip, flags)) +// { +// actual_err = zip.m_last_error; +// success = MZ_FALSE; +// } + +// if (!mz_zip_reader_end_internal(&zip, success)) +// { +// if (!actual_err) +// actual_err = zip.m_last_error; +// success = MZ_FALSE; +// } + +// if (pErr) +// *pErr = actual_err; + +// return success; +// } +// #endif /* #ifndef MINIZ_NO_STDIO */ + +/* ------------------- .ZIP archive writing */ + +// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +// static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) +// { +// p[0] = (mz_uint8)v; +// p[1] = (mz_uint8)(v >> 8); +// } +// static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) +// { +// p[0] = (mz_uint8)v; +// p[1] = (mz_uint8)(v >> 8); +// p[2] = (mz_uint8)(v >> 16); +// p[3] = (mz_uint8)(v >> 24); +// } +// static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) +// { +// mz_write_le32(p, (mz_uint32)v); +// mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); +// } + +// #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) +// #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) +// #define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) + +// static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +// { +// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +// mz_zip_internal_state *pState = pZip->m_pState; +// mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); + +// if (!n) +// return 0; + +// /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ +// if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); +// return 0; +// } + +// if (new_size > pState->m_mem_capacity) +// { +// void *pNew_block; +// size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); + +// while (new_capacity < new_size) +// new_capacity *= 2; + +// if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) +// { +// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// return 0; +// } + +// pState->m_pMem = pNew_block; +// pState->m_mem_capacity = new_capacity; +// } +// memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); +// pState->m_mem_size = (size_t)new_size; +// return n; +// } + +// static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +// { +// mz_zip_internal_state *pState; +// mz_bool status = MZ_TRUE; + +// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) +// { +// if (set_last_error) +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// return MZ_FALSE; +// } + +// pState = pZip->m_pState; +// pZip->m_pState = NULL; +// mz_zip_array_clear(pZip, &pState->m_central_dir); +// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); +// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +// #ifndef MINIZ_NO_STDIO +// if (pState->m_pFile) +// { +// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) +// { +// if (MZ_FCLOSE(pState->m_pFile) == EOF) +// { +// if (set_last_error) +// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); +// status = MZ_FALSE; +// } +// } + +// pState->m_pFile = NULL; +// } +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); +// pState->m_pMem = NULL; +// } + +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; +// return status; +// } + +// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) +// { +// mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; + +// if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +// { +// if (!pZip->m_pRead) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// } + +// if (pZip->m_file_offset_alignment) +// { +// /* Ensure user specified file offset alignment is a power of 2. */ +// if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// } + +// if (!pZip->m_pAlloc) +// pZip->m_pAlloc = miniz_def_alloc_func; +// if (!pZip->m_pFree) +// pZip->m_pFree = miniz_def_free_func; +// if (!pZip->m_pRealloc) +// pZip->m_pRealloc = miniz_def_realloc_func; + +// pZip->m_archive_size = existing_size; +// pZip->m_central_directory_file_ofs = 0; +// pZip->m_total_files = 0; + +// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + +// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); +// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); +// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + +// pZip->m_pState->m_zip64 = zip64; +// pZip->m_pState->m_zip64_has_extended_info_fields = zip64; + +// pZip->m_zip_type = MZ_ZIP_TYPE_USER; +// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) +// { +// return mz_zip_writer_init_v2(pZip, existing_size, 0); +// } + +// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) +// { +// pZip->m_pWrite = mz_zip_heap_write_func; +// pZip->m_pNeeds_keepalive = NULL; + +// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +// pZip->m_pRead = mz_zip_mem_read_func; + +// pZip->m_pIO_opaque = pZip; + +// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) +// return MZ_FALSE; + +// pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; + +// if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) +// { +// if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) +// { +// mz_zip_writer_end_internal(pZip, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } +// pZip->m_pState->m_mem_capacity = initial_allocation_size; +// } + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) +// { +// return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); +// } + +// #ifndef MINIZ_NO_STDIO +// static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +// { +// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + +// file_ofs += pZip->m_pState->m_file_archive_start_ofs; + +// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); +// return 0; +// } + +// return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); +// } + +// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) +// { +// return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); +// } + +// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) +// { +// MZ_FILE *pFile; + +// pZip->m_pWrite = mz_zip_file_write_func; +// pZip->m_pNeeds_keepalive = NULL; + +// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +// pZip->m_pRead = mz_zip_file_read_func; + +// pZip->m_pIO_opaque = pZip; + +// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) +// return MZ_FALSE; + +// if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) +// { +// mz_zip_writer_end(pZip); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); +// } + +// pZip->m_pState->m_pFile = pFile; +// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; + +// if (size_to_reserve_at_beginning) +// { +// mz_uint64 cur_ofs = 0; +// char buf[4096]; + +// MZ_CLEAR_OBJ(buf); + +// do +// { +// size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) +// { +// mz_zip_writer_end(pZip); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } +// cur_ofs += n; +// size_to_reserve_at_beginning -= n; +// } while (size_to_reserve_at_beginning); +// } + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) +// { +// pZip->m_pWrite = mz_zip_file_write_func; +// pZip->m_pNeeds_keepalive = NULL; + +// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +// pZip->m_pRead = mz_zip_file_read_func; + +// pZip->m_pIO_opaque = pZip; + +// if (!mz_zip_writer_init_v2(pZip, 0, flags)) +// return MZ_FALSE; + +// pZip->m_pState->m_pFile = pFile; +// pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); +// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; + +// return MZ_TRUE; +// } +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +// { +// mz_zip_internal_state *pState; + +// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) +// { +// /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ +// if (!pZip->m_pState->m_zip64) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// } + +// /* No sense in trying to write to an archive that's already at the support max size */ +// if (pZip->m_pState->m_zip64) +// { +// if (pZip->m_total_files == MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +// } +// else +// { +// if (pZip->m_total_files == MZ_UINT16_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + +// if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); +// } + +// pState = pZip->m_pState; + +// if (pState->m_pFile) +// { +// #ifdef MINIZ_NO_STDIO +// (void)pFilename; +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// #else +// if (pZip->m_pIO_opaque != pZip) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) +// { +// if (!pFilename) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ +// if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) +// { +// /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ +// mz_zip_reader_end_internal(pZip, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); +// } +// } + +// pZip->m_pWrite = mz_zip_file_write_func; +// pZip->m_pNeeds_keepalive = NULL; +// #endif /* #ifdef MINIZ_NO_STDIO */ +// } +// else if (pState->m_pMem) +// { +// /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ +// if (pZip->m_pIO_opaque != pZip) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pState->m_mem_capacity = pState->m_mem_size; +// pZip->m_pWrite = mz_zip_heap_write_func; +// pZip->m_pNeeds_keepalive = NULL; +// } +// /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ +// else if (!pZip->m_pWrite) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// /* Start writing new files at the archive's current central directory location. */ +// /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ +// pZip->m_archive_size = pZip->m_central_directory_file_ofs; +// pZip->m_central_directory_file_ofs = 0; + +// /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ +// /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ +// /* TODO: We could easily maintain the sorted central directory offsets. */ +// mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); + +// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) +// { +// return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); +// } + +/* TODO: pArchive_name is a terrible name here! */ +// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) +// { +// return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); +// } + +// typedef struct +// { +// mz_zip_archive *m_pZip; +// mz_uint64 m_cur_archive_file_ofs; +// mz_uint64 m_comp_size; +// } mz_zip_writer_add_state; + +// static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) +// { +// mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; +// if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) +// return MZ_FALSE; + +// pState->m_cur_archive_file_ofs += len; +// pState->m_comp_size += len; +// return MZ_TRUE; +// } + +// #define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) +// #define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) +// static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) +// { +// mz_uint8 *pDst = pBuf; +// mz_uint32 field_size = 0; + +// MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); +// MZ_WRITE_LE16(pDst + 2, 0); +// pDst += sizeof(mz_uint16) * 2; + +// if (pUncomp_size) +// { +// MZ_WRITE_LE64(pDst, *pUncomp_size); +// pDst += sizeof(mz_uint64); +// field_size += sizeof(mz_uint64); +// } + +// if (pComp_size) +// { +// MZ_WRITE_LE64(pDst, *pComp_size); +// pDst += sizeof(mz_uint64); +// field_size += sizeof(mz_uint64); +// } + +// if (pLocal_header_ofs) +// { +// MZ_WRITE_LE64(pDst, *pLocal_header_ofs); +// pDst += sizeof(mz_uint64); +// field_size += sizeof(mz_uint64); +// } + +// MZ_WRITE_LE16(pBuf + 2, field_size); + +// return (mz_uint32)(pDst - pBuf); +// } + +// static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) +// { +// (void)pZip; +// memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); +// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); +// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); +// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); +// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); +// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); +// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); +// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); +// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); +// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); +// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); +// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); +// return MZ_TRUE; +// } + +// static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, +// mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, +// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, +// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, +// mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +// { +// (void)pZip; +// memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); +// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); +// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); +// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); +// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); +// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); +// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); +// return MZ_TRUE; +// } + +// static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, +// const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, +// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, +// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, +// mz_uint64 local_header_ofs, mz_uint32 ext_attributes, +// const char *user_extra_data, mz_uint user_extra_data_len) +// { +// mz_zip_internal_state *pState = pZip->m_pState; +// mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; +// size_t orig_central_dir_size = pState->m_central_dir.m_size; +// mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + +// if (!pZip->m_pState->m_zip64) +// { +// if (local_header_ofs > 0xFFFFFFFF) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); +// } + +// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ +// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +// if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size + user_extra_data_len, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +// if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || +// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || +// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || +// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || +// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || +// (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) +// { +// /* Try to resize the central directory array back into its original state. */ +// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// return MZ_TRUE; +// } + +// static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) +// { +// /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ +// if (*pArchive_name == '/') +// return MZ_FALSE; + +// while (*pArchive_name) +// { +// if ((*pArchive_name == '\\') || (*pArchive_name == ':')) +// return MZ_FALSE; + +// pArchive_name++; +// } + +// return MZ_TRUE; +// } + +// static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) +// { +// mz_uint32 n; +// if (!pZip->m_file_offset_alignment) +// return 0; +// n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); +// return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); +// } + +// static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) +// { +// char buf[4096]; +// memset(buf, 0, MZ_MIN(sizeof(buf), n)); +// while (n) +// { +// mz_uint32 s = MZ_MIN(sizeof(buf), n); +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_file_ofs += s; +// n -= s; +// } +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) +// { +// return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); +// } + +// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, +// mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, +// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +// { +// if(!pZip) +// { +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// } + +// mz_uint16 method = 0, dos_time = 0, dos_date = 0; +// mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; +// mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; +// size_t archive_name_size; +// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; +// tdefl_compressor *pComp = NULL; +// mz_bool store_data_uncompressed; +// mz_zip_internal_state *pState; +// mz_uint8 *pExtra_data = NULL; +// mz_uint32 extra_size = 0; +// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; +// mz_uint16 bit_flags = 0; + +// if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) +// bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; + +// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) +// bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + +// if ((int)level_and_flags < 0) +// level_and_flags = MZ_DEFAULT_LEVEL; +// level = level_and_flags & 0xF; +// store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + +// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pState = pZip->m_pState; + +// if (pState->m_zip64) +// { +// if (pZip->m_total_files == MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +// } +// else +// { +// if (pZip->m_total_files == MZ_UINT16_MAX) +// { +// pState->m_zip64 = MZ_TRUE; +// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ +// } +// if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) +// { +// pState->m_zip64 = MZ_TRUE; +// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +// } +// } + +// if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (!mz_zip_writer_validate_archive_name(pArchive_name)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +// #ifndef MINIZ_NO_TIME +// if (last_modified != NULL) +// { +// mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); +// } +// else +// { +// MZ_TIME_T cur_time; +// time(&cur_time); +// mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); +// } +// #endif /* #ifndef MINIZ_NO_TIME */ + +// archive_name_size = strlen(pArchive_name); +// if (archive_name_size > MZ_UINT16_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + +// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ +// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +// if (!pState->m_zip64) +// { +// /* Bail early if the archive would obviously become too large */ +// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size +// + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + +// pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len +// + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) +// { +// pState->m_zip64 = MZ_TRUE; +// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +// } +// } + +// if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) +// { +// /* Set DOS Subdirectory attribute bit. */ +// ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; + +// /* Subdirectories cannot contain data. */ +// if ((buf_size) || (uncomp_size)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// } + +// /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ +// if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// if ((!store_data_uncompressed) && (buf_size)) +// { +// if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +// return MZ_FALSE; +// } + +// local_dir_header_ofs += num_alignment_padding_bytes; +// if (pZip->m_file_offset_alignment) +// { +// MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); +// } +// cur_archive_file_ofs += num_alignment_padding_bytes; + +// MZ_CLEAR_OBJ(local_dir_header); + +// if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +// { +// method = MZ_DEFLATED; +// } + +// if (pState->m_zip64) +// { +// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) +// { +// pExtra_data = extra_data; +// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +// } + +// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += sizeof(local_dir_header); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } +// cur_archive_file_ofs += archive_name_size; + +// if (pExtra_data != NULL) +// { +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += extra_size; +// } +// } +// else +// { +// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); +// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += sizeof(local_dir_header); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } +// cur_archive_file_ofs += archive_name_size; +// } + +// if (user_extra_data_len > 0) +// { +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += user_extra_data_len; +// } + +// if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +// { +// uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); +// uncomp_size = buf_size; +// if (uncomp_size <= 3) +// { +// level = 0; +// store_data_uncompressed = MZ_TRUE; +// } +// } + +// if (store_data_uncompressed) +// { +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } + +// cur_archive_file_ofs += buf_size; +// comp_size = buf_size; +// } +// else if (buf_size) +// { +// mz_zip_writer_add_state state; + +// state.m_pZip = pZip; +// state.m_cur_archive_file_ofs = cur_archive_file_ofs; +// state.m_comp_size = 0; + +// if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || +// (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +// return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); +// } + +// comp_size = state.m_comp_size; +// cur_archive_file_ofs = state.m_cur_archive_file_ofs; +// } + +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +// pComp = NULL; + +// if (uncomp_size) +// { +// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; +// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + +// MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); + +// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); +// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); +// if (pExtra_data == NULL) +// { +// if (comp_size > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); +// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); +// } +// else +// { +// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); +// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); +// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; +// } + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) +// return MZ_FALSE; + +// cur_archive_file_ofs += local_dir_footer_size; +// } + +// if (pExtra_data != NULL) +// { +// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +// } + +// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, +// comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, +// user_extra_data_central, user_extra_data_central_len)) +// return MZ_FALSE; + +// pZip->m_total_files++; +// pZip->m_archive_size = cur_archive_file_ofs; + +// return MZ_TRUE; +// } + +// #ifndef MINIZ_NO_STDIO +// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +// { +// if(!pZip) +// { +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// } + +// mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; +// mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; +// mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; +// mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; +// size_t archive_name_size; +// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; +// mz_uint8 *pExtra_data = NULL; +// mz_uint32 extra_size = 0; +// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; +// mz_zip_internal_state *pState; + +// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) +// gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + +// if ((int)level_and_flags < 0) +// level_and_flags = MZ_DEFAULT_LEVEL; +// level = level_and_flags & 0xF; + +// /* Sanity checks */ +// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pState = pZip->m_pState; + +// if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) +// { +// /* Source file is too large for non-zip64 */ +// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +// pState->m_zip64 = MZ_TRUE; +// } + +// /* We could support this, but why? */ +// if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (!mz_zip_writer_validate_archive_name(pArchive_name)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +// if (pState->m_zip64) +// { +// if (pZip->m_total_files == MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +// } +// else +// { +// if (pZip->m_total_files == MZ_UINT16_MAX) +// { +// pState->m_zip64 = MZ_TRUE; +// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ +// } +// } + +// archive_name_size = strlen(pArchive_name); +// if (archive_name_size > MZ_UINT16_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + +// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ +// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +// if (!pState->m_zip64) +// { +// /* Bail early if the archive would obviously become too large */ +// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +// + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 +// + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) +// { +// pState->m_zip64 = MZ_TRUE; +// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +// } +// } + +// #ifndef MINIZ_NO_TIME +// if (pFile_time) +// { +// mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); +// } +// #endif + +// if (uncomp_size <= 3) +// level = 0; + +// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) +// { +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } + +// cur_archive_file_ofs += num_alignment_padding_bytes; +// local_dir_header_ofs = cur_archive_file_ofs; + +// if (pZip->m_file_offset_alignment) +// { +// MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); +// } + +// if (uncomp_size && level) +// { +// method = MZ_DEFLATED; +// } + +// MZ_CLEAR_OBJ(local_dir_header); +// if (pState->m_zip64) +// { +// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) +// { +// pExtra_data = extra_data; +// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +// } + +// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += sizeof(local_dir_header); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +// { +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } + +// cur_archive_file_ofs += archive_name_size; + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += extra_size; +// } +// else +// { +// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); +// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += sizeof(local_dir_header); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +// { +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } + +// cur_archive_file_ofs += archive_name_size; +// } + +// if (user_extra_data_len > 0) +// { +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += user_extra_data_len; +// } + +// if (uncomp_size) +// { +// mz_uint64 uncomp_remaining = uncomp_size; +// void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); +// if (!pRead_buf) +// { +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if (!level) +// { +// while (uncomp_remaining) +// { +// mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); +// if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// } +// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); +// uncomp_remaining -= n; +// cur_archive_file_ofs += n; +// } +// comp_size = uncomp_size; +// } +// else +// { +// mz_bool result = MZ_FALSE; +// mz_zip_writer_add_state state; +// tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); +// if (!pComp) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// state.m_pZip = pZip; +// state.m_cur_archive_file_ofs = cur_archive_file_ofs; +// state.m_comp_size = 0; + +// if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); +// } + +// for (;;) +// { +// size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); +// tdefl_status status; +// tdefl_flush flush = TDEFL_NO_FLUSH; + +// if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// break; +// } + +// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); +// uncomp_remaining -= in_buf_size; + +// if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) +// flush = TDEFL_FULL_FLUSH; + +// status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); +// if (status == TDEFL_STATUS_DONE) +// { +// result = MZ_TRUE; +// break; +// } +// else if (status != TDEFL_STATUS_OKAY) +// { +// mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); +// break; +// } +// } + +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + +// if (!result) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +// return MZ_FALSE; +// } + +// comp_size = state.m_comp_size; +// cur_archive_file_ofs = state.m_cur_archive_file_ofs; +// } + +// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +// } + +// { +// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; +// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + +// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); +// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); +// if (pExtra_data == NULL) +// { +// if (comp_size > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); +// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); +// } +// else +// { +// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); +// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); +// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; +// } + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) +// return MZ_FALSE; + +// cur_archive_file_ofs += local_dir_footer_size; +// } + +// if (pExtra_data != NULL) +// { +// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +// } + +// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, +// uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, +// user_extra_data_central, user_extra_data_central_len)) +// return MZ_FALSE; + +// pZip->m_total_files++; +// pZip->m_archive_size = cur_archive_file_ofs; + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +// { +// MZ_FILE *pSrc_file = NULL; +// mz_uint64 uncomp_size = 0; +// MZ_TIME_T file_modified_time; +// MZ_TIME_T *pFile_time = NULL; +// mz_bool status; + +// memset(&file_modified_time, 0, sizeof(file_modified_time)); + +// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) +// pFile_time = &file_modified_time; +// if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); +// #endif + +// pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); +// if (!pSrc_file) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +// MZ_FSEEK64(pSrc_file, 0, SEEK_END); +// uncomp_size = MZ_FTELL64(pSrc_file); +// MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + +// status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); + +// MZ_FCLOSE(pSrc_file); + +// return status; +// } +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) +// { +// /* + 64 should be enough for any new zip64 data */ +// if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE)) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE); + +// if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start)) +// { +// mz_uint8 new_ext_block[64]; +// mz_uint8 *pDst = new_ext_block; +// mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); +// mz_write_le16(pDst + sizeof(mz_uint16), 0); +// pDst += sizeof(mz_uint16) * 2; + +// if (pUncomp_size) +// { +// mz_write_le64(pDst, *pUncomp_size); +// pDst += sizeof(mz_uint64); +// } + +// if (pComp_size) +// { +// mz_write_le64(pDst, *pComp_size); +// pDst += sizeof(mz_uint64); +// } + +// if (pLocal_header_ofs) +// { +// mz_write_le64(pDst, *pLocal_header_ofs); +// pDst += sizeof(mz_uint64); +// } + +// if (pDisk_start) +// { +// mz_write_le32(pDst, *pDisk_start); +// pDst += sizeof(mz_uint32); +// } + +// mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2)); + +// if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block)) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if ((pExt) && (ext_len)) +// { +// mz_uint32 extra_size_remaining = ext_len; +// const mz_uint8 *pExtra_data = pExt; + +// do +// { +// mz_uint32 field_id, field_data_size, field_total_size; + +// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// field_id = MZ_READ_LE16(pExtra_data); +// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); +// field_total_size = field_data_size + sizeof(mz_uint16) * 2; + +// if (field_total_size > extra_size_remaining) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) +// { +// if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size)) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// pExtra_data += field_total_size; +// extra_size_remaining -= field_total_size; +// } while (extra_size_remaining); +// } + +// return MZ_TRUE; +// } + +/* TODO: This func is now pretty freakin complex due to zip64, split it up? */ +// mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index) +// { +// mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size; +// mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs; +// mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; +// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; +// mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; +// size_t orig_central_dir_size; +// mz_zip_internal_state *pState; +// void *pBuf; +// const mz_uint8 *pSrc_central_header; +// mz_zip_archive_file_stat src_file_stat; +// mz_uint32 src_filename_len, src_comment_len, src_ext_len; +// mz_uint32 local_header_filename_size, local_header_extra_len; +// mz_uint64 local_header_comp_size, local_header_uncomp_size; +// mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; + +// /* Sanity checks */ +// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pState = pZip->m_pState; + +// /* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */ +// if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// /* Get pointer to the source central dir header and crack it */ +// if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index))) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); +// src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS); +// src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len; + +// /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32 fudge factor in case we need to add more extra data) */ +// if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + +// if (!pState->m_zip64) +// { +// if (pZip->m_total_files == MZ_UINT16_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +// } +// else +// { +// /* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */ +// if (pZip->m_total_files == MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +// } + +// if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL)) +// return MZ_FALSE; + +// cur_src_file_ofs = src_file_stat.m_local_header_ofs; +// cur_dst_file_ofs = pZip->m_archive_size; + +// /* Read the source archive's local dir header */ +// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + +// /* Compute the total size we need to copy (filename+extra data+compressed data) */ +// local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); +// local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +// local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); +// local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); +// src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size; + +// /* Try to find a zip64 extended information field */ +// if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) +// { +// mz_zip_array file_data_array; +// const mz_uint8 *pExtra_data; +// mz_uint32 extra_size_remaining = local_header_extra_len; + +// mz_zip_array_init(&file_data_array, 1); +// if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE)) +// { +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, src_file_stat.m_local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_size, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) +// { +// mz_zip_array_clear(pZip, &file_data_array); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// } + +// pExtra_data = (const mz_uint8 *)file_data_array.m_p; + +// do +// { +// mz_uint32 field_id, field_data_size, field_total_size; + +// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) +// { +// mz_zip_array_clear(pZip, &file_data_array); +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// } + +// field_id = MZ_READ_LE16(pExtra_data); +// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); +// field_total_size = field_data_size + sizeof(mz_uint16) * 2; + +// if (field_total_size > extra_size_remaining) +// { +// mz_zip_array_clear(pZip, &file_data_array); +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// } + +// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) +// { +// // const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); + +// if (field_data_size < sizeof(mz_uint64) * 2) +// { +// mz_zip_array_clear(pZip, &file_data_array); +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// } + +// // local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); +// // local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ + +// found_zip64_ext_data_in_ldir = MZ_TRUE; +// break; +// } + +// pExtra_data += field_total_size; +// extra_size_remaining -= field_total_size; +// } while (extra_size_remaining); + +// mz_zip_array_clear(pZip, &file_data_array); +// } + +// if (!pState->m_zip64) +// { +// /* Try to detect if the new archive will most likely wind up too big and bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which could be present, +64 is a fudge factor). */ +// /* We also check when the archive is finalized so this doesn't need to be perfect. */ +// mz_uint64 approx_new_archive_size = cur_dst_file_ofs + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining + (sizeof(mz_uint32) * 4) + +// pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64; + +// if (approx_new_archive_size >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); +// } + +// /* Write dest archive padding */ +// if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) +// return MZ_FALSE; + +// cur_dst_file_ofs += num_alignment_padding_bytes; + +// local_dir_header_ofs = cur_dst_file_ofs; +// if (pZip->m_file_offset_alignment) +// { +// MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); +// } + +// /* The original zip's local header+ext block doesn't change, even with zip64, so we can just copy it over to the dest zip */ +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + +// /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */ +// if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining))))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// while (src_archive_bytes_remaining) +// { +// n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining); +// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// } +// cur_src_file_ofs += n; + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } +// cur_dst_file_ofs += n; + +// src_archive_bytes_remaining -= n; +// } + +// /* Now deal with the optional data descriptor */ +// bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); +// if (bit_flags & 8) +// { +// /* Copy data descriptor */ +// if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir)) +// { +// /* src is zip64, dest must be zip64 */ + +// /* name uint32_t's */ +// /* id 1 (optional in zip64?) */ +// /* crc 1 */ +// /* comp_size 2 */ +// /* uncomp_size 2 */ +// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6)) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// } + +// n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5); +// } +// else +// { +// /* src is NOT zip64 */ +// mz_bool has_id; + +// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// } + +// has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID); + +// if (pZip->m_pState->m_zip64) +// { +// /* dest is zip64, so upgrade the data descriptor */ +// const mz_uint32 *pSrc_descriptor = (const mz_uint32 *)((const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0)); +// const mz_uint32 src_crc32 = pSrc_descriptor[0]; +// const mz_uint64 src_comp_size = pSrc_descriptor[1]; +// const mz_uint64 src_uncomp_size = pSrc_descriptor[2]; + +// mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID); +// mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32); +// mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size); +// mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size); + +// n = sizeof(mz_uint32) * 6; +// } +// else +// { +// /* dest is NOT zip64, just copy it as-is */ +// n = sizeof(mz_uint32) * (has_id ? 4 : 3); +// } +// } + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } + +// // cur_src_file_ofs += n; +// cur_dst_file_ofs += n; +// } +// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + +// /* Finally, add the new central dir header */ +// orig_central_dir_size = pState->m_central_dir.m_size; + +// memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + +// if (pState->m_zip64) +// { +// /* This is the painful part: We need to write a new central dir header + ext block with updated zip64 fields, and ensure the old fields (if any) are not included. */ +// const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len; +// mz_zip_array new_ext_block; + +// mz_zip_array_init(&new_ext_block, sizeof(mz_uint8)); + +// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX); +// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX); +// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX); + +// if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL)) +// { +// mz_zip_array_clear(pZip, &new_ext_block); +// return MZ_FALSE; +// } + +// MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size); + +// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) +// { +// mz_zip_array_clear(pZip, &new_ext_block); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len)) +// { +// mz_zip_array_clear(pZip, &new_ext_block); +// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size)) +// { +// mz_zip_array_clear(pZip, &new_ext_block); +// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len + src_ext_len, src_comment_len)) +// { +// mz_zip_array_clear(pZip, &new_ext_block); +// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// mz_zip_array_clear(pZip, &new_ext_block); +// } +// else +// { +// /* sanity checks */ +// if (cur_dst_file_ofs > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +// if (local_dir_header_ofs >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); + +// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_central_dir_following_data_size)) +// { +// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } +// } + +// /* This shouldn't trigger unless we screwed up during the initial sanity checks */ +// if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) +// { +// /* TODO: Support central dirs >= 32-bits in size */ +// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); +// } + +// n = (mz_uint32)orig_central_dir_size; +// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) +// { +// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// pZip->m_total_files++; +// pZip->m_archive_size = cur_dst_file_ofs; + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) +// { +// mz_zip_internal_state *pState; +// mz_uint64 central_dir_ofs, central_dir_size; +// mz_uint8 hdr[256]; + +// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pState = pZip->m_pState; + +// if (pState->m_zip64) +// { +// if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +// } +// else +// { +// if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +// } + +// central_dir_ofs = 0; +// central_dir_size = 0; +// if (pZip->m_total_files) +// { +// /* Write central directory */ +// central_dir_ofs = pZip->m_archive_size; +// central_dir_size = pState->m_central_dir.m_size; +// pZip->m_central_directory_file_ofs = central_dir_ofs; +// if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// pZip->m_archive_size += central_dir_size; +// } + +// if (pState->m_zip64) +// { +// /* Write zip64 end of central directory header */ +// mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; + +// MZ_CLEAR_OBJ(hdr); +// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); +// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); +// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ +// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); +// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); +// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); +// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); +// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); +// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; + +// /* Write zip64 end of central directory locator */ +// MZ_CLEAR_OBJ(hdr); +// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); +// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); +// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); +// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; +// } + +// /* Write end of central directory record */ +// MZ_CLEAR_OBJ(hdr); +// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); +// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); +// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); +// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); +// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// #ifndef MINIZ_NO_STDIO +// if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; + +// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) +// { +// if ((!ppBuf) || (!pSize)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// *ppBuf = NULL; +// *pSize = 0; + +// if ((!pZip) || (!pZip->m_pState)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (pZip->m_pWrite != mz_zip_heap_write_func) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (!mz_zip_writer_finalize_archive(pZip)) +// return MZ_FALSE; + +// *ppBuf = pZip->m_pState->m_pMem; +// *pSize = pZip->m_pState->m_mem_size; +// pZip->m_pState->m_pMem = NULL; +// pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_end(mz_zip_archive *pZip) +// { +// return mz_zip_writer_end_internal(pZip, MZ_TRUE); +// } + +// #ifndef MINIZ_NO_STDIO +// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +// { +// return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); +// } + +// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) +// { +// mz_bool status, created_new_archive = MZ_FALSE; +// mz_zip_archive zip_archive; +// struct MZ_FILE_STAT_STRUCT file_stat; +// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + +// mz_zip_zero_struct(&zip_archive); +// if ((int)level_and_flags < 0) +// level_and_flags = MZ_DEFAULT_LEVEL; + +// if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) +// { +// if (pErr) +// *pErr = MZ_ZIP_INVALID_PARAMETER; +// return MZ_FALSE; +// } + +// if (!mz_zip_writer_validate_archive_name(pArchive_name)) +// { +// if (pErr) +// *pErr = MZ_ZIP_INVALID_FILENAME; +// return MZ_FALSE; +// } + +// /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ +// /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ +// if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) +// { +// /* Create a new archive. */ +// if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) +// { +// if (pErr) +// *pErr = zip_archive.m_last_error; +// return MZ_FALSE; +// } + +// created_new_archive = MZ_TRUE; +// } +// else +// { +// /* Append to an existing archive. */ +// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) +// { +// if (pErr) +// *pErr = zip_archive.m_last_error; +// return MZ_FALSE; +// } + +// if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) +// { +// if (pErr) +// *pErr = zip_archive.m_last_error; + +// mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); + +// return MZ_FALSE; +// } +// } + +// status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); +// actual_err = zip_archive.m_last_error; + +// /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ +// if (!mz_zip_writer_finalize_archive(&zip_archive)) +// { +// if (!actual_err) +// actual_err = zip_archive.m_last_error; + +// status = MZ_FALSE; +// } + +// if (!mz_zip_writer_end_internal(&zip_archive, status)) +// { +// if (!actual_err) +// actual_err = zip_archive.m_last_error; + +// status = MZ_FALSE; +// } + +// if ((!status) && (created_new_archive)) +// { +// /* It's a new archive and something went wrong, so just delete it. */ +// int ignoredStatus = MZ_DELETE_FILE(pZip_filename); +// (void)ignoredStatus; +// } + +// if (pErr) +// *pErr = actual_err; + +// return status; +// } + +// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) +// { +// mz_uint32 file_index; +// mz_zip_archive zip_archive; +// void *p = NULL; + +// if (pSize) +// *pSize = 0; + +// if ((!pZip_filename) || (!pArchive_name)) +// { +// if (pErr) +// *pErr = MZ_ZIP_INVALID_PARAMETER; + +// return NULL; +// } + +// mz_zip_zero_struct(&zip_archive); +// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) +// { +// if (pErr) +// *pErr = zip_archive.m_last_error; + +// return NULL; +// } + +// if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) +// { +// p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); +// } + +// mz_zip_reader_end_internal(&zip_archive, p != NULL); + +// if (pErr) +// *pErr = zip_archive.m_last_error; + +// return p; +// } + +// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) +// { +// return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); +// } + +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + +/* ------------------- Misc utils */ + +// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) +// { +// return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; +// } + +// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) +// { +// return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; +// } + +// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) +// { +// mz_zip_error prev_err; + +// if (!pZip) +// return MZ_ZIP_INVALID_PARAMETER; + +// prev_err = pZip->m_last_error; + +// pZip->m_last_error = err_num; +// return prev_err; +// } + +// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) +// { +// if (!pZip) +// return MZ_ZIP_INVALID_PARAMETER; + +// return pZip->m_last_error; +// } + +// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) +// { +// return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); +// } + +// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) +// { +// mz_zip_error prev_err; + +// if (!pZip) +// return MZ_ZIP_INVALID_PARAMETER; + +// prev_err = pZip->m_last_error; + +// pZip->m_last_error = MZ_ZIP_NO_ERROR; +// return prev_err; +// } + +// const char *mz_zip_get_error_string(mz_zip_error mz_err) +// { +// switch (mz_err) +// { +// case MZ_ZIP_NO_ERROR: +// return "no error"; +// case MZ_ZIP_UNDEFINED_ERROR: +// return "undefined error"; +// case MZ_ZIP_TOO_MANY_FILES: +// return "too many files"; +// case MZ_ZIP_FILE_TOO_LARGE: +// return "file too large"; +// case MZ_ZIP_UNSUPPORTED_METHOD: +// return "unsupported method"; +// case MZ_ZIP_UNSUPPORTED_ENCRYPTION: +// return "unsupported encryption"; +// case MZ_ZIP_UNSUPPORTED_FEATURE: +// return "unsupported feature"; +// case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: +// return "failed finding central directory"; +// case MZ_ZIP_NOT_AN_ARCHIVE: +// return "not a ZIP archive"; +// case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: +// return "invalid header or archive is corrupted"; +// case MZ_ZIP_UNSUPPORTED_MULTIDISK: +// return "unsupported multidisk archive"; +// case MZ_ZIP_DECOMPRESSION_FAILED: +// return "decompression failed or archive is corrupted"; +// case MZ_ZIP_COMPRESSION_FAILED: +// return "compression failed"; +// case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: +// return "unexpected decompressed size"; +// case MZ_ZIP_CRC_CHECK_FAILED: +// return "CRC-32 check failed"; +// case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: +// return "unsupported central directory size"; +// case MZ_ZIP_ALLOC_FAILED: +// return "allocation failed"; +// case MZ_ZIP_FILE_OPEN_FAILED: +// return "file open failed"; +// case MZ_ZIP_FILE_CREATE_FAILED: +// return "file create failed"; +// case MZ_ZIP_FILE_WRITE_FAILED: +// return "file write failed"; +// case MZ_ZIP_FILE_READ_FAILED: +// return "file read failed"; +// case MZ_ZIP_FILE_CLOSE_FAILED: +// return "file close failed"; +// case MZ_ZIP_FILE_SEEK_FAILED: +// return "file seek failed"; +// case MZ_ZIP_FILE_STAT_FAILED: +// return "file stat failed"; +// case MZ_ZIP_INVALID_PARAMETER: +// return "invalid parameter"; +// case MZ_ZIP_INVALID_FILENAME: +// return "invalid filename"; +// case MZ_ZIP_BUF_TOO_SMALL: +// return "buffer too small"; +// case MZ_ZIP_INTERNAL_ERROR: +// return "internal error"; +// case MZ_ZIP_FILE_NOT_FOUND: +// return "file not found"; +// case MZ_ZIP_ARCHIVE_TOO_LARGE: +// return "archive is too large"; +// case MZ_ZIP_VALIDATION_FAILED: +// return "validation failed"; +// case MZ_ZIP_WRITE_CALLBACK_FAILED: +// return "write calledback failed"; +// default: +// break; +// } + +// return "unknown error"; +// } + +/* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */ +// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) +// { +// if ((!pZip) || (!pZip->m_pState)) +// return MZ_FALSE; + +// return pZip->m_pState->m_zip64; +// } + +// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) +// { +// if ((!pZip) || (!pZip->m_pState)) +// return 0; + +// return pZip->m_pState->m_central_dir.m_size; +// } + +// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) +// { +// return pZip ? pZip->m_total_files : 0; +// } + +// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) +// { +// if (!pZip) +// return 0; +// return pZip->m_archive_size; +// } + +// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) +// { +// if ((!pZip) || (!pZip->m_pState)) +// return 0; +// return pZip->m_pState->m_file_archive_start_ofs; +// } + +// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) +// { +// if ((!pZip) || (!pZip->m_pState)) +// return 0; +// return pZip->m_pState->m_pFile; +// } + +// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) +// { +// if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); +// } + +// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) +// { +// mz_uint n; +// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +// if (!p) +// { +// if (filename_buf_size) +// pFilename[0] = '\0'; +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// return 0; +// } +// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// if (filename_buf_size) +// { +// n = MZ_MIN(n, filename_buf_size - 1); +// memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); +// pFilename[n] = '\0'; +// } +// return n + 1; +// } + +// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) +// { +// return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); +// } + +// mz_bool mz_zip_end(mz_zip_archive *pZip) +// { +// if (!pZip) +// return MZ_FALSE; + +// if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) +// return mz_zip_reader_end(pZip); +// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +// else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) +// return mz_zip_writer_end(pZip); +// #endif + +// return MZ_FALSE; +// } + +// #ifdef __cplusplus +// } +// #endif + +// #endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ diff --git a/gomspace/libutil/src/zip/miniz/miniz.h b/gomspace/libutil/src/zip/miniz/miniz.h new file mode 100644 index 00000000..e5172634 --- /dev/null +++ b/gomspace/libutil/src/zip/miniz/miniz.h @@ -0,0 +1,1329 @@ +/* miniz.c 2.0.6 beta - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated Oct. 13, 2013 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + + Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define + MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). + + * Low-level Deflate/Inflate implementation notes: + + Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or + greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses + approximately as well as zlib. + + Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function + coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory + block large enough to hold the entire file. + + The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. + + * zlib-style API notes: + + miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in + zlib replacement in many apps: + The z_stream struct, optional memory allocation callbacks + deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound + inflateInit/inflateInit2/inflate/inflateEnd + compress, compress2, compressBound, uncompress + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. + Supports raw deflate streams or standard zlib streams with adler-32 checking. + + Limitations: + The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. + I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but + there are no guarantees that miniz.c pulls this off perfectly. + + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by + Alex Evans. Supports 1-4 bytes/pixel images. + + * ZIP archive API notes: + + The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to + get the job done with minimal fuss. There are simple API's to retrieve file information, read files from + existing archives, create new archives, append new files to existing archives, or clone archive data from + one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), + or you can specify custom file read/write callbacks. + + - Archive reading: Just call this function to read a single file from a disk archive: + + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + + For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central + directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. + + - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + + The locate operation can optionally check file comments too, which (as one example) can be used to identify + multiple versions of the same file in an archive. This function uses a simple linear search through the central + directory, so it's not very fast. + + Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and + retrieve detailed info on each file by calling mz_zip_reader_file_stat(). + + - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data + to disk and builds an exact image of the central directory in memory. The central directory image is written + all at once at the end of the archive file when the archive is finalized. + + The archive writer can optionally align each file's local header and file data to any power of 2 alignment, + which can be useful when the archive will be read from optical media. Also, the writer supports placing + arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still + readable by any ZIP tool. + + - Archive appending: The simple way to add a single file to an archive is to call this function: + + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, + const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + + The archive will be created if it doesn't already exist, otherwise it'll be appended to. + Note the appending is done in-place and is not an atomic operation, so if something goes wrong + during the operation it's possible the archive could be left without a central directory (although the local + file headers and file data will be fine, so the archive will be recoverable). + + For more complex archive modification scenarios: + 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to + preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the + compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and + you're done. This is safe but requires a bunch of temporary disk space or heap memory. + + 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), + append new files as needed, then finalize the archive which will write an updated central directory to the + original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a + possibility that the archive's central directory could be lost with this method if anything goes wrong, though. + + - ZIP archive support limitations: + No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. + Requires streams capable of seeking. + + * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the + below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. + + * Important: For best perf. be sure to customize the below macros for your target platform: + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 + #define MINIZ_LITTLE_ENDIAN 1 + #define MINIZ_HAS_64BIT_REGISTERS 1 + + * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz + uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files + (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). +*/ +#pragma once + + + + + +/* Defines to completely disable specific portions of miniz.c: + If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. */ + +/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */ +/*#define MINIZ_NO_STDIO */ + +/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */ +/* get/set file times, and the C run-time funcs that get/set times won't be called. */ +/* The current downside is the times written to your archives will be from 1979. */ +#define MINIZ_NO_TIME + +/* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */ +/*#define MINIZ_NO_ARCHIVE_APIS */ + +/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */ +/*#define MINIZ_NO_ARCHIVE_WRITING_APIS */ + +/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */ +/*#define MINIZ_NO_ZLIB_APIS */ + +/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */ +/*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ + +/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. + Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc + callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user + functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */ +/*#define MINIZ_NO_MALLOC */ + +#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) +/* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux */ +#define MINIZ_NO_TIME +#endif + +#include + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) +#include +#endif + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) +/* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */ +#define MINIZ_X86_OR_X64_CPU 1 +#else +#define MINIZ_X86_OR_X64_CPU 0 +#endif + +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ +#define MINIZ_LITTLE_ENDIAN 1 +#else +#define MINIZ_LITTLE_ENDIAN 0 +#endif + +// #if MINIZ_X86_OR_X64_CPU +/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */ +// #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +// #else +// #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 +// #endif +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 + +#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) +/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). */ +#define MINIZ_HAS_64BIT_REGISTERS 1 +#else +#define MINIZ_HAS_64BIT_REGISTERS 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- zlib-style API Definitions. */ + +/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */ +typedef unsigned long mz_ulong; + +/* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. */ +void mz_free(void *p); + +#define MZ_ADLER32_INIT (1) +/* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */ +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + +#define MZ_CRC32_INIT (0) +/* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ +// mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + +/* Compression strategies. */ +enum +{ + MZ_DEFAULT_STRATEGY = 0, + MZ_FILTERED = 1, + MZ_HUFFMAN_ONLY = 2, + MZ_RLE = 3, + MZ_FIXED = 4 +}; + +/* Method */ +#define MZ_DEFLATED 8 + +/* Heap allocation callbacks. +Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. */ +typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void *opaque, void *address); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); + +/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */ +enum +{ + MZ_NO_COMPRESSION = 0, + MZ_BEST_SPEED = 1, + MZ_BEST_COMPRESSION = 9, + MZ_UBER_COMPRESSION = 10, + MZ_DEFAULT_LEVEL = 6, + MZ_DEFAULT_COMPRESSION = -1 +}; + +#define MZ_VERSION "10.0.1" +#define MZ_VERNUM 0xA010 +#define MZ_VER_MAJOR 10 +#define MZ_VER_MINOR 0 +#define MZ_VER_REVISION 1 +#define MZ_VER_SUBREVISION 0 + +#ifndef MINIZ_NO_ZLIB_APIS + +/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). */ +enum +{ + MZ_NO_FLUSH = 0, + MZ_PARTIAL_FLUSH = 1, + MZ_SYNC_FLUSH = 2, + MZ_FULL_FLUSH = 3, + MZ_FINISH = 4, + MZ_BLOCK = 5 +}; + +/* Return status codes. MZ_PARAM_ERROR is non-standard. */ +enum +{ + MZ_OK = 0, + MZ_STREAM_END = 1, + MZ_NEED_DICT = 2, + MZ_ERRNO = -1, + MZ_STREAM_ERROR = -2, + MZ_DATA_ERROR = -3, + MZ_MEM_ERROR = -4, + MZ_BUF_ERROR = -5, + MZ_VERSION_ERROR = -6, + MZ_PARAM_ERROR = -10000 +}; + +/* Window bits */ +#define MZ_DEFAULT_WINDOW_BITS 15 + +struct mz_internal_state; + +/* Compression/decompression stream struct. */ +typedef struct mz_stream_s +{ + const unsigned char *next_in; /* pointer to next byte to read */ + unsigned int avail_in; /* number of bytes available at next_in */ + mz_ulong total_in; /* total number of bytes consumed so far */ + + unsigned char *next_out; /* pointer to next byte to write */ + unsigned int avail_out; /* number of bytes that can be written to next_out */ + mz_ulong total_out; /* total number of bytes produced so far */ + + char *msg; /* error msg (unused) */ + struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */ + + mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */ + mz_free_func zfree; /* optional heap free function (defaults to free) */ + void *opaque; /* heap alloc function user pointer */ + + int data_type; /* data_type (unused) */ + mz_ulong adler; /* adler32 of the source or uncompressed data */ + mz_ulong reserved; /* not used */ +} mz_stream; + +typedef mz_stream *mz_streamp; + +/* Returns the version string of miniz.c. */ +// const char *mz_version(void); + +/* mz_deflateInit() initializes a compressor with default options: */ +/* Parameters: */ +/* pStream must point to an initialized mz_stream struct. */ +/* level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */ +/* level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. */ +/* (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */ +/* Return values: */ +/* MZ_OK on success. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_PARAM_ERROR if the input parameters are bogus. */ +/* MZ_MEM_ERROR on out of memory. */ +int mz_deflateInit(mz_streamp pStream, int level); + +/* mz_deflateInit2() is like mz_deflate(), except with more control: */ +/* Additional parameters: */ +/* method must be MZ_DEFLATED */ +/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */ +/* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */ +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); + +/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ +// int mz_deflateReset(mz_streamp pStream); + +/* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */ +/* Parameters: */ +/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ +/* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */ +/* Return values: */ +/* MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). */ +/* MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_PARAM_ERROR if one of the parameters is invalid. */ +/* MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) */ +int mz_deflate(mz_streamp pStream, int flush); + +/* mz_deflateEnd() deinitializes a compressor: */ +/* Return values: */ +/* MZ_OK on success. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +int mz_deflateEnd(mz_streamp pStream); + +/* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ +// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + +/* Single-call compression functions mz_compress() and mz_compress2(): */ +/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); + +/* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */ +// mz_ulong mz_compressBound(mz_ulong source_len); + +/* Initializes a decompressor. */ +int mz_inflateInit(mz_streamp pStream); + +/* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: */ +/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */ +int mz_inflateInit2(mz_streamp pStream, int window_bits); + +/* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. */ +/* Parameters: */ +/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ +/* flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */ +/* On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). */ +/* MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. */ +/* Return values: */ +/* MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. */ +/* MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_DATA_ERROR if the deflate stream is invalid. */ +/* MZ_PARAM_ERROR if one of the parameters is invalid. */ +/* MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again */ +/* with more input data, or with more room in the output buffer (except when using single call decompression, described above). */ +int mz_inflate(mz_streamp pStream, int flush); + +/* Deinitializes a decompressor. */ +int mz_inflateEnd(mz_streamp pStream); + +/* Single-call decompression. */ +/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */ +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); + +/* Returns a string description of the specified error code, or NULL if the error code is invalid. */ +// const char *mz_error(int err); + +/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */ +/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ +#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES +typedef unsigned char Byte; +typedef unsigned int uInt; +typedef mz_ulong uLong; +typedef Byte Bytef; +typedef uInt uIntf; +typedef char charf; +typedef int intf; +typedef void *voidpf; +typedef uLong uLongf; +typedef void *voidp; +typedef void *const voidpc; +#define Z_NULL 0 +#define Z_NO_FLUSH MZ_NO_FLUSH +#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH +#define Z_SYNC_FLUSH MZ_SYNC_FLUSH +#define Z_FULL_FLUSH MZ_FULL_FLUSH +#define Z_FINISH MZ_FINISH +#define Z_BLOCK MZ_BLOCK +#define Z_OK MZ_OK +#define Z_STREAM_END MZ_STREAM_END +#define Z_NEED_DICT MZ_NEED_DICT +#define Z_ERRNO MZ_ERRNO +#define Z_STREAM_ERROR MZ_STREAM_ERROR +#define Z_DATA_ERROR MZ_DATA_ERROR +#define Z_MEM_ERROR MZ_MEM_ERROR +#define Z_BUF_ERROR MZ_BUF_ERROR +#define Z_VERSION_ERROR MZ_VERSION_ERROR +#define Z_PARAM_ERROR MZ_PARAM_ERROR +#define Z_NO_COMPRESSION MZ_NO_COMPRESSION +#define Z_BEST_SPEED MZ_BEST_SPEED +#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION +#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION +#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY +#define Z_FILTERED MZ_FILTERED +#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY +#define Z_RLE MZ_RLE +#define Z_FIXED MZ_FIXED +#define Z_DEFLATED MZ_DEFLATED +#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS +#define alloc_func mz_alloc_func +#define free_func mz_free_func +#define internal_state mz_internal_state +#define z_stream mz_stream +#define deflateInit mz_deflateInit +#define deflateInit2 mz_deflateInit2 +// #define deflateReset mz_deflateReset +#define deflate mz_deflate +#define deflateEnd mz_deflateEnd +// #define deflateBound mz_deflateBound +#define compress mz_compress +#define compress2 mz_compress2 +// #define compressBound mz_compressBound +#define inflateInit mz_inflateInit +#define inflateInit2 mz_inflateInit2 +#define inflate mz_inflate +#define inflateEnd mz_inflateEnd +#define uncompress mz_uncompress +// #define crc32 mz_crc32 +#define adler32 mz_adler32 +#define MAX_WBITS 15 +#define MAX_MEM_LEVEL 9 +// #define zError mz_error +#define ZLIB_VERSION MZ_VERSION +#define ZLIB_VERNUM MZ_VERNUM +#define ZLIB_VER_MAJOR MZ_VER_MAJOR +#define ZLIB_VER_MINOR MZ_VER_MINOR +#define ZLIB_VER_REVISION MZ_VER_REVISION +#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION +// #define zlibVersion mz_version +// #define zlib_version mz_version() +#endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ + +#endif /* MINIZ_NO_ZLIB_APIS */ + +#ifdef __cplusplus +} +#endif +#pragma once +#include +#include +#include +#include + +/* ------------------- Types and macros */ +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef int64_t mz_int64; +typedef uint64_t mz_uint64; +typedef int mz_bool; + +#define MZ_FALSE (0) +#define MZ_TRUE (1) + +/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */ +#ifdef _MSC_VER +#define MZ_MACRO_END while (0, 0) +#else +#define MZ_MACRO_END while (0) +#endif + +#ifdef MINIZ_NO_STDIO +#define MZ_FILE void * +#else +#include +#define MZ_FILE FILE +#endif /* #ifdef MINIZ_NO_STDIO */ + +// #ifdef MINIZ_NO_TIME +// typedef struct mz_dummy_time_t_tag +// { +// int m_dummy; +// } mz_dummy_time_t; +// #define MZ_TIME_T mz_dummy_time_t +// #else +// #define MZ_TIME_T time_t +// #endif + +#define MZ_ASSERT(x) assert(x) + +#ifdef MINIZ_NO_MALLOC +#define MZ_MALLOC(x) NULL +#define MZ_FREE(x) (void)x, ((void)0) +#define MZ_REALLOC(p, x) NULL +#else +#define MZ_MALLOC(x) malloc(x) +#define MZ_FREE(x) free(x) +#define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) +#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else +#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) +#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#define MZ_READ_LE64(p) (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U)) + +#ifdef _MSC_VER +#define MZ_FORCEINLINE __forceinline +#elif defined(__GNUC__) +#define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__)) +#else +#define MZ_FORCEINLINE inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +extern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); +extern void miniz_def_free_func(void *opaque, void *address); +// extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); + +#define MZ_UINT16_MAX (0xFFFFU) +#define MZ_UINT32_MAX (0xFFFFFFFFU) + +#ifdef __cplusplus +} +#endif +#pragma once + + +#ifdef __cplusplus +extern "C" { +#endif +/* ------------------- Low-level Compression API Definitions */ + +/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). */ +#define TDEFL_LESS_MEMORY 0 + +/* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): */ +/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */ +enum +{ + TDEFL_HUFFMAN_ONLY = 0, + TDEFL_DEFAULT_MAX_PROBES = 128, + TDEFL_MAX_PROBES_MASK = 0xFFF +}; + +/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. */ +/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */ +/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */ +/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). */ +/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */ +/* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */ +/* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */ +/* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */ +/* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). */ +enum +{ + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 +}; + +/* High level compression functions: */ +/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */ +/* On entry: */ +/* pSrc_buf, src_buf_len: Pointer and size of source block to compress. */ +/* flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. */ +/* On return: */ +/* Function returns a pointer to the compressed data, or NULL on failure. */ +/* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */ +/* The caller must free() the returned block when it's no longer needed. */ +// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ +/* Returns 0 on failure. */ +// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +/* Compresses an image to a compressed PNG file in memory. */ +/* On entry: */ +/* pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */ +/* The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. */ +/* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */ +/* If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */ +/* On return: */ +/* Function returns a pointer to the compressed data, or NULL on failure. */ +/* *pLen_out will be set to the size of the PNG image file. */ +/* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */ +// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); +// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); + +/* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); + +/* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */ +// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +enum +{ + TDEFL_MAX_HUFF_TABLES = 3, + TDEFL_MAX_HUFF_SYMBOLS_0 = 288, + TDEFL_MAX_HUFF_SYMBOLS_1 = 32, + TDEFL_MAX_HUFF_SYMBOLS_2 = 19, + TDEFL_LZ_DICT_SIZE = 32768, + TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, + TDEFL_MIN_MATCH_LEN = 3, + TDEFL_MAX_MATCH_LEN = 258 +}; + +/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). */ +#if TDEFL_LESS_MEMORY +enum +{ + TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 12, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#else +enum +{ + TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 15, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#endif + +/* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. */ +typedef enum { + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1 +} tdefl_status; + +/* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */ +typedef enum { + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 +} tdefl_flush; + +/* tdefl's compression state structure. */ +typedef struct +{ + tdefl_put_buf_func_ptr m_pPut_buf_func; + void *m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; + tdefl_status m_prev_return_status; + const void *m_pIn_buf; + void *m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8 *m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; +} tdefl_compressor; + +/* Initializes the compressor. */ +/* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */ +/* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. */ +/* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */ +/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */ +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +/* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. */ +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); + +/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ +/* tdefl_compress_buffer() always consumes the entire input buffer. */ +// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); + +// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); +mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + +/* Create tdefl_compress() flags given zlib-style compression parameters. */ +/* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */ +/* window_bits may be -15 (raw deflate) or 15 (zlib) */ +/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */ +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); + +/* Allocate the tdefl_compressor structure in C so that */ +/* non-C language bindings to tdefl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ +// tdefl_compressor *tdefl_compressor_alloc(); +// void tdefl_compressor_free(tdefl_compressor *pComp); + +#ifdef __cplusplus +} +#endif +#pragma once + +/* ------------------- Low-level Decompression API Definitions */ + +#ifdef __cplusplus +extern "C" { +#endif +/* Decompression flags used by tinfl_decompress(). */ +/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. */ +/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. */ +/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */ +/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */ +enum +{ + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +/* High level decompression functions: */ +/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */ +/* On entry: */ +/* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */ +/* On return: */ +/* Function returns a pointer to the decompressed data, or NULL on failure. */ +/* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */ +/* The caller must call mz_free() on the returned block when it's no longer needed. */ +// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ +/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */ +/* Returns 1 on success or 0 on failure. */ +typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); +// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +struct tinfl_decompressor_tag; +typedef struct tinfl_decompressor_tag tinfl_decompressor; + +/* Allocate the tinfl_decompressor structure in C so that */ +/* non-C language bindings to tinfl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ + +// tinfl_decompressor *tinfl_decompressor_alloc(); +// void tinfl_decompressor_free(tinfl_decompressor *pDecomp); + +/* Max size of LZ dictionary. */ +#define TINFL_LZ_DICT_SIZE 32768 + +/* Return status. */ +typedef enum { + /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is indicating that no more are available. The compressed data */ + /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input but this is a BAD sign (either the data is corrupted or you called it incorrectly). */ + /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */ + TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4, + + /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, but if you get this error the calling code is wrong.) */ + TINFL_STATUS_BAD_PARAM = -3, + + /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you call it again it'll return TINFL_STATUS_DONE. */ + TINFL_STATUS_ADLER32_MISMATCH = -2, + + /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */ + TINFL_STATUS_FAILED = -1, + + /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */ + + /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte that it needed, has successfully reached the end of the deflate stream, and */ + /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If you call it again you'll just get TINFL_STATUS_DONE over and over again. */ + TINFL_STATUS_DONE = 0, + + /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */ + /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also possible (but unlikely) for the inflator to keep on demanding input to */ + /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */ + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + + /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write this data into the output buffer. */ + /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed data to the caller. I've been assuming you know how much uncompressed data to expect */ + /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure streaming scenarios where you have no idea how many bytes to expect this may not be possible */ + /* so I may need to add some code to address this. */ + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +/* Initializes the decompressor to its initial state. */ +#define tinfl_init(r) \ + do \ + { \ + (r)->m_state = 0; \ + } \ + MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */ +/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */ +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); + +/* Internal/private bits follow. */ +enum +{ + TINFL_MAX_HUFF_TABLES = 3, + TINFL_MAX_HUFF_SYMBOLS_0 = 288, + TINFL_MAX_HUFF_SYMBOLS_1 = 32, + TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, + TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +typedef struct +{ + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS +#define TINFL_USE_64BIT_BITBUF 1 +#else +#define TINFL_USE_64BIT_BITBUF 0 +#endif + +#if TINFL_USE_64BIT_BITBUF +typedef mz_uint64 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (64) +#else +typedef mz_uint32 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag +{ + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +#ifdef __cplusplus +} +#endif + +#pragma once + + +/* ------------------- ZIP archive reading/writing */ + +// #ifndef MINIZ_NO_ARCHIVE_APIS + +// #ifdef __cplusplus +// extern "C" { +// #endif + +// enum +// { + /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ +// MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, +// MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, +// MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 +// }; + +// typedef struct +// { +// /* Central directory file index. */ +// mz_uint32 m_file_index; + +// /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ +// mz_uint64 m_central_dir_ofs; + +// /* These fields are copied directly from the zip's central dir. */ +// mz_uint16 m_version_made_by; +// mz_uint16 m_version_needed; +// mz_uint16 m_bit_flag; +// mz_uint16 m_method; + +// #ifndef MINIZ_NO_TIME +// MZ_TIME_T m_time; +// #endif + +// /* CRC-32 of uncompressed data. */ +// mz_uint32 m_crc32; + +// /* File's compressed size. */ +// mz_uint64 m_comp_size; + +// /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ +// mz_uint64 m_uncomp_size; + +// /* Zip internal and external file attributes. */ +// mz_uint16 m_internal_attr; +// mz_uint32 m_external_attr; + +// /* Entry's local header file offset in bytes. */ +// mz_uint64 m_local_header_ofs; + +// /* Size of comment in bytes. */ +// mz_uint32 m_comment_size; + +// /* MZ_TRUE if the entry appears to be a directory. */ +// mz_bool m_is_directory; + +// /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ +// mz_bool m_is_encrypted; + +// /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ +// mz_bool m_is_supported; + +// /* Filename. If string ends in '/' it's a subdirectory entry. */ +// /* Guaranteed to be zero terminated, may be truncated to fit. */ +// char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + +// /* Comment field. */ +// /* Guaranteed to be zero terminated, may be truncated to fit. */ +// char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; + +// } mz_zip_archive_file_stat; + +// typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); +// typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); +// typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); + +// struct mz_zip_internal_state_tag; +// typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + +// typedef enum { +// MZ_ZIP_MODE_INVALID = 0, +// MZ_ZIP_MODE_READING = 1, +// MZ_ZIP_MODE_WRITING = 2, +// MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 +// } mz_zip_mode; + +// typedef enum { +// MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, +// MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, +// MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, +// MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, + // MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ + // MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ + // MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ +// MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, +// MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 +// } mz_zip_flags; + +// typedef enum { +// MZ_ZIP_TYPE_INVALID = 0, +// MZ_ZIP_TYPE_USER, +// MZ_ZIP_TYPE_MEMORY, +// MZ_ZIP_TYPE_HEAP, +// MZ_ZIP_TYPE_FILE, +// MZ_ZIP_TYPE_CFILE, +// MZ_ZIP_TOTAL_TYPES +// } mz_zip_type; + +/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ +// typedef enum { +// MZ_ZIP_NO_ERROR = 0, +// MZ_ZIP_UNDEFINED_ERROR, +// MZ_ZIP_TOO_MANY_FILES, +// MZ_ZIP_FILE_TOO_LARGE, +// MZ_ZIP_UNSUPPORTED_METHOD, +// MZ_ZIP_UNSUPPORTED_ENCRYPTION, +// MZ_ZIP_UNSUPPORTED_FEATURE, +// MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, +// MZ_ZIP_NOT_AN_ARCHIVE, +// MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, +// MZ_ZIP_UNSUPPORTED_MULTIDISK, +// MZ_ZIP_DECOMPRESSION_FAILED, +// MZ_ZIP_COMPRESSION_FAILED, +// MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, +// MZ_ZIP_CRC_CHECK_FAILED, +// MZ_ZIP_UNSUPPORTED_CDIR_SIZE, +// MZ_ZIP_ALLOC_FAILED, +// MZ_ZIP_FILE_OPEN_FAILED, +// MZ_ZIP_FILE_CREATE_FAILED, +// MZ_ZIP_FILE_WRITE_FAILED, +// MZ_ZIP_FILE_READ_FAILED, +// MZ_ZIP_FILE_CLOSE_FAILED, +// MZ_ZIP_FILE_SEEK_FAILED, +// MZ_ZIP_FILE_STAT_FAILED, +// MZ_ZIP_INVALID_PARAMETER, +// MZ_ZIP_INVALID_FILENAME, +// MZ_ZIP_BUF_TOO_SMALL, +// MZ_ZIP_INTERNAL_ERROR, +// MZ_ZIP_FILE_NOT_FOUND, +// MZ_ZIP_ARCHIVE_TOO_LARGE, +// MZ_ZIP_VALIDATION_FAILED, +// MZ_ZIP_WRITE_CALLBACK_FAILED, +// MZ_ZIP_TOTAL_ERRORS +// } mz_zip_error; + +// typedef struct +// { +// mz_uint64 m_archive_size; +// mz_uint64 m_central_directory_file_ofs; + +// /* We only support up to UINT32_MAX files in zip64 mode. */ +// mz_uint32 m_total_files; +// mz_zip_mode m_zip_mode; +// mz_zip_type m_zip_type; +// mz_zip_error m_last_error; + +// mz_uint64 m_file_offset_alignment; + +// mz_alloc_func m_pAlloc; +// mz_free_func m_pFree; +// mz_realloc_func m_pRealloc; +// void *m_pAlloc_opaque; + +// mz_file_read_func m_pRead; +// mz_file_write_func m_pWrite; +// mz_file_needs_keepalive m_pNeeds_keepalive; +// void *m_pIO_opaque; + +// mz_zip_internal_state *m_pState; + +// } mz_zip_archive; + +// typedef struct +// { +// mz_zip_archive *pZip; +// mz_uint flags; + +// int status; +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// mz_uint file_crc32; +// #endif +// mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; +// mz_zip_archive_file_stat file_stat; +// void *pRead_buf; +// void *pWrite_buf; + +// size_t out_blk_remain; + +// tinfl_decompressor inflator; + +// } mz_zip_reader_extract_iter_state; + +/* -------- ZIP reading */ + +/* Inits a ZIP archive reader. */ +/* These functions read and validate the archive's central directory. */ +// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); + +// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); + +// #ifndef MINIZ_NO_STDIO +/* Read a archive from a disk file. */ +/* file_start_ofs is the file offset where the archive actually begins, or 0. */ +/* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */ +// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); +// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); + +/* Read an archive from an already opened FILE, beginning at the current file position. */ +/* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */ +/* The FILE will NOT be closed when mz_zip_reader_end() is called. */ +// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); +// #endif + +/* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */ +// mz_bool mz_zip_reader_end(mz_zip_archive *pZip); + +/* -------- ZIP reading or writing */ + +/* Clears a mz_zip_archive struct to all zeros. */ +/* Important: This must be done before passing the struct to any mz_zip functions. */ +// void mz_zip_zero_struct(mz_zip_archive *pZip); + +// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); +// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); + +/* Returns the total number of files in the archive. */ +// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); + +// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); +// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); +// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); + +/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ +// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); + +/* Attempts to locates a file in the archive's central directory. */ +/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ +/* Returns -1 if the file cannot be found. */ +// int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); +/* Returns MZ_FALSE if the file cannot be found. */ +// mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex); + +/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */ +/* Note that the m_last_error functionality is not thread safe. */ +// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); +// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); +// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); +// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); +// const char *mz_zip_get_error_string(mz_zip_error mz_err); + +/* MZ_TRUE if the archive file entry is a directory entry. */ +// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); + +/* MZ_TRUE if the file is encrypted/strong encrypted. */ +// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); + +/* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */ +// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); + +/* Retrieves the filename of an archive file entry. */ +/* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */ +// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); + +/* Attempts to locates a file in the archive's central directory. */ +/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ +/* Returns -1 if the file cannot be found. */ +// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); +// int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); + +/* Returns detailed information about an archive file entry. */ +// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); + +/* MZ_TRUE if the file is in zip64 format. */ +/* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */ +// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); + +/* Returns the total central directory size in bytes. */ +/* The current max supported size is <= MZ_UINT32_MAX. */ +// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); + +/* Extracts a archive file to a memory buffer using no memory allocation. */ +/* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ +// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); +// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + +/* Extracts a archive file to a memory buffer. */ +// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); +// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); + +/* Extracts a archive file to a dynamically allocated heap buffer. */ +/* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ +/* Returns NULL and sets the last error on failure. */ +// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); +// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); + +/* Extracts a archive file using a callback function to output the file's data. */ +// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); +// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); + +/* Extract a file iteratively */ +// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); +// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); +// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); +// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); + +// #ifndef MINIZ_NO_STDIO +/* Extracts a archive file to a disk file and sets its last accessed and modified times. */ +/* This function only extracts files, not archive directory records. */ +// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); +// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); + +/* Extracts a archive file starting at the current position in the destination FILE stream. */ +// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); +// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); +// #endif + +#if 0 +/* TODO */ + typedef void *mz_zip_streaming_extract_state_ptr; + mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); + uint64_t mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); + uint64_t mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); + mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, uint64_t new_ofs); + size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size); + mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); +#endif + +/* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */ +/* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */ +// mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); + +/* Validates an entire archive by calling mz_zip_validate_file() on each file. */ +// mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags); + +/* Misc utils/helpers, valid for ZIP reading or writing */ +// mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr); +// mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); + +/* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ +// mz_bool mz_zip_end(mz_zip_archive *pZip); + +/* -------- ZIP writing */ + +// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +/* Inits a ZIP archive writer. */ +/*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ +/*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ +// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); +// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); + +// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); +// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); + +// #ifndef MINIZ_NO_STDIO +// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); +// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); +// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); +// #endif + +/* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */ +/* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ +/* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). */ +/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */ +/* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */ +/* the archive is finalized the file's central directory will be hosed. */ +// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); +// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); + +/* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */ +/* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); + +/* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */ +/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ +// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); + +// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, +// const char *user_extra_data_central, mz_uint user_extra_data_central_len); + +// #ifndef MINIZ_NO_STDIO +/* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + +/* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ +// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, +// const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, +// const char *user_extra_data_central, mz_uint user_extra_data_central_len); +// #endif + +/* Adds a file to an archive by fully cloning the data from another archive. */ +/* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */ +// mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index); + +/* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ +/* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ +/* An archive must be manually finalized by calling this function for it to be valid. */ +// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); + +/* Finalizes a heap archive, returning a poiner to the heap block and its size. */ +/* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ +// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); + +/* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ +/* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */ +// mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + +/* -------- Misc. high-level helper functions: */ + +/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */ +/* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +/* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */ +// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); + +/* Reads a single file from an archive into a heap block. */ +/* If pComment is not NULL, only the file with the specified comment will be extracted. */ +/* Returns NULL on failure. */ +// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); +// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); + +// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + +// #ifdef __cplusplus +// } +// #endif + +// #endif /* MINIZ_NO_ARCHIVE_APIS */ diff --git a/gomspace/libutil/src/zip/zip.c b/gomspace/libutil/src/zip/zip.c new file mode 100644 index 00000000..b7fd00fc --- /dev/null +++ b/gomspace/libutil/src/zip/zip.c @@ -0,0 +1,357 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include "gs/util/zip/zip.h" +#include "miniz/miniz.h" + +#include +#include +#include + +#include + +static void cleanup(FILE *pInfile, FILE *pOutfile, uint8_t *stream_inbuf, uint8_t *stream_outbuf) +{ + if(pInfile) + fclose(pInfile); + + if(pOutfile) + fclose(pOutfile); + + if(stream_inbuf) + free(stream_inbuf); + + if(stream_outbuf) + free(stream_outbuf); +} + +int gs_zip_compress_file(const char *src, const char *dest) +{ + FILE *pInfile, *pOutfile; + uint32_t infile_size; + long file_loc; + + // Open input file. + pInfile = fopen(src, "rb"); + if (!pInfile) + { + log_error("Zip compress: Failed opening input file!"); + return GS_ERROR_IO; + } + + // Determine input file's size. + fseek(pInfile, 0, SEEK_END); + file_loc = ftell(pInfile); + fseek(pInfile, 0, SEEK_SET); + + if((file_loc < 0) || ((unsigned long)file_loc > UINT_MAX)) + { + log_error("Zip compress: File is too large to be processed."); + fclose(pInfile); + + return GS_ERROR_IO; + } + + infile_size = (uint32_t)file_loc; + uint32_t buffer_size = infile_size; + + // Allocate input buffer memory + uint8_t *stream_inbuf = malloc(buffer_size); + if (stream_inbuf == NULL) + { + log_error("Zip compress: Failed to allocate input buffer memory"); + fclose(pInfile); + + return GS_ERROR_IO; + } + + // Allocate output buffer memory + uint8_t *stream_outbuf = malloc(buffer_size); + if (stream_outbuf == NULL) + { + log_error("Zip compress: Failed to allocate output buffer memory"); + cleanup(pInfile, NULL, stream_inbuf, NULL); + + return GS_ERROR_IO; + } + + // Open output file. + pOutfile = fopen(dest, "wb"); + if (!pOutfile) + { + log_error("Zip compress: Failed opening output file!"); + cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); + + return GS_ERROR_IO; + } + + // Init the z_stream + z_stream stream; + memset(&stream, 0, sizeof(stream)); + stream.next_in = stream_inbuf; + stream.avail_in = 0; + stream.next_out = stream_outbuf; + stream.avail_out = buffer_size; + + // Compression. + uint32_t infile_remaining = infile_size; + + if(deflateInit(&stream, Z_BEST_COMPRESSION) != Z_OK) + { + log_error("Zip compress: deflateInit() failed!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_DATA; + } + + for( ; ; ) + { + int status; + if(!stream.avail_in) + { + // Input buffer is empty, so read more bytes from input file. + uint32_t n = gs_min((uint32_t)buffer_size, infile_remaining); + + if (fread(stream_inbuf, 1, n, pInfile) != n) + { + log_error("Zip compress: Failed reading from input file!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_IO; + } + + stream.next_in = stream_inbuf; + stream.avail_in = n; + + infile_remaining -= n; + } + + status = deflate(&stream, infile_remaining ? Z_NO_FLUSH : Z_FINISH); + + if((status == Z_STREAM_END) || (!stream.avail_out)) + { + // Output buffer is full, or compression is done, so write buffer to output file. + uint32_t n = buffer_size - stream.avail_out; + if (fwrite(stream_outbuf, 1, n, pOutfile) != n) + { + log_error("Zip compress: Failed writing to output file!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_IO; + } + + stream.next_out = stream_outbuf; + stream.avail_out = buffer_size; + } + + if(status == Z_STREAM_END) + { + break; + } + else if(status != Z_OK) + { + log_error("Zip compress: deflate() failed with status %i!", status); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_DATA; + } + } + + if(deflateEnd(&stream) != Z_OK) + { + log_error("Zip compress: deflateEnd() failed!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_DATA; + } + + + cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); + if(EOF == fclose(pOutfile)) + { + log_error("Zip compress: Failed writing to output file!"); + return GS_ERROR_IO; + } + + log_debug("Total input bytes: %u\n", (mz_uint32)stream.total_in); + log_debug("Total output bytes: %u\n", (mz_uint32)stream.total_out); + log_debug("Success.\n"); + + return GS_OK; +} + +int gs_zip_decompress_file(const char *src, const char *dest) +{ + FILE *pInfile, *pOutfile; + uint32_t infile_size; + long file_loc; + + // Open input file. + pInfile = fopen(src, "rb"); + if (!pInfile) + { + log_error("Zip decompress: Failed opening input file!"); + return GS_ERROR_IO; + } + + // Determine input file's size. + fseek(pInfile, 0, SEEK_END); + file_loc = ftell(pInfile); + fseek(pInfile, 0, SEEK_SET); + + if((file_loc < 0) || ((unsigned long)file_loc > UINT_MAX)) + { + log_error("Zip decompress: File is too large to be processed."); + fclose(pInfile); + + return GS_ERROR_IO; + } + + infile_size = (uint32_t)file_loc; + uint32_t buffer_size = infile_size; + + // Allocate input buffer memory + uint8_t *stream_inbuf = malloc(buffer_size); + if (stream_inbuf == NULL) + { + log_error("Zip decompress: Failed to allocate input buffer memory"); + fclose(pInfile); + + return GS_ERROR_IO; + } + + // Allocate output buffer memory + uint8_t *stream_outbuf = malloc(buffer_size); + if (stream_outbuf == NULL) + { + log_error("Zip decompress: Failed to allocate output buffer memory"); + cleanup(pInfile, NULL, stream_inbuf, NULL); + + return GS_ERROR_IO; + } + + // Open output file. + pOutfile = fopen(dest, "wb"); + if (!pOutfile) + { + log_error("Zip decompress: Failed opening output file!"); + cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); + + return GS_ERROR_IO; + } + + // Init the z_stream + z_stream stream; + memset(&stream, 0, sizeof(stream)); + stream.next_in = stream_inbuf; + stream.avail_in = 0; + stream.next_out = stream_outbuf; + stream.avail_out = buffer_size; + + // Decompression. + uint32_t infile_remaining = infile_size; + + if(inflateInit(&stream)) + { + log_error("Zip decompress: inflateInit() failed!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_DATA; + } + + for( ; ; ) + { + int status; + if(!stream.avail_in) + { + // Input buffer is empty, so read more bytes from input file. + uint32_t n = gs_min((uint32_t)buffer_size, infile_remaining); + + if(fread(stream_inbuf, 1, n, pInfile) != n) + { + log_error("Zip decompress: Failed reading from input file!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_IO; + } + + stream.next_in = stream_inbuf; + stream.avail_in = n; + + infile_remaining -= n; + } + + status = inflate(&stream, Z_SYNC_FLUSH); + + if((status == Z_STREAM_END) || (!stream.avail_out)) + { + // Output buffer is full, or decompression is done, so write buffer to output file. + uint32_t n = buffer_size - stream.avail_out; + if(fwrite(stream_outbuf, 1, n, pOutfile) != n) + { + log_error("Zip decompress: Failed writing to output file!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_IO; + } + stream.next_out = stream_outbuf; + stream.avail_out = buffer_size; + } + + if(status == Z_STREAM_END) + { + break; + } + else if(status != Z_OK) + { + log_error("Zip decompress: inflate() failed with status %i!", status); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_DATA; + } + } + + if(inflateEnd(&stream) != Z_OK) + { + log_error("Zip decompress: inflateEnd() failed!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_DATA; + } + + cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); + if(EOF == fclose(pOutfile)) + { + log_error("Zip decompress: Failed writing to output file!"); + return GS_ERROR_IO; + } + + log_debug("Total input bytes: %u", (mz_uint32)stream.total_in); + log_debug("Total output bytes: %u", (mz_uint32)stream.total_out); + log_debug("Success.\n"); + + return GS_OK; +} + +int gs_zip_compress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t *dest_len) +{ + mz_ulong cmp_len = src_len; + if(compress(dest, &cmp_len, src, (mz_ulong)src_len) != MZ_OK) + { + return GS_ERROR_DATA; + } + + *dest_len = cmp_len; + + return GS_OK; +} + +int gs_zip_decompress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t dest_len, uint32_t *decomp_len) +{ + mz_ulong tmp = dest_len; + if(uncompress(dest, &tmp, src, (mz_ulong)src_len) != MZ_OK) + return GS_ERROR_DATA; + + *decomp_len = tmp; + + return GS_OK; +} diff --git a/gomspace/libutil/wscript b/gomspace/libutil/wscript new file mode 100644 index 00000000..48421e39 --- /dev/null +++ b/gomspace/libutil/wscript @@ -0,0 +1,109 @@ +#!/usr/bin/env python +# encoding: utf-8 +# Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. + +import gs_gcc +import gs_doc +import gs_dist +from waflib.Build import BuildContext + +APPNAME = 'util' + + +def options(ctx): + ctx.load('gs_gcc gs_doc') + gs_gcc.gs_recurse(ctx) + + gr = ctx.add_option_group('libutil options') + gr.add_option('--console-history-len', metavar='LEN', default=10, type=int, help='Command history length, 0=none') + gr.add_option('--console-input-len', metavar='LEN', default=100, type=int, help='Command input length') + gr.add_option('--util-enable-isr-logs', action='store_true', help='Enable ISR logs') + + +def configure(ctx): + ctx.load('gs_gcc gs_doc') + + ctx.env.append_unique('FILES_LIBUTIL', ['src/*.c', + 'src/gosh/**/*.c', + 'src/log/**/*.c', + 'src/vmem/**/*.c', + 'src/watchdog/**/*.c', + 'src/drivers/**/*.c']) + + if ctx.env.GS_ARCH not in ['avr8']: + ctx.env.append_unique('FILES_LIBUTIL', ['src/zip/**/*.c']) + + if ctx.gs_is_linux(): + ctx.env.append_unique('FILES_LIBUTIL', ['src/linux/**/*.c']) + + ctx.env.GS_UTIL_CMOCKA = ctx.check_cfg(package='cmocka', args='--cflags --libs', + atleast_version='1.0.1', mandatory=False) + + # Check compiler endianness - avr32 GCC doesn't support endian defines + endianness = ctx.check_endianness() + ctx.define_cond('UTIL_LITTLE_ENDIAN', endianness == 'little') + ctx.define_cond('UTIL_BIG_ENDIAN', endianness == 'big') + + ctx.define('GS_CONSOLE_HISTORY_LEN', ctx.options.console_history_len) + ctx.define('GS_CONSOLE_INPUT_LEN', ctx.options.console_input_len) + ctx.define_cond('GS_LOG_ENABLE_ISR_LOGS', ctx.options.util_enable_isr_logs) + + ctx.gs_write_config_header('include/conf_util.h', remove=True) + + ctx.gs_add_doxygen(example=['tst'], exclude=['*/include/gs/uthash/*', + '*/include/gs/util/zip/*', + '*/include/deprecated/util/*', + '*/include/deprecated/gs/gosh/*']) + + ctx.gs_register_handler(function='command_gen_4_0', filepath='./tools/waf_command.py') + + gs_gcc.gs_recurse(ctx) + + +def build(ctx): + gs_gcc.gs_recurse(ctx) + + public_include = ctx.gs_include(name=APPNAME, + includes=['include', 'include/gs', + 'include/deprecated', 'include/deprecated/gs/gosh/'], + config_header=['include/conf_util.h']) + + ctx.gs_objects(source=ctx.path.ant_glob(ctx.env.FILES_LIBUTIL), + target=APPNAME, + includes=['src'], + use=ctx.env.USE_LIBUTIL + [public_include]) + + ctx.gs_shlib(source=ctx.path.ant_glob(ctx.env.FILES_LIBUTIL), + target=APPNAME, + includes=['src'], + gs_use_shlib=ctx.env.USE_LIBUTIL, + use=[public_include], + lib=['pthread']) + + ctx.gs_python_bindings(source=ctx.path.ant_glob('src/bindings/python/*.c'), + target=APPNAME, + gs_use_shlib=ctx.env.USE_LIBUTIL + [APPNAME], + use=[public_include], + package='libutil') + + if ctx.env.GS_UTIL_CMOCKA: + ctx.gs_stlib(source=ctx.path.ant_glob('src/test/*.c'), + name=APPNAME + '_cmocka', # overwrite default naming + target=APPNAME + '_cmocka', + includes=['include']) + + +def doc(ctx): + gs_doc.gs_library_doc(ctx, keyvalues={ + 'gs_prod_name': 'lib'+APPNAME, + 'gs_prod_desc': 'Low level APIs and utilities', + 'gs_sphinx_exclude': ['CHANGELOG.rst'], + }) + + +class Doc(BuildContext): + cmd = fun = 'doc' + + +def gs_dist(ctx): + ctx.add_default_files(source_module=True) diff --git a/mission/core/InitMission.cpp b/mission/core/InitMission.cpp index be16750d..62b50418 100644 --- a/mission/core/InitMission.cpp +++ b/mission/core/InitMission.cpp @@ -132,13 +132,21 @@ void InitMission::initTasks(){ #if ADD_TEST_CODE == 1 - FixedTimeslotTaskIF* TestTimeslotTask = TaskFactory::instance()-> - createFixedTimeslotTask("PST_TEST_TASK", 10, - PeriodicTaskIF::MINIMUM_STACK_SIZE, 1.0, nullptr); - result = pst::pollingSequenceTestFunction(TestTimeslotTask); - if(result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "InitMission::createTasks: Test PST initialization " - << "failed!" << std::endl; +// FixedTimeslotTaskIF* TestTimeslotTask = TaskFactory::instance()-> +// createFixedTimeslotTask("PST_TEST_TASK", 10, +// PeriodicTaskIF::MINIMUM_STACK_SIZE, 1.0, nullptr); +// result = pst::pollingSequenceTestFunction(TestTimeslotTask); +// if(result != HasReturnvaluesIF::RETURN_OK) { +// sif::error << "InitMission::createTasks: Test PST initialization " +// << "failed!" << std::endl; +// } + + PeriodicTaskIF* P60DockTestTask = TaskFactory::instance()-> + createPeriodicTask("P60 Dock", 50 , 4096, + 1, nullptr); + result = PusLowPrio->addComponent(objects::P60_DOCK_TEST_TASK); + if(result!=HasReturnvaluesIF::RETURN_OK){ + sif::error << "Object add component failed" << std::endl; } #endif @@ -154,7 +162,9 @@ void InitMission::initTasks(){ PusMedPrio->startTask(); PusLowPrio->startTask(); #if ADD_TEST_CODE == 1 - TestTimeslotTask->startTask(); +// TestTimeslotTask->startTask(); + P60DockTestTask->startTask(); + #endif sif::info << "Tasks started.." << std::endl; } diff --git a/mission/core/ObjectFactory.cpp b/mission/core/ObjectFactory.cpp index 898a2b51..d6bc80c4 100644 --- a/mission/core/ObjectFactory.cpp +++ b/mission/core/ObjectFactory.cpp @@ -37,8 +37,9 @@ #if ADD_TEST_CODE == 1 //#include //#include -#include +//#include //#include +#include #endif void Factory::setStaticFrameworkObjectIds(){ @@ -130,5 +131,6 @@ void ObjectFactory::produce(){ // new TestDevice(objects::TEST_DEVICE_HANDLER, objects::TEST_ECHO_COM_IF, // testCookie, true); new ArduinoComIF(objects::ARDUINO_COM_IF, true, nullptr); + new P60DockTestTask(objects::P60DOCK_TEST_TASK); #endif } diff --git a/mission/devices/P60DockHandler.cpp b/mission/devices/P60DockHandler.cpp new file mode 100644 index 00000000..500355d7 --- /dev/null +++ b/mission/devices/P60DockHandler.cpp @@ -0,0 +1,23 @@ +/* + * P60DockHandler.cpp + * + * Created on: 18.11.2020 + * Author: jakob + */ + +#include +#include +#include "P60DockHandler.h" + +P60DockHandler::P60DockHandler() { + +} + + +P60DockHandler::~P60DockHandler() { +} + + +P60DockHandler::performOperation(uint8_t operationCode) { + +} diff --git a/mission/devices/P60DockHandler.h b/mission/devices/P60DockHandler.h new file mode 100644 index 00000000..cecd5e75 --- /dev/null +++ b/mission/devices/P60DockHandler.h @@ -0,0 +1,18 @@ +/* + * P60DockHandler.h + * + * Created on: 18.11.2020 + * Author: jakob + */ + +#ifndef MISSION_DEVICES_P60DOCKHANDLER_H_ +#define MISSION_DEVICES_P60DOCKHANDLER_H_ + +class P60DockHandler: public DeviceHandlerBase { +public: + P60DockHandler(); + virtual ~P60DockHandler(); + virtual ReturnValue_t performOperation(uint8_t operationCode = 0); +}; + +#endif /* MISSION_DEVICES_P60DOCKHANDLER_H_ */ diff --git a/test/testtasks/P60DockTestTask.cpp b/test/testtasks/P60DockTestTask.cpp new file mode 100644 index 00000000..962521cb --- /dev/null +++ b/test/testtasks/P60DockTestTask.cpp @@ -0,0 +1,88 @@ +/* + * P60DockTestTask.cpp + * + * Created on: 18.11.2020 + * Author: jakob + */ + +#include +#include "P60DockTestTask.h" + +P60DockTestTask::P60DockTestTask(object_id_t objectId_): +SystemObject(objectId_){ + /* Init buffer system with 10 packets of maximum 320 bytes each */ +// csp_buffer_init(10, 320); + + uint8_t device = 0; + uint8_t csp_addr = 4; /* Current address of p60 dock */ + uint8_t mtu = 320; /* Packets larger than the set mtu will be discarded */ + char name[5] = "can0"; + + /* Init the CAN interface */ + gs_error_t result = gs_csp_can_init(device, csp_addr, mtu, name, csp_if); + if(result != GS_OK){ + sif::error << "gs_csp_can_init failed with error code: " << result + << std::endl; + } +} + + +ReturnValue_t P60DockTestTask::performOperation(uint8_t operationCode) { + + char data[5] = "test"; + int timeout_ms = 1000; + /* Send a csp packet to the can interface */ + g_error_t result = csp_can_tx_frame(csp_if, canExtMsgId, (uint8*) data, sizeof(data), + timeout_ms); + if(result != GS_OK){ + sif::error << "csp_can_tx_frame failed with error code " << result + << std::endl; + } +} + + +ReturnValue_t P60DockTestTask::sendPacket(void){ + + /* Get packet buffer for data */ + csp_packet_t *packet = csp_buffer_get(data_size); + if (packet == NULL) { + /* Could not get buffer element */ + sif::error("Failed to get buffer element\\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + + /* Connect to host HOST, port PORT with regular UDP-like protocol and + * 1000 ms timeout */ + csp_conn_t *conn = csp_connect(CSP_PRIO_NORM, HOST, PORT, 1000, CSP_O_NONE); + + if (conn == NULL) { + /* Connect failed */ + sif::error("Connection failed\\n"); + /* Remember to free packet buffer */ + csp_buffer_free(packet); + return HasReturnvaluesIF::RETURN_FAILED; + } + + /* Copy message to packet */ + char *msg = "HELLO"; + strcpy(packet->data, msg); + /* Set packet length */ + packet->length = strlen(msg); + + /* Send packet */ + if (!csp_send(conn, packet, 1000)) { + /* Send failed */ + sif::error("Send failed\\n"); + csp_buffer_free(packet); + } + /* Close connection */ + csp_close(conn); + + return HasReturnvaluesIF::RETURN_OK; +} + + +P60DockTestTask::~P60DockTestTask() { + // TODO Auto-generated destructor stub +} + diff --git a/test/testtasks/P60DockTestTask.h b/test/testtasks/P60DockTestTask.h new file mode 100644 index 00000000..860a3937 --- /dev/null +++ b/test/testtasks/P60DockTestTask.h @@ -0,0 +1,35 @@ +/* + * P60DockTestTask.h + * + * Created on: 18.11.2020 + * Author: jakob + */ + +#ifndef TEST_TESTTASKS_P60DOCKTESTTASK_H_ +#define TEST_TESTTASKS_P60DOCKTESTTASK_H_ + +extern "C" { +#include +#include +} + + +class P60DockTestTask: public ExecutableObjectIF { +public: + P60DockTestTask(); + virtual ~P60DockTestTask(); + + virtual ReturnValue_t performOperation(uint8_t operationCode = 0); + +private: + /* Interface struct for csp protocol stack */ + csp_iface_t csp_if; + uint32_t canExtMsgId = 4; + /* CAN configuration struct for SocketCAN interface "can0" */ + struct csp_can_config can_conf = {.ifc = "can0"}; + + ReturnValue_t sendPacket(void); + +}; + +#endif /* TEST_TESTTASKS_P60DOCKTESTTASK_H_ */ From fcb328393b76c7734f41cd988fcc9b07851fe088 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Mon, 23 Nov 2020 11:42:22 +0100 Subject: [PATCH 002/360] pdock 60 test task --- config/OBSWConfig.h | 2 +- gomspace/gomspace.mk | 19 +- gomspace/{libgscsp/lib => }/libcsp/CHANGELOG | 0 .../{libgscsp/lib => }/libcsp/CONTRIBUTORS | 0 gomspace/{libgscsp/lib => }/libcsp/COPYING | 0 .../{libgscsp/lib => }/libcsp/INSTALL.rst | 0 gomspace/{libgscsp/lib => }/libcsp/README.rst | 0 .../libcsp/bindings/python/libcsp/__init__.py | 0 .../{libgscsp/lib => }/libcsp/doc/example.rst | 0 .../{libgscsp/lib => }/libcsp/doc/history.rst | 0 .../lib => }/libcsp/doc/interfaces.rst | 0 .../{libgscsp/lib => }/libcsp/doc/libcsp.rst | 0 .../{libgscsp/lib => }/libcsp/doc/memory.rst | 0 .../{libgscsp/lib => }/libcsp/doc/mtu.rst | 0 .../lib => }/libcsp/doc/protocolstack.rst | 0 .../lib => }/libcsp/doc/structure.rst | 0 .../lib => }/libcsp/doc/topology.rst | 0 .../lib => }/libcsp/examples/csp_if_fifo.c | 0 .../libcsp/examples/csp_if_fifo_windows.c | 0 .../{libgscsp/lib => }/libcsp/examples/kiss.c | 0 .../python_bindings_example_client.py | 0 .../python_bindings_example_client_can.py | 0 .../python_bindings_example_server.py | 0 .../lib => }/libcsp/examples/simple.c | 0 .../lib => }/libcsp/examples/zmqproxy.c | 0 .../libcsp/include/csp/arch/csp_clock.h | 0 .../libcsp/include/csp/arch/csp_malloc.h | 0 .../libcsp/include/csp/arch/csp_queue.h | 0 .../libcsp/include/csp/arch/csp_semaphore.h | 0 .../libcsp/include/csp/arch/csp_system.h | 0 .../libcsp/include/csp/arch/csp_thread.h | 0 .../libcsp/include/csp/arch/csp_time.h | 0 .../include/csp/arch/posix/pthread_queue.h | 0 .../libcsp/include/csp/crypto/csp_hmac.h | 0 .../libcsp/include/csp/crypto/csp_sha1.h | 0 .../libcsp/include/csp/crypto/csp_xtea.h | 0 .../lib => }/libcsp/include/csp/csp.h | 0 .../libcsp/include/csp/csp_autoconfig.h | 21 +- .../lib => }/libcsp/include/csp/csp_buffer.h | 0 .../lib => }/libcsp/include/csp/csp_cmp.h | 0 .../lib => }/libcsp/include/csp/csp_crc32.h | 0 .../lib => }/libcsp/include/csp/csp_debug.h | 0 .../lib => }/libcsp/include/csp/csp_endian.h | 0 .../lib => }/libcsp/include/csp/csp_error.h | 0 .../lib => }/libcsp/include/csp/csp_iflist.h | 0 .../libcsp/include/csp/csp_interface.h | 0 .../libcsp/include/csp/csp_platform.h | 0 .../lib => }/libcsp/include/csp/csp_rtable.h | 0 .../lib => }/libcsp/include/csp/csp_types.h | 0 .../include/csp/drivers/can_socketcan.h | 0 .../lib => }/libcsp/include/csp/drivers/i2c.h | 0 .../libcsp/include/csp/drivers/usart.h | 0 .../include/csp/interfaces/csp_if_can.h | 0 .../include/csp/interfaces/csp_if_i2c.h | 0 .../include/csp/interfaces/csp_if_kiss.h | 0 .../libcsp/include/csp/interfaces/csp_if_lo.h | 0 .../include/csp/interfaces/csp_if_zmqhub.h | 0 .../libcsp/src/arch/freertos/csp_malloc.c | 0 .../libcsp/src/arch/freertos/csp_queue.c | 0 .../libcsp/src/arch/freertos/csp_semaphore.c | 0 .../libcsp/src/arch/freertos/csp_system.c | 0 .../libcsp/src/arch/freertos/csp_thread.c | 0 .../libcsp/src/arch/freertos/csp_time.c | 0 .../libcsp/src/arch/macosx/csp_malloc.c | 0 .../libcsp/src/arch/macosx/csp_queue.c | 0 .../libcsp/src/arch/macosx/csp_semaphore.c | 0 .../libcsp/src/arch/macosx/csp_system.c | 0 .../libcsp/src/arch/macosx/csp_thread.c | 0 .../libcsp/src/arch/macosx/csp_time.c | 0 .../libcsp/src/arch/macosx/pthread_queue.c | 0 .../libcsp/src/arch/posix/csp_malloc.c | 0 .../libcsp/src/arch/posix/csp_queue.c | 0 .../libcsp/src/arch/posix/csp_semaphore.c | 0 .../libcsp/src/arch/posix/csp_system.c | 0 .../libcsp/src/arch/posix/csp_thread.c | 0 .../lib => }/libcsp/src/arch/posix/csp_time.c | 0 .../libcsp/src/arch/posix/pthread_queue.c | 0 .../lib => }/libcsp/src/arch/windows/README | 0 .../libcsp/src/arch/windows/csp_malloc.c | 0 .../libcsp/src/arch/windows/csp_queue.c | 0 .../libcsp/src/arch/windows/csp_semaphore.c | 0 .../libcsp/src/arch/windows/csp_system.c | 0 .../libcsp/src/arch/windows/csp_thread.c | 0 .../libcsp/src/arch/windows/csp_time.c | 0 .../libcsp/src/arch/windows/windows_glue.h | 0 .../libcsp/src/arch/windows/windows_queue.c | 0 .../libcsp/src/arch/windows/windows_queue.h | 0 .../libcsp/src/bindings/python/pycsp.c | 0 .../lib => }/libcsp/src/crypto/csp_hmac.c | 0 .../lib => }/libcsp/src/crypto/csp_sha1.c | 0 .../lib => }/libcsp/src/crypto/csp_xtea.c | 0 .../lib => }/libcsp/src/csp_bridge.c | 0 .../lib => }/libcsp/src/csp_buffer.c | 0 .../{libgscsp/lib => }/libcsp/src/csp_conn.c | 0 .../{libgscsp/lib => }/libcsp/src/csp_conn.h | 0 .../{libgscsp/lib => }/libcsp/src/csp_crc32.c | 0 .../{libgscsp/lib => }/libcsp/src/csp_debug.c | 0 .../{libgscsp/lib => }/libcsp/src/csp_dedup.c | 0 .../{libgscsp/lib => }/libcsp/src/csp_dedup.h | 0 .../lib => }/libcsp/src/csp_endian.c | 0 .../lib => }/libcsp/src/csp_hex_dump.c | 0 .../lib => }/libcsp/src/csp_iflist.c | 0 .../{libgscsp/lib => }/libcsp/src/csp_io.c | 0 .../{libgscsp/lib => }/libcsp/src/csp_io.h | 0 .../{libgscsp/lib => }/libcsp/src/csp_port.c | 0 .../{libgscsp/lib => }/libcsp/src/csp_port.h | 0 .../lib => }/libcsp/src/csp_promisc.c | 0 .../lib => }/libcsp/src/csp_promisc.h | 0 .../{libgscsp/lib => }/libcsp/src/csp_qfifo.c | 0 .../{libgscsp/lib => }/libcsp/src/csp_qfifo.h | 0 .../{libgscsp/lib => }/libcsp/src/csp_route.c | 1 - .../{libgscsp/lib => }/libcsp/src/csp_route.h | 0 .../lib => }/libcsp/src/csp_service_handler.c | 0 .../lib => }/libcsp/src/csp_services.c | 0 .../{libgscsp/lib => }/libcsp/src/csp_sfp.c | 0 .../libcsp/src/drivers/can/can_socketcan.c | 0 .../libcsp/src/drivers/usart/usart_linux.c | 0 .../libcsp/src/drivers/usart/usart_windows.c | 0 .../libcsp/src/interfaces/csp_if_can.c | 0 .../libcsp/src/interfaces/csp_if_can_pbuf.c | 0 .../libcsp/src/interfaces/csp_if_can_pbuf.h | 0 .../libcsp/src/interfaces/csp_if_i2c.c | 0 .../libcsp/src/interfaces/csp_if_kiss.c | 0 .../libcsp/src/interfaces/csp_if_lo.c | 0 .../libcsp/src/rtable/csp_rtable_cidr.c | 0 .../libcsp/src/rtable/csp_rtable_static.c | 0 .../lib => }/libcsp/src/transport/csp_rdp.c | 0 .../libcsp/src/transport/csp_transport.h | 0 .../lib => }/libcsp/src/transport/csp_udp.c | 0 .../lib => }/libcsp/utils/cfpsplit.py | 0 .../lib => }/libcsp/utils/cspsplit.py | 0 gomspace/{libgscsp/lib => }/libcsp/waf | 0 gomspace/{libgscsp/lib => }/libcsp/wscript | 0 gomspace/libgscsp/include/gs/csp/address.h | 65 - gomspace/libgscsp/include/gs/csp/command.h | 25 - gomspace/libgscsp/include/gs/csp/conn.h | 26 - gomspace/libgscsp/include/gs/csp/csp.h | 202 - .../libgscsp/include/gs/csp/drivers/can/can.h | 54 - .../libgscsp/include/gs/csp/drivers/i2c/i2c.h | 29 - .../include/gs/csp/drivers/kiss/kiss.h | 30 - gomspace/libgscsp/include/gs/csp/error.h | 28 - .../include/gs/csp/linux/command_line.h | 24 - gomspace/libgscsp/include/gs/csp/log.h | 27 - gomspace/libgscsp/include/gs/csp/port.h | 111 - gomspace/libgscsp/include/gs/csp/router.h | 36 - gomspace/libgscsp/include/gs/csp/rtable.h | 31 - .../include/gs/csp/service_dispatcher.h | 124 - .../libgscsp/include/gs/csp/service_handler.h | 102 - .../lib/libcsp/src/interfaces/csp_if_zmqhub.c | 165 - .../libgscsp/src/bindings/python/pygscsp.c | 61 - gomspace/libgscsp/src/clock.c | 23 - gomspace/libgscsp/src/commands.c | 652 -- gomspace/libgscsp/src/conn.c | 22 - gomspace/libgscsp/src/csp.c | 91 - gomspace/libgscsp/src/drivers/can/can.c | 106 - gomspace/libgscsp/src/drivers/i2c/i2c.c | 77 - gomspace/libgscsp/src/drivers/kiss/kiss.c | 36 - gomspace/libgscsp/src/error.c | 54 - gomspace/libgscsp/src/freertos/cpu.c | 8 - gomspace/libgscsp/src/linux/command_line.c | 265 - gomspace/libgscsp/src/local.h | 21 - gomspace/libgscsp/src/log.c | 64 - gomspace/libgscsp/src/router.c | 84 - gomspace/libgscsp/src/rtable.c | 69 - gomspace/libgscsp/src/service_dispatcher.c | 213 - gomspace/libgscsp/src/service_handler.c | 86 - gomspace/libgscsp/src/transaction.c | 67 - gomspace/libgscsp/wscript | 104 - gomspace/libp60_client/include/p60.h | 48 - gomspace/libp60_client/include/p60_board.h | 35 - gomspace/libp60_client/include/power_if.h | 62 - gomspace/libp60_client/src/cmd/power_if_cmd.c | 147 - gomspace/libp60_client/src/p60_client.c | 33 - gomspace/libp60_client/src/power_if.c | 91 - gomspace/libp60_client/wscript | 28 - .../deprecated/gs/gosh/command/command.h | 49 - .../include/deprecated/gs/gosh/gosh/getopt.h | 22 - .../include/deprecated/gs/gosh/util/console.h | 43 - .../include/deprecated/util/color_printf.h | 26 - gomspace/libutil/include/gs/uthash/utarray.h | 231 - gomspace/libutil/include/gs/uthash/uthash.h | 960 -- gomspace/libutil/include/gs/uthash/utlist.h | 757 -- gomspace/libutil/include/gs/uthash/utstring.h | 393 - gomspace/libutil/include/gs/util/base16.h | 90 - gomspace/libutil/include/gs/util/bytebuffer.h | 173 - gomspace/libutil/include/gs/util/byteorder.h | 341 - gomspace/libutil/include/gs/util/check.h | 54 - gomspace/libutil/include/gs/util/clock.h | 88 - gomspace/libutil/include/gs/util/conf_util.h | 10 - gomspace/libutil/include/gs/util/crc32.h | 55 - gomspace/libutil/include/gs/util/crc8.h | 55 - gomspace/libutil/include/gs/util/delay.h | 42 - .../libutil/include/gs/util/drivers/can/can.h | 122 - .../include/gs/util/drivers/gpio/gpio.h | 91 - .../include/gs/util/drivers/i2c/common.h | 88 - .../include/gs/util/drivers/i2c/master.h | 32 - .../include/gs/util/drivers/i2c/slave.h | 79 - .../include/gs/util/drivers/spi/common.h | 66 - .../include/gs/util/drivers/spi/master.h | 95 - .../include/gs/util/drivers/spi/slave.h | 84 - .../include/gs/util/drivers/sys/memory.h | 92 - .../include/gs/util/drivers/watchdog/device.h | 61 - gomspace/libutil/include/gs/util/endian.h | 53 - gomspace/libutil/include/gs/util/error.h | 199 - gomspace/libutil/include/gs/util/fletcher.h | 89 - .../include/gs/util/function_scheduler.h | 79 - .../libutil/include/gs/util/gosh/command.h | 503 - .../libutil/include/gs/util/gosh/console.h | 123 - gomspace/libutil/include/gs/util/hexdump.h | 53 - gomspace/libutil/include/gs/util/linux/argp.h | 40 - .../include/gs/util/linux/command_line.h | 42 - .../include/gs/util/linux/drivers/can/can.h | 29 - .../include/gs/util/linux/drivers/gpio/gpio.h | 146 - .../gs/util/linux/drivers/gpio/gpio_sysfs.h | 91 - .../gs/util/linux/drivers/gpio/gpio_virtual.h | 125 - .../include/gs/util/linux/drivers/i2c/i2c.h | 198 - .../include/gs/util/linux/drivers/spi/spi.h | 175 - .../libutil/include/gs/util/linux/exitcode.h | 40 - .../libutil/include/gs/util/linux/function.h | 49 - gomspace/libutil/include/gs/util/linux/rtc.h | 28 - .../libutil/include/gs/util/linux/signal.h | 40 - .../include/gs/util/linux/sysfs_helper.h | 30 - gomspace/libutil/include/gs/util/log.h | 15 - .../include/gs/util/log/appender/appender.h | 189 - .../include/gs/util/log/appender/console.h | 57 - .../gs/util/log/appender/simple_file.h | 41 - gomspace/libutil/include/gs/util/log/log.h | 853 -- gomspace/libutil/include/gs/util/minmax.h | 67 - gomspace/libutil/include/gs/util/mutex.h | 63 - gomspace/libutil/include/gs/util/pgm.h | 162 - gomspace/libutil/include/gs/util/queue.h | 102 - gomspace/libutil/include/gs/util/rtc.h | 62 - gomspace/libutil/include/gs/util/sem.h | 75 - gomspace/libutil/include/gs/util/stdio.h | 117 - gomspace/libutil/include/gs/util/string.h | 391 - .../libutil/include/gs/util/test/cmocka.h | 136 - .../libutil/include/gs/util/test/command.h | 80 - gomspace/libutil/include/gs/util/test/log.h | 88 - gomspace/libutil/include/gs/util/thread.h | 173 - gomspace/libutil/include/gs/util/time.h | 95 - gomspace/libutil/include/gs/util/timestamp.h | 73 - gomspace/libutil/include/gs/util/types.h | 114 - gomspace/libutil/include/gs/util/unistd.h | 32 - gomspace/libutil/include/gs/util/vmem.h | 194 - .../include/gs/util/watchdog/watchdog.h | 143 - .../include/gs/util/watchdog/watchdog_task.h | 45 - gomspace/libutil/include/gs/util/zip/zip.h | 62 - gomspace/libutil/src/base16.c | 61 - gomspace/libutil/src/bindings/python/pyutil.c | 73 - gomspace/libutil/src/bytebuffer.c | 128 - gomspace/libutil/src/byteorder.c | 323 - gomspace/libutil/src/clock.c | 113 - gomspace/libutil/src/crc32.c | 79 - gomspace/libutil/src/crc8.c | 68 - gomspace/libutil/src/drivers/can/can.c | 6 - gomspace/libutil/src/drivers/i2c/i2c.c | 6 - gomspace/libutil/src/drivers/spi/spi.c | 6 - gomspace/libutil/src/drivers/sys/memory.c | 37 - gomspace/libutil/src/error.c | 106 - gomspace/libutil/src/fletcher.c | 77 - gomspace/libutil/src/function_scheduler.c | 111 - gomspace/libutil/src/gosh/command.c | 754 -- gomspace/libutil/src/gosh/command_local.h | 35 - gomspace/libutil/src/gosh/console.c | 758 -- gomspace/libutil/src/gosh/console_local.h | 10 - gomspace/libutil/src/gosh/default_commands.c | 277 - gomspace/libutil/src/gosh/getopt.c | 55 - gomspace/libutil/src/hexdump.c | 92 - gomspace/libutil/src/linux/argp.c | 34 - gomspace/libutil/src/linux/clock.c | 68 - gomspace/libutil/src/linux/command_line.c | 76 - gomspace/libutil/src/linux/cwd.c | 28 - gomspace/libutil/src/linux/delay.c | 22 - gomspace/libutil/src/linux/drivers/can/can.c | 308 - .../libutil/src/linux/drivers/gpio/gpio.c | 102 - .../src/linux/drivers/gpio/gpio_sysfs.c | 145 - .../src/linux/drivers/gpio/gpio_virtual.c | 171 - gomspace/libutil/src/linux/drivers/i2c/i2c.c | 144 - gomspace/libutil/src/linux/drivers/spi/spi.c | 137 - .../libutil/src/linux/drivers/sys/memory.c | 30 - gomspace/libutil/src/linux/function.c | 41 - gomspace/libutil/src/linux/mutex.c | 59 - gomspace/libutil/src/linux/queue.c | 217 - gomspace/libutil/src/linux/rtc.c | 78 - gomspace/libutil/src/linux/sem.c | 89 - gomspace/libutil/src/linux/signal.c | 38 - gomspace/libutil/src/linux/stdio.c | 36 - gomspace/libutil/src/linux/sysfs_helper.c | 48 - gomspace/libutil/src/linux/thread.c | 89 - gomspace/libutil/src/linux/time.c | 53 - gomspace/libutil/src/lock.c | 30 - gomspace/libutil/src/lock.h | 14 - gomspace/libutil/src/log/appender/console.c | 88 - .../libutil/src/log/appender/simple_file.c | 117 - gomspace/libutil/src/log/commands.c | 392 - gomspace/libutil/src/log/local.h | 27 - gomspace/libutil/src/log/log.c | 705 -- gomspace/libutil/src/rtc.c | 42 - gomspace/libutil/src/stdio.c | 81 - gomspace/libutil/src/string.c | 746 -- gomspace/libutil/src/strtoint.c | 399 - gomspace/libutil/src/test/cmocka.c | 63 - gomspace/libutil/src/test/command.c | 176 - gomspace/libutil/src/test/log.c | 165 - gomspace/libutil/src/time.c | 28 - gomspace/libutil/src/timestamp.c | 61 - gomspace/libutil/src/vmem/commands.c | 123 - gomspace/libutil/src/vmem/vmem.c | 143 - gomspace/libutil/src/watchdog/local.h | 18 - gomspace/libutil/src/watchdog/monitor_task.c | 68 - gomspace/libutil/src/watchdog/watchdog.c | 292 - .../libutil/src/zip/cppcheck-suppress.txt | 5 - .../libutil/src/zip/miniz/LIST_OF_CHANGES | 9429 ----------------- gomspace/libutil/src/zip/miniz/miniz.c | 7572 ------------- gomspace/libutil/src/zip/miniz/miniz.h | 1329 --- gomspace/libutil/src/zip/zip.c | 357 - gomspace/libutil/wscript | 109 - mission/core/InitMission.cpp | 2 +- mission/core/ObjectFactory.cpp | 6 +- mission/devices/P60DockHandler.cpp | 24 +- mission/devices/P60DockHandler.h | 12 +- test/testtasks/P60DockTestTask.cpp | 122 +- test/testtasks/P60DockTestTask.h | 20 +- 323 files changed, 132 insertions(+), 41250 deletions(-) rename gomspace/{libgscsp/lib => }/libcsp/CHANGELOG (100%) rename gomspace/{libgscsp/lib => }/libcsp/CONTRIBUTORS (100%) rename gomspace/{libgscsp/lib => }/libcsp/COPYING (100%) rename gomspace/{libgscsp/lib => }/libcsp/INSTALL.rst (100%) rename gomspace/{libgscsp/lib => }/libcsp/README.rst (100%) rename gomspace/{libgscsp/lib => }/libcsp/bindings/python/libcsp/__init__.py (100%) rename gomspace/{libgscsp/lib => }/libcsp/doc/example.rst (100%) rename gomspace/{libgscsp/lib => }/libcsp/doc/history.rst (100%) rename gomspace/{libgscsp/lib => }/libcsp/doc/interfaces.rst (100%) rename gomspace/{libgscsp/lib => }/libcsp/doc/libcsp.rst (100%) rename gomspace/{libgscsp/lib => }/libcsp/doc/memory.rst (100%) rename gomspace/{libgscsp/lib => }/libcsp/doc/mtu.rst (100%) rename gomspace/{libgscsp/lib => }/libcsp/doc/protocolstack.rst (100%) rename gomspace/{libgscsp/lib => }/libcsp/doc/structure.rst (100%) rename gomspace/{libgscsp/lib => }/libcsp/doc/topology.rst (100%) rename gomspace/{libgscsp/lib => }/libcsp/examples/csp_if_fifo.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/examples/csp_if_fifo_windows.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/examples/kiss.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/examples/python_bindings_example_client.py (100%) rename gomspace/{libgscsp/lib => }/libcsp/examples/python_bindings_example_client_can.py (100%) rename gomspace/{libgscsp/lib => }/libcsp/examples/python_bindings_example_server.py (100%) rename gomspace/{libgscsp/lib => }/libcsp/examples/simple.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/examples/zmqproxy.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/arch/csp_clock.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/arch/csp_malloc.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/arch/csp_queue.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/arch/csp_semaphore.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/arch/csp_system.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/arch/csp_thread.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/arch/csp_time.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/arch/posix/pthread_queue.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/crypto/csp_hmac.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/crypto/csp_sha1.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/crypto/csp_xtea.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/csp.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/csp_autoconfig.h (69%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/csp_buffer.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/csp_cmp.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/csp_crc32.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/csp_debug.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/csp_endian.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/csp_error.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/csp_iflist.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/csp_interface.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/csp_platform.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/csp_rtable.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/csp_types.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/drivers/can_socketcan.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/drivers/i2c.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/drivers/usart.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/interfaces/csp_if_can.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/interfaces/csp_if_i2c.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/interfaces/csp_if_kiss.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/interfaces/csp_if_lo.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/include/csp/interfaces/csp_if_zmqhub.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/freertos/csp_malloc.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/freertos/csp_queue.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/freertos/csp_semaphore.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/freertos/csp_system.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/freertos/csp_thread.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/freertos/csp_time.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/macosx/csp_malloc.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/macosx/csp_queue.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/macosx/csp_semaphore.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/macosx/csp_system.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/macosx/csp_thread.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/macosx/csp_time.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/macosx/pthread_queue.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/posix/csp_malloc.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/posix/csp_queue.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/posix/csp_semaphore.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/posix/csp_system.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/posix/csp_thread.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/posix/csp_time.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/posix/pthread_queue.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/windows/README (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/windows/csp_malloc.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/windows/csp_queue.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/windows/csp_semaphore.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/windows/csp_system.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/windows/csp_thread.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/windows/csp_time.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/windows/windows_glue.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/windows/windows_queue.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/arch/windows/windows_queue.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/bindings/python/pycsp.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/crypto/csp_hmac.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/crypto/csp_sha1.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/crypto/csp_xtea.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_bridge.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_buffer.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_conn.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_conn.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_crc32.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_debug.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_dedup.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_dedup.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_endian.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_hex_dump.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_iflist.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_io.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_io.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_port.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_port.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_promisc.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_promisc.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_qfifo.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_qfifo.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_route.c (99%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_route.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_service_handler.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_services.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/csp_sfp.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/drivers/can/can_socketcan.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/drivers/usart/usart_linux.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/drivers/usart/usart_windows.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/interfaces/csp_if_can.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/interfaces/csp_if_can_pbuf.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/interfaces/csp_if_can_pbuf.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/interfaces/csp_if_i2c.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/interfaces/csp_if_kiss.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/interfaces/csp_if_lo.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/rtable/csp_rtable_cidr.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/rtable/csp_rtable_static.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/transport/csp_rdp.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/transport/csp_transport.h (100%) rename gomspace/{libgscsp/lib => }/libcsp/src/transport/csp_udp.c (100%) rename gomspace/{libgscsp/lib => }/libcsp/utils/cfpsplit.py (100%) rename gomspace/{libgscsp/lib => }/libcsp/utils/cspsplit.py (100%) rename gomspace/{libgscsp/lib => }/libcsp/waf (100%) rename gomspace/{libgscsp/lib => }/libcsp/wscript (100%) delete mode 100644 gomspace/libgscsp/include/gs/csp/address.h delete mode 100644 gomspace/libgscsp/include/gs/csp/command.h delete mode 100644 gomspace/libgscsp/include/gs/csp/conn.h delete mode 100644 gomspace/libgscsp/include/gs/csp/csp.h delete mode 100644 gomspace/libgscsp/include/gs/csp/drivers/can/can.h delete mode 100644 gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h delete mode 100644 gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h delete mode 100644 gomspace/libgscsp/include/gs/csp/error.h delete mode 100644 gomspace/libgscsp/include/gs/csp/linux/command_line.h delete mode 100644 gomspace/libgscsp/include/gs/csp/log.h delete mode 100644 gomspace/libgscsp/include/gs/csp/port.h delete mode 100644 gomspace/libgscsp/include/gs/csp/router.h delete mode 100644 gomspace/libgscsp/include/gs/csp/rtable.h delete mode 100644 gomspace/libgscsp/include/gs/csp/service_dispatcher.h delete mode 100644 gomspace/libgscsp/include/gs/csp/service_handler.h delete mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c delete mode 100644 gomspace/libgscsp/src/bindings/python/pygscsp.c delete mode 100644 gomspace/libgscsp/src/clock.c delete mode 100644 gomspace/libgscsp/src/commands.c delete mode 100644 gomspace/libgscsp/src/conn.c delete mode 100644 gomspace/libgscsp/src/csp.c delete mode 100644 gomspace/libgscsp/src/drivers/can/can.c delete mode 100644 gomspace/libgscsp/src/drivers/i2c/i2c.c delete mode 100644 gomspace/libgscsp/src/drivers/kiss/kiss.c delete mode 100644 gomspace/libgscsp/src/error.c delete mode 100644 gomspace/libgscsp/src/freertos/cpu.c delete mode 100644 gomspace/libgscsp/src/linux/command_line.c delete mode 100644 gomspace/libgscsp/src/local.h delete mode 100644 gomspace/libgscsp/src/log.c delete mode 100644 gomspace/libgscsp/src/router.c delete mode 100644 gomspace/libgscsp/src/rtable.c delete mode 100644 gomspace/libgscsp/src/service_dispatcher.c delete mode 100644 gomspace/libgscsp/src/service_handler.c delete mode 100644 gomspace/libgscsp/src/transaction.c delete mode 100644 gomspace/libgscsp/wscript delete mode 100644 gomspace/libp60_client/include/p60.h delete mode 100644 gomspace/libp60_client/include/p60_board.h delete mode 100644 gomspace/libp60_client/include/power_if.h delete mode 100644 gomspace/libp60_client/src/cmd/power_if_cmd.c delete mode 100644 gomspace/libp60_client/src/p60_client.c delete mode 100644 gomspace/libp60_client/src/power_if.c delete mode 100644 gomspace/libp60_client/wscript delete mode 100644 gomspace/libutil/include/deprecated/gs/gosh/command/command.h delete mode 100644 gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h delete mode 100644 gomspace/libutil/include/deprecated/gs/gosh/util/console.h delete mode 100644 gomspace/libutil/include/deprecated/util/color_printf.h delete mode 100644 gomspace/libutil/include/gs/uthash/utarray.h delete mode 100644 gomspace/libutil/include/gs/uthash/uthash.h delete mode 100644 gomspace/libutil/include/gs/uthash/utlist.h delete mode 100644 gomspace/libutil/include/gs/uthash/utstring.h delete mode 100644 gomspace/libutil/include/gs/util/base16.h delete mode 100644 gomspace/libutil/include/gs/util/bytebuffer.h delete mode 100644 gomspace/libutil/include/gs/util/byteorder.h delete mode 100644 gomspace/libutil/include/gs/util/check.h delete mode 100644 gomspace/libutil/include/gs/util/clock.h delete mode 100644 gomspace/libutil/include/gs/util/conf_util.h delete mode 100644 gomspace/libutil/include/gs/util/crc32.h delete mode 100644 gomspace/libutil/include/gs/util/crc8.h delete mode 100644 gomspace/libutil/include/gs/util/delay.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/can/can.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/gpio/gpio.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/i2c/common.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/i2c/master.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/i2c/slave.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/spi/common.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/spi/master.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/spi/slave.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/sys/memory.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/watchdog/device.h delete mode 100644 gomspace/libutil/include/gs/util/endian.h delete mode 100644 gomspace/libutil/include/gs/util/error.h delete mode 100644 gomspace/libutil/include/gs/util/fletcher.h delete mode 100644 gomspace/libutil/include/gs/util/function_scheduler.h delete mode 100644 gomspace/libutil/include/gs/util/gosh/command.h delete mode 100644 gomspace/libutil/include/gs/util/gosh/console.h delete mode 100644 gomspace/libutil/include/gs/util/hexdump.h delete mode 100644 gomspace/libutil/include/gs/util/linux/argp.h delete mode 100644 gomspace/libutil/include/gs/util/linux/command_line.h delete mode 100644 gomspace/libutil/include/gs/util/linux/drivers/can/can.h delete mode 100644 gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h delete mode 100644 gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h delete mode 100644 gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h delete mode 100644 gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h delete mode 100644 gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h delete mode 100644 gomspace/libutil/include/gs/util/linux/exitcode.h delete mode 100644 gomspace/libutil/include/gs/util/linux/function.h delete mode 100644 gomspace/libutil/include/gs/util/linux/rtc.h delete mode 100644 gomspace/libutil/include/gs/util/linux/signal.h delete mode 100644 gomspace/libutil/include/gs/util/linux/sysfs_helper.h delete mode 100644 gomspace/libutil/include/gs/util/log.h delete mode 100644 gomspace/libutil/include/gs/util/log/appender/appender.h delete mode 100644 gomspace/libutil/include/gs/util/log/appender/console.h delete mode 100644 gomspace/libutil/include/gs/util/log/appender/simple_file.h delete mode 100644 gomspace/libutil/include/gs/util/log/log.h delete mode 100644 gomspace/libutil/include/gs/util/minmax.h delete mode 100644 gomspace/libutil/include/gs/util/mutex.h delete mode 100644 gomspace/libutil/include/gs/util/pgm.h delete mode 100644 gomspace/libutil/include/gs/util/queue.h delete mode 100644 gomspace/libutil/include/gs/util/rtc.h delete mode 100644 gomspace/libutil/include/gs/util/sem.h delete mode 100644 gomspace/libutil/include/gs/util/stdio.h delete mode 100644 gomspace/libutil/include/gs/util/string.h delete mode 100644 gomspace/libutil/include/gs/util/test/cmocka.h delete mode 100644 gomspace/libutil/include/gs/util/test/command.h delete mode 100644 gomspace/libutil/include/gs/util/test/log.h delete mode 100644 gomspace/libutil/include/gs/util/thread.h delete mode 100644 gomspace/libutil/include/gs/util/time.h delete mode 100644 gomspace/libutil/include/gs/util/timestamp.h delete mode 100644 gomspace/libutil/include/gs/util/types.h delete mode 100644 gomspace/libutil/include/gs/util/unistd.h delete mode 100644 gomspace/libutil/include/gs/util/vmem.h delete mode 100644 gomspace/libutil/include/gs/util/watchdog/watchdog.h delete mode 100644 gomspace/libutil/include/gs/util/watchdog/watchdog_task.h delete mode 100644 gomspace/libutil/include/gs/util/zip/zip.h delete mode 100644 gomspace/libutil/src/base16.c delete mode 100644 gomspace/libutil/src/bindings/python/pyutil.c delete mode 100644 gomspace/libutil/src/bytebuffer.c delete mode 100644 gomspace/libutil/src/byteorder.c delete mode 100644 gomspace/libutil/src/clock.c delete mode 100644 gomspace/libutil/src/crc32.c delete mode 100644 gomspace/libutil/src/crc8.c delete mode 100644 gomspace/libutil/src/drivers/can/can.c delete mode 100644 gomspace/libutil/src/drivers/i2c/i2c.c delete mode 100644 gomspace/libutil/src/drivers/spi/spi.c delete mode 100644 gomspace/libutil/src/drivers/sys/memory.c delete mode 100644 gomspace/libutil/src/error.c delete mode 100644 gomspace/libutil/src/fletcher.c delete mode 100644 gomspace/libutil/src/function_scheduler.c delete mode 100644 gomspace/libutil/src/gosh/command.c delete mode 100644 gomspace/libutil/src/gosh/command_local.h delete mode 100644 gomspace/libutil/src/gosh/console.c delete mode 100644 gomspace/libutil/src/gosh/console_local.h delete mode 100644 gomspace/libutil/src/gosh/default_commands.c delete mode 100644 gomspace/libutil/src/gosh/getopt.c delete mode 100644 gomspace/libutil/src/hexdump.c delete mode 100644 gomspace/libutil/src/linux/argp.c delete mode 100644 gomspace/libutil/src/linux/clock.c delete mode 100644 gomspace/libutil/src/linux/command_line.c delete mode 100644 gomspace/libutil/src/linux/cwd.c delete mode 100644 gomspace/libutil/src/linux/delay.c delete mode 100644 gomspace/libutil/src/linux/drivers/can/can.c delete mode 100644 gomspace/libutil/src/linux/drivers/gpio/gpio.c delete mode 100644 gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c delete mode 100644 gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c delete mode 100644 gomspace/libutil/src/linux/drivers/i2c/i2c.c delete mode 100644 gomspace/libutil/src/linux/drivers/spi/spi.c delete mode 100644 gomspace/libutil/src/linux/drivers/sys/memory.c delete mode 100644 gomspace/libutil/src/linux/function.c delete mode 100644 gomspace/libutil/src/linux/mutex.c delete mode 100644 gomspace/libutil/src/linux/queue.c delete mode 100644 gomspace/libutil/src/linux/rtc.c delete mode 100644 gomspace/libutil/src/linux/sem.c delete mode 100644 gomspace/libutil/src/linux/signal.c delete mode 100644 gomspace/libutil/src/linux/stdio.c delete mode 100644 gomspace/libutil/src/linux/sysfs_helper.c delete mode 100644 gomspace/libutil/src/linux/thread.c delete mode 100644 gomspace/libutil/src/linux/time.c delete mode 100644 gomspace/libutil/src/lock.c delete mode 100644 gomspace/libutil/src/lock.h delete mode 100644 gomspace/libutil/src/log/appender/console.c delete mode 100644 gomspace/libutil/src/log/appender/simple_file.c delete mode 100644 gomspace/libutil/src/log/commands.c delete mode 100644 gomspace/libutil/src/log/local.h delete mode 100644 gomspace/libutil/src/log/log.c delete mode 100644 gomspace/libutil/src/rtc.c delete mode 100644 gomspace/libutil/src/stdio.c delete mode 100644 gomspace/libutil/src/string.c delete mode 100644 gomspace/libutil/src/strtoint.c delete mode 100644 gomspace/libutil/src/test/cmocka.c delete mode 100644 gomspace/libutil/src/test/command.c delete mode 100644 gomspace/libutil/src/test/log.c delete mode 100644 gomspace/libutil/src/time.c delete mode 100644 gomspace/libutil/src/timestamp.c delete mode 100644 gomspace/libutil/src/vmem/commands.c delete mode 100644 gomspace/libutil/src/vmem/vmem.c delete mode 100644 gomspace/libutil/src/watchdog/local.h delete mode 100644 gomspace/libutil/src/watchdog/monitor_task.c delete mode 100644 gomspace/libutil/src/watchdog/watchdog.c delete mode 100644 gomspace/libutil/src/zip/cppcheck-suppress.txt delete mode 100644 gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES delete mode 100644 gomspace/libutil/src/zip/miniz/miniz.c delete mode 100644 gomspace/libutil/src/zip/miniz/miniz.h delete mode 100644 gomspace/libutil/src/zip/zip.c delete mode 100644 gomspace/libutil/wscript diff --git a/config/OBSWConfig.h b/config/OBSWConfig.h index 7a569b87..2b8b62c4 100644 --- a/config/OBSWConfig.h +++ b/config/OBSWConfig.h @@ -6,7 +6,7 @@ #ifndef CONFIG_OBSWCONFIG_H_ #define CONFIG_OBSWCONFIG_H_ -#define OBSW_ADD_TEST_CODE 1 +#define ADD_TEST_CODE 1 // Define not used yet, PUS stack and TMTC tasks are always started #define ADD_PUS_STACK 1 diff --git a/gomspace/gomspace.mk b/gomspace/gomspace.mk index d36afcd7..675fa426 100644 --- a/gomspace/gomspace.mk +++ b/gomspace/gomspace.mk @@ -1,10 +1,11 @@ -CSRC += $(wildcard $(CURRENTPATH)/libgscsp/lib/libcsp/src/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libgscsp/src/drivers/can/*.c) +CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/drivers/can/*.c) +CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/*.c) +CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/interfaces/*.c) +CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/rtable/csp_rtable_cidr.c) +CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/crypto/*.c) +CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/arch/posix/*.c) +CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/transport/*.c) -INCLUDES += $(CURRENTPATH)/libgscsp/include -INCLUDES += $(CURRENTPATH)/libgscsp/lib/libcsp/include/csp/interfaces -INCLUDES += $(CURRENTPATH)/libgscsp/lib/libcsp/include -INCLUDES += $(CURRENTPATH)/libgscsp/lib/libcsp/include/csp -INCLUDES += $(CURRENTPATH)/libutil/include -INCLUDES += $(CURRENTPATH)/libutil/include/gs/util -INCLUDES += $(CURRENTPATH)/lib/libcsp/include \ No newline at end of file +INCLUDES += $(CURRENTPATH)/libcsp/include +INCLUDES += $(CURRENTPATH)/libcsp/include/csp/crypto +INCLUDES += $(CURRENTPATH)/libcsp \ No newline at end of file diff --git a/gomspace/libgscsp/lib/libcsp/CHANGELOG b/gomspace/libcsp/CHANGELOG similarity index 100% rename from gomspace/libgscsp/lib/libcsp/CHANGELOG rename to gomspace/libcsp/CHANGELOG diff --git a/gomspace/libgscsp/lib/libcsp/CONTRIBUTORS b/gomspace/libcsp/CONTRIBUTORS similarity index 100% rename from gomspace/libgscsp/lib/libcsp/CONTRIBUTORS rename to gomspace/libcsp/CONTRIBUTORS diff --git a/gomspace/libgscsp/lib/libcsp/COPYING b/gomspace/libcsp/COPYING similarity index 100% rename from gomspace/libgscsp/lib/libcsp/COPYING rename to gomspace/libcsp/COPYING diff --git a/gomspace/libgscsp/lib/libcsp/INSTALL.rst b/gomspace/libcsp/INSTALL.rst similarity index 100% rename from gomspace/libgscsp/lib/libcsp/INSTALL.rst rename to gomspace/libcsp/INSTALL.rst diff --git a/gomspace/libgscsp/lib/libcsp/README.rst b/gomspace/libcsp/README.rst similarity index 100% rename from gomspace/libgscsp/lib/libcsp/README.rst rename to gomspace/libcsp/README.rst diff --git a/gomspace/libgscsp/lib/libcsp/bindings/python/libcsp/__init__.py b/gomspace/libcsp/bindings/python/libcsp/__init__.py similarity index 100% rename from gomspace/libgscsp/lib/libcsp/bindings/python/libcsp/__init__.py rename to gomspace/libcsp/bindings/python/libcsp/__init__.py diff --git a/gomspace/libgscsp/lib/libcsp/doc/example.rst b/gomspace/libcsp/doc/example.rst similarity index 100% rename from gomspace/libgscsp/lib/libcsp/doc/example.rst rename to gomspace/libcsp/doc/example.rst diff --git a/gomspace/libgscsp/lib/libcsp/doc/history.rst b/gomspace/libcsp/doc/history.rst similarity index 100% rename from gomspace/libgscsp/lib/libcsp/doc/history.rst rename to gomspace/libcsp/doc/history.rst diff --git a/gomspace/libgscsp/lib/libcsp/doc/interfaces.rst b/gomspace/libcsp/doc/interfaces.rst similarity index 100% rename from gomspace/libgscsp/lib/libcsp/doc/interfaces.rst rename to gomspace/libcsp/doc/interfaces.rst diff --git a/gomspace/libgscsp/lib/libcsp/doc/libcsp.rst b/gomspace/libcsp/doc/libcsp.rst similarity index 100% rename from gomspace/libgscsp/lib/libcsp/doc/libcsp.rst rename to gomspace/libcsp/doc/libcsp.rst diff --git a/gomspace/libgscsp/lib/libcsp/doc/memory.rst b/gomspace/libcsp/doc/memory.rst similarity index 100% rename from gomspace/libgscsp/lib/libcsp/doc/memory.rst rename to gomspace/libcsp/doc/memory.rst diff --git a/gomspace/libgscsp/lib/libcsp/doc/mtu.rst b/gomspace/libcsp/doc/mtu.rst similarity index 100% rename from gomspace/libgscsp/lib/libcsp/doc/mtu.rst rename to gomspace/libcsp/doc/mtu.rst diff --git a/gomspace/libgscsp/lib/libcsp/doc/protocolstack.rst b/gomspace/libcsp/doc/protocolstack.rst similarity index 100% rename from gomspace/libgscsp/lib/libcsp/doc/protocolstack.rst rename to gomspace/libcsp/doc/protocolstack.rst diff --git a/gomspace/libgscsp/lib/libcsp/doc/structure.rst b/gomspace/libcsp/doc/structure.rst similarity index 100% rename from gomspace/libgscsp/lib/libcsp/doc/structure.rst rename to gomspace/libcsp/doc/structure.rst diff --git a/gomspace/libgscsp/lib/libcsp/doc/topology.rst b/gomspace/libcsp/doc/topology.rst similarity index 100% rename from gomspace/libgscsp/lib/libcsp/doc/topology.rst rename to gomspace/libcsp/doc/topology.rst diff --git a/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo.c b/gomspace/libcsp/examples/csp_if_fifo.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo.c rename to gomspace/libcsp/examples/csp_if_fifo.c diff --git a/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo_windows.c b/gomspace/libcsp/examples/csp_if_fifo_windows.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo_windows.c rename to gomspace/libcsp/examples/csp_if_fifo_windows.c diff --git a/gomspace/libgscsp/lib/libcsp/examples/kiss.c b/gomspace/libcsp/examples/kiss.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/examples/kiss.c rename to gomspace/libcsp/examples/kiss.c diff --git a/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client.py b/gomspace/libcsp/examples/python_bindings_example_client.py similarity index 100% rename from gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client.py rename to gomspace/libcsp/examples/python_bindings_example_client.py diff --git a/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client_can.py b/gomspace/libcsp/examples/python_bindings_example_client_can.py similarity index 100% rename from gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client_can.py rename to gomspace/libcsp/examples/python_bindings_example_client_can.py diff --git a/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_server.py b/gomspace/libcsp/examples/python_bindings_example_server.py similarity index 100% rename from gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_server.py rename to gomspace/libcsp/examples/python_bindings_example_server.py diff --git a/gomspace/libgscsp/lib/libcsp/examples/simple.c b/gomspace/libcsp/examples/simple.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/examples/simple.c rename to gomspace/libcsp/examples/simple.c diff --git a/gomspace/libgscsp/lib/libcsp/examples/zmqproxy.c b/gomspace/libcsp/examples/zmqproxy.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/examples/zmqproxy.c rename to gomspace/libcsp/examples/zmqproxy.c diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_clock.h b/gomspace/libcsp/include/csp/arch/csp_clock.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_clock.h rename to gomspace/libcsp/include/csp/arch/csp_clock.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_malloc.h b/gomspace/libcsp/include/csp/arch/csp_malloc.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_malloc.h rename to gomspace/libcsp/include/csp/arch/csp_malloc.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_queue.h b/gomspace/libcsp/include/csp/arch/csp_queue.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_queue.h rename to gomspace/libcsp/include/csp/arch/csp_queue.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_semaphore.h b/gomspace/libcsp/include/csp/arch/csp_semaphore.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_semaphore.h rename to gomspace/libcsp/include/csp/arch/csp_semaphore.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_system.h b/gomspace/libcsp/include/csp/arch/csp_system.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_system.h rename to gomspace/libcsp/include/csp/arch/csp_system.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_thread.h b/gomspace/libcsp/include/csp/arch/csp_thread.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_thread.h rename to gomspace/libcsp/include/csp/arch/csp_thread.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_time.h b/gomspace/libcsp/include/csp/arch/csp_time.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_time.h rename to gomspace/libcsp/include/csp/arch/csp_time.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/posix/pthread_queue.h b/gomspace/libcsp/include/csp/arch/posix/pthread_queue.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/arch/posix/pthread_queue.h rename to gomspace/libcsp/include/csp/arch/posix/pthread_queue.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_hmac.h b/gomspace/libcsp/include/csp/crypto/csp_hmac.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_hmac.h rename to gomspace/libcsp/include/csp/crypto/csp_hmac.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_sha1.h b/gomspace/libcsp/include/csp/crypto/csp_sha1.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_sha1.h rename to gomspace/libcsp/include/csp/crypto/csp_sha1.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_xtea.h b/gomspace/libcsp/include/csp/crypto/csp_xtea.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_xtea.h rename to gomspace/libcsp/include/csp/crypto/csp_xtea.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp.h b/gomspace/libcsp/include/csp/csp.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/csp.h rename to gomspace/libcsp/include/csp/csp.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_autoconfig.h b/gomspace/libcsp/include/csp/csp_autoconfig.h similarity index 69% rename from gomspace/libgscsp/lib/libcsp/include/csp/csp_autoconfig.h rename to gomspace/libcsp/include/csp/csp_autoconfig.h index 77746afd..703f3754 100644 --- a/gomspace/libgscsp/lib/libcsp/include/csp/csp_autoconfig.h +++ b/gomspace/libcsp/include/csp/csp_autoconfig.h @@ -1,5 +1,12 @@ -#ifndef W_INCLUDE_CSP_CSP_AUTOCONFIG_H_WAF -#define W_INCLUDE_CSP_CSP_AUTOCONFIG_H_WAF +/* + * csp_autoconfig.h + * + * Created on: 20.11.2020 + * Author: jakob + */ + +#ifndef GOMSPACE_LIBCSP_INCLUDE_CSP_CSP_AUTOCONFIG_H_ +#define GOMSPACE_LIBCSP_INCLUDE_CSP_CSP_AUTOCONFIG_H_ #define ENABLE_NANOPOWER2_CLIENT 1 #define GIT_REV "unknown" @@ -18,9 +25,9 @@ /* #undef CSP_USE_DEDUP */ /* #undef CSP_USE_INIT_SHUTDOWN */ #define CSP_USE_CAN 1 -#define CSP_USE_I2C 1 -#define CSP_USE_KISS 1 -#define CSP_USE_ZMQHUB 1 +/* #define CSP_USE_I2C 1 */ +/* #define CSP_USE_KISS 1 */ +/* #define CSP_USE_ZMQHUB 1 */ #define CSP_CONN_MAX 10 #define CSP_CONN_QUEUE_LENGTH 100 #define CSP_FIFO_INPUT 100 @@ -35,7 +42,7 @@ #define CSP_LITTLE_ENDIAN 1 /* #undef CSP_BIG_ENDIAN */ #define CSP_HAVE_STDBOOL_H 1 -#define CSP_HAVE_LIBSOCKETCAN 1 +/* #define CSP_HAVE_LIBSOCKETCAN 1 */ #define LIBCSP_VERSION "1.5" -#endif /* W_INCLUDE_CSP_CSP_AUTOCONFIG_H_WAF */ +#endif /* GOMSPACE_LIBCSP_INCLUDE_CSP_CSP_AUTOCONFIG_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_buffer.h b/gomspace/libcsp/include/csp/csp_buffer.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/csp_buffer.h rename to gomspace/libcsp/include/csp/csp_buffer.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_cmp.h b/gomspace/libcsp/include/csp/csp_cmp.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/csp_cmp.h rename to gomspace/libcsp/include/csp/csp_cmp.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_crc32.h b/gomspace/libcsp/include/csp/csp_crc32.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/csp_crc32.h rename to gomspace/libcsp/include/csp/csp_crc32.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_debug.h b/gomspace/libcsp/include/csp/csp_debug.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/csp_debug.h rename to gomspace/libcsp/include/csp/csp_debug.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_endian.h b/gomspace/libcsp/include/csp/csp_endian.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/csp_endian.h rename to gomspace/libcsp/include/csp/csp_endian.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_error.h b/gomspace/libcsp/include/csp/csp_error.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/csp_error.h rename to gomspace/libcsp/include/csp/csp_error.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_iflist.h b/gomspace/libcsp/include/csp/csp_iflist.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/csp_iflist.h rename to gomspace/libcsp/include/csp/csp_iflist.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_interface.h b/gomspace/libcsp/include/csp/csp_interface.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/csp_interface.h rename to gomspace/libcsp/include/csp/csp_interface.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_platform.h b/gomspace/libcsp/include/csp/csp_platform.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/csp_platform.h rename to gomspace/libcsp/include/csp/csp_platform.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_rtable.h b/gomspace/libcsp/include/csp/csp_rtable.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/csp_rtable.h rename to gomspace/libcsp/include/csp/csp_rtable.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_types.h b/gomspace/libcsp/include/csp/csp_types.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/csp_types.h rename to gomspace/libcsp/include/csp/csp_types.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/drivers/can_socketcan.h b/gomspace/libcsp/include/csp/drivers/can_socketcan.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/drivers/can_socketcan.h rename to gomspace/libcsp/include/csp/drivers/can_socketcan.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/drivers/i2c.h b/gomspace/libcsp/include/csp/drivers/i2c.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/drivers/i2c.h rename to gomspace/libcsp/include/csp/drivers/i2c.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/drivers/usart.h b/gomspace/libcsp/include/csp/drivers/usart.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/drivers/usart.h rename to gomspace/libcsp/include/csp/drivers/usart.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_can.h b/gomspace/libcsp/include/csp/interfaces/csp_if_can.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_can.h rename to gomspace/libcsp/include/csp/interfaces/csp_if_can.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_i2c.h b/gomspace/libcsp/include/csp/interfaces/csp_if_i2c.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_i2c.h rename to gomspace/libcsp/include/csp/interfaces/csp_if_i2c.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_kiss.h b/gomspace/libcsp/include/csp/interfaces/csp_if_kiss.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_kiss.h rename to gomspace/libcsp/include/csp/interfaces/csp_if_kiss.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_lo.h b/gomspace/libcsp/include/csp/interfaces/csp_if_lo.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_lo.h rename to gomspace/libcsp/include/csp/interfaces/csp_if_lo.h diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_zmqhub.h b/gomspace/libcsp/include/csp/interfaces/csp_if_zmqhub.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_zmqhub.h rename to gomspace/libcsp/include/csp/interfaces/csp_if_zmqhub.h diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_malloc.c b/gomspace/libcsp/src/arch/freertos/csp_malloc.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_malloc.c rename to gomspace/libcsp/src/arch/freertos/csp_malloc.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_queue.c b/gomspace/libcsp/src/arch/freertos/csp_queue.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_queue.c rename to gomspace/libcsp/src/arch/freertos/csp_queue.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_semaphore.c b/gomspace/libcsp/src/arch/freertos/csp_semaphore.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_semaphore.c rename to gomspace/libcsp/src/arch/freertos/csp_semaphore.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_system.c b/gomspace/libcsp/src/arch/freertos/csp_system.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_system.c rename to gomspace/libcsp/src/arch/freertos/csp_system.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_thread.c b/gomspace/libcsp/src/arch/freertos/csp_thread.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_thread.c rename to gomspace/libcsp/src/arch/freertos/csp_thread.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_time.c b/gomspace/libcsp/src/arch/freertos/csp_time.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_time.c rename to gomspace/libcsp/src/arch/freertos/csp_time.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_malloc.c b/gomspace/libcsp/src/arch/macosx/csp_malloc.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_malloc.c rename to gomspace/libcsp/src/arch/macosx/csp_malloc.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_queue.c b/gomspace/libcsp/src/arch/macosx/csp_queue.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_queue.c rename to gomspace/libcsp/src/arch/macosx/csp_queue.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_semaphore.c b/gomspace/libcsp/src/arch/macosx/csp_semaphore.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_semaphore.c rename to gomspace/libcsp/src/arch/macosx/csp_semaphore.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_system.c b/gomspace/libcsp/src/arch/macosx/csp_system.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_system.c rename to gomspace/libcsp/src/arch/macosx/csp_system.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_thread.c b/gomspace/libcsp/src/arch/macosx/csp_thread.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_thread.c rename to gomspace/libcsp/src/arch/macosx/csp_thread.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_time.c b/gomspace/libcsp/src/arch/macosx/csp_time.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_time.c rename to gomspace/libcsp/src/arch/macosx/csp_time.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/pthread_queue.c b/gomspace/libcsp/src/arch/macosx/pthread_queue.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/macosx/pthread_queue.c rename to gomspace/libcsp/src/arch/macosx/pthread_queue.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_malloc.c b/gomspace/libcsp/src/arch/posix/csp_malloc.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_malloc.c rename to gomspace/libcsp/src/arch/posix/csp_malloc.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_queue.c b/gomspace/libcsp/src/arch/posix/csp_queue.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_queue.c rename to gomspace/libcsp/src/arch/posix/csp_queue.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_semaphore.c b/gomspace/libcsp/src/arch/posix/csp_semaphore.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_semaphore.c rename to gomspace/libcsp/src/arch/posix/csp_semaphore.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_system.c b/gomspace/libcsp/src/arch/posix/csp_system.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_system.c rename to gomspace/libcsp/src/arch/posix/csp_system.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_thread.c b/gomspace/libcsp/src/arch/posix/csp_thread.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_thread.c rename to gomspace/libcsp/src/arch/posix/csp_thread.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_time.c b/gomspace/libcsp/src/arch/posix/csp_time.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_time.c rename to gomspace/libcsp/src/arch/posix/csp_time.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/pthread_queue.c b/gomspace/libcsp/src/arch/posix/pthread_queue.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/posix/pthread_queue.c rename to gomspace/libcsp/src/arch/posix/pthread_queue.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/README b/gomspace/libcsp/src/arch/windows/README similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/windows/README rename to gomspace/libcsp/src/arch/windows/README diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_malloc.c b/gomspace/libcsp/src/arch/windows/csp_malloc.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_malloc.c rename to gomspace/libcsp/src/arch/windows/csp_malloc.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_queue.c b/gomspace/libcsp/src/arch/windows/csp_queue.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_queue.c rename to gomspace/libcsp/src/arch/windows/csp_queue.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_semaphore.c b/gomspace/libcsp/src/arch/windows/csp_semaphore.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_semaphore.c rename to gomspace/libcsp/src/arch/windows/csp_semaphore.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_system.c b/gomspace/libcsp/src/arch/windows/csp_system.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_system.c rename to gomspace/libcsp/src/arch/windows/csp_system.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_thread.c b/gomspace/libcsp/src/arch/windows/csp_thread.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_thread.c rename to gomspace/libcsp/src/arch/windows/csp_thread.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_time.c b/gomspace/libcsp/src/arch/windows/csp_time.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_time.c rename to gomspace/libcsp/src/arch/windows/csp_time.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_glue.h b/gomspace/libcsp/src/arch/windows/windows_glue.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_glue.h rename to gomspace/libcsp/src/arch/windows/windows_glue.h diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.c b/gomspace/libcsp/src/arch/windows/windows_queue.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.c rename to gomspace/libcsp/src/arch/windows/windows_queue.c diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.h b/gomspace/libcsp/src/arch/windows/windows_queue.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.h rename to gomspace/libcsp/src/arch/windows/windows_queue.h diff --git a/gomspace/libgscsp/lib/libcsp/src/bindings/python/pycsp.c b/gomspace/libcsp/src/bindings/python/pycsp.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/bindings/python/pycsp.c rename to gomspace/libcsp/src/bindings/python/pycsp.c diff --git a/gomspace/libgscsp/lib/libcsp/src/crypto/csp_hmac.c b/gomspace/libcsp/src/crypto/csp_hmac.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/crypto/csp_hmac.c rename to gomspace/libcsp/src/crypto/csp_hmac.c diff --git a/gomspace/libgscsp/lib/libcsp/src/crypto/csp_sha1.c b/gomspace/libcsp/src/crypto/csp_sha1.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/crypto/csp_sha1.c rename to gomspace/libcsp/src/crypto/csp_sha1.c diff --git a/gomspace/libgscsp/lib/libcsp/src/crypto/csp_xtea.c b/gomspace/libcsp/src/crypto/csp_xtea.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/crypto/csp_xtea.c rename to gomspace/libcsp/src/crypto/csp_xtea.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_bridge.c b/gomspace/libcsp/src/csp_bridge.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_bridge.c rename to gomspace/libcsp/src/csp_bridge.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_buffer.c b/gomspace/libcsp/src/csp_buffer.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_buffer.c rename to gomspace/libcsp/src/csp_buffer.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_conn.c b/gomspace/libcsp/src/csp_conn.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_conn.c rename to gomspace/libcsp/src/csp_conn.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_conn.h b/gomspace/libcsp/src/csp_conn.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_conn.h rename to gomspace/libcsp/src/csp_conn.h diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_crc32.c b/gomspace/libcsp/src/csp_crc32.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_crc32.c rename to gomspace/libcsp/src/csp_crc32.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_debug.c b/gomspace/libcsp/src/csp_debug.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_debug.c rename to gomspace/libcsp/src/csp_debug.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_dedup.c b/gomspace/libcsp/src/csp_dedup.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_dedup.c rename to gomspace/libcsp/src/csp_dedup.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_dedup.h b/gomspace/libcsp/src/csp_dedup.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_dedup.h rename to gomspace/libcsp/src/csp_dedup.h diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_endian.c b/gomspace/libcsp/src/csp_endian.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_endian.c rename to gomspace/libcsp/src/csp_endian.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_hex_dump.c b/gomspace/libcsp/src/csp_hex_dump.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_hex_dump.c rename to gomspace/libcsp/src/csp_hex_dump.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_iflist.c b/gomspace/libcsp/src/csp_iflist.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_iflist.c rename to gomspace/libcsp/src/csp_iflist.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_io.c b/gomspace/libcsp/src/csp_io.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_io.c rename to gomspace/libcsp/src/csp_io.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_io.h b/gomspace/libcsp/src/csp_io.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_io.h rename to gomspace/libcsp/src/csp_io.h diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_port.c b/gomspace/libcsp/src/csp_port.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_port.c rename to gomspace/libcsp/src/csp_port.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_port.h b/gomspace/libcsp/src/csp_port.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_port.h rename to gomspace/libcsp/src/csp_port.h diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_promisc.c b/gomspace/libcsp/src/csp_promisc.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_promisc.c rename to gomspace/libcsp/src/csp_promisc.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_promisc.h b/gomspace/libcsp/src/csp_promisc.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_promisc.h rename to gomspace/libcsp/src/csp_promisc.h diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c b/gomspace/libcsp/src/csp_qfifo.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c rename to gomspace/libcsp/src/csp_qfifo.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h b/gomspace/libcsp/src/csp_qfifo.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h rename to gomspace/libcsp/src/csp_qfifo.h diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_route.c b/gomspace/libcsp/src/csp_route.c similarity index 99% rename from gomspace/libgscsp/lib/libcsp/src/csp_route.c rename to gomspace/libcsp/src/csp_route.c index 627dfdc8..bc843577 100644 --- a/gomspace/libgscsp/lib/libcsp/src/csp_route.c +++ b/gomspace/libcsp/src/csp_route.c @@ -40,7 +40,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "csp_qfifo.h" #include "csp_dedup.h" #include "transport/csp_transport.h" -#include "csp_buffer.h" /** * Check supported packet options diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_route.h b/gomspace/libcsp/src/csp_route.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_route.h rename to gomspace/libcsp/src/csp_route.h diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_service_handler.c b/gomspace/libcsp/src/csp_service_handler.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_service_handler.c rename to gomspace/libcsp/src/csp_service_handler.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_services.c b/gomspace/libcsp/src/csp_services.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_services.c rename to gomspace/libcsp/src/csp_services.c diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_sfp.c b/gomspace/libcsp/src/csp_sfp.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/csp_sfp.c rename to gomspace/libcsp/src/csp_sfp.c diff --git a/gomspace/libgscsp/lib/libcsp/src/drivers/can/can_socketcan.c b/gomspace/libcsp/src/drivers/can/can_socketcan.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/drivers/can/can_socketcan.c rename to gomspace/libcsp/src/drivers/can/can_socketcan.c diff --git a/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_linux.c b/gomspace/libcsp/src/drivers/usart/usart_linux.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_linux.c rename to gomspace/libcsp/src/drivers/usart/usart_linux.c diff --git a/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_windows.c b/gomspace/libcsp/src/drivers/usart/usart_windows.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_windows.c rename to gomspace/libcsp/src/drivers/usart/usart_windows.c diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can.c b/gomspace/libcsp/src/interfaces/csp_if_can.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can.c rename to gomspace/libcsp/src/interfaces/csp_if_can.c diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.c b/gomspace/libcsp/src/interfaces/csp_if_can_pbuf.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.c rename to gomspace/libcsp/src/interfaces/csp_if_can_pbuf.c diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.h b/gomspace/libcsp/src/interfaces/csp_if_can_pbuf.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.h rename to gomspace/libcsp/src/interfaces/csp_if_can_pbuf.h diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_i2c.c b/gomspace/libcsp/src/interfaces/csp_if_i2c.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_i2c.c rename to gomspace/libcsp/src/interfaces/csp_if_i2c.c diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_kiss.c b/gomspace/libcsp/src/interfaces/csp_if_kiss.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_kiss.c rename to gomspace/libcsp/src/interfaces/csp_if_kiss.c diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_lo.c b/gomspace/libcsp/src/interfaces/csp_if_lo.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_lo.c rename to gomspace/libcsp/src/interfaces/csp_if_lo.c diff --git a/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_cidr.c b/gomspace/libcsp/src/rtable/csp_rtable_cidr.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_cidr.c rename to gomspace/libcsp/src/rtable/csp_rtable_cidr.c diff --git a/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_static.c b/gomspace/libcsp/src/rtable/csp_rtable_static.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_static.c rename to gomspace/libcsp/src/rtable/csp_rtable_static.c diff --git a/gomspace/libgscsp/lib/libcsp/src/transport/csp_rdp.c b/gomspace/libcsp/src/transport/csp_rdp.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/transport/csp_rdp.c rename to gomspace/libcsp/src/transport/csp_rdp.c diff --git a/gomspace/libgscsp/lib/libcsp/src/transport/csp_transport.h b/gomspace/libcsp/src/transport/csp_transport.h similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/transport/csp_transport.h rename to gomspace/libcsp/src/transport/csp_transport.h diff --git a/gomspace/libgscsp/lib/libcsp/src/transport/csp_udp.c b/gomspace/libcsp/src/transport/csp_udp.c similarity index 100% rename from gomspace/libgscsp/lib/libcsp/src/transport/csp_udp.c rename to gomspace/libcsp/src/transport/csp_udp.c diff --git a/gomspace/libgscsp/lib/libcsp/utils/cfpsplit.py b/gomspace/libcsp/utils/cfpsplit.py similarity index 100% rename from gomspace/libgscsp/lib/libcsp/utils/cfpsplit.py rename to gomspace/libcsp/utils/cfpsplit.py diff --git a/gomspace/libgscsp/lib/libcsp/utils/cspsplit.py b/gomspace/libcsp/utils/cspsplit.py similarity index 100% rename from gomspace/libgscsp/lib/libcsp/utils/cspsplit.py rename to gomspace/libcsp/utils/cspsplit.py diff --git a/gomspace/libgscsp/lib/libcsp/waf b/gomspace/libcsp/waf similarity index 100% rename from gomspace/libgscsp/lib/libcsp/waf rename to gomspace/libcsp/waf diff --git a/gomspace/libgscsp/lib/libcsp/wscript b/gomspace/libcsp/wscript similarity index 100% rename from gomspace/libgscsp/lib/libcsp/wscript rename to gomspace/libcsp/wscript diff --git a/gomspace/libgscsp/include/gs/csp/address.h b/gomspace/libgscsp/include/gs/csp/address.h deleted file mode 100644 index 9d6e701c..00000000 --- a/gomspace/libgscsp/include/gs/csp/address.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_ADDRESS_H -#define LIBGSCSP_INCLUDE_GS_CSP_ADDRESS_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Default CSP addresses for nodes in the satellite - often changed for each project. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Default address for OBC (On Board Computer). - Example: a3200-sdk. -*/ -#define GS_CSP_ADDR_OBC 1 -/** - Power supply. - Example: nano-power. -*/ -#define GS_CSP_ADDR_EPS 2 -/** - Payload address. -*/ -#define GS_CSP_ADDR_PAYLOAD_3 3 -/** - Default address for ADCS. - Example: a3200-adcs. -*/ -#define GS_CSP_ADDR_ADCS 4 -/** - Default address for radio. - Example: nanocom-ax. -*/ -#define GS_CSP_ADDR_NANOCOM 5 -/** - Payload address. -*/ -#define GS_CSP_ADDR_PAYLOAD_6 6 -/** - Battery pack. - Example: nano-power-bpx. -*/ -#define GS_CSP_ADDR_BPX 7 -/** - Payload address. -*/ -#define GS_CSP_ADDR_PAYLOAD_8 8 -/** - Reaction wheels. - Example: gsw-600. -*/ -#define GS_CSP_ADDR_GSW600 9 -/** - Antenna module. - Example: ant2150. -*/ -#define GS_CSP_ADDR_ANT2150 10 - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/command.h b/gomspace/libgscsp/include/gs/csp/command.h deleted file mode 100644 index 79d518db..00000000 --- a/gomspace/libgscsp/include/gs/csp/command.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_COMMAND_H -#define LIBGSCSP_INCLUDE_GS_CSP_COMMAND_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - CSP commands. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Register CSP commands. - @return_gs_error_t -*/ -gs_error_t gs_csp_register_commands(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/conn.h b/gomspace/libgscsp/include/gs/csp/conn.h deleted file mode 100644 index c8bd755e..00000000 --- a/gomspace/libgscsp/include/gs/csp/conn.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_CONN_H -#define LIBGSCSP_INCLUDE_GS_CSP_CONN_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Extensions to standard libcsp connection interface. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Return number of open connections. - - @return number of open connections. -*/ -size_t gs_csp_conn_get_open(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/csp.h b/gomspace/libgscsp/include/gs/csp/csp.h deleted file mode 100644 index 6268bced..00000000 --- a/gomspace/libgscsp/include/gs/csp/csp.h +++ /dev/null @@ -1,202 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_CSP_H -#define LIBGSCSP_INCLUDE_GS_CSP_CSP_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Extensions to standard libcsp. -*/ - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Default CSP timeout (mS). - - Default timeout value for communicating with a satellite, based on round-trip time of approximately 500 mS. -*/ -#define GS_CSP_TIMEOUT 3000 - -/** - Check if address is a valid CSP adddress. - @param[in] address CSP address to verify - @return \a true if address is valid. -*/ -bool gs_csp_is_address_valid(uint8_t address); - -/** - gscsp and csp configuration. -*/ -typedef struct { - /** - Forward CSP logs to GomSpace log (libutil). - */ - bool use_gs_log; - - /** - Use command line options. - Configure interfaces specified on the command line. - @note Only supported on Linux - ignored on platforms without command line options. - */ - bool use_command_line_options; - - /** - Size of a CSP buffer (in bytes). - @see csp_buffer_init(). - */ - size_t csp_buffer_size; - /** - Number of CSP buffers to allocate. - @see csp_buffer_init(). - */ - size_t csp_buffers; - - /** - CSP address of the system - */ - uint8_t address; - /** - Host name, returned by the #CSP_CMP_IDENT request. - @note String must remain valid as long as the application is running. - */ - const char *hostname; - /** - Model, returned by the #CSP_CMP_IDENT request. - @note String must remain valid as long as the application is running. - */ - const char *model; - /** - Revision, returned by the #CSP_CMP_IDENT request - @note String must remain valid as long as the application is running. - */ - const char *revision; - -} gs_csp_conf_t; - -/** - Get default CSP configuration for server systems. - @param[in] conf user supplied configuration struct. -*/ -void gs_csp_conf_get_defaults_server(gs_csp_conf_t * conf); - -/** - Get default CSP configuration for embedded systems. - @param[in] conf user supplied configuration struct. -*/ -void gs_csp_conf_get_defaults_embedded(gs_csp_conf_t * conf); - -/** - Initialize CSP. - - Wraps initialization of libcsp, by calling following functions - - hooks CSP log system into GomSpace log system. - - initializes CSP buffers by calling csp_buffer_init() - - initializes CSP by calling csp_init() - - configure interfaces specificed on command line - - configure routing table specificed on command line, or default if only one interface is present. - - @param[in] conf configuration. - @return_gs_error_t -*/ -gs_error_t gs_csp_init(const gs_csp_conf_t * conf); - -/** - Perform an entire request/reply transaction, - - Copies both input buffer and reply to output buffer. - Also makes the connection and closes it again - Differ from 'csp_transaction()' by limiting input buffer size when input length is unknown - - @param[in] prio CSP Prio - @param[in] dest CSP Dest - @param[in] port CSP Port - @param[in] timeout timeout in ms - @param[in] tx_buf pointer to outgoing data buffer - @param[in] tx_len length of request to send - @param[out] rx_buf pointer to incoming data buffer - @param[in] rx_max_len length of expected reply (input buffer size) - @param[out] rx_len pointer to length of reply - @param[in] opts connection options. - @return GS_ERROR_OVERFLOW when input length larger than buffer - it still updates rx_buf - @return GS_ERROR_IO when 'csp_send()' or 'csp_read()' fails - @return GS_ERROR_ALLOC when 'csp_get_buffer()' fails - @return_gs_error_t - */ -gs_error_t gs_csp_transaction2(uint8_t prio, - uint8_t dest, - uint8_t port, - uint32_t timeout, - const void * tx_buf, - size_t tx_len, - void * rx_buf, - size_t rx_max_len, - size_t * rx_len, - uint32_t opts); - -/** - Perform an entire request/reply transaction, - - @param[in] prio CSP Prio - @param[in] dest CSP Dest - @param[in] port CSP Port - @param[in] timeout timeout in ms - @param[in] tx_buf pointer to outgoing data buffer - @param[in] tx_len length of request to send - @param[out] rx_buf pointer to incoming data buffer - @param[in] rx_max_len length of expected reply (input buffer size) - @param[out] rx_len pointer to length of reply - @return GS_ERROR_OVERFLOW when input length larger than buffer - it still updates rx_buf - @return GS_ERROR_IO when 'csp_send()' or 'csp_read()' fails - @return GS_ERROR_ALLOC when 'csp_get_buffer()' fails - @return_gs_error_t - @see gs_csp_transaction2() -*/ -static inline gs_error_t gs_csp_transaction(uint8_t prio, - uint8_t dest, - uint8_t port, - uint32_t timeout, - const void * tx_buf, - size_t tx_len, - void * rx_buf, - size_t rx_max_len, - size_t * rx_len) -{ - return gs_csp_transaction2(prio, dest, port, timeout, tx_buf, tx_len, rx_buf, rx_max_len, rx_len, 0); -} - -/** - Use an existing connection to perform a transaction. - - This is only possible if the next packet is on the same port and destination! - Differ from 'csp_transaction_persistent()' by limiting input buffer size when input length is unknown - - @param[in] conn pointer to connection structure - @param[in] timeout timeout in ms - @param[in] tx_buf pointer to outgoing data buffer - @param[in] tx_len length of request to send - @param[out] rx_buf pointer to incoming data buffer - @param[in] rx_max_len length of expected reply (input buffer size) - @param[out] rx_len pointer to length of reply - @return GS_ERROR_OVERFLOW when input length larger than buffer - it still updates rx_buf - @return GS_ERROR_IO when 'csp_send()' or 'csp_read()' fails - @return GS_ERROR_ALLOC when 'csp_get_buffer()' fails - @return_gs_error_t - */ -gs_error_t gs_csp_transaction_persistent(csp_conn_t * conn, - uint32_t timeout, - const void * tx_buf, - size_t tx_len, - void * rx_buf, - size_t rx_max_len, - size_t * rx_len); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/drivers/can/can.h b/gomspace/libgscsp/include/gs/csp/drivers/can/can.h deleted file mode 100644 index 0d10c4fc..00000000 --- a/gomspace/libgscsp/include/gs/csp/drivers/can/can.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_CAN_CAN_H -#define LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_CAN_CAN_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - GomSpace CAN API for CSP. -*/ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Default CAN interface name. -*/ -#define GS_CSP_CAN_DEFAULT_IF_NAME "CAN" - -/** - Initialize CSP for CAN device. - - @param[in] device CAN device - @param[in] csp_addr CSP address. - @param[in] mtu MTU, normally CSP_CAN_MTU. - @param[in] name name of CSP interface, if NULL #GS_CSP_CAN_DEFAULT_IF_NAME will be used. - @param[in] set_default_route if \a true, the device will be set as default route. - @param[out] csp_if the added CSP interface. - @return #GS_ERROR_EXIST if device already exists. - @return_gs_error_t -*/ -gs_error_t gs_csp_can_init2(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, bool set_default_route, csp_iface_t ** csp_if); - -/** - Initialize CSP for CAN device. - - @param[in] device CAN device - @param[in] csp_addr CSP address. - @param[in] mtu MTU, normally CSP_CAN_MTU. - @param[in] name name of CSP interface, if NULL #GS_CSP_CAN_DEFAULT_IF_NAME will be used. - @param[out] csp_if the added CSP interface. - @return #GS_ERROR_EXIST if device already exists. - @return_gs_error_t - @see gs_csp_can_init2() -*/ -gs_error_t gs_csp_can_init(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, csp_iface_t ** csp_if); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h b/gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h deleted file mode 100644 index 4b6204f1..00000000 --- a/gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_I2C_I2C_H -#define LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_I2C_I2C_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - GomSpace I2C API for CSP. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Initialize CSP for I2C device. - @note I2C device must be initialized allready with the same I2C address as the CSP address. - - @param[in] device I2C device. - @param[in] csp_addr CSP address. - @return_gs_error_t -*/ -gs_error_t gs_csp_i2c_init(uint8_t device, uint8_t csp_addr); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h b/gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h deleted file mode 100644 index cb098fce..00000000 --- a/gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_KISS_KISS_H -#define LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_KISS_KISS_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -/** - @file - - GomSpace KISS API for CSP. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Initialize CSP for KISS device. - @note KISS/UART device must be initialized all ready. - - @param[in] device KISS/UART device. - @return_gs_error_t -*/ -gs_error_t gs_csp_kiss_init(uint8_t device); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/error.h b/gomspace/libgscsp/include/gs/csp/error.h deleted file mode 100644 index 8de40787..00000000 --- a/gomspace/libgscsp/include/gs/csp/error.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_ERROR_H -#define LIBGSCSP_INCLUDE_GS_CSP_ERROR_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Converting CSP error codes to #gs_error_t -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Convert CSP error. - - @param[in] csp_error CSP error - @return GS error code representing the CSP error. -*/ -gs_error_t gs_csp_error(int csp_error); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/linux/command_line.h b/gomspace/libgscsp/include/gs/csp/linux/command_line.h deleted file mode 100644 index e416eda5..00000000 --- a/gomspace/libgscsp/include/gs/csp/linux/command_line.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef GS_CSP_LINUX_COMMAND_LINE_H -#define GS_CSP_LINUX_COMMAND_LINE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Command line support. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Command line options. -*/ -extern const struct argp_child gs_csp_command_line_options; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/log.h b/gomspace/libgscsp/include/gs/csp/log.h deleted file mode 100644 index 91360cc0..00000000 --- a/gomspace/libgscsp/include/gs/csp/log.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_LOG_H -#define LIBGSCSP_INCLUDE_GS_CSP_LOG_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - CSP log hook. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Hook into CSP log system. - All CSP logs will be logged through Log (libutil). - - @return_gs_error_t -*/ -gs_error_t gs_csp_log_init(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/port.h b/gomspace/libgscsp/include/gs/csp/port.h deleted file mode 100644 index 29fa32e4..00000000 --- a/gomspace/libgscsp/include/gs/csp/port.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_PORT_H -#define LIBGSCSP_INCLUDE_GS_CSP_PORT_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Port definitions for standard CSP and GomSpace services. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Port definitions for standard CSP and GomSpace services. -*/ -typedef enum { - /** - CSP Management Protocol - standard CSP service. - */ - GS_CSP_CMP = CSP_CMP, // 0 - /** - Ping - standard CSP service. - */ - GS_CSP_PING = CSP_PING, // 1 - /** - Show process status - standard CSP service. - */ - GS_CSP_PS = CSP_PS, // 2 - /** - Show memory free - standard CSP service. - */ - GS_CSP_MEM_FREE = CSP_MEMFREE, // 3 - GS_CSP_MEMFREE = GS_CSP_MEM_FREE, - /** - Reboot/reset request - standard CSP service. - */ - GS_CSP_REBOOT = CSP_REBOOT, // 4 - /** - Show number of free CSP buffers - standard CSP service. - */ - GS_CSP_BUF_FREE = CSP_BUF_FREE, // 5 - /** - Show uptime (time since last reset) - standard CSP service. - */ - GS_CSP_UPTIME = CSP_UPTIME, // 6 - /** - Parameter service (libparam) - */ - GS_CSP_PORT_RPARAM = 7, - /** - File Transfer Service (libftp) - */ - GS_CSP_PORT_FTP = 9, - /** - Remote log service (liblog) - */ - GS_CSP_PORT_RLOG = 11, - /** - Remote GOSH service (librgosh) - */ - GS_CSP_PORT_RGOSH = 12, - /** - AIS command port (libais). - */ - GS_CSP_PORT_AIS = 13, - /** - ADS-B command port (libadsb). - */ - GS_CSP_PORT_ADSB = 14, - - /** - GomSpace Sensor Bus (libgssb). - */ - GS_CSP_PORT_GSSB = 16, - /** - Flight Planner (libfp). - */ - GS_CSP_PORT_FP = 18, - /** - ADCS (libadcs). - */ - GS_CSP_PORT_ADCS = 20, - /** - House Keeping (libhk). - */ - GS_CSP_PORT_HK = 21, - /** - G(omSpace) script service (libgosh) - */ - GS_CSP_PORT_GSCRIPT = 22, - /** - Remote shell (libgosh). - Executes shell commands (linux server only). - Requires CSP_O_RDP. - */ - GS_CSP_PORT_REMOTE_SHELL = 27, - /** - House keeping beacon port (libhk). - Default port for sending beacons from satellite to ground (configurable). - */ - GS_CSP_PORT_HK_BEACON = 30, - -} gs_csp_port_t; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/router.h b/gomspace/libgscsp/include/gs/csp/router.h deleted file mode 100644 index dae8990a..00000000 --- a/gomspace/libgscsp/include/gs/csp/router.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_ROUTER_H -#define LIBGSCSP_INCLUDE_GS_CSP_ROUTER_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - CSP router task, with support for stopping/terminating router task. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Start CSP router (task/thread). - @param[in] stack_size stack size in bytes, minimum 300 bytes. - @param[in] priority task priority, normally GS_THREAD_PRIORITY_HIGH. - @return_gs_error_t -*/ -gs_error_t gs_csp_router_task_start(size_t stack_size, gs_thread_priority_t priority); - -/** - Stop CSP router task (for testing). - - Signal stop to the router and waits for it to terminate (join). - @note Join is performed, which may hang forever if the router doesn't respond to the stop request. - @return_gs_error_t -*/ -gs_error_t gs_csp_router_task_stop(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/rtable.h b/gomspace/libgscsp/include/gs/csp/rtable.h deleted file mode 100644 index 511b7bc2..00000000 --- a/gomspace/libgscsp/include/gs/csp/rtable.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef GS_CSP_RTABLE_H -#define GS_CSP_RTABLE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - CSP routing table support. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Load routing table. - Extension to csp_rtable_load(). - - @param[in] rtable string containing the routing table to set/load. - @param[in] set_default_route if \a true, sets a default route if no routing table specified and only one interface configured. - @param[in] use_command_line_option if \a true (and command line supported), use command line options to configure routing. - @return_gs_error_t -*/ -gs_error_t gs_csp_rtable_load(const char * rtable, bool set_default_route, bool use_command_line_option); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/service_dispatcher.h b/gomspace/libgscsp/include/gs/csp/service_dispatcher.h deleted file mode 100644 index e80ef66d..00000000 --- a/gomspace/libgscsp/include/gs/csp/service_dispatcher.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_SERVICE_DISPATCHER_H -#define LIBGSCSP_INCLUDE_GS_CSP_SERVICE_DISPATCHER_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - CSP Service Dispatcher. - - The dispatcher is a task/thread, listening on a configured number of ports and forwards the the incoming connection - to a configured CSP service handler. - The dispatcher touches a software watchdog for every handled connection. -*/ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - CSP service dispatcher configuration. -*/ -typedef struct { - /** - Name of dispatcher. - */ - const char * name; - /** - Array of service handlers - index'ed by CSP port number. - */ - const gs_csp_service_handler_t * handler_array; - /** - Array size of \a handler_array. - */ - unsigned int handler_array_size; - /** - Bind to any unbound ports (CSP_ANY). - Only one task/dispatcher can bind to any ports. This can be used to log unexpected incoming connections. - */ - bool bind_any; - /** - Disable watchdog. - The watchdog is created with a fixed timeout of 20 seconds. - */ - bool disable_watchdog; - /** - CSP connection backlog. - If 0 (zero), the backlog is set to 10. - */ - size_t listen_backlog; - /** - Callback after timeout or processsed connection. - The return value is the next timeout in milli seconds. - Return UINT32_MAX to use default timeout. - */ - unsigned int (*callback)(void); - /** - Socket options. - */ - uint32_t socket_options; -} gs_csp_service_dispatcher_conf_t; - -/** - Basic CSP service handlers. - - Can be used to configure handlers for all basic CSP services. -*/ -#define GS_CSP_BASIC_SERVICE_HANDLERS \ - [GS_CSP_CMP] = gs_csp_cmp_service_handler, \ - [GS_CSP_PING] = gs_csp_ping_service_handler, \ - [GS_CSP_PS] = gs_csp_ps_service_handler, \ - [GS_CSP_MEMFREE] = gs_csp_mem_free_service_handler, \ - [GS_CSP_REBOOT] = gs_csp_reboot_service_handler, \ - [GS_CSP_BUF_FREE] = gs_csp_buf_free_service_handler, \ - [GS_CSP_UPTIME] = gs_csp_uptime_service_handler - -/** - Service dispatcher handle. - @see gs_csp_service_dispatcher_create(), gs_csp_service_dispatcher_close() -*/ -typedef struct gs_csp_service_dispatcher * gs_csp_service_dispatcher_t; - -/** - Create service dispatcher (task/thread). - - @param[in] conf configuration - must remain valid as long as the dispatcher is running. - @param[in] stack_size thread stack size. - @param[in] priority thread priority. - @param[out] return_handle created dispatcher - use NULL if not used. - @return_gs_error_t -*/ -gs_error_t gs_csp_service_dispatcher_create(const gs_csp_service_dispatcher_conf_t * conf, - size_t stack_size, - gs_thread_priority_t priority, - gs_csp_service_dispatcher_t * return_handle); - -/** - Wake up service dispatcher. - - This will cause the disapther to wake up (from listing for new connections), and invoke the configured \a callback function, - before listing for new connections. - - @param[in] handle dispatcher. - @return_gs_error_t -*/ -gs_error_t gs_csp_service_dispatcher_wake_up(gs_csp_service_dispatcher_t handle); - -/** - Destroy/close service dispatcher (for testing). - - Signal stop to the dispatcher and waits for it to terminate (join). - - @note Join is performed, which may hang forever if the dispatcher doesn't respond to the stop request. - @param[in] handle dispatcher. - @return_gs_error_t -*/ -gs_error_t gs_csp_service_dispatcher_destroy(gs_csp_service_dispatcher_t handle); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/service_handler.h b/gomspace/libgscsp/include/gs/csp/service_handler.h deleted file mode 100644 index 52479129..00000000 --- a/gomspace/libgscsp/include/gs/csp/service_handler.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_SERVICE_HANDLER_H -#define LIBGSCSP_INCLUDE_GS_CSP_SERVICE_HANDLER_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - CSP Service handler. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - CSP Service handler. - - It is the handler's responsibility to process all pakcets on the connection and close the connection when done - even if a failure - is returned. - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -typedef gs_error_t (*gs_csp_service_handler_t)(csp_conn_t * conn); - -/** - Service handler for CSP Management Protocol. - - Invokes standard libcsp service handler. - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -gs_error_t gs_csp_cmp_service_handler(csp_conn_t * conn); - -/** - Service handler for ping. - - Invokes standard libcsp service handler. - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -gs_error_t gs_csp_ping_service_handler(csp_conn_t * conn); - -/** - Service handler for getting process list. - - Invokes standard libcsp service handler. - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -gs_error_t gs_csp_ps_service_handler(csp_conn_t * conn); - -/** - Service handler for getting memory free. - - Invokes GomSpace handler, which doesn't use malloc() to determine \a free memory. - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -gs_error_t gs_csp_mem_free_service_handler(csp_conn_t * conn); - - -/** - Service handler for reboot (reset) of node. - - Invokes standard libcsp service handler. - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -gs_error_t gs_csp_reboot_service_handler(csp_conn_t * conn); - -/** - Service handler for getting free CSP buffers. - - Invokes standard libcsp service handler. - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -gs_error_t gs_csp_buf_free_service_handler(csp_conn_t * conn); - -/** - Service handler for getting uptime (in seconds). - - Invokes GomSpace handler (works on Linux). - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -gs_error_t gs_csp_uptime_service_handler(csp_conn_t * conn); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c deleted file mode 100644 index 5292663b..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c +++ /dev/null @@ -1,165 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include - -/* CSP includes */ -#include -#include -#include -#include -#include -#include - -/* ZMQ */ -#include - -static void * context; -static void * publisher; -static void * subscriber; -static csp_bin_sem_handle_t tx_wait; - -/** - * Interface transmit function - * @param packet Packet to transmit - * @param timeout Timeout in ms - * @return 1 if packet was successfully transmitted, 0 on error - */ -int csp_zmqhub_tx(csp_iface_t * interface, csp_packet_t * packet, uint32_t timeout) { - - /* Send envelope */ - uint8_t dest = csp_rtable_find_mac(packet->id.dst); - if (dest == CSP_NODE_MAC) - dest = packet->id.dst; - - uint16_t length = packet->length; - uint8_t * destptr = ((uint8_t *) &packet->id) - sizeof(dest); - memcpy(destptr, &dest, sizeof(dest)); - csp_bin_sem_wait(&tx_wait, CSP_INFINITY); /* Using ZMQ in thread safe manner*/ - int result = zmq_send(publisher, destptr, length + sizeof(packet->id) + sizeof(dest), 0); - csp_bin_sem_post(&tx_wait); /* Release tx semaphore */ - if (result < 0) - csp_log_error("ZMQ send error: %u %s\r\n", result, strerror(result)); - - csp_buffer_free(packet); - - return CSP_ERR_NONE; - -} - -CSP_DEFINE_TASK(csp_zmqhub_task) { - - while(1) { - zmq_msg_t msg; - assert(zmq_msg_init_size(&msg, 1024) == 0); - - /* Receive data */ - if (zmq_msg_recv(&msg, subscriber, 0) < 0) { - zmq_msg_close(&msg); - csp_log_error("ZMQ: %s", zmq_strerror(zmq_errno())); - continue; - } - - int datalen = zmq_msg_size(&msg); - if (datalen < 5) { - csp_log_warn("ZMQ: Too short datalen: %u", datalen); - while(zmq_msg_recv(&msg, subscriber, ZMQ_NOBLOCK) > 0) - zmq_msg_close(&msg); - continue; - } - - /* Create new csp packet */ - csp_packet_t * packet = csp_buffer_get(256); - if (packet == NULL) { - zmq_msg_close(&msg); - continue; - } - - /* Copy the data from zmq to csp */ - uint8_t * destptr = ((uint8_t *) &packet->id) - sizeof(*destptr); - memcpy(destptr, zmq_msg_data(&msg), datalen); - packet->length = datalen - sizeof(packet->id) - sizeof(*destptr); - - /* Queue up packet to router */ - csp_qfifo_write(packet, &csp_if_zmqhub, NULL); - - zmq_msg_close(&msg); - } - - return CSP_TASK_RETURN; - -} - -int csp_zmqhub_init(uint8_t addr, const char * host) { - char url_pub[100]; - char url_sub[100]; - - sprintf(url_pub, "tcp://%s:6000", host); - sprintf(url_sub, "tcp://%s:7000", host); - - return csp_zmqhub_init_w_endpoints(addr, url_pub, url_sub); -} - -int csp_zmqhub_init_w_endpoints(uint8_t addr, const char * publisher_endpoint, - const char * subscriber_endpoint) { - - context = zmq_ctx_new(); - assert(context); - - csp_log_info("INIT ZMQ with addr %u to servers %s / %s\r\n", - addr, publisher_endpoint, subscriber_endpoint); - - /* Publisher (TX) */ - publisher = zmq_socket(context, ZMQ_PUB); - assert(publisher); - assert(zmq_connect(publisher, publisher_endpoint) == 0); - - /* Subscriber (RX) */ - subscriber = zmq_socket(context, ZMQ_SUB); - assert(subscriber); - assert(zmq_connect(subscriber, subscriber_endpoint) == 0); - - if (addr == CSP_NODE_MAC) { // == 255 - assert(zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, NULL, 0) == 0); - } else { - assert(zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, &addr, 1) == 0); - } - /* ZMQ isn't thread safe, so we add a binary semaphore to wait on for tx */ - if (csp_bin_sem_create(&tx_wait) != CSP_SEMAPHORE_OK) { - csp_log_error("Failed to initialize semaphore in csp_zmqhub_init_w_endpoints"); - return CSP_ERR_NOMEM; - } - /* Start RX thread */ - static csp_thread_handle_t handle_subscriber; - int ret = csp_thread_create(csp_zmqhub_task, "ZMQ", 20000, NULL, 0, &handle_subscriber); - csp_log_info("Task start %d\r\n", ret); - - /* Register interface */ - csp_iflist_add(&csp_if_zmqhub); - - return CSP_ERR_NONE; - -} - -/* Interface definition */ -csp_iface_t csp_if_zmqhub = { - .name = "ZMQHUB", - .nexthop = csp_zmqhub_tx, -}; diff --git a/gomspace/libgscsp/src/bindings/python/pygscsp.c b/gomspace/libgscsp/src/bindings/python/pygscsp.c deleted file mode 100644 index c69d346b..00000000 --- a/gomspace/libgscsp/src/bindings/python/pygscsp.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -#include - -#include - -#if PY_MAJOR_VERSION == 3 -#define IS_PY3 -#endif - -/* gs_error_t gs_csp_i2c_init(uint8_t device, uint8_t csp_addr); */ -static PyObject* pygscsp_csp_i2c_init(PyObject *self, PyObject *args) { - uint8_t device; - uint8_t csp_addr; - - if (!PyArg_ParseTuple(args, "BB", &device, &csp_addr)) { - Py_RETURN_NONE; - } - - return Py_BuildValue("i", gs_csp_i2c_init(device, csp_addr)); -} - - -static PyMethodDef methods[] = { - - {"i2c_init", pygscsp_csp_i2c_init, METH_VARARGS, ""}, - - /* sentinel */ - {NULL, NULL, 0, NULL} -}; - -#ifdef IS_PY3 -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "libgscsp_py3", - NULL, - -1, - methods, - NULL, - NULL, - NULL, - NULL -}; -#endif - -#ifdef IS_PY3 -PyMODINIT_FUNC PyInit_libgscsp_py3(void) { -#else -PyMODINIT_FUNC initlibgscsp_py2(void) { -#endif - -#ifdef IS_PY3 - PyObject* m = PyModule_Create(&moduledef); -#else - Py_InitModule("libgscsp_py2", methods); -#endif - -#ifdef IS_PY3 - return m; -#endif - } - diff --git a/gomspace/libgscsp/src/clock.c b/gomspace/libgscsp/src/clock.c deleted file mode 100644 index 9e9a7d53..00000000 --- a/gomspace/libgscsp/src/clock.c +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Required by libcsp. - Proto-typed in ./libcsp/include/csp/arch/csp_clock.h, but with different argumet! - - __attribute__((weak)) extern void clock_get_time(csp_timestamp_t * time); - __attribute__((weak)) extern void clock_set_time(csp_timestamp_t * time); -*/ - -#include -#include - -void clock_get_time(csp_timestamp_t * time) -{ - gs_clock_get_time((gs_timestamp_t*)time); -} - -void clock_set_time(csp_timestamp_t * time) -{ - gs_clock_set_time((gs_timestamp_t*)time); -} diff --git a/gomspace/libgscsp/src/commands.c b/gomspace/libgscsp/src/commands.c deleted file mode 100644 index 6abd3019..00000000 --- a/gomspace/libgscsp/src/commands.c +++ /dev/null @@ -1,652 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static gs_error_t parse_node_timeout(gs_command_context_t *ctx, int node_index, uint8_t * node, int timeout_index, uint32_t * timeout) -{ - gs_error_t error = GS_OK; - if (node) { - *node = csp_get_address(); - - if (ctx->argc > node_index) { - error = gs_string_to_uint8(ctx->argv[node_index], node); - } - } - - if (timeout && (error == GS_OK)) { - *timeout = 1000; - - if (ctx->argc > timeout_index) { - error = gs_string_to_uint32(ctx->argv[timeout_index], timeout); - } - } - - return error; -} - -static int cmd_ping(gs_command_context_t *ctx) -{ - uint8_t node; - uint32_t timeout; - int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); - if (res) { - return res; - } - - uint32_t size = 1; - if ((ctx->argc > 3) && (gs_string_to_uint32(ctx->argv[3], &size) != GS_OK)) { - return GS_ERROR_ARG; - } - - uint32_t options = CSP_O_NONE; - if (ctx->argc > 4) { - const char * features = ctx->argv[4]; - if (strchr(features, 'r')) - options |= CSP_O_RDP; - if (strchr(features, 'x')) - options |= CSP_O_XTEA; - if (strchr(features, 'h')) - options |= CSP_O_HMAC; - if (strchr(features, 'c')) - options |= CSP_O_CRC32; - } - - printf("Ping node %u, timeout %" PRIu32 ", size %" PRIu32 ": options: 0x%" PRIx32 " ... ", node, timeout, size, options); - - const uint64_t start = gs_clock_get_nsec(); - const int time = csp_ping(node, timeout, size, options); - const uint64_t stop = gs_clock_get_nsec(); - const float elapsed = (((float)(stop - start)) / 1E6); - if (time < 0) { - printf("timeout after %.03f ms\r\n", elapsed); - return GS_ERROR_TIMEOUT; - } - - printf("reply in %.03f ms\r\n", elapsed); - - return GS_OK; -} - -static int cmd_ps(gs_command_context_t *ctx) -{ - uint8_t node; - uint32_t timeout; - int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); - if (res) { - return res; - } - - csp_ps(node, timeout); - - return GS_OK; -} - -static int cmd_memfree(gs_command_context_t *ctx) -{ - uint8_t node; - uint32_t timeout; - int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); - if (res) { - return res; - } - - csp_memfree(node, timeout); - - return GS_OK; -} - -static int cmd_reboot(gs_command_context_t *ctx) -{ - if (ctx->argc < 2) { - return GS_ERROR_ARG; - } - uint8_t node; - int res = parse_node_timeout(ctx, 1, &node, 0, NULL); - if (res) { - return res; - } - - csp_reboot(node); - - return GS_OK; -} - -static int cmd_shutdown(gs_command_context_t *ctx) -{ - if (ctx->argc < 2) { - return GS_ERROR_ARG; - } - uint8_t node; - int res = parse_node_timeout(ctx, 1, &node, 0, NULL); - if (res) { - return res; - } - - csp_shutdown(node); - - return GS_OK; -} - -static int cmd_buf_free(gs_command_context_t *ctx) -{ - uint8_t node; - uint32_t timeout; - int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); - if (res) { - return res; - } - - csp_buf_free(node, timeout); - - return GS_OK; -} - -static int cmd_uptime(gs_command_context_t *ctx) -{ - uint8_t node; - uint32_t timeout; - int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); - if (res) { - return res; - } - - csp_uptime(node, timeout); - - return GS_OK; -} - -#ifdef CSP_DEBUG - -static int cmd_csp_route_print_table(gs_command_context_t *ctx) -{ - csp_route_print_table(); - return GS_OK; -} - -static int cmd_csp_route_print_interfaces(gs_command_context_t *ctx) -{ - csp_route_print_interfaces(); - return GS_OK; -} - -static int cmd_csp_conn_print_table(gs_command_context_t *ctx) -{ - csp_conn_print_table(); - return GS_OK; -} - -#endif - -#if CSP_USE_RDP -static int cmd_csp_rdp_set_opt(gs_command_context_t *ctx) -{ - if (ctx->argc < 7) { - return GS_ERROR_ARG; - } - int res; - uint32_t window_size; - if ((res = gs_string_to_uint32(ctx->argv[1], &window_size))) { - return res; - } - uint32_t conn_timeout; - if ((res = gs_string_to_uint32(ctx->argv[2], &conn_timeout))) { - return res; - } - uint32_t packet_timeout; - if ((res = gs_string_to_uint32(ctx->argv[3], &packet_timeout))) { - return res; - } - uint32_t delayed_acks; - if ((res = gs_string_to_uint32(ctx->argv[4], &delayed_acks))) { - return res; - } - uint32_t ack_timeout; - if ((res = gs_string_to_uint32(ctx->argv[5], &ack_timeout))) { - return res; - } - uint32_t ack_delay_count; - if ((res = gs_string_to_uint32(ctx->argv[6], &ack_delay_count))) { - return res; - } - - printf("Setting arguments to: window size %" PRIu32 ", conn timeout %" PRIu32 ", packet timeout %" PRIu32 ", delayed acks %" PRIu32 ", ack timeout %" PRIu32 ", ack delay count %" PRIu32 "\r\n", - window_size, conn_timeout, packet_timeout, delayed_acks, ack_timeout, ack_delay_count); - - csp_rdp_set_opt(window_size, conn_timeout, packet_timeout, delayed_acks, ack_timeout, ack_delay_count); - - return GS_OK; -} -#endif - -static int cmd_cmp_ident(gs_command_context_t *ctx) -{ - uint8_t node; - uint32_t timeout; - int ret = parse_node_timeout(ctx, 1, &node, 2, &timeout); - if (ret) { - return ret; - } - - struct csp_cmp_message msg; - - ret = csp_cmp_ident(node, timeout, &msg); - if (ret != CSP_ERR_NONE) { - printf("CSP error: %d\r\n", ret); - return gs_csp_error(ret);; - } - - printf("Hostname: %s\r\n", msg.ident.hostname); - printf("Model: %s\r\n", msg.ident.model); - printf("Revision: %s\r\n", msg.ident.revision); - printf("Date: %s\r\n", msg.ident.date); - printf("Time: %s\r\n", msg.ident.time); - - return GS_OK; -} - -static int cmd_cmp_route_set(gs_command_context_t *ctx) -{ - if (ctx->argc != 6) - return GS_ERROR_ARG; - - uint8_t node = atoi(ctx->argv[1]); - uint32_t timeout = atoi(ctx->argv[2]); - printf("Sending route_set to node %"PRIu8" timeout %"PRIu32"\r\n", node, timeout); - - struct csp_cmp_message msg; - msg.route_set.dest_node = atoi(ctx->argv[3]); - msg.route_set.next_hop_mac = atoi(ctx->argv[4]); - strncpy(msg.route_set.interface, ctx->argv[5], 10); - printf("Dest_node: %u, next_hop_mac: %u, interface %s\r\n", msg.route_set.dest_node, msg.route_set.next_hop_mac, msg.route_set.interface); - - int ret = csp_cmp_route_set(node, timeout, &msg); - if (ret != CSP_ERR_NONE) { - printf("CSP error: %d\r\n", ret); - return gs_csp_error(ret); - } - - return GS_OK; -} - -static int cmd_cmp_ifc(gs_command_context_t *ctx) { - - uint8_t node; - uint32_t timeout; - char * interface; - - if (ctx->argc > 4 || ctx->argc < 3) - return GS_ERROR_ARG; - - node = atoi(ctx->argv[1]); - interface = ctx->argv[2]; - - if (ctx->argc < 4) - timeout = 1000; - else - timeout = atoi(ctx->argv[3]); - - struct csp_cmp_message msg; - strncpy(msg.if_stats.interface, interface, CSP_CMP_ROUTE_IFACE_LEN); - - printf("Requesting interface stats for interface %s\r\n", interface); - - int ret = csp_cmp_if_stats(node, timeout, &msg); - if (ret != CSP_ERR_NONE) { - printf("CSP error: %d\r\n", ret); - return gs_csp_error(ret); - } - - msg.if_stats.tx = csp_ntoh32(msg.if_stats.tx); - msg.if_stats.rx = csp_ntoh32(msg.if_stats.rx); - msg.if_stats.tx_error = csp_ntoh32(msg.if_stats.tx_error); - msg.if_stats.rx_error = csp_ntoh32(msg.if_stats.rx_error); - msg.if_stats.drop = csp_ntoh32(msg.if_stats.drop); - msg.if_stats.autherr = csp_ntoh32(msg.if_stats.autherr); - msg.if_stats.frame = csp_ntoh32(msg.if_stats.frame); - msg.if_stats.txbytes = csp_ntoh32(msg.if_stats.txbytes); - msg.if_stats.rxbytes = csp_ntoh32(msg.if_stats.rxbytes); - msg.if_stats.irq = csp_ntoh32(msg.if_stats.irq); - - printf("%-5s tx: %05"PRIu32" rx: %05"PRIu32" txe: %05"PRIu32" rxe: %05"PRIu32"\r\n" - " drop: %05"PRIu32" autherr: %05"PRIu32 " frame: %05"PRIu32"\r\n" - " txb: %"PRIu32" rxb: %"PRIu32"\r\n\r\n", - msg.if_stats.interface, msg.if_stats.tx, msg.if_stats.rx, msg.if_stats.tx_error, msg.if_stats.rx_error, msg.if_stats.drop, - msg.if_stats.autherr, msg.if_stats.frame, msg.if_stats.txbytes, msg.if_stats.rxbytes); - - return GS_OK; -} - -static int cmd_cmp_peek(gs_command_context_t *ctx) -{ - if ((ctx->argc != 4) && (ctx->argc != 5)) - return GS_ERROR_ARG; - - uint8_t node; - uint32_t timeout; - int res = parse_node_timeout(ctx, 1, &node, 4, &timeout); - if (res) { - return res; - } - - uint32_t addr; - if (gs_string_to_uint32(ctx->argv[2], &addr)) { - return GS_ERROR_ARG; - } - - uint32_t len; - if (gs_string_to_uint32(ctx->argv[3], &len)) { - return GS_ERROR_ARG; - } - if (len > CSP_CMP_PEEK_MAX_LEN) { - return GS_ERROR_RANGE; - } - - printf("Dumping mem from node %u addr 0x%"PRIx32" len %"PRIx32" timeout %"PRIu32"\r\n", node, addr, len, timeout); - - struct csp_cmp_message msg; - msg.peek.addr = csp_hton32(addr); - msg.peek.len = len; - - int ret = csp_cmp_peek(node, timeout, &msg); - if (ret != CSP_ERR_NONE) { - printf("CSP error: %d\r\n", ret); - return gs_csp_error(ret); - } - - gs_hexdump_addr(msg.peek.data, len, GS_TYPES_UINT2PTR(addr)); - - return GS_OK; -} - -static int cmd_cmp_poke(gs_command_context_t *ctx) -{ - if ((ctx->argc != 4) && (ctx->argc != 5)) - return GS_ERROR_ARG; - - uint8_t node; - uint32_t timeout; - int res = parse_node_timeout(ctx, 1, &node, 4, &timeout); - if (res) { - return res; - } - - uint32_t addr; - if (gs_string_to_uint32(ctx->argv[2], &addr)) { - return GS_ERROR_ARG; - } - - unsigned char data[CSP_CMP_POKE_MAX_LEN]; - uint32_t len = base16_decode(ctx->argv[3], data); - if (len > CSP_CMP_PEEK_MAX_LEN) { - printf("Max length is: %u\r\n", CSP_CMP_PEEK_MAX_LEN); - return GS_ERROR_RANGE; - } - - printf("Writing to mem at node %u addr 0x%"PRIx32" len %"PRIx32" timeout %"PRIu32"\r\n", node, addr, len, timeout); - gs_hexdump_addr(data, len, GS_TYPES_UINT2PTR(addr)); - - struct csp_cmp_message msg; - msg.poke.addr = csp_hton32(addr); - msg.poke.len = len; - memcpy(msg.poke.data, data, CSP_CMP_POKE_MAX_LEN); - - int ret = csp_cmp_poke(node, timeout, &msg); - if (ret != CSP_ERR_NONE) { - printf("CSP error: %d\r\n", ret); - return gs_csp_error(ret); - } - - return GS_OK; -} - -static int cmd_cmp_clock(gs_command_context_t *ctx, uint32_t node, uint32_t timeout, const gs_timestamp_t * set) -{ - char tbuf[GS_CLOCK_ISO8601_BUFFER_LENGTH]; - struct csp_cmp_message msg; - memset(&msg, 0, sizeof(msg)); - - if (set) { - gs_clock_to_iso8601_string(set, tbuf, sizeof(tbuf)); - printf("Set time: %s (%" PRIu32 ".%09" PRIu32 " sec)\r\n", tbuf, set->tv_sec, set->tv_nsec); - msg.clock.tv_sec = csp_hton32(set->tv_sec); - msg.clock.tv_nsec = csp_hton32(set->tv_nsec); - } - - gs_timestamp_t t1, t2; - gs_clock_get_time(&t1); - int ret = csp_cmp_clock(node, timeout, &msg); - if (ret != CSP_ERR_NONE) { - return gs_csp_error(ret); - } - gs_clock_get_time(&t2); - - /* Calculate round-trip time */ - const int64_t rtt = ((uint64_t)t2.tv_sec * 1000000000 + t2.tv_nsec) - ((uint64_t)t1.tv_sec * 1000000000 + t1.tv_nsec); - - gs_timestamp_t timestamp; - timestamp.tv_sec = csp_ntoh32(msg.clock.tv_sec); - timestamp.tv_nsec = csp_ntoh32(msg.clock.tv_nsec); - - gs_clock_to_iso8601_string(×tamp, tbuf, sizeof(tbuf)); - printf("Get time: %s (%" PRIu32 ".%09" PRIu32 " sec)\r\n", tbuf, timestamp.tv_sec, timestamp.tv_nsec); - - /* Calculate time difference to local clock. This takes the round-trip - * into account, but assumes a symmetrical link */ - const int64_t remote = (uint64_t)timestamp.tv_sec * 1000000000 + timestamp.tv_nsec; - const int64_t local = (uint64_t)t1.tv_sec * 1000000000 + t1.tv_nsec + rtt / 2; - - const double diff = (remote - local) / 1000000.0; - printf("Remote is %f ms %s local time\r\n", fabs(diff), diff > 0 ? "ahead of" : "behind"); - - return GS_OK; -} - -static int cmd_cmp_clock_get(gs_command_context_t *ctx) -{ - if (ctx->argc < 2) { - return GS_ERROR_ARG; - } - - uint32_t node; - if (gs_string_to_uint32(ctx->argv[1], &node) != GS_OK) { - return GS_ERROR_ARG; - } - - uint32_t timeout = 1000; - if (ctx->argc > 2) { - if (gs_string_to_uint32(ctx->argv[2], &timeout) != GS_OK) { - return GS_ERROR_ARG; - } - } - - return cmd_cmp_clock(ctx, node, timeout, NULL); -} - -static int cmd_cmp_clock_set(gs_command_context_t *ctx) -{ - if (ctx->argc < 3) { - return GS_ERROR_ARG; - } - - uint32_t node; - if (gs_string_to_uint32(ctx->argv[1], &node) != GS_OK) { - return GS_ERROR_ARG; - } - - gs_timestamp_t ts; - if (gs_clock_from_string(ctx->argv[2], &ts) != GS_OK) { - return GS_ERROR_ARG; - } - - uint32_t timeout = 1000; - if (ctx->argc > 3) { - if (gs_string_to_uint32(ctx->argv[3], &timeout) != GS_OK) { - return GS_ERROR_ARG; - } - } - - return cmd_cmp_clock(ctx, node, timeout, &ts); -} - -static int cmd_cmp_clock_sync(gs_command_context_t *ctx) -{ - if (ctx->argc < 2) { - return GS_ERROR_ARG; - } - - uint32_t node; - if (gs_string_to_uint32(ctx->argv[1], &node) != GS_OK) { - return GS_ERROR_ARG; - } - - uint32_t timeout = 1000; - if (ctx->argc > 2) { - if (gs_string_to_uint32(ctx->argv[2], &timeout) != GS_OK) { - return GS_ERROR_ARG; - } - } - - gs_timestamp_t ts; - gs_clock_get_time(&ts); - - return cmd_cmp_clock(ctx, node, timeout, &ts); -} - -static const gs_command_t GS_COMMAND_SUB cmp_clock_commands[] = { - { - .name = "get", - .help = "Get clock on ", - .usage = " [timeout]", - .handler = cmd_cmp_clock_get, - }, - { - .name = "set", - .help = "Set time of ", - .usage = " [timeout]", - .handler = cmd_cmp_clock_set, - }, - { - .name = "sync", - .help = "Sync/set time of to time of this node", - .usage = " [timeout]", - .handler = cmd_cmp_clock_sync, - } -}; - -static const gs_command_t GS_COMMAND_SUB cmp_commands[] = { - { - .name = "ident", - .help = "Node id", - .usage = "[node] [timeout]", - .handler = cmd_cmp_ident, - },{ - .name = "route_set", - .help = "Update table", - .usage = " ", - .handler = cmd_cmp_route_set, - },{ - .name = "ifc", - .help = "Remote IFC", - .usage = " [timeout]", - .handler = cmd_cmp_ifc, - },{ - .name = "peek", - .help = "Show remote memory", - .usage = " [timeout]", - .handler = cmd_cmp_peek, - },{ - .name = "poke", - .help = "Modify remote memory", - .usage = " [timeout]", - .handler = cmd_cmp_poke, - },{ - .name = "clock", - .help = "Get/set clock", - .chain = GS_COMMAND_INIT_CHAIN(cmp_clock_commands), - } -}; - -static const gs_command_t GS_COMMAND_ROOT csp_commands[] = { - { - .name = "ping", - .help = "csp: Ping", - .usage = "[node] [timeout] [size] [opt: r|x|h|c]", - .handler = cmd_ping, - },{ - .name = "rps", - .help = "csp: Remote ps", - .usage = "[node] [timeout]", - .handler = cmd_ps, - },{ - .name = "memfree", - .help = "csp: Memory free", - .usage = "[node] [timeout]", - .handler = cmd_memfree, - },{ - .name = "buffree", - .help = "csp: Buffer free", - .usage = "[node] [timeout]", - .handler = cmd_buf_free, - },{ - .name = "reboot", - .help = "csp: Reboot", - .usage = "", - .handler = cmd_reboot, - },{ - .name = "shutdown", - .help = "csp: Shutdown", - .usage = "", - .handler = cmd_shutdown, - },{ - .name = "uptime", - .help = "csp: Uptime", - .usage = "[node] [timeout]", - .handler = cmd_uptime, - },{ - .name = "cmp", - .help = "csp: Management", - .chain = GS_COMMAND_INIT_CHAIN(cmp_commands), - }, -#ifdef CSP_DEBUG - { - .name = "route", - .help = "csp: Show routing table", - .handler = cmd_csp_route_print_table, - },{ - .name = "ifc", - .help = "csp: Show interfaces", - .handler = cmd_csp_route_print_interfaces, - },{ - .name = "conn", - .help = "csp: Show connection table", - .handler = cmd_csp_conn_print_table, - }, -#endif -#if CSP_USE_RDP - { - .name = "rdpopt", - .help = "csp: Set RDP options", - .handler = cmd_csp_rdp_set_opt, - .usage = " " - }, -#endif -}; - -gs_error_t gs_csp_register_commands(void) -{ - return GS_COMMAND_REGISTER(csp_commands); -} diff --git a/gomspace/libgscsp/src/conn.c b/gomspace/libgscsp/src/conn.c deleted file mode 100644 index 05e6459e..00000000 --- a/gomspace/libgscsp/src/conn.c +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include <../lib/libcsp/src/csp_conn.h> // internal libcsp header - -size_t gs_csp_conn_get_open(void) -{ - size_t open = 0; - size_t max_connections; - const csp_conn_t * connections = csp_conn_get_array(&max_connections); - if (connections) { - for (unsigned int i = 0; i < max_connections; ++i) { - if (connections[i].state != CONN_CLOSED) { - ++open; - } - } - } - - // csp_conn_print_table(); - - return open; -} diff --git a/gomspace/libgscsp/src/csp.c b/gomspace/libgscsp/src/csp.c deleted file mode 100644 index 2367ec6a..00000000 --- a/gomspace/libgscsp/src/csp.c +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include "local.h" - -void gs_csp_conf_get_defaults_embedded(gs_csp_conf_t * conf) -{ - static const gs_csp_conf_t defaults = { - .use_gs_log = true, - .use_command_line_options = true, - .csp_buffer_size = 256, // typical MTU size is 256 - .csp_buffers = 10, // in case of RDP connections, must be > RDP Windows size - .address = 1, - .hostname = "hostname", - .model = "model", - .revision = "revision", - }; - - *conf = defaults; - -#if GS_CSP_COMMAND_LINE_SUPPORT - conf->address = gs_csp_command_line_get_address(); -#endif -} - -void gs_csp_conf_get_defaults_server(gs_csp_conf_t * conf) -{ - gs_csp_conf_get_defaults_embedded(conf); - conf->csp_buffer_size = 512; - conf->csp_buffers = 400; -} - -gs_error_t gs_csp_init(const gs_csp_conf_t * conf) -{ - GS_CHECK_ARG(conf != NULL); - - if (conf->use_gs_log) { - gs_csp_log_init(); - } - - int res = csp_buffer_init(conf->csp_buffers, conf->csp_buffer_size); - if (res != CSP_ERR_NONE) { - log_error("%s: csp_buffer_init(buffers: %u, size: %u) failed, CSP error: %d, error: %d", - __FUNCTION__, (unsigned int) conf->csp_buffers, (unsigned int) conf->csp_buffer_size, res, gs_csp_error(res)); - return gs_csp_error(res); - } - - csp_set_hostname(conf->hostname); - csp_set_model(conf->model); - csp_set_revision(conf->revision); - - uint8_t csp_address = conf->address; -#if GS_CSP_COMMAND_LINE_SUPPORT - if (gs_csp_command_line_is_address_set()) { - csp_address = gs_csp_command_line_get_address(); - } -#endif - - res = csp_init(csp_address); - if (res != CSP_ERR_NONE) { - log_error("%s: csp_init(address: %u) failed, CSP error: %d, error: %d", - __FUNCTION__, conf->address, res, gs_csp_error(res)); - return gs_csp_error(res); - } - -#if GS_CSP_COMMAND_LINE_SUPPORT - if (conf->use_command_line_options) { - gs_error_t error = gs_csp_command_line_configure_interfaces(); - if (error) { - log_error("%s: gs_csp_command_line_configure_interfaces() failed, error: %d", - __FUNCTION__, error); - return error; - } - } -#endif - - return GS_OK; -} - -bool gs_csp_is_address_valid(uint8_t address) -{ - if (address < 1) { - return false; - } - if (address >= 33) { - return false; - } - return true; -} diff --git a/gomspace/libgscsp/src/drivers/can/can.c b/gomspace/libgscsp/src/drivers/can/can.c deleted file mode 100644 index dc19d1a7..00000000 --- a/gomspace/libgscsp/src/drivers/can/can.c +++ /dev/null @@ -1,106 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include - -#include -#include -#include -#include -#include -#include - -#define NO_OF_CAN_CHANNELS 2 -#define MAX_NAME_LENGTH 10 // It says in csp_types.h, that it should be below 10 bytes - -// change default log group -#define LOG_DEFAULT gs_can_log - -typedef struct { - // self reference device handle - uint8_t can_ch; - // CSP interface name - char interface_name[MAX_NAME_LENGTH]; - // CSP interface - csp_iface_t interface; -} gs_csp_can_interface_t; - -static gs_csp_can_interface_t csp_can_interfaces[NO_OF_CAN_CHANNELS]; - -static void gs_csp_can_rxdata_callback_isr(int hdl, - uint32_t canMsgId, - bool extendedMsgId, - const void * data, - size_t data_size, - uint32_t nowMs, - void * user_data, - gs_context_switch_t * cswitch) -{ - csp_can_rx(&csp_can_interfaces[hdl].interface, canMsgId, data, data_size, &cswitch->task_woken); -} - -// Required by libcsp -int csp_can_tx_frame(csp_iface_t *interface, uint32_t id, const uint8_t * data, uint8_t dlc) -{ - return gs_can_send_extended(((gs_csp_can_interface_t *)interface->driver)->can_ch, id, data, dlc, 1000); -} - -gs_error_t gs_csp_can_init2(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, bool set_default_route, csp_iface_t ** csp_if) -{ - GS_CHECK_HANDLE(device < NO_OF_CAN_CHANNELS); - gs_csp_can_interface_t * interface = &csp_can_interfaces[device]; - - // Register/subscribe to CAN frames for CSP - const uint32_t can_id = CFP_MAKE_DST(csp_get_address()); - const uint32_t can_mask = CFP_MAKE_DST((1 << CFP_HOST_SIZE) - 1); - - log_debug("%s(%u): id=0x%" PRIx32 ", mask=0x%" PRIx32, __FUNCTION__, device, can_id, can_mask); - - if (gs_string_empty(name)) { - name = GS_CSP_CAN_DEFAULT_IF_NAME; - } - if (strlen(name) >= MAX_NAME_LENGTH) { - return GS_ERROR_ARG; - } - - if (csp_iflist_get_by_name(name)) { - log_error("%s(%u): name: [%s] - already exists", __FUNCTION__, device, name); - return GS_ERROR_EXIST; - } - - // hook CAN into CSP - GS_STRNCPY(interface->interface_name, name); - interface->interface.name = interface->interface_name; - interface->interface.nexthop = csp_can_tx; - interface->interface.mtu = mtu; - interface->interface.driver = interface; - - csp_iflist_add(&interface->interface); - - if (csp_if) { - *csp_if = &interface->interface; - } - - gs_error_t error = gs_can_set_extended_filter_mask(0, can_id, can_mask, gs_csp_can_rxdata_callback_isr, NULL); - if (error) { - log_error("%s: gs_can_set_extended_filter_mask() failed, error: %s", __FUNCTION__, gs_error_string(error)); - return error; - } - - error = gs_can_start(device); - if (error) { - log_error("%s: gs_can_start() failed, error: %s", __FUNCTION__, gs_error_string(error)); - return error; - } - - if (set_default_route) { - // Route all to CAN - csp_rtable_set(0, 0, &interface->interface, CSP_NODE_MAC); - } - - return GS_OK; -} - -gs_error_t gs_csp_can_init(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, csp_iface_t ** csp_if) -{ - return gs_csp_can_init2(device, csp_addr, mtu, name, true, csp_if); -} diff --git a/gomspace/libgscsp/src/drivers/i2c/i2c.c b/gomspace/libgscsp/src/drivers/i2c/i2c.c deleted file mode 100644 index c40cd9c8..00000000 --- a/gomspace/libgscsp/src/drivers/i2c/i2c.c +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include -#include -#include -#if !defined(__linux__) -#include -#endif - -#define E_FAIL -19 // The CSP I2C driver evaluates any other value than -1 as fail - -#define I2C_FRAME_OVERHEAD (sizeof(i2c_frame_t) - sizeof(((i2c_frame_t *)0)->data)) - -static void gs_csp_i2c_rxdata_callback_isr(uint8_t handle, const uint8_t * rx, size_t rx_length, gs_context_switch_t * cswitch) -{ - i2c_frame_t * frame = (i2c_frame_t *) (rx - I2C_FRAME_OVERHEAD); - frame->len = rx_length; -#if (__linux__) - csp_i2c_rx(frame, NULL); -#else - csp_i2c_rx(frame, &cswitch->task_woken); -#endif -} - -static void * gs_csp_i2c_get_buffer(uint8_t handle) -{ - void * buff = csp_buffer_get_isr(I2C_MTU); - if (buff != NULL) { - buff = ((uint8_t *)buff) + I2C_FRAME_OVERHEAD; - } - return buff; -} - -/** - CSP send function, required by libcsp - */ -int i2c_send(int handle, i2c_frame_t * frame, uint16_t timeout) -{ - int res_tx = gs_i2c_master_transaction(handle, frame->dest, frame->data, frame->len, 0, 0, timeout); - if (res_tx == GS_OK) { - csp_buffer_free(frame); - return E_NO_ERR; - } else { - return E_FAIL; - } -} - -/** - CSP init function, required by libcsp - */ -int i2c_init(int handle, int mode, uint8_t addr, uint16_t speed, int queue_len_tx, int queue_len_rx, - i2c_callback_t callback) -{ - if (gs_i2c_slave_set_rx(handle, gs_csp_i2c_rxdata_callback_isr) != GS_OK) { - return E_FAIL; - } - if (gs_i2c_slave_set_get_rx_buf(handle, gs_csp_i2c_get_buffer, I2C_MTU) != GS_OK) { - return E_FAIL; - } - if (gs_i2c_slave_start(handle) != GS_OK) { - return E_FAIL; - } - return E_NO_ERR; -} - -gs_error_t gs_csp_i2c_init(uint8_t device, uint8_t csp_addr) -{ - int dummy_speed = 0; // Speed not used - - /* Calls CSP I2C init, which has the I2C interface instance - From here the above "i2c_init" is called */ - return gs_csp_error(csp_i2c_init(csp_addr, device, dummy_speed)); -} diff --git a/gomspace/libgscsp/src/drivers/kiss/kiss.c b/gomspace/libgscsp/src/drivers/kiss/kiss.c deleted file mode 100644 index c3357f7d..00000000 --- a/gomspace/libgscsp/src/drivers/kiss/kiss.c +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -static csp_iface_t csp_if_kiss; -static uint8_t uart_csp_device; - -static void usart_rx_callback(void * user_data, const uint8_t * data, size_t data_size, gs_context_switch_t * cswitch) -{ - csp_kiss_rx(&csp_if_kiss, (uint8_t *)data, data_size, cswitch); -} - -static void csp_kiss_putc(char c) -{ - gs_uart_write(uart_csp_device, -1, c); -} - -static void csp_kiss_discard(char c, void *pxTaskWoken) -{ - // Do nothing with discarded characters -} - -gs_error_t gs_csp_kiss_init(uint8_t device) -{ - static csp_kiss_handle_t csp_kiss_driver; - static const char * kiss_name = "KISS"; - csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_kiss, CSP_NODE_MAC); - - csp_kiss_init(&csp_if_kiss, &csp_kiss_driver, csp_kiss_putc, csp_kiss_discard, kiss_name); - - uart_csp_device = device; - - return gs_uart_set_rx_callback(device, usart_rx_callback, NULL); -} diff --git a/gomspace/libgscsp/src/error.c b/gomspace/libgscsp/src/error.c deleted file mode 100644 index 45777e31..00000000 --- a/gomspace/libgscsp/src/error.c +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -gs_error_t gs_csp_error(int csp_error) -{ - switch (csp_error) { - case CSP_ERR_NONE: /* No error */ - return GS_OK; - - case CSP_ERR_NOMEM: /* Not enough memory */ - return GS_ERROR_ALLOC; - - case CSP_ERR_INVAL: /* Invalid argument */ - return GS_ERROR_ARG; - - case CSP_ERR_TIMEDOUT: /* Operation timed out */ - return GS_ERROR_TIMEOUT; - - case CSP_ERR_USED: /* Resource already in use */ - return GS_ERROR_IN_USE; - - case CSP_ERR_NOTSUP: /* Operation not supported */ - return GS_ERROR_NOT_SUPPORTED; - - case CSP_ERR_BUSY: /* Device or resource busy */ - return GS_ERROR_BUSY; - - case CSP_ERR_ALREADY: /* Connection already in progress */ - return GS_ERROR_ALREADY_IN_PROGRESS; - - case CSP_ERR_RESET: /* Connection reset */ - return GS_ERROR_CONNECTION_RESET; - - case CSP_ERR_NOBUFS: /* No more buffer space available */ - return GS_ERROR_NO_BUFFERS; - - case CSP_ERR_TX: /* Transmission failed */ - case CSP_ERR_DRIVER: /* Error in driver layer */ - return GS_ERROR_IO; - - case CSP_ERR_AGAIN: - return GS_ERROR_AGAIN; - - case CSP_ERR_HMAC: /* HMAC failed */ - case CSP_ERR_XTEA: /* XTEA failed */ - case CSP_ERR_CRC32: /* CRC32 failed */ - return GS_ERROR_DATA; - - default: - break; - } - return csp_error; -} diff --git a/gomspace/libgscsp/src/freertos/cpu.c b/gomspace/libgscsp/src/freertos/cpu.c deleted file mode 100644 index a17fd62b..00000000 --- a/gomspace/libgscsp/src/freertos/cpu.c +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -void cpu_reset(void) -{ - gs_sys_reset(GS_SYS_RESET_CSP); -} diff --git a/gomspace/libgscsp/src/linux/command_line.c b/gomspace/libgscsp/src/linux/command_line.c deleted file mode 100644 index 7c2b9bec..00000000 --- a/gomspace/libgscsp/src/linux/command_line.c +++ /dev/null @@ -1,265 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include "../local.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define IF_NAME "if" - -#define DEFAULT_CAN_DEVICE "can0" - -#define DEFAULT_KISS_IF_NAME "KISS" -#define DEFAULT_KISS_DEVICE "/dev/ttyUSB0" -#define KISS_SPEED "speed" -#define DEFAULT_KISS_SPEED 500000 - -#define DEFAULT_ZMQ_SERVER "localhost" - -#define DEFAULT_I2C_DEVICE "0" - -#define CSP_ADDRESS_NOT_SET 255 -#define DEFAULT_CSP_ADDRESS 8 - -static uint8_t csp_address = CSP_ADDRESS_NOT_SET; -static const char * csp_can_device = NULL; -static const char * csp_kiss_device = NULL; -static const char * csp_i2c_device = NULL; -static const char * csp_zmq_server = NULL; -static const char * csp_rtable = NULL; - -static int parser(int key, char *arg, struct argp_state *state) -{ -switch (key) { - case 'a': - return gs_string_to_uint8(arg, &csp_address); - - case 'c': - if (csp_can_device) { - return GS_ERROR_IN_USE; - } - if (arg) { - csp_can_device = arg; - } else { - csp_can_device = DEFAULT_CAN_DEVICE; - } - break; - - case 'k': - if (csp_kiss_device) { - return GS_ERROR_IN_USE; - } - if (arg) { - csp_kiss_device = arg; - } else { - csp_kiss_device = DEFAULT_KISS_DEVICE; - } - break; - - case 'i': - if (csp_i2c_device) { - return GS_ERROR_IN_USE; - } - if (arg) { - csp_i2c_device = arg; - } else { - csp_i2c_device = DEFAULT_I2C_DEVICE; - } - break; - - case 'z': - if (csp_zmq_server) { - return GS_ERROR_IN_USE; - } - if (arg) { - csp_zmq_server = arg; - } else { - csp_zmq_server = DEFAULT_ZMQ_SERVER; - } - break; - - case 'R': - csp_rtable = arg; - break; - - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - -static const struct argp_option options[] = { - { - .name = "csp-address", - .key = 'a', - .arg = "ADDR", - .flags = 0, - .doc = "Set address, default: " GS_DEF2STRING(DEFAULT_CSP_ADDRESS) - }, - { - .name = "csp-rtable", - .key = 'R', - .arg = "RTABLE", - .flags = 0, - .doc = "Set routing table\nRTABLE=
/ [mac]\nExample: \"0/0 ZMQHUB 24, 24/2 ZMQHUB\"" - }, -#if (CSP_USE_CAN) - { - .name = "csp-can", - .key = 'c', - .arg = "DEVICE", - .flags = OPTION_ARG_OPTIONAL, - .doc = "Add CAN interface\nDEVICE=" DEFAULT_CAN_DEVICE - }, -#endif -#if (CSP_USE_KISS) - { - .name = "csp-kiss", - .key = 'k', - .arg = "DEVICE", - .flags = OPTION_ARG_OPTIONAL, - .doc = "Add KISS over UART interface\nDEVICE=" DEFAULT_KISS_DEVICE "," IF_NAME "=" DEFAULT_KISS_IF_NAME","KISS_SPEED"=" GS_DEF2STRING(DEFAULT_KISS_SPEED) - }, -#endif -#if (CSP_USE_I2C) - { - .name = "csp-i2c", - .key = 'i', - .arg = "DEVICE", - .flags = OPTION_ARG_OPTIONAL, - .doc = "Add I2C interface\nDEVICE=0,"GS_I2C_COMMAND_LINE_SPEED"=" GS_DEF2STRING(GS_I2C_DEFAULT_BPS) "," GS_I2C_COMMAND_LINE_ADDRESS "=1," GS_I2C_COMMAND_LINE_DEVICE "=" GS_DEF2STRING(GS_I2C_ALL_DEVICES) - }, -#endif -#if (CSP_USE_ZMQHUB) - { - .name = "csp-zmq", - .key = 'z', - .arg = "SERVER", - .flags = OPTION_ARG_OPTIONAL, - .doc = "Add ZMQ interface\nSERVER=" DEFAULT_ZMQ_SERVER - }, -#endif - { - .flags = OPTION_DOC, - .name = "Examples:" -#if (CSP_USE_CAN) - "\n CAN: configure address 10 and CAN interface can0:" - "\n $ -a10 -ccan0" -#endif -#if (CSP_USE_KISS) - "\n KISS: configure address 10 and uart on /dev/ttyUSB0 at baudrate 500000:" - "\n $ -a10 -k/dev/ttyUSB0,speed=500000" -#endif -#if (CSP_USE_I2C) - "\n I2C: configure address 10 and I2C Aardvark dongle with id 2238384015, speed 400K:" - "\n $ -a10 -i2238384015,speed=400000" -#endif -#if (CSP_USE_ZMQHUB) - "\n ZMQ: configure address 10 and ZMQ proxy on localhost:" - "\n $ -a10 -zlocalhost" -#endif - }, - {0} -}; - -static const struct argp argp = {.options = options, .parser = parser}; - -const struct argp_child gs_csp_command_line_options = {.argp = &argp, .header = "CSP"}; - -gs_error_t gs_csp_command_line_configure_interfaces(void) -{ -#if (CSP_USE_KISS) - // KISS - only here, because the embedded init functions are stubbed in libemul - if (csp_kiss_device) { - static char device[50]; - static char ifname[50]; - uint32_t speed; - int res = gs_string_get_suboption_string(csp_kiss_device, NULL, DEFAULT_KISS_DEVICE, device, sizeof(device)); - res |= gs_string_get_suboption_string(csp_kiss_device, IF_NAME, DEFAULT_KISS_IF_NAME, ifname, sizeof(ifname)); - res |= gs_string_get_suboption_uint32(csp_kiss_device, KISS_SPEED, DEFAULT_KISS_SPEED, &speed); - if (res == GS_OK) { - static csp_iface_t csp_if_kiss; - static csp_kiss_handle_t csp_kiss_driver; - csp_kiss_init(&csp_if_kiss, &csp_kiss_driver, usart_putc, usart_insert, ifname); - struct usart_conf conf = {.device = device, .baudrate = speed}; - usart_init(&conf); - void my_usart_rx(uint8_t * buf, int len, void * pxTaskWoken) { - csp_kiss_rx(&csp_if_kiss, buf, len, pxTaskWoken); - } - usart_set_callback(my_usart_rx); - } - } -#endif - -#if (CSP_USE_CAN) - // CAN - only here, because the embedded init functions are stubbed in libemul - if (csp_can_device) { - char device[50]; - int res = gs_string_get_suboption_string(csp_can_device, NULL, DEFAULT_CAN_DEVICE, device, sizeof(device)); - if (res == GS_OK) { - csp_can_socketcan_init(device, 0, 0); - } - } -#endif - -#if (CSP_USE_ZMQHUB) - // ZMQ - currently ZMQ is only supported on Linux, and therefor handled here - if (csp_zmq_server) { - char server[50]; - int res = gs_string_get_suboption_string(csp_zmq_server, NULL, DEFAULT_ZMQ_SERVER, server, sizeof(server)); - if (res == GS_OK) { - csp_zmqhub_init(csp_get_address(), server); - } - } -#endif - -#if (CSP_USE_I2C) - // I2C - if (csp_i2c_device) { - uint8_t device = 0; - gs_string_get_suboption_uint8(csp_i2c_device, GS_I2C_COMMAND_LINE_DEVICE, GS_I2C_ALL_DEVICES, &device); - if (device == GS_I2C_ALL_DEVICES) { - device = 0; - } - - char modified_options[300]; - snprintf(modified_options, sizeof(modified_options), "%s,%s=%u", csp_i2c_device, GS_I2C_COMMAND_LINE_ADDRESS, csp_get_address()); - gs_error_t error = gs_function_invoke("i2c", modified_options); - if (error) { - log_error("Failed to initialize I2C adapter, error: %s", gs_error_string(error)); - } else { - error = gs_csp_i2c_init(device, csp_get_address()); - if (error) { - log_error("gs_csp_i2c_init(%u, %u) failed, error: %s", device, csp_get_address(), gs_error_string(error)); - } - } - } -#endif - - return GS_OK; -} - -bool gs_csp_command_line_is_address_set(void) -{ - return (csp_address != CSP_ADDRESS_NOT_SET); -} - -uint8_t gs_csp_command_line_get_address(void) -{ - if (gs_csp_command_line_is_address_set()) { - return csp_address; - } - return DEFAULT_CSP_ADDRESS; -} - -const char * gs_csp_command_line_get_rtable(void) -{ - return csp_rtable; -} diff --git a/gomspace/libgscsp/src/local.h b/gomspace/libgscsp/src/local.h deleted file mode 100644 index 5c033c14..00000000 --- a/gomspace/libgscsp/src/local.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef GS_CSP_SRC_LOCAL_H -#define GS_CSP_SRC_LOCAL_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#if (__linux__) -#define GS_CSP_COMMAND_LINE_SUPPORT 1 -#include -#endif - -GS_LOG_GROUP_EXTERN(gs_csp_log); -#define LOG_DEFAULT gs_csp_log - -// local command line APIs -bool gs_csp_command_line_is_address_set(void); -uint8_t gs_csp_command_line_get_address(void); -const char * gs_csp_command_line_get_rtable(void); -gs_error_t gs_csp_command_line_configure_interfaces(void); - -#endif diff --git a/gomspace/libgscsp/src/log.c b/gomspace/libgscsp/src/log.c deleted file mode 100644 index 932e5394..00000000 --- a/gomspace/libgscsp/src/log.c +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include "local.h" - -GS_LOG_GROUP(gs_csp_log, "csp", GS_LOG_CAT_CSP, LOG_DEFAULT_MASK); - -static void gs_log_csp_debug_hook(csp_debug_level_t level, const char *format, va_list args) -{ - gs_log_level_t mapped_level; - - switch (level) { - /* Regular log levels */ - default: - case CSP_ERROR: - mapped_level = LOG_ERROR; - break; - case CSP_WARN: - mapped_level = LOG_WARNING; - break; - case CSP_INFO: - mapped_level = LOG_INFO; - break; - /* Extended log levels */ - case CSP_BUFFER: - mapped_level = LOG_TRACE; - break; - case CSP_PACKET: - mapped_level = LOG_INFO; - break; - case CSP_PROTOCOL: - mapped_level = LOG_DEBUG; - break; - case CSP_LOCK: - mapped_level = LOG_TRACE; - break; - } - - const int do_log = ((LOG_DEFAULT->mask & (1 << mapped_level)) > 0); - - if (do_log) { - /* forward to log system */ - gs_log_va(mapped_level, LOG_DEFAULT, format, args); - } -} - -gs_error_t gs_csp_log_init(void) -{ - gs_log_group_register(LOG_DEFAULT); - - csp_debug_set_level(CSP_ERROR, true); - csp_debug_set_level(CSP_WARN, true); - csp_debug_set_level(CSP_INFO, true); - csp_debug_set_level(CSP_BUFFER, true); - csp_debug_set_level(CSP_PACKET, true); - csp_debug_set_level(CSP_PROTOCOL, true); - csp_debug_set_level(CSP_LOCK, true); - - csp_debug_hook_set(gs_log_csp_debug_hook); - - return GS_OK; -} diff --git a/gomspace/libgscsp/src/router.c b/gomspace/libgscsp/src/router.c deleted file mode 100644 index 95f013eb..00000000 --- a/gomspace/libgscsp/src/router.c +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include -#include -#include -#include "../lib/libcsp/src/csp_qfifo.h" // internal libcsp header -> FIFO_TIMEOUT, csp_qfifo_wake_up() -#include <../lib/libcsp/src/csp_conn.h> // internal libcsp header -#include "local.h" - -typedef struct { - bool run; - gs_thread_t thread; -} gs_csp_router_t; - -static gs_csp_router_t gs_csp_router; - -static void * gs_csp_router_task(void *param) -{ - /* Here there be routing */ - while (gs_csp_router.run) { - csp_route_work(FIFO_TIMEOUT); - } - log_info("CSP router task terminating"); - gs_thread_exit(0); -} - -gs_error_t gs_csp_router_task_stop(void) -{ - GS_CHECK_HANDLE(gs_csp_router.run && (gs_csp_router.thread != 0)); - - // Close connections in state "RDP closing" - instead of waiting for timeout -#ifdef CSP_USE_RDP - { - size_t max_connections; - const csp_conn_t * conn = csp_conn_get_array(&max_connections); - if (conn && max_connections) { - for (unsigned int i = 0; i < max_connections; ++i, ++conn) { - if ((conn->state == CONN_OPEN) && (conn->rdp.state == RDP_CLOSE_WAIT)) { - log_info("Force close RDP %p in state closing", conn); - csp_close((csp_conn_t *) conn); - } - } - } - } -#endif - - // wait for RDP connections to close - unsigned int open = gs_csp_conn_get_open(); - if (open) { - const unsigned int MAX_TIMEOUT_MS = 30000; - log_info("Waiting up to %u mS for %u connection(s) to timeout/close ...", MAX_TIMEOUT_MS, open); - const uint32_t start_ms = gs_time_rel_ms(); - while (gs_csp_conn_get_open() && (gs_time_diff_ms(start_ms, gs_time_rel_ms()) < MAX_TIMEOUT_MS)) { - gs_time_sleep_ms(200); - } - } - - log_info("Waiting for CSP router task to stop ..."); - gs_csp_router.run = false; - csp_qfifo_wake_up(); - gs_error_t error = gs_thread_join(gs_csp_router.thread, NULL); - memset(&gs_csp_router, 0, sizeof(gs_csp_router)); - log_info("CSP router task stopped"); - return error; -} - -gs_error_t gs_csp_router_task_start(size_t stack_size, gs_thread_priority_t priority) -{ - if (gs_csp_router.run) { - return GS_ERROR_IN_USE; - } - - gs_csp_router.run = true; - gs_error_t error = gs_thread_create("RTE", gs_csp_router_task, NULL, stack_size, priority, - GS_THREAD_CREATE_JOINABLE, &gs_csp_router.thread); - if (error) { - memset(&gs_csp_router, 0, sizeof(gs_csp_router)); - } - return error; -} diff --git a/gomspace/libgscsp/src/rtable.c b/gomspace/libgscsp/src/rtable.c deleted file mode 100644 index f836e3d0..00000000 --- a/gomspace/libgscsp/src/rtable.c +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include "local.h" - -// Return interface, if only one configured -static csp_iface_t * get_single_if(unsigned int * return_count) -{ - unsigned int count = 0; - csp_iface_t * found = NULL; - - for (csp_iface_t * ifc = csp_iflist_get(); ifc; ifc = ifc->next) { - if (strcasecmp(ifc->name, "LOOP") == 0) { - // ignore loopback - } else { - ++count; - found = ifc; - } - } - *return_count = count; - return found; -} - -gs_error_t gs_csp_rtable_load(const char * rtable, bool set_default_route, bool use_command_line_option) -{ - //csp_rtable_clear(); - -#if GS_CSP_COMMAND_LINE_SUPPORT - if (use_command_line_option && gs_string_empty(rtable)) { - // try rtable from command line (if set) - rtable = gs_csp_command_line_get_rtable(); - } -#endif - - if (gs_string_empty(rtable) == false) { - - if (csp_rtable_check(rtable) > 0) { - csp_rtable_load(rtable); - log_info("%s: loaded routing table [%s]", __FUNCTION__, rtable); - return GS_OK; - } - - log_warning("%s: ignoring route table: [%s] due to error(s)", __FUNCTION__, rtable); - } - - if (set_default_route) { - unsigned int count = 0; - csp_iface_t * ifc = get_single_if(&count); - if (count == 0) { - log_warning("%s: no interfaces configured", __FUNCTION__); - return GS_ERROR_NOT_FOUND; - } - - if (count > 1) { - log_warning("%s: %u interfaces configured - will not set default routes", __FUNCTION__, count); - return GS_ERROR_AMBIGUOUS; - } - - // set default route - int res = csp_route_set(CSP_DEFAULT_ROUTE, ifc, CSP_NODE_MAC); - if (res != CSP_ERR_NONE) { - log_warning("%s: failed to set default route on interface: [%s], CSP error: %d", __FUNCTION__, ifc->name, res); - return gs_csp_error(res); - } - } - - return GS_OK; -} diff --git a/gomspace/libgscsp/src/service_dispatcher.c b/gomspace/libgscsp/src/service_dispatcher.c deleted file mode 100644 index 507549af..00000000 --- a/gomspace/libgscsp/src/service_dispatcher.c +++ /dev/null @@ -1,213 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include -#include "../lib/libcsp/src/csp_conn.h" // internal libcsp header -#include "local.h" - -static GS_LOG_GROUP(gs_cspdispatcher_log, "cspdispatcher", GS_LOG_CAT_CSP, LOG_DEFAULT_MASK); -#undef LOG_DEFAULT -#define LOG_DEFAULT gs_cspdispatcher_log - -#define WD_TIMEOUT_SECOUNDS 30 -#define DEFAULT_TIMEOUT_MS (((WD_TIMEOUT_SECOUNDS * 1000) / 3) * 2) - -struct gs_csp_service_dispatcher { - // Configuration - const gs_csp_service_dispatcher_conf_t * conf; - // Run or stop/exit. - bool run; - // Server socket - csp_socket_t * socket; - // Software watchdog - gs_swwd_hdl_t * wd; - // Thread handle. - gs_thread_t thread; -}; - -static void * service_dispatcher_task(void * parameter) -{ - gs_csp_service_dispatcher_t handle = parameter; - - unsigned int timeout_ms = (handle->conf->callback) ? 0 : DEFAULT_TIMEOUT_MS; - - log_debug("[%s] entering connection loop, timeout: %u mS", handle->conf->name, timeout_ms); - - while (handle->run) { - if (handle->wd) { - gs_swwd_touch(handle->wd); - } - - /* Wait for incoming connection, or timeout */ - csp_conn_t * conn = csp_accept(handle->socket, timeout_ms); - - if (conn) { - unsigned int in_port = csp_conn_dport(conn); - - log_debug("[%s] new connection %p on port: %u, source: %d:%d, flags: 0x%x", - handle->conf->name, conn, in_port, csp_conn_src(conn), csp_conn_sport(conn), csp_conn_flags(conn)); - - gs_csp_service_handler_t handler; - if (in_port < handle->conf->handler_array_size) { - handler = handle->conf->handler_array[in_port]; - } else { - handler = NULL; - } - - if (handler) { - gs_error_t error = (handler)(conn); - log_debug("[%s] connection on port: %u processed by %p, error: %s", - handle->conf->name, in_port, handler, gs_error_string(error)); - } else { - log_warning("[%s] no handler on port: %u - closing connection: source: %d:%d, flags: 0x%x", - handle->conf->name, in_port, csp_conn_src(conn), csp_conn_sport(conn), csp_conn_flags(conn)); - csp_close(conn); - } - } - - if (handle->conf->callback) { - timeout_ms = handle->conf->callback(); - if (timeout_ms > DEFAULT_TIMEOUT_MS) { - timeout_ms = DEFAULT_TIMEOUT_MS; - } - } - } - - log_debug("[%s] terminating ...", handle->conf->name); - gs_thread_exit(NULL); -} - -static gs_error_t service_dispatcher_create(const gs_csp_service_dispatcher_conf_t * conf, - size_t stack_size, - gs_thread_priority_t priority, - gs_csp_service_dispatcher_t * return_handle) -{ - gs_csp_service_dispatcher_t handle = calloc(1, sizeof(*handle)); - if (handle == 0) { - return GS_ERROR_ALLOC; - } - - *return_handle = handle; - - handle->conf = conf; - - // Create watchdog - if (conf->disable_watchdog == false) { - gs_error_t error = gs_swwd_register(&handle->wd, WD_TIMEOUT_SECOUNDS, NULL, NULL, conf->name); - if (error) { - log_error("[%s] gs_swwd_register(%s, %u) failed, error: %d", - conf->name, conf->name, WD_TIMEOUT_SECOUNDS, error); - handle->wd = NULL; - return error; - } - } - - // Open "server" socket - handle->socket = csp_socket(conf->socket_options); - if (handle->socket == NULL) { - log_error("[%s] csp_socket(0) failed", - conf->name); - return GS_ERROR_ALLOC; - } - - // Bind to port(s) to socket - for (unsigned int i = 0; i < conf->handler_array_size; ++i) { - if (conf->handler_array[i]) { - int res = csp_bind(handle->socket, i); - if (res) { - log_error("[%s] csp_bind(socket: %p, port: %u) failed, result: %d", - conf->name, handle->socket, i, res); - return GS_ERROR_IN_USE; - } - } - } - - // Bind on "any" port? - if (conf->bind_any) { - int res = csp_bind(handle->socket, CSP_ANY); - if (res) { - log_error("[%s] csp_bind(socket: %p, port: %u) failed, result: %d", - conf->name, handle->socket, CSP_ANY, res); - return GS_ERROR_IN_USE; - } - } - - // Create listen backlog - { - size_t backlog = conf->listen_backlog ? conf->listen_backlog : 10; - int res = csp_listen(handle->socket, backlog); - if (res) { - log_error("[%s] csp_listen(%p, %zu) failed, result: %d", - conf->name, handle->socket, backlog, res); - return GS_ERROR_UNKNOWN; - } - } - - // Launch thread - handle->run = true; - gs_error_t error = gs_thread_create(handle->conf->name, service_dispatcher_task, handle, stack_size, priority, - GS_THREAD_CREATE_JOINABLE, &handle->thread); - if (error) { - handle->thread = 0; - } - - return error; -} - -gs_error_t gs_csp_service_dispatcher_create(const gs_csp_service_dispatcher_conf_t * conf, - size_t stack_size, - gs_thread_priority_t priority, - gs_csp_service_dispatcher_t * return_handle) -{ - GS_CHECK_ARG(conf != NULL); - - gs_log_group_register(gs_cspdispatcher_log); - - gs_csp_service_dispatcher_t handle; - gs_error_t error = service_dispatcher_create(conf, stack_size, priority, &handle); - if (error) { - //gs_csp_service_dispatcher_destroy(handle); - handle = NULL; - } - - if (return_handle) { - *return_handle = handle; - } - - return error; -} - -gs_error_t gs_csp_service_dispatcher_wake_up(gs_csp_service_dispatcher_t handle) -{ - GS_CHECK_HANDLE(handle && handle->socket && handle->socket->socket); - csp_packet_t * packet = NULL; - int res = csp_queue_enqueue(handle->socket->socket, &packet, 0); - return (res == CSP_QUEUE_OK) ? GS_OK : GS_ERROR_FULL; -} - -gs_error_t gs_csp_service_dispatcher_destroy(gs_csp_service_dispatcher_t handle) -{ - GS_CHECK_HANDLE(handle && handle->conf); - - log_debug("[%s] stopping dispatcher ...", handle->conf->name); - - handle->run = false; - if (handle->thread) { - gs_csp_service_dispatcher_wake_up(handle); - gs_thread_join(handle->thread, NULL); - } - - csp_close(handle->socket); - - if (handle->wd) { - gs_swwd_deregister(&handle->wd); - } - - memset(handle, 0, sizeof(*handle)); - free(handle); - - return GS_OK; -} diff --git a/gomspace/libgscsp/src/service_handler.c b/gomspace/libgscsp/src/service_handler.c deleted file mode 100644 index b602847d..00000000 --- a/gomspace/libgscsp/src/service_handler.c +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include - -// callback for processing packets on a connection. -typedef void (*csp_service_packet_handler_t)(csp_conn_t * conn, csp_packet_t * packet); - -// Process all packets on the connectio and close it when done. -static gs_error_t call_csp_packet_handler(csp_conn_t * conn, csp_service_packet_handler_t handler) -{ - csp_packet_t *packet; - while ((packet = csp_read(conn, 0))) { - (handler)(conn, packet); - } - csp_close(conn); - return GS_OK; -} - -gs_error_t gs_csp_cmp_service_handler(csp_conn_t * conn) -{ - return call_csp_packet_handler(conn, csp_service_handler); -} - -gs_error_t gs_csp_ping_service_handler(csp_conn_t * conn) -{ - return call_csp_packet_handler(conn, csp_service_handler); -} - -gs_error_t gs_csp_ps_service_handler(csp_conn_t * conn) -{ - return call_csp_packet_handler(conn, csp_service_handler); -} - -static void memfree(csp_conn_t * conn, csp_packet_t * packet) -{ - uint32_t mem_free = 0; - - gs_mem_ram_type_t ram_type = gs_mem_get_ram_default(); - gs_mem_ram_stat_t ram_stat; - if(gs_mem_get_ram_stat(ram_type, &ram_stat) == GS_OK) { - mem_free = ram_stat.available; - } - - mem_free = util_hton32(mem_free); - memcpy(packet->data, &mem_free, sizeof(mem_free)); - packet->length = sizeof(mem_free); - - if (!csp_send(conn, packet, 0)) { - csp_buffer_free(packet); - } -} - -gs_error_t gs_csp_mem_free_service_handler(csp_conn_t * conn) -{ - return call_csp_packet_handler(conn, memfree); -} - -gs_error_t gs_csp_reboot_service_handler(csp_conn_t * conn) -{ - return call_csp_packet_handler(conn, csp_service_handler); -} - -gs_error_t gs_csp_buf_free_service_handler(csp_conn_t * conn) -{ - return call_csp_packet_handler(conn, csp_service_handler); -} - -static void uptime(csp_conn_t * conn, csp_packet_t * packet) -{ - uint32_t time = gs_time_uptime(); - time = util_hton32(time); - memcpy(packet->data, &time, sizeof(time)); - packet->length = sizeof(time); - - if (!csp_send(conn, packet, 0)) { - csp_buffer_free(packet); - } -} - -gs_error_t gs_csp_uptime_service_handler(csp_conn_t * conn) -{ - return call_csp_packet_handler(conn, uptime); -} diff --git a/gomspace/libgscsp/src/transaction.c b/gomspace/libgscsp/src/transaction.c deleted file mode 100644 index 96ba262a..00000000 --- a/gomspace/libgscsp/src/transaction.c +++ /dev/null @@ -1,67 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include - -gs_error_t gs_csp_transaction_persistent(csp_conn_t * conn, uint32_t timeout, const void * tx_buf, - size_t tx_len, void * rx_buf, size_t rx_max_len, size_t * rx_len) -{ - GS_CHECK_HANDLE(conn != NULL); - - size_t size = (rx_max_len > tx_len) ? rx_max_len : tx_len; - csp_packet_t * packet = csp_buffer_get(size); - if (packet == NULL) { - return GS_ERROR_ALLOC; - } - - /* Copy the request */ - if (tx_len > 0 && tx_buf != NULL) { - memcpy(packet->data, tx_buf, tx_len); - } - - packet->length = tx_len; - - if (!csp_send(conn, packet, timeout)) { - csp_buffer_free(packet); - return GS_ERROR_IO; - } - - /* If no reply is expected, return now */ - if (rx_max_len == 0) { - return GS_OK; - } - - packet = csp_read(conn, timeout); - if (packet == NULL) { - return GS_ERROR_IO; - } - - gs_error_t return_val; - if (rx_max_len >= packet->length) { - size = packet->length; - return_val = GS_OK; - } else { - csp_log_error("Reply length %u, buffer only %u", packet->length, rx_max_len); - size = rx_max_len; - return_val = GS_ERROR_OVERFLOW; - } - memcpy(rx_buf, packet->data, size); - *rx_len = packet->length; - csp_buffer_free(packet); - return return_val; -} - -gs_error_t gs_csp_transaction2(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, const void * tx_buf, - size_t tx_len, void * rx_buf, size_t rx_max_len, size_t * rx_len, uint32_t opts) -{ - csp_conn_t * conn = csp_connect(prio, dest, port, 0, opts); - if (conn == NULL) { - return GS_ERROR_HANDLE; - } - - gs_error_t res = gs_csp_transaction_persistent(conn, timeout, tx_buf, tx_len, rx_buf, rx_max_len, rx_len); - - csp_close(conn); - - return res; -} diff --git a/gomspace/libgscsp/wscript b/gomspace/libgscsp/wscript deleted file mode 100644 index a78d7f56..00000000 --- a/gomspace/libgscsp/wscript +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -# Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. - -import gs_gcc -import gs_doc -from waflib.Build import BuildContext - -APPNAME = 'gscsp' - - -def libcsp_with_os(ctx): - if ctx.gs_is_linux(): - return 'posix' - if ctx.gs_is_freertos(): - return 'freertos' - return None - - -def libcsp_with_driver_usart(ctx): - if ctx.gs_is_linux(): - return 'linux' - return None - - -def options(ctx): - ctx.load('gs_gcc gs_doc') - gs_gcc.gs_recurse(ctx) - - -def configure(ctx): - ctx.load('gs_gcc gs_doc') - - ctx.env.append_unique('FILES_GSCSP', 'src/*.c') - ctx.env.append_unique('USE_GSCSP', ['csp', 'csp_h', 'util']) - - if ctx.options.enable_if_i2c: - ctx.env.append_unique('FILES_GSCSP', 'src/drivers/i2c/*.c') - - if ctx.gs_is_freertos(): - ctx.env.append_unique('FILES_GSCSP', 'src/drivers/can/*.c') - ctx.env.append_unique('FILES_GSCSP', 'src/drivers/kiss/*.c') - ctx.env.append_unique('FILES_GSCSP', 'src/freertos/*.c') - ctx.env.append_unique('USE_GSCSP', ['embed']) - - if ctx.gs_is_linux(): - ctx.env.append_unique('FILES_GSCSP', 'src/linux/*.c') - - # libcsp options - ctx.options.with_os = libcsp_with_os(ctx) - ctx.options.with_driver_usart = libcsp_with_driver_usart(ctx) - bindings = True if (ctx.gs_is_linux() and not ctx.gs_is_build_disabled(['shlib', 'csp_shlib'])) else False - ctx.options.enable_bindings = bindings - ctx.options.enable_python3_bindings = bindings - ctx.options.disable_stlib = True - ctx.options.enable_crc32 = True - ctx.options.with_connection_so = ctx.options.with_connection_so | 0x0040 # always CRC32, disable CSP_O_NOCRC32 - - if ctx.options.enable_if_can and ctx.options.enable_can_socketcan: - ctx.check_cc(lib='socketcan', mandatory=True) - - ctx.gs_add_doxygen(input=['include', 'lib/libcsp/include']) - - gs_gcc.gs_recurse(ctx) - - -def build(ctx): - gs_gcc.gs_recurse(ctx) - - public_include = ctx.gs_include(name=APPNAME, - includes=['include']) - - ctx.gs_objects(source=ctx.path.ant_glob(ctx.env.FILES_GSCSP), - target=APPNAME, - use=ctx.env.USE_GSCSP + [public_include]) - - ctx.gs_shlib(source=ctx.path.ant_glob(ctx.env.FILES_GSCSP), - target=APPNAME, - gs_prefix='', # make library libgscsp - gs_use_shlib=ctx.env.USE_GSCSP + [public_include]) - - ctx.gs_python_bindings(source=ctx.path.ant_glob('src/bindings/python/pygscsp.c'), - target=APPNAME, - gs_prefix='', # make library libgscsp - gs_use_shlib=ctx.env.USE_GSCSP + [APPNAME, public_include], - package='libgscsp') - - -def doc(ctx): - gs_doc.add_task_library_doc(ctx, keyvalues={ - 'gs_prod_name': 'lib'+APPNAME, - 'gs_prod_desc': 'GomSpace CSP extension', - }) - - -class Doc(BuildContext): - cmd = fun = 'doc' - - -def gs_dist(ctx): - gs_gcc.gs_recurse(ctx) - ctx.add_default_files(source_module=True) - ctx.add_files(ctx.path.ant_glob(['lib/libcsp/**/*'])) - ctx.add_license_file("CSP", "lib/libcsp/COPYING") diff --git a/gomspace/libp60_client/include/p60.h b/gomspace/libp60_client/include/p60.h deleted file mode 100644 index 186d43f8..00000000 --- a/gomspace/libp60_client/include/p60.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef _P60_H_ -#define _P60_H_ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#define P60_PORT_RPARAM 7 -#define P60_PORT_GNDWDT_RESET 9 -#define P60_PORT_CMDCONTROL 10 -#define P60_PORT_GSSB_SERVICE 15 -#define P60_PORT_GSCRIPT 22 - -/** FRAM MEMORY MAP */ -#define P60_FRAM_BOARD 0x0000 - -/** FRAM FILENAMES */ -#define P60_FNO_BOARD 0 -#define P60_FNO_BOARD_DFL 4 - -#define P60_FRAM_WP_BEGIN (0x1000) -#define P60_FRAM_WP_END (0x1C00 - 1) - -/** GND WD FRAM ADDR **/ -#define P60_FRAM_GNDWDT 0x1F00 - -/** PARAM INDEX MAP */ -#define P60_BOARD_PARAM 0 - -#define DEVICE_FM24CL64B 0 - -typedef enum { - UNKNOWN_RST = 0, - GND_WDT_RST, - I2C_WDT_RST, - CAN_WDT_RST, - EXT_HARD_RST, - EXT_SOFT_RST, -} p60_reset_cause_t; - -extern const uint8_t board_fallback_type; -extern const uint8_t csp_fallback_addr; -extern const uint8_t board_rs422_mode; - -extern void module_init_early(void); -extern void module_init(void); -extern void wdt_gnd_clear(void); -extern uint16_t command_control(uint8_t *packet, uint16_t length); -extern void module_task(void * pvParameters); - -#endif /* _P60_H_ */ diff --git a/gomspace/libp60_client/include/p60_board.h b/gomspace/libp60_client/include/p60_board.h deleted file mode 100644 index 2abd906d..00000000 --- a/gomspace/libp60_client/include/p60_board.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - * NanoCom firmware - * - */ - -#ifndef P60_PARAM_H_ -#define P60_PARAM_H_ - -#include -#include - -/** - * Define memory space - */ -#define P60_BOARD_UID 0x00 -#define P60_BOARD_TYPE 0x10 -#define P60_BOARD_REV 0x11 -#define P60_BOARD_CSP_ADDR 0x12 -#define P60_BOARD_I2C_ADDR 0x13 -#define P60_BOARD_I2C_SPEED_KHZ 0x14 -#define P60_BOARD_CAN_SPEED_KHZ 0x16 -#define P60_BOARD_KISS_ENABLE 0x18 -#define P60_BOARD_RS422_MODE 0x19 -#define P60_BOARD_RS422_SPEED_KHZ 0x1C -#define P60_BOARD_RTABLE_STR 0x20 //! This one is 0x60 = 96 bytes -#define P60_BOARD_RTABLE_STR_SIZE 0x60 - -/** Define the memory size */ -#define P60_BOARD_PARAM_SIZE 0x80 - -extern const param_table_t p60_config[]; -extern const int p60_config_count; - -#endif /* P60_PARAM_H_ */ diff --git a/gomspace/libp60_client/include/power_if.h b/gomspace/libp60_client/include/power_if.h deleted file mode 100644 index 6762d1ec..00000000 --- a/gomspace/libp60_client/include/power_if.h +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - * NanoPower firmware - * - */ - -#ifndef POWER_IF_H_ -#define POWER_IF_H_ - -#include - -#define POWER_IF_SET 1 -#define POWER_IF_GET 2 -#define POWER_IF_LIST 3 - -#define POWER_IF_STATUS_OK 0 -#define POWER_IF_STATUS_ERROR 1 - -#define POWER_IF_NAME_LEN 8 - -typedef struct __attribute__((packed)) { - uint8_t ch_idx; - uint8_t mode; - uint16_t on_cnt; - uint16_t off_cnt; - uint16_t cur_lu_lim; - uint16_t cur_lim; - uint16_t voltage; - int16_t current; - uint16_t latchup; - char name[POWER_IF_NAME_LEN]; -} power_if_ch_status_t; - -typedef struct __attribute__((packed)) { - uint8_t ch_idx; - uint8_t mode; - char name[8]; -} power_if_list_t; - -typedef struct __attribute__((packed)) { - uint8_t cmd; - uint8_t status; - power_if_ch_status_t ch_status; -} power_if_cmd_request_t; - -typedef struct __attribute__((packed)) { - uint8_t cmd; - uint8_t status; - power_if_ch_status_t ch_status; -} power_if_cmd_response_t; - -typedef struct __attribute__((packed)) { - uint8_t cmd; - uint8_t status; - uint8_t count; - power_if_list_t list[16]; -} power_if_cmd_list_response_t; - -int p60_power_if_cmd(uint8_t node, uint8_t port, uint32_t timeout, uint8_t cmd, void * ch_status_p); -uint8_t p60_power_if_get_ch_idx(char * ch_name, uint8_t * ch_no, uint8_t ch_no_max); - -#endif /* POWER_IF_H_ */ diff --git a/gomspace/libp60_client/src/cmd/power_if_cmd.c b/gomspace/libp60_client/src/cmd/power_if_cmd.c deleted file mode 100644 index 9851f912..00000000 --- a/gomspace/libp60_client/src/cmd/power_if_cmd.c +++ /dev/null @@ -1,147 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include - -#include -#include - -#include - -static uint8_t power_if_port = 10; -static uint32_t power_if_timeout = 5000; - -static int cmd_power_if_port(struct command_context * ctx) { - if (ctx->argc < 2) { - printf("Current port is %d\n", power_if_port); - return CMD_ERROR_NONE; - } - power_if_port = atoi(ctx->argv[1]); - return CMD_ERROR_NONE; -} - -static int cmd_power_if_timeout(struct command_context *ctx) { - if (ctx->argc < 2) { - printf("Current timeout is %"PRIu32"\n", power_if_timeout); - return CMD_ERROR_NONE; - } - if (sscanf(command_args(ctx), "%"SCNu32, &power_if_timeout) != 1) - return CMD_ERROR_SYNTAX; - if (power_if_timeout > 30000) { - printf("Timeout set to high, limited to 30000 ms\n"); - power_if_timeout = 30000; - } - printf("Timeout set to %"PRIu32"\n", power_if_timeout); - return CMD_ERROR_NONE; -} - -static int cmd_power_if_set_get(struct command_context * ctx) { - power_if_ch_status_t ch_status; - - if (ctx->argc < 3) { - return CMD_ERROR_SYNTAX; - } - uint8_t node = atoi(ctx->argv[1]); - memset(&ch_status, 0, sizeof(ch_status)); - strncpy(ch_status.name, ctx->argv[2], 7); - ch_status.name[7] = 0; - char * cmd = ctx->argv[0]; - if (!strcmp(cmd, "status") && (ctx->argc == 3)) { - if (!p60_power_if_cmd(node, power_if_port, power_if_timeout, POWER_IF_GET, &ch_status)) { - return CMD_ERROR_FAIL; - } - } else { - if (!strcmp(cmd, "on")) { - ch_status.mode = 1; - } else if (!strcmp(cmd, "off")) { - ch_status.mode = 0; - } - ch_status.on_cnt = (ctx->argc > 3) ? atoi(ctx->argv[3]) : 0; - ch_status.off_cnt = (ctx->argc > 4) ? atoi(ctx->argv[4]) : 0; - if (!p60_power_if_cmd(node, power_if_port, power_if_timeout, POWER_IF_SET, &ch_status)) { - return CMD_ERROR_FAIL; - } - } - printf("Node %u, Output channel '%s' (%u) is %s\r\n", node, ch_status.name, ch_status.ch_idx, (ch_status.mode ? "ON": "OFF")); - printf(" ch_idx: %u\r\n", ch_status.ch_idx); - printf(" mode: %u\r\n", ch_status.mode); - printf(" on_cnt: %u\r\n", ch_status.on_cnt); - printf(" off_cnt: %u\r\n", ch_status.off_cnt); - printf(" cur_lu_lim: %u\r\n", ch_status.cur_lu_lim); - printf(" cur_lim: %u\r\n", ch_status.cur_lim); - printf(" voltage: %u\r\n", ch_status.voltage); - printf(" current: %d\r\n", ch_status.current); - printf(" latchup: %u\r\n", ch_status.latchup); - - return CMD_ERROR_NONE; -} - -static int cmd_power_if_list(struct command_context * ctx) { - if (ctx->argc < 2) { - return CMD_ERROR_SYNTAX; - } - uint8_t node = atoi(ctx->argv[1]); - power_if_cmd_list_response_t ch_list; - if (!p60_power_if_cmd(node, power_if_port, power_if_timeout, POWER_IF_LIST, &ch_list)) { - return CMD_ERROR_FAIL; - } - printf("ch name status\r\n"); - for (uint8_t ch = 0; ch < ch_list.count; ch++) { - printf("%2u %-8s %s\r\n", ch_list.list[ch].ch_idx, ch_list.list[ch].name, ch_list.list[ch].mode ? "ON": "OFF"); - } - return CMD_ERROR_NONE; -} - -command_t power_if_commands[] = { - { - .name = "port", - .help = "Set power interface port (default is 10)", - .usage = "", - .handler = cmd_power_if_port, - }, - { - .name = "timeout", - .help = "Set power interface timeout in milliseconds", - .usage = "", - .handler = cmd_power_if_timeout, - }, - { - .name = "status", - .help = "Get power channel status", - .usage = " ", - .handler = cmd_power_if_set_get, - }, - { - .name = "on", - .help = "Turn power channel on", - .usage = " [ ]", - .handler = cmd_power_if_set_get, - }, - { - .name = "off", - .help = "Turn power channel off", - .usage = " off [ ]", - .handler = cmd_power_if_set_get, - }, - { - .name = "list", - .help = "Get list power channels", - .usage = "", - .handler = cmd_power_if_list, - }, -}; - -command_t __root_command power_if_root_command[] = { - { - .name = "power", - .help = "client: NanoPower P60", - .chain = INIT_CHAIN(power_if_commands), - } -}; - -void cmd_power_if_setup(void) { - command_register(power_if_root_command); -} diff --git a/gomspace/libp60_client/src/p60_client.c b/gomspace/libp60_client/src/p60_client.c deleted file mode 100644 index 76e1a905..00000000 --- a/gomspace/libp60_client/src/p60_client.c +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - * NanoCom firmware - * - */ - -#include -#include -#include -#include - -#include -#include - -/** - * Setup info about board configuration parameters - */ -const param_table_t p60_config[] = { - {.name = "uid", .addr = P60_BOARD_UID, .type = PARAM_STRING, .size = 16}, - {.name = "type", .addr = P60_BOARD_TYPE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "rev", .addr = P60_BOARD_REV, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "csp_addr", .addr = P60_BOARD_CSP_ADDR, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "i2c_addr", .addr = P60_BOARD_I2C_ADDR, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "i2c_speed", .addr = P60_BOARD_I2C_SPEED_KHZ, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, - {.name = "can_speed", .addr = P60_BOARD_CAN_SPEED_KHZ, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, - {.name = "kiss_en", .addr = P60_BOARD_KISS_ENABLE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "rs422_mode", .addr = P60_BOARD_RS422_MODE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "rs422_speed", .addr = P60_BOARD_RS422_SPEED_KHZ, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, - {.name = "csp_rtable", .addr = P60_BOARD_RTABLE_STR, .type = PARAM_STRING, .size = P60_BOARD_RTABLE_STR_SIZE}, - -}; - -const int p60_config_count = sizeof(p60_config) / sizeof(p60_config[0]); diff --git a/gomspace/libp60_client/src/power_if.c b/gomspace/libp60_client/src/power_if.c deleted file mode 100644 index e9266ca0..00000000 --- a/gomspace/libp60_client/src/power_if.c +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - * NanoPower firmware - * - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include - -uint8_t p60_power_if_get_ch_idx(char * ch_name, uint8_t * ch_no, uint8_t ch_no_max) { - - uint8_t result = 1; - uint8_t len = strlen(ch_name); - for (int i = 0; i < len; i++) { - if (!isdigit(ch_name[i])) { - result = 0; - break; - } - } - if (result) { - *ch_no = atoi(ch_name); - if (*ch_no >= ch_no_max) { - result = 0; - } - } - return result; -} - -int p60_power_if_cmd(uint8_t node, uint8_t port, uint32_t timeout, uint8_t cmd, void * ch_status_p) { - - power_if_cmd_request_t req; - - if ((cmd == POWER_IF_SET) || (cmd == POWER_IF_GET)) { - power_if_cmd_response_t resp; - power_if_ch_status_t * ch_status = (power_if_ch_status_t *)ch_status_p; - if (cmd == POWER_IF_SET) { - req.cmd = POWER_IF_SET; - req.ch_status.mode = ch_status->mode; - req.ch_status.on_cnt = csp_hton16(ch_status->on_cnt); - req.ch_status.off_cnt = csp_hton16(ch_status->off_cnt); - } else { - req.cmd = POWER_IF_GET; - req.ch_status.mode = 0; - req.ch_status.on_cnt = 0; - req.ch_status.off_cnt = 0; - } - ch_status->name[POWER_IF_NAME_LEN - 1] = 0; - strcpy(req.ch_status.name, ch_status->name); - if (csp_transaction(CSP_PRIO_HIGH, node, port, timeout, &req, sizeof(power_if_cmd_request_t), &resp, sizeof(power_if_cmd_response_t))) { - if ((resp.cmd == POWER_IF_SET) || (resp.cmd == POWER_IF_GET)) { - if (resp.status == POWER_IF_STATUS_OK) { - ch_status->ch_idx = resp.ch_status.ch_idx; - ch_status->mode = resp.ch_status.mode; - ch_status->on_cnt = csp_ntoh16(resp.ch_status.on_cnt); - ch_status->off_cnt = csp_ntoh16(resp.ch_status.off_cnt); - ch_status->cur_lu_lim = csp_ntoh16(resp.ch_status.cur_lu_lim); - ch_status->cur_lim = csp_ntoh16(resp.ch_status.cur_lim); - ch_status->voltage = csp_ntoh16(resp.ch_status.voltage); - ch_status->current = csp_ntoh16(resp.ch_status.current); - ch_status->latchup = csp_ntoh16(resp.ch_status.latchup); - strncpy(ch_status->name, resp.ch_status.name, POWER_IF_NAME_LEN - 1); - /* Ensure zero termination*/ - ch_status->name[POWER_IF_NAME_LEN - 1] = 0; - return 1; - } - } - } - } else if (cmd == POWER_IF_LIST) { - power_if_cmd_list_response_t * ch_list = (power_if_cmd_list_response_t *)ch_status_p; - req.cmd = POWER_IF_LIST; - req.ch_status.mode = 0; - req.ch_status.on_cnt = 0; - req.ch_status.off_cnt = 0; - req.ch_status.name[0] = 0; - if (csp_transaction(CSP_PRIO_HIGH, node, port, timeout, &req, sizeof(power_if_cmd_request_t), ch_list, sizeof(power_if_cmd_list_response_t))) { - if ((ch_list->cmd == POWER_IF_LIST) && (ch_list->status == POWER_IF_STATUS_OK)) { - return 1; - } - } - } - - return 0; -} diff --git a/gomspace/libp60_client/wscript b/gomspace/libp60_client/wscript deleted file mode 100644 index dc4dcf8a..00000000 --- a/gomspace/libp60_client/wscript +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -# Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. - -APPNAME = 'p60_client' - - -def options(ctx): - gr = ctx.add_option_group('NanoPower-P60 library client options') - gr.add_option('--disable-libp60-cmd', action='store_true', help='Disable client cmd code for NanoPower-P60 library') - - -def configure(ctx): - ctx.env.append_unique('FILES_LIBP60_CLIENT', ['src/*.c']) - if not ctx.options.disable_libp60_cmd: - ctx.env.append_unique('FILES_LIBP60_CLIENT', ['src/cmd/*.c']) - - -def build(ctx): - public_include = APPNAME + '_h' - ctx(export_includes=['include'], name=public_include) - ctx.objects(source=ctx.path.ant_glob(ctx.env.FILES_LIBP60_CLIENT), - target=APPNAME, - use=['csp', 'gosh', 'param', 'param_client', 'util', public_include]) - - -def gs_dist(ctx): - ctx.add_default_files(source_module=True) diff --git a/gomspace/libutil/include/deprecated/gs/gosh/command/command.h b/gomspace/libutil/include/deprecated/gs/gosh/command/command.h deleted file mode 100644 index 540afea4..00000000 --- a/gomspace/libutil/include/deprecated/gs/gosh/command/command.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef GS_GOSH_COMMAND_COMMAND_H -#define GS_GOSH_COMMAND_COMMAND_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - Legacy header file - use gs/util/gosh/command.h -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define CMD_ERROR_NONE GS_OK -#define CMD_ERROR_FAIL GS_ERROR_UNKNOWN -#define CMD_ERROR_SYNTAX GS_ERROR_ARG -#define CMD_ERROR_NOMEM GS_ERROR_ALLOC -#define CMD_ERROR_INVALID GS_ERROR_DATA -#define CMD_ERROR_NOTFOUND GS_ERROR_NOT_FOUND - -#define CMD_HIDDEN GS_COMMAND_FLAG_HIDDEN - -#define __root_command GS_COMMAND_ROOT -#define __sub_command GS_COMMAND_SUB - -#define INIT_CHAIN(__list) GS_COMMAND_INIT_CHAIN(__list) -#define command_register(__cmd) GS_COMMAND_REGISTER(__cmd) - -typedef struct command command_t; - -static inline const char * command_args(gs_command_context_t *ctx) -{ - return gs_command_args(ctx); -} - -static inline int command_run(char *line) -{ - gs_error_t result = GS_OK; - gs_error_t error = gs_command_run(line, &result); - if (error == GS_OK) { - return result; - } - return error; -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h b/gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h deleted file mode 100644 index e0e40329..00000000 --- a/gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef GS_GOSH_GOSH_GETOPT_H -#define GS_GOSH_GOSH_GETOPT_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - Legacy header file - use gs/util/gosh/getopt.h -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -static inline int gosh_getopt(gs_command_context_t *ctx, const char *opts) -{ - return gs_command_getopt(ctx, opts); -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/deprecated/gs/gosh/util/console.h b/gomspace/libutil/include/deprecated/gs/gosh/util/console.h deleted file mode 100644 index a8d1c94d..00000000 --- a/gomspace/libutil/include/deprecated/gs/gosh/util/console.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef GS_GOSH_UTIL_CONSOLE_H -#define GS_GOSH_UTIL_CONSOLE_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - Legacy header file - use gs/util/gosh/console.h -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -static inline int console_init(void) -{ - return gs_console_init(); -} - -static inline int console_exit(void) -{ - return gs_console_exit(); -} - -static inline void console_set_hostname(const char *host) -{ - gs_console_set_prompt(host); -} - -static inline void console_clear(void) -{ - gs_console_clear(); -} - -static inline void console_update(void) -{ - gs_console_update(); -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/deprecated/util/color_printf.h b/gomspace/libutil/include/deprecated/util/color_printf.h deleted file mode 100644 index a2129460..00000000 --- a/gomspace/libutil/include/deprecated/util/color_printf.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef DEPRECATED_UTIL_COLOR_PRINTF_H -#define DEPRECATED_UTIL_COLOR_PRINTF_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -typedef enum color_printf_e { - /* Colors */ - COLOR_COLORS = GS_COLOR_COLORS, - COLOR_NONE = GS_COLOR_NONE, - COLOR_BLACK = GS_COLOR_BLACK, - COLOR_RED = GS_COLOR_RED, - COLOR_GREEN = GS_COLOR_GREEN, - COLOR_YELLOW = GS_COLOR_YELLOW, - COLOR_BLUE = GS_COLOR_BLUE, - COLOR_MAGENTA = GS_COLOR_MAGENTA, - COLOR_CYAN = GS_COLOR_CYAN, - COLOR_WHITE = GS_COLOR_WHITE, - /* Attributes */ - COLOR_ATTRS = GS_COLOR_ATTRS, - COLOR_BOLD = GS_COLOR_BOLD, -} color_printf_t; - -#define color_printf gs_color_printf - -#endif diff --git a/gomspace/libutil/include/gs/uthash/utarray.h b/gomspace/libutil/include/gs/uthash/utarray.h deleted file mode 100644 index 145f3631..00000000 --- a/gomspace/libutil/include/gs/uthash/utarray.h +++ /dev/null @@ -1,231 +0,0 @@ -/* -Copyright (c) 2008-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -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. -*/ - -/* a dynamic array implementation using macros - */ -#ifndef UTARRAY_H -#define UTARRAY_H - -#define UTARRAY_VERSION 1.9.9 - -#ifdef __GNUC__ -#define _UNUSED_ __attribute__ ((__unused__)) -#else -#define _UNUSED_ -#endif - -#include /* size_t */ -#include /* memset, etc */ -#include /* exit */ - -#define oom() exit(-1) - -typedef void (ctor_f)(void *dst, const void *src); -typedef void (dtor_f)(void *elt); -typedef void (init_f)(void *elt); -typedef struct { - size_t sz; - init_f *init; - ctor_f *copy; - dtor_f *dtor; -} UT_icd; - -typedef struct { - unsigned i,n;/* i: index of next available slot, n: num slots */ - UT_icd icd; /* initializer, copy and destructor functions */ - char *d; /* n slots of size icd->sz*/ -} UT_array; - -#define utarray_init(a,_icd) do { \ - memset(a,0,sizeof(UT_array)); \ - (a)->icd=*_icd; \ -} while(0) - -#define utarray_done(a) do { \ - if ((a)->n) { \ - if ((a)->icd.dtor) { \ - size_t _ut_i; \ - for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ - (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ - } \ - } \ - free((a)->d); \ - } \ - (a)->n=0; \ -} while(0) - -#define utarray_new(a,_icd) do { \ - a=(UT_array*)malloc(sizeof(UT_array)); \ - utarray_init(a,_icd); \ -} while(0) - -#define utarray_free(a) do { \ - utarray_done(a); \ - free(a); \ -} while(0) - -#define utarray_reserve(a,by) do { \ - if (((a)->i+by) > ((a)->n)) { \ - while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \ - if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd.sz)) == NULL) oom(); \ - } \ -} while(0) - -#define utarray_push_back(a,p) do { \ - utarray_reserve(a,1); \ - if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \ - else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \ -} while(0) - -#define utarray_pop_back(a) do { \ - if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \ - else { (a)->i--; } \ -} while(0) - -#define utarray_extend_back(a) do { \ - utarray_reserve(a,1); \ - if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \ - else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \ - (a)->i++; \ -} while(0) - -#define utarray_len(a) ((a)->i) - -#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL) -#define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd.sz*(j) ))) - -#define utarray_insert(a,p,j) do { \ - if (j > (a)->i) utarray_resize(a,j); \ - utarray_reserve(a,1); \ - if ((j) < (a)->i) { \ - memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \ - ((a)->i - (j))*((a)->icd.sz)); \ - } \ - if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \ - else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \ - (a)->i++; \ -} while(0) - -#define utarray_inserta(a,w,j) do { \ - if (utarray_len(w) == 0) break; \ - if (j > (a)->i) utarray_resize(a,j); \ - utarray_reserve(a,utarray_len(w)); \ - if ((j) < (a)->i) { \ - memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \ - _utarray_eltptr(a,j), \ - ((a)->i - (j))*((a)->icd.sz)); \ - } \ - if ((a)->icd.copy) { \ - size_t _ut_i; \ - for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \ - (a)->icd.copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \ - } \ - } else { \ - memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \ - utarray_len(w)*((a)->icd.sz)); \ - } \ - (a)->i += utarray_len(w); \ -} while(0) - -#define utarray_resize(dst,num) do { \ - size_t _ut_i; \ - if (dst->i > (size_t)(num)) { \ - if ((dst)->icd.dtor) { \ - for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \ - (dst)->icd.dtor(utarray_eltptr(dst,_ut_i)); \ - } \ - } \ - } else if (dst->i < (size_t)(num)) { \ - utarray_reserve(dst,num-dst->i); \ - if ((dst)->icd.init) { \ - for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \ - (dst)->icd.init(utarray_eltptr(dst,_ut_i)); \ - } \ - } else { \ - memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd.sz*(num-dst->i)); \ - } \ - } \ - dst->i = num; \ -} while(0) - -#define utarray_concat(dst,src) do { \ - utarray_inserta((dst),(src),utarray_len(dst)); \ -} while(0) - -#define utarray_erase(a,pos,len) do { \ - if ((a)->icd.dtor) { \ - size_t _ut_i; \ - for(_ut_i=0; _ut_i < len; _ut_i++) { \ - (a)->icd.dtor(utarray_eltptr((a),pos+_ut_i)); \ - } \ - } \ - if ((a)->i > (pos+len)) { \ - memmove( _utarray_eltptr((a),pos), _utarray_eltptr((a),pos+len), \ - (((a)->i)-(pos+len))*((a)->icd.sz)); \ - } \ - (a)->i -= (len); \ -} while(0) - -#define utarray_renew(a,u) do { \ - if (a) utarray_clear(a); \ - else utarray_new((a),(u)); \ -} while(0) - -#define utarray_clear(a) do { \ - if ((a)->i > 0) { \ - if ((a)->icd.dtor) { \ - size_t _ut_i; \ - for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ - (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ - } \ - } \ - (a)->i = 0; \ - } \ -} while(0) - -#define utarray_sort(a,cmp) do { \ - qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \ -} while(0) - -#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp) - -#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL) -#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL)) -#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL)) -#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL) -#define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(size_t)(a)->icd.sz) : -1) - -/* last we pre-define a few icd for common utarrays of ints and strings */ -static void utarray_str_cpy(void *dst, const void *src) { - char **_src = (char**)src, **_dst = (char**)dst; - *_dst = (*_src == NULL) ? NULL : strdup(*_src); -} -static void utarray_str_dtor(void *elt) { - char **eltc = (char**)elt; - if (*eltc) free(*eltc); -} -static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor}; -static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL}; -static const UT_icd ut_ptr_icd _UNUSED_ = {sizeof(void*),NULL,NULL,NULL}; - -#endif /* UTARRAY_H */ diff --git a/gomspace/libutil/include/gs/uthash/uthash.h b/gomspace/libutil/include/gs/uthash/uthash.h deleted file mode 100644 index c8c6d25c..00000000 --- a/gomspace/libutil/include/gs/uthash/uthash.h +++ /dev/null @@ -1,960 +0,0 @@ -/* -Copyright (c) 2003-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -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. -*/ - -#ifndef UTHASH_H -#define UTHASH_H - -#include /* memcmp,strlen */ -#include /* ptrdiff_t */ -#include /* exit() */ - -/* These macros use decltype or the earlier __typeof GNU extension. - As decltype is only available in newer compilers (VS2010 or gcc 4.3+ - when compiling c++ source) this code uses whatever method is needed - or, for VS2008 where neither is available, uses casting workarounds. */ -#if defined(_MSC_VER) /* MS compiler */ -#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ -#define DECLTYPE(x) (decltype(x)) -#else /* VS2008 or older (or VS2010 in C mode) */ -#define NO_DECLTYPE -#define DECLTYPE(x) -#endif -#elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__) -#define NO_DECLTYPE -#define DECLTYPE(x) -#else /* GNU, Sun and other compilers */ -#define DECLTYPE(x) (__typeof(x)) -#endif - -#ifdef NO_DECLTYPE -#define DECLTYPE_ASSIGN(dst,src) \ -do { \ - char **_da_dst = (char**)(&(dst)); \ - *_da_dst = (char*)(src); \ -} while(0) -#else -#define DECLTYPE_ASSIGN(dst,src) \ -do { \ - (dst) = DECLTYPE(dst)(src); \ -} while(0) -#endif - -/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */ -#if defined (_WIN32) -#if defined(_MSC_VER) && _MSC_VER >= 1600 -#include -#elif defined(__WATCOMC__) -#include -#else -typedef unsigned int uint32_t; -typedef unsigned char uint8_t; -#endif -#else -#include -#endif - -#define UTHASH_VERSION 1.9.9 - -#ifndef uthash_fatal -#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ -#endif -#ifndef uthash_malloc -#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ -#endif -#ifndef uthash_free -#define uthash_free(ptr,sz) free(ptr) /* free fcn */ -#endif - -#ifndef uthash_noexpand_fyi -#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ -#endif -#ifndef uthash_expand_fyi -#define uthash_expand_fyi(tbl) /* can be defined to log expands */ -#endif - -/* initial number of buckets */ -#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ -#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ -#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ - -/* calculate the element whose hash handle address is hhe */ -#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) - -#define HASH_FIND(hh,head,keyptr,keylen,out) \ -do { \ - out=NULL; \ - if (head) { \ - unsigned _hf_bkt,_hf_hashv; \ - HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ - if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ - HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ - keyptr,keylen,out); \ - } \ - } \ -} while (0) - -#ifdef HASH_BLOOM -#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) -#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) -#define HASH_BLOOM_MAKE(tbl) \ -do { \ - (tbl)->bloom_nbits = HASH_BLOOM; \ - (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ - if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ - memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ - (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ -} while (0) - -#define HASH_BLOOM_FREE(tbl) \ -do { \ - uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ -} while (0) - -#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) -#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) - -#define HASH_BLOOM_ADD(tbl,hashv) \ - HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) - -#define HASH_BLOOM_TEST(tbl,hashv) \ - HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) - -#else -#define HASH_BLOOM_MAKE(tbl) -#define HASH_BLOOM_FREE(tbl) -#define HASH_BLOOM_ADD(tbl,hashv) -#define HASH_BLOOM_TEST(tbl,hashv) (1) -#define HASH_BLOOM_BYTELEN 0 -#endif - -#define HASH_MAKE_TABLE(hh,head) \ -do { \ - (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ - sizeof(UT_hash_table)); \ - if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ - memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ - (head)->hh.tbl->tail = &((head)->hh); \ - (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ - (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ - (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ - (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ - HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ - if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ - memset((head)->hh.tbl->buckets, 0, \ - HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ - HASH_BLOOM_MAKE((head)->hh.tbl); \ - (head)->hh.tbl->signature = HASH_SIGNATURE; \ -} while(0) - -#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ - HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add) - -#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ -do { \ - replaced=NULL; \ - HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced); \ - if (replaced!=NULL) { \ - HASH_DELETE(hh,head,replaced); \ - }; \ - HASH_ADD(hh,head,fieldname,keylen_in,add); \ -} while(0) - -#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ -do { \ - unsigned _ha_bkt; \ - (add)->hh.next = NULL; \ - (add)->hh.key = (char*)(keyptr); \ - (add)->hh.keylen = (unsigned)(keylen_in); \ - if (!(head)) { \ - head = (add); \ - (head)->hh.prev = NULL; \ - HASH_MAKE_TABLE(hh,head); \ - } else { \ - (head)->hh.tbl->tail->next = (add); \ - (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ - (head)->hh.tbl->tail = &((add)->hh); \ - } \ - (head)->hh.tbl->num_items++; \ - (add)->hh.tbl = (head)->hh.tbl; \ - HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ - (add)->hh.hashv, _ha_bkt); \ - HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ - HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ - HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ - HASH_FSCK(hh,head); \ -} while(0) - -#define HASH_TO_BKT( hashv, num_bkts, bkt ) \ -do { \ - bkt = ((hashv) & ((num_bkts) - 1)); \ -} while(0) - -/* delete "delptr" from the hash table. - * "the usual" patch-up process for the app-order doubly-linked-list. - * The use of _hd_hh_del below deserves special explanation. - * These used to be expressed using (delptr) but that led to a bug - * if someone used the same symbol for the head and deletee, like - * HASH_DELETE(hh,users,users); - * We want that to work, but by changing the head (users) below - * we were forfeiting our ability to further refer to the deletee (users) - * in the patch-up process. Solution: use scratch space to - * copy the deletee pointer, then the latter references are via that - * scratch pointer rather than through the repointed (users) symbol. - */ -#define HASH_DELETE(hh,head,delptr) \ -do { \ - struct UT_hash_handle *_hd_hh_del; \ - if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ - uthash_free((head)->hh.tbl->buckets, \ - (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ - HASH_BLOOM_FREE((head)->hh.tbl); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - head = NULL; \ - } else { \ - unsigned _hd_bkt; \ - _hd_hh_del = &((delptr)->hh); \ - if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ - (head)->hh.tbl->tail = \ - (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ - (head)->hh.tbl->hho); \ - } \ - if ((delptr)->hh.prev) { \ - ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ - (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ - } else { \ - DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ - } \ - if (_hd_hh_del->next) { \ - ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \ - (head)->hh.tbl->hho))->prev = \ - _hd_hh_del->prev; \ - } \ - HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ - HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ - (head)->hh.tbl->num_items--; \ - } \ - HASH_FSCK(hh,head); \ -} while (0) - - -/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ -#define HASH_FIND_STR(head,findstr,out) \ - HASH_FIND(hh,head,findstr,(unsigned)strlen(findstr),out) -#define HASH_ADD_STR(head,strfield,add) \ - HASH_ADD(hh,head,strfield[0],strlen(add->strfield),add) -#define HASH_REPLACE_STR(head,strfield,add,replaced) \ - HASH_REPLACE(hh,head,strfield[0],(unsigned)strlen(add->strfield),add,replaced) -#define HASH_FIND_INT(head,findint,out) \ - HASH_FIND(hh,head,findint,sizeof(int),out) -#define HASH_ADD_INT(head,intfield,add) \ - HASH_ADD(hh,head,intfield,sizeof(int),add) -#define HASH_REPLACE_INT(head,intfield,add,replaced) \ - HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) -#define HASH_FIND_PTR(head,findptr,out) \ - HASH_FIND(hh,head,findptr,sizeof(void *),out) -#define HASH_ADD_PTR(head,ptrfield,add) \ - HASH_ADD(hh,head,ptrfield,sizeof(void *),add) -#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ - HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) -#define HASH_DEL(head,delptr) \ - HASH_DELETE(hh,head,delptr) - -/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. - * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. - */ -#ifdef HASH_DEBUG -#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) -#define HASH_FSCK(hh,head) \ -do { \ - struct UT_hash_handle *_thh; \ - if (head) { \ - unsigned _bkt_i; \ - unsigned _count; \ - char *_prev; \ - _count = 0; \ - for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ - unsigned _bkt_count = 0; \ - _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ - _prev = NULL; \ - while (_thh) { \ - if (_prev != (char*)(_thh->hh_prev)) { \ - HASH_OOPS("invalid hh_prev %p, actual %p\n", \ - _thh->hh_prev, _prev ); \ - } \ - _bkt_count++; \ - _prev = (char*)(_thh); \ - _thh = _thh->hh_next; \ - } \ - _count += _bkt_count; \ - if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ - HASH_OOPS("invalid bucket count %u, actual %u\n", \ - (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ - } \ - } \ - if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("invalid hh item count %u, actual %u\n", \ - (head)->hh.tbl->num_items, _count ); \ - } \ - /* traverse hh in app order; check next/prev integrity, count */ \ - _count = 0; \ - _prev = NULL; \ - _thh = &(head)->hh; \ - while (_thh) { \ - _count++; \ - if (_prev !=(char*)(_thh->prev)) { \ - HASH_OOPS("invalid prev %p, actual %p\n", \ - _thh->prev, _prev ); \ - } \ - _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ - _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ - (head)->hh.tbl->hho) : NULL ); \ - } \ - if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("invalid app item count %u, actual %u\n", \ - (head)->hh.tbl->num_items, _count ); \ - } \ - } \ -} while (0) -#else -#define HASH_FSCK(hh,head) -#endif - -/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to - * the descriptor to which this macro is defined for tuning the hash function. - * The app can #include to get the prototype for write(2). */ -#ifdef HASH_EMIT_KEYS -#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ -do { \ - unsigned _klen = fieldlen; \ - write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ - write(HASH_EMIT_KEYS, keyptr, fieldlen); \ -} while (0) -#else -#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) -#endif - -/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ -#ifdef HASH_FUNCTION -#define HASH_FCN HASH_FUNCTION -#else -#define HASH_FCN HASH_JEN -#endif - -/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ -#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned _hb_keylen=keylen; \ - char *_hb_key=(char*)(key); \ - (hashv) = 0; \ - while (_hb_keylen--) { (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; } \ - bkt = (hashv) & (num_bkts-1); \ -} while (0) - - -/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at - * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ -#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned _sx_i; \ - char *_hs_key=(char*)(key); \ - hashv = 0; \ - for(_sx_i=0; _sx_i < keylen; _sx_i++) \ - hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ - bkt = hashv & (num_bkts-1); \ -} while (0) -/* FNV-1a variation */ -#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned _fn_i; \ - char *_hf_key=(char*)(key); \ - hashv = 2166136261UL; \ - for(_fn_i=0; _fn_i < keylen; _fn_i++) { \ - hashv = hashv ^ _hf_key[_fn_i]; \ - hashv = hashv * 16777619; \ - } \ - bkt = hashv & (num_bkts-1); \ -} while(0) - -#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned _ho_i; \ - char *_ho_key=(char*)(key); \ - hashv = 0; \ - for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ - hashv += _ho_key[_ho_i]; \ - hashv += (hashv << 10); \ - hashv ^= (hashv >> 6); \ - } \ - hashv += (hashv << 3); \ - hashv ^= (hashv >> 11); \ - hashv += (hashv << 15); \ - bkt = hashv & (num_bkts-1); \ -} while(0) - -#define HASH_JEN_MIX(a,b,c) \ -do { \ - a -= b; a -= c; a ^= ( c >> 13 ); \ - b -= c; b -= a; b ^= ( a << 8 ); \ - c -= a; c -= b; c ^= ( b >> 13 ); \ - a -= b; a -= c; a ^= ( c >> 12 ); \ - b -= c; b -= a; b ^= ( a << 16 ); \ - c -= a; c -= b; c ^= ( b >> 5 ); \ - a -= b; a -= c; a ^= ( c >> 3 ); \ - b -= c; b -= a; b ^= ( a << 10 ); \ - c -= a; c -= b; c ^= ( b >> 15 ); \ -} while (0) - -#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned _hj_i,_hj_j,_hj_k; \ - unsigned char *_hj_key=(unsigned char*)(key); \ - hashv = 0xfeedbeef; \ - _hj_i = _hj_j = 0x9e3779b9; \ - _hj_k = (unsigned)(keylen); \ - while (_hj_k >= 12) { \ - _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ - + ( (unsigned)_hj_key[2] << 16 ) \ - + ( (unsigned)_hj_key[3] << 24 ) ); \ - _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ - + ( (unsigned)_hj_key[6] << 16 ) \ - + ( (unsigned)_hj_key[7] << 24 ) ); \ - hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ - + ( (unsigned)_hj_key[10] << 16 ) \ - + ( (unsigned)_hj_key[11] << 24 ) ); \ - \ - HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ - \ - _hj_key += 12; \ - _hj_k -= 12; \ - } \ - hashv += keylen; \ - switch ( _hj_k ) { \ - case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ - case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ - case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ - case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ - case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ - case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ - case 5: _hj_j += _hj_key[4]; \ - case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ - case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ - case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ - case 1: _hj_i += _hj_key[0]; \ - } \ - HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ - bkt = hashv & (num_bkts-1); \ -} while(0) - -/* The Paul Hsieh hash function */ -#undef get16bits -#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ - || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) -#define get16bits(d) (*((const uint16_t *) (d))) -#endif - -#if !defined (get16bits) -#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ - +(uint32_t)(((const uint8_t *)(d))[0]) ) -#endif -#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned char *_sfh_key=(unsigned char*)(key); \ - uint32_t _sfh_tmp, _sfh_len = keylen; \ - \ - int _sfh_rem = _sfh_len & 3; \ - _sfh_len >>= 2; \ - hashv = 0xcafebabe; \ - \ - /* Main loop */ \ - for (;_sfh_len > 0; _sfh_len--) { \ - hashv += get16bits (_sfh_key); \ - _sfh_tmp = (uint32_t)(get16bits (_sfh_key+2)) << 11 ^ hashv; \ - hashv = (hashv << 16) ^ _sfh_tmp; \ - _sfh_key += 2*sizeof (uint16_t); \ - hashv += hashv >> 11; \ - } \ - \ - /* Handle end cases */ \ - switch (_sfh_rem) { \ - case 3: hashv += get16bits (_sfh_key); \ - hashv ^= hashv << 16; \ - hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)] << 18); \ - hashv += hashv >> 11; \ - break; \ - case 2: hashv += get16bits (_sfh_key); \ - hashv ^= hashv << 11; \ - hashv += hashv >> 17; \ - break; \ - case 1: hashv += *_sfh_key; \ - hashv ^= hashv << 10; \ - hashv += hashv >> 1; \ - } \ - \ - /* Force "avalanching" of final 127 bits */ \ - hashv ^= hashv << 3; \ - hashv += hashv >> 5; \ - hashv ^= hashv << 4; \ - hashv += hashv >> 17; \ - hashv ^= hashv << 25; \ - hashv += hashv >> 6; \ - bkt = hashv & (num_bkts-1); \ -} while(0) - -#ifdef HASH_USING_NO_STRICT_ALIASING -/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. - * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. - * MurmurHash uses the faster approach only on CPU's where we know it's safe. - * - * Note the preprocessor built-in defines can be emitted using: - * - * gcc -m64 -dM -E - < /dev/null (on gcc) - * cc -## a.c (where a.c is a simple test file) (Sun Studio) - */ -#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) -#define MUR_GETBLOCK(p,i) p[i] -#else /* non intel */ -#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) -#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) -#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) -#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) -#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) -#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) -#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) -#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) -#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) -#else /* assume little endian non-intel */ -#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) -#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) -#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) -#endif -#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ - (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ - (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ - MUR_ONE_THREE(p)))) -#endif -#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) -#define MUR_FMIX(_h) \ -do { \ - _h ^= _h >> 16; \ - _h *= 0x85ebca6b; \ - _h ^= _h >> 13; \ - _h *= 0xc2b2ae35l; \ - _h ^= _h >> 16; \ -} while(0) - -#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ -do { \ - const uint8_t *_mur_data = (const uint8_t*)(key); \ - const int _mur_nblocks = (keylen) / 4; \ - uint32_t _mur_h1 = 0xf88D5353; \ - uint32_t _mur_c1 = 0xcc9e2d51; \ - uint32_t _mur_c2 = 0x1b873593; \ - uint32_t _mur_k1 = 0; \ - const uint8_t *_mur_tail; \ - const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ - int _mur_i; \ - for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ - _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ - _mur_k1 *= _mur_c1; \ - _mur_k1 = MUR_ROTL32(_mur_k1,15); \ - _mur_k1 *= _mur_c2; \ - \ - _mur_h1 ^= _mur_k1; \ - _mur_h1 = MUR_ROTL32(_mur_h1,13); \ - _mur_h1 = _mur_h1*5+0xe6546b64; \ - } \ - _mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ - _mur_k1=0; \ - switch((keylen) & 3) { \ - case 3: _mur_k1 ^= _mur_tail[2] << 16; \ - case 2: _mur_k1 ^= _mur_tail[1] << 8; \ - case 1: _mur_k1 ^= _mur_tail[0]; \ - _mur_k1 *= _mur_c1; \ - _mur_k1 = MUR_ROTL32(_mur_k1,15); \ - _mur_k1 *= _mur_c2; \ - _mur_h1 ^= _mur_k1; \ - } \ - _mur_h1 ^= (keylen); \ - MUR_FMIX(_mur_h1); \ - hashv = _mur_h1; \ - bkt = hashv & (num_bkts-1); \ -} while(0) -#endif /* HASH_USING_NO_STRICT_ALIASING */ - -/* key comparison function; return 0 if keys equal */ -#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) - -/* iterate over items in a known bucket to find desired item */ -#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ -do { \ - if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ - else out=NULL; \ - while (out) { \ - if ((out)->hh.keylen == keylen_in) { \ - if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \ - } \ - if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \ - else out = NULL; \ - } \ -} while(0) - -/* add an item to a bucket */ -#define HASH_ADD_TO_BKT(head,addhh) \ -do { \ - head.count++; \ - (addhh)->hh_next = head.hh_head; \ - (addhh)->hh_prev = NULL; \ - if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ - (head).hh_head=addhh; \ - if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ - && (addhh)->tbl->noexpand != 1) { \ - HASH_EXPAND_BUCKETS((addhh)->tbl); \ - } \ -} while(0) - -/* remove an item from a given bucket */ -#define HASH_DEL_IN_BKT(hh,head,hh_del) \ - (head).count--; \ - if ((head).hh_head == hh_del) { \ - (head).hh_head = hh_del->hh_next; \ - } \ - if (hh_del->hh_prev) { \ - hh_del->hh_prev->hh_next = hh_del->hh_next; \ - } \ - if (hh_del->hh_next) { \ - hh_del->hh_next->hh_prev = hh_del->hh_prev; \ - } - -/* Bucket expansion has the effect of doubling the number of buckets - * and redistributing the items into the new buckets. Ideally the - * items will distribute more or less evenly into the new buckets - * (the extent to which this is true is a measure of the quality of - * the hash function as it applies to the key domain). - * - * With the items distributed into more buckets, the chain length - * (item count) in each bucket is reduced. Thus by expanding buckets - * the hash keeps a bound on the chain length. This bounded chain - * length is the essence of how a hash provides constant time lookup. - * - * The calculation of tbl->ideal_chain_maxlen below deserves some - * explanation. First, keep in mind that we're calculating the ideal - * maximum chain length based on the *new* (doubled) bucket count. - * In fractions this is just n/b (n=number of items,b=new num buckets). - * Since the ideal chain length is an integer, we want to calculate - * ceil(n/b). We don't depend on floating point arithmetic in this - * hash, so to calculate ceil(n/b) with integers we could write - * - * ceil(n/b) = (n/b) + ((n%b)?1:0) - * - * and in fact a previous version of this hash did just that. - * But now we have improved things a bit by recognizing that b is - * always a power of two. We keep its base 2 log handy (call it lb), - * so now we can write this with a bit shift and logical AND: - * - * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) - * - */ -#define HASH_EXPAND_BUCKETS(tbl) \ -do { \ - unsigned _he_bkt; \ - unsigned _he_bkt_i; \ - struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ - UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ - _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ - 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ - if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ - memset(_he_new_buckets, 0, \ - 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ - tbl->ideal_chain_maxlen = \ - (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ - ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ - tbl->nonideal_items = 0; \ - for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ - { \ - _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ - while (_he_thh) { \ - _he_hh_nxt = _he_thh->hh_next; \ - HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ - _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ - if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ - tbl->nonideal_items++; \ - _he_newbkt->expand_mult = _he_newbkt->count / \ - tbl->ideal_chain_maxlen; \ - } \ - _he_thh->hh_prev = NULL; \ - _he_thh->hh_next = _he_newbkt->hh_head; \ - if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ - _he_thh; \ - _he_newbkt->hh_head = _he_thh; \ - _he_thh = _he_hh_nxt; \ - } \ - } \ - uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ - tbl->num_buckets *= 2; \ - tbl->log2_num_buckets++; \ - tbl->buckets = _he_new_buckets; \ - tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ - (tbl->ineff_expands+1) : 0; \ - if (tbl->ineff_expands > 1) { \ - tbl->noexpand=1; \ - uthash_noexpand_fyi(tbl); \ - } \ - uthash_expand_fyi(tbl); \ -} while(0) - - -/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ -/* Note that HASH_SORT assumes the hash handle name to be hh. - * HASH_SRT was added to allow the hash handle name to be passed in. */ -#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) -#define HASH_SRT(hh,head,cmpfcn) \ -do { \ - unsigned _hs_i; \ - unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ - struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ - if (head) { \ - _hs_insize = 1; \ - _hs_looping = 1; \ - _hs_list = &((head)->hh); \ - while (_hs_looping) { \ - _hs_p = _hs_list; \ - _hs_list = NULL; \ - _hs_tail = NULL; \ - _hs_nmerges = 0; \ - while (_hs_p) { \ - _hs_nmerges++; \ - _hs_q = _hs_p; \ - _hs_psize = 0; \ - for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ - _hs_psize++; \ - _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ - ((void*)((char*)(_hs_q->next) + \ - (head)->hh.tbl->hho)) : NULL); \ - if (! (_hs_q) ) break; \ - } \ - _hs_qsize = _hs_insize; \ - while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ - if (_hs_psize == 0) { \ - _hs_e = _hs_q; \ - _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ - ((void*)((char*)(_hs_q->next) + \ - (head)->hh.tbl->hho)) : NULL); \ - _hs_qsize--; \ - } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ - _hs_e = _hs_p; \ - if (_hs_p){ \ - _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ - ((void*)((char*)(_hs_p->next) + \ - (head)->hh.tbl->hho)) : NULL); \ - } \ - _hs_psize--; \ - } else if (( \ - cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ - DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ - ) <= 0) { \ - _hs_e = _hs_p; \ - if (_hs_p){ \ - _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ - ((void*)((char*)(_hs_p->next) + \ - (head)->hh.tbl->hho)) : NULL); \ - } \ - _hs_psize--; \ - } else { \ - _hs_e = _hs_q; \ - _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ - ((void*)((char*)(_hs_q->next) + \ - (head)->hh.tbl->hho)) : NULL); \ - _hs_qsize--; \ - } \ - if ( _hs_tail ) { \ - _hs_tail->next = ((_hs_e) ? \ - ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ - } else { \ - _hs_list = _hs_e; \ - } \ - if (_hs_e) { \ - _hs_e->prev = ((_hs_tail) ? \ - ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ - } \ - _hs_tail = _hs_e; \ - } \ - _hs_p = _hs_q; \ - } \ - if (_hs_tail){ \ - _hs_tail->next = NULL; \ - } \ - if ( _hs_nmerges <= 1 ) { \ - _hs_looping=0; \ - (head)->hh.tbl->tail = _hs_tail; \ - DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ - } \ - _hs_insize *= 2; \ - } \ - HASH_FSCK(hh,head); \ - } \ -} while (0) - -/* This function selects items from one hash into another hash. - * The end result is that the selected items have dual presence - * in both hashes. There is no copy of the items made; rather - * they are added into the new hash through a secondary hash - * hash handle that must be present in the structure. */ -#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ -do { \ - unsigned _src_bkt, _dst_bkt; \ - void *_last_elt=NULL, *_elt; \ - UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ - ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ - if (src) { \ - for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ - for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ - _src_hh; \ - _src_hh = _src_hh->hh_next) { \ - _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ - if (cond(_elt)) { \ - _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ - _dst_hh->key = _src_hh->key; \ - _dst_hh->keylen = _src_hh->keylen; \ - _dst_hh->hashv = _src_hh->hashv; \ - _dst_hh->prev = _last_elt; \ - _dst_hh->next = NULL; \ - if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ - if (!dst) { \ - DECLTYPE_ASSIGN(dst,_elt); \ - HASH_MAKE_TABLE(hh_dst,dst); \ - } else { \ - _dst_hh->tbl = (dst)->hh_dst.tbl; \ - } \ - HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ - HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ - (dst)->hh_dst.tbl->num_items++; \ - _last_elt = _elt; \ - _last_elt_hh = _dst_hh; \ - } \ - } \ - } \ - } \ - HASH_FSCK(hh_dst,dst); \ -} while (0) - -#define HASH_CLEAR(hh,head) \ -do { \ - if (head) { \ - uthash_free((head)->hh.tbl->buckets, \ - (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ - HASH_BLOOM_FREE((head)->hh.tbl); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - (head)=NULL; \ - } \ -} while(0) - -#define HASH_OVERHEAD(hh,head) \ - ((head) ? ( \ - (size_t)((((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ - ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ - (sizeof(UT_hash_table)) + \ - (HASH_BLOOM_BYTELEN)))) : 0) - -#ifdef NO_DECLTYPE -#define HASH_ITER(hh,head,el,tmp) \ -for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ - el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) -#else -#define HASH_ITER(hh,head,el,tmp) \ -for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ - el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) -#endif - -/* obtain a count of items in the hash */ -#define HASH_COUNT(head) HASH_CNT(hh,head) -#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) - -typedef struct UT_hash_bucket { - struct UT_hash_handle *hh_head; - unsigned count; - - /* expand_mult is normally set to 0. In this situation, the max chain length - * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If - * the bucket's chain exceeds this length, bucket expansion is triggered). - * However, setting expand_mult to a non-zero value delays bucket expansion - * (that would be triggered by additions to this particular bucket) - * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. - * (The multiplier is simply expand_mult+1). The whole idea of this - * multiplier is to reduce bucket expansions, since they are expensive, in - * situations where we know that a particular bucket tends to be overused. - * It is better to let its chain length grow to a longer yet-still-bounded - * value, than to do an O(n) bucket expansion too often. - */ - unsigned expand_mult; - -} UT_hash_bucket; - -/* random signature used only to find hash tables in external analysis */ -#define HASH_SIGNATURE 0xa0111fe1 -#define HASH_BLOOM_SIGNATURE 0xb12220f2 - -typedef struct UT_hash_table { - UT_hash_bucket *buckets; - unsigned num_buckets, log2_num_buckets; - unsigned num_items; - struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ - ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ - - /* in an ideal situation (all buckets used equally), no bucket would have - * more than ceil(#items/#buckets) items. that's the ideal chain length. */ - unsigned ideal_chain_maxlen; - - /* nonideal_items is the number of items in the hash whose chain position - * exceeds the ideal chain maxlen. these items pay the penalty for an uneven - * hash distribution; reaching them in a chain traversal takes >ideal steps */ - unsigned nonideal_items; - - /* ineffective expands occur when a bucket doubling was performed, but - * afterward, more than half the items in the hash had nonideal chain - * positions. If this happens on two consecutive expansions we inhibit any - * further expansion, as it's not helping; this happens when the hash - * function isn't a good fit for the key domain. When expansion is inhibited - * the hash will still work, albeit no longer in constant time. */ - unsigned ineff_expands, noexpand; - - uint32_t signature; /* used only to find hash tables in external analysis */ -#ifdef HASH_BLOOM - uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ - uint8_t *bloom_bv; - char bloom_nbits; -#endif - -} UT_hash_table; - -typedef struct UT_hash_handle { - struct UT_hash_table *tbl; - void *prev; /* prev element in app order */ - void *next; /* next element in app order */ - struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ - struct UT_hash_handle *hh_next; /* next hh in bucket order */ - void *key; /* ptr to enclosing struct's key */ - unsigned keylen; /* enclosing struct's key len */ - unsigned hashv; /* result of hash-fcn(key) */ -} UT_hash_handle; - -#endif /* UTHASH_H */ diff --git a/gomspace/libutil/include/gs/uthash/utlist.h b/gomspace/libutil/include/gs/uthash/utlist.h deleted file mode 100644 index b5f3f04c..00000000 --- a/gomspace/libutil/include/gs/uthash/utlist.h +++ /dev/null @@ -1,757 +0,0 @@ -/* -Copyright (c) 2007-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -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. -*/ - -#ifndef UTLIST_H -#define UTLIST_H - -#define UTLIST_VERSION 1.9.9 - -#include - -/* - * This file contains macros to manipulate singly and doubly-linked lists. - * - * 1. LL_ macros: singly-linked lists. - * 2. DL_ macros: doubly-linked lists. - * 3. CDL_ macros: circular doubly-linked lists. - * - * To use singly-linked lists, your structure must have a "next" pointer. - * To use doubly-linked lists, your structure must "prev" and "next" pointers. - * Either way, the pointer to the head of the list must be initialized to NULL. - * - * ----------------.EXAMPLE ------------------------- - * struct item { - * int id; - * struct item *prev, *next; - * } - * - * struct item *list = NULL: - * - * int main() { - * struct item *item; - * ... allocate and populate item ... - * DL_APPEND(list, item); - * } - * -------------------------------------------------- - * - * For doubly-linked lists, the append and delete macros are O(1) - * For singly-linked lists, append and delete are O(n) but prepend is O(1) - * The sort macro is O(n log(n)) for all types of single/double/circular lists. - */ - -/* These macros use decltype or the earlier __typeof GNU extension. - As decltype is only available in newer compilers (VS2010 or gcc 4.3+ - when compiling c++ code), this code uses whatever method is needed - or, for VS2008 where neither is available, uses casting workarounds. */ -#ifdef _MSC_VER /* MS compiler */ -#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ -#define LDECLTYPE(x) decltype(x) -#else /* VS2008 or older (or VS2010 in C mode) */ -#define NO_DECLTYPE -#define LDECLTYPE(x) char* -#endif -#elif defined(__ICCARM__) -#define NO_DECLTYPE -#define LDECLTYPE(x) char* -#else /* GNU, Sun and other compilers */ -#define LDECLTYPE(x) __typeof(x) -#endif - -/* for VS2008 we use some workarounds to get around the lack of decltype, - * namely, we always reassign our tmp variable to the list head if we need - * to dereference its prev/next pointers, and save/restore the real head.*/ -#ifdef NO_DECLTYPE -#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } -#define _NEXT(elt,list,next) ((char*)((list)->next)) -#define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } -/* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */ -#define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } -#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } -#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } -#else -#define _SV(elt,list) -#define _NEXT(elt,list,next) ((elt)->next) -#define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to) -/* #define _PREV(elt,list,prev) ((elt)->prev) */ -#define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) -#define _RS(list) -#define _CASTASGN(a,b) (a)=(b) -#endif - -/****************************************************************************** - * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * - * Unwieldy variable names used here to avoid shadowing passed-in variables. * - *****************************************************************************/ -#define LL_SORT(list, cmp) \ - LL_SORT2(list, cmp, next) - -#define LL_SORT2(list, cmp, next) \ -do { \ - LDECLTYPE(list) _ls_p; \ - LDECLTYPE(list) _ls_q; \ - LDECLTYPE(list) _ls_e; \ - LDECLTYPE(list) _ls_tail; \ - int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ - if (list) { \ - _ls_insize = 1; \ - _ls_looping = 1; \ - while (_ls_looping) { \ - _CASTASGN(_ls_p,list); \ - list = NULL; \ - _ls_tail = NULL; \ - _ls_nmerges = 0; \ - while (_ls_p) { \ - _ls_nmerges++; \ - _ls_q = _ls_p; \ - _ls_psize = 0; \ - for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ - _ls_psize++; \ - _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ - if (!_ls_q) break; \ - } \ - _ls_qsize = _ls_insize; \ - while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ - if (_ls_psize == 0) { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ - } else if (_ls_qsize == 0 || !_ls_q) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ - } else if (cmp(_ls_p,_ls_q) <= 0) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ - } else { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ - } \ - if (_ls_tail) { \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ - } else { \ - _CASTASGN(list,_ls_e); \ - } \ - _ls_tail = _ls_e; \ - } \ - _ls_p = _ls_q; \ - } \ - if (_ls_tail) { \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ - } \ - if (_ls_nmerges <= 1) { \ - _ls_looping=0; \ - } \ - _ls_insize *= 2; \ - } \ - } \ -} while (0) - - -#define DL_SORT(list, cmp) \ - DL_SORT2(list, cmp, prev, next) - -#define DL_SORT2(list, cmp, prev, next) \ -do { \ - LDECLTYPE(list) _ls_p; \ - LDECLTYPE(list) _ls_q; \ - LDECLTYPE(list) _ls_e; \ - LDECLTYPE(list) _ls_tail; \ - int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ - if (list) { \ - _ls_insize = 1; \ - _ls_looping = 1; \ - while (_ls_looping) { \ - _CASTASGN(_ls_p,list); \ - list = NULL; \ - _ls_tail = NULL; \ - _ls_nmerges = 0; \ - while (_ls_p) { \ - _ls_nmerges++; \ - _ls_q = _ls_p; \ - _ls_psize = 0; \ - for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ - _ls_psize++; \ - _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ - if (!_ls_q) break; \ - } \ - _ls_qsize = _ls_insize; \ - while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ - if (_ls_psize == 0) { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ - } else if (_ls_qsize == 0 || !_ls_q) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ - } else if (cmp(_ls_p,_ls_q) <= 0) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ - } else { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ - } \ - if (_ls_tail) { \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ - } else { \ - _CASTASGN(list,_ls_e); \ - } \ - _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ - _ls_tail = _ls_e; \ - } \ - _ls_p = _ls_q; \ - } \ - _CASTASGN(list->prev, _ls_tail); \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ - if (_ls_nmerges <= 1) { \ - _ls_looping=0; \ - } \ - _ls_insize *= 2; \ - } \ - } \ -} while (0) - -#define CDL_SORT(list, cmp) \ - CDL_SORT2(list, cmp, prev, next) - -#define CDL_SORT2(list, cmp, prev, next) \ -do { \ - LDECLTYPE(list) _ls_p; \ - LDECLTYPE(list) _ls_q; \ - LDECLTYPE(list) _ls_e; \ - LDECLTYPE(list) _ls_tail; \ - LDECLTYPE(list) _ls_oldhead; \ - LDECLTYPE(list) _tmp; \ - int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ - if (list) { \ - _ls_insize = 1; \ - _ls_looping = 1; \ - while (_ls_looping) { \ - _CASTASGN(_ls_p,list); \ - _CASTASGN(_ls_oldhead,list); \ - list = NULL; \ - _ls_tail = NULL; \ - _ls_nmerges = 0; \ - while (_ls_p) { \ - _ls_nmerges++; \ - _ls_q = _ls_p; \ - _ls_psize = 0; \ - for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ - _ls_psize++; \ - _SV(_ls_q,list); \ - if (_NEXT(_ls_q,list,next) == _ls_oldhead) { \ - _ls_q = NULL; \ - } else { \ - _ls_q = _NEXT(_ls_q,list,next); \ - } \ - _RS(list); \ - if (!_ls_q) break; \ - } \ - _ls_qsize = _ls_insize; \ - while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ - if (_ls_psize == 0) { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ - if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ - } else if (_ls_qsize == 0 || !_ls_q) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ - if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ - } else if (cmp(_ls_p,_ls_q) <= 0) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ - if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ - } else { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ - if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ - } \ - if (_ls_tail) { \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ - } else { \ - _CASTASGN(list,_ls_e); \ - } \ - _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ - _ls_tail = _ls_e; \ - } \ - _ls_p = _ls_q; \ - } \ - _CASTASGN(list->prev,_ls_tail); \ - _CASTASGN(_tmp,list); \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list); \ - if (_ls_nmerges <= 1) { \ - _ls_looping=0; \ - } \ - _ls_insize *= 2; \ - } \ - } \ -} while (0) - -/****************************************************************************** - * singly linked list macros (non-circular) * - *****************************************************************************/ -#define LL_PREPEND(head,add) \ - LL_PREPEND2(head,add,next) - -#define LL_PREPEND2(head,add,next) \ -do { \ - (add)->next = head; \ - head = add; \ -} while (0) - -#define LL_CONCAT(head1,head2) \ - LL_CONCAT2(head1,head2,next) - -#define LL_CONCAT2(head1,head2,next) \ -do { \ - LDECLTYPE(head1) _tmp; \ - if (head1) { \ - _tmp = head1; \ - while (_tmp->next) { _tmp = _tmp->next; } \ - _tmp->next=(head2); \ - } else { \ - (head1)=(head2); \ - } \ -} while (0) - -#define LL_APPEND(head,add) \ - LL_APPEND2(head,add,next) - -#define LL_APPEND2(head,add,next) \ -do { \ - LDECLTYPE(head) _tmp; \ - (add)->next=NULL; \ - if (head) { \ - _tmp = head; \ - while (_tmp->next) { _tmp = _tmp->next; } \ - _tmp->next=(add); \ - } else { \ - (head)=(add); \ - } \ -} while (0) - -#define LL_DELETE(head,del) \ - LL_DELETE2(head,del,next) - -#define LL_DELETE2(head,del,next) \ -do { \ - LDECLTYPE(head) _tmp; \ - if ((head) == (del)) { \ - (head)=(head)->next; \ - } else { \ - _tmp = head; \ - while (_tmp->next && (_tmp->next != (del))) { \ - _tmp = _tmp->next; \ - } \ - if (_tmp->next) { \ - _tmp->next = ((del)->next); \ - } \ - } \ -} while (0) - -/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ -#define LL_APPEND_VS2008(head,add) \ - LL_APPEND2_VS2008(head,add,next) - -#define LL_APPEND2_VS2008(head,add,next) \ -do { \ - if (head) { \ - (add)->next = head; /* use add->next as a temp variable */ \ - while ((add)->next->next) { (add)->next = (add)->next->next; } \ - (add)->next->next=(add); \ - } else { \ - (head)=(add); \ - } \ - (add)->next=NULL; \ -} while (0) - -#define LL_DELETE_VS2008(head,del) \ - LL_DELETE2_VS2008(head,del,next) - -#define LL_DELETE2_VS2008(head,del,next) \ -do { \ - if ((head) == (del)) { \ - (head)=(head)->next; \ - } else { \ - char *_tmp = (char*)(head); \ - while ((head)->next && ((head)->next != (del))) { \ - head = (head)->next; \ - } \ - if ((head)->next) { \ - (head)->next = ((del)->next); \ - } \ - { \ - char **_head_alias = (char**)&(head); \ - *_head_alias = _tmp; \ - } \ - } \ -} while (0) -#ifdef NO_DECLTYPE -#undef LL_APPEND -#define LL_APPEND LL_APPEND_VS2008 -#undef LL_DELETE -#define LL_DELETE LL_DELETE_VS2008 -#undef LL_DELETE2 -#define LL_DELETE2 LL_DELETE2_VS2008 -#undef LL_APPEND2 -#define LL_APPEND2 LL_APPEND2_VS2008 -#undef LL_CONCAT /* no LL_CONCAT_VS2008 */ -#undef DL_CONCAT /* no DL_CONCAT_VS2008 */ -#endif -/* end VS2008 replacements */ - -#define LL_COUNT(head,el,counter) \ - LL_COUNT2(head,el,counter,next) \ - -#define LL_COUNT2(head,el,counter,next) \ -{ \ - counter = 0; \ - LL_FOREACH2(head,el,next){ ++counter; } \ -} - -#define LL_FOREACH(head,el) \ - LL_FOREACH2(head,el,next) - -#define LL_FOREACH2(head,el,next) \ - for(el=head;el;el=(el)->next) - -#define LL_FOREACH_SAFE(head,el,tmp) \ - LL_FOREACH_SAFE2(head,el,tmp,next) - -#define LL_FOREACH_SAFE2(head,el,tmp,next) \ - for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) - -#define LL_SEARCH_SCALAR(head,out,field,val) \ - LL_SEARCH_SCALAR2(head,out,field,val,next) - -#define LL_SEARCH_SCALAR2(head,out,field,val,next) \ -do { \ - LL_FOREACH2(head,out,next) { \ - if ((out)->field == (val)) break; \ - } \ -} while(0) - -#define LL_SEARCH(head,out,elt,cmp) \ - LL_SEARCH2(head,out,elt,cmp,next) - -#define LL_SEARCH2(head,out,elt,cmp,next) \ -do { \ - LL_FOREACH2(head,out,next) { \ - if ((cmp(out,elt))==0) break; \ - } \ -} while(0) - -#define LL_REPLACE_ELEM(head, el, add) \ -do { \ - LDECLTYPE(head) _tmp; \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ - (add)->next = (el)->next; \ - if ((head) == (el)) { \ - (head) = (add); \ - } else { \ - _tmp = head; \ - while (_tmp->next && (_tmp->next != (el))) { \ - _tmp = _tmp->next; \ - } \ - if (_tmp->next) { \ - _tmp->next = (add); \ - } \ - } \ -} while (0) - -#define LL_PREPEND_ELEM(head, el, add) \ -do { \ - LDECLTYPE(head) _tmp; \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ - (add)->next = (el); \ - if ((head) == (el)) { \ - (head) = (add); \ - } else { \ - _tmp = head; \ - while (_tmp->next && (_tmp->next != (el))) { \ - _tmp = _tmp->next; \ - } \ - if (_tmp->next) { \ - _tmp->next = (add); \ - } \ - } \ -} while (0) \ - - -/****************************************************************************** - * doubly linked list macros (non-circular) * - *****************************************************************************/ -#define DL_PREPEND(head,add) \ - DL_PREPEND2(head,add,prev,next) - -#define DL_PREPEND2(head,add,prev,next) \ -do { \ - (add)->next = head; \ - if (head) { \ - (add)->prev = (head)->prev; \ - (head)->prev = (add); \ - } else { \ - (add)->prev = (add); \ - } \ - (head) = (add); \ -} while (0) - -#define DL_APPEND(head,add) \ - DL_APPEND2(head,add,prev,next) - -#define DL_APPEND2(head,add,prev,next) \ -do { \ - if (head) { \ - (add)->prev = (head)->prev; \ - (head)->prev->next = (add); \ - (head)->prev = (add); \ - (add)->next = NULL; \ - } else { \ - (head)=(add); \ - (head)->prev = (head); \ - (head)->next = NULL; \ - } \ -} while (0) - -#define DL_CONCAT(head1,head2) \ - DL_CONCAT2(head1,head2,prev,next) - -#define DL_CONCAT2(head1,head2,prev,next) \ -do { \ - LDECLTYPE(head1) _tmp; \ - if (head2) { \ - if (head1) { \ - _tmp = (head2)->prev; \ - (head2)->prev = (head1)->prev; \ - (head1)->prev->next = (head2); \ - (head1)->prev = _tmp; \ - } else { \ - (head1)=(head2); \ - } \ - } \ -} while (0) - -#define DL_DELETE(head,del) \ - DL_DELETE2(head,del,prev,next) - -#define DL_DELETE2(head,del,prev,next) \ -do { \ - assert((del)->prev != NULL); \ - if ((del)->prev == (del)) { \ - (head)=NULL; \ - } else if ((del)==(head)) { \ - (del)->next->prev = (del)->prev; \ - (head) = (del)->next; \ - } else { \ - (del)->prev->next = (del)->next; \ - if ((del)->next) { \ - (del)->next->prev = (del)->prev; \ - } else { \ - (head)->prev = (del)->prev; \ - } \ - } \ -} while (0) - -#define DL_COUNT(head,el,counter) \ - DL_COUNT2(head,el,counter,next) \ - -#define DL_COUNT2(head,el,counter,next) \ -{ \ - counter = 0; \ - DL_FOREACH2(head,el,next){ ++counter; } \ -} - -#define DL_FOREACH(head,el) \ - DL_FOREACH2(head,el,next) - -#define DL_FOREACH2(head,el,next) \ - for(el=head;el;el=(el)->next) - -/* this version is safe for deleting the elements during iteration */ -#define DL_FOREACH_SAFE(head,el,tmp) \ - DL_FOREACH_SAFE2(head,el,tmp,next) - -#define DL_FOREACH_SAFE2(head,el,tmp,next) \ - for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) - -/* these are identical to their singly-linked list counterparts */ -#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR -#define DL_SEARCH LL_SEARCH -#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 -#define DL_SEARCH2 LL_SEARCH2 - -#define DL_REPLACE_ELEM(head, el, add) \ -do { \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ - if ((head) == (el)) { \ - (head) = (add); \ - (add)->next = (el)->next; \ - if ((el)->next == NULL) { \ - (add)->prev = (add); \ - } else { \ - (add)->prev = (el)->prev; \ - (add)->next->prev = (add); \ - } \ - } else { \ - (add)->next = (el)->next; \ - (add)->prev = (el)->prev; \ - (add)->prev->next = (add); \ - if ((el)->next == NULL) { \ - (head)->prev = (add); \ - } else { \ - (add)->next->prev = (add); \ - } \ - } \ -} while (0) - -#define DL_PREPEND_ELEM(head, el, add) \ -do { \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ - (add)->next = (el); \ - (add)->prev = (el)->prev; \ - (el)->prev = (add); \ - if ((head) == (el)) { \ - (head) = (add); \ - } else { \ - (add)->prev->next = (add); \ - } \ -} while (0) \ - - -/****************************************************************************** - * circular doubly linked list macros * - *****************************************************************************/ -#define CDL_PREPEND(head,add) \ - CDL_PREPEND2(head,add,prev,next) - -#define CDL_PREPEND2(head,add,prev,next) \ -do { \ - if (head) { \ - (add)->prev = (head)->prev; \ - (add)->next = (head); \ - (head)->prev = (add); \ - (add)->prev->next = (add); \ - } else { \ - (add)->prev = (add); \ - (add)->next = (add); \ - } \ -(head)=(add); \ -} while (0) - -#define CDL_DELETE(head,del) \ - CDL_DELETE2(head,del,prev,next) - -#define CDL_DELETE2(head,del,prev,next) \ -do { \ - if ( ((head)==(del)) && ((head)->next == (head))) { \ - (head) = 0L; \ - } else { \ - (del)->next->prev = (del)->prev; \ - (del)->prev->next = (del)->next; \ - if ((del) == (head)) (head)=(del)->next; \ - } \ -} while (0) - -#define CDL_COUNT(head,el,counter) \ - CDL_COUNT2(head,el,counter,next) \ - -#define CDL_COUNT2(head, el, counter,next) \ -{ \ - counter = 0; \ - CDL_FOREACH2(head,el,next){ ++counter; } \ -} - -#define CDL_FOREACH(head,el) \ - CDL_FOREACH2(head,el,next) - -#define CDL_FOREACH2(head,el,next) \ - for(el=head;el;el=((el)->next==head ? 0L : (el)->next)) - -#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ - CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) - -#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \ - for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ - (el) && ((tmp2)=(el)->next, 1); \ - ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) - -#define CDL_SEARCH_SCALAR(head,out,field,val) \ - CDL_SEARCH_SCALAR2(head,out,field,val,next) - -#define CDL_SEARCH_SCALAR2(head,out,field,val,next) \ -do { \ - CDL_FOREACH2(head,out,next) { \ - if ((out)->field == (val)) break; \ - } \ -} while(0) - -#define CDL_SEARCH(head,out,elt,cmp) \ - CDL_SEARCH2(head,out,elt,cmp,next) - -#define CDL_SEARCH2(head,out,elt,cmp,next) \ -do { \ - CDL_FOREACH2(head,out,next) { \ - if ((cmp(out,elt))==0) break; \ - } \ -} while(0) - -#define CDL_REPLACE_ELEM(head, el, add) \ -do { \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ - if ((el)->next == (el)) { \ - (add)->next = (add); \ - (add)->prev = (add); \ - (head) = (add); \ - } else { \ - (add)->next = (el)->next; \ - (add)->prev = (el)->prev; \ - (add)->next->prev = (add); \ - (add)->prev->next = (add); \ - if ((head) == (el)) { \ - (head) = (add); \ - } \ - } \ -} while (0) - -#define CDL_PREPEND_ELEM(head, el, add) \ -do { \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ - (add)->next = (el); \ - (add)->prev = (el)->prev; \ - (el)->prev = (add); \ - (add)->prev->next = (add); \ - if ((head) == (el)) { \ - (head) = (add); \ - } \ -} while (0) \ - -#endif /* UTLIST_H */ - diff --git a/gomspace/libutil/include/gs/uthash/utstring.h b/gomspace/libutil/include/gs/uthash/utstring.h deleted file mode 100644 index 867442c8..00000000 --- a/gomspace/libutil/include/gs/uthash/utstring.h +++ /dev/null @@ -1,393 +0,0 @@ -/* -Copyright (c) 2008-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -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. -*/ - -/* a dynamic string implementation using macros - */ -#ifndef UTSTRING_H -#define UTSTRING_H - -#define UTSTRING_VERSION 1.9.9 - -#ifdef __GNUC__ -#define _UNUSED_ __attribute__ ((__unused__)) -#else -#define _UNUSED_ -#endif - -#include -#include -#include -#include -#define oom() exit(-1) - -typedef struct { - char *d; - size_t n; /* allocd size */ - size_t i; /* index of first unused byte */ -} UT_string; - -#define utstring_reserve(s,amt) \ -do { \ - if (((s)->n - (s)->i) < (size_t)(amt)) { \ - (s)->d = (char*)realloc((s)->d, (s)->n + amt); \ - if ((s)->d == NULL) oom(); \ - (s)->n += amt; \ - } \ -} while(0) - -#define utstring_init(s) \ -do { \ - (s)->n = 0; (s)->i = 0; (s)->d = NULL; \ - utstring_reserve(s,100); \ - (s)->d[0] = '\0'; \ -} while(0) - -#define utstring_done(s) \ -do { \ - if ((s)->d != NULL) free((s)->d); \ - (s)->n = 0; \ -} while(0) - -#define utstring_free(s) \ -do { \ - utstring_done(s); \ - free(s); \ -} while(0) - -#define utstring_new(s) \ -do { \ - s = (UT_string*)calloc(sizeof(UT_string),1); \ - if (!s) oom(); \ - utstring_init(s); \ -} while(0) - -#define utstring_renew(s) \ -do { \ - if (s) { \ - utstring_clear(s); \ - } else { \ - utstring_new(s); \ - } \ -} while(0) - -#define utstring_clear(s) \ -do { \ - (s)->i = 0; \ - (s)->d[0] = '\0'; \ -} while(0) - -#define utstring_bincpy(s,b,l) \ -do { \ - utstring_reserve((s),(l)+1); \ - if (l) memcpy(&(s)->d[(s)->i], b, l); \ - (s)->i += l; \ - (s)->d[(s)->i]='\0'; \ -} while(0) - -#define utstring_concat(dst,src) \ -do { \ - utstring_reserve((dst),((src)->i)+1); \ - if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \ - (dst)->i += (src)->i; \ - (dst)->d[(dst)->i]='\0'; \ -} while(0) - -#define utstring_len(s) ((unsigned)((s)->i)) - -#define utstring_body(s) ((s)->d) - -_UNUSED_ static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) { - int n; - va_list cp; - while (1) { -#ifdef _WIN32 - cp = ap; -#else - va_copy(cp, ap); -#endif - n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp); - va_end(cp); - - if ((n > -1) && ((size_t) n < (s->n-s->i))) { - s->i += n; - return; - } - - /* Else try again with more space. */ - if (n > -1) utstring_reserve(s,n+1); /* exact */ - else utstring_reserve(s,(s->n)*2); /* 2x */ - } -} -#ifdef __GNUC__ -/* support printf format checking (2=the format string, 3=start of varargs) */ -static void utstring_printf(UT_string *s, const char *fmt, ...) - __attribute__ (( format( printf, 2, 3) )); -#endif -_UNUSED_ static void utstring_printf(UT_string *s, const char *fmt, ...) { - va_list ap; - va_start(ap,fmt); - utstring_printf_va(s,fmt,ap); - va_end(ap); -} - -/******************************************************************************* - * begin substring search functions * - ******************************************************************************/ -/* Build KMP table from left to right. */ -_UNUSED_ static void _utstring_BuildTable( - const char *P_Needle, - size_t P_NeedleLen, - long *P_KMP_Table) -{ - long i, j; - - i = 0; - j = i - 1; - P_KMP_Table[i] = j; - while (i < (long) P_NeedleLen) - { - while ( (j > -1) && (P_Needle[i] != P_Needle[j]) ) - { - j = P_KMP_Table[j]; - } - i++; - j++; - if (i < (long) P_NeedleLen) - { - if (P_Needle[i] == P_Needle[j]) - { - P_KMP_Table[i] = P_KMP_Table[j]; - } - else - { - P_KMP_Table[i] = j; - } - } - else - { - P_KMP_Table[i] = j; - } - } - - return; -} - - -/* Build KMP table from right to left. */ -_UNUSED_ static void _utstring_BuildTableR( - const char *P_Needle, - size_t P_NeedleLen, - long *P_KMP_Table) -{ - long i, j; - - i = P_NeedleLen - 1; - j = i + 1; - P_KMP_Table[i + 1] = j; - while (i >= 0) - { - while ( (j < (long) P_NeedleLen) && (P_Needle[i] != P_Needle[j]) ) - { - j = P_KMP_Table[j + 1]; - } - i--; - j--; - if (i >= 0) - { - if (P_Needle[i] == P_Needle[j]) - { - P_KMP_Table[i + 1] = P_KMP_Table[j + 1]; - } - else - { - P_KMP_Table[i + 1] = j; - } - } - else - { - P_KMP_Table[i + 1] = j; - } - } - - return; -} - - -/* Search data from left to right. ( Multiple search mode. ) */ -_UNUSED_ static long _utstring_find( - const char *P_Haystack, - size_t P_HaystackLen, - const char *P_Needle, - size_t P_NeedleLen, - long *P_KMP_Table) -{ - long i, j; - long V_FindPosition = -1; - - /* Search from left to right. */ - i = j = 0; - while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) ) - { - while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) ) - { - i = P_KMP_Table[i]; - } - i++; - j++; - if (i >= (int)P_NeedleLen) - { - /* Found. */ - V_FindPosition = j - i; - break; - } - } - - return V_FindPosition; -} - - -/* Search data from right to left. ( Multiple search mode. ) */ -_UNUSED_ static long _utstring_findR( - const char *P_Haystack, - size_t P_HaystackLen, - const char *P_Needle, - size_t P_NeedleLen, - long *P_KMP_Table) -{ - long i, j; - long V_FindPosition = -1; - - /* Search from right to left. */ - j = (P_HaystackLen - 1); - i = (P_NeedleLen - 1); - while ( (j >= 0) && (j >= i) ) - { - while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) ) - { - i = P_KMP_Table[i + 1]; - } - i--; - j--; - if (i < 0) - { - /* Found. */ - V_FindPosition = j + 1; - break; - } - } - - return V_FindPosition; -} - - -/* Search data from left to right. ( One time search mode. ) */ -_UNUSED_ static long utstring_find( - UT_string *s, - long P_StartPosition, /* Start from 0. -1 means last position. */ - const char *P_Needle, - size_t P_NeedleLen) -{ - long V_StartPosition; - long V_HaystackLen; - long *V_KMP_Table; - long V_FindPosition = -1; - - if (P_StartPosition < 0) - { - V_StartPosition = s->i + P_StartPosition; - } - else - { - V_StartPosition = P_StartPosition; - } - V_HaystackLen = s->i - V_StartPosition; - if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) - { - V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); - if (V_KMP_Table != NULL) - { - _utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table); - - V_FindPosition = _utstring_find(s->d + V_StartPosition, - V_HaystackLen, - P_Needle, - P_NeedleLen, - V_KMP_Table); - if (V_FindPosition >= 0) - { - V_FindPosition += V_StartPosition; - } - - free(V_KMP_Table); - } - } - - return V_FindPosition; -} - - -/* Search data from right to left. ( One time search mode. ) */ -_UNUSED_ static long utstring_findR( - UT_string *s, - long P_StartPosition, /* Start from 0. -1 means last position. */ - const char *P_Needle, - size_t P_NeedleLen) -{ - long V_StartPosition; - long V_HaystackLen; - long *V_KMP_Table; - long V_FindPosition = -1; - - if (P_StartPosition < 0) - { - V_StartPosition = s->i + P_StartPosition; - } - else - { - V_StartPosition = P_StartPosition; - } - V_HaystackLen = V_StartPosition + 1; - if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) - { - V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); - if (V_KMP_Table != NULL) - { - _utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table); - - V_FindPosition = _utstring_findR(s->d, - V_HaystackLen, - P_Needle, - P_NeedleLen, - V_KMP_Table); - - free(V_KMP_Table); - } - } - - return V_FindPosition; -} -/******************************************************************************* - * end substring search functions * - ******************************************************************************/ - -#endif /* UTSTRING_H */ diff --git a/gomspace/libutil/include/gs/util/base16.h b/gomspace/libutil/include/gs/util/base16.h deleted file mode 100644 index 0fddccc5..00000000 --- a/gomspace/libutil/include/gs/util/base16.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef GS_UTIL_BASE16_H -#define GS_UTIL_BASE16_H -/* - * Copyright (C) 2010 Michael Brown . - * - * This program 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 2 of the - * License, or any later version. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/** - @file - - Encoding and decoding base16 arrays to and from strings. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Calculate length of base16-encoded data - - @param raw_len Raw data length - @return Encoded string length (excluding NUL) -*/ -static inline size_t base16_encoded_len(size_t raw_len) -{ - return (2 * raw_len); -} - -/** - Calculate maximum length of base16-decoded string - @param encoded Encoded string - @return Maximum length of raw data -*/ -static inline size_t base16_decoded_max_len(const char *encoded) -{ - return ((strlen(encoded) + 1) / 2); -} - -/** - Base16-encode data - - The buffer must be the correct length for the encoded string. Use - something like - - char buf[ base16_encoded_len ( len ) + 1 ]; - - (the +1 is for the terminating NUL) to provide a buffer of the - correct size. - - @param raw Raw data - @param len Length of raw data - @param encoded Buffer for encoded string -*/ -void base16_encode(const uint8_t *raw, size_t len, char *encoded); - -/** - Base16-decode data - - The buffer must be large enough to contain the decoded data. Use - something like - - char buf[ base16_decoded_max_len ( encoded ) ]; - - to provide a buffer of the correct size. - - @param encoded Encoded string - @param raw Raw data - @return Length of raw data, or negative error (gs_error_t) -*/ -int base16_decode(const char *encoded, uint8_t *raw); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/bytebuffer.h b/gomspace/libutil/include/gs/util/bytebuffer.h deleted file mode 100644 index ad727e01..00000000 --- a/gomspace/libutil/include/gs/util/bytebuffer.h +++ /dev/null @@ -1,173 +0,0 @@ -#ifndef GS_UTIL_BYTEBUFFER_h -#define GS_UTIL_BYTEBUFFER_h -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Byte buffer provides formatting/serialzing of text/binary data. The buffer keeps track of used space, and prevents overrun. - - The current buffer state can be checked using gs_bytebuffer_state(). - - @dontinclude bytebuffer/bytebuffer_test.c - @skip TEST_gs_bytebuffer_use_case - @until } -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Buffer handle. - Never access handle members directly. -*/ -typedef struct { - /** - Internal: Pointer to user supplied buffer. - @see gs_bytebuffer_init() - */ - uint8_t * buffer; - /** - Internal: Size of user supplied buffer. - @see gs_bytebuffer_init() - */ - size_t size; - /** - Internal: Number of bytes used. - */ - size_t used; - /** - Internal: FUTURE: Committed used - */ - size_t committed_used; - /** - Internal: flags to keep track of buffer state. - */ - uint8_t flags; -} gs_bytebuffer_t; - -/** - Initialize buffer. - - @param[in] bb handle. - @param[in] buffer user supplied buffer of \a buffer_size size (bytes). If NULL, the buffer will keep track of required bytes. - @param[in] buffer_size size of \a buffer. - @return_gs_error_t -*/ -gs_error_t gs_bytebuffer_init(gs_bytebuffer_t * bb, void * buffer, size_t buffer_size); - -/** - Insert data using vprintf. - - @param[in] bb handle. - @param[in] format printf syntax for formatting data - @param[in] ap variable argument list. -*/ -void gs_bytebuffer_vprintf(gs_bytebuffer_t * bb, const char * format, va_list ap); - -/** - Insert data using printf. - - @param[in] bb handle. - @param[in] format printf syntax for formatting data -*/ -void gs_bytebuffer_printf(gs_bytebuffer_t * bb, const char * format, ...) __attribute__ ((format (__printf__, 2, 3))); - -/** - Append data to buffer. - - @param[in] bb handle. - @param[in] data data to append to buffer. - @param[in] length length of data (bytes). -*/ -void gs_bytebuffer_append(gs_bytebuffer_t * bb, const void * data, size_t length); - -/** - Append string to buffer. - - @param[in] bb handle. - @param[in] string string to append to buffer. -*/ -void gs_bytebuffer_append_string(gs_bytebuffer_t * bb, const char * string); - -/** - Append string to buffer. - - @param[in] bb handle. - @param[in] string string to append to buffer. - @param[in] max_length max characters to append from \a string. -*/ -void gs_bytebuffer_append_string_max(gs_bytebuffer_t * bb, const char * string, size_t max_length); - -/** - Return buffer as string - enforcing NUL termination. - - This will always add a NUL termination (zero), which may lead to overflow/truncation of the string. - The NUL termination is NOT added to \a used count. - - @param[in] bb handle. - @param[out] error optional, state of buffer - see gs_bytebuffer_error(). - @return C-string (NUL terminated) -*/ -char * gs_bytebuffer_get_as_string(gs_bytebuffer_t * bb, gs_error_t * error); - -/** - Return buffer state. - - @param[in] bb handle. - @return GS_ERROR_OVERFLOW if data has been truncated. - @return GS_ERROR_DATA in case of error during formatting. - @return_gs_error_t -*/ -gs_error_t gs_bytebuffer_get_state(gs_bytebuffer_t * bb); - -/** - Return buffer (user supplied). - - @param[in] bb handle. -*/ -static inline void * gs_bytebuffer_get_buffer(gs_bytebuffer_t * bb) -{ - return bb->buffer; -} - -/** - Return buffer size (user supplied). - - @param[in] bb handle. - @return buffer size -*/ -static inline size_t gs_bytebuffer_get_size(gs_bytebuffer_t * bb) -{ - return bb->size; -} - -/** - Return number of free bytes. - - @param[in] bb handle. - @return number of free bytes. -*/ -static inline size_t gs_bytebuffer_get_free(gs_bytebuffer_t * bb) -{ - return (bb->size) ? (bb->size - bb->used) : 0; -} - -/** - Return number of used bytes. - - @param[in] bb handle. - @return used bytes. -*/ -static inline size_t gs_bytebuffer_get_used(gs_bytebuffer_t * bb) -{ - return bb->used; -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/byteorder.h b/gomspace/libutil/include/gs/util/byteorder.h deleted file mode 100644 index 3d2d6bef..00000000 --- a/gomspace/libutil/include/gs/util/byteorder.h +++ /dev/null @@ -1,341 +0,0 @@ -#ifndef GS_UTIL_BYTEORDER_H -#define GS_UTIL_BYTEORDER_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Convert numbers between host and network order. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Convert value from host order to network order - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_htons(uint16_t value); - -/** - Convert value from network order to host order - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_ntohs(uint16_t value); - -/** - Convert value from host order to network order - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_htonl(uint32_t value); - -/** - Convert value from network order to host order - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_ntohl(uint32_t value); - -/** - Convert value from host order to network order - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_hton16(uint16_t value); - -/** - Convert value from host order to network order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_hton16_array(const uint16_t * from, uint16_t * to, size_t count); - -/** - Convert value from network order to host order - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_ntoh16(uint16_t value); - -/** - Convert value from network order to host order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_ntoh16_array(const uint16_t * from, uint16_t * to, size_t count); - -/** - Convert value from host order to network order - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_hton32(uint32_t value); - -/** - Convert value from host order to network order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_hton32_array(const uint32_t * from, uint32_t * to, size_t count); - -/** - Convert value from network order to host order - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_ntoh32(uint32_t value); - -/** - Convert value from network order to host order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_ntoh32_array(const uint32_t * from, uint32_t * to, size_t count); - -/** - Convert value from host order to network order - @param[in] value value to convert. - @return converted value. -*/ -uint64_t util_hton64(uint64_t value); - -/** - Convert value from host order to network order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_hton64_array(const uint64_t * from, uint64_t * to, size_t count); - -/** - Convert value from network order to host order - @param[in] value value to convert. - @return converted value. -*/ -uint64_t util_ntoh64(uint64_t value); - -/** - Convert value from network order to host order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_ntoh64_array(const uint64_t * from, uint64_t * to, size_t count); - -/** - Convert value from host order to network order - @param[in] value value to convert. - @return converted value. -*/ -float util_htonflt(float value); - -/** - Convert value from host order to network order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_htonflt_array(const float * from, float * to, size_t count); - -/** - Convert value from network order to host order - @param[in] value value to convert. - @return converted value. -*/ -float util_ntohflt(float value); - -/** - Convert value from network order to host order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_ntohflt_array(const float * from, float * to, size_t count); - -/** - Convert value from host order to network order - @param[in] value value to convert. - @return converted value. -*/ -double util_htondbl(double value); - -/** - Convert value from host order to network order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_htondbl_array(const double * from, double * to, size_t count); - -/** - Convert value from network order to host order - @param[in] value value to convert. - @return converted value. -*/ -double util_ntohdbl(double value); - -/** - Convert value from network order to host order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_ntohdbl_array(const double * from, double * to, size_t count); - -/** - Convert value from host order to big endian. - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_htobe16(uint16_t value); - -/** - Convert value from host order to little endian. - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_htole16(uint16_t value); - -/** - Convert value from big endian to host order. - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_betoh16(uint16_t value); - -/** - Convert value from little endian to host order. - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_letoh16(uint16_t value); - -/** - Convert value from host order to big endian. - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_htobe32(uint32_t value); - -/** - Convert value from host order to little endian. - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_htole32(uint32_t value); - -/** - Convert value from big endian to host order. - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_betoh32(uint32_t value); - -/** - Convert value from little endian to host order. - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_letoh32(uint32_t value); - -/** - Convert value from host order to big endian. - @param[in] value value to convert. - @return converted value. -*/ -uint64_t util_htobe64(uint64_t value); - -/** - Convert value from host order to little endian. - @param[in] value value to convert. - @return converted value. -*/ -uint64_t util_htole64(uint64_t value); - -/** - Convert value from big endian to host order. - @param[in] value value to convert. - @return converted value. -*/ -uint64_t util_betoh64(uint64_t value); - -/** - Convert value from little endian to host order. - @param[in] value value to convert. - @return converted value. -*/ -uint64_t util_letoh64(uint64_t value); - -/** - Byte swap. - @param[in] value value to byteswap. - @return swapped value -*/ -uint16_t gs_bswap_16(uint16_t value); - -/** - Byte swap array. - @param[in] from from address. - @param[out] to to address. - @param[in] count element count. -*/ -void gs_bswap_16_array(const uint16_t * from, uint16_t * to, size_t count); - -/** - Byte swap. - @param[in] value value to byteswap. - @return swapped value -*/ -uint32_t gs_bswap_32(uint32_t value); - -/** - Byte swap array. - @param[in] from from address. - @param[out] to to address. - @param[in] count element count. -*/ -void gs_bswap_32_array(const uint32_t * from, uint32_t * to, size_t count); - -/** - Byte swap. - @param[in] value value to byteswap. - @return swapped value -*/ -uint64_t gs_bswap_64(uint64_t value); - -/** - Byte swap array. - @param[in] from from address. - @param[out] to to address. - @param[in] count element count. -*/ -void gs_bswap_64_array(const uint64_t * from, uint64_t * to, size_t count); - -/** - Byte swap. - @param[in] value value to byteswap. - @return swapped value -*/ -float gs_bswap_float(float value); - -/** - Byte swap array. - @param[in] from from address. - @param[out] to to address. - @param[in] count element count. -*/ -void gs_bswap_float_array(const float * from, float * to, size_t count); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/check.h b/gomspace/libutil/include/gs/util/check.h deleted file mode 100644 index 23920161..00000000 --- a/gomspace/libutil/include/gs/util/check.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef GS_UTIL_CHECK_H -#define GS_UTIL_CHECK_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Argument checking. - - Logs can be enabled through a define. -*/ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if (GS_CHECK_LOG) -#define GS_CHECK_HANDLE(check) if (!(check)) { log_error("Invalid handle - assert: " GS_DEF2STRING(check)); return GS_ERROR_HANDLE;} -#define GS_CHECK_ARG(check) if (!(check)) { log_error("Invalid argument - assert: " GS_DEF2STRING(check)); return GS_ERROR_ARG;} -#define GS_CHECK_SUPPORTED(check) if (!(check)) { log_error("Not supported - assert: " GS_DEF2STRING(check)); return GS_ERROR_NOT_SUPPORTED;} -#define GS_CHECK_RANGE(check) if (!(check)) { log_error("Invalid range - assert: " GS_DEF2STRING(check)); return GS_ERROR_RANGE;} -#else -/** - Perform evalution of 'check' and return GS_ERROR_HANDLE if not 'true'. -*/ -#define GS_CHECK_HANDLE(check) if (!(check)) { return GS_ERROR_HANDLE;} -/** - Perform evalution of 'check' and return GS_ERROR_ARG if not 'true'. -*/ -#define GS_CHECK_ARG(check) if (!(check)) { return GS_ERROR_ARG;} -/** - Perform evalution of 'check' and return GS_ERROR_NOT_SUPPORTED if not 'true'. -*/ -#define GS_CHECK_SUPPORTED(check) if (!(check)) { return GS_ERROR_NOT_SUPPORTED;} -/** - Perform evalution of 'check' and return GS_ERROR_RANGE if not 'true'. -*/ -#define GS_CHECK_RANGE(check) if (!(check)) { return GS_ERROR_RANGE;} -#endif - -/** - Assert on 'value'. - - @deprecated use GS_STATIC_ASSERT() -*/ -#define GS_CHECK_STATIC_ASSERT(condition, name) GS_STATIC_ASSERT(condition, name) - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/clock.h b/gomspace/libutil/include/gs/util/clock.h deleted file mode 100644 index 1d4a9548..00000000 --- a/gomspace/libutil/include/gs/util/clock.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef GS_UTIL_CLOCK_H -#define GS_UTIL_CLOCK_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Get/set time (including RTC), convert to/from string. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Returns real time/clock (UTC - time since Epoch/1970). - - If the platform supports a Real Time Clock, the RTC is normally read on first call. An offset is calculated for the relative clock, which - then is used to calculate the actual time. - - @note clock_get_time() is proto-typed in libcsp as weak, but with different argument which MUST match gs_timestamp_t. - @param[out] time user allocated buffer, contaning the current UTC time. -*/ -void gs_clock_get_time(gs_timestamp_t * time); - -/** - Set real time/clock (UTC). - If the platform supports a Real Time Clock, the RTC is also updated. - @param[in] time UTC time. - @return_gs_error_t -*/ -gs_error_t gs_clock_set_time(const gs_timestamp_t * time); - -/** - Returns elapsed time since some unspecified starting point. - @param[out] time user allocated buffer, receives elapsed time. - @see gs_time_rel_ms() -*/ -void gs_clock_get_monotonic(gs_timestamp_t * time); - -/** - Returns number of elapsed nano-seconds since some unspecified starting point. - @return nano-seconds. -*/ -uint64_t gs_clock_get_nsec(void); - -/** - Buffer length for containing full ISO8601 timestamp - including zero (0) termination. -*/ -#define GS_CLOCK_ISO8601_BUFFER_LENGTH 21 - -/** - Convert UTC to a ISO8601 string. - ISO8601 timestamp: 2017-03-30T06:20:45Z - @param[in] utc_time UTC time. - @param[out] buffer user allocated buffer. - @param[in] buffer_size size of \a buf. - @return_gs_error_t -*/ -gs_error_t gs_clock_to_iso8601_string(const gs_timestamp_t * utc_time, char * buffer, size_t buffer_size); - -/** - Convert UTC to a ISO8601 string. - ISO8601 timestamp: 2017-03-30T06:20:45Z - @param[in] utc_sec UTC seconds. - @param[out] buffer user allocated buffer. - @param[in] buffer_size size of \a buf. - @return_gs_error_t -*/ -gs_error_t gs_clock_to_iso8601_string2(uint32_t utc_sec, char * buffer, size_t buffer_size); - -/** - Convert string (UTC time) to timstamp. - Parse string as: - 1. \.\ - number of seconds elapsed since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). - 2. YYYY-MM-DDTHH:MM:SSZ - ISO8601 - @param[in] str time - @param[out] ts time - @return_gs_error_t -*/ -gs_error_t gs_clock_from_string(const char * str, gs_timestamp_t * ts); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/conf_util.h b/gomspace/libutil/include/gs/util/conf_util.h deleted file mode 100644 index 55831fb5..00000000 --- a/gomspace/libutil/include/gs/util/conf_util.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef W_INCLUDE_CONF_UTIL_H_WAF -#define W_INCLUDE_CONF_UTIL_H_WAF - -#define UTIL_LITTLE_ENDIAN 1 -/* #undef UTIL_BIG_ENDIAN */ -#define GS_CONSOLE_HISTORY_LEN 10 -#define GS_CONSOLE_INPUT_LEN 100 -/* #undef GS_LOG_ENABLE_ISR_LOGS */ - -#endif /* W_INCLUDE_CONF_UTIL_H_WAF */ diff --git a/gomspace/libutil/include/gs/util/crc32.h b/gomspace/libutil/include/gs/util/crc32.h deleted file mode 100644 index f2be6775..00000000 --- a/gomspace/libutil/include/gs/util/crc32.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef GS_UTIL_CRC32_H -#define GS_UTIL_CRC32_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - CRC32 checksumes. - - https://en.wikipedia.org/wiki/Cyclic_redundancy_check. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Return init/seed value for CRC-32. - @return initial/seed value for CRC-32, using 0xffffffff. - @see gs_crc32_update(), gs_crc32_finalize() -*/ -uint32_t gs_crc32_init(void); - -/** - Update CRC-32. - @param[in] crc current CRC-32 - @param[in] block start of memory block. - @param[in] length length of \a block. - @return updated CRC-32. - @see gs_crc32_init(), gs_crc32_finalize() -*/ -uint32_t gs_crc32_update(uint32_t crc, const void * block, size_t length); - -/** - Return finalized CRC-32. - @param[in] crc Checksum is finalized by xor'ing 0xffffffff. - @return finalized CRC-32. - @see gs_crc32_init(), gs_crc32_update() -*/ -uint32_t gs_crc32_finalize(uint32_t crc); - -/** - Return finalized CRC-32 on amemory block. - - @param[in] block block to calculate CRC-32 on. - @param[in] length length/size of \a block. - @return finalized CRC-32. -*/ -uint32_t gs_crc32(const void *block, size_t length); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/crc8.h b/gomspace/libutil/include/gs/util/crc8.h deleted file mode 100644 index 99b14d0a..00000000 --- a/gomspace/libutil/include/gs/util/crc8.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef GS_UTIL_CRC8_H -#define GS_UTIL_CRC8_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - CRC8 checksumes. - - https://en.wikipedia.org/wiki/Cyclic_redundancy_check. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Return init/seed value for CRC-8. - @return initial/seed value for CRC-8, using 0xff. - @see gs_crc8_update(), gs_crc8_finalize() -*/ -uint8_t gs_crc8_init(void); - -/** - Update CRC-8. - @param[in] crc current CRC-8 - @param[in] block start of memory block. - @param[in] length length of \a block. - @return updated CRC-8. - @see gs_crc8_init(), gs_crc8_finalize() -*/ -uint8_t gs_crc8_update(uint8_t crc, const void * block, size_t length); - -/** - Return finalized CRC-8. - @param[in] crc Checksum is finalized by xor'ing 0xffffffff. - @return finalized CRC-8. - @see gs_crc8_init(), gs_crc8_update() -*/ -uint8_t gs_crc8_finalize(uint8_t crc); - -/** - Return finalized CRC-8 on amemory block. - - @param[in] block block to calculate CRC-8 on. - @param[in] length length/size of \a block. - @return finalized CRC-8. -*/ -uint8_t gs_crc8(const void *block, size_t length); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/delay.h b/gomspace/libutil/include/gs/util/delay.h deleted file mode 100644 index d205b48c..00000000 --- a/gomspace/libutil/include/gs/util/delay.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef GS_UTIL_DELAY_H -#define GS_UTIL_DELAY_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Delay execution. - - @note Most implementations uses busy waiting. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Delay for number of microseconds. - @note Linux doesn't busy wait. - @param us Number of microseconds to wait -*/ -void gs_delay_us(uint32_t us); - -/** - Return current counter used for us delays - @return timestamp in us -*/ -uint16_t gs_delay_ts_get(void); - -/** - Wait until delay has passed since timestamp - - @param[in] ts Timestamp in us - @param[in] delay The requested delay since ts -*/ -void gs_delay_from_ts(uint16_t ts, uint16_t delay); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/can/can.h b/gomspace/libutil/include/gs/util/drivers/can/can.h deleted file mode 100644 index 27f7acd5..00000000 --- a/gomspace/libutil/include/gs/util/drivers/can/can.h +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_CAN_CAN_H -#define GS_UTIL_DRIVERS_CAN_CAN_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - CAN interface. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Default log group for CAN driver. -*/ -GS_LOG_GROUP_EXTERN(gs_can_log); - -/** - Bit-rate (default). -*/ -#define GS_CAN_DEFAULT_BPS 1000000 - -/** - Callback for handling received data (from CAN driver). - @param[in] device hardware device - @param[in] canMsgId standard or extended message id. - @param[in] extendedMsgId \a true if extended id, \a false if standard id. - @param[in] data pointer to data. - @param[in] data_size size of data. - @param[in] nowMs current relative time in mS. - @param[in] user_data user data. - @param[in] cswitch If called from within an ISR (embedded platform), this will none NULL. -*/ -typedef void (*gs_can_rxdata_callback_t)(int hdl, - uint32_t canMsgId, - bool extendedMsgId, - const void * data, - size_t data_size, - uint32_t nowMs, - void * user_data, - gs_context_switch_t * cswitch); - -/** - Send CAN message with standard id (11 bits). - @param[in] device hardware device - @param[in] canMsgId standard CAN message id. - @param[in] data pointer to data. - @param[in] data_size size of data. - @param[in] timeout_ms timeout in mS. - @return GS_ERROR_FULL if Tx queue is full - @return_gs_error_t -*/ -gs_error_t gs_can_send_standard(uint8_t device, uint32_t canMsgId, const void * data, size_t data_size, int timeout_ms); - -/** - Send CAN message with exended id (29 bits). - @param[in] device hardware device - @param[in] canExtMsgId exteneded message id. - @param[in] data pointer to data. - @param[in] data_size size of data. - @param[in] timeout_ms timeout in mS. - @return GS_ERROR_FULL if Tx queue is full - @return_gs_error_t -*/ -gs_error_t gs_can_send_extended(uint8_t device, uint32_t canExtMsgId, const void * data, size_t data_size, int timeout_ms); - -/** - Set filter and callback for standard message id. - @param[in] device hardware device - @param[in] canMsgId standard message id. - @param[in] mask filter mask. - @param[in] rx_callback callback function. - @param[in] rx_user_data user data provided in callback. - @return GS_ERROR_FULL if all message id slots are used. - @return_gs_error_t -*/ -gs_error_t gs_can_set_standard_filter_mask(uint8_t device, uint32_t canMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * rx_user_data); - -/** - Set filter and callback for extended message id. - @param[in] device hardware device - @param[in] canExtMsgId extended message id. - @param[in] mask filter mask. - @param[in] rx_callback callback function. - @param[in] rx_user_data user data provided in callback. - @return GS_ERROR_FULL if all message id slots are used. - @return_gs_error_t -*/ -gs_error_t gs_can_set_extended_filter_mask(uint8_t device, uint32_t canExtMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * rx_user_data); - -/** - Stop CAN layer. - If a CAN transceiver is present and controlled, it will be disabled. - @param[in] device hardware device - @return_gs_error_t -*/ -gs_error_t gs_can_stop(uint8_t device); - -/** - Start CAN layer. - Clear all buffers and start CAN. - If a CAN transceiver is present and controlled, it will be enabled. - @param[in] device hardware device - @return_gs_error_t -*/ -gs_error_t gs_can_start(uint8_t device); - -/** - Get current CAN layer error state. - @param[in] device hardware device - @param[out] restart_required \a true if CAN layer should be re-started. Pass NULL, if not wanted. - @return_gs_error_t -*/ -gs_error_t gs_can_error_state(uint8_t device, bool * restart_required); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/gpio/gpio.h b/gomspace/libutil/include/gs/util/drivers/gpio/gpio.h deleted file mode 100644 index ff2803c0..00000000 --- a/gomspace/libutil/include/gs/util/drivers/gpio/gpio.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_GPIO_GPIO_H -#define GS_UTIL_DRIVERS_GPIO_GPIO_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - GPIO interface provides a generic interface toward hardware GPIO's. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - GPIO definition. -*/ -typedef struct { - //! Chip/group/port number which the GPIO belongs to. - uint16_t port; - //! The pin number of the GPIO. - uint16_t pin; -} gs_gpio_t; - -/** - GPIO interrupt function. -*/ -typedef void (*gs_gpio_isr_t)(gs_context_switch_t * cswitch); - -/** - Configuration for interrupt related to a GPIO. -*/ -typedef struct { - //! True if it shall trigger on rising edge. - bool rising_edge; - //! True if it shall trigger on falling edge. - bool falling_edge; - //! True if it shall have high priority (if nested isr supported). - bool high_priority; - //! ISR to be called on trigger. - gs_gpio_isr_t isr; -} gs_interrupt_conf_t; - -/** - GPIO get value - - @param[in] gpio The gpio to read - @param[in] value Returned GPIO value (true/false = High/Low) - @return_gs_error_t -*/ -gs_error_t gs_gpio_get(gs_gpio_t gpio, bool *value); - -/** - GPIO get value without error check - - @param[in] gpio The gpio to read - @return GPIO value (true/false = High/Low) -*/ -bool gs_gpio_get_nc(gs_gpio_t gpio); - -/** - GPIO set value - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @return_gs_error_t -*/ -gs_error_t gs_gpio_set(gs_gpio_t gpio, bool value); - -/** - GPIO set value without error check - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) -*/ -void gs_gpio_set_nc(gs_gpio_t gpio, bool value); - -/** - Initialize GPIO as an external interrupt pin. - - @param[in] gpio The gpio to configure - @param[in] conf Configuration of interrupt pin - @return_gs_error_t - */ -gs_error_t gs_gpio_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/i2c/common.h b/gomspace/libutil/include/gs/util/drivers/i2c/common.h deleted file mode 100644 index 895847d3..00000000 --- a/gomspace/libutil/include/gs/util/drivers/i2c/common.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_I2C_COMMON_H -#define GS_UTIL_DRIVERS_I2C_COMMON_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Common (master and slave) I2C definitions. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Default log group for I2C driver. -*/ -GS_LOG_GROUP_EXTERN(gs_i2c_log); - -/** - I2C mode. -*/ -typedef enum { - //! Master mode - GS_I2C_MASTER = 0, - //! Multimaster mode - GS_I2C_MULTI_MASTER = 1, - //! Slave mode - GS_I2C_SLAVE = 2, -} gs_i2c_mode_t; - -/** - Cross-platform I2C configuration. -*/ -typedef struct { - //! Data order, True: MSB first, False: LSB first (default = True) - bool data_order_msb; - //! Device mode (master, multimaster, or slave) - gs_i2c_mode_t mode; - //! Address of node in multimaster and slave mode (not used in master mode) - uint16_t addr; - //! Bits per second (default is #GS_I2C_DEFAULT_BPS) - uint32_t bps; - //! Address size in bits, 7, 8 or 10 bits (default/prefered is #GS_I2C_DEFAULT_ADDRESS_SIZE) - uint8_t addrbits; -} gs_i2c_config_t; - -/** - Cross-platform I2C configuration. - @deprecated use gs_i2c_config_t. -*/ -typedef gs_i2c_config_t gs_i2c_bus_config_t; - -/** - Default bit-rate. -*/ -#define GS_I2C_DEFAULT_BPS 100000 - -/** - Default address size. -*/ -#define GS_I2C_DEFAULT_ADDRESS_SIZE 7 - -/** - Default data order (MSB). -*/ -#define GS_I2C_DEFAULT_DATA_ORDER_MSB 1 - -/** - Speed (command line sub-option). -*/ -#define GS_I2C_COMMAND_LINE_SPEED "speed" - -/** - Device (command line sub-option). -*/ -#define GS_I2C_COMMAND_LINE_DEVICE "device" - -/** - Address (command line sub-option). -*/ -#define GS_I2C_COMMAND_LINE_ADDRESS "address" - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/i2c/master.h b/gomspace/libutil/include/gs/util/drivers/i2c/master.h deleted file mode 100644 index 169d5d2a..00000000 --- a/gomspace/libutil/include/gs/util/drivers/i2c/master.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_I2C_MASTER_H -#define GS_UTIL_DRIVERS_I2C_MASTER_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - I2C master interface. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Perform transaction to I2C slave. - @param[in] device hardware device (bus) - @param[in] addr slave address - @param[in] tx transmit buffer - @param[in] txlen number of bytes to transmit - @param[out] rx receive buffer - can be NULL. - @param[in] rxlen number of bytes to receive. - @param[in] timeout_ms timeout in milliseconds, primarily for locking the I2C channel. - @return_gs_error_t -*/ -gs_error_t gs_i2c_master_transaction(uint8_t device, uint8_t addr, const void * tx, size_t txlen, void * rx, size_t rxlen, int timeout_ms); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/i2c/slave.h b/gomspace/libutil/include/gs/util/drivers/i2c/slave.h deleted file mode 100644 index 540000e3..00000000 --- a/gomspace/libutil/include/gs/util/drivers/i2c/slave.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_I2C_SLAVE_H -#define GS_UTIL_DRIVERS_I2C_SLAVE_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - I2C slave interface. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Start/enable I2C bus reception. - - Reception should not automatically be enabled by their init() functions, as this will complicate adding additional layers/hooks. - - @param[in] device I2C bus (handle) - @return_gs_error_t -*/ -gs_error_t gs_i2c_slave_start(uint8_t device); - -/** - Rx callback. - - Function called when data has been received on the bus (I2C write operation complete). - - @param[in] device I2C bus (handle). - @param[in] rx receive buffer. - @param[in] rx_length number of bytes received. - @param_cswitch -*/ -typedef void (* gs_i2c_slave_receive_t)(uint8_t device, const uint8_t * rx, size_t rx_length, gs_context_switch_t * cswitch); - -/** - Set rx callback. - - @param[in] device I2C bus (handle). - @param[in] rx Rx callback. - @return_gs_error_t -*/ -gs_error_t gs_i2c_slave_set_rx(uint8_t device, gs_i2c_slave_receive_t rx); - -/** - Get rx buffer callback. - - Function called from driver, for getting a pointer to the rx buffer. - - @param[in] device I2C bus (handle). -*/ -typedef void * (* gs_i2c_slave_get_rx_buf_t)(uint8_t device); - -/** - Set rx buffer get callback. - - @param[in] device I2C bus (handle). - @param[in] get_rx_buf get rx buffer callback. - @param[in] buf_length length of buffer retrieved with this callback. - @return_gs_error_t -*/ -gs_error_t gs_i2c_slave_set_get_rx_buf(uint8_t device, gs_i2c_slave_get_rx_buf_t get_rx_buf, size_t buf_length); - -/** - Set response data. - - @param[in] device I2C bus (handle). - @param[in] tx pointer to data. NOTE: data is not copied due to performance, so data must stay valid until the response has been sent. - @param[in] tx_length length of data. - @return_gs_error_t -*/ -gs_error_t gs_i2c_slave_set_response(uint8_t device, const uint8_t * tx, size_t tx_length); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/spi/common.h b/gomspace/libutil/include/gs/util/drivers/spi/common.h deleted file mode 100644 index 069a346e..00000000 --- a/gomspace/libutil/include/gs/util/drivers/spi/common.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_SPI_COMMON_H -#define GS_UTIL_DRIVERS_SPI_COMMON_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Common (master and slave) SPI definitions. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Default log group for SPI driver. -*/ -GS_LOG_GROUP_EXTERN(gs_spi_log); - -/** - SPI mode - clock polarity and phase. -*/ -typedef enum { - /** - Polarity = 0, Phase = 0 (default). - */ - GS_SPI_MODE_CPOL0_CPHA0 = 0, - /** - Polarity = 0, Phase = 1. - */ - GS_SPI_MODE_CPOL0_CPHA1 = 1, - /** - Polarity = 1, Phase = 0. - */ - GS_SPI_MODE_CPOL1_CPHA0 = 2, - /** - Polarity = 1, Phase = 1. - */ - GS_SPI_MODE_CPOL1_CPHA1 = 3 -} gs_spi_mode_t; - -/** - Default bit-rate. -*/ -#define GS_SPI_DEFAULT_BPS 400000 - -/** - Speed (command line sub-option). -*/ -#define GS_SPI_COMMAND_LINE_SPEED "speed" - -/** - Slave (command line sub-option). -*/ -#define GS_SPI_COMMAND_LINE_SLAVE "slave" - -/** - Device (command line sub-option). -*/ -#define GS_SPI_COMMAND_LINE_DEVICE "device" - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/spi/master.h b/gomspace/libutil/include/gs/util/drivers/spi/master.h deleted file mode 100644 index 986f1ce4..00000000 --- a/gomspace/libutil/include/gs/util/drivers/spi/master.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_SPI_MASTER_H -#define GS_UTIL_DRIVERS_SPI_MASTER_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - SPI master interface. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Cross-platform master SPI configuration. -*/ -typedef struct { - /** - Data order, \a True: MSB first, \a False: LSB first - Default: \a True. - */ - bool data_order_msb; - /** - Bits per second. - Default: #GS_SPI_DEFAULT_BPS. - */ - uint32_t bps; - /** - Mode, specifying polarity and phase. - Default: #GS_SPI_MODE_CPOL0_CPHA0. - */ - gs_spi_mode_t mode; - /** - Character size in bits, 8-16 bits. - Default: 8 bits (prefered). - */ - uint8_t bits; -} gs_spi_master_slave_config_t; - -/** - Single master transaction. -*/ -typedef struct { - /** - Pointer to tx data, or NULL if no tx. - */ - const void *tx; - /** - Pointer to rx buffer, or NULL if no rx. - */ - void *rx; - /** - Size/length of rx/tx (bytes). - */ - size_t size; -} gs_spi_master_trans_t; - -/** - Close/free slave. - Freeing resources associated with the slave. - @param[in] slave SPI slave - @return_gs_error_t -*/ -gs_error_t gs_spi_master_close_slave(uint8_t slave); - -/** - Perform transaction to/from a pre-configured SPI slave. - Basically for i < size: send tx[i] and receive rx[i]. - @note: 8 bit SPI character size required! - @param[in] slave SPI slave - @param[in] tx tx buffer - @param[out] rx rx buffer - can be NULL. - @param[in] size number of to send and also receive. - @param[in] timeout_ms timeout in milliseconds, primarily for locking the SPI device. - @return_gs_error_t -*/ -gs_error_t gs_spi_master_transaction(uint8_t slave, const void * tx, void * rx, size_t size, int timeout_ms); - -/** - Perform N transaction to/from a pre-configured SPI slave within one chip selection - @note: 8 bit SPI character size required! - @param[in] slave SPI slave - @param[in] trans Pointer to transactions - @param[in] count Number of transactions (rx and/or tx) to complete - @param[in] timeout_ms timeout in milliseconds, primarily for locking the SPI device. - @return_gs_error_t -*/ -gs_error_t gs_spi_master_transactions(uint8_t slave, gs_spi_master_trans_t *trans, size_t count, int timeout_ms); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/spi/slave.h b/gomspace/libutil/include/gs/util/drivers/spi/slave.h deleted file mode 100644 index 0be02a8e..00000000 --- a/gomspace/libutil/include/gs/util/drivers/spi/slave.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_SPI_SLAVE_H -#define GS_UTIL_DRIVERS_SPI_SLAVE_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - SPI slave interface. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Cross-platform slave SPI configuration. -*/ -typedef struct { - /** - Data order, \a True: MSB first, \a False: LSB first - Default: \a True. - */ - bool data_order_msb; - /** - Mode, specifying polarity and phase. - Default: #GS_SPI_MODE_CPOL0_CPHA0. - */ - gs_spi_mode_t mode; - /** - Character size in bits, 8-16 bits. - Default: 8 bits (prefered). - */ - uint8_t bits; -} gs_spi_slave_config_t; - -/** - Start/enable SPI device reception. - - Reception should not automatically be enabled by their init() functions, as this will complicate adding additional layers/hooks. - - @param[in] device SPI device (handle) - @return_gs_error_t -*/ -gs_error_t gs_spi_slave_start(uint8_t device); - -/** - Rx callback. - - Function called as data is recevied on the device. - - @param[in] device SPI device (handle). - @param[in] rx_buffer Pointer to start of rx buffer. - @param[in] rx number of bytes received so far. - @param[in] new_request \a true on the first callback of new data, \a false on receiving additional data during same \a chip-select. Can be used to bring receiver back in sync with new request. - @param_cswitch - @return total number of bytes to receive before next call back. Return 0 to ignore rest of data - no additional call backs will be done for current SPI transaction. -*/ -typedef uint8_t (* gs_spi_slave_receive_t)(uint8_t device, const uint8_t * rx_buffer, size_t rx, bool new_request, gs_context_switch_t * cswitch); - -/** - Set rx callback. - - @param[in] device SPI device (handle). - @param[in] rx Rx callback. - @return_gs_error_t -*/ -gs_error_t gs_spi_slave_set_rx(uint8_t device, gs_spi_slave_receive_t rx); - -/** - Set response data. - - @param[in] device SPI device (handle). - @param[in] offset offset (in bytes) for the response, counted from start of request, i.e. offset of 2 means data will be sent as the 3rd byte. - @param[in] tx pointer to data. NOTE: data is not copied due to performance, so data must stay valid until the response has been sent. - @param[in] size size of data. - @return_gs_error_t -*/ -gs_error_t gs_spi_slave_set_response(uint8_t device, size_t offset, const uint8_t * tx, size_t size); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/sys/memory.h b/gomspace/libutil/include/gs/util/drivers/sys/memory.h deleted file mode 100644 index ca3862df..00000000 --- a/gomspace/libutil/include/gs/util/drivers/sys/memory.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_SYS_MEMORY_H -#define GS_UTIL_DRIVERS_SYS_MEMORY_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Cross platform memory status API. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - RAM status - Containing different size parameters describing RAM usage. - All sizes are in bytes. - If a parameter is not available/supported on a specific platform, the parameter is set to -1. - */ -typedef struct { - //! total size of RAM - long total; - //! max available RAM for allocation after initialization of of global/static variables - long max_available; - //! available RAM at runtime for dynamic allocation - long available; - //! Lowest registered available RAM since boot - long min_available; -} gs_mem_ram_stat_t; - -/** - RAM types - Defines the different RAM types (external/internal) supported on - the various platforms. - */ -typedef enum { - GS_MEM_RAM_TYPE_INTERNAL = 0,//!< Internal RAM type - GS_MEM_RAM_TYPE_EXTERNAL //!< External RAM type -} gs_mem_ram_type_t; - -/** - Get status of internal RAM - - @param[out] ram_stat RAM status, each member of struct is -1 if not supported on specific platform - @return_gs_error_t - */ -gs_error_t gs_mem_get_int_ram_stat(gs_mem_ram_stat_t * ram_stat); - -/** - Get status of external RAM - - @param[out] ram_stat RAM status, each member of struct is -1 if not supported on specific platform - @return_gs_error_t - */ -gs_error_t gs_mem_get_ext_ram_stat(gs_mem_ram_stat_t * ram_stat); - - -/** - Get status of selected RAM - - @param[in] type RAM type to query status for - @param[out] ram_stat RAM status, each member of struct is -1 if not supported on specific platform - @return_gs_error_t - */ -gs_error_t gs_mem_get_ram_stat(gs_mem_ram_type_t type, gs_mem_ram_stat_t * ram_stat); - - -/** - Get default RAM type - - returns the default RAM type used for allocations (Heap). - @return gs_mem_ram_type_t - */ -gs_mem_ram_type_t gs_mem_get_ram_default(); - - -/** - Print RAM status. - - @param[in] ram_stat RAM status - @param[in] out output stream - @return_gs_error_t - */ -gs_error_t gs_mem_print_ram_stat(gs_mem_ram_stat_t * ram_stat, FILE * out); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/watchdog/device.h b/gomspace/libutil/include/gs/util/drivers/watchdog/device.h deleted file mode 100644 index 613e511e..00000000 --- a/gomspace/libutil/include/gs/util/drivers/watchdog/device.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_HW_WATCHDOG_H -#define GS_UTIL_DRIVERS_HW_WATCHDOG_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Hardward watchdog (HWWD) device interface. - - Hardware Watchdog interface which provides a generic interface towards - any HWWD. Most HWWD implementation should be able to fit behind - this interface, with just a small "adaption" layer needed. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Hardware watchdog driver interface. -*/ -typedef struct gs_watchdog_dev_ops gs_watchdog_dev_ops_t; - -/** - Hardware watchdog (HWWD) device structure - - Structure that describes the HWWD device and holds - the parameters needed for storing e.g. timeout values etc. -*/ -typedef struct gs_watchdog_device { - int id; /**< An ID for the HWWD device - This is currently not used. */ - const gs_watchdog_dev_ops_t *ops; /**< Pointer to ops struct defining the operations a HWWD device supports. */ - unsigned int timeout; /**< The timeout value that the HWWD device should be configured with. */ - unsigned int pretimeout; /**< The pretimeout (if supported) by the HWWD device */ - unsigned int min_timeout; /**< Minimum timeout value supported by the HWWD device */ - unsigned int max_timeout; /**< Maximum timeout value supported by the HWWD device */ - void *driver_data; /**< Pointer to driver specific data can be used by the HWWD driver impl. */ -} gs_watchdog_device_t; - -/** - Hardware watchdog driver interface. -*/ -struct gs_watchdog_dev_ops -{ - /* mandatory operations */ - gs_error_t (*start)(gs_watchdog_device_t *); /**< Starts the HWWD device */ - gs_error_t (*stop)(gs_watchdog_device_t *); /**< Stops the HWWD device */ - gs_error_t (*ping)(gs_watchdog_device_t *); /**< Polls the HWWD device and restart count-down */ - /* optional operations */ - gs_error_t (*set_timeout)(gs_watchdog_device_t *, unsigned int); /**< (Optional) Set timeout of the HWWD device */ - gs_error_t (*set_pretimeout)(gs_watchdog_device_t *, unsigned int); /**< (Optional) Set Pre-timeout of the HWWD device */ - gs_error_t (*restart)(gs_watchdog_device_t *); /**< (Optional) Restart the HWWD device */ - unsigned int (*get_timeleft)(gs_watchdog_device_t *); /**< (Optional) Get time left until HWWD device times out. */ - int (*status)(gs_watchdog_device_t *); /**< (Optional) Reads status of the HWWD device */ -}; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/endian.h b/gomspace/libutil/include/gs/util/endian.h deleted file mode 100644 index 8e931d8a..00000000 --- a/gomspace/libutil/include/gs/util/endian.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef GS_UTIL_ENDIAN_H -#define GS_UTIL_ENDIAN_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Detecting endian type. -*/ - -// generated by waf configure, defines either UTIL_BIG_ENDIAN or UTIL_LITTLE_ENDIAN -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if !UTIL_BIG_ENDIAN && !UTIL_LITTLE_ENDIAN - #error No endian defined -#endif -#if UTIL_BIG_ENDIAN && UTIL_LITTLE_ENDIAN - #error Both big and little endian defined -#endif - -#include - -/** - Returns \a true if platform is big endian. -*/ -static inline bool gs_endian_big(void) -{ -#if (UTIL_BIG_ENDIAN) - return true; -#else - return false; -#endif -} - -/** - Returns \a true if platform is little endian. -*/ -static inline bool gs_endian_little(void) -{ -#if (UTIL_LITTLE_ENDIAN) - return true; -#else - return false; -#endif -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/error.h b/gomspace/libutil/include/gs/util/error.h deleted file mode 100644 index d1743165..00000000 --- a/gomspace/libutil/include/gs/util/error.h +++ /dev/null @@ -1,199 +0,0 @@ -#ifndef GS_UTIL_ERROR_H -#define GS_UTIL_ERROR_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Common error code definitions. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Common/generic error codes. - Based on POSIX \a errno values, but negative instead of positive. -*/ -typedef enum gs_error_t { - /** - Success - ok (POSIX). - */ - GS_OK = 0, - /** - Operation not permitted (POSIX.1: EPERM). - */ - GS_ERROR_PERM = -1, - /** - Interrupted system call (or Interrupted function call) (POSIX: EINTR). - */ - GS_ERROR_INTR = -4, - /** - Input/output error (POSIX.1: EIO) - */ - GS_ERROR_IO = -5, - /** - Resource temporarily unavailable (may be the same value as EWOULDBLOCK) (POSIX.1: EAGAIN). - */ - GS_ERROR_AGAIN = -11, - /** - Cannot allocate memory (or Not enough space) (POSIX.1: ENOMEM). - */ - GS_ERROR_ALLOC = -12, - /** - Permission denied (POSIX.1: EACCES). - */ - GS_ERROR_ACCESS = -13, - /** - Device or resource busy (POSIX.1: EBUSY). - */ - GS_ERROR_BUSY = -16, - /** - File exists (POSIX.1-2001: EEXIST). - */ - GS_ERROR_EXIST = -17, - /** - Invalid argument (POSIX.1: EINVAL). - */ - GS_ERROR_ARG = -22, - /** - Function not implemented (POSIX.1: ENOSYS) - */ - GS_ERROR_NOT_IMPLEMENTED = -38, - /** - Value too large to be stored in data type (POSIX.1: EOVERFLOW). - Example: trying to put 50 characters into a 10 character array. - @see GS_ERROR_RANGE. - */ - GS_ERROR_OVERFLOW = -75, - /** - Operation not supported (POSIX.1: ENOTSUP) - */ - GS_ERROR_NOT_SUPPORTED = -95, - /** - Address already in use (POSIX.1: EADDRINUSE). - */ - GS_ERROR_IN_USE = -98, - /** - Connection reset (POSIX.1-2001: ECONNRESET). - */ - GS_ERROR_CONNECTION_RESET = -104, - /** - No buffer space available (POSIX.1 (XSI STREAMS option): ENOBUFS). - */ - GS_ERROR_NO_BUFFERS = -105, - /** - Timeout (POSIX.1-2001: ETIMEDOUT). - */ - GS_ERROR_TIMEOUT = -110, - /** - Connection already in progress (POSIX.1-2001: EALREADY). - */ - GS_ERROR_ALREADY_IN_PROGRESS = -114, - - /** - Handle error (GOMspace). - */ - GS_ERROR_HANDLE = -2000, // from errno.h: #define __ELASTERROR 2000 /* Users can add values starting here */ - /** - Not found (GOMspace). - */ - GS_ERROR_NOT_FOUND = -2001, - /** - Full (GOMspace). - */ - GS_ERROR_FULL = -2002, - /** - Range error (GOMspace). - Example: specifying 120 hours, where only 0-23 is valid. - @see GS_ERROR_OVERFLOW - */ - GS_ERROR_RANGE = -2003, - /** - Data error (GOMspace). - */ - GS_ERROR_DATA = -2004, - /** - Unknown error (GOMspace). - @note avoid use - use specific error to improve debugging/troubleshooting. - */ - GS_ERROR_UNKNOWN = -2005, - /** - No data available (GOMspace). - */ - GS_ERROR_NO_DATA = -2006, - /** - Stale data - not updated (GOMspace). - */ - GS_ERROR_STALE = -2007, - /** - Type error (GOMspace). - */ - GS_ERROR_TYPE = -2008, - /** - Ambiguous error (GOMspace). - */ - GS_ERROR_AMBIGUOUS = -2009, - /** - State error (GOMspace). - */ - GS_ERROR_STATE = -2010, - -} gs_error_t; - -/** - * Convert an error code to a string. - * Uses standard POSIX strerror() under the hood. - * @param[in] error error to convert. If negative (e.g. \a gs_error_t), it is first converted to a positive value. - * @return string usefull for logging purposes (should not be used for programatically processing). - */ -const char * gs_error_string(int error); - -/** - Convert standard POSIX \a errno to gs_error_t. - @param[in] error POSIX error code (errno). - @return convert error code, by simply converting to a negative number. -*/ -gs_error_t gs_error(int error); - -#if (GS_UTIL_DEPRECATED_ERROR_CODES) -/** - Legacy error definitions. - @deprecated Use standard gs_error_t codes - these defines are only kept, so very old code (not yet update to use #gs_error_t) can compile. - @{ -*/ -#define E_NO_ERR -1 -#define E_NO_DEVICE -2 -#define E_MALLOC_FAIL -3 -#define E_THREAD_FAIL -4 -#define E_NO_QUEUE -5 -#define E_INVALID_BUF_SIZE -6 -#define E_INVALID_PARAM -7 -#define E_NO_SS -8 -#define E_GARBLED_BUFFER -9 -#define E_FLASH_ERROR -10 -#define E_BOOT_SER -13 -#define E_BOOT_DEBUG -14 -#define E_BOOT_FLASH -15 -#define E_TIMEOUT -16 -#define E_NO_BUFFER -17 -#define E_OUT_OF_MEM -18 -#define E_FAIL -19 -/** @} */ - -/** - Converts legacy error definitions to string. - @deprecated Use standard gs_error_t codes - this function is only kept, so very old code (not yet update to use #gs_error_t) can compile. - @param[in] code error code - @return string describing the error. -*/ -const char * error_string(int code) __attribute__((deprecated)); - -#endif // GS_UTIL_DEPRECATED_ERROR_CODES - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/fletcher.h b/gomspace/libutil/include/gs/util/fletcher.h deleted file mode 100644 index 5b24c23c..00000000 --- a/gomspace/libutil/include/gs/util/fletcher.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef GS_UTIL_FLETCHER_H -#define GS_UTIL_FLETCHER_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Fletcher16 checksum, -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Fletcher16 checksum (read using copy function). - - Data is read from \a data, using the specified \a memcpyfcn function. - - @param[in] data data. - @param[in] size number of \a data bytes. - @param[in] memcpyfcn memory copy function. If NULL is specified, standard memcpy will be used. - @returns fletcher16 checksum -*/ -uint16_t gs_fletcher16_memcpy(const void * data, size_t size, void * (*memcpyfcn)(void *, const void *, size_t)); - -/** - Fletcher16 checksum (read from program memory). - - AVR8: reads from program memory. - Other architectures: identical to gs_fletcher16(). - - @param[in] data_in data. - @param[in] size number of \a data bytes. - @returns fletcher16 checksum -*/ -uint16_t gs_fletcher16_P(const void * data_in, size_t size); - -/** - Fletcher16 checksum. - - @param[in] data data. - @param[in] size number of \a data bytes. - @returns fletcher16 checksum -*/ -uint16_t gs_fletcher16(const void * data, size_t size); - -/** - Fletcher16 working set. - @see gs_fletcher16_init(), gs_fletcher16_update(), gs_fletcher16_finalize() -*/ -typedef struct { - /** - Sum1 - internal. - */ - uint16_t sum1; - /** - Sum2 - internal. - */ - uint16_t sum2; -} gs_fletcher16_t; - -/** - Initialize fletcher16 working set. - @param[in] f16 working set. -*/ -void gs_fletcher16_init(gs_fletcher16_t * f16); - -/** - Update fletcher16 checksum. - @param[in] f16 working set. - @param[in] data data. - @param[in] size number of \a data bytes. -*/ -void gs_fletcher16_update(gs_fletcher16_t * f16, const void * data, size_t size); - -/** - Finalize fletcher16 checksum and return it. - - @param[in] f16 working set. - @returns fletcher16 checksum -*/ -uint16_t gs_fletcher16_finalize(gs_fletcher16_t * f16); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/function_scheduler.h b/gomspace/libutil/include/gs/util/function_scheduler.h deleted file mode 100644 index 229c5031..00000000 --- a/gomspace/libutil/include/gs/util/function_scheduler.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef GS_UTIL_FUNCTION_SCHEDULER -#define GS_UTIL_FUNCTION_SCHEDULER -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Function scheduler. - - Simple framework for invoking functions at intervals. - - Instead of creating a lot of tasks (which uses memory), this framework can be used to schedule execution of functions at specified intervals. - - Once setup, calling gs_function_scheduler_execute_ms() will execute all functions timed out and return the time, until the next function has - to be executed or max timeout specified (or max wait time supported on the platform). - - The API supports multiple schedulers, but is not thread-safe. - - @note Do NOT use for time critical control, as the actual time interval is influenced by the host thread and other scheduled functions. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Scheduler handle. -*/ -typedef struct gs_function_scheduler gs_function_scheduler_t; - -/** - Function callback. - - @return timeout in mS until next callback. -*/ -typedef uint32_t (*gs_function_scheduler_function_t)(void * user_data); - -/** - Initialize scheduler. - Memory is allocated once for \a max_entries. - @param[in] max_timeout_ms max timeout in mS. - @param[in] max_entries max number of entries for this scheduler. - @param[out] scheduler reference to created scheduler. - @return_gs_error_t -*/ -gs_error_t gs_function_scheduler_create(uint32_t max_timeout_ms, unsigned int max_entries, gs_function_scheduler_t ** scheduler); - -/** - Free scheduler (release resources). - @param[in] scheduler scheduler. - @return_gs_error_t -*/ -gs_error_t gs_function_scheduler_destroy(gs_function_scheduler_t * scheduler); - -/** - Execute scheduled function(s) and returns number of mS until next execute must be called again. - - @note Return type is \a int to prevent overflow on platforms where int is less than 32 bits. - - @param[in] scheduler scheduler. - @return next timeout in mS. -*/ -int gs_function_scheduler_execute_ms(gs_function_scheduler_t * scheduler); - -/** - Register function to be executed at mS intervals. - @param[in] scheduler scheduler. - @param[in] first_timeout_ms mS until first execution. - @param[in] func function to execute. - @param[in] user_data function user data. - @return_gs_error_t -*/ -gs_error_t gs_function_scheduler_register_ms(gs_function_scheduler_t * scheduler, uint32_t first_timeout_ms, gs_function_scheduler_function_t func, void * user_data); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/gosh/command.h b/gomspace/libutil/include/gs/util/gosh/command.h deleted file mode 100644 index 8187152e..00000000 --- a/gomspace/libutil/include/gs/util/gosh/command.h +++ /dev/null @@ -1,503 +0,0 @@ -#ifndef GS_UTIL_GOSH_COMMAND_H -#define GS_UTIL_GOSH_COMMAND_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Command framework. - - Provides a simple way of organizing commands in a hierarchy. A command is a text string mapping to a function - supporting arguments. -*/ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Max langth of a command (including NUL termination). -*/ -#define GS_COMMAND_MAX_LEN_COMMAND 20 - -/** - Flag for hiding command in help and tab-complete. -*/ -#define GS_COMMAND_FLAG_HIDDEN 0x02 - -/** - 'root' command attribute. - - On embedded (none Linux) systems, it is prefered to store as much as possible in \a program memory, in order to save RAM. - This is accomplished by tagging all \a root commands with this attribute, which instructs the linker to put all commands in a named - section. This section is then through the linker-script, placed in \a program memory. - The command framework can read commands directly from this section, and therefore doesn't need an RAM to maintain the list. - - The gs_command_register() must still be called for all \a root commands, which ensures that the linker doesn't throw away the - command objects, due to missing code reference. - - On a Linux system, the commands are not group in a section. Instead gs_command_register() dynamicly builds a list with the commands. - - @see gs_command_register() -*/ -#if (__linux__ == 0) -#define GS_COMMAND_ROOT __attribute__ ((section(".commands"))) -#else -#define GS_COMMAND_ROOT -#endif - -/** - Sub command attribute, - - Only necesasry on AVR8, due to its memory model. -*/ -#define GS_COMMAND_SUB GS_PGM_OBJECT - -/** - Macro for initializing command chains. -*/ -#define GS_COMMAND_INIT_CHAIN(__list) {.list = __list, .count = GS_ARRAY_SIZE(__list)} - -/** - Macro for registering commands. - - @see gs_command_register() -*/ -#define GS_COMMAND_REGISTER(__cmd) gs_command_register(__cmd, GS_ARRAY_SIZE(__cmd)) - -/** - Command reference. - @note Use gs_command_t instead of 'struct command'. -*/ -typedef struct command gs_command_t; - -/** - Commands context reference - @note Use gs_command_context_t instead of struct command_context - */ -typedef struct command_context gs_command_context_t; - -/** - Command output interface -*/ -typedef struct command_io_functions { - /** - Function interface for setting result - @param output_ctx pointer to output context for the given impl. - @param group Group name specifies the group that a given key/value pair belongs to. - @param key key name - @param value string value of the result - @return_gs_error_t - */ - gs_error_t (*set_result)(gs_command_context_t *ctx, const char *group, const char *key, const char *value); - /** - Function interface for flushing results. Used by the command handler to ensure output/results - are flushed to stdout/File or any other receiver of the output. - @param output_ctx pointer to output context for the given impl. - @return_gs_error_t - */ - gs_error_t (*flush)(gs_command_context_t *ctx); - /** - Function interface for waiting for key/input - @param output_ctx pointer to output context for the given impl. - @param ch pointer to character returned by function - @param timeout_ms maximum time to wait of the character. - @return_gs_error_t - */ - gs_error_t (*wait_for_key)(gs_command_context_t *ctx, int *ch, int timeout_ms); -} gs_command_io_functions_t; - - - -/** - Command context for executing a command. -*/ -struct command_context { - /** - Input (raw) command line, including arguments. - */ - const char * command_line; - - /** - Command being executed. - */ - const gs_command_t * command; - - /** - Number of arguments (standard argc style). - */ - int argc; - - /** - Argument array (standard argv style). - */ - char **argv; - - /** - FILE handle for capturing stdout from command. - */ - FILE* out; - - /** - getopt variable. - */ - int optind; - - /** - getopt variable. - */ - int optopt; - - /** - getopt variable. - */ - char *optarg; - - /** - getopt variable. - */ - int optsp; - - /** - Function interface for I/O operations - */ - const gs_command_io_functions_t *io_functions; - - /** - Pointer for storing the context used by the I/O functions - */ - void * io_ctx; -}; - -/** - Command logging call-back - - logs information on the command called. - @param[in] cmd_line command line string - @param[in] ret return code from command execution framework - @param[in] cmd_ret return code from the executed command - @param[in] start time_stamp when command execution started. - @param[in] end time_stamp when command execution completed. - @param[in] ctx context pointer for the logger. - @return_gs_error_t -*/ -typedef gs_error_t (*gs_command_log_t)(const char *cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t start, gs_timestamp_t end, void * ctx); - -/** - Command handler. -*/ -typedef int (*gs_command_handler_t)(gs_command_context_t * ctx); - -/** - Completer call-back (tab complete). - - @param[in] ctx command context. - @param[in] arg_to_complete argument to complete - @return #GS_OK Found at least 1 match. - The \a completer is expected to have completed more of the command line. - If the framework detects multiple matches, the framework will proceed as if #GS_ERROR_AMBIGUOUS was returned. - The framework doesn't expect anything to be printed to \a out, but will update/refresh the console line. - @return #GS_ERROR_AMBIGUOUS Ambiguous - multiple matches or force the framework to show help. - The \a completer may have extended/completed more of the command line. - The framework expects the \a completer to have printed to \a out, and will show help/usage for the command on a new line. - @return #GS_ERROR_NOT_FOUND (or others) No matches found or no more arguments to complete. - The framewrok doesn't expect anything to be printed to \a out, and will not update the console. -*/ -typedef gs_error_t (*gs_command_completer_t)(gs_command_context_t * ctx, int arg_to_complete); - -/** - Add token - helper to 'tab complete' argument(s). - - @param[in] ctx command context. - @param[in] token possible completion - the API will find the common part. - @param[in] exact \a true if \a token is an exact match - all other added tokens will be ignored. - @return number of tokens added. -*/ -unsigned int gs_command_completer_add_token(gs_command_context_t * ctx, const char * token, bool exact); - -/** - Chain element for chaning sub-commands. -*/ -typedef struct { - /** - Command list. - */ - const gs_command_t * list; - /** - Number of commands in the \a list. - */ - unsigned int count; -} gs_command_chain_t; - -/** - Signals no command arguments in command definition, see mandatory arguments. -*/ -#define GS_COMMAND_NO_ARGS 255 - -/** - Command definition. -*/ -struct command { -#if (__AVR__) - char name[GS_COMMAND_MAX_LEN_COMMAND]; - char help[50]; - char usage[50]; -#else - /** - Name. - */ - const char * const name; - /** - Help text. - */ - const char * const help; - /** - Usage text. - */ - const char * const usage; -#endif - /** - Command handler - the "actual command function". - */ - gs_command_handler_t handler; -#if (__AVR__ == 0) - /** - Completer function - helps completing an argument. - */ - gs_command_completer_t completer; -#endif - /** - Sub-command (if any). - */ - gs_command_chain_t chain; - /** - Mode/flags. - See #GS_COMMAND_FLAG_HIDDEN. - */ - unsigned int mode; - /** - Number of mandatory (minimum) arguments. - - @note Due to backwards compatibility, 0 (zero) cannot be used to signal no arguments - use #GS_COMMAND_NO_ARGS instead, if command doesn't take any arguments (mandatory or optional). - */ - uint8_t mandatory_args; - /** - Number of optional arguments. - */ - uint8_t optional_args; - /** - Filler for future use. - */ - uint8_t filler[2]; -}; - -/** - Returns the arguments as a string, where arguments are separated by spaces. - @param ctx command context. - @return Pointer to concatenated arguments -*/ -const char * gs_command_args(gs_command_context_t *ctx); - -/** - Execute command. - @deprecated Replaced by gs_command_execute & gs_command_execute_stdio - - Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return - result is stored in \a command_result. - - @param[in] command Command to execute, including arguments separated by spaces. - @param[out] command_result Result returned by \a command (if executed). Use \a NULL to ignore result. - @return #GS_ERROR_NOT_FOUND if command wasn't found. - @return #GS_ERROR_ARG if number of argumenets exceeds \a mandatory + \a optional count. - @return_gs_error_t -*/ -gs_error_t gs_command_run(const char * command, gs_error_t * command_result); - -/** - Execute command. - - Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return - result is stored in \a command_result. - - @param[in] command Command to execute, including arguments separated by spaces. - @param[out] command_result Result returned by \a command (if executed). Use \a NULL to ignore result. - @param[in] out output (FILE) stream - @param[in] iof Pointer to function interface of IO operations - @param[in] iof_ctx Pointer to context used by the IO function interface - @return #GS_ERROR_NOT_FOUND if command wasn't found. - @return #GS_ERROR_ARG if number of argumenets exceeds \a mandatory + \a optional count. - @return_gs_error_t -*/ -gs_error_t gs_command_execute(const char * command, gs_error_t * command_result, FILE *out, const gs_command_io_functions_t * iof, void * iof_ctx); - -/** - Execute command. - - Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return - result is stored in \a command_result. The results are printed on stdout and input captured on stdin. - - @param[in] command Command to execute, including arguments separated by spaces. - @param[out] command_result Result from command. Use \a NULL to ignore result. - @return #GS_OK if command was executed - result returned in \a command_result. Otherwise an error indicating why the command wasn't executed. -*/ -gs_error_t gs_command_execute_stdio(const char * command, gs_error_t * command_result); - -/** - Set output - - Sets output from command, using the io function struct in ctx. - - @param[in] ctx the command context - @param[in] group a string specifying the group of the result. Leave blank if not used. - @param[in] key a string specifying the key/name of the result variable. - @param[in] value a string representation of the result value. - @return_gs_error_t -*/ -gs_error_t gs_command_set_output(gs_command_context_t *ctx, const char* group, const char* key, const char* value); - -/** - Set output - - Sets output from command using printf formatting, using the io function struct in ctx. - - @param[in] ctx the command context - @param[in] group a string specifying the group of the result. Leave blank if not used. - @param[in] key a string specifying the key/name of the result variable. - @param[in] format printf syntax for formatting data - @return_gs_error_t -*/ -gs_error_t gs_command_set_output_printf(gs_command_context_t *ctx, const char* group, const char* key, const char * format, ...); - -/** - Flush output/Results - - Instruct the command output stream & results to be flushed from it's buffers. - - @param[in] ctx the command context - @return_gs_error_t -*/ -gs_error_t gs_command_flush_output(gs_command_context_t *ctx); - -/** - Wait for any key input - - Instruct the command input stream to wait for any key. - - @param[in] ctx the command context - @param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milliseconds. - @return true if command should proceed (either because of key press present or if no input stream available) -*/ -bool gs_command_wait_any_key(gs_command_context_t *ctx, int timeout_ms); - -/** - Wait for key input - - Instruct the io stream to wait for a key, and return the pressed key in ch. - - @param[in] ctx the command context - @param[out] ch the character that was read on the input stream - @param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milliseconds. - @return #GS_OK if key was read - @return #GS_ERROR_HANDLE if no input stream is present - @return #GS_ERROR_TIMEOUT on timeout. -*/ -gs_error_t gs_command_wait_key(gs_command_context_t *ctx, int* ch, int timeout_ms); - -/** - Register commands. - - gs_command_init() must be called prior to registering any commands. - - See #GS_COMMAND_ROOT for details. - - @param[in] cmds Pointer to command array - @param[in] cmd_count Number of commands in command array - @return_gs_error_t -*/ -gs_error_t gs_command_register(const gs_command_t * cmds, size_t cmd_count); - -/** - Initialize command system and register default commands. - - Registers following commands: gs_log_register_commands() and gs_command_register_default_commands(). - - @param[in] min_stack_size Minimum stack size required for executing commands. The stack size will be used by other sub-systems such as gs_console, g-script. Stack size may be ignored on some platforms, e.g. Linux. - @return_gs_error_t - @see gs_command_init_no_commands() -*/ -gs_error_t gs_command_init(size_t min_stack_size); - -/** - Initialize command system (without any default commands). - - @param[in] min_stack_size Minimum stack size required for executing commands. The stack size will be used by other sub-systems such as gs_console, g-script. Stack size may be ignored on some platforms, e.g. Linux. - @return_gs_error_t - @see gs_command_init() -*/ -gs_error_t gs_command_init_no_commands(size_t min_stack_size); - - -/** - Register a call-back used for logging of command execution. - - @param[in] log_cb the logging call back. - @param[in] log_ctx pointer to context data. Set to NULL if not used. - @return_gs_error_t -*/ -gs_error_t gs_command_register_logger(gs_command_log_t log_cb, void *log_ctx); - -/** - Default implementation of the command logger, that can be used if no other - custom command logger is provided by the system. - - @param[in] cmd_line command line string - @param[in] ret return code provided by the command execution function. - @param[in] cmd_ret return code provided by the executed command. - @param[in] t_start time stamp when command execution started. - @param[in] t_end time stamp when command execution completed. - @param[in] log_ctx context for the command logger. - @return_gs_error_t -*/ -gs_error_t gs_command_logger_default(const char* cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t t_start, gs_timestamp_t t_end, void * log_ctx); - -/** - Return minimum stack size. - @return minimm stack size required for executing commands. The minimum stack size is set by call to gs_command_init(). -*/ -size_t gs_command_get_stack_size(void); - -/** - Register set of default commands. - @return_gs_error_t -*/ -gs_error_t gs_command_register_default_commands(void); - -/** - Split line into argc/argv. - - @param[in] line line to split - the line will be chop up into argv. - @param[out] argc argc count. - @param[out] argv argv array. - @param[in] max_argc max argv elements. - @return \a true if successfull, else \a false. -*/ -bool gs_command_build_argv(char *line, int *argc, char **argv, int max_argc); - -/** - Parse options. - - Adapted from AT&T public domain source from: - http://www.informatica.co.cr/unix-source-code/research/1985/1103.html - - @param[in] ctx command context. - @param[in] opts options - @return option character -*/ -int gs_command_getopt(gs_command_context_t *ctx, const char *opts); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/gosh/console.h b/gomspace/libutil/include/gs/util/gosh/console.h deleted file mode 100644 index e0c9c42a..00000000 --- a/gomspace/libutil/include/gs/util/gosh/console.h +++ /dev/null @@ -1,123 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -#ifndef GS_UTIL_GOSH_CONSOLE_H -#define GS_UTIL_GOSH_CONSOLE_H -/** - @file - - Console (stdin/stdout) interface for running commands. - - This assumes a VT102 terminal emulator, and tries to fix some of minicom's quirks with e.g. home/end keys. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Initialize the API and console. - - @deprecated version 3.4, use gs_console_start() - - @return_gs_error_t -*/ -gs_error_t gs_console_init(void); - -/** - Restores terminal settings (only relevant on Linux). - - @deprecated version 3.4, this is handled by an installed exit-handler in gs_console_start(). - - @return_gs_error_t -*/ -gs_error_t gs_console_exit(void); - -/** - Set console prompt. - - @param[in] prompt user prompt - the API only stores the pointer, so do not modify/delete content. NULL or empty string is ignored (no change). -*/ -void gs_console_set_prompt(const char * prompt); - -/** - Clear the console screen -*/ -void gs_console_clear(void); - -/** - Update console. -*/ -void gs_console_update(void); - -/** - Create console thread. - - The console thread reads from stdin and writes to stdout. - - The thread is created with low priority, #GS_THREAD_PRIORITY_LOW. - - @deprecated version 3.4, use gs_console_start() - - @param[out] handle handle to created thread - thread will be created joinable if supported by platform. Use NULL, if not wanted. - @return_gs_error_t -*/ -gs_error_t gs_console_create_thread(gs_thread_t * handle); - -/** - Create console thread with priority. - - The console thread reads from stdin and writes to stdout. - - @deprecated version 3.4, use gs_console_start() - - @param[in] priority thread priority, normally #GS_THREAD_PRIORITY_LOW. - @param[out] handle handle to created thread - thread will be created joinable if supported by platform. Use NULL, if not wanted. - @return_gs_error_t -*/ -gs_error_t gs_console_create_thread_with_priority(gs_thread_priority_t priority, gs_thread_t * handle); - -/** - @anchor GS_CONSOLE_F - @defgroup GS_CONSOLE_F Console flags. - Use with gs_console_start() to configure behaviour. - @{ -*/ -/** - Linux only: no signal handlers installed (e.g. to catch SIG_TERM). - @see gs_console_start() -*/ -#define GS_CONSOLE_F_NO_SIGNAL_HANDLER 0x0001 -/** @} */ - -/** - Start console thread (priority: #GS_THREAD_PRIORITY_LOW). - - The console thread reads from stdin and writes to stdout. The thread is created with low priority, #GS_THREAD_PRIORITY_LOW. - - Linux: Changes terminal settings and installs an atexit() handler to restore the settings, Signal handlers will be installed to catch SIG_TERM -> exit() and ignore SIG_INT (controlled by option on command line) - unless #GS_CONSOLE_F_NO_SIGNAL_HANDLER is specified. - - @param[in] prompt set console prompt by calling gs_console_set_prompt(). - @param[in] flags configure behaviour, see @ref GS_CONSOLE_F definitions. - @return #GS_ERROR_EXIST if console thread already created. - @return_gs_error_t -*/ -gs_error_t gs_console_start(const char * prompt, uint32_t flags); - -/** - Stop (and join with) console thread. - - @note This is only supported on Linux. - - The thread is interrupted using pthread_cancel(), which does not guarantee \a clean shutdown if the thread is busy executing a command. - - @return #GS_ERROR_NOT_SUPPORTED if not supported on current platform. - @return #GS_ERROR_HANDLE if no console has been started with gs_console_start(). - @return_gs_error_t -*/ -gs_error_t gs_console_stop(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/hexdump.h b/gomspace/libutil/include/gs/util/hexdump.h deleted file mode 100644 index 43a085e5..00000000 --- a/gomspace/libutil/include/gs/util/hexdump.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef GS_UTIL_HEXDUMP_H -#define GS_UTIL_HEXDUMP_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Dump memory as hex numbers and ascii characters. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Dump memory to an output stream. - @param[in] src memory address. - @param[in] len number of bytes to dump. - @param[in] disp_addr display address, used instead of \a src. - @param[in] out output stream. -*/ -void gs_hexdump_to_stream(const void * src, size_t len, const void * disp_addr, FILE* out); - -/** - Dump memory on stdout. - - @param[in] src memory address. - @param[in] len number of bytes to dump. -*/ -static inline void gs_hexdump(const void *src, size_t len) -{ - gs_hexdump_to_stream(src, len, src, stdout); -} - -/** - Dump memory on stdout. - @param[in] src memory address. - @param[in] len number of bytes to dump. - @param[in] disp_addr display address, used instead of \a src. -*/ -static inline void gs_hexdump_addr(const void * src, size_t len, const void * disp_addr) -{ - gs_hexdump_to_stream(src, len, disp_addr, stdout); -} - -#ifdef __cplusplus -} -#endif -#endif - - diff --git a/gomspace/libutil/include/gs/util/linux/argp.h b/gomspace/libutil/include/gs/util/linux/argp.h deleted file mode 100644 index b8eff835..00000000 --- a/gomspace/libutil/include/gs/util/linux/argp.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef GS_UTIL_LINUX_ARGP_H -#define GS_UTIL_LINUX_ARGP_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Extensions to GNU argp parser (convenience functions). -*/ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Wrapper for argp_parse. - - This function will call exit/terminate the process, if parsing fails. - - \a argv may be re-organized. - - @param[in] argp argp struct. - @param[in] argc argument count, i.e. standard argc. - @param[in] argv argument array, i.e. standard argv. - @param[in] flags future use. - @param[out] arg_index first unparsed option (-> argv modified). - @param[in] revision program revision, e.g. 3.0.1-12-g0cf1b59+. -*/ -void gs_argp_parse(const struct argp * argp, - int argc, char ** argv, - unsigned int flags, int * arg_index, - const char * revision); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/command_line.h b/gomspace/libutil/include/gs/util/linux/command_line.h deleted file mode 100644 index d9dbc3a3..00000000 --- a/gomspace/libutil/include/gs/util/linux/command_line.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef GS_UTIL_LINUX_COMMAND_LINE_H -#define GS_UTIL_LINUX_COMMAND_LINE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Command line support. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Command line options for ignoring CTRL-C -*/ -extern const struct argp_child gs_console_command_line_ignore_ctrlc_argp; - -/** - Command line options for adding -h (help). -*/ -const struct argp_child gs_help_command_line_argp; - -/** - Return if ctrl-c ignored on command line. - @return \a true i ctrl-c ignored. -*/ -bool gs_command_line_ignore_ctrlc(void); - -/** - Return program name based on argv[0]. - @param[in] argv expected to be argv[0] amd point to the program name (possibly with full path). - @return program name. -*/ -const char * gs_command_line_program_name(const char * argv); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/can/can.h b/gomspace/libutil/include/gs/util/linux/drivers/can/can.h deleted file mode 100644 index f04b3f83..00000000 --- a/gomspace/libutil/include/gs/util/linux/drivers/can/can.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef GS_UTIL_LINUX_DRIVERS_CAN_CAN_H -#define GS_UTIL_LINUX_DRIVERS_CAN_CAN_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Linux CAN interface. - - @note Only 1 filter/mask can be set, using gs_can_set_standard_filter_mask() or gs_can_set_extended_filter_mask() -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Open and initialize a CAN handle. - @param[in] ifname name of CAN interface. - @param[out] handle opened CAN handle. - @return_gs_error_t -*/ -gs_error_t gs_can_open(const char * ifname, int * handle); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h deleted file mode 100644 index f04cc1f5..00000000 --- a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef GS_UTIL_LINUX_DRIVERS_GPIO_H -#define GS_UTIL_LINUX_DRIVERS_GPIO_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - @brief GPIO interface - - GPIO interface provides a generic interface where specific GPIO drivers can be plugged in. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - GomSpace linux driver GPIO get value - - @param[in] gpio The gpio to read - @param[in] value Returned GPIO value (true/false = High/Low) - @param[in] driver_data data to specific driver - - @return_gs_error_t -*/ -typedef gs_error_t (*gs_gpio_get_t)(gs_gpio_t gpio, bool *value, void * driver_data); - -/** - GomSpace linux driver GPIO get value without error check - - @param[in] gpio The gpio to read - @param[in] driver_data data to specific driver - - @return GPIO value (true/false = High/Low) -*/ -typedef bool (*gs_gpio_get_nc_t)(gs_gpio_t gpio, void * driver_data); - -/** - GomSpace linux driver GPIO set value - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @param[in] driver_data data to specific driver - - @return_gs_error_t -*/ -typedef gs_error_t (*gs_gpio_set_t)(gs_gpio_t gpio, bool value, void * driver_data); - -/** - GomSpace linux driver GPIO set value without error check - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @param[in] driver_data data to specific driver -*/ -typedef void (*gs_gpio_set_nc_t)(gs_gpio_t gpio, bool value, void * driver_data); - -/** - GomSpace linux driver initialize GPIO as an external interrupt pin - - @param[in] gpio The gpio to configure - @param[in] conf Configuration of interrupt pin - @param[in] driver_data data to specific driver - - @return_gs_error_t - */ -typedef gs_error_t (*gs_gpio_init_as_interrupt_t)(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data); - - -/** - Every port. - */ -#define GS_GPIO_ALL_PORTS UINT16_MAX - -/** - Every pin. - */ -#define GS_GPIO_ALL_PINS UINT16_MAX - -/** - GPIO driver. - */ -typedef struct { - /** - Function for handling GPIO get. - */ - gs_gpio_get_t get_handler; - /** - Function for handling GPIO get no check. - */ - gs_gpio_get_nc_t get_nc_handler; - /** - Function for handling GPIO set. - */ - gs_gpio_set_t set_handler; - /** - Function for handling GPIO set no check. - */ - gs_gpio_set_nc_t set_nc_handler; - /** - Function for handling GPIO initialize as interrupt. - */ - gs_gpio_init_as_interrupt_t init_as_interrupt_handler; -} gs_gpio_driver_t; - - -/** - GPIO driver entry - */ -typedef struct { - /** - GPIO port, to which the driver is used (if GS_GPIO_ALL_PORTS, then all ports uses this driver). - */ - uint16_t port; - /** - GPIO pin, to which the driver is used (if GS_GPIO_ALL_PINS, then all pins uses this driver). - */ - uint16_t pin; - /** - GPIO driver. - */ - const gs_gpio_driver_t * driver; - /** - Driver specific data. - */ - void * driver_data; -} gs_gpio_driver_entry_t; - -/** - Register a driver. - - A specific driver can be assigned to a port and pin or it can be assigned to all pins and/or all ports. - - The latest registered driver, which fit the GPIO, is the one used. - - @param[in] driver_entry driver and configuration to be registered - @return_gs_error_t - */ -gs_error_t gs_gpio_register_driver(const gs_gpio_driver_entry_t * driver_entry); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h deleted file mode 100644 index 0f95e5aa..00000000 --- a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_SYSFS_H_ -#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_SYSFS_H_ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - @brief Linux GPIO driver based on sysfs. - This driver needs to be registered in the generic GPIO linux driver @see 'gs/util/linux/drivers/gpio/gpio.h' -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - GPIO sysfs driver data. - - @note Driver takes no driver data, so a NULL pointer is valid -*/ -typedef void * gs_gpio_sysfs_driver_data_t; - -/** - GPIO sysfs driver interface. -*/ -extern const gs_gpio_driver_t gs_gpio_sysfs_driver; - -/** - GPIO sysfs initialize - - @param[in] gpio The gpio to initialize - @param[in] output Direction of pin (True/False = Output/Input) - @param[in] init_value Pin state if configured as output (True/False = High/Low) - @param[in] active_low if set pin is configured as active low (so a gs_gpio_sysfs_set with 1 will actually set value low) - @return_gs_error_t - */ -gs_error_t gs_gpio_sysfs_initialize(gs_gpio_t gpio, bool output, bool init_value, bool active_low); - -/** - GPIO sysfs get value - - @param[in] gpio The gpio to read - @param[in] value Returned GPIO value (true/false = High/Low) - @param[in] driver_data data to driver (not used) - @return_gs_error_t -*/ -gs_error_t gs_gpio_sysfs_get(gs_gpio_t gpio, bool *value, void * driver_data); - -/** - GPIO sysfs get value without error check - - @param[in] gpio The gpio to read - @param[in] driver_data data to driver (not used) - @return GPIO value (true/false = High/Low) -*/ -bool gs_gpio_sysfs_get_nc(gs_gpio_t gpio, void * driver_data); - -/** - GPIO sysfs set value - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @param[in] driver_data data to driver (not used) - @return_gs_error_t -*/ -gs_error_t gs_gpio_sysfs_set(gs_gpio_t gpio, bool value, void * driver_data); - -/** - GPIO sysfs set value without error check - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @param[in] driver_data data to driver (not used) -*/ -void gs_gpio_sysfs_set_nc(gs_gpio_t gpio, bool value, void * driver_data); - -/** - Initialize GPIO sysfs as an external interrupt pin - - @param[in] gpio The gpio to configure - @param[in] conf Configuration of interrupt pin - @param[in] driver_data data to driver (not used) - @return_gs_error_t - */ -gs_error_t gs_gpio_sysfs_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h deleted file mode 100644 index e61b70a4..00000000 --- a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_VIRTUAL_H_ -#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_VIRTUAL_H_ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - @brief Linux GPIO driver to be used in unit tests. - This driver needs to be registered in the generic GPIO linux driver @see 'gs/util/linux/drivers/gpio/gpio.h' -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - GPIO virtual driver data. - - @note Driver takes no driver data, so a NULL pointer is valid -*/ -typedef void * gs_gpio_virtual_driver_data_t; - -/** - GPIO virtual driver interface. -*/ -extern const gs_gpio_driver_t gs_gpio_virtual_driver; - -/** - GPIO virtual driver entry, where all ports and pins are routed to virtual driver - */ -extern const gs_gpio_driver_entry_t gs_gpio_virtual_driver_entry_all; - -/** - GPIO virtual initialize - - @param[in] gpio The gpio to initialize - @param[in] output Direction of pin (True/False = Output/Input) - @param[in] value Pin state if configured as output (True/False = High/Low) - @return_gs_error_t - */ -gs_error_t gs_gpio_virtual_initialize(gs_gpio_t gpio, bool output, bool value); - -/** - GPIO virtual get value - - @param[in] gpio The gpio to read - @param[in] value Returned GPIO value (true/false = High/Low) - @param[in] driver_data data to driver (not used) - @return_gs_error_t -*/ -gs_error_t gs_gpio_virtual_get(gs_gpio_t gpio, bool *value, void * driver_data); - -/** - GPIO virtual get value without error check - - @param[in] gpio The gpio to read - @param[in] driver_data data to driver (not used) - @return GPIO value (true/false = High/Low) -*/ -bool gs_gpio_virtual_get_nc(gs_gpio_t gpio, void * driver_data); - -/** - GPIO virtual set value - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @param[in] driver_data data to driver (not used) - @return_gs_error_t -*/ -gs_error_t gs_gpio_virtual_set(gs_gpio_t gpio, bool value, void * driver_data); - -/** - GPIO virtual set value without error check - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @param[in] driver_data data to driver (not used) -*/ -void gs_gpio_virtual_set_nc(gs_gpio_t gpio, bool value, void * driver_data); - -/** - Initialize GPIO virtual as an external interrupt pin - - @param[in] gpio The gpio to configure - @param[in] conf Configuration of interrupt pin - @param[in] driver_data data to driver (not used) - @return_gs_error_t - */ -gs_error_t gs_gpio_virtual_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data); - -/** - Force set a pin - - This sets a pin regardless if it is configured as input, output or interrupt - If the pin is configured as interrupt, the registered ISR's will be called within this function, - if the transition matches (rising/falling) - - @note This function is specific to this driver and is should not be registered. - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @return_gs_error_t - */ -gs_error_t gs_gpio_virtual_force_set(gs_gpio_t gpio, bool value); - -/** - Get transitions - - This gives the number of transitions ((high -> low) + (low -> high)), - since last time this function was called at this pin. This function resets the counter of the pin. - An even number means, that the pin has the same state as it was initialized to. - - @note This function is specific to this driver and should not be registered - - @param[in] gpio The gpio, of which transitions are given - @param[out] transitions Number of transitions - @return - */ -gs_error_t gs_gpio_virtual_get_transistions(gs_gpio_t gpio, uint32_t * transitions); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h b/gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h deleted file mode 100644 index 858c26a2..00000000 --- a/gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h +++ /dev/null @@ -1,198 +0,0 @@ -#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_I2C_I2C_H_ -#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_I2C_I2C_H_ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - @brief Linux I2C plugin driver -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - GomSpace linux driver I2C master transaction. - - @see 'gs/util/drivers/i2c/master.h' - - @param[in] device I2C device - @param[in] addr I2C address - @param[in] tx tx buffer - @param[in] txlen bytes to be sent - @param[out] rx rx buffer - @param[in] rxlen bytes to be received - @param[in] timeout_ms timeout in milliseconds - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (* gs_i2c_master_transaction_t)(uint8_t device, uint8_t addr, const void * tx, size_t txlen, - void * rx, size_t rxlen, int timeout_ms, void * driver_data); - -/** - GomSpace linux driver I2C slave start. - - @see 'gs/util/drivers/i2c/slave.h' - - @param[in] device I2C device - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (* gs_i2c_slave_start_t)(uint8_t device, void * driver_data); - -/** - GomSpace linux driver I2C set rx callback - - @see 'gs/util/drivers/i2c/slave.h' - - @param[in] device I2C device - @param[in] rx rx callback - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (* gs_i2c_slave_set_rx_t)(uint8_t device, gs_i2c_slave_receive_t rx, void * driver_data); - -/** - GomSpace linux driver I2C slave set 'get_rx_buffer' callback. - - @see 'gs/util/drivers/i2c/slave.h' - - @param[in] device I2C device - @param[in] get_rx_buf get_rx_buf callback - @param[in] buf_length length of buffer received by calling callback - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (* gs_i2c_slave_set_get_rx_buf_t)(uint8_t device, gs_i2c_slave_get_rx_buf_t get_rx_buf, size_t buf_length, void * driver_data); - -/** - GomSpace linux driver I2C slave set slave response. - - @see 'gs/util/drivers/i2c/slave.h' - - @param[in] device I2C device - @param[in] tx tx buffer - @param[in] tx_length bytes to be send - @param[in] driver_data data to specific driver - @return_gs_error_t -*/ -typedef gs_error_t (* gs_i2c_slave_set_response_t)(uint8_t device, const uint8_t * tx, size_t tx_length, void * driver_data); - -/** - Every I2C device ([0 : 254]). - */ -#define GS_I2C_ALL_DEVICES 255 - -/** - Every I2C address (0 : 127]). - */ -#define GS_I2C_ALL_ADDR 255 - -/** - I2C master driver. - */ -typedef struct { - /** - Function for handling master transactions. - */ - gs_i2c_master_transaction_t master_transaction_handler; -} gs_i2c_master_driver_t; - - -/** - I2C master driver entry - */ -typedef struct { - /** - I2C device, to which the driver is used (if GS_I2C_ALL_DEVICES, then all devices uses this driver). - */ - uint8_t device; - /** - I2C addr, to which the driver is used (if GS_I2C_ALL_ADDR, then all addr on given device uses this driver). - */ - uint8_t addr; - /** - I2C master driver. - */ - const gs_i2c_master_driver_t * driver; - /** - Driver specific data. - */ - void * driver_data; -} gs_i2c_master_driver_entry_t; - - -/** - I2C slave driver - */ -typedef struct { - /** - Function for handling slave start. - */ - gs_i2c_slave_start_t start_handler; - /** - Function for handling the 'setting of rx callback'. - */ - gs_i2c_slave_set_rx_t set_rx_handler; - /** - Function for handling setting of an 'rx buff get' function. - */ - gs_i2c_slave_set_get_rx_buf_t set_get_rx_buf_handler; - /** - Function for handling 'set response'. - */ - gs_i2c_slave_set_response_t set_response_handler; -} gs_i2c_slave_driver_t; - - -/** - I2C slave driver entry. - */ -typedef struct { - /** - I2C device, to which the driver is used (if GS_I2C_ALL_DEVICES, then all devices uses this driver). - */ - uint8_t device; - /** - I2C slave driver. - */ - const gs_i2c_slave_driver_t * driver; - /** - Driver specific data. - */ - void * driver_data; -} gs_i2c_slave_driver_entry_t; - - -/** - Register a master driver. - - A specific driver can be assigned to a specific address and device - or it can be registered to every address on a device or every address on every device. - - The latest registered driver, which fit the device an address, is the one used. - - @param[in] driver_entry driver and configuration to be registered - @return_gs_error_t - */ -gs_error_t gs_i2c_master_register_driver(const gs_i2c_master_driver_entry_t * driver_entry); - -/** - Register a slave driver - - A specific driver can be assigned to a specific device or a driver can be assigned to every device. - - The latest registered driver, which fit the device, is the one used. - - @param[in] driver_entry driver and configuration to be registered - @return_gs_error_t - */ -gs_error_t gs_i2c_slave_register_driver(const gs_i2c_slave_driver_entry_t * driver_entry); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h b/gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h deleted file mode 100644 index 24e5ae22..00000000 --- a/gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h +++ /dev/null @@ -1,175 +0,0 @@ -#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_SPI_SPI_H_ -#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_SPI_SPI_H_ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Linux SPI plugin driver -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Linux driver SPI master transactions. - - @see 'gs/util/drivers/spi/master.h' - - @param[in] slave SPI slave - @param[in] trans Pointer to transactions - @param[in] count Number of transactions (rx and/or tx) to complete - @param[in] timeout_ms timeout in milliseconds, primarily for locking the SPI device. - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (*gs_spi_master_transactions_t)(uint8_t slave, gs_spi_master_trans_t *trans, size_t count, - int timeout_ms, void * driver_data); - -/** - Linux driver SPI slave start. - - @see 'gs/util/drivers/spi/slave.h' - - @param[in] device SPI device (handle) - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (* gs_spi_slave_start_t)(uint8_t device, void * driver_data); - -/** - Linux driver SPI set rx callback - - @see 'gs/util/drivers/spi/slave.h' - - @param[in] device SPI device (handle). - @param[in] rx Rx callback. - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (* gs_spi_slave_set_rx_t)(uint8_t device, gs_spi_slave_receive_t rx, void * driver_data); - -/** - Linux driver SPI slave set slave response. - - @see 'gs/util/drivers/spi/slave.h' - - @param[in] device SPI device (handle). - @param[in] offset offset (in bytes) for the response, counted from start of request, i.e. offset of 2 means data will be sent as the 3rd byte. - @param[in] tx pointer to data. NOTE: data is not copied due to performance, so data must stay valid until the response has been sent. - @param[in] size size of data. - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (* gs_spi_slave_set_response_t)(uint8_t device, size_t offset, const uint8_t * tx, size_t size, void * driver_data); - -/** - Every SPI slave ([0 : 254]). - */ -#define GS_SPI_ALL_SLAVES 255 - -/** - Every SPI device (0 : 254]). - */ -#define GS_SPI_ALL_DEVICES 255 - - -/** - SPI master driver. - */ -typedef struct { - /** - Function for handling master transactions. - */ - gs_spi_master_transactions_t master_transactions_handler; -} gs_spi_master_driver_t; - - -/** - SPI master driver entry - */ -typedef struct { - /** - SPI slave, to which the driver is used (if #GS_SPI_ALL_SLAVES, then all slaves uses this driver). - */ - uint8_t slave; - /** - SPI master driver. - */ - const gs_spi_master_driver_t * driver; - /** - Driver specific data. - */ - void * driver_data; -} gs_spi_master_driver_entry_t; - - -/** - SPI slave driver - */ -typedef struct { - /** - Function for handling slave start. - */ - gs_spi_slave_start_t start_handler; - /** - Function for handling the 'setting of rx callback'. - */ - gs_spi_slave_set_rx_t set_rx_handler; - /** - Function for handling 'set response'. - */ - gs_spi_slave_set_response_t set_response_handler; -} gs_spi_slave_driver_t; - - -/** - SPI slave driver entry. - */ -typedef struct { - /** - SPI device, to which the driver is used (if #GS_SPI_ALL_DEVICES, then all devices uses this driver). - */ - uint8_t device; - /** - SPI slave driver. - */ - const gs_spi_slave_driver_t * driver; - /** - Driver specific data. - */ - void * driver_data; -} gs_spi_slave_driver_entry_t; - - -/** - Register a master driver. - - A specific driver can be assigned to a slave or it can be assigned to every slave. - - The latest registered driver, which fit the slave, is the one used. - - @param[in] driver_entry driver and configuration to be registered - @return_gs_error_t - */ -gs_error_t gs_spi_master_register_driver(const gs_spi_master_driver_entry_t * driver_entry); - -/** - Register a slave driver - - A specific driver can be assigned to a specific device or a driver can be assigned to every device. - - The latest registered driver, which fit the device, is the one used. - - @param[in] driver_entry driver and configuration to be registered - @return_gs_error_t - */ -gs_error_t gs_spi_slave_register_driver(const gs_spi_slave_driver_entry_t * driver_entry); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/exitcode.h b/gomspace/libutil/include/gs/util/linux/exitcode.h deleted file mode 100644 index 35e89f06..00000000 --- a/gomspace/libutil/include/gs/util/linux/exitcode.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef GS_UTIL_LINUX_EXITCODE_H -#define GS_UTIL_LINUX_EXITCODE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - "standard" Linux exit codes. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Program completed ok (from stdlib.h) -*/ -#define GS_EXITCODE_OK EXIT_SUCCESS - -/** - Program terminated due to an error (from stdlib.h). -*/ -#define GS_EXITCODE_ERROR EXIT_FAILURE - -/** - Program terminated due to invalid usage, eg argument (from sysexits.h). -*/ -#define GS_EXITCODE_USAGE EX_USAGE - -/** - Program terminated due to a signal (from [TLDP](http://www.tldp.org/LDP/abs/html/exitcodes.html)). -*/ -#define GS_EXITCODE_SIGNAL(sig) (128 + sig) - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/function.h b/gomspace/libutil/include/gs/util/linux/function.h deleted file mode 100644 index b918993d..00000000 --- a/gomspace/libutil/include/gs/util/linux/function.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef GS_UTIL_LINUX_FUNCTION_H -#define GS_UTIL_LINUX_FUNCTION_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Function interface - invokes a function by name. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Function prototype. - @param[in] arg argument provided to gs_function_invoke(). - @return_gs_error_t -*/ -typedef gs_error_t (*gs_function_t)(void * arg); - -/** - Register \a function by name. - - @param[in] short_name short name for function, used by gs_function_invoke() to find function to invoke. - @param[in] long_name long name (unique) for function, used by gs_function_invoke() to find function to invoke. - @param[in] function function to be invoked by gs_function_invoke() - @return #GS_ERROR_FULL if registry is full. - @return_gs_error_t -*/ -gs_error_t gs_function_register(const char * short_name, const char * long_name, gs_function_t function); - -/** - Invoke \a function by name. - - The return value is from the registered function, except for #GS_ERROR_NOT_IMPLEMENTED. - - @param[in] name registered function name. - @param[in] arg argument for function. - @return #GS_ERROR_NOT_IMPLEMENTED if the \a name isn't found. - @return_gs_error_t -*/ -gs_error_t gs_function_invoke(const char * name, void * arg); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/rtc.h b/gomspace/libutil/include/gs/util/linux/rtc.h deleted file mode 100644 index fa063f76..00000000 --- a/gomspace/libutil/include/gs/util/linux/rtc.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef GS_UTIL_LINUX_RTC_H -#define GS_UTIL_LINUX_RTC_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Real Time Clock interface (linux). -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Register Real Time Clock interface. - @note Setting the RTC will normally require special permission. - @param[in] get if true, get will be registered. - @param[in] set if true, set will be registered. - @return_gs_error_t -*/ -gs_error_t gs_rtc_register_linux(bool get, bool set); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/signal.h b/gomspace/libutil/include/gs/util/linux/signal.h deleted file mode 100644 index b3c280e7..00000000 --- a/gomspace/libutil/include/gs/util/linux/signal.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef GS_UTIL_LINUX_SIGNAL_H -#define GS_UTIL_LINUX_SIGNAL_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Signal helpers - catch and ignore. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Standard Linux signal handler. -*/ -typedef void (*gs_signal_handler)(int signal, siginfo_t *si, void *context); - -/** - Register/catch signal and invoke handler. - @param[in] signal signal to catch. - @param[in] handler signal handler. If \a handler is NULL, a default handler will be invoked, which calls exit(#GS_EXITCODE_SIGNAL + signal). - @return_gs_error_t -*/ -gs_error_t gs_signal_catch(int signal, gs_signal_handler handler); - -/** - Ignore signal - @param[in] signal signal to ignore. - @return_gs_error_t -*/ -gs_error_t gs_signal_ignore(int signal); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/sysfs_helper.h b/gomspace/libutil/include/gs/util/linux/sysfs_helper.h deleted file mode 100644 index ad05a6fe..00000000 --- a/gomspace/libutil/include/gs/util/linux/sysfs_helper.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef GS_UTIL_SYSFS_HELPER_H -#define GS_UTIL_SYSFS_HELPER_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Sysfs interface. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Sysfs write (GPIO). -*/ -gs_error_t gs_sysfs_write_file(const char *path, const char *value); - -/** - Sysfs read (GPIO). -*/ -gs_error_t gs_sysfs_read_file(const char *path, char *value, size_t len); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/log.h b/gomspace/libutil/include/gs/util/log.h deleted file mode 100644 index 13659adf..00000000 --- a/gomspace/libutil/include/gs/util/log.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef GS_UTIL_LOG_H -#define GS_UTIL_LOG_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Log interface. - - The log interface supports logging to different group. - - Logging is done through groups (domains), which can runtime be re-configured with level. -*/ -#include - -#endif diff --git a/gomspace/libutil/include/gs/util/log/appender/appender.h b/gomspace/libutil/include/gs/util/log/appender/appender.h deleted file mode 100644 index 29a0c140..00000000 --- a/gomspace/libutil/include/gs/util/log/appender/appender.h +++ /dev/null @@ -1,189 +0,0 @@ -#ifndef GS_UTIL_LOG_APPENDER_APPENDER_H -#define GS_UTIL_LOG_APPENDER_APPENDER_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Log Appender interface. - - The log appender interface supports logging to different "stores". - Logging is done through groups, which can be registered to different log appenders. - Each log appender has it's own filter (level mask). - Examples of log appenders could be: console, file, vmem, ... -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/** - Log appender (forward declaration) - All log groups log to one or more appenders. The Log appender is responsible - for putting the actual log data to a store/console or some other log medium. -*/ -typedef struct gs_log_appender gs_log_appender_t; - -/** - Log appender record iterator callback function - - @param[in] ctx context data for iterator. - @param[in] level log level of record being iterated - @param[in] ts timestamp of record being iterated - @param[in] group group string (zero terminated) of record being iterated - @param[in] msg message string (zero terminated) of record being iterated - @return true/false: Return false to discontinue iteration. -*/ -typedef bool (*gs_log_record_iterator_t)(void *ctx, gs_log_level_t level, const gs_timestamp_t *ts, const char *group, const char *msg); - -/** - Log appender driver interface -*/ -typedef struct { - /** appender init function */ - gs_error_t (*init)(gs_log_appender_t *appender); - /** appender function */ - void (*append)(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va); - /** appender function for isr context */ - void (*append_isr)(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va); - /** appender function for getting appender details string */ - void (*info)(gs_log_appender_t *appender, char * info_str, uint8_t str_size); - /** appender function for iterating stored appenders log history */ - void (*hist)(gs_log_appender_t *appender, void * ctx, gs_log_record_iterator_t iter); - /** appender function for clearing it's log history */ - void (*clear)(gs_log_appender_t *appender); - /** appender function for flushing cached log entries to it's store. - This is only relevant for appenders implementing a log cache. */ - void (*flush)(gs_log_appender_t *appender); -} gs_log_appender_driver_t; - -/** - Log appender - All log groups log to one or more appenders. The Log appender is responsible - for putting the actual log data to a store/console or some other log medium. -*/ -struct gs_log_appender { - /** Name of the appender */ - const char * name; - /** appender driver interface */ - const gs_log_appender_driver_t * drv; - /** appender driver configuration data */ - const void * drv_config; - /** appender driver data - dynamic/internal data */ - void * drv_data; - /** appender level mask */ - uint8_t mask; -}; - -/** - Register an appender for the given log group. - All logging, where the mask matches the groups \a level_mask, will be forwarded to this appender. - - @param[in] group_name Name of the group. - @param[in] appender_name Name of appender to register for this group. - @return gs_error_t -*/ -gs_error_t gs_log_group_register_appender(const char * group_name, const char * appender_name); - -/** - Log appender iterator callback function - - @param[in] ctx context data for iterator. - @param[in] appender log appender being iterated - - @return true/false: Return false to discontinue iteration. -*/ -typedef bool (*gs_log_appender_iterator_t)(void *ctx, gs_log_appender_t * appender); - -/** - Iterate all or specific log appender(s). - - @param[in] name name of log appender, or NULL/\"all\" for all groups. - @param[in] ctx user context data. - @param[in] iter iterator, return \a true to continue, \a false to break iteration. - @return_gs_error_t -*/ -gs_error_t gs_log_appender_iterate(const char * name, void * ctx, gs_log_appender_iterator_t iter); - -/** - Iterate registered appenders for a specific group. - - @param[in] group log group to iterate appenders on. - @param[in] ctx user context data. - @param[in] iter appender iterator, return \a true to continue, \a false to break iteration. - @return gs_error_t -*/ -gs_error_t gs_log_group_appender_iterate(gs_log_group_t * group, void * ctx, gs_log_appender_iterator_t iter); - -/** - Register log appender. - - The log appender will be registered and initialized (if the appender has en init function, see #gs_log_appender_driver_t) - - The appender will not be attached to any log groups. For registering an appender to a group, use gs_log_group_register_appender() - - @param[in] appender appender - must stay in memory during the life-time of the application - @return_gs_error_t -*/ -gs_error_t gs_log_appender_register(gs_log_appender_t *appender); - -/** - Add log appender(s). - - The log appender will be registered and initialized (if the appender has en init function, see #gs_log_appender_driver_t) - - The appender will not be attached to any log groups. For registering an appender to a group, use gs_log_group_register_appender() - - @deprecated impossible to determine which appender fails, use gs_log_appender_register() - @param[in] appenders array of appender(s) - must stay in memory during the life-time of the application - @param[in] count array count - number of appenders. - @return_gs_error_t -*/ -gs_error_t gs_log_appender_add(gs_log_appender_t *appenders, uint16_t count); - -/** - Set log appender level mask. - - @param[in] appender_name log appender name - @param[in] mask level mask to set. - @return_gs_error_t -*/ -gs_error_t gs_log_appender_set_level_mask(const char * appender_name, uint8_t mask); - -/** - Get log appender level mask. - - @param[in] appender_name log appender name - @param[out] mask returned current level mask. - @return_gs_error_t -*/ -gs_error_t gs_log_appender_get_level_mask(const char * appender_name, uint8_t *mask); - -/** - Iterate log history for all or specific log appender. - - @param[in] name name of log appender, or NULL/\"all\" for all appenders. - @param[in] ctx user context data for iterator. - @param[in] iter iterator, return \a true to continue, \a false to break iteration. - @return gs_error_t -*/ -gs_error_t gs_log_appender_history_iterate(const char * name, void * ctx, gs_log_record_iterator_t iter); - -/** - Flush all log appenders data to storage. - - This will call the flush API (if implemented) for all log appenders - available on the system. This should be called on regular basis from - a system thread to ensure all cached data is correctly flushed to their - stores. - - @return gs_error_t -*/ -gs_error_t gs_log_appender_flush_all(); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/log/appender/console.h b/gomspace/libutil/include/gs/util/log/appender/console.h deleted file mode 100644 index 37f63fc5..00000000 --- a/gomspace/libutil/include/gs/util/log/appender/console.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef GS_UTIL_LOG_APPENDER_CONSOLE_H -#define GS_UTIL_LOG_APPENDER_CONSOLE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Console log appender - logs to stdout. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Log appender for console - - This log appender is the standard appender which is always available - on any system. The appender should be registered to the root group, - in order to get console/stdio logs. -*/ -extern gs_log_appender_t gs_log_appender_console; - -/** - Log appender for console callback type - - This callback function can be used for registering a user defined logger function if - the default can not be used for the given system. - - @param[in] appender pointer to the console appender. - @param[in] level log level for log message - @param[in] group log group for log message - @param[in] ts timestamp for log message - @param[in] format format of message in printf style - @param[in] va variable argument list in printf style - - @return void -*/ -typedef void (*gs_log_appender_console_cb_t)(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va); - -/** - Set Log appender for console callback - - When set, the given callback is called instead of the default console log function. - To revert back to the default console log function, call this function with NULL as parameter. - - @param[in] cb callback to use for console logging. - - @return gs_error_t -*/ -gs_error_t gs_log_appender_console_set_cb(gs_log_appender_console_cb_t cb); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/log/appender/simple_file.h b/gomspace/libutil/include/gs/util/log/appender/simple_file.h deleted file mode 100644 index ab2537a6..00000000 --- a/gomspace/libutil/include/gs/util/log/appender/simple_file.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef GS_UTIL_LOG_APPENDER_SIMPLE_FILE_H -#define GS_UTIL_LOG_APPENDER_SIMPLE_FILE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Simple log-file appender. -*/ -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Simple File Log Appender driver configuration -*/ -typedef struct gs_log_appender_simple_file_config { - /** - Name of file to create/write logs to - */ - const char *filename; - /** - Truncate the file, when opening the log file. - */ - bool truncate; - /** - Uee local time stamps when logging to log file, otherwise UTC. - */ - bool use_local_time; -} gs_log_appender_simple_file_config_t; - -/** - Log appender for file. -*/ -extern const gs_log_appender_driver_t gs_log_appender_simple_file_driver; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/log/log.h b/gomspace/libutil/include/gs/util/log/log.h deleted file mode 100644 index 53470a75..00000000 --- a/gomspace/libutil/include/gs/util/log/log.h +++ /dev/null @@ -1,853 +0,0 @@ -#ifndef GS_UTIL_LOG_LOG_H -#define GS_UTIL_LOG_LOG_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Log interface. - - Logging is done through groups (domains), where the level mask can be changed runtime. -*/ - -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Name of the root log group -*/ -#define GS_LOG_GROUP_ROOT "root" - -/** - Log levels. - - The levels can easily be mapped to standard syslog severity levels (https://en.wikipedia.org/wiki/Syslog). -*/ -typedef enum { - /** - Trace (more detailed than \a debug). - - syslog: maps to \a debug (or \a trace if supported). - */ - GS_LOG_TRACE = 0, - /** - Debug. - - syslog: maps to \a debug. - */ - GS_LOG_DEBUG = 1, - /** - Informational. - - syslog: maps to \a informational. - */ - GS_LOG_INFO = 2, - /** - Normal but significant conditions. - - syslog: maps to \a notice. - */ - GS_LOG_NOTICE = 3, - /** - Warning. - - syslog: maps to \a warning. - */ - GS_LOG_WARNING = 4, - /** - Error. - - syslog: maps to \a error. - */ - GS_LOG_ERROR = 5, - - /** - Trace (more detailed than \a debug). - @deprecated use #GS_LOG_TRACE - */ - LOG_TRACE = GS_LOG_TRACE, - /** - Debug. - @deprecated use #GS_LOG_DEBUG - */ - LOG_DEBUG = GS_LOG_DEBUG, - /** - Informational. - @deprecated use #GS_LOG_INFO - */ - LOG_INFO = GS_LOG_INFO, - /** - Normal but significant conditions. - @deprecated use #GS_LOG_NOTICE - */ - LOG_NOTICE = GS_LOG_NOTICE, - /** - Warning. - @deprecated use #GS_LOG_WARNING - */ - LOG_WARNING = GS_LOG_WARNING, - /** - Error. - @deprecated use #GS_LOG_ERROR - */ - LOG_ERROR = GS_LOG_ERROR, -} gs_log_level_t; - -/** - Log categories. - - The category is a way of grouping information about which sub-systems have logged. It is primarily used in the \a - telemetry table, to indicate what sub-systems have logged an \a error or \a warning - indicating a possible problem. - - Up to 32 categories are supported (stored in a uint32). - - Categories should be unique within a single node. However, nothing happens if categories clashes - it will only be more difficult to determine what part of the system logged. - - Standard categories are defined from #GS_LOG_CAT_1 and up. Products or mission specific software should start from #GS_LOG_CAT_32 and down. -*/ -typedef enum { - //! Standard, used for #GS_LOG_CAT_DEFAULT - GS_LOG_CAT_1 = 1 << 0, - //! Standard, used for #GS_LOG_CAT_DRIVER - GS_LOG_CAT_2 = 1 << 1, - //! Standard, used for #GS_LOG_CAT_CSP - GS_LOG_CAT_3 = 1 << 2, - //! Standard, used for #GS_LOG_CAT_PARAM - GS_LOG_CAT_4 = 1 << 3, - //! Standard, used for #GS_LOG_CAT_FILE_SYSTEM - GS_LOG_CAT_5 = 1 << 4, - //! Standard, used for #GS_LOG_CAT_COMMAND - GS_LOG_CAT_6 = 1 << 5, - //! Standard, used for #GS_LOG_CAT_HK - GS_LOG_CAT_7 = 1 << 6, - //! Standard, used for #GS_LOG_CAT_FP - GS_LOG_CAT_8 = 1 << 7, - //! Standard, used for #GS_LOG_CAT_ADCS - GS_LOG_CAT_9 = 1 << 8, - GS_LOG_CAT_10 = 1 << 9, - GS_LOG_CAT_11 = 1 << 10, - GS_LOG_CAT_12 = 1 << 11, - GS_LOG_CAT_13 = 1 << 12, - GS_LOG_CAT_14 = 1 << 13, - GS_LOG_CAT_15 = 1 << 14, - GS_LOG_CAT_16 = 1 << 15, -#if (__AVR__ == 0) - GS_LOG_CAT_17 = 1 << 16, - GS_LOG_CAT_18 = 1 << 17, - GS_LOG_CAT_19 = 1 << 18, - GS_LOG_CAT_20 = 1 << 19, - GS_LOG_CAT_21 = 1 << 20, - GS_LOG_CAT_22 = 1 << 21, - GS_LOG_CAT_23 = 1 << 22, - GS_LOG_CAT_24 = 1 << 23, - GS_LOG_CAT_25 = 1 << 24, - GS_LOG_CAT_26 = 1 << 25, - GS_LOG_CAT_27 = 1 << 26, - GS_LOG_CAT_28 = 1 << 27, - GS_LOG_CAT_29 = 1 << 28, - GS_LOG_CAT_30 = 1 << 29, - GS_LOG_CAT_31 = 1 << 30, - //! Product or mission specific - start here and down - GS_LOG_CAT_32 = 1 << 31, -#endif -} gs_log_category_t; - -/** - @defgroup reserved_log_categories Reserved/assigned log categories. - These categories are assigned/reserved for certain sub-systems. - @{ -*/ - /** - Default, used if nothing else fits. - */ -#define GS_LOG_CAT_DEFAULT GS_LOG_CAT_1 - /** - Driver layer. - */ -#define GS_LOG_CAT_DRIVER GS_LOG_CAT_2 - /** - CSP. - */ -#define GS_LOG_CAT_CSP GS_LOG_CAT_3 - /** - Parameter system. - */ -#define GS_LOG_CAT_PARAM GS_LOG_CAT_4 - /** - File system. - */ -#define GS_LOG_CAT_FILE_SYSTEM GS_LOG_CAT_5 - /** - Command framework and execution. - */ -#define GS_LOG_CAT_COMMAND GS_LOG_CAT_6 - /** - Housekeeping System. - */ -#define GS_LOG_CAT_HK GS_LOG_CAT_7 - /** - Flight Planner. - */ -#define GS_LOG_CAT_FP GS_LOG_CAT_8 - /** - ADCS - */ -#define GS_LOG_CAT_ADCS GS_LOG_CAT_9 -/** @} */ - -struct gs_log_list; /* forward declared private log list struct */ -/** - Log list type (private) - - Private gs_log_list type. -*/ -typedef struct gs_log_list gs_log_list_t; - -/** - Log group. - All logs are logged to a \a group. The group contains the current log level mask, - which controls whether the log is carried through or not. -*/ -typedef struct { - /** - Name of log group. - */ - const char * name; - /** - Category, see #gs_log_category_t. - */ - uint32_t category; - /** - Current level mask, see #gs_log_level_t. - */ - uint8_t mask; - /** - Is group additive, if \a true (default) logging will be done on both root appenders and this groups appenders - if \a false, logging will only be done to this groups appenders. - */ - bool additivity; - /** - Private list of appenders. - */ - gs_log_list_t * appenders; -#if (__AVR__) - uint16_t dummy_align; -#endif -} gs_log_group_t; - -/** - Log masks (levels converted to mask). - @{ -*/ -/** - Trace level enabled. -*/ -#define GS_LOG_TRACE_MASK (1 << GS_LOG_TRACE) -/** - Debug level enabled. -*/ -#define GS_LOG_DEBUG_MASK (1 << GS_LOG_DEBUG) -/** - Info level enabled. -*/ -#define GS_LOG_INFO_MASK (1 << GS_LOG_INFO) -/** - Notice level enabled. -*/ -#define GS_LOG_NOTICE_MASK (1 << GS_LOG_NOTICE) -/** - Warning level enabled. -*/ -#define GS_LOG_WARNING_MASK (1 << GS_LOG_WARNING) -/** - Error level enabled. -*/ -#define GS_LOG_ERROR_MASK (1 << GS_LOG_ERROR) -/** - All levels enabled. -*/ -#define GS_LOG_ALL_MASK (GS_LOG_TRACE_MASK | GS_LOG_DEBUG_MASK | GS_LOG_INFO_MASK | GS_LOG_NOTICE_MASK | GS_LOG_WARNING_MASK | GS_LOG_ERROR_MASK) -/** - Default levels enabled - #GS_LOG_ERROR, #GS_LOG_WARNING and #GS_LOG_NOTICE. -*/ -#define GS_LOG_DEFAULT_MASK (GS_LOG_ERROR_MASK | GS_LOG_WARNING_MASK | GS_LOG_NOTICE_MASK) -/** - Trace level enabled. - @deprecated use #GS_LOG_TRACE_MASK -*/ -#define LOG_TRACE_MASK GS_LOG_TRACE_MASK -/** - Debug level enabled. - @deprecated use #GS_LOG_DEBUG_MASK -*/ -#define LOG_DEBUG_MASK GS_LOG_DEBUG_MASK -/** - Info level enabled. - @deprecated use #GS_LOG_INFO_MASK -*/ -#define LOG_INFO_MASK GS_LOG_INFO_MASK -/** - Notice level enabled. - @deprecated use #GS_LOG_NOTICE_MASK -*/ -#define LOG_NOTICE_MASK GS_LOG_NOTICE_MASK -/** - Warning level enabled. - @deprecated use #GS_LOG_WARNING_MASK -*/ -#define LOG_WARNING_MASK GS_LOG_WARNING_MASK -/** - Error level enabled. - @deprecated use #GS_LOG_ERROR_MASK -*/ -#define LOG_ERROR_MASK GS_LOG_ERROR_MASK -/** - All levels enabled. - @deprecated use #GS_LOG_ALL_MASK -*/ -#define LOG_ALL_MASK GS_LOG_ALL_MASK -/** - Default levels enabled - #GS_LOG_ERROR, #GS_LOG_WARNING and #GS_LOG_NOTICE. - @deprecated use #GS_LOG_DEFAULT_MASK -*/ -#define LOG_DEFAULT_MASK GS_LOG_DEFAULT_MASK -/**@}*/ - -/** - Define/Create a log group. - - @note name clash: This defines a variable, which potentially is \a global, meaning possibility of name clashes. Therefore log group should always - be prefixed with something that makes it fairly unique, i.e. component name. Example: gs_a3200dock_log - log group used by liba3200dock library. - - @param[in] group name of variables created. See note above about name clash. - @param[in] name_in display name - @param[in] cat_in log group category - @param[in] level_mask log level mask. -*/ -#define GS_LOG_GROUP(group, name_in, cat_in, level_mask) \ - gs_log_group_t group##_s = {.name = name_in, .category = cat_in, \ - .mask = level_mask, .additivity = true, \ - .appenders = NULL}; \ - gs_log_group_t * group = &group##_s - -/** - Define log group with initial mask for \a print and \a store. - - @note name clash: This defines a variable, which potentially is \a global, meaning possibility of name clashes. Therefore log group should always - be prefixed with something that makes it fairly unique, i.e. component name. Example: gs_a3200dock_log - log group used by liba3200dock library. - - @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(...) instead. - - @param[in] group name of variables created. See note above about name clash. - @param[in] name_in display name - @param[in] print_mask enable mask for \a print. - @param[in] store_mask enable mask for \a store. -*/ -#define LOG_GROUP_MASKED(group, name_in, print_mask, store_mask) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, (print_mask | store_mask)) - -/** - Declare log group as external (defined else where). - - @param[in] group the log group variable defined elsewhere. -*/ -#define GS_LOG_GROUP_EXTERN(group) extern gs_log_group_t * group - -/** - Define log group - levels are #GS_LOG_DEFAULT_MASK - - @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(..) instead. -*/ -#define LOG_GROUP(group, name_in) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, LOG_DEFAULT_MASK) - -/** - Define verbose log group - all levels are enabled (#GS_LOG_ALL_MASK) - - @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(..) instead. -*/ -#define LOG_GROUP_VERBOSE(group, name_in) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, LOG_ALL_MASK) - -/** - Define silent log group - all levels are disabled. - - @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(..) instead. -*/ -#define LOG_GROUP_SILENT(group, name_in) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, 0) - -/** - Declare log group as external (defined else where). - - @deprecated use #GS_LOG_GROUP_EXTERN(...) instead. -*/ -#define LOG_GROUP_EXTERN(group) GS_LOG_GROUP_EXTERN(group) - -/** - Default log group. - This can be overridden by a define -*/ -extern gs_log_group_t * LOG_DEFAULT; - -/** - Initializes the log system. - - @param[in] with_console_appender Enable/Disable console log appender - @return_gs_error_t -*/ -gs_error_t gs_log_init(bool with_console_appender); - -/** - Set log group level mask. - - @param[in] group_name log group name - @param[in] mask level mask to set. - @return_gs_error_t -*/ -gs_error_t gs_log_group_set_level_mask(const char * group_name, uint8_t mask); - -/** - Get log group level mask. - - @param[in] group_name log group name - @param[out] mask returned current level mask. - @return_gs_error_t -*/ -gs_error_t gs_log_group_get_level_mask(const char * group_name, uint8_t *mask); - -/** - Log group iterator callback function - - @param[in] ctx context data for iterator. - @param[in] group log group being iterated. - - @return true/false: Return false to discontinue iteration. -*/ -typedef bool (*gs_log_group_iterator_t)(void *ctx, gs_log_group_t * group); - -/** - Iterate all or specific log group(s). - - @param[in] group_name name of log group, or NULL/\"all\" for all groups. - @param[in] ctx user context data. - @param[in] iter iterator, return \a true to continue, \a false to break iteration. - @return_gs_error_t -*/ -gs_error_t gs_log_group_iterate(const char * group_name, void * ctx, gs_log_group_iterator_t iter); - -/** - Register a log group in the log system. - - The log group will be added to a system wide list of log groups, enabling list and set of level. - - @note The group must remain valid during the life-time of the application. - - @param[in] group The log group to be added to the system. - @return_gs_error_t -*/ -gs_error_t gs_log_group_register(gs_log_group_t *group); - -/** - Register a log group in the log system. - - @note The group must stay in memory during the life-time of the application - @see gs_log_group_register() - @param[in] group The log group to be added to the system. - @return_gs_error_t -*/ -static inline gs_error_t gs_log_group_add(gs_log_group_t *group) -{ - return gs_log_group_register(group); -} - -/** - Checks if a level is enabled on a log group - - @param[in] group The log group to check. - @param[in] level The log level to check if it's set on the group. - @return bool (true if enabled / false if not enabled) -*/ -bool gs_log_group_is_level_enabled(gs_log_group_t *group, gs_log_level_t level); - -/** - Convert string to log level. - - @param[in] str log level. - @param[out] return_level converted log level. - @return_gs_error_t -*/ -gs_error_t gs_log_string_to_level(const char * str, gs_log_level_t * return_level); - -/** - Convert level to single character. - - @param[in] level log level - @return single character representing the \a level. -*/ -char gs_log_level_to_char(gs_log_level_t level); - - -/** - Register Log commands. - @return_gs_error_t -*/ -gs_error_t gs_log_register_commands(void); - -/** - Generic log. - @note This function should not be called directly, use log macros. - - @param level log level - @param group log group. If NULL, the \a default log group will be used. - @param format Format string (printf style). -*/ -void gs_log(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) __attribute__ ((format (__printf__, 3, 4))); - -/** - Generic log from ISR. - @note This function should not be called directly, use log macros. - - @param level log level - @param group log group. If NULL, the \a default log group will be used. - @param format Format string (printf style). -*/ -void gs_log_isr(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) __attribute__ ((format (__printf__, 3, 4))); - -/** - Generic log (va_list). - @note This function should not be called directly, use log macros. - - @param level log level - @param group log group. If NULL, the \a default log group will be used. - @param format Format string (printf style). - @param args arguments for \a format. -*/ -void gs_log_va(gs_log_level_t level, gs_log_group_t * group, const char * format, va_list args); - -/** - Enable/disable color in \a print logs. - Default is \a enabled/true. - - @param[in] color \a true to enable color, \a false disable color. -*/ -void gs_log_set_print_color(bool color); - -/** - Level to color (begin). - - @param[in] level log level. - @return color string. -*/ -const char * gs_log_level_to_color_begin(gs_log_level_t level); - -/** - Level to color (end). - - @return color string. -*/ -const char * gs_log_level_to_color_end(void); - -/** - Take a level as input an create a level mask enabling all - levels with priority >= level. - - If level is e.g. LOG_INFO, the mask will enable Error, Warn & Info. - - * @param level the log level. - * @return level mask - */ -uint8_t gs_log_level_to_mask(gs_log_level_t level); - -/** - Convert string to log mask. - - Format: [+-]level[,[+-]level] - - + add level, - remove level. - - @param[in] str log mask - @param[in] current_mask current mask, used when input format contains + or -. - @param[out] return_mask converted log mask. - @return_gs_error_t -*/ -gs_error_t gs_log_string_to_mask(const char *str, uint8_t current_mask, uint8_t * return_mask); - -#if !(__DOXYGEN__) -/** - Internal macro for checking if log is enabled, before making log. -*/ -#define __gs_log(level, group, format, ...) \ - if (group->mask & (1 << level)) { \ - gs_log(level, group, GS_PGM_STR(format), ##__VA_ARGS__); \ - } - -/** - Internal macro for checking if log is enabled for isr, before making log. -*/ -#define __gs_log_isr(level, group, format, ...) \ - if (group->mask & (1 << level)) { \ - gs_log_isr(level, group, GS_PGM_STR(format), ##__VA_ARGS__); \ - } - -/** - Internal macro used for performing a log only once. - @note This creates a \a static \a variable. -*/ -#define __gs_log_once(level, group, format, ...) \ - ({ \ - static bool print_once; \ - if (!print_once) { \ - print_once = true; \ - __gs_log(level, group, format, ##__VA_ARGS__); \ - } \ - }) -#endif // __DOXYGEN__ - -/** - Default compile-time enabling/disabling of all levels - Unless levels are individually defined, this will be the default value. -*/ -#if !defined(GS_LOG_DISABLE_ALL) -#define GS_LOG_DISABLE_ALL 0 -#endif - -/** - Disable \a error level compile-time by defining a value > 0 -*/ -#if !defined(GS_LOG_DISABLE_ERROR) -#define GS_LOG_DISABLE_ERROR GS_LOG_DISABLE_ALL -#endif - -/** - Disable \a warning level compile-time by defining a value > 0 -*/ -#if !defined(GS_LOG_DISABLE_WARNING) -#define GS_LOG_DISABLE_WARNING GS_LOG_DISABLE_ALL -#endif - -/** - Disable \a notice level compile-time by defining a value > 0 -*/ -#if !defined(GS_LOG_DISABLE_NOTICE) -#define GS_LOG_DISABLE_NOTICE GS_LOG_DISABLE_ALL -#endif - -/** - Disable \a info level compile-time by defining a value > 0 -*/ -#if !defined(GS_LOG_DISABLE_INFO) -#define GS_LOG_DISABLE_INFO GS_LOG_DISABLE_ALL -#endif - -/** - Disable \a debug level compile-time by defining a value > 0 -*/ -#if !defined(GS_LOG_DISABLE_DEBUG) -#define GS_LOG_DISABLE_DEBUG GS_LOG_DISABLE_ALL -#endif - -/** - Disable \a trace level compile-time by defining a value > 0 -*/ -#if !defined(GS_LOG_DISABLE_TRACE) -#define GS_LOG_DISABLE_TRACE GS_LOG_DISABLE_ALL -#endif - -/** - Log \a error to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_error(format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log(LOG_ERROR, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a error from ISR to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_error_isr(format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log_isr(LOG_ERROR, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a error to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_error_group(group, format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log(LOG_ERROR, (group), format, ##__VA_ARGS__); } - -/** - Log \a error only once to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_error_once(format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log_once(LOG_ERROR, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a error only once to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_error_once_group(group, format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log_once(LOG_ERROR, (group), format, ##__VA_ARGS__); } - -/** - Log \a warning to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_warning(format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log(LOG_WARNING, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a warning from ISR to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_warning_isr(format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log_isr(LOG_WARNING, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a warning to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_warning_group(group, format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log(LOG_WARNING, (group), format, ##__VA_ARGS__); } - -/** - Log \a warning only once to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_warning_once(format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log_once(LOG_WARNING, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a warning only once to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_warning_once_group(group, format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log_once(LOG_WARNING, (group), format, ##__VA_ARGS__); } - -/** - Log \a notice to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_notice(format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log(LOG_NOTICE, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a notice from ISR to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_notice_isr(format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log_isr(LOG_NOTICE, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a notice to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_notice_group(group, format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log(LOG_NOTICE, (group), format, ##__VA_ARGS__); } - -/** - Log \a notice only once to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_notice_once(format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log_once(LOG_NOTICE, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a notice only once to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_notice_once_group(group, format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log_once(LOG_NOTICE, (group), format, ##__VA_ARGS__); } - -/** - Log \a info to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_info(format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log(LOG_INFO, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a info from ISR to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_info_isr(format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log_isr(LOG_INFO, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a info to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_info_group(group, format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log(LOG_INFO, (group), format, ##__VA_ARGS__); } - -/** - Log \a info only once to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_info_once(format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log_once(LOG_INFO, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a info only once to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_info_once_group(group, format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log_once(LOG_INFO, (group), format, ##__VA_ARGS__); } - -/** - Log \a debug to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_debug(format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log(LOG_DEBUG, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a debug from ISR to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_debug_isr(format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log_isr(LOG_DEBUG, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a debug to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_debug_group(group, format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log(LOG_DEBUG, (group), format, ##__VA_ARGS__); } - -/** - Log \a debug only once to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_debug_once(format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log_once(LOG_DEBUG, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a debug only once to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_debug_once_group(group, format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log_once(LOG_DEBUG, (group), format, ##__VA_ARGS__); } - -/** - Log \a trace to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_trace(format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log(LOG_TRACE, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a trace from ISR to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_trace_isr(format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log_isr(LOG_TRACE, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a trace to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_trace_group(group, format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log(LOG_TRACE, (group), format, ##__VA_ARGS__); } - -/** - Log \a trace only once to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_trace_once(format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log_once(LOG_TRACE, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a trace only once to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_trace_once_group(group, format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log_once(LOG_TRACE, (group), format, ##__VA_ARGS__); } - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/minmax.h b/gomspace/libutil/include/gs/util/minmax.h deleted file mode 100644 index 4b9edf74..00000000 --- a/gomspace/libutil/include/gs/util/minmax.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef GS_UTIL_MINMAX_H -#define GS_UTIL_MINMAX_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Min/max utilities. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Return minimum value. - @param[in] x value - @param[in] y value - @return the lowest value of the input parameters. -*/ -#define gs_min(x,y) ({ \ - __typeof__ (x) _x = (x); \ - __typeof__ (y) _y = (y); \ - _x < _y ? _x : _y; }) - -/** - Return maximum value. - @param[in] x value - @param[in] y value - @return the maximum value of the input parameters. -*/ -#define gs_max(x,y) ({ \ - __typeof__ (x) _x = (x); \ - __typeof__ (y) _y = (y); \ - _x > _y ? _x : _y; }) - -/** - Return minimum value. - @param[in] x value - @param[in] y value - @param[in] z value - @return the lowest value of the input parameters. -*/ -#define gs_min3(x,y,z) gs_min(gs_min((x),(y)), (z)) - -/** - Return maximum value. - @param[in] x value - @param[in] y value - @param[in] z value - @return the maximum value of the input parameters. -*/ -#define gs_max3(x,y,z) gs_max(gs_max((x),(y)), (z)) - -/** - Clamp value within min/max. - @param[in] x value - @param[in] _max max value - @param[in] _min min value - @return value between min and max. -*/ -#define gs_clamp(x, _min, _max) ({ \ - gs_min(gs_max((x), (_min)), (_max)); }) - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/mutex.h b/gomspace/libutil/include/gs/util/mutex.h deleted file mode 100644 index b5a411f7..00000000 --- a/gomspace/libutil/include/gs/util/mutex.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef GS_UTIL_MUTEX_H -#define GS_UTIL_MUTEX_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Mutex (recursive). - - The mutex API wraps POSIX \a pthread_mutex and FreeRTOS \a mutex. - - @note Mutex can not be used from within an ISR routine - use gs_sem instead. -*/ - -#include -#if __linux__ -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if __linux__ -/** - Mutex handle. -*/ -typedef pthread_mutex_t * gs_mutex_t; -#else -typedef struct gs_freertos_mutex_t * gs_mutex_t; -#endif - -/** - Create mutex. - @param[out] mutex handle. - @return error code. -*/ -gs_error_t gs_mutex_create(gs_mutex_t * mutex); - -/** - Destroy mutex - free resources. - @param[in] mutex handle. - @return error code. -*/ -gs_error_t gs_mutex_destroy(gs_mutex_t mutex); - -/** - Lock mutex. - @param[in] mutex handle. - @return error code. -*/ -gs_error_t gs_mutex_lock(gs_mutex_t mutex); - -/** - Unlock mutex. - @param[in] mutex handle. - @return error code. -*/ -gs_error_t gs_mutex_unlock(gs_mutex_t mutex); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/pgm.h b/gomspace/libutil/include/gs/util/pgm.h deleted file mode 100644 index 04e39013..00000000 --- a/gomspace/libutil/include/gs/util/pgm.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef GS_UTIL_PROGMEM_H -#define GS_UTIL_PROGMEM_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Macros for handling special memory access. - - On most targets/processors, constant data/strings are located in the program space and can be read in the same way as data in the data space. - However, on a few targets (e.g. avr/avr8), data/strings must be marked in a special way in order to go into the program space, see #GS_PGM_STR() - - Using following macros, will make it easier to make cross-platform code and avoid \#if/\#endif. - These macros should only be used where the code also needs to run on avr/avr8. - - @note Including this header on avr/avr8 will REDEFINE printf!. - - http://www.atmel.com/webdoc/avrlibcreferencemanual/group__avr__pgmspace.html. - http://www.nongnu.org/avr-libc/user-manual/pgmspace.html. -*/ - -#include -#if defined(__AVR__) -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(__AVR__) || (__DOXYGEN__) -/** - Special program/data memory handling. -*/ -#define GS_PGM 1 - -/** - Place object in program space (must be const). - Example: static const uint8_t data8[] GS_PGM_OBJECT = {1, 255}; -*/ -#define GS_PGM_OBJECT PROGMEM - -/** - Place const string in program space. - By default the string goes into data, uses thereby uses up space. - Once the string is placed in program space, xx_P functions must be used to access them - see #GS_PGM_PRINTF. - @note printf is re-defined by including this header -*/ -#define GS_PGM_STR(str) PSTR(str) - -/** - Read uint8 from program space (near). -*/ -#define GS_PGM_UINT8(value) pgm_read_byte(&(value)) - -/** - Read uint8 from program space using a pointer (near). -*/ -#define GS_PGM_UINT8_BY_PTR(value) pgm_read_byte(value) - -/** - Read word from program space (near). -*/ -#define GS_PGM_UINT16(value) pgm_read_word(&(value)) -/** - Read word from program space using a pointer (near). -*/ -#define GS_PGM_UINT16_BY_PTR(value) pgm_read_word(value) - -/** - Read dword from program space (near). -*/ -#define GS_PGM_UINT32(value) pgm_read_dword(&(value)) -/** - Read word from program space using a pointer (near). -*/ -#define GS_PGM_UINT32_BY_PTR(value) pgm_read_dword(value) - -/** - Memcpy from program space (near). - @param[in] dst destination. - @param[in] src source - program space. - @param[in] n number of bytes to copy -*/ -#define GS_PGM_MEMCPY(dst, src, n) memcpy_P(dst, src, n) - -/** - String compare (program space) - @param[in] s1 string 1 - @param[in] s2 string 2 - program space. - @param[in] n max number of bytes to compare -*/ -#define GS_PGM_STRNCMP(s1,s2,n) strncmp_P(s1, s2, n) - -/** - String compare (program space) - @param[in] s1 string 1 - @param[in] s2 string 2 - program space. - @param[in] n max number of bytes to compare -*/ -#define GS_PGM_STRNCASECMP(s1,s2,n) strncasecmp_P(s1, s2, n) - -/** - String formatting character for referencing a string placed in programs space. -*/ -#define GS_PGM_FMT_STR "S" - -/** - printf (format string in program space). - Example: print \a param->name (from prgram space) and \a value from data space, using a format string in program space. - GS_PGM_PRINTF(GS_PGM_STR("%"GS_PGM_FMT_STR", %d"), param->name, value) -*/ -#define GS_PGM_PRINTF(format, ...) printf_P(format, ##__VA_ARGS__) - -/** - vprintf (format string in program space). -*/ -#define GS_PGM_VPRINTF(format, va) vfprintf_P(stdout, format, va) - -/** - snprintf (format string in program space). -*/ -#define GS_PGM_SNPRINTF(buf, bufsize, format, ...) snprintf_P(buf, bufsize, format, ##__VA_ARGS__) - -/** - vsnprintf (format string in program space). -*/ -#define GS_PGM_VSNPRINTF(buf, bufsize, format, va) vsnprintf_P(buf, bufsize, format, va) - -/** - redefines printf (puts format string in program space) - */ -#undef printf -#define printf(format, ...) GS_PGM_PRINTF(GS_PGM_STR(format), ## __VA_ARGS__) - -#else - -#undef GS_PGM - -#define GS_PGM_OBJECT -#define GS_PGM_STR(str) (str) -#define GS_PGM_UINT8(value) (value) -#define GS_PGM_UINT8_BY_PTR(value) (*(value)) -#define GS_PGM_UINT16(value) (value) -#define GS_PGM_UINT16_BY_PTR(value) (*(value)) -#define GS_PGM_UINT32(value) (value) -#define GS_PGM_UINT32_BY_PTR(value) (*(value)) -#define GS_PGM_MEMCPY(dst, src, size) memcpy(dst, src, size) -#define GS_PGM_STRNCMP(s1,pgmstr,size) strncmp(s1, pgmstr, size) -#define GS_PGM_STRNCASECMP(s1,pgmstr,size) strncasecmp(s1, pgmstr, size) - -#define GS_PGM_FMT_STR "s" -#define GS_PGM_PRINTF(format, ...) printf(format, ## __VA_ARGS__) -#define GS_PGM_VPRINTF(format, va) vprintf(format, va) -#define GS_PGM_SNPRINTF(buf, bufsize, format, ...) snprintf(buf, bufsize, format, ##__VA_ARGS__) -#define GS_PGM_VSNPRINTF(buf, bufsize, format, va) vsnprintf(buf, bufsize, format, va) - -#endif - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/queue.h b/gomspace/libutil/include/gs/util/queue.h deleted file mode 100644 index 43b7e9ae..00000000 --- a/gomspace/libutil/include/gs/util/queue.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef GS_UTIL_QUEUE_H -#define GS_UTIL_QUEUE_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Queue. - - The queue API wraps FreeRTOS \a queue. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if __linux__ -/** - Queue handle. -*/ -typedef struct gs_pthread_queue * gs_queue_t; -#else -typedef struct gs_freertos_queue_t * gs_queue_t; -#endif - -/** - Create queue. - - @param[in] items max number of items on the queue. - @param[in] item_size size of item (bytes). - @param[out] queue created queue. - @return_gs_error_t -*/ -gs_error_t gs_queue_create(size_t items, size_t item_size, gs_queue_t * queue); - -/** - Destroy queue - free resources. - - @param[in] queue handle. - @return_gs_error_t -*/ -gs_error_t gs_queue_destroy(gs_queue_t queue); - -/** - Enqueue object on queue. - @param[in] queue handle. - @param[in] value pointer to object, size specified at gs_queue_create(). - @param_int_timeout_ms - @return_gs_error_timeout - @return_gs_error_t -*/ -gs_error_t gs_queue_enqueue(gs_queue_t queue, const void *value, int timeout_ms); - -/** - Enqueue object on queue from within an ISR. - @param[in] queue handle. - @param[in] value pointer to object, size specified at gs_queue_create(). - @param[in] cswitch context switch. - @return GS_ERROR_FULL if queue is full. - @return_gs_error_t -*/ -gs_error_t gs_queue_enqueue_isr(gs_queue_t queue, const void * value, gs_context_switch_t * cswitch); - -/** - Dequeue object from queue. - @param[in] queue handle. - @param[out] buf element - size specified in gs_queue_create(). - @param_int_timeout_ms - @return_gs_error_timeout - @return_gs_error_t -*/ -gs_error_t gs_queue_dequeue(gs_queue_t queue, int timeout_ms, void *buf); - -/** - Dequeue object from queue from within an ISR. - @param[in] queue handle. - @param[in] cswitch context switch. - @param[out] buf element - size specified in gs_queue_create(). - @return GS_ERROR_NOT_FOUND if no elements in queue. - @return_gs_error_t -*/ -gs_error_t gs_queue_dequeue_isr(gs_queue_t queue, gs_context_switch_t * cswitch, void * buf); - -/** - Return queue size. - @param[in] queue handle. - @return queue size -*/ -unsigned int gs_queue_size(gs_queue_t queue); - -/** - Return queue size from within an ISR. - @param[in] queue handle. - @return queue size -*/ -unsigned int gs_queue_size_isr(gs_queue_t queue); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/rtc.h b/gomspace/libutil/include/gs/util/rtc.h deleted file mode 100644 index b1988925..00000000 --- a/gomspace/libutil/include/gs/util/rtc.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef GS_UTIL_RTC_H -#define GS_UTIL_RTC_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Real Time Clock interface. - - The RTC driver is used by gs_clock_get_time() and gs_clock_set_time(). -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Platform supporting RTC must register the driver, before the rest of the system can access it. - @see gs_rtc_register() -*/ -typedef struct { - /** - Call-back for getting RTC time. - @param[out] time user allocated struct for returning time. - */ - gs_error_t (*get_time)(void * driver_data, gs_timestamp_t * time); - /** - Call-back for setting RTC time. - @param[in] time user allocated struct for returning time. - */ - gs_error_t (*set_time)(void * driver_data, const gs_timestamp_t * time); -} gs_rtc_driver_t; - -/** - Register RTC driver. - @param[in] driver driver - data/struct must remain valid as long as registered. - @param[in] driver_data driver specific data, forwarded to driver when set/get is called. - @return_gs_error_t -*/ -gs_error_t gs_rtc_register(const gs_rtc_driver_t * driver, void * driver_data); - -/** - Return GS_OK if RTC is supported. -*/ -gs_error_t gs_rtc_supported(void); - -/** - Set RTC. -*/ -gs_error_t gs_rtc_get_time(gs_timestamp_t * time); - -/** - Get RTC. -*/ -gs_error_t gs_rtc_set_time(const gs_timestamp_t * time); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/sem.h b/gomspace/libutil/include/gs/util/sem.h deleted file mode 100644 index 4afd4d7d..00000000 --- a/gomspace/libutil/include/gs/util/sem.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef GS_UTIL_SEM_H -#define GS_UTIL_SEM_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Semaphore. - - The semaphore API wraps POSIX \a semaphore and FreeRTOS \a counted semaphore. - - Main difference is that FreeRTOS uses different API calls, when called from within - an ISR routine. -*/ - -#include -#if __linux__ -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if __linux__ -/** - Semaphore handle. -*/ -typedef sem_t * gs_sem_t; -#else -typedef struct gs_freertos_sem_t * gs_sem_t; -#endif - -/** - Create semaphore. - @param[in] initialValue initial value. - @param[out] sem created semaphore. - @return_gs_error_t -*/ -gs_error_t gs_sem_create(unsigned int initialValue, gs_sem_t * sem); - -/** - Destroy semaphore - free resources. - @param[in] sem handle. - @return_gs_error_t -*/ -gs_error_t gs_sem_destroy(gs_sem_t sem); - -/** - Wait for semaphore to be signaled. - @param[in] sem handle. - @param_int_timeout_ms - @return_gs_error_timeout - @return_gs_error_t -*/ -gs_error_t gs_sem_wait(gs_sem_t sem, int timeout_ms); - -/** - Post/signal semaphore. - @param[in] sem handle. - @return_gs_error_t -*/ -gs_error_t gs_sem_post(gs_sem_t sem); - -/** - Post/signal semaphore from within a ISR. - @param[in] sem handle. - @param[in] cswitch context switch. - @return_gs_error_t -*/ -gs_error_t gs_sem_post_isr(gs_sem_t sem, gs_context_switch_t * cswitch); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/stdio.h b/gomspace/libutil/include/gs/util/stdio.h deleted file mode 100644 index 992d4dda..00000000 --- a/gomspace/libutil/include/gs/util/stdio.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef GS_UTIL_STDIO_H -#define GS_UTIL_STDIO_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - GomSpace extensions to standard \a stdio.h. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Put character on stdout. -*/ -gs_error_t gs_stdio_putchar(int ch); - -/** - Read character from stdin with timeout. - @param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milli seconds. - @param[out] ch character read. If NULL, one character from stdin is still consumed - but nothing returned. - @return GS_ERROR_TIMEOUT on timeout - @return_gs_error_t -*/ -gs_error_t gs_stdio_getchar_timed(int timeout_ms, int *ch); - -/** - Read character from stdin. - Blocks until a character is available. - @param[out] ch character read. If NULL, one character from stdin is still consumed - but nothing returned. - @return_gs_error_t -*/ -static inline gs_error_t gs_stdio_getchar(int * ch) -{ - return gs_stdio_getchar_timed(-1, ch); -} - -/** - Read characters from stdin. - Blocks until all characters are read. - @param[in,out] buf user supplied buffer for receiving characters. - @param[in] n number of characters to read. - @return_gs_error_t -*/ -gs_error_t gs_stdio_get(char * buf, size_t n); - -/** - Write characters to stdout. - Blocks until characters are written. - @param[in] buf characters to write. - @param[in] n number of characters to write. - @param[in] text if \a true, new lines (\\n) are converted to \\r\\n. - @return_gs_error_t -*/ -gs_error_t gs_stdio_put(const char * buf, size_t n, bool text); - -/** - Pattern for printing a byte as binary. - @see GS_STDIO_BYTETOBINARY() -*/ -#define GS_STDIO_BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d" - -/** - Macro for splitting a byte info 'bits'. -*/ -#define GS_STDIO_BYTETOBINARY(byte) \ - (byte & 0x80 ? 1 : 0), \ - (byte & 0x40 ? 1 : 0), \ - (byte & 0x20 ? 1 : 0), \ - (byte & 0x10 ? 1 : 0), \ - (byte & 0x08 ? 1 : 0), \ - (byte & 0x04 ? 1 : 0), \ - (byte & 0x02 ? 1 : 0), \ - (byte & 0x01 ? 1 : 0) - -/** - Color definitions for gs_color_printf() - @see gs_color_printf() -*/ -typedef enum { - /** - Colors. - */ - GS_COLOR_COLORS = 0x00ff, - GS_COLOR_NONE = 0, - GS_COLOR_BLACK = 1, - GS_COLOR_RED = 2, - GS_COLOR_GREEN = 3, - GS_COLOR_YELLOW = 4, - GS_COLOR_BLUE = 5, - GS_COLOR_MAGENTA = 6, - GS_COLOR_CYAN = 7, - GS_COLOR_WHITE = 8, - /** - Attributes - */ - GS_COLOR_ATTRS = 0xff00, - GS_COLOR_BOLD = 0x100, -} gs_color_printf_t; - -/** - Printf with colors on stdout. - - Using the standard terminal escape sequences for setting the color. - @param[in] color color settings. - @param[in] format standard printf format string. -*/ -void gs_color_printf(gs_color_printf_t color, const char * format, ...) __attribute__ ((format (__printf__, 2, 3))); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/string.h b/gomspace/libutil/include/gs/util/string.h deleted file mode 100644 index 034af8c6..00000000 --- a/gomspace/libutil/include/gs/util/string.h +++ /dev/null @@ -1,391 +0,0 @@ -#ifndef GS_UTIL_STRING_H -#define GS_UTIL_STRING_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - String utilitizes. - - All string parsing functions will return #GS_OK if the string was parsed entirely. - If the string contains characters that are not part of the selected base, the functions will return #GS_ERROR_DATA. - If the value parsed is bigger than the output type, the functions will return #GS_ERROR_OVERFLOW. - Spaces are ignored by all functions. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Macro helper for concatening tokens. -*/ -#define GS_STRINGZ(x) #x - -/** - Stringify a preprocessing token. -*/ -#define GS_DEF2STRING(x) GS_STRINGZ(x) - -/** - * Strncpy (using size of destination) and forced zero termination. - */ -#define GS_STRNCPY(dst,src) strncpy(dst,src,GS_ARRAY_SIZE(dst));dst[GS_ARRAY_SIZE(dst)-1] = 0 - -/** - Convert string to int32 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_int32(const char * string, int32_t * value); - -/** - Convert string to uint32 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_uint32(const char * string, uint32_t * value); - -/** - Convert string to int64 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_int64(const char * string, int64_t * value); - -/** - Convert string to uint64 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_uint64(const char * string, uint64_t * value); - -/** - Convert string to int8 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 12 (decimal), 0x12 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_int8(const char * string, int8_t * value); - -/** - Convert string to uint8 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 12 (decimal), 0x12 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_uint8(const char * string, uint8_t * value); - -/** - Convert string to int16 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_int16(const char * string, int16_t * value); - -/** - Convert string to uint16 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_uint16(const char * string, uint16_t * value); - -/** - Convert string to uint32 (hexadecimal). - Accepts: hexadecimal (no leading 0x), e.g. a123, A123. - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_hex_to_uint32(const char * string, uint32_t * value); - -/** - Convert string to uint64 (hexadecimal). - Accepts: hexadecimal (no leading 0x), e.g. a123, A123. - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_hex_to_uint64(const char * string, uint64_t * value); - -/** - Convert string to boolean. - Accepts: true, false, on, off, 1, 0 (ignores case) - @param[in] string string to convert. - @param[out] pvalue converted value - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_bool(const char * string, bool * pvalue); - -/** - Convert string to float. - @param[in] string string to convert. - @param[out] pvalue converted value - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_float(const char * string, float * pvalue); - -/** - Convert string to double. - @param[in] string string to convert. - @param[out] pvalue converted value - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_double(const char * string, double * pvalue); - -/** - Return string for boolean value (true or false). - @param[in] value value - @return \a 'true' if input is true, else \a 'false'. -*/ -const char * gs_string_from_bool(bool value); - -/** - Convert string to pointer (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_pointer(const char * string, void ** value); - -/** - Format size as Bytes, Kilo or Mega. - - Output examples: \a 512.0B, \a 1.0K and \a 1.0M. - - @param[in] size size in bytes - @param[out] buffer formatted size - @param[in] buffer_size size of \a buf - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -char * gs_string_bytesize(long size, char *buffer, size_t buffer_size); - -/** - GS implementation of gcc's strtol - Instead of setting errno this function takes a pointer to err which is set - the same way as with gcc's strtol - - @param[in] nptr input string - @param[out] endptr the pointer to the end of the string parsed - @param[in] base number system (10 or 16) - @param[out] err return value if overflow - @return converted value -*/ -int32_t gs_string_strto32int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); - -/** - GS implementation of gcc's strtoul - Instead of setting errno this function takes a pointer to err which is set - the same way as with gcc's strtoul - - @param[in] nptr input string - @param[out] endptr the pointer to the end of the string parsed - @param[in] base number system (10 or 16) - @param[out] err return value if overflow - @return converted value -*/ -uint64_t gs_string_strto64uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); - -/** - GS implementation of gcc's strtoul - Instead of setting errno this function takes a pointer to err which is set - the same way as with gcc's strtoul - - @param[in] nptr input string - @param[out] endptr the pointer to the end of the string parsed - @param[in] base number system (10 or 16) - @param[out] err return value if overflow - @return converted value -*/ -int64_t gs_string_strto64int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); - -/** - GS implementation of gcc's strtoul - Instead of setting errno this function takes a pointer to err which is set - the same way as with gcc's strtoul - - @param[in] nptr input string - @param[out] endptr the pointer to the end of the string parsed - @param[in] base number system (10 or 16) - @param[out] err return value if overflow - @return converted value -*/ -uint32_t gs_string_strto32uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); - -/** - Returns pointer to first none-space character. - - @param[in] string string - @return NULL if \a string is NULL, otherwise first none-space character. -*/ -const char * gs_string_skip_leading_spaces(const char * string); - -/** - Check if a string is NULL or empty. - - @param[in] string string - @return true if string is empty or NULL. -*/ -bool gs_string_empty(const char * string); - -/** - Case-insentive wilcard match (similiar to fnmatch). - - Supports following wildcard(s): - - * (asterix) zero or more characters. - - This may be extended in future versions and will not be considered a break of the API. - - @param[in] pattern pattern to match against \a string. - @param[in] string string to match against \a pattern - @return \a true if match, else \ false -*/ -bool gs_string_match(const char * pattern, const char * string); - -/** - Returns \a true if string contains wildcards. - - @param[in] string string to check for wildcards. - @return \a true if string contains wildcards recognized by gs_string_match(). -*/ -bool gs_string_has_wildcards(const char * string); - -/** - Trim string in buffer by removing leading/trailing white space. - - Uses isspace(c). - - @param[in] buffer buffer to trim. - @param[in] buffer_size size of \a buffer. -*/ -void gs_string_trim(char * buffer, size_t buffer_size); - -/** - Returns \a true if string ends with endswith. - - @param[in] string string to check - @param[in] endswith string that string should end with - @return \a true if string endswith endswith -*/ -bool gs_string_endswith(const char * string, const char * endswith); - -/** - Extract suboption from a string. - - @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". - @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). - @param[out] buf user buffer for returning value of sub-option. - @param[in] buf_size size of \a buf user buffer. - @return_gs_error_t -*/ -gs_error_t gs_string_get_suboption(const char * options, const char * suboption, char * buf, size_t buf_size); - -/** - Extract suboption (as string) from a string. - - @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". - @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). - @param[in] def default value, returned if sub-option isn't found. - @param[out] buf user buffer for returning value of sub-option. - @param[in] buf_size size of \a buf user buffer. - @return If the sub-option isn't found, the \a def default value will be copied to \a buf and #GS_OK will be returned. - @return_gs_error_t -*/ -gs_error_t gs_string_get_suboption_string(const char * options, const char * suboption, const char * def, char * buf, size_t buf_size); - -/** - Extract suboption (as uint8) from a string. - - @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". - @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). - @param[in] def default value, returned if sub-option isn't found. - @param[out] value user supplied buffer for returning the value. - @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. - @return_gs_error_t -*/ -gs_error_t gs_string_get_suboption_uint8(const char * options, const char * suboption, uint8_t def, uint8_t * value); - -/** - Extract suboption (as uint16) from a string. - - @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". - @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). - @param[in] def default value, returned if sub-option isn't found. - @param[out] value user supplied buffer for returning the value. - @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. - @return_gs_error_t -*/ -gs_error_t gs_string_get_suboption_uint16(const char * options, const char * suboption, uint16_t def, uint16_t * value); - -/** - Extract suboption (as uint32) from a string. - - @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". - @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). - @param[in] def default value, returned if sub-option isn't found. - @param[out] value user supplied buffer for returning the value. - @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. - @return_gs_error_t -*/ -gs_error_t gs_string_get_suboption_uint32(const char * options, const char * suboption, uint32_t def, uint32_t * value); - -/** - Extract suboption (as bool) from a string. - - @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". - @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). - @param[in] def default value, returned if sub-option isn't found. - @param[out] value user supplied buffer for returning the value. - @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. - @return_gs_error_t -*/ -gs_error_t gs_string_get_suboption_bool(const char * options, const char * suboption, bool def, bool * value); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/test/cmocka.h b/gomspace/libutil/include/gs/util/test/cmocka.h deleted file mode 100644 index 43648627..00000000 --- a/gomspace/libutil/include/gs/util/test/cmocka.h +++ /dev/null @@ -1,136 +0,0 @@ -#ifndef GS_UTIL_TEST_CMOCKA_H -#define GS_UTIL_TEST_CMOCKA_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Cmocka extensions. - - Official site for cmocka https://cmocka.org. -*/ - -#include - -// cmocka -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if !(__DOXYGEN__) -// internal helpers - use macros -void _gs_assert_int_equal(const intptr_t a, const intptr_t b, bool equal, const char * const file, const int line); -void _gs_assert_uint_equal(const uintptr_t a, const uintptr_t b, bool equal, bool hex, const char * const file, const int line); -void _gs_assert_error_equal(const int a, const int b, bool equal, const char * const file, const int line); -void _gs_assert_float_equal(const float a, const float b, const float diff, bool equal, const char * const file, const int line); -void _gs_assert_double_equal(const double a, const double b, const double diff, bool equal, const char * const file, const int line); -#endif - -/** - Assert int (print value as signed). -*/ -#define GS_ASSERT_INT_EQUAL(a,b) _gs_assert_int_equal((intptr_t) (a), (intptr_t) (b), true, __FILE__, __LINE__) -/** - Assert unsigned int (print value as unsigned). -*/ -#define GS_ASSERT_UINT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, false, __FILE__, __LINE__) -/** - Assert int (print value as hex). -*/ -#define GS_ASSERT_XINT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, true, __FILE__, __LINE__) -/** - Assert #gs_error_t (print value and error text). -*/ -#define GS_ASSERT_ERROR_EQUAL(a,b) _gs_assert_error_equal(a, b, true, __FILE__, __LINE__) -/** - Assert #GS_OK (print value and error text). -*/ -#define GS_ASSERT_ERROR_OK(a) _gs_assert_error_equal(a, GS_OK, true, __FILE__, __LINE__) -/** - Assert float (print value as signed). -*/ -#define GS_ASSERT_FLOAT_EQUAL(a,b,diff) _gs_assert_float_equal(a, b, diff, true, __FILE__, __LINE__) -/** - Assert double (print value as signed). -*/ -#define GS_ASSERT_DOUBLE_EQUAL(a,b,diff) _gs_assert_double_equal(a, b, diff, true, __FILE__, __LINE__) - -/** - Assert int (print value as signed). -*/ -#define GS_ASSERT_INT_NOT_EQUAL(a,b) _gs_assert_int_equal((intptr_t) (a), (intptr_t) (b), false, __FILE__, __LINE__) -/** - Assert unsigned int (print value as unsigned). -*/ -#define GS_ASSERT_UINT_NOT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), false, false, __FILE__, __LINE__) -/** - Assert int (print value as hex). -*/ -#define GS_ASSERT_XINT_NOT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), false, true, __FILE__, __LINE__) -/** - Assert #GS_OK (print value and error text). -*/ -#define GS_ASSERT_ERROR_NOT_EQUAL(a,b) _gs_assert_error_equal(a, b, false, __FILE__, __LINE__) - -/** - Code reference. -*/ -#define GS_REF() __FILE__,__LINE__ -/** - Assert int with code reference (print value as signed). -*/ -#define GS_ASSERT_INT_EQUAL_REF(a,b,file,line) _gs_assert_int_equal((intptr_t) (a), (intptr_t) (b), true, file, file, line) -/** - Assert unsigned int with code reference (print value as unsigned). -*/ -#define GS_ASSERT_UINT_EQUAL_REF(a,b,file,line) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, false, file, line) -/** - Assert int with code reference (print value as hex). -*/ -#define GS_ASSERT_XINT_EQUAL_REF(a,b,file,line) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, true, file, line) -/** - Assert #gs_error_t with code reference (print value and error text). -*/ -#define GS_ASSERT_ERROR_EQUAL_REF(a,b,file,line) _gs_assert_error_equal(a, b, true, file, line) -/** - Assert #GS_OK with code reference (print value and error text). -*/ -#define GS_ASSERT_ERROR_OK_REF(a,file,line) _gs_assert_error_equal(a, GS_OK, true, file, line) - -/** - Run \a cmocka test group. - - @param[in] name name of test. If name is \a tests and GS_TEST_NAME is set, GS_TEST_NAME will be used instead. - @param[in] tests array of tests. - @param[in] num_tests number of tests. - @param[in] setup setup function, can be NULL. - @param[in] teardown teardown function, can be NULL. - @return 0 on success. -*/ -static inline int gs_cmocka_run_group_tests(const char *name, - const struct CMUnitTest * const tests, - const size_t num_tests, - CMFixtureFunction setup, - CMFixtureFunction teardown) -{ -#ifdef GS_TEST_NAME // set by buildtools::gs_test_cmocka.py - if (strcasecmp(name, "tests") == 0) { - name = GS_DEF2STRING(GS_TEST_NAME); - } -#endif - return _cmocka_run_group_tests(name, tests, num_tests, setup, teardown); -} - -#ifdef GS_TEST_NAME -// hi-jack cmocka's macro -#undef cmocka_run_group_tests -#define cmocka_run_group_tests(tests, setup, teardown) gs_cmocka_run_group_tests(GS_DEF2STRING(tests), tests, GS_ARRAY_SIZE(tests), setup, teardown) -#endif - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/test/command.h b/gomspace/libutil/include/gs/util/test/command.h deleted file mode 100644 index d2227017..00000000 --- a/gomspace/libutil/include/gs/util/test/command.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef GS_UTIL_TEST_COMMAND_H -#define GS_UTIL_TEST_COMMAND_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Command Test framework. - - Provides a simple way of unit-testing/validating commands. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Validate command execution. - - Runs a commands and validates the output/results agains the inputs. - Asserts if the results does not match. - - @param[in] cmd command (including arguments) to execute. - @param[in] ret expected return code from the command execution framework. - @param[in] cmd_ret expected return code from the commands handler. This is only validated if (ret = GS_OK). - @param[in] std_in string with expected command input. - @param[in] std_out string with expected command output. Wildcards (*\/?) are supported. - @param[in] file string with file name. - @param[in] line string with line no. - @return void -*/ -void _gs_assert_command_validate(const char *cmd, gs_error_t ret, gs_error_t cmd_ret, const char *std_in, const char *std_out, const char * const file, const int line); - -/** - Validate command results returned from last command execution. - Asserts if the results does not match. - - @param[in] no the result no to verify. - @param[in] group string with expected group id. Wildcards (*\/?) are supported. - @param[in] key string with expected key. Wildcards (*\/?) are supported. - @param[in] value string with expected value. Wildcards (*\/?) are supported. - @param[in] file string with file name. - @param[in] line string with line no. - @return void -*/ -void _gs_assert_command_validate_last_result(unsigned int no, const char *group, const char *key, const char *value, const char * const file, const int line); - -/** - Validate command execution. - - Runs a commands and validates the output/results agains the inputs. - Asserts if the results does not match. - - @param[in] cmd command (including arguments) to execute. - @param[in] ret expected return code from the command execution framework. - @param[in] cmd_ret expected return code from the commands handler. This is only validated if (ret = GS_OK). - @param[in] std_in string with expected command input. - @param[in] std_out string with expected command output. Wildcards (*\/?) are supported. - @return void -*/ -#define GS_ASSERT_COMMAND(cmd,ret,cmd_ret,std_in,std_out) _gs_assert_command_validate(cmd,ret,cmd_ret,std_in,std_out, __FILE__, __LINE__); - -/** - Validate command results returned from last command execution. - Asserts if the results does not match. - - @param[in] no the result no to verify. - @param[in] group string with expected group id. Wildcards (*\/?) are supported. - @param[in] key string with expected key. Wildcards (*\/?) are supported. - @param[in] value string with expected value. Wildcards (*\/?) are supported. - @return void -*/ -#define GS_ASSERT_COMMAND_RESULT(no,group,key,value) _gs_assert_command_validate_last_result(no,group,key,value, __FILE__, __LINE__); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/test/log.h b/gomspace/libutil/include/gs/util/test/log.h deleted file mode 100644 index 13322953..00000000 --- a/gomspace/libutil/include/gs/util/test/log.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef GS_UTIL_TEST_LOG_H -#define GS_UTIL_TEST_LOG_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Log Test framework. - - Provides a simple way of veriyfing logs generated during unit-testing. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Assert log count - internal helper function. -*/ -void gs_assert_log_count(int level, unsigned int count, const char * file, int line); - -/** - Assert log messag and count - internal helper function. -*/ -void gs_assert_log(unsigned int stack_index, unsigned int count, gs_log_level_t level, const char * pattern, const char * file, int line); - -/** - Initialize framework, by installing a callback for \a print. - @param[in] verbose of \a true, logs will be printed on stdout. -*/ -void gs_test_log_init(bool verbose); - -/** - Clear log stats. -*/ -void gs_test_log_clear(void); - -/** - Assert number of error logs. -*/ -#define GS_ASSERT_LOG_ERROR(cnt) gs_assert_log_count(LOG_ERROR, cnt, __FILE__, __LINE__); - -/** - Assert number of warning logs. -*/ -#define GS_ASSERT_LOG_WARNING(cnt) gs_assert_log_count(LOG_WARNING, cnt, __FILE__, __LINE__); - -/** - Assert number of notice logs. -*/ -#define GS_ASSERT_LOG_NOTICE(cnt) gs_assert_log_count(LOG_NOTICE, cnt, __FILE__, __LINE__); - -/** - Assert number of info logs. -*/ -#define GS_ASSERT_LOG_INFO(cnt) gs_assert_log_count(LOG_INFO, cnt, __FILE__, __LINE__); - -/** - Assert number of debug logs. -*/ -#define GS_ASSERT_LOG_DEBUG(cnt) gs_assert_log_count(LOG_DEBUG, cnt, __FILE__, __LINE__); - -/** - Assert number of trace logs. -*/ -#define GS_ASSERT_LOG_TRACE(cnt) gs_assert_log_count(LOG_TRACE, cnt, __FILE__, __LINE__); - -/** - Assert number of all logs. -*/ -#define GS_ASSERT_LOG_ALL(cnt) gs_assert_log_count(-1, cnt, __FILE__, __LINE__); - -/** - Assert/find number of entries matching level and pattern. -*/ -#define GS_ASSERT_LOG(count,level,pattern) gs_assert_log(-1, count, level, pattern, __FILE__, __LINE__) - -/** - Assert log at stack index against matching level and pattern. -*/ -#define GS_ASSERT_LOG_AT(stack_index,level,pattern) gs_assert_log(stack_index, 1, level, pattern, __FILE__, __LINE__) - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/thread.h b/gomspace/libutil/include/gs/util/thread.h deleted file mode 100644 index 37340818..00000000 --- a/gomspace/libutil/include/gs/util/thread.h +++ /dev/null @@ -1,173 +0,0 @@ -#ifndef GS_UTIL_THREAD_H -#define GS_UTIL_THREAD_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Thread/task API based on POSIX standard. - - The thread API wraps POSIX \a pthread and FreeRTOS \a task. -*/ - -#include -#if __linux__ -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if __linux__ -/** - Thread handle. -*/ -typedef pthread_t gs_thread_t; -#else -typedef struct gs_freertos_task_t * gs_thread_t; -#endif - -/** - Type used to declare thread stack buffer for gs_thread_create_with_stack. -*/ -typedef uint32_t gs_stack_type_t; - -/** - Thread priorities. - These values are mapped to platform specific values. -*/ -typedef enum { - /** - Idle (lowest) priority. - Typical use: Not much - runs when nothing else runs. - FreeRTOS: Idle thread. - */ - GS_THREAD_PRIORITY_IDLE = 5, - /** - Low priority. - Typical use: Service applications, e.g. servicing requests from the outside. - GOMspace: housekeeping, GOSH. - */ - GS_THREAD_PRIORITY_LOW = 10, - /** - Normal priority. - Typical use: Control - the primary application(s). - */ - GS_THREAD_PRIORITY_NORMAL = 15, - /** - High priority. - Typical use: Drivers off loading data from hardware to software buffers. - GOMspace: csp_route_task. - */ - GS_THREAD_PRIORITY_HIGH = 20, - /** - High priority. - Typical use: Very time critical threads. No long, time consuming processing. - FreeRTOS: Timer thread. - */ - GS_THREAD_PRIORITY_CRITICAL = 25, -} gs_thread_priority_t; - -/** - Thread function. -*/ -typedef void * (*gs_thread_func_t)(void * parameter); - -/** - Create thread as joinable. - @note only supported on linux. The thread must be joined to free all resources. -*/ -#define GS_THREAD_CREATE_JOINABLE 0x0001 - -/** - Create thread (or task on some platforms). - - pthread/Posix supports exit value and join, FreeRTOS supports neither (perhaps in the future), so API is designed after Posix. - - FreeRTOS: a thread must always terminate with a call to gs_thread_exit(). - linux: a thread is by default created detached, unless #GS_THREAD_CREATE_JOINABLE is specified. - - @param[in] name name of thread. Ignored on Linux. - @param[in] func function for thread to execute. - @param[in] parameter parameter parsed to the thread function. - @param[in] stack_size number of bytes to allocate for stack - not used/supported on all platforms. Ignored on Linux. - @param[in] priority thread priority. Ignored on Linux. - @param[in] flags flags to control creation, see #GS_THREAD_CREATE_JOINABLE. - @param[out] handle handle to the created thread, use NULL if not wanted. - @return_gs_error_t -*/ -gs_error_t gs_thread_create(const char * const name, - gs_thread_func_t func, - void * parameter, - size_t stack_size, - gs_thread_priority_t priority, - uint32_t flags, - gs_thread_t * handle); - -/** - Create thread (or task on some platforms) with user supplied buffer for stack. - - pthread/Posix supports exit value and join, FreeRTOS supports neither (perhaps in the future), so API is designed after Posix. - - FreeRTOS: a thread must always terminate with a call to gs_thread_exit(). - FreeRTOS v9.0 must be compiled with configSUPPORT_STATIC_ALLOCTION set to 1 - otherwise warning log is printed and user supplied - stack buffer is discarded - linux: a thread is by default created detached, unless #GS_THREAD_CREATE_JOINABLE is specified. - stack_buf is ignored. - - @param[in] name name of thread. Ignored on Linux. - @param[in] func function for thread to execute. - @param[in] parameter parameter parsed to the thread function. - @param[in] stack_size size of the user supplied stack buffer - not used/supported on all platforms. Ignored on Linux. - @param[in] stack_buf User supplied stack buffer - not used/supported on all platforms. Ignored on Linux. - @param[in] priority thread priority. Ignored on Linux. - @param[in] flags flags to control creation, see #GS_THREAD_CREATE_JOINABLE. - @param[out] handle handle to the created thread, use NULL if not wanted. - @return_gs_error_t -*/ -gs_error_t gs_thread_create_with_stack(const char * const name, - gs_thread_func_t func, - void * parameter, - size_t stack_size, - gs_stack_type_t *stack_buf, - gs_thread_priority_t priority, - uint32_t flags, - gs_thread_t * handle); - -/** - Exit current thread. - @param[in] exit_value exit value. -*/ -void gs_thread_exit(void * exit_value) __attribute__ ((noreturn)); - -/** - Sleep for X milli-seconds. - @note FreeRTOS: minimum sleep time depends on ticks per milli-second. A thread is suspended minimum 1 tick - unless \a time_ms is 0, in which case yield is called. - @deprecated use gs_time_sleep_ms() - @param[in] time_ms milli-seconds to sleep. -*/ -void gs_thread_sleep_ms(uint32_t time_ms); - -/** - Join with a terminated thread. - - @note Only supported on Linux and primarily used for testing. - @note This is not based on pthread_cancel(), so the user must have signaled the thread to stop - otherwise this will hang forever. - - @param[in] thread handle. - @param[out] return_retval return value from thread, use NULL if not wanted. - @return_gs_error_t -*/ -gs_error_t gs_thread_join(gs_thread_t thread, void ** return_retval); - -/** - Block thread forever. - - Primarily used in Linux applications main() to block main thread. -*/ -void gs_thread_block(void) __attribute__ ((noreturn)); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/time.h b/gomspace/libutil/include/gs/util/time.h deleted file mode 100644 index d4425906..00000000 --- a/gomspace/libutil/include/gs/util/time.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef GS_UTIL_TIME_H -#define GS_UTIL_TIME_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Releative time. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Converts minutes to seconds. -*/ -#define GS_TIME_MINS_TO_SECS(m) (m * 60) - -/** - Converts hours to seconds. -*/ -#define GS_TIME_HOURS_TO_SECS(h) (h * GS_TIME_MINS_TO_SECS(60)) - -/** - Converts days to seconds. -*/ -#define GS_TIME_DAYS_TO_SECS(d) (d * GS_TIME_HOURS_TO_SECS(24)) - -/** - Return relative time (milli seconds). - @note This will eventually wrap on all platforms - platform must wrap on 32 bit. - @return relativ milli seconds -*/ -uint32_t gs_time_rel_ms(void); - -/** - Return relative time (milli seconds). - @note This will eventually wrap on all platforms - platform must wrap on 32 bit. - @return relativ milli seconds -*/ -uint32_t gs_time_rel_ms_isr(void); - -/** - Returns seconds since process started. - @note On some platforms (e.g. Linux), first call will set offset and - first call it therefor not thread-safe. - @return seconds since boot (or process startup). -*/ -uint32_t gs_time_uptime(void); - -/** - Return time difference, compensating for time wrap due to 32 bit. - @note the function can not detect multiple time wraps, so function using it should - take action within 32 bit time. - @param[in] ref_ms reference time. - @param[in] now_ms current time. - @returns ms difference, compensating for time wrapping (if now_ms is less than ref_ms). -*/ -uint32_t gs_time_diff_ms(uint32_t ref_ms, uint32_t now_ms); - -/** - Sleep for X milli-seconds. - No busy waiting. - @note FreeRTOS: minimum sleep time depends on ticks per second. Suspends execution for minimum 1 tick - unless \a time is 0, in which case yield is called. - @param[in] time_ms milli-seconds to sleep. -*/ -void gs_time_sleep_ms(uint32_t time_ms); - -/** - Sleep X milli-seconds relative to reference. - - This sleep function uses a reference \a ref_ms to compensate for variance in processing time. - - No busy waiting. - - @param[in,out] ref_ms time reference. - @param[in] sleep_ms how many milli-seconds to sleep - relative to reference. - @return \a true if sleep time relative to last reference couldn't be done (reference reset), \a false if normal sleep was done. -*/ -bool gs_time_sleep_until_ms(uint32_t * ref_ms, uint32_t sleep_ms); - -/** - Sleep for X nano-seconds. - No busy waiting. - @note FreeRTOS: minimum sleep time depends on ticks per second. Suspends execution for minimum 1 tick - unless \a time is 0, in which case yield is called. - @param[in] time_ns nano-seconds to sleep. -*/ -void gs_time_sleep_ns(uint64_t time_ns); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/timestamp.h b/gomspace/libutil/include/gs/util/timestamp.h deleted file mode 100644 index 80fef6da..00000000 --- a/gomspace/libutil/include/gs/util/timestamp.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef GS_UTIL_TIMESTAMP_H -#define GS_UTIL_TIMESTAMP_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Timestamp utilities, for add, subtract, compare, copy, etc. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Number of nano seconds per second. -*/ -#define GS_TIMESTAMP_NSEC_PER_SEC 1000000000 - -/** - Portable time structure. - - Stanadard timespec_t is non-portable, so this structure must be used instead -*/ -typedef struct { - /** Seconds. */ - uint32_t tv_sec; - /** Nano seconds. */ - uint32_t tv_nsec; -} gs_timestamp_t; - -/** - @deprecated Use gs_timestamp_t -*/ -typedef gs_timestamp_t timestamp_t; - -/** - Add 2 timestamp's (t1 = t1 + t2). - @param[in,out] t1 timestamp - @param[in] t2 timestamp. - @return 0 on success, otherwise -1 -*/ -int timestamp_add(gs_timestamp_t * t1, const gs_timestamp_t * t2); - -/** - Subtract 2 timestamp's (t1 = t1 - t2) - @param[in,out] t1 timestamp - @param[in] t2 timestamp. - @return 0 on success, otherwise -1 -*/ -int timestamp_diff(gs_timestamp_t * t1, const gs_timestamp_t * t2); - -/** - Check if t2 is greate than t1. - @param[in] t1 time to compare - @param[in] t2 time to compare - @return 1 if t2 > t1, else 0. -1 on bad arguments. -*/ -int timestamp_ge(const gs_timestamp_t * t1, const gs_timestamp_t * t2); - -/** - Copy timestamp. - @param[in] from from timestamp - @param[out] to to timestamp - @return 0 on success, otherwise -1 -*/ -int timestamp_copy(const gs_timestamp_t * from, gs_timestamp_t * to); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/types.h b/gomspace/libutil/include/gs/util/types.h deleted file mode 100644 index 2c0d0597..00000000 --- a/gomspace/libutil/include/gs/util/types.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef GS_UTIL_TYPES_H -#define GS_UTIL_TYPES_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Base type definitions and functions. - - In some rare cases, it is impossible to make code that works on all platforms. In these cases the following defines may be used to - exclude/include code: - | define | Platform | - | :----: | :---- | - | \_\_AVR\_\_ | 8 bit, e.g. atmega1281, atmega2560, attiny25, attiny44, attiny84 | - | \_\_linux\_\_ | 32/64 bit, Linux based | - - -*/ - -#include // intXX_t -#include // bool -#include // size_t - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Control static declaration at compile time. - Allows unit tests to access internal functions or variables. - @note Static declared variables are initialized to zero by the compiler - BUT if you use GS_NO_STATIC instead of static, they will not be initialized. -*/ -#if GS_NO_STATIC -#define GS_STATIC -#else -#define GS_STATIC static -#endif - -/** - Convert integer to pointer. -*/ -#define GS_TYPES_INT2PTR(value) ((void*)(intptr_t)(value)) - -/** - Convert integer to pointer. -*/ -#define GS_TYPES_UINT2PTR(value) ((void*)(uintptr_t)(value)) - -/** - Convert pointer to integer. -*/ -#define GS_TYPES_PTR2INT(value) ((intptr_t)(void*)(value)) - -/** - Convert pointer to integer. -*/ -#define GS_TYPES_PTR2UINT(value) ((uintptr_t)(void*)(value)) - -/** - Assert on 'value'. - - Example: - GS_STATIC_ASSERT(sizeof(int) >= 2, int_must_be_at_least_16bit); - fails if size of (int) is less than 2 bytes. -*/ -#define GS_STATIC_ASSERT(condition, name) typedef char name[(condition) ? 1 : -1] - -/** - Context switch state. - Used by FreeRTOS when waking a higher priority task/thread from within an ISR. - The actual struct is defined in libembed. -*/ -typedef struct gs_context_switch gs_context_switch_t; - -/** - Return element count of array. -*/ -#define GS_ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) - -/** - Address union. -*/ -typedef union { - /** - Normal address pointer. - */ - void* p; - /** - Address pointer as an unsigned value. - */ - uintptr_t u; -} gs_address_t; - -/** - @cond HIDDEN_SYMBOLS - Compile check size of primitives (just to be sure, that they are what we expect). -*/ -GS_STATIC_ASSERT(sizeof(gs_address_t) == sizeof(void*), unexpected_address_void_pointer_size); -GS_STATIC_ASSERT(sizeof(gs_address_t) == sizeof(uintptr_t), unexpected_address_uintptr_size); -GS_STATIC_ASSERT(sizeof(bool) == sizeof(uint8_t), unexpected_bool_size); -GS_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), unexpected_float_size); -#if (__AVR__) -// avr/avr8 is 8 bit -GS_STATIC_ASSERT(sizeof(int) == sizeof(int16_t), unexpected_int_size_on_avr8); -#else -// rest should be 32 or 64 bit -GS_STATIC_ASSERT(sizeof(int) == sizeof(int32_t), unexpected_int_size); -GS_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t), unexpected_double_size); -#endif -/** @endcond */ - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/unistd.h b/gomspace/libutil/include/gs/util/unistd.h deleted file mode 100644 index a8b65845..00000000 --- a/gomspace/libutil/include/gs/util/unistd.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef GS_UTIL_UNISTD_H -#define GS_UTIL_UNISTD_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - GomSpace extensions to standard \a unistd.h. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Get current working directory. - - @note Linux uses standard getcwd(). - - @param[out] buf user supplied buffer for returning path. - @param[in] bufsize size of \a buf. - @return #GS_ERROR_NOT_FOUND if no current directory is set. - @return #GS_ERROR_RANGE if \a buf is too small - @return_gs_error_t -*/ -gs_error_t gs_getcwd(char * buf, size_t bufsize); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/vmem.h b/gomspace/libutil/include/gs/util/vmem.h deleted file mode 100644 index 19576a63..00000000 --- a/gomspace/libutil/include/gs/util/vmem.h +++ /dev/null @@ -1,194 +0,0 @@ -#ifndef GS_UTIL_VMEM_H -#define GS_UTIL_VMEM_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Virtual memory interface. - - The API provides support for accessing different hardware components using a common API, by providing a component specific driver. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Virtual memory mapping. -*/ -typedef struct gs_vmem gs_vmem_t; - -/** - VMEM driver write. - - @param[in] vmem vmem entry. - @param[in] to Address where to write data to. - @param[in] from Address where to write data from. - @param[in] size Number of bytes to write. - @return_gs_error_t -*/ -typedef gs_error_t (*gs_vmem_write_function_t)(const gs_vmem_t * vmem, void* to, const void * from, size_t size); - -/** - VMEM driver read. - - @param[in] vmem vmem entry. - @param[in] to Address where to read data to. - @param[in] from Address where to read data from. - @param[in] size Number of bytes to read. - @return_gs_error_t -*/ -typedef gs_error_t (*gs_vmem_read_function_t)(const gs_vmem_t * vmem, void* to, const void * from, size_t size); - -/** - VMEM driver lock. - - @param[in] vmem vmem entry. - @param[in] on Enable/Disable lock. - @return_gs_error_t -*/ -typedef gs_error_t (*gs_vmem_lock_function_t)(const gs_vmem_t * vmem, bool on); - -/** - VMEM driver information. - - Return relevant information for the VMEM driver. - - @param[in] vmem vmem entry. - @param[in] buffer user allocated buffer for returning information. - @param[in] buffer_size size (length) of \a buffer. - @return_gs_error_t -*/ -typedef gs_error_t (*gs_vmem_info_function_t)(const gs_vmem_t * vmem, char * buffer, size_t buffer_size); - -/** - VMEM driver interface. -*/ -typedef struct { - /** - Write function. - */ - const gs_vmem_write_function_t write; - /** - Read function. - */ - const gs_vmem_read_function_t read; - /** - Lock function. - */ - const gs_vmem_lock_function_t lock; - /** - Information function. - */ - const gs_vmem_info_function_t info; -} gs_vmem_driver_t; - -/** - Virtual memory mapping. - - @note Call gs_vmem_set_map() for registering mappings. -*/ -struct gs_vmem { - /** - Logical name of enry. - */ - const char *const name; - /** - Virtual memory start. - */ - gs_address_t virtmem; - /** - Physical memory start. - This address only makes sense for the VMEM driver. - */ - gs_address_t physmem; - /** - Size of memory block. - */ - const size_t size; - /** - Driver function. - */ - const gs_vmem_driver_t* drv; - /** - Driver data. - */ - const void* drv_data; -}; - -/** - Set VMEM mapping. - Must be done for the API to work. - @param[in] map VMEM mapping table, must be terminated with an NULL entry. - @return_gs_error_t -*/ -gs_error_t gs_vmem_set_map(const gs_vmem_t * map); - -/** - Return VMEM map. -*/ -const gs_vmem_t * gs_vmem_get_map(void); - -/** - Print all VMEM entries to stdout. - @param[in] out output stream - @return_gs_error_t -*/ -gs_error_t gs_vmem_list(FILE * out); - -/** - Get VMEM entry by name. - @param[in] name name of VMEM entry. - @return VMEM mapping or NULL if not found. -*/ -const gs_vmem_t * gs_vmem_get_by_name(const char * name); - -/** - Lock/un-lock VMEM area. - @param[in] name name of VMEM entry. - @param[in] on Enable/Disable lock. - @return GS_ERROR_NOT_FOUND area not found. - @return GS_ERROR_NOT_SUPPORTED if locking isn't supported. - @return_gs_error_t -*/ -gs_error_t gs_vmem_lock_by_name(const char * name, bool on); - -/** - Lock/un-lock all VMEM areas. - @param[in] on lock on or off. - @return_gs_error_t -*/ -gs_error_t gs_vmem_lock_all(bool on); - -/** - memcpy on VMEM. - @note if no VMEM entries are found, a normal memcpy is called with the provided pointers. - @param[in] to to location. - @param[in] from from location. - @param[in] size number of bytes to copy. -*/ -void* gs_vmem_cpy(void* to, const void* from, size_t size); - -/** - Macro for calling gs_vmem_cpy(). -*/ -#define GS_VMEM_CPY(to, from, size) gs_vmem_cpy(to, from, size) - -/** - Macro for calling gs_vmem_cpy(). - @deprecated Use gs_vmem_cpy() directly. -*/ -#define VMEM_CPY(to, from, size) gs_vmem_cpy(to, from, size) - -/** - Register VMEM commands. - @return_gs_error_t -*/ -gs_error_t gs_vmem_register_commands(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/watchdog/watchdog.h b/gomspace/libutil/include/gs/util/watchdog/watchdog.h deleted file mode 100644 index 30d2bd30..00000000 --- a/gomspace/libutil/include/gs/util/watchdog/watchdog.h +++ /dev/null @@ -1,143 +0,0 @@ -#ifndef GS_UTIL_WATCHDOG_WATCHDOG_H -#define GS_UTIL_WATCHDOG_WATCHDOG_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Software watchdog client interface. - - The software watchdog (SWWD) enables having multiple instances of a Watchdog. - The software watchdog manages the HW watchdog, and will ultimately - trigger the HW watchdog, if one or more clients are not servicing the - software watchdog. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Software Watchdog handle -*/ -typedef struct gs_swwd_hdl gs_swwd_hdl_t; - -/** - Software watchdog callback function. - - Called by the SWWD upon timeout. - @param[in] userdata user data provided on gs_swwd_register() -*/ -typedef void (*gs_swwd_callback_function_t)(void * userdata); - -/** - Watchdog timeout action. -*/ -typedef enum { - /** - Reset system on timeout (stops touching the hardware watchdog). - Once the watchdog has timeout, the watchdog cannot be re-activated. - */ - GS_SWWD_TIMEOUT_ACTION_RESET = 0, - /** - Log 'warning' on timeout, but otherwise ignore the timeout. - The watchdog can re-activated by touching the watchdog again. - */ - GS_SWWD_TIMEOUT_ACTION_LOG = 1, -} gs_swwd_timeout_action_t; - -/** - Create the software watchdog back-end. - - Only one SWWD back-end can exist at any given time. - - @param[in] max_clients The maximum number of Software Watchog clients supported. - @param[in] dev The HW Watchdog device to use. - @return_gs_error_t -*/ -gs_error_t gs_swwd_create(uint32_t max_clients, gs_watchdog_device_t *dev); - -/** - Destroy the Software Watchdog back-end (and stop the SWWD monitor task if started). - - @param[in] timeout_s Maximum number of seconds to allow this operation to complete. - @return_gs_error_t -*/ -gs_error_t gs_swwd_destroy(uint32_t timeout_s); - -/** - Check for expired software watchdog clients. This function is only to be used if the - SWWD monitor task is not started. Otherwise the SWWD task will handle this in the back- - ground. I.e: - - In passive mode this function must be called periodically to check for expired - clients, and service the HW watchdog. - - In active mode this function is called in background by the SWWD monitor task. - - The interval between these checks should be much less that the HW watchdog - timeout period, to ensure that the HW Watchdog is correctly serviced. - Calling this e.g. every 1-3 seconds will be a good default. - - @param[out] num_expired The number of SW Watchog clients currently expired. - @return_gs_error_t -*/ -gs_error_t gs_swwd_check_expired_clients(uint32_t *num_expired); - -/** - Register/create a new software watchdog instance - - @param[out] wdt_handle A reference to software watchdog handle - @param[in] timeout Timeout in seconds. - @param[in] callback Callback function which is called on timeout. NULL if unused. - @param[in] userdata Pointer to user data used in the callback function. Ignored if callback is NULL. - @param[in] client_name A descriptive name given by the user in order to identify the watchdog/client - the pointer must remain valid as long as the watchdog is registered. - @param[in] action what action to take, when/if the watchdog times out. - @return_gs_error_t -*/ -gs_error_t gs_swwd_register_with_action(gs_swwd_hdl_t ** wdt_handle, uint32_t timeout, gs_swwd_callback_function_t callback, void * userdata, const char *client_name, gs_swwd_timeout_action_t action); - -/** - Register/create a software watchdog with action \a reset on timeout. - - @param[out] wdt_handle A reference to software watchdog handle - @param[in] timeout Timeout in seconds before the software watchdog fires. - @param[in] callback Callback function which is called on timeout. NULL if unused. - @param[in] userdata Pointer to user data used in the callback function. Ignored if callback is NULL. - @param[in] client_name A descriptive name given by the user in order to identify the watchdog/client - the pointer must remain valid as long as the watchdog is registered. - @return_gs_error_t -*/ -static inline gs_error_t gs_swwd_register(gs_swwd_hdl_t ** wdt_handle, uint32_t timeout, gs_swwd_callback_function_t callback, void * userdata, const char *client_name) -{ - return gs_swwd_register_with_action(wdt_handle, timeout, callback, userdata, client_name, GS_SWWD_TIMEOUT_ACTION_RESET); -} - -/** - De-Register a Software Watchdog instance - - @param[in] wdt_handle A software watchdog handle - @return_gs_error_t -*/ -gs_error_t gs_swwd_deregister(gs_swwd_hdl_t ** wdt_handle); - -/** - Touch Software Watchdog to reset the timer - - @param[in] wdt_handle A software watchdog handle - @return_gs_error_t -*/ -gs_error_t gs_swwd_touch(gs_swwd_hdl_t * wdt_handle); - -/** - Set timeout of the Software Watchdog. - - @param[in] wdt_handle A software watchdog handle - @param[in] timeout Timeout in seconds before the SWWD fires. - @return_gs_error_t -*/ -gs_error_t gs_swwd_set_timeout(gs_swwd_hdl_t * wdt_handle, uint32_t timeout); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/watchdog/watchdog_task.h b/gomspace/libutil/include/gs/util/watchdog/watchdog_task.h deleted file mode 100644 index 833f1511..00000000 --- a/gomspace/libutil/include/gs/util/watchdog/watchdog_task.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef GS_UTIL_WATCHDOG_WATCHDOG_TASK_H -#define GS_UTIL_WATCHDOG_WATCHDOG_TASK_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Software Watchdog server/task interface - - The Software Watchdog task implements the core (backend) functionality of the the software watchdog. - The Client API for the SW watchdog is implemented in watchdog.h - - @note This API is not thread safe! -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Start the Software Watchdog monitor task if the SWWD is to be used as a - separate task (active mode). - In this case the SWWD task will monitor expired clients in the background - and the polling API gs_swwd_check_expired_clients() needs not to be called by - the user. - - @return_gs_error_t -*/ - -gs_error_t gs_swwd_monitor_task_start(); - -/** - Stops the Software Watchdog monitor task - - @param[in] timeout_s Maximum number of seconds to allow this operation to complete. - - @return_gs_error_t -*/ -gs_error_t gs_swwd_monitor_task_stop(uint32_t timeout_s); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/zip/zip.h b/gomspace/libutil/include/gs/util/zip/zip.h deleted file mode 100644 index 04c87974..00000000 --- a/gomspace/libutil/include/gs/util/zip/zip.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef LIBUTIL_ZIP_ZIP_UTILS_H -#define LIBUTIL_ZIP_ZIP_UTILS_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Compress/decompress API based on zlib compressed data format specification standards. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/** - Compress file. - - @param[in] src file to be compressed. - @param[out] dest compressed output file. - @return_gs_error_t -*/ -int gs_zip_compress_file(const char *src, const char *dest); - -/** - Decompress file. - - @param[in] src file to be secompressed. - @param[out] dest decompressed output file. - @return_gs_error_t -*/ -int gs_zip_decompress_file(const char *src, const char *dest); - -/** - Compress data. - - @param[in] src pointer to the data to be compressed. - @param[in] src_len size of the data. - @param[out] dest pointer to the compressed data. - @param[out] dest_len pointer to the size of the compressed data. - @return_gs_error_t -*/ -int gs_zip_compress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t *dest_len); - -/** - Decompress data. - - @param[in] src pointer to the data to be decompressed. - @param[in] src_len size of the data. - @param[out] dest pointer to the decompressed data. - @param[out] dest_len size of the destination memory area. - @param[out] decomp_len pointer to the size of the decompressed data. - @return_gs_error_t -*/ -int gs_zip_decompress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t dest_len, uint32_t *decomp_len); - - -#ifdef __cplusplus -} -#endif -#endif /* LIBUTIL_ZIP_ZIP_UTILS_H */ diff --git a/gomspace/libutil/src/base16.c b/gomspace/libutil/src/base16.c deleted file mode 100644 index da3a83c6..00000000 --- a/gomspace/libutil/src/base16.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2010 Michael Brown . - * - * This program 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 2 of the - * License, or any later version. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -void base16_encode(const uint8_t * raw, size_t len, char *encoded) -{ - const uint8_t *raw_bytes = raw; - char *encoded_bytes = encoded; - size_t remaining = len; - - for (; remaining--; encoded_bytes += 2) - snprintf(encoded_bytes, 3, "%02X", *(raw_bytes++)); - -} - -int base16_decode(const char *encoded, uint8_t *raw) -{ - uint8_t *raw_bytes = raw; - if (encoded) { - const char *encoded_bytes = encoded; - char buf[3]; - char *endp; - - while (encoded_bytes[0]) { - if (!encoded_bytes[1]) { - log_error("Base16-encoded string \"%s\" has invalid length\n", - encoded); - return GS_ERROR_ARG; - } - memcpy(buf, encoded_bytes, 2); - buf[2] = '\0'; - *(raw_bytes++) = (uint8_t) strtoul(buf, &endp, 16); - if (*endp != '\0') { - log_error("Base16-encoded string \"%s\" has invalid byte \"%s\"\n", - encoded, buf); - return GS_ERROR_ARG; - } - encoded_bytes += 2; - } - } - return (int)(raw_bytes - raw); -} diff --git a/gomspace/libutil/src/bindings/python/pyutil.c b/gomspace/libutil/src/bindings/python/pyutil.c deleted file mode 100644 index b2924ba6..00000000 --- a/gomspace/libutil/src/bindings/python/pyutil.c +++ /dev/null @@ -1,73 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -#if PY_MAJOR_VERSION == 3 -#define IS_PY3 -#endif - -/** - * Helpers - */ - -static PyObject* pyutil_get_clock_time(PyObject *self, PyObject *args) { - gs_timestamp_t ts; - gs_clock_get_time(&ts); - return Py_BuildValue("II", ts.tv_sec, ts.tv_nsec); -} - - -static PyObject* pyutil_error_string(PyObject *self, PyObject *args) -{ - int error; - if (!PyArg_ParseTuple(args, "i", &error)) - { - Py_RETURN_NONE; - } - return Py_BuildValue("s", gs_error_string(error)); -} - -static PyMethodDef methods[] = { - - /* helpers */ - {"get_clock_time", pyutil_get_clock_time, METH_NOARGS, ""}, - {"error_string", pyutil_error_string, METH_VARARGS, ""}, - - /* sentinel */ - {NULL, NULL, 0, NULL} -}; - -#ifdef IS_PY3 -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "libgsutil_py3", - NULL, /* module documentation, may be NULL */ - -1, /* size of per-interpreter state of the module, - or -1 if the module keeps state in global variables. */ - methods, - NULL, - NULL, - NULL, - NULL -}; -#endif - -#ifdef IS_PY3 -PyMODINIT_FUNC PyInit_libgsutil_py3(void) { -#else -PyMODINIT_FUNC initlibgsutil_py2(void) { -#endif - -#ifdef IS_PY3 - PyObject* m = PyModule_Create(&moduledef); -#else - Py_InitModule("libgsutil_py2", methods); -#endif - -#ifdef IS_PY3 - return m; -#endif -} - diff --git a/gomspace/libutil/src/bytebuffer.c b/gomspace/libutil/src/bytebuffer.c deleted file mode 100644 index 49b5a495..00000000 --- a/gomspace/libutil/src/bytebuffer.c +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -#define GS_BYTEBUFFER_F_FAILED 0x01 -#define GS_BYTEBUFFER_F_OVERRUN 0x02 - -gs_error_t gs_bytebuffer_init(gs_bytebuffer_t * bb, void * buffer, size_t buffer_size) -{ - GS_CHECK_HANDLE(bb != NULL); - memset(bb, 0, sizeof(*bb)); - if (buffer) { - if (buffer_size < 2) { - // must always have room for NUL termination. - return GS_ERROR_ARG; - } - bb->buffer = buffer; - bb->size = buffer_size; - } else { - // dry run - don't insert anything in buffer, but increment used - } - - return GS_OK; -} - -void gs_bytebuffer_vprintf(gs_bytebuffer_t * bb, const char * format, va_list ap) -{ - int res; - if (bb->buffer == NULL) { - // dry run - char buf[3]; - res = vsnprintf(buf, 0, format, ap); - if (res >= 0) { - bb->used += res; - } - } else { - const size_t free_bytes = gs_bytebuffer_get_free(bb); - res = vsnprintf((char*)&bb->buffer[bb->used], free_bytes, format, ap); - if (res > 0) { - if ((size_t)res >= free_bytes) { - // over run - bb->flags |= GS_BYTEBUFFER_F_OVERRUN; - bb->used = bb->size; - bb->buffer[bb->size - 1] = 0; - } else { - bb->used += res; - } - } - } - if (res < 0) { - bb->flags |= GS_BYTEBUFFER_F_FAILED; - } -} - -void gs_bytebuffer_printf(gs_bytebuffer_t * bb, const char * format, ...) -{ - va_list ap; - va_start(ap, format); - gs_bytebuffer_vprintf(bb, format, ap); - va_end(ap); -} - -void gs_bytebuffer_append(gs_bytebuffer_t * bb, const void * data, size_t length) -{ - if (bb->buffer == NULL) { - // dry run - bb->used += length; - } else { - const size_t free_bytes = gs_bytebuffer_get_free(bb); - if (free_bytes >= length) { - memcpy(&bb->buffer[bb->used], data, length); - bb->used += length; - } else { - memcpy(&bb->buffer[bb->used], data, free_bytes); - bb->flags |= GS_BYTEBUFFER_F_OVERRUN; - bb->used += free_bytes; - } - } -} - -void gs_bytebuffer_append_string(gs_bytebuffer_t * bb, const char * string) -{ - if (gs_string_empty(string) == false) { - gs_bytebuffer_append(bb, string, strlen(string)); - } -} - -void gs_bytebuffer_append_string_max(gs_bytebuffer_t * bb, const char * string, size_t max_length) -{ - if (gs_string_empty(string) == false) { - gs_bytebuffer_append(bb, string, strnlen(string, max_length)); - } -} - -char * gs_bytebuffer_get_as_string(gs_bytebuffer_t * bb, gs_error_t * error) -{ - if (bb && bb->buffer) { - // handle NUL termination - if (bb->used < bb->size) { - bb->buffer[bb->used] = 0; - } else { - // overrun - truncation buffer - bb->flags |= GS_BYTEBUFFER_F_OVERRUN; - bb->buffer[bb->used - 1] = 0; - } - if (error) { - *error = gs_bytebuffer_get_state(bb); - } - return (char*) bb->buffer; - } - return NULL; -} - -gs_error_t gs_bytebuffer_get_state(gs_bytebuffer_t * bb) -{ - if (bb) { - if (bb->flags & GS_BYTEBUFFER_F_FAILED) { - return GS_ERROR_DATA; - } - if (bb->flags & GS_BYTEBUFFER_F_OVERRUN) { - return GS_ERROR_OVERFLOW; - } - return GS_OK; - } - return GS_ERROR_HANDLE; -} diff --git a/gomspace/libutil/src/byteorder.c b/gomspace/libutil/src/byteorder.c deleted file mode 100644 index e00c9737..00000000 --- a/gomspace/libutil/src/byteorder.c +++ /dev/null @@ -1,323 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include - -/* Convert 16-bit number from host byte order to network byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_hton16(uint16_t h16) { -#if UTIL_BIG_ENDIAN - return h16; - -#elif UTIL_LITTLE_ENDIAN - return (uint16_t)(((h16 & 0xff00) >> 8) | - ((h16 & 0x00ff) << 8)); -#endif -} - -/* Convert 16-bit number from network byte order to host byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_ntoh16(uint16_t n16) { - return util_hton16(n16); -} - -/* Convert 32-bit number from host byte order to network byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_hton32(uint32_t h32) { -#if UTIL_BIG_ENDIAN - return h32; - -#elif UTIL_LITTLE_ENDIAN - return (((h32 & 0xff000000) >> 24) | - ((h32 & 0x000000ff) << 24) | - ((h32 & 0x0000ff00) << 8) | - ((h32 & 0x00ff0000) >> 8)); -#endif -} - -/* Convert 32-bit number from network byte order to host byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_ntoh32(uint32_t n32) { - return util_hton32(n32); -} - -/* Convert 64-bit number from host byte order to network byte order */ -extern inline uint64_t __attribute__ ((__const__)) util_hton64(uint64_t h64) { -#if UTIL_BIG_ENDIAN - return h64; - -#elif UTIL_LITTLE_ENDIAN - return (((h64 & 0xff00000000000000LL) >> 56) | - ((h64 & 0x00000000000000ffLL) << 56) | - ((h64 & 0x00ff000000000000LL) >> 40) | - ((h64 & 0x000000000000ff00LL) << 40) | - ((h64 & 0x0000ff0000000000LL) >> 24) | - ((h64 & 0x0000000000ff0000LL) << 24) | - ((h64 & 0x000000ff00000000LL) >> 8) | - ((h64 & 0x00000000ff000000LL) << 8)); -#endif -} - -/* Convert 64-bit number from host byte order to network byte order */ -extern inline uint64_t __attribute__ ((__const__)) util_ntoh64(uint64_t n64) { - return util_hton64(n64); -} - -/* Convert float from host byte order to network byte order */ -extern inline float __attribute__ ((__const__)) util_htonflt(float f) { -#if UTIL_BIG_ENDIAN - return f; - -#elif UTIL_LITTLE_ENDIAN - union v { - float f; - uint32_t i; - }; - union v val; - val.f = f; - val.i = util_hton32(val.i); - return val.f; -#endif -} - -/* Convert float from host byte order to network byte order */ -extern inline float __attribute__ ((__const__)) util_ntohflt(float f) { - return util_htonflt(f); -} - -/* Convert double from host byte order to network byte order */ -extern inline double __attribute__ ((__const__)) util_htondbl(double d) { -#if UTIL_BIG_ENDIAN - return d; - -#elif UTIL_LITTLE_ENDIAN - union v { - double d; - uint64_t i; - }; - union v val; - val.d = d; - val.i = util_hton64(val.i); - return val.d; -#endif -} - -/* Convert float from host byte order to network byte order */ -extern inline double __attribute__ ((__const__)) util_ntohdbl(double d) { - return util_htondbl(d); -} - -/* Convert 16-bit number from host byte order to big endian byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_htobe16(uint16_t h16) { - return util_hton16(h16); -} - -/* Convert 16-bit number from host byte order to little endian byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_htole16(uint16_t h16) { -#if UTIL_LITTLE_ENDIAN - return h16; - -#elif UTIL_BIG_ENDIAN - return (uint16_t)(((h16 & 0xff00) >> 8) | - ((h16 & 0x00ff) << 8)); -#endif -} - -/* Convert 16-bit number from big endian byte order to little endian byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_betoh16(uint16_t be16) { - return util_ntoh16(be16); -} - -/* Convert 16-bit number from little endian byte order to host byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_letoh16(uint16_t le16) { - return util_htole16(le16); -} - -/* Convert 32-bit number from host byte order to big endian byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_htobe32(uint32_t h32) { - return util_hton32(h32); -} - -/* Convert 32-bit number from little endian byte order to host byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_htole32(uint32_t h32) { -#if UTIL_LITTLE_ENDIAN - return h32; - -#elif UTIL_BIG_ENDIAN - return (((h32 & 0xff000000) >> 24) | - ((h32 & 0x000000ff) << 24) | - ((h32 & 0x0000ff00) << 8) | - ((h32 & 0x00ff0000) >> 8)); -#endif -} - -/* Convert 32-bit number from big endian byte order to host byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_betoh32(uint32_t be32) { - return util_ntoh32(be32); -} - -/* Convert 32-bit number from little endian byte order to host byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_letoh32(uint32_t le32) { - return util_htole32(le32); -} - -/* Convert 64-bit number from host byte order to big endian byte order */ -extern inline uint64_t __attribute__ ((__const__)) util_htobe64(uint64_t h64) { - return util_hton64(h64); -} - -/* Convert 64-bit number from host byte order to little endian byte order */ -extern inline uint64_t __attribute__ ((__const__)) util_htole64(uint64_t h64) { -#if UTIL_LITTLE_ENDIAN - return h64; - -#elif UTIL_BIG_ENDIAN - return (((h64 & 0xff00000000000000LL) >> 56) | - ((h64 & 0x00000000000000ffLL) << 56) | - ((h64 & 0x00ff000000000000LL) >> 40) | - ((h64 & 0x000000000000ff00LL) << 40) | - ((h64 & 0x0000ff0000000000LL) >> 24) | - ((h64 & 0x0000000000ff0000LL) << 24) | - ((h64 & 0x000000ff00000000LL) >> 8) | - ((h64 & 0x00000000ff000000LL) << 8)); -#endif -} - -/* Convert 64-bit number from big endian byte order to host byte order */ -extern inline uint64_t __attribute__ ((__const__)) util_betoh64(uint64_t be64) { - return util_ntoh64(be64); -} - -/* Convert 64-bit number from little endian byte order to host byte order */ -extern inline uint64_t __attribute__ ((__const__)) util_letoh64(uint64_t le64) { - return util_htole64(le64); -} - -/* Convert 16-bit number from host byte order to network byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_htons(uint16_t h16) { - return util_hton16(h16); -} - -/* Convert 16-bit number from network byte order to host byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_ntohs(uint16_t n16) { - return util_ntoh16(n16); -} - -/* Convert 32-bit number from host byte order to network byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_htonl(uint32_t h32) { - return util_hton32(h32); -} - -/* Convert 32-bit number from network byte order to host byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_ntohl(uint32_t n32) { - return util_ntoh32(n32); -} - -#define BYTEORDER_ARRAY(convert, from, to, count) { \ - for (unsigned int i = 0; i < count; ++i, ++from, ++to) { \ - *to = convert(*from); \ - } \ - } - -void util_hton16_array(const uint16_t * from, uint16_t * to, size_t count) -{ - BYTEORDER_ARRAY(util_hton16, from, to, count); -} - -void util_hton32_array(const uint32_t * from, uint32_t * to, size_t count) -{ - BYTEORDER_ARRAY(util_hton32, from, to, count); -} - -void util_hton64_array(const uint64_t * from, uint64_t * to, size_t count) -{ - BYTEORDER_ARRAY(util_hton64, from, to, count); -} - -void util_ntoh16_array(const uint16_t * from, uint16_t * to, size_t count) -{ - BYTEORDER_ARRAY(util_ntoh16, from, to, count); -} - -void util_ntoh32_array(const uint32_t * from, uint32_t * to, size_t count) -{ - BYTEORDER_ARRAY(util_ntoh32, from, to, count); -} - -void util_ntoh64_array(const uint64_t * from, uint64_t * to, size_t count) -{ - BYTEORDER_ARRAY(util_ntoh64, from, to, count); -} - -void util_htonflt_array(const float * from, float * to, size_t count) -{ - BYTEORDER_ARRAY(util_htonflt, from, to, count); -} - -void util_ntohflt_array(const float * from, float * to, size_t count) -{ - BYTEORDER_ARRAY(util_ntohflt, from, to, count); -} - -void util_htondbl_array(const double * from, double * to, size_t count) -{ - BYTEORDER_ARRAY(util_htondbl, from, to, count); -} - -void util_ntohdbl_array(const double * from, double * to, size_t count) -{ - BYTEORDER_ARRAY(util_ntohdbl, from, to, count); -} - -uint16_t gs_bswap_16(uint16_t value) -{ - return (uint16_t)(((value & 0xff00) >> 8) | - ((value & 0x00ff) << 8)); -} - -void gs_bswap_16_array(const uint16_t * from, uint16_t * to, size_t count) -{ - BYTEORDER_ARRAY(gs_bswap_16, from, to, count); -} - -uint32_t gs_bswap_32(uint32_t value) -{ - return (((value & 0xff000000) >> 24) | - ((value & 0x000000ff) << 24) | - ((value & 0x0000ff00) << 8) | - ((value & 0x00ff0000) >> 8)); -} - -void gs_bswap_32_array(const uint32_t * from, uint32_t * to, size_t count) -{ - BYTEORDER_ARRAY(gs_bswap_32, from, to, count); -} - -uint64_t gs_bswap_64(uint64_t value) -{ - return (((value & 0xff00000000000000LL) >> 56) | - ((value & 0x00000000000000ffLL) << 56) | - ((value & 0x00ff000000000000LL) >> 40) | - ((value & 0x000000000000ff00LL) << 40) | - ((value & 0x0000ff0000000000LL) >> 24) | - ((value & 0x0000000000ff0000LL) << 24) | - ((value & 0x000000ff00000000LL) >> 8) | - ((value & 0x00000000ff000000LL) << 8)); -} - -void gs_bswap_64_array(const uint64_t * from, uint64_t * to, size_t count) -{ - BYTEORDER_ARRAY(gs_bswap_64, from, to, count); -} - -float gs_bswap_float(float value) -{ - union v { - float f; - uint32_t i; - } val; - val.f = value; - val.i = gs_bswap_32(val.i); - return val.f; -} - -void gs_bswap_float_array(const float * from, float * to, size_t count) -{ - BYTEORDER_ARRAY(gs_bswap_float, from, to, count); -} diff --git a/gomspace/libutil/src/clock.c b/gomspace/libutil/src/clock.c deleted file mode 100644 index ac215df6..00000000 --- a/gomspace/libutil/src/clock.c +++ /dev/null @@ -1,113 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include - -#if !__AVR__ -#include -#endif - -gs_error_t gs_clock_to_iso8601_string2(uint32_t utc_sec, char * buf, size_t buf_size) -{ - if ((buf == NULL) || (buf_size == 0)) { - return GS_ERROR_ARG; - } - -#if __AVR__ - int res = snprintf(buf, buf_size, "%"PRIu32"Z", utc_sec); - if ((res < 0) || ((size_t)res >= buf_size)) { - buf[buf_size - 1] = 0; - return GS_ERROR_RANGE; - } -#else - const time_t time_seconds = (time_t) utc_sec; - struct tm tm_buf; - struct tm * tm = gmtime_r(&time_seconds, &tm_buf); - if (tm == NULL) { - int res = snprintf(buf, buf_size, "%ldZ", time_seconds); - if ((res < 0) || ((size_t)res >= buf_size)) { - buf[buf_size - 1] = 0; - } - return GS_ERROR_DATA; - } - - // ISO8601 timestamp: 2017-03-30T06:20:45Z - int res = snprintf(buf, buf_size, "%04d-%02d-%02dT%02d:%02d:%02dZ", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - if ((res < 0) || ((size_t)res >= buf_size)) { - buf[buf_size - 1] = 0; - return GS_ERROR_RANGE; - } -#endif - - return GS_OK; -} - -gs_error_t gs_clock_to_iso8601_string(const gs_timestamp_t * utc_time, char * buf, size_t buf_size) -{ - if (utc_time == NULL) { - return GS_ERROR_ARG; - } - - return gs_clock_to_iso8601_string2(utc_time->tv_sec, buf, buf_size); -} - -gs_error_t gs_clock_from_string(const char * str, gs_timestamp_t * ts) -{ - if (!str || !str[0] || !ts) { - return GS_ERROR_ARG; - } - - // check for . - { - uint32_t sec; - uint32_t nsec; - int res = sscanf(str, "%" SCNu32 ".%" SCNu32, &sec, &nsec); - if (res == 2) { - ts->tv_sec = sec; - ts->tv_nsec = nsec; - return GS_OK; - } - } - -#if !__AVR__ - // check for ISO8601 - { - struct tm tm; - memset(&tm, 0, sizeof(tm)); // no daylight saving - //int res = sscanf(str, "%" SCNd32 "-%" SCNd32 "-%" SCNd32 "T%" SCNd32 ":%" SCNd32 ":%" SCNd32 "Z", - int res = sscanf(str, "%d-%d-%dT%d:%d:%dZ", - &tm.tm_year, &tm.tm_mon, &tm.tm_mday, - &tm.tm_hour, &tm.tm_min, &tm.tm_sec); - if ((res == 6) && - (tm.tm_year >= 1970) && (tm.tm_year <= 2038) && - (tm.tm_mon >= 1) && (tm.tm_mon <= 12) && - (tm.tm_mday >= 1) && (tm.tm_mday <= 31) && - (tm.tm_hour >= 0) && (tm.tm_hour <= 23) && - (tm.tm_min >= 0) && (tm.tm_min <= 59) && - (tm.tm_sec >= 0) && (tm.tm_sec <= 60)) - { - tm.tm_year -= 1900; - tm.tm_mon -= 1; - -#if __linux__ - // not posix compliant - time_t sec = timegm(&tm); -#else - // embedded platforms do not have timezones/daylight-saving - so standard mktime works - time_t sec = mktime(&tm); -#endif - if (sec >= 0) { - ts->tv_sec = (uint32_t) sec; - ts->tv_nsec = 0; - return GS_OK; - } - } - } -#endif - - return GS_ERROR_DATA; -} diff --git a/gomspace/libutil/src/crc32.c b/gomspace/libutil/src/crc32.c deleted file mode 100644 index 90d21832..00000000 --- a/gomspace/libutil/src/crc32.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * efone - Distributed internet phone system. - * - * (c) 1999,2000 Krzysztof Dabrowski - * (c) 1999,2000 ElysiuM deeZine - * - * This program 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 - * 2 of the License, or (at your option) any later version. - * - * Based on implementation by Finn Yannick Jacobs - */ - -#include -#include - -static const uint32_t crc_tab[256] GS_PGM_OBJECT = { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -}; - -#define CALC_CRC32_STEP(crc,byte) (((crc >> 8) & 0x00FFFFFF) ^ GS_PGM_UINT32_BY_PTR(&crc_tab[(crc ^ byte) & (uint32_t) 0xFF])) - -uint32_t gs_crc32_init(void) -{ - return 0xFFFFFFFF; -} - -uint32_t gs_crc32_update(uint32_t crc, const void * block, size_t length) -{ - if (block && length) { - const uint8_t * u8 = block; - for (unsigned int i = 0; i < length; i++) { - crc = CALC_CRC32_STEP(crc, *u8++); - } - } - return crc; -} - -uint32_t gs_crc32_finalize(uint32_t crc) -{ - return (crc ^ 0xFFFFFFFF); -} - -uint32_t gs_crc32(const void * block, size_t length) -{ - return gs_crc32_finalize(gs_crc32_update(gs_crc32_init(), block, length)); -} diff --git a/gomspace/libutil/src/crc8.c b/gomspace/libutil/src/crc8.c deleted file mode 100644 index aa810b31..00000000 --- a/gomspace/libutil/src/crc8.c +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -static const uint8_t crc_tab[256] GS_PGM_OBJECT = { - 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, - 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, - 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, - 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, - 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, - 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, - 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, - 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, - 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, - 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, - 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, - 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, - 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, - 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, - 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, - 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, - 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, - 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, - 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, - 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, - 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, - 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, - 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, - 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, - 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, - 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, - 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, - 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, - 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, - 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, - 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, - 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 -}; - - -#define CALC_CRC8_STEP(crc,byte) ((crc >> 8) ^ GS_PGM_UINT8_BY_PTR(&crc_tab[(crc ^ byte) & (uint8_t) 0xFF])) - -uint8_t gs_crc8_init(void) -{ - return 0xFF; -} - -uint8_t gs_crc8_update(uint8_t crc, const void * block, size_t length) -{ - if (block && length) { - const uint8_t * u8 = block; - for (unsigned int i = 0; i < length; i++) { - crc = CALC_CRC8_STEP(crc, *u8++); - } - } - return crc; -} - -uint8_t gs_crc8_finalize(uint8_t crc) -{ - return (crc ^ 0x00); -} - -uint8_t gs_crc8(const void * block, size_t length) -{ - return gs_crc8_finalize(gs_crc8_update(gs_crc8_init(), block, length)); -} diff --git a/gomspace/libutil/src/drivers/can/can.c b/gomspace/libutil/src/drivers/can/can.c deleted file mode 100644 index c08eaddb..00000000 --- a/gomspace/libutil/src/drivers/can/can.c +++ /dev/null @@ -1,6 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -// deifne common log group. -GS_LOG_GROUP(gs_can_log, "can", GS_LOG_CAT_DRIVER, GS_LOG_DEFAULT_MASK); diff --git a/gomspace/libutil/src/drivers/i2c/i2c.c b/gomspace/libutil/src/drivers/i2c/i2c.c deleted file mode 100644 index acd9e60e..00000000 --- a/gomspace/libutil/src/drivers/i2c/i2c.c +++ /dev/null @@ -1,6 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -// define common log group. -GS_LOG_GROUP(gs_i2c_log, "i2c", GS_LOG_CAT_DRIVER, GS_LOG_DEFAULT_MASK); diff --git a/gomspace/libutil/src/drivers/spi/spi.c b/gomspace/libutil/src/drivers/spi/spi.c deleted file mode 100644 index eea8153a..00000000 --- a/gomspace/libutil/src/drivers/spi/spi.c +++ /dev/null @@ -1,6 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -// define common log group. -GS_LOG_GROUP(gs_spi_log, "spi", GS_LOG_CAT_DRIVER, GS_LOG_DEFAULT_MASK); diff --git a/gomspace/libutil/src/drivers/sys/memory.c b/gomspace/libutil/src/drivers/sys/memory.c deleted file mode 100644 index 365dcf4a..00000000 --- a/gomspace/libutil/src/drivers/sys/memory.c +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -static const char * long_to_string(char * buf, size_t buf_size, long lvalue) -{ - if (lvalue >= 0) { - snprintf(buf, buf_size, "%ld", lvalue); - return buf; - } - return "Unknown"; -} - -gs_error_t gs_mem_get_ram_stat(gs_mem_ram_type_t type, gs_mem_ram_stat_t * ram_stat) -{ - if (type == GS_MEM_RAM_TYPE_INTERNAL) { - return gs_mem_get_int_ram_stat(ram_stat); - } else if (type == GS_MEM_RAM_TYPE_EXTERNAL) { - return gs_mem_get_ext_ram_stat(ram_stat); - } - - /* Unsupported memory type */ - return GS_ERROR_NOT_SUPPORTED; -} - -gs_error_t gs_mem_print_ram_stat(gs_mem_ram_stat_t * ram_stat, FILE * out) -{ - GS_CHECK_ARG(ram_stat != NULL); - char buf[20]; - - fprintf(out, "Total: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->total)); - fprintf(out, "Max available: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->max_available)); - fprintf(out, "Min available: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->min_available)); - fprintf(out, "Available: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->available)); - return GS_OK; -} diff --git a/gomspace/libutil/src/error.c b/gomspace/libutil/src/error.c deleted file mode 100644 index 57e42abd..00000000 --- a/gomspace/libutil/src/error.c +++ /dev/null @@ -1,106 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#define GS_UTIL_DEPRECATED_ERROR_CODES 1 - -#include -#include -#include -#include - -#ifdef __AVR__ -const char * gs_error_string(int error) -{ - /** - avr: const strings are not automatically stored in program space (see gs/util/pgm.h), and if stored - in program space, they require special formatting in logs (i.e. "%S"). - So we settle for simple error string, with the error nnumber - no need to change log/(s)printf etc. - @note: solution is not 100% thread/task safe. - */ - static char buffer[15]; // large enough to always keep zero termination, due to no thread/task lock - snprintf(buffer, sizeof(buffer), "%d", error); - return buffer; -} -#else -const char * gs_error_string(int error) -{ - switch (error) { - case GS_OK: return "GS_OK(0)"; - case GS_ERROR_PERM: return GS_DEF2STRING(GS_ERROR_PERM) "(-1)"; - case GS_ERROR_INTR: return GS_DEF2STRING(GS_ERROR_INTR) "(-4)"; - case GS_ERROR_IO: return GS_DEF2STRING(GS_ERROR_IO) "(-5)"; - case GS_ERROR_AGAIN: return GS_DEF2STRING(GS_ERROR_AGAIN) "(-11)"; - case GS_ERROR_ALLOC: return GS_DEF2STRING(GS_ERROR_ALLOC) "(-12)"; - case GS_ERROR_ACCESS: return GS_DEF2STRING(GS_ERROR_ACCESS) "(-13)"; - case GS_ERROR_BUSY: return GS_DEF2STRING(GS_ERROR_BUSY) "(-16)"; - case GS_ERROR_EXIST: return GS_DEF2STRING(GS_ERROR_EXIST) "(-17)"; - case GS_ERROR_ARG: return GS_DEF2STRING(GS_ERROR_ARG) "(-22)"; - case GS_ERROR_NOT_IMPLEMENTED: return GS_DEF2STRING(GS_ERROR_NOT_IMPLEMENTED) "(-38)"; - case GS_ERROR_OVERFLOW: return GS_DEF2STRING(GS_ERROR_OVERFLOW) "(-75)"; - case GS_ERROR_NOT_SUPPORTED: return GS_DEF2STRING(GS_ERROR_NOT_SUPPORTED) "(-95)"; - case GS_ERROR_IN_USE: return GS_DEF2STRING(GS_ERROR_IN_USE) "(-98)"; - case GS_ERROR_CONNECTION_RESET: return GS_DEF2STRING(GS_ERROR_CONNECTION_RESET) "(-104)"; - case GS_ERROR_NO_BUFFERS: return GS_DEF2STRING(GS_ERROR_NO_BUFFERS) "(-105)"; - case GS_ERROR_TIMEOUT: return GS_DEF2STRING(GS_ERROR_TIMEOUT) "(-110)"; - case GS_ERROR_ALREADY_IN_PROGRESS: return GS_DEF2STRING(GS_ERROR_ALREADY_IN_PROGRESS) "(-114)"; - - case GS_ERROR_HANDLE: return GS_DEF2STRING(GS_ERROR_HANDLE) "(-2000)"; - case GS_ERROR_NOT_FOUND: return GS_DEF2STRING(GS_ERROR_NOT_FOUND) "(-2001)"; - case GS_ERROR_FULL: return GS_DEF2STRING(GS_ERROR_FULL) "(-2002)"; - case GS_ERROR_RANGE: return GS_DEF2STRING(GS_ERROR_RANGE) "(-2003)"; - case GS_ERROR_DATA: return GS_DEF2STRING(GS_ERROR_DATA) "(-2004)"; - case GS_ERROR_UNKNOWN: return GS_DEF2STRING(GS_ERROR_UNKNOWN) "(-2005)"; - case GS_ERROR_NO_DATA: return GS_DEF2STRING(GS_ERROR_NO_DATA) "(-2006)"; - case GS_ERROR_STALE: return GS_DEF2STRING(GS_ERROR_STALE) "(-2007)"; - case GS_ERROR_TYPE: return GS_DEF2STRING(GS_ERROR_TYPE) "(-2008)"; - case GS_ERROR_AMBIGUOUS: return GS_DEF2STRING(GS_ERROR_AMBIGUOUS) "(-2009)"; - case GS_ERROR_STATE: return GS_DEF2STRING(GS_ERROR_STATE) "(-2010)"; - } - - // as fallback we use standard POSIX error string - const int posix_error = abs(error); - return strerror(posix_error); -} -#endif - -gs_error_t gs_error(int error) -{ - return (abs(error) * -1); -} - -#ifndef __AVR__ -const char * error_string(int code) -{ - switch (code) { - case E_NO_ERR: - return "No error"; - case E_NO_DEVICE: - return "No device"; - case E_MALLOC_FAIL: - return "Malloc fail"; - case E_THREAD_FAIL: - return "Thread failure"; - case E_NO_QUEUE: - return "No such queue"; - case E_INVALID_BUF_SIZE: - return "Invalid buffer size"; - case E_INVALID_PARAM: - return "Invalid paramater"; - case E_NO_SS: - return "No such subsystem"; - case E_GARBLED_BUFFER: - return "Rubbish in buffer"; - case E_FLASH_ERROR: - return "FLASH error"; - case E_BOOT_SER: - return "Thread boot fail: serial driver"; - case E_BOOT_DEBUG: - return "Thread boot fail: debug console"; - case E_BOOT_FLASH: - return "Thread boot fail: flash driver"; - case E_NO_BUFFER: - return "No buffer"; - default: - return "Unknown error"; - } -} -#endif diff --git a/gomspace/libutil/src/fletcher.c b/gomspace/libutil/src/fletcher.c deleted file mode 100644 index a9dab265..00000000 --- a/gomspace/libutil/src/fletcher.c +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -uint16_t gs_fletcher16_memcpy(const void * data_in, size_t count, void * (*memcpyfcn)(void *, const void *, size_t)) -{ - if (memcpyfcn == NULL) { - memcpyfcn = &memcpy; - } - - uint16_t sum1 = 0; - uint16_t sum2 = 0; - - if (data_in && count) { - const uint8_t * data = data_in; - for (unsigned int idx = 0; idx < count; ++idx) { - uint8_t byte; - (*memcpyfcn)(&byte, &data[idx], 1); - sum1 = (uint16_t)((sum1 + byte) % 255); - sum2 = (uint16_t)((sum2 + sum1) % 255); - } - } - return (uint16_t)((sum2 << 8) | sum1); -} - -uint16_t gs_fletcher16_P(const void * data_in, size_t count) -{ - uint16_t sum1 = 0; - uint16_t sum2 = 0; - - if (data_in && count) { - const uint8_t * data = data_in; - for (unsigned int idx = 0; idx < count; ++idx) { - sum1 = (uint16_t)((sum1 + GS_PGM_UINT8_BY_PTR(data++)) % 255); - sum2 = (uint16_t)((sum2 + sum1) % 255); - } - } - return (uint16_t)((sum2 << 8) | sum1); -} - -uint16_t gs_fletcher16(const void * data_in, size_t size) -{ - uint16_t sum1 = 0; - uint16_t sum2 = 0; - - if (data_in && size) { - const uint8_t * data = data_in; - for (unsigned int idx = 0; idx < size; ++idx) { - sum1 = (uint16_t)((sum1 + (*data++)) % 255); - sum2 = (uint16_t)((sum2 + sum1) % 255); - } - } - return (uint16_t)((sum2 << 8) | sum1); -} - -void gs_fletcher16_init(gs_fletcher16_t * f16) -{ - f16->sum1 = f16->sum2 = 0; -} - -void gs_fletcher16_update(gs_fletcher16_t * f16, const void * data_in, size_t size) -{ - if (f16 && data_in && size) { - const uint8_t * data = data_in; - for (unsigned int idx = 0; idx < size; ++idx) { - f16->sum1 = (uint16_t)((f16->sum1 + (*data++)) % 255); - f16->sum2 = (uint16_t)((f16->sum2 + f16->sum1) % 255); - } - } -} - -uint16_t gs_fletcher16_finalize(gs_fletcher16_t * f16) -{ - return (uint16_t)((f16->sum2 << 8) | f16->sum1); -} diff --git a/gomspace/libutil/src/function_scheduler.c b/gomspace/libutil/src/function_scheduler.c deleted file mode 100644 index a89c8db2..00000000 --- a/gomspace/libutil/src/function_scheduler.c +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include - -#include -#include -#include -#include -#include -#include - -typedef struct { - // function to call - gs_function_scheduler_function_t function; - // function's user data - void * user_data; - // timeout in mS - uint32_t timeout_ms; - // last execution time in mS - uint32_t last_exec_ms; -} gs_function_scheduler_entry_t; - -struct gs_function_scheduler { - // Max timeout in mS - uint32_t max_timeout_ms; - // allocated entries - unsigned int max_entries; - // entries - gs_function_scheduler_entry_t * entries; -}; - -GS_CHECK_STATIC_ASSERT(sizeof(int) >= 2, int_must_be_at_least_16bit); - -gs_error_t gs_function_scheduler_create(uint32_t max_timeout_ms, unsigned int max_entries, gs_function_scheduler_t ** return_scheduler) -{ - GS_CHECK_ARG(max_timeout_ms <= INT_MAX); - GS_CHECK_ARG(max_entries > 0); - GS_CHECK_ARG(return_scheduler != NULL); - - gs_function_scheduler_entry_t * entries = calloc(max_entries, sizeof(*entries)); - if (entries == NULL) { - return GS_ERROR_ALLOC; - } - - gs_function_scheduler_t * scheduler = calloc(1, sizeof(*scheduler)); - if (scheduler == NULL) { - free (entries); - return GS_ERROR_ALLOC; - } - - scheduler->max_timeout_ms = max_timeout_ms; - scheduler->entries = entries; - scheduler->max_entries = max_entries; - - *return_scheduler = scheduler; - - return GS_OK; -} - -gs_error_t gs_function_scheduler_destroy(gs_function_scheduler_t * scheduler) -{ - GS_CHECK_HANDLE(scheduler); - free(scheduler->entries); - free(scheduler); - return GS_OK; -} - -gs_error_t gs_function_scheduler_register_ms(gs_function_scheduler_t * scheduler, - uint32_t first_timeout_ms, gs_function_scheduler_function_t func, void * user_data) -{ - GS_CHECK_HANDLE(scheduler != NULL); - GS_CHECK_ARG(func != NULL); - - gs_function_scheduler_entry_t * entry = scheduler->entries; - for (unsigned int i = 0; i < scheduler->max_entries; ++i, ++entry) { - if (entry->function == NULL) { - entry->function = func; - entry->user_data = user_data; - entry->timeout_ms = first_timeout_ms; - entry->last_exec_ms = gs_time_rel_ms(); - return GS_OK; - } - } - - return GS_ERROR_FULL; -} - -int gs_function_scheduler_execute_ms(gs_function_scheduler_t * scheduler) -{ - uint32_t timeout_ms = 5000; // max timeout to ensure gs_time_rel_ms() works correctly (wrapping more than once is bad) - - if (scheduler) { - timeout_ms = scheduler->max_timeout_ms; - uint32_t now_ms = gs_time_rel_ms(); - - gs_function_scheduler_entry_t * entry = scheduler->entries; - for (unsigned int i = 0; i < scheduler->max_entries; ++i, ++entry) { - if (entry->function) { - uint32_t elapsed = gs_time_diff_ms(entry->last_exec_ms, now_ms); - if (elapsed >= entry->timeout_ms) { - entry->timeout_ms = (entry->function)(entry->user_data); - entry->last_exec_ms = now_ms = gs_time_rel_ms(); - elapsed = 0; - } - timeout_ms = gs_min(timeout_ms, (entry->timeout_ms - elapsed)); - } - } - } - - return (int)((timeout_ms < INT_MAX) ? timeout_ms : INT_MAX); -} diff --git a/gomspace/libutil/src/gosh/command.c b/gomspace/libutil/src/gosh/command.c deleted file mode 100644 index b68d6c82..00000000 --- a/gomspace/libutil/src/gosh/command.c +++ /dev/null @@ -1,754 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include "command_local.h" - -#include -#include - -#include // register commands -#include // register commands -#include -#include -#include "../lock.h" - -#define MAX_ARGC 30 - -#ifdef __AVR__ -#include -#define cmd_strcmp strcmp_P -#define cmd_strncmp strncmp_P -#define cmd_strlen strlen_P -#define cmd_strcpy strcpy_P -#define cmd_read_ptr(ptr) ((void *) pgm_read_word(ptr)) -#define cmd_read_int(ptr) pgm_read_word(ptr) -#else -#define cmd_strcmp strcmp -#define cmd_strncmp strncmp -#define cmd_strlen strlen -#define cmd_strcpy strcpy -#define cmd_read_ptr(ptr) *ptr -#define cmd_read_int(ptr) *ptr -#endif - -// define common command log group. -static GS_LOG_GROUP(gs_command_log, "command", GS_LOG_CAT_COMMAND, LOG_DEFAULT_MASK | LOG_INFO_MASK); -#define LOG_DEFAULT gs_command_log - -/** - Compile check that size of gs_command_t is multiplum of 4. -*/ -GS_STATIC_ASSERT((sizeof(gs_command_t) % 4) == 0, gs_command_t_is_not_a_multiplum_of_4); - -// Private context -typedef struct process_context { - // command context - must be first, as it is used to access private context (same address) - gs_command_context_t context; - // process function - gs_error_t (*process)(const gs_command_t * const cmds, int cmd_count, int arg_offset, struct process_context * pc); - // command error - gs_error_t error; - // only exact match (space after last argument) - bool requires_exact_match; - // first command match - const gs_command_t * cmd; - // number of hits when hunting commands, completion etc. - unsigned int hits; - // complete result - struct { - char * line; - size_t token_start; - } complete; -} private_context_t; - -// command block -typedef struct gs_command_block { - //! Pointer to command block. - const gs_command_t * commands; - //! Number of commands in command block. - size_t count; - //! Reference to next command block. - struct gs_command_block * next; -} gs_command_block_t; - -// commands -static gs_command_block_t g_commands; - -// minimum stack size in bytes. -static size_t g_stack_size; - -// command logger callback -static gs_command_log_t g_command_logger = NULL; -static void * g_command_logger_ctx = NULL; - -static gs_error_t command_stdio_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value) -{ - static const char* printed_group_header = NULL; - /* Print Group header if Group string is non-empty */ - if ((group != NULL) && (group[0] != '\0')) { - if (printed_group_header != group) { - fprintf(ctx->out, "%s:\r\n", group); - printed_group_header = group; - } - } - /* Print ": " if key string is non-empty */ - if (key != NULL) { - if (key[0] != '\0') { - if ((group != NULL) && (group[0] != '\0')) { - fprintf(ctx->out, " %s: ", key); - } else { - fprintf(ctx->out, "%s: ", key); - } - } - } - fprintf(ctx->out, "%s\r\n", value); - return GS_OK; -} - -gs_error_t gs_command_stdio_flush(gs_command_context_t *ctx) -{ - fflush(ctx->out); - return GS_OK; -} - -gs_error_t gs_command_stdio_wait_for_key(gs_command_context_t *ctx, int *ch, int timeout_ms) -{ - return gs_stdio_getchar_timed(timeout_ms, ch); -} - -static const gs_command_io_functions_t stdio_functions = { - .set_result = command_stdio_set_result, - .flush = gs_command_stdio_flush, - .wait_for_key = gs_command_stdio_wait_for_key -}; - -const char * gs_command_args(gs_command_context_t *ctx) -{ - if (ctx->argc > 1) { - // find first matching argument (= starts with) - this is not 100% and doesn't handle arguments with spaces (quoted) - const char * arg = ctx->command_line; - while (arg && arg[0]) { - if (strncmp(arg, ctx->argv[1], strlen(ctx->argv[1])) == 0) { - return arg; - } - // skip argument - for (; *arg && (*arg != ' '); ++arg); - // skip spaces - // cppcheck-suppress redundantCondition - for (; *arg && (*arg == ' '); ++arg); - } - } - return ""; -} - -bool gs_command_build_argv(char *line, int *argc, char **argv, int max_argc) -{ - // Skip spaces - for (; line && *line && isspace((unsigned int)*line); ++line); - - *argc = 0; - argv[*argc] = line; - - char quote = 0; - - while (*line) { - // check for quote's: ' or " - if ((*line == '\'') || (*line == '\"')) { - if (quote == 0) { - quote = *line; - argv[*argc]++; - } else if (quote == *line) { - quote = 0; - *line = '\0'; - } - } - // check for whitespace and no quotes active - else if (isspace((unsigned int)*line) && quote == 0) { - /* Delete space */ - *line++ = '\0'; - - // skip spaces - for (; *line && isspace((unsigned int)*line); ++line); - - /* If there is more data, we have another argument */ - if (*line) { - (*argc)++; - if (*argc >= max_argc) { - return false; - } - argv[*argc] = line; - } - - continue; - } - - line++; - } - - (*argc)++; - if (*argc >= max_argc) { - return false; - } - - // According to C11 section 5.1.2.2.1, argv[argc] must be NULL - argv[*argc] = NULL; - - // Check for invalid number of quotes - return (quote == 0) ? true : false; -} - -static inline gs_error_t command_logger(const char *cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t ts, gs_timestamp_t te) -{ - gs_lock_lock(); - gs_command_log_t logger = g_command_logger; - void * log_ctx = g_command_logger_ctx; - gs_lock_unlock(); - - if (logger) { - return logger(cmd_line, ret, cmd_ret, ts, te, log_ctx); - } - return GS_OK; -} - -static gs_error_t command_execute(const gs_command_t * const cmds, int cmd_count, int arg_offset, private_context_t * pc) -{ - for (int i = 0; i < cmd_count; i++) { - const gs_command_t * cmd = &cmds[i]; - - if (cmd_strcmp(pc->context.argv[arg_offset], cmd->name) == 0) { - // check for sub-commands - const gs_command_t * list = (void*) cmd_read_ptr(&cmd->chain.list); - if (list) { - ++arg_offset; - if (arg_offset >= pc->context.argc) { - return GS_ERROR_TYPE; - } - return command_execute(list, cmd_read_int(&cmd->chain.count), arg_offset, pc); - } - - gs_command_handler_t handler = (void *) cmd_read_ptr(&cmd->handler); - if (handler == NULL) { - return GS_ERROR_NOT_IMPLEMENTED; - } - - pc->context.argc -= arg_offset; - pc->context.argv = &pc->context.argv[arg_offset]; - pc->context.command = cmd; - - // check arguments - if specified - if (cmd->mandatory_args || cmd->optional_args) { - const int min_args = (cmd->mandatory_args == GS_COMMAND_NO_ARGS) ? 0 : cmd->mandatory_args; - const int args = (pc->context.argc - 1); - if (args < min_args) { - return GS_ERROR_ARG; - } - if (args > (min_args + cmd->optional_args)) { - return GS_ERROR_ARG; - } - } - - pc->error = handler(&pc->context); - return GS_OK; // command was excecuted - } - } - - return GS_ERROR_NOT_FOUND; -} - -static gs_error_t command_process(private_context_t * pc) -{ - const char * command = gs_string_skip_leading_spaces(pc->context.command_line); - - // Make copy of string, because command parser mangles destroys it - const size_t command_len = strlen(command); - char command_copy[command_len + 1]; - strcpy(command_copy, command); - - if (command_len && command[command_len-1] == ' ') { - pc->requires_exact_match = true; - } - - pc->context.optsp = 1; - pc->context.optind = 1; - pc->context.optopt = '?'; - pc->context.command_line = command; - - // split into arguments - char *argv[MAX_ARGC + 1]; - if (gs_command_build_argv(command_copy, &pc->context.argc, argv, MAX_ARGC + 1) == false) { - return GS_ERROR_ARG; - } - pc->context.argv = argv; - - gs_error_t error = GS_ERROR_NOT_FOUND; - for (const gs_command_block_t * block = &g_commands; block && (error == GS_ERROR_NOT_FOUND); block = block->next) { - if (block->commands) { - error = (pc->process)(block->commands, block->count, 0, pc); - } - } - - return error; -} - -gs_error_t gs_command_run(const char * command, gs_error_t * return_command_result) -{ - return gs_command_execute_stdio(command, return_command_result); -} - -gs_error_t gs_command_execute_stdio(const char * command, gs_error_t * return_command_result) -{ - return gs_command_execute(command, return_command_result, stdout, &stdio_functions, NULL); -} - -gs_error_t gs_command_execute(const char * command, gs_error_t * return_command_result, FILE *out, - const gs_command_io_functions_t *iof, void *iof_ctx) -{ - command = gs_string_skip_leading_spaces(command); - GS_CHECK_ARG(gs_string_empty(command) == false); - - private_context_t pc = { - .process = command_execute, - .error = GS_OK, - .context = { - .command_line = command, - .out = out, - .io_functions = iof, - .io_ctx = iof_ctx, - } - }; - gs_timestamp_t tm_start, tm_end; - gs_clock_get_time(&tm_start); - gs_error_t error = command_process(&pc); - gs_clock_get_time(&tm_end); - command_logger(pc.context.command_line, error, pc.error, tm_start, tm_end); - if ((error == GS_OK) && return_command_result) { - *return_command_result = pc.error; - } - return error; -} - -gs_error_t gs_command_set_output(gs_command_context_t *ctx, const char* group, const char* key, const char* value) -{ - GS_CHECK_ARG(ctx); - - if (ctx->io_functions && ctx->io_functions->set_result) { - return ctx->io_functions->set_result(ctx, group, key, value); - } - - /* If no IO-function set - ignore the data and send Success */ - return GS_OK; -} - -gs_error_t gs_command_set_output_printf(gs_command_context_t *ctx, const char* group, const char* key, const char * format, ...) -{ - GS_CHECK_ARG(ctx); - - if (ctx->io_functions && ctx->io_functions->set_result) - { - va_list args; - va_start(args, format); - char value[256]; - int size = vsnprintf(value, sizeof(value), format, args); - va_end(args); - - /* Don't allow to set truncated results - Return error in this case */ - if (size >= (int)sizeof(value)) { - return GS_ERROR_ALLOC; - } - - return ctx->io_functions->set_result(ctx, group, key, value); - } - - /* If no IO-function set - ignore the data and send Success */ - return GS_OK; -} - -gs_error_t gs_command_flush_output(gs_command_context_t *ctx) -{ - GS_CHECK_ARG(ctx); - - if (ctx->io_functions && ctx->io_functions->flush) { - return ctx->io_functions->flush(ctx); - } - - /* If no IO-function set - ignore the data and send Success */ - return GS_OK; -} - -bool gs_command_wait_any_key(gs_command_context_t *ctx, int timeout_ms) -{ - int ch; - gs_error_t ret = gs_command_wait_key(ctx, &ch, timeout_ms); - - if (ret == GS_ERROR_TIMEOUT) { - return false; - } - - /* Ensure that a commands handler will not stall if IO function if not available etc. - False will only be returned in case of a positive timeout */ - return true; -} - -gs_error_t gs_command_wait_key(gs_command_context_t *ctx, int* ch, int timeout_ms) -{ - if (ctx && ctx->io_functions && ctx->io_functions->wait_for_key) - { - return ctx->io_functions->wait_for_key(ctx, ch, timeout_ms); - } - - /* If no IO-function set set return GS_ERROR_HANDLE */ - return GS_ERROR_HANDLE; -} - -unsigned int gs_command_completer_add_token(gs_command_context_t * ctx, const char * token, bool exact) -{ - private_context_t * pc = (private_context_t *) ctx; - char * line = &pc->complete.line[pc->complete.token_start]; - - if (token == NULL) { - // mark any pending partial token as exact - if ((line[0] == 0) || (pc->hits != 1)) { - return pc->hits; - } - exact = true; - } - - if (exact) { - if (token) { - strcpy(line, token); - } - strcat(line, " "); - pc->complete.token_start = strlen(pc->complete.line); - pc->hits = 1; - } else { - if (pc->hits == 0) { - strcpy(line, token); - } else { - for (; *line && *token && (*line == *token); ++line, ++token); - *line = 0; - } - ++pc->hits; - } - - return pc->hits; -} - -static unsigned int command_complete_add(private_context_t * pc, const gs_command_t * cmd, bool exact) -{ - if (cmd) { - pc->cmd = cmd; - return gs_command_completer_add_token(&pc->context, cmd->name, exact); - } else { - return gs_command_completer_add_token(&pc->context, NULL, exact); - } -} - -static gs_error_t command_complete(const gs_command_t * const cmds, int cmd_count, int arg_offset, private_context_t * pc) -{ - if (arg_offset > 0) { - // command we are looking for must be in this block - pc->hits = 0; - } - pc->cmd = NULL; - bool exact_match = false; - - for (int i = 0; i < cmd_count; i++) { - const gs_command_t * cmd = &cmds[i]; - - if (cmd_read_int(&cmd->mode) & GS_COMMAND_FLAG_HIDDEN) { - continue; - } - - if (gs_string_empty(pc->context.argv[arg_offset])) { - // exceeding known token(s) - partial match - command_complete_add(pc, cmd, false); - continue; - } - - if (pc->requires_exact_match || ((arg_offset+1) < pc->context.argc)) { - // must be an exact match - if (cmd_strcmp(pc->context.argv[arg_offset], cmd->name) == 0) { - command_complete_add(pc, cmd, true); - exact_match = true; - break; - } - } else if (cmd_strncmp(pc->context.argv[arg_offset], cmd->name, - strlen(pc->context.argv[arg_offset])) == 0) { - // partial match - command_complete_add(pc, cmd, false); - } - } - - if (exact_match || ((arg_offset > 0) && (pc->hits == 1))) { - command_complete_add(pc, NULL, true); - - if (strlen(pc->complete.line) > strlen(pc->context.command_line)) { - return GS_OK; - } - - if (pc->cmd->chain.list) { - return command_complete(pc->cmd->chain.list, pc->cmd->chain.count, arg_offset+1, pc); - } - - // command arguments - pc->context.argc -= arg_offset; - pc->context.argv = &pc->context.argv[arg_offset]; - pc->context.command = pc->cmd; - - // add the "already" completed ones - int arg_to_complete = 1; - for (; arg_to_complete < (pc->context.argc - 1); ++arg_to_complete) { - gs_command_completer_add_token(&pc->context, pc->context.argv[arg_to_complete], true); - } - // add the last - if its completed (space after) - if ((arg_to_complete < pc->context.argc) && pc->requires_exact_match) { - // cppcheck-suppress unreadVariable - not used on __AVR__ because it doesn't support 'completer' - gs_command_completer_add_token(&pc->context, pc->context.argv[arg_to_complete], true); - ++arg_to_complete; - } - -#if (__AVR__ == 0) - if (pc->cmd->completer) { - pc->hits = 0; - (pc->cmd->completer)(&pc->context, arg_to_complete); - } else -#endif - { - pc->hits = 1; // no completer - assume single hit - } - - return GS_OK; // only used for breaking loop - } - - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_command_complete(char *line, size_t max_line_length, FILE* out) -{ - const size_t line_len = strlen(line); - char buffer[max_line_length]; - buffer[0] = 0; - private_context_t pc = { - .process = command_complete, - .context = { - .command_line = line, - .out = out, - }, - .complete = { - .line = buffer, - }, - }; - command_process(&pc); - gs_command_completer_add_token(&pc.context, NULL, true); - if (strlen(buffer) > line_len ) { - strcpy(line, buffer); - } - switch (pc.hits) { - case 0: - return GS_ERROR_NOT_FOUND; - case 1: - return GS_OK; - default: - return GS_ERROR_AMBIGUOUS; - } -} - -static void command_help_print(const gs_command_t * const cmd, private_context_t * pc) -{ - if (pc->hits == 1) { - if (cmd->help) { - fprintf(pc->context.out, "%s\r\n", cmd->help); - } - if (cmd->chain.count == 0) { - fprintf(pc->context.out, "usage: %s %s\r\n", cmd->name, cmd->usage ? cmd->usage : ""); - } else { - for (unsigned int i = 0; i < cmd->chain.count; ++i) { - const gs_command_t * scmd = &cmd->chain.list[i]; - - if (scmd->mode & GS_COMMAND_FLAG_HIDDEN) { - continue; - } - fprintf(pc->context.out, " %-19s %s\r\n", scmd->name, scmd->help ? scmd->help : ""); - } - } - } else { - fprintf(pc->context.out, " %-19s %s\r\n", cmd->name, cmd->help ? cmd->help : ""); - } -} - -static void command_help_hit(const gs_command_t * const cmd, private_context_t * pc) -{ - pc->error = GS_OK; - ++pc->hits; - if (pc->hits == 1) { - // single hit so far - hold off printing until we know if we get more - pc->cmd = cmd; - } else { - if (pc->cmd) { - command_help_print(pc->cmd, pc); - pc->cmd = NULL; - } - command_help_print(cmd, pc); - } -} - -static gs_error_t command_help(const gs_command_t * const cmds, int cmd_count, int arg_offset, private_context_t * pc) -{ - for (int i = 0; i < cmd_count; i++) { - const gs_command_t * cmd = &cmds[i]; - - if (cmd_read_int(&cmd->mode) & GS_COMMAND_FLAG_HIDDEN) { - continue; - } - - if (pc->requires_exact_match || ((arg_offset+1) < pc->context.argc)) { - // must be an exact match - if (cmd_strcmp(pc->context.argv[arg_offset], cmd->name) == 0) { - const gs_command_t * list = (void*) cmd_read_ptr(&cmd->chain.list); - if (list && ((arg_offset+1) < pc->context.argc)) { - return command_help(list, cmd_read_int(&cmd->chain.count), arg_offset+1, pc); - } - command_help_hit(cmd, pc); - } - - } else if (cmd_strncmp(pc->context.argv[arg_offset], cmd->name, - strlen(pc->context.argv[arg_offset])) == 0) { - command_help_hit(cmd, pc); - } - } - - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_command_show_help(const char * command, FILE* out) -{ - private_context_t pc = { - .process = command_help, - .error = GS_ERROR_NOT_FOUND, - .context = { - .command_line = command, - .out = out, - } - }; - gs_error_t error = command_process(&pc); - if (pc.cmd) { - command_help_print(pc.cmd, &pc); - error = GS_OK; - } else if ((error == GS_ERROR_NOT_FOUND) && pc.hits) { - error = GS_OK; - } - return error; -} - -gs_error_t gs_command_register(const gs_command_t * commands, size_t count) -{ - GS_CHECK_ARG(commands != NULL); - GS_CHECK_ARG(count > 0); - - gs_error_t error = GS_OK; - - gs_lock_lock(); - { - // check if command block already installed - gs_command_block_t * last_block = NULL; - for (gs_command_block_t * block = &g_commands; block; block = block->next) { - if (block->commands) { - const gs_command_t * cmd = block->commands; - // loop through because it may be in the linked blocks - for (size_t i = 0; i < block->count; ++i, ++cmd) { - if (cmd == commands) { - error = GS_ERROR_EXIST; - break; - } - } - } - last_block = block; - } - - if (error == GS_OK) { - gs_command_block_t * block = calloc(1, sizeof(*block)); - if (block) { - // Insert command last, so lock isn't needed when accessing commands - block->commands = commands; - block->count = count; - block->next = NULL; - last_block->next = block; - } else { - error = GS_ERROR_ALLOC; - } - } - } - gs_lock_unlock(); - - return (error != GS_ERROR_EXIST) ? error : GS_OK; -} - -size_t gs_command_get_stack_size(void) -{ - return g_stack_size; -} - -gs_error_t gs_command_init_no_commands(size_t stack_size) -{ - g_stack_size = stack_size; - - gs_error_t error = gs_lock_init(); - if (error) { - return error; - } - - gs_log_group_register(gs_command_log); - -#if (__linux__ == 0) - // look up static linked commands - only embedded (= none linux) systems - gs_command_block_t * block = &g_commands; - extern volatile unsigned int __command_start __attribute__ ((__weak__)); - extern volatile unsigned int __command_end __attribute__ ((__weak__)); - if (&__command_start) { - block->count = ((ptrdiff_t)&__command_end - (ptrdiff_t)&__command_start) / sizeof(gs_command_t); - block->commands = (gs_command_t *) &__command_start; - } -#endif - - return GS_OK; -} - -gs_error_t gs_command_init(size_t stack_size) -{ - gs_error_t error = gs_command_init_no_commands(stack_size); - if (error == GS_OK) { - // register default commands - gs_command_register_default_commands(); - gs_log_register_commands(); - } - return error; -} - -gs_error_t gs_command_logger_default(const char* cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t t_start, gs_timestamp_t t_end, void *log_ctx) -{ - (void)log_ctx; - - timestamp_diff(&t_end, &t_start); - if (ret == GS_OK) { - log_info_group(gs_command_log, "'%s' returned '%s' [" - "t: <%04"PRIu32".%06"PRIu32">, dt: <%01"PRIu32".%06"PRIu32">]", - cmd_line, gs_error_string(cmd_ret), - t_start.tv_sec, t_start.tv_nsec/1000, t_end.tv_sec, t_end.tv_nsec/1000); - } else { - log_info_group(gs_command_log, "'%s' could not be run, returned '%s' [" - "t: <%04"PRIu32".%06"PRIu32">]", - cmd_line, gs_error_string(ret), - t_start.tv_sec, t_start.tv_nsec/1000); - } - return GS_OK; -} - -gs_error_t gs_command_register_logger(gs_command_log_t log_cb, void *log_ctx) -{ - gs_lock_lock(); - g_command_logger = log_cb; - g_command_logger_ctx = log_ctx; - gs_lock_unlock(); - - return GS_OK; -} - diff --git a/gomspace/libutil/src/gosh/command_local.h b/gomspace/libutil/src/gosh/command_local.h deleted file mode 100644 index 69f715e1..00000000 --- a/gomspace/libutil/src/gosh/command_local.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -/** - Command I/O function - flush stdout. -*/ -gs_error_t gs_command_stdio_flush(gs_command_context_t *ctx); - -/** - Command I/O function - wait for a key. -*/ -gs_error_t gs_command_stdio_wait_for_key(gs_command_context_t *ctx, int *ch, int timeout_ms); - -/** - Complete command. - @param[in] line command line to complete - @param[in] max \a length (size) - @param[in] out output stream, e.g. stdout -*/ -gs_error_t gs_command_complete(char *line, size_t max_line_length, FILE* out); - -/** - Show help. - @param line command line to show help for. - @param out output stream, e.g. stdout -*/ -gs_error_t gs_command_show_help(const char * command, FILE * out); - -/** - Change console mode. - @param[in] mode console mode, 'cci' - @return_gs_error_t -*/ -int gs_console_change_mode(const char * mode); diff --git a/gomspace/libutil/src/gosh/console.c b/gomspace/libutil/src/gosh/console.c deleted file mode 100644 index 99b04aac..00000000 --- a/gomspace/libutil/src/gosh/console.c +++ /dev/null @@ -1,758 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - The console interface provides support for executing commands over stdout (typically a serial port). - - The connection can run in 2 modes: - - normal, standard GOSH interface (Human Machine Interface), echo characters, prompt, etc. - - cci, Computer Computer Interface. Simple text interface, but with tagged output format - easier to parse by a computer. -*/ -#include "console_local.h" -#include "command_local.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include // console defines set through Waf options - -#if (__linux__) -#include -#include -#include -#include -#endif - -/* Max history length (elements) */ -#ifndef GS_CONSOLE_HISTORY_LEN -#define GS_CONSOLE_HISTORY_LEN 10 -#endif - -/* Max input length */ -#ifndef GS_CONSOLE_INPUT_LEN -#define GS_CONSOLE_INPUT_LEN 100 -#endif - -#define CONTROL(X) ((X) - '@') - -typedef enum { - CONSOLE_NORMAL = 0, - CONSOLE_ESCAPE = 1, - CONSOLE_PRE_ESCAPE = 2, -} console_escape_t; - -static const char hash_prompt[] = "\033[1;30m # "; - -static const char backspace_char = '\b'; -static const char space_char = ' '; -static const char cr_char = '\r'; -static const char nl_char = '\n'; - -static const char * user_prompt = "gosh"; - -static console_escape_t escape = CONSOLE_NORMAL; - -#if (GS_CONSOLE_HISTORY_LEN > 0) -static int history_elements; -static int history_cur; -static int history_browse; -static char history[GS_CONSOLE_HISTORY_LEN][GS_CONSOLE_INPUT_LEN+1]; -#endif - -static int size; -static int pos; -static char buf[GS_CONSOLE_INPUT_LEN+1]; -static gs_thread_t console_thread; - -#if (__linux__) -static bool termios_changed; -static struct termios old_stdin; -static struct termios old_stdout; -#endif - -static gs_mutex_t g_cci_lock; // Lock for protecting stdout for async output, e.g. log messages -static gs_error_t command_io_cci_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value); -static const gs_command_io_functions_t cci_io_functions = { - .set_result = command_io_cci_set_result, - .flush = gs_command_stdio_flush, - .wait_for_key = gs_command_stdio_wait_for_key, -}; -#define CCI_START_TAG "[X[" -#define CCI_END_TAG "]X]" - -static void gs_console_write(const char *str, int length) -{ - for (int i = 0; i < length; i++) { - putchar(str[i]); - } -} - -static void gs_console_prompt(void) -{ - static const char col_start[] = "\033[1;32m"; - static const char col_end[] = "\033[0m"; - - gs_console_write(col_start, sizeof(col_start) - 1); - gs_console_write(user_prompt, strlen(user_prompt)); - gs_console_write(hash_prompt, sizeof(hash_prompt) - 1); - gs_console_write(col_end, sizeof(col_end) - 1); -} - -void gs_console_set_prompt(const char * _prompt) -{ - if (gs_string_empty(_prompt) == false) { - user_prompt = _prompt; - } -} - -static void gs_console_reset(void) -{ - pos = size = 0; - buf[pos] = 0; - gs_console_prompt(); -} - -static void gs_console_rewind(void) -{ - int plen = strlen(hash_prompt) + strlen(user_prompt); - gs_console_write(&cr_char, 1); - while (size-- + plen) { - gs_console_write(&space_char, 1); - } - pos = size = 0; - gs_console_write(&cr_char, 1); -} - -void gs_console_clear(void) -{ - static const char clear[] = "\033[H\033[2J"; - gs_console_write(clear, sizeof(clear) - 1); - gs_console_rewind(); - gs_console_reset(); -} - -void gs_console_update(void) -{ - gs_console_rewind(); - gs_console_prompt(); - pos = size = strlen(buf); - gs_console_write(buf, size); -} - -#if (GS_CONSOLE_HISTORY_LEN > 0) - -static void gs_console_history_add(void) -{ - strncpy(history[history_cur], buf, GS_CONSOLE_INPUT_LEN); - history[history_cur][GS_CONSOLE_INPUT_LEN] = 0; - - history_browse = 0; - history_cur = (history_cur + 1) % GS_CONSOLE_HISTORY_LEN; - - if (history_elements < GS_CONSOLE_HISTORY_LEN) { - history_elements++; - } -} - -static void gs_console_last_line(void) -{ - if (history_elements < 1) { - return; - } - - if (history_browse >= history_elements) { - return; - } - - gs_console_rewind(); - history_browse++; - strcpy(buf, history[(history_cur - history_browse + GS_CONSOLE_HISTORY_LEN) % GS_CONSOLE_HISTORY_LEN]); - gs_console_update(); -} - -static void gs_console_next_line(void) -{ - if (history_elements < 1) { - return; - } - - if (history_browse < 1) { - return; - } - - gs_console_rewind(); - history_browse--; - if (history_browse > 0) { - strcpy(buf, history[(history_cur - history_browse + GS_CONSOLE_HISTORY_LEN) % GS_CONSOLE_HISTORY_LEN]); - } else { - buf[0] = '\0'; - } - gs_console_update(); -} - -#endif - -static void gs_console_forward_char(void) -{ - if (pos < size) { - gs_console_write(&buf[pos], 1); - pos++; - } -} - -static void gs_console_end_of_line(void) -{ - while (pos < size) { - gs_console_forward_char(); - } -} - -static void gs_console_backward_char(void) -{ - if (pos > 0) { - pos--; - gs_console_write(&backspace_char, 1); - } -} - -static void gs_console_beginning_of_line(void) -{ - while (pos) { - gs_console_backward_char(); - } -} - -static void gs_console_newline(void) -{ - gs_console_write(&cr_char, 1); - gs_console_write(&nl_char, 1); -} - -static bool gs_command_not_empty(const char *ibuf) -{ - while (*ibuf) { - if (!isblank((int) *ibuf++)) { - return true; - } - } - return false; -} - -static void show_help(const char * command) -{ - gs_error_t error = gs_command_show_help(command, stdout); - if (error) { - printf("Could not show help for \'%s\': %s (%d)\r\n", command, gs_error_string(error), error); - } -} - -static void gs_console_execute(void) -{ - gs_console_newline(); - buf[GS_CONSOLE_INPUT_LEN] = 0; // ensure 0 termination - if (size > 0 && gs_command_not_empty(buf)) { -#if (GS_CONSOLE_HISTORY_LEN > 0) - gs_console_history_add(); -#endif - gs_error_t result = GS_OK; - gs_error_t error = gs_command_execute_stdio(buf, &result); - if (error == GS_ERROR_TYPE) { - show_help(buf); - } else if (error == GS_ERROR_NOT_FOUND) { - printf("Unknown command \'%s\'\r\n", buf); - } else if (error == GS_ERROR_ARG) { - show_help(buf); - } else if (error) { - printf("Command \'%s\' did not execute: %s (%d)\r\n", buf, gs_error_string(error), error); - } else if (result == GS_ERROR_ARG) { - show_help(buf); - } else if (result) { - printf("Command \'%s\' executed, but returned error: %s (%d)\r\n", buf, gs_error_string(result), result); - } - } - gs_console_reset(); -} - -static void gs_console_complete(void) -{ - /* We don't expand in the middle of a line */ - if (size != pos) { - return; - } - - const size_t old_buf_len = strlen(buf); - gs_error_t ret = gs_command_complete(buf, sizeof(buf), stdout); - if ((ret == GS_OK) && (old_buf_len == strlen(buf))) { - // completed (again) and no change - show help - ret = GS_ERROR_AMBIGUOUS; - } - switch (ret) { - case GS_ERROR_AMBIGUOUS: - gs_console_newline(); - show_help(buf); - gs_console_update(); - break; - case GS_OK: - gs_console_update(); - break; - default: - case GS_ERROR_NOT_FOUND: - break; - } -} - -static void gs_console_insert(char c) -{ - int i; - int diff = size - pos; - - if (size >= GS_CONSOLE_INPUT_LEN) { - return; - } - - memmove(&buf[pos + 1], &buf[pos], diff); - buf[pos] = c; - - gs_console_write(&buf[pos], diff + 1); - for (i = 0; i < diff; i++) { - gs_console_write(&backspace_char, 1); - } - - size++; - pos++; - buf[size] = '\0'; -} - -static void gs_console_insert_overwrite(char c) -{ - buf[pos++] = c; - - if (pos > size) { - size++; - } - - gs_console_write(&c, 1); -} - -static void gs_console_delete(void) -{ - int i; - int diff = size - pos; - - /* Nothing to delete */ - if (size == pos) { - return; - } - - size--; - memmove(&buf[pos], &buf[pos + 1], diff - 1); - buf[size] = '\0'; - - gs_console_write(&buf[pos], diff - 1); - gs_console_write(&space_char, 1); - for (i = 0; i < diff; i++) { - gs_console_write(&backspace_char, 1); - } -} - -static void gs_console_backspace(void) -{ - if (pos < 1) { - return; - } - - gs_console_backward_char(); - gs_console_delete(); -} - -static void gs_console_kill_line(void) -{ - int i; - int diff; - - diff = size - pos; - - if (diff == 0) { - return; - } - - for (i = 0; i < diff; i++) { - gs_console_write(&space_char, 1); - } - for (i = 0; i < diff; i++) { - gs_console_write(&backspace_char, 1); - } - - memset(&buf[pos], 0, diff); - size = pos; -} - -static void gs_console_kill_line_from_beginning(void) -{ - gs_console_beginning_of_line(); - gs_console_kill_line(); -} - -static void gs_console_backward_kill_word(void) -{ - while (pos > 0 && buf[pos - 1] == ' ') { - gs_console_backspace(); - } - while (pos > 0 && buf[pos - 1] != ' ') { - gs_console_backspace(); - } -} - -static void gs_console_transpose_chars(void) -{ - char c1, c2; - - if (size < 2 || pos < 1) { - return; - } - - if (pos == size) { - c1 = buf[pos - 1]; - c2 = buf[pos - 2]; - - gs_console_backward_char(); - gs_console_backward_char(); - gs_console_insert_overwrite(c1); - gs_console_insert_overwrite(c2); - } else { - c1 = buf[pos]; - c2 = buf[pos - 1]; - - gs_console_backward_char(); - gs_console_insert_overwrite(c1); - gs_console_insert_overwrite(c2); - } -} - -static void gs_console_normal(char c) -{ - switch (c) { - case CONTROL('A'): - gs_console_beginning_of_line(); - break; - case CONTROL('B'): - gs_console_backward_char(); - break; - case CONTROL('C'): - // Either ignored or handled through signals - break; - case CONTROL('D'): - gs_console_delete(); - break; - case CONTROL('E'): - gs_console_end_of_line(); - break; - case CONTROL('F'): - gs_console_forward_char(); - break; - case CONTROL('K'): - gs_console_kill_line(); - break; - case CONTROL('L'): - gs_console_clear(); - break; -#if (GS_CONSOLE_HISTORY_LEN > 0) - case CONTROL('N'): - gs_console_next_line(); - break; - case CONTROL('P'): - gs_console_last_line(); - break; -#endif - case CONTROL('T'): - gs_console_transpose_chars(); - break; - case CONTROL('U'): - gs_console_kill_line_from_beginning(); - break; - case CONTROL('W'): - gs_console_backward_kill_word(); - break; - case CONTROL('Z'): - // We cannot suspend - break; - case CONTROL('H'): - case 0x7f: - gs_console_backspace(); - break; - case '\r': - case '\n': - gs_console_execute(); - break; - case '\t': - gs_console_complete(); - break; - case '\033': - escape = CONSOLE_ESCAPE; - break; - default: - if (escape == CONSOLE_ESCAPE) { - if ((c == '[') || (c == 'O')) { - c = getchar(); - if (c == 'F') - gs_console_end_of_line(); - if (c == 'H') - gs_console_beginning_of_line(); -#if (GS_CONSOLE_HISTORY_LEN > 0) - if (c == 'A') - gs_console_last_line(); - if (c == 'B') - gs_console_next_line(); -#endif - if (c == 'C') - gs_console_forward_char(); - if (c == 'D') - gs_console_backward_char(); - if (c == '1') - if (getchar() == '~') - gs_console_beginning_of_line(); - if (c == '3') - if (getchar() == '~') - gs_console_delete(); - } - escape = CONSOLE_NORMAL; - break; - } - - if (isprint((unsigned char) c)) { - gs_console_insert(c); - } - - break; - } -} - -static gs_error_t command_io_cci_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value) -{ - gs_mutex_lock(g_cci_lock); - { - printf(CCI_START_TAG "cmd_res,%s,%s,%s" CCI_END_TAG, group, key, value); - } - gs_mutex_unlock(g_cci_lock); - return GS_OK; -} - -static void gs_console_cci_log(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) -{ - va_list my_va; - va_copy(my_va, va); - - gs_mutex_lock(g_cci_lock); - { - printf(CCI_START_TAG "log,%04"PRIu32".%06"PRIu32",%c,%s,", ts->tv_sec, ts->tv_nsec / 1000, gs_log_level_to_char(level), group->name); - vprintf(format, my_va); - printf(CCI_END_TAG "\r\n"); - } - gs_mutex_unlock(g_cci_lock); - - va_end(my_va); -} - -static void gs_console_cci(char c) -{ - switch (c) { - case CONTROL('C'): - case CONTROL('L'): - size = 0; - buf[0] = 0; - break; - case '\r': - case '\n': - buf[GS_CONSOLE_INPUT_LEN] = 0; // ensure 0 termination - if (size > 0 && gs_command_not_empty(buf)) { - static unsigned int seq; // simple sequence number keep incrementing - - gs_mutex_lock(g_cci_lock); - ++seq; - printf(CCI_START_TAG "cmd_exec_begin,%u,%s" CCI_END_TAG "\r\n", seq, buf); - gs_mutex_unlock(g_cci_lock); - - gs_error_t result = GS_OK; - gs_error_t error = gs_command_execute(buf, &result, stdout, &cci_io_functions, NULL); - - gs_mutex_lock(g_cci_lock); - printf(CCI_START_TAG "cmd_exec_end,%u,%d,%d" CCI_END_TAG "\r\n", seq, error, result); - gs_mutex_unlock(g_cci_lock); - } - size = 0; - buf[0] = 0; - break; - default: - if (isprint((unsigned char) c) && (size < GS_CONSOLE_INPUT_LEN)) { - buf[size++] = c; - buf[size] = 0; - } - break; - } -} - -// Currrent mode handler, switch by sending command -static void (*console_handler)(char c) = gs_console_normal; - -int gs_console_change_mode(const char * mode) -{ - if (strcasecmp(mode, "cci") == 0) { - gs_error_t error = GS_OK; - if (console_handler != gs_console_cci) { - error = gs_mutex_create(&g_cci_lock); - if (error == GS_OK) { - gs_log_appender_console_set_cb(gs_console_cci_log); - console_handler = gs_console_cci; // change console handler - } - } - return error; - } - return GS_ERROR_NOT_SUPPORTED; -} - -static void * gs_console_thread(void * param) -{ - gs_console_reset(); - while (1) { - char c = getchar(); - console_handler(c); - } - - gs_thread_exit(NULL); -} - -gs_error_t gs_console_exit(void) -{ -#if (__linux__) - if (termios_changed) { - tcsetattr(STDIN_FILENO, TCSANOW, &old_stdin); - tcsetattr(STDOUT_FILENO, TCSANOW, &old_stdout); - } -#endif - return GS_OK; -} - -#if (__linux__) -static inline void exithandler(void) -{ - printf("\n"); - gs_console_exit(); -} -#endif - -static gs_error_t gs_console_init2(uint32_t flags) -{ -#if (__linux__) - // save current stdio setting, for restoring when terminating process - tcgetattr(STDIN_FILENO, &old_stdin); - tcgetattr(STDOUT_FILENO, &old_stdout); - - // change stdin settings - { - struct termios new = old_stdin; - new.c_iflag &= ~(IGNCR | ICRNL); - new.c_lflag &= ~(ECHO | ICANON | IEXTEN); - new.c_cc[VTIME]=0; - new.c_cc[VMIN]=1; - tcsetattr(STDIN_FILENO, TCSANOW, &new); - } - // change stdout settings - { - struct termios new = old_stdout; - new.c_iflag &= ~(IGNCR | ICRNL); - new.c_lflag &= ~(ECHO | ICANON | IEXTEN); - new.c_cc[VTIME]=0; - new.c_cc[VMIN]=1; - tcsetattr(STDOUT_FILENO, TCSANOW, &new); - } - - termios_changed = true; - - // add exit-handler to restore original termianl settings - atexit(exithandler); - - // install signal handlers to ensure terminal settings are restored - if ((flags & GS_CONSOLE_F_NO_SIGNAL_HANDLER) == 0) { - // install signal handler(s) to ensure atexit() is called - gs_signal_catch(SIGTERM, NULL); - - if (gs_command_line_ignore_ctrlc() == false) { - gs_signal_catch(SIGINT, NULL); - } - } -#endif - -#if (__AVR__ == 0) - /** This is very important on AVR32 */ - setvbuf(stdin, NULL, _IONBF, 0); - setvbuf(stdout, NULL, _IONBF, 0); - setvbuf(stderr, NULL, _IONBF, 0); -#endif - return GS_OK; -} - -gs_error_t gs_console_init() -{ - return gs_console_init2(0); -} - -static gs_error_t _console_create_thread(gs_thread_priority_t priority, gs_thread_t * handle, uint32_t thread_create_flags) -{ - gs_error_t error = gs_thread_create("CONSOLE", - gs_console_thread, NULL, - gs_command_get_stack_size(), - priority, - thread_create_flags, - handle); - if (error == GS_OK) { - // give thread a few moments to print prompt - gs_time_sleep_ms(20); - } - return error; -} - -gs_error_t gs_console_create_thread(gs_thread_t * handle) -{ - return _console_create_thread(GS_THREAD_PRIORITY_LOW, handle, 0); -} - -gs_error_t gs_console_create_thread_with_priority(gs_thread_priority_t priority, gs_thread_t * handle) -{ - return _console_create_thread(priority, handle, 0); -} - -gs_error_t gs_console_start(const char * prompt, uint32_t flags) -{ - if (console_thread) { - return GS_ERROR_EXIST; - } - - gs_console_init2(flags); - gs_console_set_prompt(prompt); - - return _console_create_thread(GS_THREAD_PRIORITY_LOW, &console_thread, GS_THREAD_CREATE_JOINABLE); -} - -gs_error_t gs_console_stop(void) -{ - if (console_thread == 0) { - return GS_ERROR_HANDLE; - } -#if (__linux__) - if (pthread_cancel(console_thread) != 0) { - return GS_ERROR_IO; - } - gs_error_t error = gs_thread_join(console_thread, NULL); - if (error == GS_OK) { - console_thread = 0; - } - return error; -#else - return GS_ERROR_NOT_SUPPORTED; -#endif -} diff --git a/gomspace/libutil/src/gosh/console_local.h b/gomspace/libutil/src/gosh/console_local.h deleted file mode 100644 index 1332e732..00000000 --- a/gomspace/libutil/src/gosh/console_local.h +++ /dev/null @@ -1,10 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -/** - Change console mode. - @param[in] mode console mode, 'rgosh', 'normal' - @return_gs_error_t -*/ -int gs_console_change_mode(const char * mode); diff --git a/gomspace/libutil/src/gosh/default_commands.c b/gomspace/libutil/src/gosh/default_commands.c deleted file mode 100644 index fb535318..00000000 --- a/gomspace/libutil/src/gosh/default_commands.c +++ /dev/null @@ -1,277 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include "command_local.h" -#include "console_local.h" - -#include - -#if defined(__linux__) -#include -#include -#endif - -#include -#include -#include -#include -#include - -static int cmd_help(gs_command_context_t * context) -{ - return gs_command_show_help(gs_command_args(context), context->out); -} - -static int cmd_sleep(gs_command_context_t * context) -{ - uint32_t sleep_ms; - gs_error_t error = gs_string_to_uint32(context->argv[1], &sleep_ms); - if (error) { - return error; - } - - gs_time_sleep_ms(sleep_ms); - - return GS_OK; -} - -static int cmd_watch(gs_command_context_t * context, bool check_error) -{ - uint32_t sleep_ms; - gs_error_t error = gs_string_to_uint32(context->argv[1], &sleep_ms); - if (error) { - return error; - } - - fprintf(context->out, "Execution delay: %" PRIu32 "\r\n", sleep_ms); - - char * new_command = strstr(gs_command_args(context), " "); - if (new_command == NULL) { - return GS_ERROR_ARG; - } else { - new_command = new_command + 1; - } - - fprintf(context->out, "Command: %s\r\n", new_command); - - while(1) { - - gs_error_t cmd_result; - error = gs_command_execute(new_command, &cmd_result, context->out, context->io_functions, context->io_ctx); - if (error) { - return error; - } - if (check_error && cmd_result) { - return cmd_result; - } - - if (gs_stdio_getchar_timed(sleep_ms, NULL) != GS_ERROR_TIMEOUT) { - break; - } - } - - return GS_OK; -} - -static int cmd_watch_nocheck(gs_command_context_t * context) -{ - return cmd_watch(context, false); -} - -static int cmd_watch_check(gs_command_context_t * context) -{ - return cmd_watch(context, true); -} - -#define CONTROL(X) ((X) - '@') - -static int cmd_batch(gs_command_context_t * ctx) -{ - char c; - int quit = 0, execute = 0; - unsigned int batch_size = 100; - unsigned int batch_input = 0; - unsigned int batch_count = 0; - char * batch[20] = {}; - printf("Type each command followed by enter, hit ctrl+e to end typing, ctrl+x to cancel:\r\n"); - - /* Wait for ^q to quit. */ - while (quit == 0) { - - /* Get character */ - c = getchar(); - - switch (c) { - - /* CTRL + X */ - case 0x18: - quit = 1; - break; - - /* CTRL + E */ - case 0x05: - execute = 1; - quit = 1; - break; - - /* Backspace */ - case CONTROL('H'): - case 0x7f: - if (batch_input > 0) { - putchar('\b'); - putchar(' '); - putchar('\b'); - batch_input--; - } - break; - - case '\r': - putchar('\r'); - putchar('\n'); - if ((batch[batch_count] != NULL) && (batch_input < batch_size)) - batch[batch_count][batch_input++] = '\r'; - if ((batch[batch_count] != NULL) && (batch_input < batch_size)) - batch[batch_count][batch_input++] = '\0'; - batch_count++; - batch_input = 0; - if (batch_count == 20) - quit = 1; - break; - - default: - putchar(c); - if (batch[batch_count] == NULL) { - batch[batch_count] = calloc(GS_CONSOLE_INPUT_LEN+1, 1); - } - - if ((batch[batch_count] != NULL) && (batch_input < batch_size)) - batch[batch_count][batch_input++] = c; - break; - } - } - - if (execute) { - printf("\r\n"); - for (unsigned int i = 0; i <= batch_count; i++) { - if (batch[i]) - printf("[%02u] %s\r\n", i, batch[i]); - } - printf("Press ctrl+e to execute, or any key to abort\r\n"); - c = getchar(); - if (c != 0x05) - execute = 0; - } - - /* Run/Free batch job */ - for (unsigned int i = 0; i <= batch_count; i++) { - if (execute && batch[i]) { - printf("EXEC [%02u] %s\r\n", i, batch[i]); - gs_command_run(batch[i], NULL); - } - free(batch[i]); - } - - return GS_OK; -} - -#if defined(__linux__) -static int cmd_exit(gs_command_context_t * context) -{ - gs_console_exit(); - exit(EXIT_SUCCESS); - return GS_OK; -} -#endif - -static int cmd_clock(gs_command_context_t * ctx) -{ - if (ctx->argc > 1) { - gs_timestamp_t ts; - gs_error_t error = gs_clock_from_string(ctx->argv[1], &ts); - if (error) { - return GS_ERROR_ARG; - } - error = gs_clock_set_time(&ts); - if (error) { - fprintf(ctx->out, "Failed to set time, error=%s\r\n", gs_error_string(error)); - return GS_ERROR_DATA; - } - } - - timestamp_t clock; - gs_clock_get_monotonic(&clock); - fprintf(ctx->out, "monotonic: %10"PRIu32".%09"PRIu32" sec\r\n", clock.tv_sec, clock.tv_nsec); - gs_command_set_output_printf(ctx, "", "monotonic", "%10"PRIu32".%09"PRIu32"", clock.tv_sec, clock.tv_nsec); - - char tbuf[25]; - gs_clock_get_time(&clock); - gs_clock_to_iso8601_string(&clock, tbuf, sizeof(tbuf)); - fprintf(ctx->out, "realtime: %10"PRIu32".%09"PRIu32" sec -> %s\r\n", clock.tv_sec, clock.tv_nsec, tbuf); - gs_command_set_output_printf(ctx, "", "realtime", "%10"PRIu32".%09"PRIu32"", clock.tv_sec, clock.tv_nsec); - - return GS_OK; -} - -static int cmd_console_mode(gs_command_context_t * ctx) -{ - return gs_console_change_mode(ctx->argv[1]); -} - -static const gs_command_t GS_COMMAND_ROOT cmd_default[] = { - { - .name = "help", - .help = "Show help", - .usage = "[command[ subcommand[ arg ...]]]", - .handler = cmd_help, - .optional_args = 100, - },{ - .name = "sleep", - .help = "Sleep X ms", - .usage = "", - .handler = cmd_sleep, - .mandatory_args = 1, - },{ - .name = "watch", - .help = "Run commands at intervals (abort with key)", - .usage = " [arg ...]", - .handler = cmd_watch_nocheck, - .mandatory_args = 2, - .optional_args = 100, - },{ - .name = "watch_check", - .help = "Like 'watch', but abort if command fails", - .usage = " ", - .handler = cmd_watch_check, - .mandatory_args = 2, - .optional_args = 100, - },{ - .name = "batch", - .help = "Run multiple commands", - .handler = cmd_batch, - .mode = GS_COMMAND_FLAG_HIDDEN, - },{ - .name = "clock", - .help = "Get/set system clock", - .usage = "[ | ]", - .handler = cmd_clock, - .optional_args = 1, - },{ - .name = "console_mode", - .help = "Console mode(s): cci", - .usage = "", - .handler = cmd_console_mode, - .mode = GS_COMMAND_FLAG_HIDDEN, - .mandatory_args = 1, - }, -#if defined(__linux__) - { - .name = "exit", - .help = "Exit program", - .handler = cmd_exit, - }, -#endif -}; - -gs_error_t gs_command_register_default_commands(void) -{ - return GS_COMMAND_REGISTER(cmd_default); -} diff --git a/gomspace/libutil/src/gosh/getopt.c b/gomspace/libutil/src/gosh/getopt.c deleted file mode 100644 index 81055bef..00000000 --- a/gomspace/libutil/src/gosh/getopt.c +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include - -#include -#include -#include - -int gs_command_getopt(gs_command_context_t *ctx, const char *opts) -{ - int c; - char *cp; - - if (ctx->optsp == 1) { - if (ctx->optind >= ctx->argc || - ctx->argv[ctx->optind][0] != '-' || - ctx->argv[ctx->optind][1] == '\0') { - return EOF; - } else if (!strcmp(ctx->argv[ctx->optind], "--")) { - ctx->optind++; - return EOF; - } - } - - ctx->optopt = c = ctx->argv[ctx->optind][ctx->optsp]; - if (c == ':' || (cp = strchr(opts, c)) == NULL) { - printf("illegal option -- %c\r\n", c); - if (ctx->argv[ctx->optind][++ctx->optsp] == '\0') { - ctx->optind++; - ctx->optsp = 1; - } - return '?'; - } - - if (*++cp == ':') { - if (ctx->argv[ctx->optind][ctx->optsp+1] != '\0') { - ctx->optarg = &ctx->argv[ctx->optind++][ctx->optsp+1]; - } else if(++ctx->optind >= ctx->argc) { - printf("option requires an argument -- %c\r\n", c); - ctx->optsp = 1; - return '?'; - } else { - ctx->optarg = ctx->argv[ctx->optind++]; - } - ctx->optsp = 1; - } else { - if (ctx->argv[ctx->optind][++ctx->optsp] == '\0') { - ctx->optsp = 1; - ctx->optind++; - } - ctx->optarg = NULL; - } - - return c; -} diff --git a/gomspace/libutil/src/hexdump.c b/gomspace/libutil/src/hexdump.c deleted file mode 100644 index 7330ef91..00000000 --- a/gomspace/libutil/src/hexdump.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include - -static void print_disp_addr02(FILE * out, uintptr_t disp_addr) -{ - fprintf(out, "0x%02"PRIx32" : ", (uint32_t) disp_addr); -} -static void print_disp_addr04(FILE * out, uintptr_t disp_addr) -{ - fprintf(out, "0x%04"PRIx32" : ", (uint32_t) disp_addr); -} -static void print_disp_addrxx(FILE * out, uintptr_t disp_addr) -{ -#if defined(PRIx64) - fprintf(out, "0x%08"PRIx64" : ", (uint64_t) disp_addr); -#else - fprintf(out, "0x%08"PRIx32" : ", (uint32_t) disp_addr); -#endif -} - -void gs_hexdump_to_stream(const void * in_src, size_t len, const void * in_disp_addr, FILE* out) -{ - volatile const uint8_t * src = in_src; - uintptr_t disp_addr = GS_TYPES_PTR2UINT(in_disp_addr); - const uintptr_t end_disp_addr = disp_addr + len; - - // work-rounds for not printing NIL (if address 0), align addresses, not supporting %zx, %*x or %08p on all platforms - void (*print_addr)(FILE * out, uintptr_t disp_addr); - if (end_disp_addr <= 0xff) { - print_addr = print_disp_addr02; - } else if (end_disp_addr <= 0xffff) { - print_addr = print_disp_addr04; - } else { - print_addr = print_disp_addrxx; - } - - print_addr(out, disp_addr); - - size_t i = 0; - size_t j = 0; - size_t k = 0; - char text[17]; - for(; i < len; ++i) { - const uint8_t ch = *src++; - ++disp_addr; - - // hex - fprintf(out, "%02x ", ch); - ++j; - if (j == 8) { - fprintf(out, " "); - } - - // printable - if ((ch < 32) || (ch > 126)) { - text[k] = '.'; - } else { - text[k] = (char) ch; - } - ++k; - text[k] = 0; - - // newline? - if(j >= 16) { - fprintf(out, "|%-16.16s|\r\n", text); - j = 0; - k = 0; - text[k] = 0; - - if (i < (len - 1)) { - print_addr(out, disp_addr); - } - } - } - if ((i == 0) || (i % 16)) { - if (j) { - // something was printed - show textual - for (; j < 16; j++) { - if (j == 7) { - fprintf(out, " "); - } - fprintf(out, " "); - } - fprintf(out, "|%-16.16s|", text); - } - fprintf(out, "\r\n"); - } -} diff --git a/gomspace/libutil/src/linux/argp.c b/gomspace/libutil/src/linux/argp.c deleted file mode 100644 index e9156595..00000000 --- a/gomspace/libutil/src/linux/argp.c +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -void gs_argp_parse(const struct argp * argp, - int argc, char ** argv, - unsigned int flags, int * return_arg_index, - const char * revision) -{ - if (gs_string_empty(revision) == false) { - argp_program_version = revision; - } - - int arg_index = 0; - int res = argp_parse(argp, argc, argv, 0, &arg_index, 0); - if (res) { - printf("Failed to parse argument/option (result: %d)\n", res); - exit(GS_EXITCODE_USAGE); - } - - if ((return_arg_index == NULL) && (arg_index < argc)) { - // application doesn't expect unhandled arguments - for (int i = arg_index; i < argc; ++i) { - printf("Unhandled/unknown argument: [%s]\n", argv[i]); - } - exit(GS_EXITCODE_USAGE); - } - - if (return_arg_index) { - *return_arg_index = arg_index; - } -} diff --git a/gomspace/libutil/src/linux/clock.c b/gomspace/libutil/src/linux/clock.c deleted file mode 100644 index 191aac25..00000000 --- a/gomspace/libutil/src/linux/clock.c +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include - -void gs_clock_get_time(gs_timestamp_t * time) -{ - struct timespec now; - clock_gettime(CLOCK_REALTIME, &now); - - time->tv_sec = (uint32_t) now.tv_sec; - time->tv_nsec = (uint32_t) now.tv_nsec; -} - -gs_error_t gs_clock_set_time(const gs_timestamp_t * time) -{ - struct timespec now; - now.tv_sec = time->tv_sec; - now.tv_nsec = time->tv_nsec; - - int res = clock_settime(CLOCK_REALTIME, &now); - if (res != 0) { - return gs_error(errno); - } - - gs_error_t error = GS_OK; - if (gs_rtc_supported() == GS_OK) { - error = gs_rtc_set_time(time); - } - - return error; -} - -void gs_clock_get_monotonic(gs_timestamp_t * time) -{ - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - - time->tv_sec = (uint32_t) now.tv_sec; - time->tv_nsec = (uint32_t) now.tv_nsec; -} - -uint64_t gs_clock_get_nsec(void) -{ - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - - return (((uint64_t)now.tv_sec) * GS_TIMESTAMP_NSEC_PER_SEC) + ((uint64_t)now.tv_nsec); -} - -/** - Required by libcsp. - Proto-typed in ./libcsp/include/csp/arch/csp_clock.h, but with different argumet! - - __attribute__((weak)) extern void clock_get_time(csp_timestamp_t * time); - __attribute__((weak)) extern void clock_set_time(csp_timestamp_t * time); -*/ -void clock_get_time(gs_timestamp_t * time) -{ - gs_clock_get_time(time); -} - -void clock_set_time(const gs_timestamp_t * time) -{ - gs_clock_set_time(time); -} diff --git a/gomspace/libutil/src/linux/command_line.c b/gomspace/libutil/src/linux/command_line.c deleted file mode 100644 index e95cd602..00000000 --- a/gomspace/libutil/src/linux/command_line.c +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -#define KEY_IGNORE_CTRLC 200 - -static bool ignore_ctrlc; - -static int parser(int key, char *arg, struct argp_state *state) -{ - switch (key) { - case KEY_IGNORE_CTRLC: - ignore_ctrlc = true; - gs_signal_ignore(SIGINT); - break; - - case 'h': - argp_help(state->root_argp, state->out_stream, ARGP_HELP_STD_HELP, state->name); - exit(0); - break; - - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - -static const struct argp_option options[] = { - { - .name = "ignore-ctrlc", - .key = KEY_IGNORE_CTRLC, - .doc = "Ignore/disable CTRL-C" - }, - {0} -}; - -static const struct argp argp_console = {.options = options, .parser = parser}; - -const struct argp_child gs_console_command_line_ignore_ctrlc_argp = {.argp = &argp_console}; - -bool gs_command_line_ignore_ctrlc(void) -{ - return ignore_ctrlc; -} - -static const struct argp_option help_options[] = { - { - .name = "help", - .key = 'h', - .doc = "Give this help list" - }, - {0} -}; - -static const struct argp gs_argp_help = {.options = help_options, .parser = parser}; - -const struct argp_child gs_help_command_line_argp = {.argp = &gs_argp_help}; - -const char * gs_command_line_program_name(const char * argv) -{ - if (gs_string_empty(argv) == false) { - const char * name = strrchr(argv, '/'); - if (name) { - // skip slash - ++name; - if (gs_string_empty(name) == false) { - return name; - } - } else { - return argv; - } - } - return ""; -} diff --git a/gomspace/libutil/src/linux/cwd.c b/gomspace/libutil/src/linux/cwd.c deleted file mode 100644 index 1cfe373d..00000000 --- a/gomspace/libutil/src/linux/cwd.c +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -gs_error_t gs_getcwd(char * buf, size_t bufsize) -{ - if (buf && bufsize) { - char * wd = getcwd(buf, bufsize); - if (wd) { - return GS_OK; - } - switch(errno) { - case ENAMETOOLONG: - case ERANGE: - return GS_ERROR_RANGE; - - case EACCES: - case ENOENT: - return GS_ERROR_NOT_FOUND; - - default: - break; - } - } - return GS_ERROR_ARG; -} diff --git a/gomspace/libutil/src/linux/delay.c b/gomspace/libutil/src/linux/delay.c deleted file mode 100644 index f0a39081..00000000 --- a/gomspace/libutil/src/linux/delay.c +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -void gs_delay_us(uint32_t time_us) -{ - uint64_t ns = time_us; - ns *= 1000LL; - gs_time_sleep_ns(ns); -} - -uint16_t gs_delay_ts_get(void) -{ - return 0; -} - -void gs_delay_from_ts(uint16_t ts, uint16_t delay) -{ - -} diff --git a/gomspace/libutil/src/linux/drivers/can/can.c b/gomspace/libutil/src/linux/drivers/can/can.c deleted file mode 100644 index 40a6b8c8..00000000 --- a/gomspace/libutil/src/linux/drivers/can/can.c +++ /dev/null @@ -1,308 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -typedef struct { - // true if handle is in use - bool inuse; - - // opened socket - int can_socket; - - // receiver thread - gs_thread_t rxthread; - - // received data callback - gs_can_rxdata_callback_t rx_callback; - void * user_data; - -} gs_can_handle_t; - -#define MAX_CAN_HANDLES 10 -static gs_can_handle_t can_handles[MAX_CAN_HANDLES]; - -static int gs_can_alloc_handle(void) -{ - int handle_id; - for (handle_id = 0; (handle_id < MAX_CAN_HANDLES) && (can_handles[handle_id].inuse == true); ++handle_id); - - if (handle_id < MAX_CAN_HANDLES) { - gs_can_handle_t * handle = &can_handles[handle_id]; - memset(handle, 0, sizeof(*handle)); - handle->inuse = true; - handle->can_socket = -1; - } - - return handle_id; -} - -static inline gs_can_handle_t * gs_can_handle(uint8_t hdl) -{ - if (hdl >= MAX_CAN_HANDLES) { - return NULL; - } - if (can_handles[hdl].inuse == false) { - return NULL; - } - return &can_handles[hdl]; -} - -static void * gs_can_rx_thread(void * parameter) -{ - int hdl = (int) GS_TYPES_PTR2INT(parameter); - - log_debug("%s: running, hdl: %d", __FUNCTION__, hdl); - - gs_can_handle_t * handle = gs_can_handle(hdl); - if (handle == NULL) { - log_error("%s: CAN handle: %d is invalid or not opened", __FUNCTION__, hdl); - gs_thread_exit(NULL); - } - - while (1) { - /* Read CAN frame */ - struct can_frame frame; - ssize_t nbytes = read(handle->can_socket, &frame, sizeof(frame)); - if (nbytes < 0) { - log_error("%s: read() on socket failed, error: %s", __FUNCTION__, strerror(errno)); - continue; - } - - if (nbytes != sizeof(frame)) { - log_warning("%s: read() returned incomplete CAN frame of %d bytes - ignoring frame", __FUNCTION__, (int) nbytes); - continue; - } - - /* Frame type */ - if (frame.can_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) { - /* Drop error and remote frames */ - log_warning("%s: discarding ERR/RTR frame, can_id: 0x%x", __FUNCTION__, frame.can_id); - continue; - } - - const bool extId = (frame.can_id & CAN_EFF_FLAG) ? true : false; - if (extId) { - frame.can_id &= CAN_EFF_MASK; - } else { - frame.can_id &= CAN_SFF_MASK; - } - handle->rx_callback(hdl, frame.can_id, extId, frame.data, frame.can_dlc, gs_time_rel_ms(), handle->user_data, false); - } - - /* We should never reach this point */ - return NULL; -} - -static gs_error_t gs_can_send(uint8_t hdl, uint32_t canMsgId, bool extended, const void * data, size_t data_size, int timeout_ms) -{ - gs_can_handle_t * handle = gs_can_handle(hdl); - if (handle == NULL) { - return GS_ERROR_HANDLE; - } - - if ((data == NULL) || (data_size > 8)) { - log_error("%s: invalid data: %p, data_size: %u", __FUNCTION__, (void*) data, (unsigned int) data_size); - return GS_ERROR_ARG; - } - - struct can_frame frame; - memset(&frame, 0, sizeof(frame)); - frame.can_id = canMsgId; - if (extended) { - frame.can_id |= CAN_EFF_FLAG; - } - - memcpy(frame.data, data, data_size); - - frame.can_dlc = (uint8_t) data_size; - - const int DELAY_MS = 10; - while (write(handle->can_socket, &frame, sizeof(frame)) != sizeof(frame)) { - if ((timeout_ms > 0) && (errno == ENOBUFS)) { - // Wait a bit and try again - gs_thread_sleep_ms(DELAY_MS); - timeout_ms -= DELAY_MS; - } else { - gs_error_t gserror = gs_error(errno); - log_error("%s: write() failed, error: %s", __FUNCTION__, gs_error_string(gserror)); - return gserror; - } - } - - return GS_OK; -} - -gs_error_t gs_can_send_standard(uint8_t hdl, uint32_t canMsgId, const void * data, size_t data_size, int timeout_ms) -{ - return gs_can_send(hdl, canMsgId, false, data, data_size, timeout_ms); -} - -gs_error_t gs_can_send_extended(uint8_t hdl, uint32_t canExtMsgId, const void * data, size_t data_size, int timeout_ms) -{ - return gs_can_send(hdl, canExtMsgId, true, data, data_size, timeout_ms); -} - -static void gs_can_close(gs_can_handle_t * handle) -{ - if (handle->can_socket >= 0) { - close(handle->can_socket); - } - - // free instance - must be the last thing done, no lock needed - handle->inuse = false; -} - -gs_error_t gs_can_open(const char * ifname, int * return_handle) -{ - if ((ifname == NULL) || (ifname[0] == 0) || (return_handle == NULL)) { - log_error("%s: invalid CAN interface name", __FUNCTION__); - return GS_ERROR_ARG; - } - - int handle_id = gs_can_alloc_handle(); - if (handle_id >= MAX_CAN_HANDLES) { - log_error("%s: no free handles", __FUNCTION__); - return GS_ERROR_FULL; - } - gs_can_handle_t * handle = &can_handles[handle_id]; - - /* Create socket */ - if ((handle->can_socket = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { - gs_error_t gserror = gs_error(errno); - log_error("%s: socket() failed, error: %s", __FUNCTION__, gs_error_string(gserror)); - gs_can_close(handle); - return gserror; - } - - /* Locate interface */ - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1); - if (ioctl(handle->can_socket, SIOCGIFINDEX, &ifr) < 0) { - gs_error_t gserror = gs_error(errno); - log_error("%s: ioctl(ifname: [%s]) failed, error: %s", __FUNCTION__, ifr.ifr_name, gs_error_string(gserror)); - gs_can_close(handle); - return gserror; - } - - /* Bind the socket to CAN interface */ - struct sockaddr_can addr; - memset(&addr, 0, sizeof(addr)); - addr.can_family = AF_CAN; - addr.can_ifindex = ifr.ifr_ifindex; - if (bind(handle->can_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - gs_error_t gserror = gs_error(errno); - log_error("%s: bind() failed, error: %s", __FUNCTION__, gs_error_string(gserror)); - gs_can_close(handle); - return gserror; - } - - *return_handle = handle_id; - - return GS_OK; -} - -static gs_error_t gs_can_set_filter_mask(uint8_t hdl, bool extended, uint32_t canMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * user_data) -{ - gs_can_handle_t * handle = gs_can_handle(hdl); - if (handle == NULL) { - return GS_ERROR_HANDLE; - } - - if (extended) { - if ((canMsgId > CAN_EFF_MASK) || (mask > CAN_EFF_MASK)) { - return GS_ERROR_ARG; - } - } else { - if ((canMsgId > CAN_SFF_MASK) || (mask > CAN_SFF_MASK)) { - return GS_ERROR_ARG; - } - } - - handle->rx_callback = rx_callback; - handle->user_data = user_data; - - struct can_filter filter; - filter.can_id = canMsgId; - filter.can_mask = mask; - if (extended == false) { - filter.can_mask |= (CAN_EFF_MASK & ~CAN_SFF_MASK); - } - - if (setsockopt(handle->can_socket, SOL_CAN_RAW, CAN_RAW_FILTER, &filter, sizeof(filter)) < 0) { - gs_error_t gserror = gs_error(errno); - log_error("%s: setsockopt(id: 0x%x, mask: 0x%x) failed, error: %s", __FUNCTION__, canMsgId, mask, gs_error_string(gserror)); - return gserror; - } - - return GS_OK; -} - -gs_error_t gs_can_set_standard_filter_mask(uint8_t hdl, uint32_t canMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * user_data) -{ - return gs_can_set_filter_mask(hdl, false, canMsgId, mask, rx_callback, user_data); -} - -gs_error_t gs_can_set_extended_filter_mask(uint8_t hdl, uint32_t canExtMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * user_data) -{ - return gs_can_set_filter_mask(hdl, true, canExtMsgId, mask, rx_callback, user_data); -} - -gs_error_t gs_can_start(uint8_t hdl) -{ - gs_can_handle_t * handle = gs_can_handle(hdl); - if (handle == NULL) { - return GS_ERROR_HANDLE; - } - - if (handle->rxthread) { - return GS_OK; - } - - /* Create receiver thread */ - gs_error_t gserror = gs_thread_create("rxcan", gs_can_rx_thread, GS_TYPES_INT2PTR(hdl), 0, GS_THREAD_PRIORITY_HIGH, 0, &handle->rxthread); - if (gserror) { - log_error("s: gs_thread_create() failed, error: %s", gs_error_string(gserror)); - return gserror; - } - - return GS_OK; -} - -gs_error_t gs_can_stop(uint8_t hdl) -{ - gs_can_handle_t * handle = gs_can_handle(hdl); - if (handle == NULL) { - return GS_ERROR_HANDLE; - } - - return GS_ERROR_NOT_IMPLEMENTED; -} - -gs_error_t gs_can_error_state(uint8_t hdl, bool * restart_required) -{ - gs_can_handle_t * handle = gs_can_handle(hdl); - if (handle == NULL) { - return GS_ERROR_HANDLE; - } - - if (restart_required) { - *restart_required = false; - } - - // missing error state check on CAN layer - - return GS_OK; -} diff --git a/gomspace/libutil/src/linux/drivers/gpio/gpio.c b/gomspace/libutil/src/linux/drivers/gpio/gpio.c deleted file mode 100644 index 484c6a58..00000000 --- a/gomspace/libutil/src/linux/drivers/gpio/gpio.c +++ /dev/null @@ -1,102 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -#define MAX_DRIVERS 20 - -typedef struct { - gs_gpio_driver_entry_t entry; - bool in_use; -} gs_gpio_driver_handle_t; - -static gs_gpio_driver_handle_t gpio_drivers[MAX_DRIVERS]; -static uint8_t max_index_in_use = 0; - - -static inline gs_gpio_driver_entry_t * gs_find_driver_entry(gs_gpio_t * gpio) -{ - gs_gpio_driver_handle_t * handle; - for (int i = max_index_in_use; i >= 0; i--) { - handle = &gpio_drivers[i]; - if (((gpio->pin == handle->entry.pin) || (handle->entry.pin == GS_GPIO_ALL_PINS)) && - ((gpio->port == handle->entry.port) || (handle->entry.port == GS_GPIO_ALL_PORTS)) && - (handle->in_use == true)) { - return &handle->entry; - } - } - return NULL; -} - -gs_error_t gs_gpio_get(gs_gpio_t gpio, bool *value) -{ - gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); - if (driver_entry) { - if (driver_entry->driver->get_handler) { - return driver_entry->driver->get_handler(gpio, value, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -bool gs_gpio_get_nc(gs_gpio_t gpio) -{ - gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); - if (driver_entry) { - if (driver_entry->driver->get_nc_handler) { - return driver_entry->driver->get_nc_handler(gpio, driver_entry->driver_data); - } - } - return false; -} - -gs_error_t gs_gpio_set(gs_gpio_t gpio, bool value) -{ - gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); - if (driver_entry) { - if (driver_entry->driver->set_handler) { - return driver_entry->driver->set_handler(gpio, value, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -void gs_gpio_set_nc(gs_gpio_t gpio, bool value) -{ - gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); - if (driver_entry) { - if (driver_entry->driver->set_nc_handler) { - driver_entry->driver->set_nc_handler(gpio, value, driver_entry->driver_data); - } - } -} - -gs_error_t gs_gpio_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf) -{ - gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); - if (driver_entry) { - if (driver_entry->driver->init_as_interrupt_handler) { - return driver_entry->driver->init_as_interrupt_handler(gpio, conf, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_gpio_register_driver(const gs_gpio_driver_entry_t * driver_entry) -{ - GS_CHECK_ARG(driver_entry != NULL); - GS_CHECK_ARG(driver_entry->driver != NULL); - - gs_gpio_driver_handle_t * handle; - for (uint8_t i = 0; i < MAX_DRIVERS; i++) { - handle = &gpio_drivers[i]; - if (handle->in_use == false) { - handle->entry = *driver_entry; - handle->in_use = true; - max_index_in_use = i; - return GS_OK; - } - } - /* Not enough space in buffer */ - return GS_ERROR_FULL; -} diff --git a/gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c b/gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c deleted file mode 100644 index 57efd042..00000000 --- a/gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c +++ /dev/null @@ -1,145 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - @brief GPIO Implementation for Linux of the GPIO API in libutil. - - The GPIO driver provides a simple interface toward driving HW GPIO's. -*/ - -#include - -#include -#include -#include -#include - -#include - -#include - -gs_error_t gs_gpio_sysfs_initialize(gs_gpio_t gpio, bool output,bool init_value, bool active_low) -{ - char gpio_pin_str[6]; - snprintf(gpio_pin_str, sizeof(gpio_pin_str), "%d", gpio.pin); - - /* Try to unexport first */ - gs_sysfs_write_file("/sys/class/gpio/unexport", gpio_pin_str); - - if (gs_sysfs_write_file("/sys/class/gpio/export", gpio_pin_str) != GS_OK) - { - log_warning("failed to export GPIO %s: %s", gpio_pin_str, strerror(errno)); - return GS_ERROR_NOT_SUPPORTED; - } - - char gpio_sys_fname[128]; - snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/active_low", gpio.pin); - const char * active_low_str = active_low ? "1" : "0"; - - if (gs_sysfs_write_file(gpio_sys_fname, active_low_str) != GS_OK) - { - log_warning("failed to set GPIO %d active_low: %s", gpio.pin, strerror(errno)); - return GS_ERROR_NOT_SUPPORTED; - } - - snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/direction", gpio.pin); - - /* Glitch-free output set (high/low makes pin an output and sets value to 1/0 respectively)*/ - const char * dir = output ? (init_value ? "high" : "low") : "in"; - - if (gs_sysfs_write_file(gpio_sys_fname, dir) != GS_OK) - { - log_warning("failed to set GPIO %d direction: %s", gpio.pin, strerror(errno)); - return GS_ERROR_NOT_SUPPORTED; - } - - return GS_OK; -} - -gs_error_t gs_gpio_sysfs_get(gs_gpio_t gpio, bool *value, void * driver_data) -{ - char gpio_sys_fname[128]; - snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); - - if (access(gpio_sys_fname, R_OK) != 0) - { - log_error("GPIO %d not initialized - Can't read the input.", gpio.pin); - return GS_ERROR_ACCESS; - } - - char value_str[10]; - gs_error_t ret = gs_sysfs_read_file(gpio_sys_fname, value_str, sizeof(value_str)); - if (ret == GS_OK) - { - if (strcmp(value_str, "1") == 0) - *value = true; - else - *value = false; - } - - return ret; -} - -bool gs_gpio_sysfs_get_nc(gs_gpio_t gpio, void * driver_data) -{ - char gpio_sys_fname[128]; - snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); - - if (access(gpio_sys_fname, R_OK) != 0) - { - log_error("GPIO %d not initialized - Can't read the input.", gpio.pin); - return 0; - } - - char value_str[10]; - gs_sysfs_read_file(gpio_sys_fname, value_str, sizeof(value_str)); - - if (strncmp(value_str, "1", 10) == 0) { - return true; - } else { - return false; - } -} - -gs_error_t gs_gpio_sysfs_set(gs_gpio_t gpio, bool value, void * driver_data) -{ - const char *value_str = value ? "1" : "0"; - - char gpio_sys_fname[128]; - snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); - if (access(gpio_sys_fname, W_OK) == 0) - { - return gs_sysfs_write_file(gpio_sys_fname, value_str); - } - - log_error("GPIO %d not initialized - Can't set the output.", gpio.pin); - return GS_ERROR_ACCESS; -} - -void gs_gpio_sysfs_set_nc(gs_gpio_t gpio, bool value, void * driver_data) -{ - const char *value_str = value ? "1" : "0"; - - char gpio_sys_fname[128]; - snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); - if (access(gpio_sys_fname, W_OK) == 0) - { - gs_sysfs_write_file(gpio_sys_fname, value_str); - return; - } - log_error("GPIO %d not initialized - Can't set the output.", gpio.pin); -} - -gs_error_t gs_gpio_sysfs_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data) -{ - return GS_ERROR_NOT_IMPLEMENTED; -} - -const gs_gpio_driver_t gs_gpio_sysfs_driver = { - .get_handler = gs_gpio_sysfs_get, - .get_nc_handler = gs_gpio_sysfs_get_nc, - .set_handler = gs_gpio_sysfs_set, - .set_nc_handler = gs_gpio_sysfs_set_nc, - .init_as_interrupt_handler = gs_gpio_sysfs_init_as_interrupt, -}; - diff --git a/gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c b/gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c deleted file mode 100644 index ce20c885..00000000 --- a/gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c +++ /dev/null @@ -1,171 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -#define MAX_VPINS 500 - -#define FALLING_EDGE_FLAG 0x1 -#define RISING_EDGE_FLAG 0x2 - -typedef struct { - gs_gpio_t gpio; - bool output; - bool value; - bool in_use; - gs_gpio_isr_t isr; - uint8_t edge_flags; - uint32_t transistions; -} gs_gpio_virtual_t; - -static gs_gpio_virtual_t vpins[MAX_VPINS]; - -gs_error_t gs_gpio_virtual_initialize(gs_gpio_t gpio, bool output, bool value) -{ - gs_gpio_virtual_t * pin; - for (uint16_t i = 0; i < MAX_VPINS; i++) { - pin = &vpins[i]; - if ((!pin->in_use) || ((pin->gpio.pin == gpio.pin) && (pin->gpio.port == gpio.port))) { - pin->gpio = gpio; - pin->output = output; - pin->value = value; - pin->in_use = true; - return GS_OK; - } - } - return GS_ERROR_FULL; -} - -static gs_gpio_virtual_t * find_vpin(gs_gpio_t * gpio) -{ - gs_gpio_virtual_t * pin; - for (uint16_t i = 0; i < MAX_VPINS; i++) { - pin = &vpins[i]; - if (pin->gpio.pin == gpio->pin) { - if (pin->gpio.port == gpio->port) { - if (pin->in_use) { - return pin; - } - } - } - } - return NULL; -} - -gs_error_t gs_gpio_virtual_get(gs_gpio_t gpio, bool *value, void * driver_data) -{ - gs_gpio_virtual_t * pin = find_vpin(&gpio); - if (pin) { - *value = pin->value; - return GS_OK; - } - return GS_ERROR_NOT_FOUND; -} - -bool gs_gpio_virtual_get_nc(gs_gpio_t gpio, void * driver_data) -{ - gs_gpio_virtual_t * pin = find_vpin(&gpio); - if (pin) { - return pin->value; - } - return false; -} - -gs_error_t gs_gpio_virtual_set(gs_gpio_t gpio, bool value, void * driver_data) -{ - gs_gpio_virtual_t * pin = find_vpin(&gpio); - if (pin) { - if (pin->output) { - if (pin->value != value) { - pin->value = value; - pin->transistions++; - } - return GS_OK; - } - return GS_ERROR_PERM; - } - return GS_ERROR_NOT_FOUND; -} - -void gs_gpio_virtual_set_nc(gs_gpio_t gpio, bool value, void * driver_data) -{ - gs_gpio_virtual_t * pin = find_vpin(&gpio); - if (pin) { - if (pin->output) { - if (pin->value != value) { - pin->value = value; - pin->transistions++; - } - } - } -} - -gs_error_t gs_gpio_virtual_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data) -{ - gs_gpio_virtual_t * pin; - for (uint16_t i = 0; i < MAX_VPINS; i++) { - pin = &vpins[i]; - if ((!pin->in_use) || ((pin->gpio.pin == gpio.pin) && (pin->gpio.port == gpio.port))) { - pin->gpio = gpio; - pin->output = false; - pin->value = 0; - pin->in_use = true; - pin->isr = conf->isr; - if (conf->falling_edge) { - pin->edge_flags |= FALLING_EDGE_FLAG; - } - if (conf->rising_edge) { - pin->edge_flags |= RISING_EDGE_FLAG; - } - return GS_OK; - } - } - return GS_ERROR_FULL; -} - -gs_error_t gs_gpio_virtual_force_set(gs_gpio_t gpio, bool value) -{ - gs_gpio_virtual_t * pin = find_vpin(&gpio); - if (pin) { - bool old_value = pin->value; - if (old_value != value) { - pin->value = value; - pin->transistions++; - if (pin->isr) { - if ((old_value == false) && (pin->edge_flags & RISING_EDGE_FLAG)) { - pin->isr(NULL); - } else if ((old_value == true) && (pin->edge_flags & FALLING_EDGE_FLAG)) { - pin->isr(NULL); - } - } - } - return GS_OK; - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_gpio_virtual_get_transistions(gs_gpio_t gpio, uint32_t * transitions) -{ - gs_gpio_virtual_t * pin = find_vpin(&gpio); - if (pin) { - *transitions = pin->transistions; - pin->transistions = 0; - return GS_OK; - } - return GS_ERROR_NOT_FOUND; -} - -const gs_gpio_driver_t gs_gpio_virtual_driver = { - .get_handler = gs_gpio_virtual_get, - .get_nc_handler = gs_gpio_virtual_get_nc, - .set_handler = gs_gpio_virtual_set, - .set_nc_handler = gs_gpio_virtual_set_nc, - .init_as_interrupt_handler = gs_gpio_virtual_init_as_interrupt, -}; - - -const gs_gpio_driver_entry_t gs_gpio_virtual_driver_entry_all = { - .port = GS_GPIO_ALL_PORTS, - .pin = GS_GPIO_ALL_PINS, - .driver = &gs_gpio_virtual_driver, - .driver_data = NULL, -}; diff --git a/gomspace/libutil/src/linux/drivers/i2c/i2c.c b/gomspace/libutil/src/linux/drivers/i2c/i2c.c deleted file mode 100644 index 679ae3f7..00000000 --- a/gomspace/libutil/src/linux/drivers/i2c/i2c.c +++ /dev/null @@ -1,144 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -#define MAX_DRIVERS 20 -#define HIGHEST_I2C_ADDR 127 - -typedef struct { - gs_i2c_master_driver_entry_t entry; - bool in_use; -} gs_i2c_master_driver_handle_t; - -typedef struct { - gs_i2c_slave_driver_entry_t entry; - bool in_use; -} gs_i2c_slave_driver_handle_t; - -static gs_i2c_master_driver_handle_t master_drivers[MAX_DRIVERS]; -static gs_i2c_slave_driver_handle_t slave_drivers[MAX_DRIVERS]; - -static uint8_t max_index_master_in_use = 0; -static uint8_t max_index_slave_in_use = 0; - -gs_error_t gs_i2c_master_transaction(uint8_t device, uint8_t addr, const void * tx, - size_t txlen, - void * rx, - size_t rxlen, - int timeout_ms) -{ - GS_CHECK_RANGE(addr <= HIGHEST_I2C_ADDR); - gs_i2c_master_driver_handle_t * handle; - for (int i = max_index_master_in_use; i >= 0; i--) { - handle = &master_drivers[i]; - if (((device == handle->entry.device) || (handle->entry.device == GS_I2C_ALL_DEVICES)) - && ((addr == handle->entry.addr) || (handle->entry.addr == GS_I2C_ALL_ADDR)) - && (handle->in_use == true)) { - if (handle->entry.driver->master_transaction_handler) { - return handle->entry.driver->master_transaction_handler(device, addr, tx, txlen, rx, rxlen, timeout_ms, handle->entry.driver_data); - } - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_i2c_master_register_driver(const gs_i2c_master_driver_entry_t * driver_entry) -{ - GS_CHECK_ARG(driver_entry != NULL); - GS_CHECK_ARG(driver_entry->driver != NULL); - - GS_CHECK_RANGE((driver_entry->addr == GS_I2C_ALL_ADDR) || (driver_entry->addr <= HIGHEST_I2C_ADDR)); - - gs_i2c_master_driver_handle_t * handle; - for (uint8_t i = 0; i < MAX_DRIVERS; i++) { - handle = &master_drivers[i]; - if (handle->in_use == false) { - handle->entry = *driver_entry; - handle->in_use = true; - max_index_master_in_use = i; - return GS_OK; - } - } - - /* Not enough space in buffer */ - return GS_ERROR_FULL; -} - -static inline gs_i2c_slave_driver_entry_t * gs_slave_find_driver_entry(uint8_t device) -{ - gs_i2c_slave_driver_handle_t * handle; - for (int i = max_index_slave_in_use; i >= 0; i--) { - handle = &slave_drivers[i]; - if (((device == handle->entry.device) || (handle->entry.device == GS_I2C_ALL_DEVICES)) - && (handle->in_use == true)) { - return &handle->entry; - } - } - return NULL; -} - -gs_error_t gs_i2c_slave_start(uint8_t device) -{ - gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); - if (driver_entry) { - if (driver_entry->driver->start_handler) { - return driver_entry->driver->start_handler(device, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_i2c_slave_set_rx(uint8_t device, gs_i2c_slave_receive_t rx) -{ - gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); - if (driver_entry) { - if (driver_entry->driver->set_rx_handler) { - return driver_entry->driver->set_rx_handler(device, rx, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_i2c_slave_set_get_rx_buf(uint8_t device, gs_i2c_slave_get_rx_buf_t get_rx_buf, size_t buf_length) -{ - gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); - if (driver_entry) { - if (driver_entry->driver->set_get_rx_buf_handler) { - return driver_entry->driver->set_get_rx_buf_handler(device, get_rx_buf, buf_length, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_i2c_slave_set_response(uint8_t device, const uint8_t * tx, size_t tx_length) -{ - gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); - if (driver_entry) { - if (driver_entry->driver->set_response_handler) { - return driver_entry->driver->set_response_handler(device, tx, tx_length, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_i2c_slave_register_driver(const gs_i2c_slave_driver_entry_t * driver_entry) -{ - GS_CHECK_ARG(driver_entry != NULL); - GS_CHECK_ARG(driver_entry->driver != NULL); - - gs_i2c_slave_driver_handle_t * handle; - for (uint8_t i = 0; i < MAX_DRIVERS; i++) { - handle = &slave_drivers[i]; - if (handle->in_use == false) { - handle->entry = *driver_entry; - handle->in_use = true; - max_index_slave_in_use = i; - return GS_OK; - } - } - - /* Not enough space in buffer */ - return GS_ERROR_FULL; -} diff --git a/gomspace/libutil/src/linux/drivers/spi/spi.c b/gomspace/libutil/src/linux/drivers/spi/spi.c deleted file mode 100644 index 6756482c..00000000 --- a/gomspace/libutil/src/linux/drivers/spi/spi.c +++ /dev/null @@ -1,137 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -#define MAX_DRIVERS 20 - -typedef struct { - gs_spi_master_driver_entry_t entry; - bool in_use; -} gs_spi_master_driver_handle_t; - -typedef struct { - gs_spi_slave_driver_entry_t entry; - bool in_use; -} gs_spi_slave_driver_handle_t; - -static gs_spi_master_driver_handle_t master_drivers[MAX_DRIVERS]; -static gs_spi_slave_driver_handle_t slave_drivers[MAX_DRIVERS]; - -static uint8_t max_index_master_in_use = 0; -static uint8_t max_index_slave_in_use = 0; - -static inline gs_spi_master_driver_entry_t * gs_master_find_driver_entry(uint8_t slave) -{ - gs_spi_master_driver_handle_t * handle; - for (int i = max_index_master_in_use; i >= 0; i--) { - handle = &master_drivers[i]; - if (((slave == handle->entry.slave) || (handle->entry.slave == GS_SPI_ALL_SLAVES)) && (handle->in_use == true)) { - return &handle->entry; - } - } - return NULL; -} - -gs_error_t gs_spi_master_transaction(uint8_t slave, const void * tx, void * rx, size_t size, int timeout_ms) -{ - gs_spi_master_trans_t trans = {.tx = tx, .rx = rx, .size = size}; - return gs_spi_master_transactions(slave, &trans, 1, timeout_ms); -} - -gs_error_t gs_spi_master_transactions(uint8_t slave, gs_spi_master_trans_t *trans, size_t count, int timeout_ms) -{ - gs_spi_master_driver_entry_t * driver_entry = gs_master_find_driver_entry(slave); - if (driver_entry) { - if (driver_entry->driver->master_transactions_handler) { - return driver_entry->driver->master_transactions_handler(slave, trans, count, timeout_ms, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_spi_master_register_driver(const gs_spi_master_driver_entry_t * driver_entry) -{ - GS_CHECK_ARG(driver_entry != NULL); - GS_CHECK_ARG(driver_entry->driver != NULL); - - gs_spi_master_driver_handle_t * handle; - for (uint8_t i = 0; i < MAX_DRIVERS; i++) { - handle = &master_drivers[i]; - if (handle->in_use == false) { - handle->entry = *driver_entry; - handle->in_use = true; - max_index_master_in_use = i; - return GS_OK; - } - } - - /* Not enough space in buffer */ - return GS_ERROR_FULL; -} - -static inline gs_spi_slave_driver_entry_t * gs_slave_find_driver_entry(uint8_t device) -{ - gs_spi_slave_driver_handle_t * handle; - for (int i = max_index_slave_in_use; i >= 0; i--) { - handle = &slave_drivers[i]; - if (((device == handle->entry.device) || (handle->entry.device == GS_SPI_ALL_DEVICES)) - && (handle->in_use == true)) { - return &handle->entry; - } - } - return NULL; -} - -gs_error_t gs_spi_slave_start(uint8_t device) -{ - gs_spi_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); - if (driver_entry) { - if (driver_entry->driver->start_handler) { - return driver_entry->driver->start_handler(device, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_spi_slave_set_rx(uint8_t device, gs_spi_slave_receive_t rx) -{ - gs_spi_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); - if (driver_entry) { - if (driver_entry->driver->set_rx_handler) { - return driver_entry->driver->set_rx_handler(device, rx, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_spi_slave_set_response(uint8_t device, size_t offset, const uint8_t * tx, size_t size) -{ - gs_spi_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); - if (driver_entry) { - if (driver_entry->driver->set_response_handler) { - return driver_entry->driver->set_response_handler(device, offset, tx, size, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_spi_slave_register_driver(const gs_spi_slave_driver_entry_t * driver_entry) -{ - GS_CHECK_ARG(driver_entry != NULL); - GS_CHECK_ARG(driver_entry->driver != NULL); - - gs_spi_slave_driver_handle_t * handle; - for (uint8_t i = 0; i < MAX_DRIVERS; i++) { - handle = &slave_drivers[i]; - if (handle->in_use == false) { - handle->entry = *driver_entry; - handle->in_use = true; - max_index_slave_in_use = i; - return GS_OK; - } - } - /* Not enough space in buffer */ - return GS_ERROR_FULL; -} diff --git a/gomspace/libutil/src/linux/drivers/sys/memory.c b/gomspace/libutil/src/linux/drivers/sys/memory.c deleted file mode 100644 index 8def9988..00000000 --- a/gomspace/libutil/src/linux/drivers/sys/memory.c +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -gs_error_t gs_mem_get_int_ram_stat(gs_mem_ram_stat_t * ram_stat) -{ - return GS_ERROR_NOT_SUPPORTED; -} - -gs_error_t gs_mem_get_ext_ram_stat(gs_mem_ram_stat_t * ram_stat) -{ - struct sysinfo info; - int res = sysinfo(&info); - if (res != GS_OK) { - return res; - } - - ram_stat->total = info.totalram; - ram_stat->max_available = -1; - ram_stat->min_available = -1; - ram_stat->available = info.freeram; - - return GS_OK; -} - -gs_mem_ram_type_t gs_mem_get_ram_default() -{ - return GS_MEM_RAM_TYPE_EXTERNAL; -} diff --git a/gomspace/libutil/src/linux/function.c b/gomspace/libutil/src/linux/function.c deleted file mode 100644 index 9e0f7c0f..00000000 --- a/gomspace/libutil/src/linux/function.c +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -typedef struct { - const char * short_name; - const char * long_name; - gs_function_t function; -} gs_function_register_t; - -static gs_function_register_t registry[10]; - -gs_error_t gs_function_register(const char * short_name, const char * long_name, gs_function_t function) -{ - for (unsigned int i = 0; i < GS_ARRAY_SIZE(registry); ++i) { - gs_function_register_t * cb = ®istry[i]; - if ((cb->short_name == NULL) && (cb->long_name == NULL)) { - cb->short_name = short_name; - cb->long_name = long_name; - cb->function = function; - return GS_OK; - } - } - return GS_ERROR_FULL; -} - -gs_error_t gs_function_invoke(const char * name, void * arg) -{ - for (unsigned int i = 0; i < GS_ARRAY_SIZE(registry); ++i) { - gs_function_register_t * cb = ®istry[i]; - if ((gs_string_empty(cb->short_name) == false) && (strcasecmp(cb->short_name, name) == 0)) { - return (cb->function)(arg); - } - if ((gs_string_empty(cb->long_name) == false) && (strcasecmp(cb->long_name, name) == 0)) { - return (cb->function)(arg); - } - } - - return GS_ERROR_NOT_IMPLEMENTED; -} diff --git a/gomspace/libutil/src/linux/mutex.c b/gomspace/libutil/src/linux/mutex.c deleted file mode 100644 index 00336510..00000000 --- a/gomspace/libutil/src/linux/mutex.c +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -gs_error_t gs_mutex_create(gs_mutex_t * mutex) -{ - if (mutex == NULL) { - return GS_ERROR_ARG; - } - - *mutex = malloc(sizeof(pthread_mutex_t)); - if (*mutex == NULL) { - return GS_ERROR_ALLOC; - } - - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - int res = pthread_mutex_init(*mutex, &attr); - if (res < 0) { - res = gs_error(errno); - free(*mutex); - } - - return res; -} - -gs_error_t gs_mutex_destroy(gs_mutex_t mutex) -{ - int res = GS_OK; - if (mutex) { - res = pthread_mutex_destroy(mutex); - if (res < 0) { - res = gs_error(errno); - } - free(mutex); - } - return res; -} - -gs_error_t gs_mutex_lock(gs_mutex_t mutex) -{ - int res = pthread_mutex_lock(mutex); - if (res < 0) { - res = gs_error(errno); - } - return res; -} - -gs_error_t gs_mutex_unlock(gs_mutex_t mutex) -{ - int res = pthread_mutex_unlock(mutex); - if (res < 0) { - res = gs_error(errno); - } - return res; -} diff --git a/gomspace/libutil/src/linux/queue.c b/gomspace/libutil/src/linux/queue.c deleted file mode 100644 index cb477f70..00000000 --- a/gomspace/libutil/src/linux/queue.c +++ /dev/null @@ -1,217 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - * Inspired by c-pthread-queue by Matthew Dickinson - * http://code.google.com/p/c-pthread-queue/ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define PTHREAD_QUEUE_ARG GS_ERROR_ARG -#define PTHREAD_QUEUE_EMPTY GS_ERROR_NOT_FOUND -#define PTHREAD_QUEUE_FULL GS_ERROR_FULL -#define PTHREAD_QUEUE_TIMEOUT GS_ERROR_TIMEOUT -#define PTHREAD_QUEUE_OK GS_OK - -typedef struct gs_pthread_queue { - uint8_t * buffer; - size_t size; - size_t item_size; - size_t items; - size_t in; - size_t out; - pthread_mutex_t mutex; - pthread_cond_t cond_full; - pthread_cond_t cond_empty; -} pthread_queue_t; - -static pthread_queue_t * pthread_queue_create(size_t length, size_t item_size) -{ - pthread_queue_t * q = malloc(sizeof(pthread_queue_t)); - - if (q != NULL) { - q->buffer = malloc(length*item_size); - if (q->buffer != NULL) { - q->size = length; - q->item_size = item_size; - q->items = 0; - q->in = 0; - q->out = 0; - if (pthread_mutex_init(&(q->mutex), NULL) || pthread_cond_init(&(q->cond_full), NULL) || pthread_cond_init(&(q->cond_empty), NULL)) { - free(q->buffer); - free(q); - q = NULL; - } - } else { - free(q); - q = NULL; - } - } - - return q; -} - -static void pthread_queue_delete(pthread_queue_t * q) -{ - if (q) { - free(q->buffer); - free(q); - } -} - -static int pthread_queue_enqueue(pthread_queue_t * queue, const void * value, uint32_t timeout) -{ - /* Calculate timeout */ - struct timespec ts; - if (clock_gettime(CLOCK_REALTIME, &ts)) { - return PTHREAD_QUEUE_ARG; - } - - uint32_t sec = timeout / 1000; - uint32_t nsec = (timeout - 1000 * sec) * 1000000; - - ts.tv_sec += sec; - - if (ts.tv_nsec + nsec > 1000000000) - ts.tv_sec++; - - ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; - - /* Get queue lock */ - pthread_mutex_lock(&(queue->mutex)); - - while (queue->items == queue->size) { - int ret = -1; - if (timeout) { - ret = pthread_cond_timedwait(&(queue->cond_full), &(queue->mutex), &ts); - } - if (ret) { - pthread_mutex_unlock(&(queue->mutex)); - return PTHREAD_QUEUE_TIMEOUT; - } - } - - /* Coby object from input buffer */ - memcpy(queue->buffer+(queue->in * queue->item_size), value, queue->item_size); - queue->items++; - queue->in = (queue->in + 1) % queue->size; - pthread_mutex_unlock(&(queue->mutex)); - - /* Nofify blocked threads */ - pthread_cond_broadcast(&(queue->cond_empty)); - - return PTHREAD_QUEUE_OK; -} - -static int pthread_queue_dequeue(pthread_queue_t * queue, void * buf, uint32_t timeout) -{ - /* Calculate timeout */ - struct timespec ts; - if (clock_gettime(CLOCK_REALTIME, &ts)) { - return PTHREAD_QUEUE_ARG; - } - - uint32_t sec = timeout / 1000; - uint32_t nsec = (timeout - 1000 * sec) * 1000000; - - ts.tv_sec += sec; - - if (ts.tv_nsec + nsec > 1000000000) - ts.tv_sec++; - - ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; - - /* Get queue lock */ - pthread_mutex_lock(&(queue->mutex)); - while (queue->items == 0) { - int ret = -1; - if (timeout) { - ret = pthread_cond_timedwait(&(queue->cond_empty), &(queue->mutex), &ts); - } - if (ret) { - pthread_mutex_unlock(&(queue->mutex)); - return PTHREAD_QUEUE_TIMEOUT; - } - } - - /* Coby object to output buffer */ - memcpy(buf, queue->buffer+(queue->out * queue->item_size), queue->item_size); - queue->items--; - queue->out = (queue->out + 1) % queue->size; - pthread_mutex_unlock(&(queue->mutex)); - - /* Nofify blocked threads */ - pthread_cond_broadcast(&(queue->cond_full)); - - return PTHREAD_QUEUE_OK; -} - -static size_t pthread_queue_items(pthread_queue_t * queue) -{ - pthread_mutex_lock(&(queue->mutex)); - size_t items = queue->items; - pthread_mutex_unlock(&(queue->mutex)); - return items; -} - -gs_error_t gs_queue_create(size_t items, size_t item_size, gs_queue_t * queue) -{ - if (queue == NULL) { - return GS_ERROR_ARG; - } - pthread_queue_t * q = pthread_queue_create(items, item_size); - if (q == NULL) { - return GS_ERROR_ALLOC; - } - *queue = q; - return GS_OK; -} - -gs_error_t gs_queue_destroy(gs_queue_t queue) -{ - pthread_queue_delete(queue); - return GS_OK; -} - -gs_error_t gs_queue_enqueue(gs_queue_t queue, const void *value, int timeout_ms) -{ - return pthread_queue_enqueue(queue, value, (timeout_ms >= 0) ? timeout_ms : INT_MAX); -} - -gs_error_t gs_queue_enqueue_isr(gs_queue_t queue, const void * value, gs_context_switch_t * cswitch) -{ - (void) cswitch; - gs_error_t error = gs_queue_enqueue(queue, value, 0); - return (error != GS_ERROR_TIMEOUT) ? error : GS_ERROR_FULL; -} - -gs_error_t gs_queue_dequeue(gs_queue_t queue, int timeout_ms, void *buf) -{ - return pthread_queue_dequeue(queue, buf, (timeout_ms >= 0) ? timeout_ms : INT_MAX); -} - -gs_error_t gs_queue_dequeue_isr(gs_queue_t queue, gs_context_switch_t * cswitch, void *buf) -{ - (void) cswitch; - gs_error_t error = gs_queue_dequeue(queue, 0, buf); - return (error != GS_ERROR_TIMEOUT) ? error : GS_ERROR_NOT_FOUND; -} - -unsigned int gs_queue_size(gs_queue_t queue) -{ - if (queue) { - return pthread_queue_items(queue); - } - return 0; -} - -unsigned int gs_queue_size_isr(gs_queue_t queue) -{ - return gs_queue_size(queue); -} diff --git a/gomspace/libutil/src/linux/rtc.c b/gomspace/libutil/src/linux/rtc.c deleted file mode 100644 index ff241d58..00000000 --- a/gomspace/libutil/src/linux/rtc.c +++ /dev/null @@ -1,78 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -static gs_error_t gs_rtc_get(void * driver_data, gs_timestamp_t * return_time) -{ - if (return_time == NULL) { - return GS_ERROR_ARG; - } - - return_time->tv_sec = 0; - return_time->tv_nsec = 0; - - int fd = open("/dev/rtc", O_RDONLY | O_CLOEXEC); - if (fd < 0) { - return gs_error(errno); - } - - struct tm tm; - memset(&tm, 0, sizeof(tm)); - int res = ioctl(fd, RTC_RD_TIME, &tm); - close(fd); - if (res < 0) { - return gs_error(errno); - } - - time_t time = mktime(&tm); - if (time < 0) { - return GS_ERROR_DATA; - } - - return_time->tv_sec = (uint32_t) time; - - return GS_OK; -} - -static gs_error_t gs_rtc_set(void * driver_data, const gs_timestamp_t * set_time) -{ - if (set_time == NULL) { - return GS_ERROR_ARG; - } - - int fd = open("/dev/rtc", O_RDONLY | O_CLOEXEC); - if (fd < 0) { - return gs_error(errno); - } - - const time_t now = set_time->tv_sec; - struct tm tm; - gmtime_r(&now, &tm); - int res = ioctl(fd, RTC_SET_TIME, &tm); - close(fd); - if (res < 0) { - return gs_error(errno); - } - - return GS_OK; -} - -gs_error_t gs_rtc_register_linux(bool get, bool set) -{ - static gs_rtc_driver_t rtc_driver; - if (get) { - rtc_driver.get_time = gs_rtc_get; - } - if (set) { - rtc_driver.set_time = gs_rtc_set; - } - return gs_rtc_register(&rtc_driver, NULL); -} diff --git a/gomspace/libutil/src/linux/sem.c b/gomspace/libutil/src/linux/sem.c deleted file mode 100644 index b4d2c09d..00000000 --- a/gomspace/libutil/src/linux/sem.c +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include - -gs_error_t gs_sem_create(unsigned int initialValue, gs_sem_t * sem) -{ - if (sem == NULL) { - return GS_ERROR_ARG; - } - - *sem = malloc(sizeof(sem_t)); - if (*sem == NULL) { - return GS_ERROR_ALLOC; - } - - int res = sem_init(*sem, 0, initialValue); - if (res < 0) { - res = gs_error(errno); - free(*sem); - } - - return res; -} - -gs_error_t gs_sem_destroy(gs_sem_t sem) -{ - int res = GS_OK; - if (sem) { - res = sem_destroy(sem); - if (res < 0) { - res = gs_error(errno); - } - free(sem); - } - return res; -} - -gs_error_t gs_sem_wait(gs_sem_t sem, int timeout_ms) -{ - int res; - - if (timeout_ms < 0) { - res = sem_wait(sem); - } else { - struct timespec ts; - res = clock_gettime(CLOCK_REALTIME, &ts); - if (res == 0) { - const uint32_t ms = (uint32_t)timeout_ms; - uint32_t sec = ms / 1000; - uint32_t nsec = (ms - (1000 * sec)) * 1000000; - - ts.tv_sec += sec; - - if (ts.tv_nsec + nsec >= 1000000000) { - ts.tv_sec++; - } - - ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; - - res = sem_timedwait(sem, &ts); - } - } - if (res < 0) { - res = gs_error(errno); - } - return res; -} - -gs_error_t gs_sem_post(gs_sem_t sem) -{ - int res = sem_post(sem); - if (res < 0) { - res = gs_error(errno); - } - return res; -} - -gs_error_t gs_sem_post_isr(gs_sem_t sem, gs_context_switch_t * cswitch) -{ - (void) cswitch; - int res = sem_post(sem); - if (res < 0) { - res = gs_error(errno); - } - return res; -} diff --git a/gomspace/libutil/src/linux/signal.c b/gomspace/libutil/src/linux/signal.c deleted file mode 100644 index 826bc325..00000000 --- a/gomspace/libutil/src/linux/signal.c +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -static void gs_signal_default_handler(int signo, siginfo_t *si, void *context) -{ - exit(GS_EXITCODE_SIGNAL(signo)); // ensure atexit are invoked -} - -gs_error_t gs_signal_catch(int signal, gs_signal_handler handler) -{ - if (handler == NULL) { - handler = gs_signal_default_handler; - } - struct sigaction sa = { .sa_flags = SA_SIGINFO, - .sa_sigaction = handler}; - if (sigemptyset(&sa.sa_mask)) { - return GS_ERROR_UNKNOWN; - } - if (sigaction(signal, &sa, NULL)) { - return GS_ERROR_UNKNOWN; - } - return GS_OK; -} - -gs_error_t gs_signal_ignore(int signal) -{ - struct sigaction sa = { .sa_flags = 0, - .sa_handler = SIG_IGN}; // handle signal by ignoring - if (sigemptyset(&sa.sa_mask)) { - return GS_ERROR_UNKNOWN; - } - if (sigaction(signal, &sa, NULL)) { - return GS_ERROR_UNKNOWN; - } - return GS_OK; -} diff --git a/gomspace/libutil/src/linux/stdio.c b/gomspace/libutil/src/linux/stdio.c deleted file mode 100644 index 0fa052b7..00000000 --- a/gomspace/libutil/src/linux/stdio.c +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -gs_error_t gs_stdio_putchar(int ch) -{ - const int res = putchar(ch); - if (res < 0) { - return GS_ERROR_IO; - } - return GS_OK; -} - -gs_error_t gs_stdio_getchar_timed(int timeout_ms, int * ch) -{ - struct pollfd fds = {STDIN_FILENO, POLLIN, 0}; - const int res = poll(&fds, 1, timeout_ms); - - if (res == 0) { - return GS_ERROR_TIMEOUT; - } - - if ((res > 0) && (fds.revents & POLLIN)) { - int tmp = getchar(); - if (tmp >= 0) { - if (ch) { - *ch = tmp; - } - return GS_OK; - } - } - - return GS_ERROR_IO; -} diff --git a/gomspace/libutil/src/linux/sysfs_helper.c b/gomspace/libutil/src/linux/sysfs_helper.c deleted file mode 100644 index 2cdb390a..00000000 --- a/gomspace/libutil/src/linux/sysfs_helper.c +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -gs_error_t gs_sysfs_write_file(const char *path, const char *value) -{ - log_trace("sysfs: write %s to %s", value, path); - - int fd = open(path, O_WRONLY); - if (fd < 0) { - return GS_ERROR_HANDLE; - } - - size_t len = strlen(value); - ssize_t bytes = write(fd, value, len); - close(fd); - if (bytes < 0) { - return GS_ERROR_NO_DATA; - } - - return (len == (size_t)bytes) ? GS_OK : GS_ERROR_NO_DATA; -} - -gs_error_t gs_sysfs_read_file(const char *path, char *value, size_t len) -{ - log_trace("sysfs: read %s", path); - - int fd = open(path, O_RDONLY); - if (fd < 0) { - return GS_ERROR_HANDLE; - } - - ssize_t bytes = read(fd, value, len); - close(fd); - if (bytes < 0) { - return GS_ERROR_DATA; - } - - return GS_OK; -} diff --git a/gomspace/libutil/src/linux/thread.c b/gomspace/libutil/src/linux/thread.c deleted file mode 100644 index 43de1815..00000000 --- a/gomspace/libutil/src/linux/thread.c +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -gs_error_t gs_thread_create(const char * const name, - gs_thread_func_t func, - void * parameter, - size_t stack_size, - gs_thread_priority_t priority, - uint32_t flags, - gs_thread_t * return_handle) -{ - gs_time_uptime(); // force initialize of static offset - - pthread_attr_t attr; - int res = pthread_attr_init(&attr); - if (res) { - return GS_ERROR_ALLOC; - } - - if (flags & GS_THREAD_CREATE_JOINABLE) { - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - } else { - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - } - - gs_thread_t handle; - res = pthread_create(&handle, &attr, func, parameter); - pthread_attr_destroy(&attr); - if (res) { - return GS_ERROR_ALLOC; - } - - if (return_handle) { - *return_handle = handle; - } - - return GS_OK; -} - -gs_error_t gs_thread_create_with_stack(const char * const name, - gs_thread_func_t func, - void * parameter, - size_t stack_size, - gs_stack_type_t *stack, - gs_thread_priority_t priority, - uint32_t flags, - gs_thread_t * return_handle) -{ - return gs_thread_create(name, func, parameter, stack_size, priority, flags, return_handle); -} - -void gs_thread_exit(void * exitValue) -{ - pthread_exit(exitValue); -} - -void gs_thread_sleep_ms(uint32_t time_ms) -{ - gs_time_sleep_ms(time_ms); -} - -gs_error_t gs_thread_join(gs_thread_t thread, void ** return_retval) -{ - gs_error_t error = GS_ERROR_ARG; - void * retval = 0; - if (thread) { - int res = pthread_join(thread, &retval); - if (res == 0) { - error = GS_OK; - } else { - retval = 0; - } - } - if (return_retval) { - *return_retval = retval; - } - return error; -} - -void gs_thread_block(void) -{ - /* Wait here forever */ - for (;;) { - gs_time_sleep_ms(10000); - } -} diff --git a/gomspace/libutil/src/linux/time.c b/gomspace/libutil/src/linux/time.c deleted file mode 100644 index 46377feb..00000000 --- a/gomspace/libutil/src/linux/time.c +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -uint32_t gs_time_rel_ms(void) -{ - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { - return 0; - } - - return (uint32_t)((ts.tv_sec * 1000) + (ts.tv_nsec/1000000)); -} - -uint32_t gs_time_rel_ms_isr(void) -{ - return gs_time_rel_ms(); -} - -static uint32_t uptime_offset = 0; -uint32_t gs_time_uptime(void) -{ - uint32_t seconds; - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { - seconds = 0; - } else { - seconds = (uint32_t) ts.tv_sec; - } - if (uptime_offset == 0) { - uptime_offset = seconds; - } - return (seconds - uptime_offset); -} - -void gs_time_sleep_ns(uint64_t time_ns) -{ - struct timespec ts; - ts.tv_sec = (time_ns / GS_TIMESTAMP_NSEC_PER_SEC); - ts.tv_nsec = (time_ns % GS_TIMESTAMP_NSEC_PER_SEC); - - // improvement: check return code (INTR) and use remaining. - nanosleep(&ts, NULL); -} - -void gs_time_sleep_ms(uint32_t time_ms) -{ - uint64_t ns = time_ms; - ns *= 1000000LL; - gs_time_sleep_ns( ns); -} diff --git a/gomspace/libutil/src/lock.c b/gomspace/libutil/src/lock.c deleted file mode 100644 index 76be91bd..00000000 --- a/gomspace/libutil/src/lock.c +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (c) 2013-2019 GomSpace A/S. All rights reserved. */ - -#include "lock.h" -#include - -static gs_mutex_t gs_lock; - -gs_error_t gs_lock_init(void) -{ - if (gs_lock == NULL) { - return gs_mutex_create(&gs_lock); - } - return GS_OK; -} - -gs_error_t gs_lock_lock(void) -{ - if (gs_lock == NULL) { - gs_error_t error = gs_lock_init(); - if (error) { - return error; - } - } - return gs_mutex_lock(gs_lock); -} - -gs_error_t gs_lock_unlock(void) -{ - return gs_mutex_unlock(gs_lock); -} diff --git a/gomspace/libutil/src/lock.h b/gomspace/libutil/src/lock.h deleted file mode 100644 index b22841e8..00000000 --- a/gomspace/libutil/src/lock.h +++ /dev/null @@ -1,14 +0,0 @@ -/* Copyright (c) 2013-2019 GomSpace A/S. All rights reserved. */ -/** - @file - - Basic/core locking. - - Use for rare read/write locking, e.g. protecting register/de-regsiter functions. -*/ - -#include - -gs_error_t gs_lock_init(void); -gs_error_t gs_lock_lock(void); -gs_error_t gs_lock_unlock(void); diff --git a/gomspace/libutil/src/log/appender/console.c b/gomspace/libutil/src/log/appender/console.c deleted file mode 100644 index 818248b3..00000000 --- a/gomspace/libutil/src/log/appender/console.c +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -// generated by waf configure -> GS_LOG_ENABLE_ISR_LOGS -#include - -static gs_log_appender_console_cb_t g_console_log_cb = NULL; -static gs_mutex_t g_log_console_mutex = NULL; - -gs_error_t gs_log_console_append_init(gs_log_appender_t *appender) -{ - gs_error_t ret = GS_OK; - if (g_log_console_mutex == NULL) { - ret = gs_mutex_create(&g_log_console_mutex); - if (ret != GS_OK) { - g_log_console_mutex = NULL; - } - } - return ret; -} - -static void gs_log_console_append_isr(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) -{ - va_list my_va; - va_copy(my_va, va); - - const char * color = gs_log_level_to_color_begin(level); - const char * end_color = gs_log_level_to_color_end(); - const char clevel = gs_log_level_to_char(level); - - // print log - printf("%s%04"PRIu32".%06"PRIu32" %c %s: ", color, ts->tv_sec, ts->tv_nsec / 1000, clevel, group->name); - GS_PGM_VPRINTF(format, my_va); - printf("%s\r\n", end_color); - - va_end(my_va); -} - -static void gs_log_console_append(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) -{ - if (g_console_log_cb) - return g_console_log_cb(appender, level, group, ts, format, va); - - if (g_log_console_mutex) { - gs_mutex_lock(g_log_console_mutex); - } - - gs_log_console_append_isr(appender, level, group, ts, format, va); - - if (g_log_console_mutex) { - gs_mutex_unlock(g_log_console_mutex); - } -} - -static void gs_log_console_append_get_info(gs_log_appender_t *appender, char *info_str, uint8_t str_size) -{ - if (!info_str) { - return; - } - - snprintf(info_str, str_size, "Prints on stdout"); -} - -gs_error_t gs_log_appender_console_set_cb(gs_log_appender_console_cb_t cb) -{ - g_console_log_cb = cb; - return GS_OK; -} - -static const gs_log_appender_driver_t console_appender_driver = { - .init = gs_log_console_append_init, - .append = gs_log_console_append, -#ifdef GS_LOG_ENABLE_ISR_LOGS - .append_isr = gs_log_console_append_isr, -#else - .append_isr = 0, -#endif - .info = gs_log_console_append_get_info, -}; - -gs_log_appender_t gs_log_appender_console = { - .name = "console", - .drv = &console_appender_driver, - .drv_config = 0, - .mask = LOG_ALL_MASK, -}; diff --git a/gomspace/libutil/src/log/appender/simple_file.c b/gomspace/libutil/src/log/appender/simple_file.c deleted file mode 100644 index f74a19e7..00000000 --- a/gomspace/libutil/src/log/appender/simple_file.c +++ /dev/null @@ -1,117 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#ifndef __AVR__ -#include -#include -#include - -#include -#include - -typedef struct simple_file_drv_data { - FILE *fp; - gs_mutex_t mutex; -} simple_file_drv_data_t; - -static gs_error_t gs_log_simple_file_init(gs_log_appender_t *appender) -{ - const gs_log_appender_simple_file_config_t *config = appender->drv_config; - - if (config == NULL || gs_string_empty(config->filename)) { - return GS_ERROR_ARG; - } - - simple_file_drv_data_t *drv_data = appender->drv_data; - if (drv_data == NULL) { - drv_data = calloc(1, sizeof(*drv_data)); - if (drv_data == NULL) { - return GS_ERROR_ALLOC; - } - } - - /* If file is already open - Close it first */ - if (drv_data->fp) { - gs_mutex_lock(drv_data->mutex); - fclose(drv_data->fp); - drv_data->fp = NULL; - gs_mutex_unlock(drv_data->mutex); - gs_mutex_destroy(drv_data->mutex); - } - - const char * mode = config->truncate ? "w" : "a"; - - drv_data->fp = fopen(config->filename, mode); - if (drv_data->fp == NULL) { - log_error("%s: failed to open log-file: [%s], mode: %s", __FUNCTION__, config->filename, mode); - free(drv_data); - drv_data = 0; - return GS_ERROR_IO; - } - - gs_mutex_create(&drv_data->mutex); - appender->drv_data = drv_data; /* Set driver data on appender */ - return GS_OK; -} - -static void gs_log_simple_file_append(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) -{ - va_list my_va; - va_copy(my_va, va); - - const gs_log_appender_simple_file_config_t *config = appender->drv_config; - simple_file_drv_data_t *drv_data = appender->drv_data; - if (drv_data == 0) { - va_end(my_va); - return; - } - - const char clevel = gs_log_level_to_char(level); - - const time_t t = ts->tv_sec; - struct tm result; - const char * tzone; - if (config->use_local_time) { - localtime_r(&t, &result); - tzone = ""; - } else { - gmtime_r(&t, &result); - tzone = "Z"; - } - - if (drv_data->mutex) { - gs_mutex_lock(drv_data->mutex); - } - { - fprintf(drv_data->fp, "%04d-%02d-%02d %02d:%02d:%02d.%06"PRIu32"%s %c %s: ", - result.tm_year + 1900, result.tm_mon + 1, result.tm_mday, - result.tm_hour, result.tm_min, result.tm_sec, - ts->tv_nsec / 1000, tzone, clevel, group->name); - vfprintf(drv_data->fp, format, my_va); - fprintf(drv_data->fp, "\r\n"); - fflush(drv_data->fp); - } - if (drv_data->mutex) { - gs_mutex_unlock(drv_data->mutex); - } - - va_end(my_va); -} - -static void gs_log_simple_file_append_info(gs_log_appender_t *appender, char *info_str, uint8_t str_size) -{ - if (!info_str) { - return; - } - - const gs_log_appender_simple_file_config_t *config = appender->drv_config; - snprintf(info_str, str_size, "Writes to file \"%s\"", config->filename); -} - -const gs_log_appender_driver_t gs_log_appender_simple_file_driver = { - .init = gs_log_simple_file_init, - .append = gs_log_simple_file_append, - .append_isr = 0, - .info = gs_log_simple_file_append_info, -}; - -#endif diff --git a/gomspace/libutil/src/log/commands.c b/gomspace/libutil/src/log/commands.c deleted file mode 100644 index 85ac7ae5..00000000 --- a/gomspace/libutil/src/log/commands.c +++ /dev/null @@ -1,392 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include "local.h" -#include - - -// iterator context -typedef struct { - gs_command_context_t * ctx; - gs_log_group_t * first; - gs_log_appender_t * first_appender; - bool completer; - bool detailed; -} iter_group_t; - -#define FORMAT_BUF_SIZE 10 -static const char * format_mask(uint8_t mask, char * buf) -{ - snprintf(buf, FORMAT_BUF_SIZE, "%c%c%c%c%c%c", - (mask & LOG_ERROR_MASK) ? 'E' : '.', - (mask & LOG_WARNING_MASK) ? 'W' : '.', - (mask & LOG_NOTICE_MASK) ? 'N' : '.', - (mask & LOG_INFO_MASK) ? 'I' : '.', - (mask & LOG_DEBUG_MASK) ? 'D' : '.', - (mask & LOG_TRACE_MASK) ? 'T' : '.'); - return buf; -} - -static bool iter_print_group_appenders(void * ctx_in, gs_log_appender_t * appender) -{ - gs_bytebuffer_t *bb = ctx_in; - gs_bytebuffer_printf(bb, "%s,", appender->name); - return true; -} - -static bool iter_print_group(void * ctx_in, gs_log_group_t * group) -{ - iter_group_t * ctx = ctx_in; - char level_mask[FORMAT_BUF_SIZE]; - if (!ctx->completer) { - char appender_str[128] = "\0"; - gs_bytebuffer_t bb; - gs_bytebuffer_init(&bb, appender_str, sizeof(appender_str)); - gs_log_group_appender_iterate(group, &bb, iter_print_group_appenders); - if (ctx->detailed) { - gs_command_set_output_printf(ctx->ctx, group->name, "category", "0x%08x", group->category); - gs_command_set_output_printf(ctx->ctx, group->name, "mask", "%-6s (0x%02x)", format_mask(group->mask, level_mask), group->mask); - gs_command_set_output_printf(ctx->ctx, group->name, "appenders", appender_str); - } else { - gs_command_set_output_printf(ctx->ctx, NULL, NULL, "%-15s %-6s %s", group->name, format_mask(group->mask, level_mask), appender_str); - } - } else { - fprintf(ctx->ctx->out, " %-15s %-6s\r\n", - group->name, - format_mask(group->mask, level_mask)); - } - return true; -} - -static int cmd_log_group_list(gs_command_context_t * ctx) -{ - iter_group_t iter = {.ctx = ctx, .completer = false}; - - if (ctx->argc > 1) { - iter.detailed = true; - gs_log_group_iterate(ctx->argv[1], &iter, iter_print_group); - } else { - fprintf(ctx->out, "Group Mask Appenders\r\n"); - gs_log_group_iterate("*", &iter, iter_print_group); - } - return GS_OK; -} - -static bool iter_print_appender(void * ctx_in, gs_log_appender_t * appender) -{ - iter_group_t * ctx = ctx_in; - char level_mask[FORMAT_BUF_SIZE]; - if (!ctx->completer) { - if (ctx->detailed) { - gs_command_set_output_printf(ctx->ctx, appender->name, "mask", "%-6s (0x%02x)", format_mask(appender->mask, level_mask), appender->mask); - - if (appender->drv->info) { - char info_str[100]; - appender->drv->info(appender, info_str, sizeof(info_str)); - gs_command_set_output(ctx->ctx, appender->name, "info", info_str); - } - } else { - gs_command_set_output_printf(ctx->ctx, NULL, NULL, "%-15s %-6s", appender->name, format_mask(appender->mask, level_mask)); - } - } else { - fprintf(ctx->ctx->out, " %-15s %-6s\r\n", - appender->name, - format_mask(appender->mask, level_mask)); - } - return true; -} - -static int cmd_log_appender_list(gs_command_context_t * ctx) -{ - iter_group_t iter = {.ctx = ctx, .completer = false}; - - if (ctx->argc > 1) { - iter.detailed = true; - gs_log_appender_iterate(ctx->argv[1], &iter, iter_print_appender); - } else { - fprintf(ctx->out, "Appender Mask\r\n"); - gs_log_appender_iterate("*", &iter, iter_print_appender); - } - return GS_OK; -} - -typedef gs_error_t (*log_get_mask_t)(const char *name, uint8_t* mask); -typedef gs_error_t (*log_set_mask_t)(const char *name, uint8_t mask); - -static int cmd_log_mask_handler(gs_command_context_t * ctx, log_get_mask_t get_mask, log_set_mask_t set_mask) -{ - /* strtok writes to the string, so we need to duplicate it to avoid writing to read-only memory */ - char strbuf[100]; - GS_STRNCPY(strbuf, ctx->argv[1]); - - char * saveptr = NULL; - char * token = strtok_r(strbuf, ",", &saveptr); - gs_error_t error = GS_OK; - while (token && (error == GS_OK)) { - - uint8_t old_mask = 0; - if (gs_log_is_group_all(token) == false) { - error = get_mask(token, &old_mask); - } - if (error == GS_OK) { - uint8_t new_mask = 0; - error = gs_log_string_to_mask(ctx->argv[2], old_mask, &new_mask); - if (error == GS_OK) { - error = set_mask(token, new_mask); - } - } - - token = strtok_r(NULL, ",", &saveptr); - } - - return error; -} - -static int cmd_log_group_mask(gs_command_context_t * ctx) -{ - return cmd_log_mask_handler(ctx, gs_log_group_get_level_mask, gs_log_group_set_level_mask); -} - -static int cmd_log_appender_mask(gs_command_context_t * ctx) -{ - return cmd_log_mask_handler(ctx, gs_log_appender_get_level_mask, gs_log_appender_set_level_mask); -} - - -#ifndef __AVR__ -static bool iter_log_completer(void *ctx_in, gs_log_group_t * group) -{ - iter_group_t * ctx = ctx_in; - unsigned int hits = gs_command_completer_add_token(ctx->ctx, group->name, false); - if (hits == 1) { - ctx->first = group; - } else { - if (hits == 2) { - fprintf(ctx->ctx->out, "\r\n"); - iter_print_group(ctx, ctx->first); - } - iter_print_group(ctx, group); - } - return true; -} - -static gs_error_t cmd_log_group_completer(gs_command_context_t * ctx, int arg_to_complete) -{ - if (arg_to_complete == 1) { - iter_group_t iter = {.ctx = ctx, .completer = true}; - char name[50]; - snprintf(name, sizeof(name), "%s*", (ctx->argc > 1) ? ctx->argv[1] : ""); - gs_log_group_iterate(name, &iter, iter_log_completer); - return GS_OK; - } - return GS_ERROR_AMBIGUOUS; -} - -static bool iter_log_appender_completer(void *ctx_in, gs_log_appender_t * appender) -{ - iter_group_t * ctx = ctx_in; - unsigned int hits = gs_command_completer_add_token(ctx->ctx, appender->name, false); - if (hits == 1) { - ctx->first_appender = appender; - } else { - if (hits == 2) { - fprintf(ctx->ctx->out, "\r\n"); - iter_print_appender(ctx, ctx->first_appender); - } - iter_print_appender(ctx, appender); - } - return true; -} - -static gs_error_t cmd_log_appender_completer(gs_command_context_t * ctx, int arg_to_complete) -{ - if (arg_to_complete == 1) { - iter_group_t iter = {.ctx = ctx, .completer = true}; - char name[50]; - snprintf(name, sizeof(name), "%s*", (ctx->argc > 1) ? ctx->argv[1] : ""); - gs_log_appender_iterate(name, &iter, iter_log_appender_completer); - return GS_OK; - } - return GS_ERROR_AMBIGUOUS; -} -#endif - -typedef struct { - gs_command_context_t *cmd_ctx; - unsigned int count; -} hist_ctx_t; - -static bool appender_history_iter(void *ctx, gs_log_level_t level, const gs_timestamp_t *ts, const char *group, const char *msg) -{ - hist_ctx_t * hist_ctx = ctx; - - /* Break iteration if history record count is reached. */ - if (hist_ctx->count-- == 0) { - return false; - } - - gs_command_set_output_printf(hist_ctx->cmd_ctx, NULL, NULL, - "%s%04"PRIu32".%06"PRIu32" %c %s: %s%s", - gs_log_level_to_color_begin(level), - ts->tv_sec, ts->tv_nsec/1000, - gs_log_level_to_char(level), - group, - msg, - gs_log_level_to_color_end()); - - return true; -} - -static int cmd_log_appender_hist(gs_command_context_t * ctx) -{ - hist_ctx_t hist_ctx = {.cmd_ctx = ctx, .count = 20}; - if (ctx->argc == 3) { - hist_ctx.count = atoi(ctx->argv[2]); - } - - return gs_log_appender_history_iterate(ctx->argv[1], &hist_ctx, appender_history_iter); -} - - -static bool iter_log_group_find(void* ctx_in, gs_log_group_t *group) -{ - gs_log_group_t **grp = ctx_in; - *grp = group; - return false; -} - -static int cmd_log_insert(gs_command_context_t * ctx) -{ - gs_log_group_t *log_group = NULL; - gs_error_t error = gs_log_group_iterate(ctx->argv[1], &log_group, iter_log_group_find); - if (error != GS_OK) { - return error; - } - - gs_log_level_t level; - error = gs_log_string_to_level(ctx->argv[2], &level); - if (error == GS_OK) { - gs_log(level, log_group, GS_PGM_STR("%s"), ctx->argv[3]); - } - - return error; -} - -static int cmd_log_color(gs_command_context_t * ctx) -{ - bool color; - gs_error_t error = gs_string_to_bool(ctx->argv[1], &color); - if (error == GS_OK) { - gs_log_set_print_color(color); - } - - return error; -} - -static const gs_command_t GS_COMMAND_SUB cmd_log_group_cmds[] = { - { - .name = "list", - .help = "list log groups", - .usage = "[group]", -#ifndef __AVR__ - .completer = cmd_log_group_completer, -#endif - .handler = cmd_log_group_list, - .mandatory_args = GS_COMMAND_NO_ARGS, - .optional_args = 1, - },{ - .name = "mask", - .help = "Set log group mask(s): e|w|i|d|t|stand|all|non", - .usage = "[,group] <[+-]level>[,level]", -#ifndef __AVR__ - .completer = cmd_log_group_completer, -#endif - .handler = cmd_log_group_mask, - .mandatory_args = 2, - },{ - .name = "insert", - .help = "Log message", - .usage = " ", -#ifndef __AVR__ - .completer = cmd_log_group_completer, -#endif - .handler = cmd_log_insert, - .mandatory_args = 3, - },{ - .name = "color", - .help = "Enable/disable color logs (stdout)", - .usage = "", - .handler = cmd_log_color, - .mandatory_args = 1, - } -}; - -static const gs_command_t GS_COMMAND_SUB cmd_log_appender_cmds[] = { - { - .name = "list", - .help = "list log appenders", - .usage = "[appender]", -#ifndef __AVR__ - .completer = cmd_log_appender_completer, -#endif - .handler = cmd_log_appender_list, - .mandatory_args = GS_COMMAND_NO_ARGS, - .optional_args = 1, - }, { - .name = "mask", - .help = "Set log appender mask(s): e|w|i|d|t|stand|all|non", - .usage = "[,appender] <[+-]level>[,level]", -#ifndef __AVR__ - .completer = cmd_log_appender_completer, -#endif - .handler = cmd_log_appender_mask, - .mandatory_args = 2, - }, { - .name = "hist", - .help = "Show log appender history", - .usage = " [cnt]", -#ifndef __AVR__ - .completer = cmd_log_appender_completer, -#endif - .handler = cmd_log_appender_hist, - .mandatory_args = 1, - .optional_args = 1, - } -}; - -static const gs_command_t GS_COMMAND_SUB cmd_log_cmds[] = { - { - .name = "group", - .help = "log group commands", - .chain = GS_COMMAND_INIT_CHAIN(cmd_log_group_cmds), - }, { - .name = "appender", - .help = "log appender commands", - .chain = GS_COMMAND_INIT_CHAIN(cmd_log_appender_cmds), - } -}; - -static const gs_command_t GS_COMMAND_ROOT cmd_log[] = { - { - .name = "log", - .help = "log: Log system", - .chain = GS_COMMAND_INIT_CHAIN(cmd_log_cmds) - },{ - .name = "debug", - .help = "Set Log group mask(s): e|w|n|i|d|t|stand|all|off", - .usage = "[,group] <[+-]level>[,level]", -#ifndef __AVR__ - .completer = cmd_log_group_completer, -#endif - .handler = cmd_log_group_mask, - .mandatory_args = 2, - }, -}; - -gs_error_t gs_log_register_commands(void) -{ - return GS_COMMAND_REGISTER(cmd_log); -} diff --git a/gomspace/libutil/src/log/local.h b/gomspace/libutil/src/log/local.h deleted file mode 100644 index 654577c8..00000000 --- a/gomspace/libutil/src/log/local.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -struct gs_log_list { - union { - gs_log_group_t * group; - gs_log_appender_t *appender; - } data; - struct gs_log_list * next; -}; - -/** - De-register appender for the given log group. - - @note The de-register function is not safe when logging is active, this function - is mostly for test and should only be used in product code with extreme caution. - If logging is still not active, this function can be used safely. - - @param[in] group_name Name of the group. - @param[in] appender_name Name of appender to de-register for this group. - @return gs_error_t -*/ -gs_error_t gs_log_group_deregister_appender(const char * group_name, const char * appender_name); - -bool gs_log_is_group_all(const char * name); diff --git a/gomspace/libutil/src/log/log.c b/gomspace/libutil/src/log/log.c deleted file mode 100644 index 16865900..00000000 --- a/gomspace/libutil/src/log/log.c +++ /dev/null @@ -1,705 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include "local.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "../lock.h" -#include - -#define MASK_SET 0 -#define MASK_AND 1 -#define MASK_OR 2 - -// use color in log print -static bool g_print_no_color; - -// Log Group list -GS_STATIC gs_log_list_t g_log_groups = { .data = { .group = 0} }; - -// Log Appender list -GS_STATIC gs_log_list_t g_log_appenders = { .data = { .appender = 0} }; - -// Root Log Appenders - used for holding a appender list -GS_STATIC gs_log_group_t g_log_group_root = {.name = GS_LOG_GROUP_ROOT}; - -// Default log group - always present. -GS_LOG_GROUP(LOG_DEFAULT, "default", GS_LOG_CAT_DEFAULT, LOG_ERROR_MASK | LOG_WARNING_MASK | LOG_NOTICE_MASK | LOG_INFO_MASK); - -bool gs_log_is_group_all(const char * name) -{ - return (name && ((strcasecmp(name, "*") == 0) || (strcasecmp(name, "all") == 0))); -} - -static bool iter_set_level_mask(void * ctx_in, gs_log_group_t * group) -{ - uint8_t * level_mask = ctx_in; - group->mask = *level_mask; - return true; -} - -gs_error_t gs_log_group_set_level_mask(const char * group_name, uint8_t mask) -{ - if (gs_string_empty(group_name)) { - return GS_ERROR_HANDLE; - } - - return gs_log_group_iterate(group_name, &mask, iter_set_level_mask); -} - -static bool iter_get_level_mask(void * ctx_in, gs_log_group_t * group) -{ - uint8_t * level_mask = ctx_in; - *level_mask = group->mask; - return true; -} - -gs_error_t gs_log_group_get_level_mask(const char * group_name, uint8_t *mask) -{ - if (gs_string_empty(group_name)) { - return GS_ERROR_HANDLE; - } - - gs_error_t error = gs_log_group_iterate(group_name, mask, iter_get_level_mask); - return error; -} - -gs_error_t gs_log_string_to_level(const char * str, gs_log_level_t * return_level) -{ - if (gs_string_empty(str)) { - return GS_ERROR_ARG; - } - - const size_t len = strlen(str); - gs_log_level_t level; - - if (strncasecmp(str, "trace", len) == 0) { - level = LOG_TRACE; - } else if (strncasecmp(str, "debug", len) == 0) { - level = LOG_DEBUG; - } else if (strncasecmp(str, "informational", len) == 0) { - level = LOG_INFO; - } else if (strncasecmp(str, "notice", len) == 0) { - level = LOG_NOTICE; - } else if (strncasecmp(str, "warning", len) == 0) { - level = LOG_WARNING; - } else if (strncasecmp(str, "error", len) == 0) { - level = LOG_ERROR; - } else { - return GS_ERROR_DATA; - } - - if (return_level) { - *return_level = level; - } - - return GS_OK; -} - -char gs_log_level_to_char(gs_log_level_t level) -{ - switch (level) { - case LOG_TRACE: return 'T'; - case LOG_DEBUG: return 'D'; - case LOG_INFO: return 'I'; - case LOG_NOTICE: return 'N'; - case LOG_WARNING: return 'W'; - case LOG_ERROR: return 'E'; - default: return '?'; - } -} - -gs_error_t gs_log_string_to_mask(const char *str, uint8_t old, uint8_t * return_mask) -{ - GS_CHECK_ARG(gs_string_empty(str) == false); - - char strbuf[50]; // copy buf, coz strtok will mess it up - GS_STRNCPY(strbuf, str); - - char *saveptr = NULL; - char *token = strtok_r(strbuf, ",", &saveptr); - while (token) { - // check for +xxx (add), -xxxx (remove), xxxx (set) - int op = MASK_SET; - if (*token == '+') { - op = MASK_OR; - token++; - } else if (*token == '-') { - op = MASK_AND; - token++; - } - - const unsigned int token_length = strlen(token); - if (token_length < 1) { - return GS_ERROR_DATA; - } - - /* Check mask */ - uint8_t mask; - gs_log_level_t level; - if (gs_log_string_to_level(token, &level) == GS_OK) { - // actual level - if (op == MASK_SET) { - // set all level bits equal or lover - mask = LOG_ALL_MASK & ~((1 << level) - 1); - } else { - mask = (1 << level); - } - } else if (!strncasecmp(token, "default", token_length)) { // legacy - conflicts with 'de(bug)' - mask = LOG_DEFAULT_MASK; - op = MASK_SET; - } else if (!strncasecmp(token, "standard", token_length)) { - mask = LOG_DEFAULT_MASK; - op = MASK_SET; - } else if (!strncasecmp(token, "all", token_length)) { - mask = LOG_ALL_MASK; - op = MASK_SET; - } else if (!strncasecmp(token, "off", token_length)) { - mask = 0; - op = MASK_SET; - } else if (!strncasecmp(token, "none", token_length)) { // legacy - conflicts with 'no(tice)' - mask = 0; - op = MASK_SET; - } else if (gs_string_to_uint8(token, &mask) == GS_OK) { - op = MASK_SET; - } else { - return GS_ERROR_DATA; - } - - /* Apply operation */ - if (op == MASK_OR) { - old |= mask; - } else if (op == MASK_AND) { - old &= ~mask; - } else if (op == MASK_SET) { - old = mask; - } - - token = strtok_r(NULL, ",", &saveptr); - } - - if (return_mask) { - *return_mask = old; - } - - return GS_OK; -} - -/** - All functions must call this initialization function, to ensure log is initialized. -*/ -static gs_error_t gs_log_init_internal(void) -{ - if (g_log_groups.data.group == NULL) { - return gs_log_init(true); - } - return GS_OK; -} - -gs_error_t gs_log_group_iterate(const char * group_name, void * ctx, gs_log_group_iterator_t iter) -{ - const bool all = (gs_string_empty(group_name) || gs_log_is_group_all(group_name)); - bool found = false; - - for (gs_log_list_t *node = &g_log_groups; node; node = node->next) { - if (node->data.group) { - if (all || gs_string_match(group_name, node->data.group->name)) { - found = true; - bool cont = iter(ctx, node->data.group); - if (cont == false) { - return GS_OK; - } - } - } - } - - return found ? GS_OK : GS_ERROR_NOT_FOUND; -} - -static gs_error_t gs_log_group_register_internal(gs_log_group_t *group) -{ - // check if appender is already in the list and find last node - gs_log_list_t * parent = &g_log_groups; // there will always be at least 1 group -> default - for (; parent; parent = parent->next) { - if ((parent->data.group == group) || (strcasecmp(group->name, parent->data.group->name) == 0)) { - return GS_ERROR_EXIST; - } - if (parent->next == NULL) { - break; - } - } - - gs_log_list_t * new_group_node = calloc(1, sizeof(*new_group_node)); - if (new_group_node == NULL) { - return GS_ERROR_ALLOC; - } - - new_group_node->data.group = group; - - // add to list - must be done last, iterating list can be done without locking - parent->next = new_group_node; - - return GS_OK; -} - -gs_error_t gs_log_group_register(gs_log_group_t *group) -{ - GS_CHECK_ARG(group != NULL); - GS_CHECK_ARG(gs_string_empty(group->name) == false); - - gs_log_init_internal(); - - gs_lock_lock(); - gs_error_t error = gs_log_group_register_internal(group); - gs_lock_unlock(); - - return error; -} - - -bool gs_log_group_is_level_enabled(gs_log_group_t *group, gs_log_level_t level) -{ - return ((group->mask & level) > 0); -} - -gs_error_t gs_log_appender_iterate(const char * name, void * ctx, gs_log_appender_iterator_t iter) -{ - const bool all = (gs_string_empty(name) || gs_log_is_group_all(name)); - bool found = false; - - /* Iterate the dynamically registered log appenders: */ - for (gs_log_list_t *node = &g_log_appenders; node; node = node->next) { - if (node->data.appender) { - if (all || gs_string_match(name, node->data.appender->name)) { - found = true; - bool cont = iter(ctx, node->data.appender); - if (cont == false) { - return GS_OK; - } - } - } - } - - return found ? GS_OK : GS_ERROR_NOT_FOUND; -} - -struct gs_log_history_ctx { - gs_log_record_iterator_t iter; - void *ctx; -}; - -static bool gs_log_history_iterator(void* ctx, gs_log_appender_t *appender) -{ - struct gs_log_history_ctx *hist_ctx = ctx; - if (appender->drv->hist) { - appender->drv->hist(appender, hist_ctx->ctx, hist_ctx->iter); - } - return true; -} - -gs_error_t gs_log_appender_history_iterate(const char * name, void * ctx, gs_log_record_iterator_t iter) -{ - struct gs_log_history_ctx hist_ctx = {.iter=iter, .ctx = ctx}; - - return gs_log_appender_iterate(name, &hist_ctx, gs_log_history_iterator); -} - -static gs_error_t gs_log_appender_register_internal(gs_log_appender_t *appender) -{ - if (g_log_appenders.data.appender == NULL) { - // first appender - g_log_appenders.data.appender = appender; - - if (appender->drv->init) { - gs_error_t error = appender->drv->init(appender); - if (error) { - g_log_appenders.data.appender = NULL; - return error; - } - } - - return GS_OK; - } - - // check if appender is already in the list and find last node - gs_log_list_t * parent = &g_log_appenders; - for (; parent; parent = parent->next) { - if ((parent->data.appender == appender) || (strcasecmp(parent->data.appender->name, appender->name) == 0)) { - return GS_ERROR_EXIST; - } - if (parent->next == NULL) { - break; - } - } - - gs_log_list_t *new_appender = calloc(1, sizeof(*new_appender)); - if (new_appender == NULL) { - return GS_ERROR_ALLOC; - } - - new_appender->data.appender = appender; - - if (appender->drv->init) { - gs_error_t error = appender->drv->init(appender); - if (error) { - free(new_appender); - return error; - } - } - - // add to list - must be done last, iterating list can be done without locking - parent->next = new_appender; - - return GS_OK; -} - -gs_error_t gs_log_appender_register(gs_log_appender_t *appender) -{ - GS_CHECK_ARG(appender != NULL); - GS_CHECK_ARG(gs_string_empty(appender->name) == false); - GS_CHECK_ARG(appender->drv != NULL); - GS_CHECK_ARG(appender->drv->append != NULL); - - gs_log_init_internal(); - - gs_lock_lock(); - gs_error_t error = gs_log_appender_register_internal(appender); - gs_lock_unlock(); - - return error; -} - -gs_error_t gs_log_appender_add(gs_log_appender_t *appender, uint16_t count) -{ - GS_CHECK_ARG(appender != NULL); - GS_CHECK_ARG(count != 0); - - gs_error_t error = GS_OK; - for (uint16_t i = 0; i < count; i++) { - gs_error_t tmp_error = gs_log_appender_register(&appender[i]); - if ((error == GS_OK) && tmp_error) { - error = tmp_error; - } - } - - return error; -} - -static bool iter_set_appender_level_mask(void * ctx_in, gs_log_appender_t * appender) -{ - uint8_t * level_mask = ctx_in; - appender->mask = *level_mask; - return true; -} - -gs_error_t gs_log_appender_set_level_mask(const char * appender_name, uint8_t mask) -{ - if (gs_string_empty(appender_name)) { - return GS_ERROR_HANDLE; - } - - return gs_log_appender_iterate(appender_name, &mask, iter_set_appender_level_mask); -} - -static bool iter_get_appender_level_mask(void * ctx_in, gs_log_appender_t * appender) -{ - uint8_t * level_mask = ctx_in; - *level_mask = appender->mask; - return true; -} - -gs_error_t gs_log_appender_get_level_mask(const char * appender_name, uint8_t *mask) -{ - if (gs_string_empty(appender_name)) { - return GS_ERROR_HANDLE; - } - - return gs_log_appender_iterate(appender_name, mask, iter_get_appender_level_mask); -} - -// Appender register/de-register iterator context -typedef struct { - gs_log_appender_t *appender; - gs_error_t ret; -} iter_group_appender_t; - -static bool iter_log_appender_add(void *ctx, gs_log_group_t *group) -{ - iter_group_appender_t* in = ctx; - - gs_log_list_t * last_elem = group->appenders; - for (gs_log_list_t *elem = group->appenders; elem; elem = elem->next) { - last_elem = elem; - if (elem->data.appender == in->appender) { - in->ret = GS_ERROR_EXIST; - return true; - } - } - - in->ret = GS_ERROR_ALLOC; - gs_log_list_t *new_appender = calloc(1, sizeof(*new_appender)); - if (new_appender) { - new_appender->data.appender = in->appender; - new_appender->next = 0; - if (last_elem != NULL) { - last_elem->next = new_appender; - } else { - group->appenders = new_appender; - } - in->ret = GS_OK; - } - - return true; -} - -gs_error_t gs_log_group_register_appender(const char * group_name, const char * appender_name) -{ - gs_log_appender_t *appender = NULL; - for (gs_log_list_t *elem = &g_log_appenders; elem; elem = elem->next) { - if (elem->data.appender) { - if (strcasecmp(elem->data.appender->name, appender_name) == 0) { - appender = elem->data.appender; - break; - } - } - } - if (NULL == appender) { - return GS_ERROR_NOT_FOUND; - } - - iter_group_appender_t ctx = {.appender = appender, .ret = GS_OK}; - - gs_error_t ret = GS_OK; - if (strcasecmp(group_name, GS_LOG_GROUP_ROOT) == 0) { - iter_log_appender_add(&ctx, &g_log_group_root); - } else { - ret = gs_log_group_iterate(group_name, &ctx, iter_log_appender_add); - } - - if (ret == GS_OK) { - ret = ctx.ret; - } - - return ret; -} - -static bool iter_log_appender_remove(void *ctx, gs_log_group_t *group) -{ - iter_group_appender_t* in = ctx; - in->ret = GS_ERROR_NOT_FOUND; - - gs_log_list_t * last_elem = group->appenders; - for (gs_log_list_t *elem = group->appenders; elem; elem = elem->next) { - if (elem->data.appender == in->appender) { - if (elem == group->appenders) { - group->appenders = elem->next; - } - last_elem->next = elem->next; - free(elem); - in->ret = GS_OK; - break; - } - last_elem = elem; - } - - return true; -} - -gs_error_t gs_log_group_deregister_appender(const char * group_name, const char * appender_name) -{ - gs_log_appender_t *appender = NULL; - for (gs_log_list_t *elem = &g_log_appenders; elem; elem = elem->next) { - if (elem->data.appender) { - if (strcasecmp(elem->data.appender->name, appender_name) == 0) { - appender = elem->data.appender; - break; - } - } - } - if (NULL == appender) { - return GS_ERROR_NOT_FOUND; - } - - iter_group_appender_t ctx = {.appender = appender, .ret = GS_OK}; - - gs_error_t ret; - if (strcasecmp(group_name, GS_LOG_GROUP_ROOT) == 0) { - ret = iter_log_appender_remove(&ctx, &g_log_group_root); - } else { - ret = gs_log_group_iterate(group_name, &ctx, iter_log_appender_remove); - } - - if (ret == GS_OK) { - ret = ctx.ret; - } - - return ret; -} - -gs_error_t gs_log_group_appender_iterate(gs_log_group_t * group, void * ctx, gs_log_appender_iterator_t iter) -{ - GS_CHECK_ARG(group != NULL); - - bool found = false; - for (gs_log_list_t *elem = group->appenders; elem; elem = elem->next) { - found = true; - iter(ctx, elem->data.appender); - } - - /* Iterate root appenders */ - for (gs_log_list_t *elem = g_log_group_root.appenders; elem; elem = elem->next) { - found = true; - iter(ctx, elem->data.appender); - } - - return found ? GS_OK : GS_ERROR_NOT_FOUND; -} - -static inline void gs_log_process_appenders(const gs_log_list_t * it, gs_log_level_t level, - const gs_log_group_t * group, gs_timestamp_t* ts, bool from_isr, const char * format, va_list va) -{ - for (; it; it = it->next) { - gs_log_appender_t* appender = it->data.appender; - - if ((appender->mask & (1 << level)) == 0) { - continue; - } - - if (from_isr == false) { - // log from none ISR context - appender->drv->append(appender, level, group, ts, format, va); - - } else if (appender->drv->append_isr) { - // log from ISR (Interrupt Service Routine) context - appender->drv->append_isr(appender, level, group, ts, format, va); - } - } -} - -static inline void gs_log_common_va(gs_log_level_t level, gs_log_group_t * group, bool from_isr, const char * format, va_list va) -{ - // get time as soon as possible - gs_timestamp_t ts; - gs_clock_get_time(&ts); - - // only needed if someone call function directly - otherwise the log macro has set it to a valid group - if (group == NULL) { - group = LOG_DEFAULT; - } - - // check level mask for current group (this will nearly always be true, because the log macro has done the checking - if (group->mask & (1 << level)) { - - // legacy - if log hasn't been initialized, this will initialize with console output enabled. - gs_log_init_internal(); - - if (group->appenders) { - gs_log_process_appenders(group->appenders, level, group, &ts, from_isr, format, va); - } - - if (group->additivity) { - /* Call root appenders */ - gs_log_process_appenders(g_log_group_root.appenders, level, group, &ts, from_isr, format, va); - } - } -} - -void gs_log(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) -{ - va_list va_args; - va_start(va_args, format); - gs_log_common_va(level, group, false, format, va_args); - va_end(va_args); -} - -void gs_log_isr(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) -{ - va_list va_args; - va_start(va_args, format); - gs_log_common_va(level, group, true, format, va_args); - va_end(va_args); -} - -void gs_log_va(gs_log_level_t level, gs_log_group_t * group, const char * format, va_list args) -{ - gs_log_common_va(level, group, false, format, args); -} - -void gs_log_set_print_color(bool color) -{ - g_print_no_color = (color == false); -} - -const char * gs_log_level_to_color_begin(gs_log_level_t level) -{ - if (g_print_no_color) { - return ""; - } - - switch (level) { - case LOG_ERROR: return "\E[1;31m"; // Red - case LOG_WARNING: return "\E[0;33m"; // Yellow - case LOG_NOTICE: - case LOG_INFO: return "\E[0;32m"; // Green - case LOG_DEBUG: return "\E[0;34m"; // Blue - default: - case LOG_TRACE: return "\E[0;35m"; // Magenta - } -} - -const char * gs_log_level_to_color_end(void) -{ - if (g_print_no_color) { - return ""; - } - - return "\E[0m"; -} - -uint8_t gs_log_level_to_mask(gs_log_level_t level) -{ - /* Enable all levels with priority above the set level */ - uint8_t level_mask = (0xFF << level) & LOG_ALL_MASK; - return level_mask; -} - -static bool iter_flush_appender(void * ctx_in, gs_log_appender_t * appender) -{ - if (appender->drv->flush) { - appender->drv->flush(appender); - } - return true; -} - -gs_error_t gs_log_appender_flush_all() -{ - return gs_log_appender_iterate("", NULL, iter_flush_appender); -} - -gs_error_t gs_log_init(bool with_console_appender) -{ - gs_error_t error = GS_OK; - - gs_lock_init(); // ignore result, this is the log system - - if (g_log_groups.data.group == NULL) { - - // default log group -> mark log as initialized - g_log_groups.data.group = LOG_DEFAULT; - - // register console log appender - if (with_console_appender) { - error = gs_log_appender_register(&gs_log_appender_console); - if (error == GS_OK) { - error = gs_log_group_register_appender(GS_LOG_GROUP_ROOT, gs_log_appender_console.name); - } - } - } - - return error; -} diff --git a/gomspace/libutil/src/rtc.c b/gomspace/libutil/src/rtc.c deleted file mode 100644 index 160df778..00000000 --- a/gomspace/libutil/src/rtc.c +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include - -static const gs_rtc_driver_t * rtc_driver; -static void * rtc_driver_data; - -gs_error_t gs_rtc_register(const gs_rtc_driver_t * driver, void * driver_data) -{ - rtc_driver = driver; - rtc_driver_data = driver_data; - return GS_OK; -} - -gs_error_t gs_rtc_supported(void) -{ - return rtc_driver ? GS_OK : GS_ERROR_NOT_SUPPORTED; -} - -gs_error_t gs_rtc_get_time(gs_timestamp_t * time) -{ - if (time == NULL) { - return GS_ERROR_ARG; - } - - if (rtc_driver && rtc_driver->get_time) { - return rtc_driver->get_time(rtc_driver_data, time); - } - return GS_ERROR_NOT_SUPPORTED; -} - -gs_error_t gs_rtc_set_time(const gs_timestamp_t * time) -{ - if (time == NULL) { - return GS_ERROR_ARG; - } - - if (rtc_driver && rtc_driver->set_time) { - return rtc_driver->set_time(rtc_driver_data, time); - } - return GS_ERROR_NOT_SUPPORTED; -} diff --git a/gomspace/libutil/src/stdio.c b/gomspace/libutil/src/stdio.c deleted file mode 100644 index c723f8fe..00000000 --- a/gomspace/libutil/src/stdio.c +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include - -gs_error_t gs_stdio_get(char * buf, size_t len) -{ - while (len > 0) { - int ch; - gs_error_t error = gs_stdio_getchar(&ch); - if (error) { - return error; - } - *buf++ = ch; - --len; - } - - return GS_OK; -} - -gs_error_t gs_stdio_put(const char * buf, size_t len, bool text) -{ - while (len > 0) { - if ((*buf == '\n') && text) { - gs_stdio_putchar('\r'); - } - gs_stdio_putchar(*buf++); - --len; - } - - return GS_OK; -} - -void gs_color_printf(gs_color_printf_t color_arg, const char * format, ...) -{ - va_list args; - va_start(args, format); - - if ((color_arg & GS_COLOR_ATTRS) == GS_COLOR_BOLD) { - printf("\033[1;"); - } else { - printf("\033[0;"); - } - - switch(color_arg & GS_COLOR_COLORS) { - case GS_COLOR_NONE: - printf("0m"); - break; - case GS_COLOR_BLACK: - printf("30m"); - break; - case GS_COLOR_RED: - printf("31m"); - break; - case GS_COLOR_GREEN: - printf("32m"); - break; - case GS_COLOR_YELLOW: - printf("33m"); - break; - case GS_COLOR_BLUE: - printf("34m"); - break; - case GS_COLOR_MAGENTA: - printf("35m"); - break; - case GS_COLOR_CYAN: - printf("36m"); - break; - case GS_COLOR_WHITE: - printf("37m"); - break; - default: - break; - } - - vprintf(format, args); - printf("\033[0m"); - - va_end(args); -} diff --git a/gomspace/libutil/src/string.c b/gomspace/libutil/src/string.c deleted file mode 100644 index 31419fd0..00000000 --- a/gomspace/libutil/src/string.c +++ /dev/null @@ -1,746 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include -#include -#if (__AVR__ == 0) -#include -#endif - -#ifndef GS_STRING_GET_SUBOPTION_UNIT_TEST -#define GS_STRING_GET_SUBOPTION_UNIT_TEST 0 -#endif - -const char * gs_string_skip_leading_spaces(const char * string) -{ - if (string) { - for (; *string == ' '; ++string); - } - return string; -} - -gs_error_t gs_string_to_int32(const char * string, int32_t * return_value) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (!(isdigit((int)string[0]) || (string[0] == '-'))) { - return GS_ERROR_DATA; - } - - int32_t tmp; - uint8_t base = 10; - - // check for hexadecimal notation - if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) - { - base = 16; - } - - const char *desired_end = string + strlen(string); - // The desired end should point to that last non-space char in the string - while ((isspace((int)desired_end[0]) || (desired_end[0] == '\0')) && (desired_end > string)) - { - desired_end--; - } - char *end; - gs_error_t err = GS_OK; - tmp = gs_string_strto32int(string, &end, base, &err); - if (err != GS_OK) - { - return err; - } - if (desired_end != end-1) - { - return GS_ERROR_DATA; - } - - if (return_value) - { - *return_value = tmp; - } - - return GS_OK; -} - -gs_error_t gs_string_to_int8(const char * string, int8_t * return_value) -{ - int32_t value; - gs_error_t error = gs_string_to_int32(string, &value); - if (error == GS_OK) { - if ((value >= INT8_MIN) && (value <= INT8_MAX)) { - if (return_value) { - *return_value = (int8_t) value; - } - } else { - error = GS_ERROR_OVERFLOW; - } - } - return error; -} - -gs_error_t gs_string_to_uint8(const char * string, uint8_t * return_value) -{ - uint32_t value; - gs_error_t error = gs_string_to_uint32(string, &value); - if (error == GS_OK) { - if (value <= UINT8_MAX) { - if (return_value) { - *return_value = (uint8_t) value; - } - } else { - error = GS_ERROR_OVERFLOW; - } - } - return error; -} - -gs_error_t gs_string_to_int16(const char * string, int16_t * return_value) -{ - int32_t value; - gs_error_t error = gs_string_to_int32(string, &value); - if (error == GS_OK) { - if ((value >= INT16_MIN) && (value <= INT16_MAX)) { - if (return_value) { - *return_value = (int16_t) value; - } - } else { - error = GS_ERROR_OVERFLOW; - } - } - return error; -} - -gs_error_t gs_string_to_uint16(const char * string, uint16_t * return_value) -{ - uint32_t value; - gs_error_t error = gs_string_to_uint32(string, &value); - if (error == GS_OK) { - if (value <= UINT16_MAX) { - if (return_value) { - *return_value = (uint16_t) value; - } - } else { - error = GS_ERROR_OVERFLOW; - } - } - return error; -} - -gs_error_t gs_string_to_uint32(const char * string, uint32_t * return_value) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (!isdigit((int)string[0])) { - return GS_ERROR_DATA; - } - - uint32_t tmp; - uint8_t base = 10; - - // check for hexadecimal notation - if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) - { - base = 16; - } - const char *desired_end = string + strlen(string); - // The desired end should point to that last non-space char in the string - while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) - { - desired_end--; - } - char *end; - gs_error_t err = GS_OK; - tmp = gs_string_strto32uint(string, &end, base, &err); - - if (err != GS_OK) - { - return err; - } - if (desired_end != end-1) - { - return GS_ERROR_DATA; - } - - - if (return_value) { - *return_value = tmp; - } - - return GS_OK; -} - -gs_error_t gs_string_to_uint64(const char * string, uint64_t * return_value) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (!isdigit((int)string[0])) - { - return GS_ERROR_DATA; - } - - uint64_t tmp; - uint8_t base = 10; - - // check for hexadecimal notation - if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) { - base = 16; - } - const char *desired_end = string + strlen(string); - // The desired end should point to that last non-space char in the string - while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) - { - desired_end--; - } - char *end; - gs_error_t err = GS_OK; - tmp = gs_string_strto64uint(string, &end, base, &err); - if (err != GS_OK) - { - return err; - } - - if (desired_end != end-1) - { - return GS_ERROR_DATA; - } - - - if (return_value) { - *return_value = tmp; - } - - return GS_OK; -} - -gs_error_t gs_string_to_int64(const char * string, int64_t * return_value) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (!(isdigit((int)string[0]) || (string[0] == '-'))) - { - return GS_ERROR_DATA; - } - - int64_t tmp; - uint8_t base = 10; - - // check for hexadecimal notation - if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) { - base = 16; - } - const char *desired_end = string + strlen(string); - // The desired end should point to that last non-space char in the string - while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) - { - desired_end--; - } - char *end; - gs_error_t err = GS_OK; - tmp = gs_string_strto64int(string, &end, base, &err); - if (err != GS_OK) - { - return err; - } - - if (desired_end != end-1) - { - return GS_ERROR_DATA; - } - - - if (return_value) { - *return_value = tmp; - } - - return GS_OK; -} - -gs_error_t gs_string_hex_to_uint32(const char * string, uint32_t * return_value) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (!isxdigit((int)string[0])) { - return GS_ERROR_DATA; - } - - const char *desired_end = string + strlen(string); - // The desired end should point to that last non-space char in the string - while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) - { - desired_end--; - } - char *end; - gs_error_t err = GS_OK; - uint32_t tmp = gs_string_strto32uint(string, &end, 16, &err); - - if (err != GS_OK) - { - return err; - } - if (desired_end != end-1) - { - return GS_ERROR_DATA; - } - - if (return_value) { - *return_value = tmp; - } - - return GS_OK; -} - -gs_error_t gs_string_hex_to_uint64(const char * string, uint64_t * return_value) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (!isxdigit((int)string[0])) - { - return GS_ERROR_DATA; - } - - const char *desired_end = string + strlen(string); - // The desired end should point to that last non-space char in the string - while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) - { - desired_end--; - } - char *end; - gs_error_t err = GS_OK; - uint64_t tmp = gs_string_strto64uint(string, &end, 16, &err); - if (err != GS_OK) - { - return err; - } - - if (desired_end != end-1) - { - return GS_ERROR_DATA; - } - - if (return_value) { - *return_value = tmp; - } - - return GS_OK; -} - -#if (__AVR__ == 0) -gs_error_t gs_string_to_float(const char * string, float * pvalue) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (gs_string_empty(string)) { - return GS_ERROR_DATA; - } - - // float strtof(const char *nptr, char **endptr); - char * endp = NULL; - float tmp = strtof(string, &endp); - //if ((endp == NULL) || (gs_string_empty(gs_string_skip_leading_spaces(endp)) == false) || (string == endp)) { - if ((endp == NULL) || (gs_string_empty(gs_string_skip_leading_spaces(endp)) == false) || (string == endp) || isinf(tmp)) { - return GS_ERROR_DATA; - } - - if (pvalue) { - *pvalue = tmp; - } - - return GS_OK; -} - -gs_error_t gs_string_to_double(const char * string, double * pvalue) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (gs_string_empty(string)) { - return GS_ERROR_DATA; - } - - // double strtod(const char *nptr, char **endptr); - char * endp = NULL; - double tmp = strtod(string, &endp); - if ((endp == NULL) || (gs_string_empty(gs_string_skip_leading_spaces(endp)) == false) || isinf(tmp)) { - return GS_ERROR_DATA; - } - - if (pvalue) { - *pvalue = tmp; - } - - return GS_OK; -} -#endif - -#define GS_STRING_BOOL_TRUE "true" -#define GS_STRING_BOOL_FALSE "false" - -const char * gs_string_from_bool(bool value) -{ - if (value) { - return GS_STRING_BOOL_TRUE; - } else { - return GS_STRING_BOOL_FALSE; - } -} - -gs_error_t gs_string_to_bool(const char * string, bool * return_value) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - if (string[0] == 0) { - return GS_ERROR_DATA; - } - - bool value = false; - if (strcasecmp(string, GS_STRING_BOOL_TRUE) == 0) { - value = true; - } else if (strcasecmp(string, GS_STRING_BOOL_FALSE) == 0) { - value = false; - } else if (strcasecmp(string, "on") == 0) { - value = true; - } else if (strcasecmp(string, "off") == 0) { - value = false; - } else if (strcasecmp(string, "1") == 0) { - value = true; - } else if (strcasecmp(string, "0") == 0) { - value = false; - } else if (strcasecmp(string, "yes") == 0) { - value = true; - } else if (strcasecmp(string, "no") == 0) { - value = false; - } else { - return GS_ERROR_DATA; - } - - if (return_value) { - *return_value = value; - } - - return GS_OK; -} - -char * gs_string_bytesize(long n, char *buf, size_t buf_size) -{ - char postfix = 'B'; - double size = (double) n; - if (n >= 1048576) { - size /= 1048576.0; - postfix = 'M'; - } else if (n >= 1024) { - size /= 1024.0; - postfix = 'K'; - } - snprintf(buf, buf_size, "%.1f%c", size, postfix); - return buf; -} - -gs_error_t gs_string_to_pointer(const char * string, void ** value) -{ -#if __LP64__ - uint64_t tmp; - gs_error_t error = gs_string_to_uint64(string, &tmp); - if ((error == GS_OK) && value) { - *value = GS_TYPES_UINT2PTR(tmp); - } - return error; -#else - uint32_t tmp; - gs_error_t error = gs_string_to_uint32(string, &tmp); - if ((error == GS_OK) && value) { - *value = GS_TYPES_UINT2PTR(tmp); - } - return error; -#endif -} - -bool gs_string_empty(const char * string) -{ - if ((string == NULL) || (string[0] == 0)) { - return true; - } - return false; -} - -bool gs_string_match(const char * pattern, const char * string) -{ - if (string && pattern) { - while (*string || *pattern) { - int p = tolower((int)*pattern); - int s = tolower((int)*string); - - if (*pattern == '*') { - ++pattern; - p = tolower((int)*pattern); - for (; *string && (tolower((int)*string) != p); ++string); - s = tolower((int)*string); - } - - if (s != p) { - return false; - } - - if (s) { - ++string; - } - if (p) { - ++pattern; - } - } - if ((*string == 0) && (*pattern == 0)) { - return true; - } - } - return false; -} - -bool gs_string_has_wildcards(const char * string) -{ - if (strchr(string, '*')) { - return true; - } - // future wildcard - //if (strchr(str, '?')) { - // return true; - //} - return false; -} - -void gs_string_trim(char * buffer, size_t buffer_size) -{ - // remove trailing stuff - int len = strnlen(buffer, buffer_size); - if (len) { - for (int i = (len - 1); i >= 0; --i) { - if (isspace((int)buffer[i])) { - buffer[i] = 0; - } else { - break; - } - } - } - - char * start; - for (start = buffer; *start && isspace((int)*start); ++start); - if (*start && (start != buffer)) { - // move chars up - for (; *start; ++start) { - *buffer++ = *start; - } - *buffer = 0; - } -} - -bool gs_string_endswith(const char * string, const char * endswith) -{ - if (string == NULL || endswith == NULL) { - return false; - } - - int str_len = strlen(string); - int endswith_len = strlen(endswith); - - return (str_len >= endswith_len) && - (0 == strcmp(string + (str_len-endswith_len), endswith)); -} - -static size_t suboption_len(const char * ref, const char * end) -{ - if (ref) { - size_t len = (end) ? ((size_t)(end - ref)) : strlen(ref); - for (; len && (ref[len - 1] == ' '); --len); - return len; - } - return 0; -} - -static gs_error_t suboption_copy(const char * data, size_t len, char * buf, size_t buf_size, gs_error_t error) -{ - if (len >= buf_size) { - error = GS_ERROR_OVERFLOW; - len = (buf_size - 1); - } - - if (data == NULL) { - len = 0; - } else { - strncpy(buf, data, len); - } - - buf[len] = 0; - - return error; -} - -gs_error_t gs_string_get_suboption(const char * options, const char * suboption, char * buf, size_t buf_size) -{ - GS_CHECK_ARG(options != NULL); - GS_CHECK_ARG((buf != NULL) && (buf_size > 0)); - - const char * next = options; - for (;next;) { - const char * key = next; - if (*key == ',') { - key = NULL; // no key-value - } - next = strchr(next, ','); - - const char * value = NULL; - if (key) { - for (; *key == ' '; ++key); - - value = strchr(key, '='); - if (value == NULL) { - // no value - } else if (next && (value >= next)) { - // no value - value = NULL; - } - } - - const unsigned int key_len = suboption_len(key, value ? value : next); - - if (value) { - if (*value == '=') { - ++value; - } - for (; *value == ' '; ++value); - } - - const unsigned int value_len = suboption_len(value, next); - - if (GS_STRING_GET_SUBOPTION_UNIT_TEST) { // -> #define - printf(" key=[%.*s], len=%u, value=[%.*s], len=%u, next=[%s]\n", - key_len, key ? key : "", key_len, - value_len, value ? value : "", value_len, - next ? next : ""); - } - - // if suboption is empty, it means get value of first element - ignoring any key - if (gs_string_empty(suboption)) { - if (value) { - return suboption_copy(value, value_len, buf, buf_size, GS_OK); - } - if (key) { - return suboption_copy(key, key_len, buf, buf_size, GS_OK); - } - return suboption_copy(NULL, 0, buf, buf_size, GS_OK); // empty - } - - if ((key_len == strlen(suboption)) && (strncasecmp(key, suboption, key_len) == 0)) { - return suboption_copy(value, value_len, buf, buf_size, GS_OK); - } - - if (next) { - ++next; - if (next[0] == 0) { - next = NULL; - } - } - } - - // not found - return default - return suboption_copy(NULL, 0, buf, buf_size, GS_ERROR_NOT_FOUND); -} - -static const char * _suboption_name(const char * suboption) -{ - if (gs_string_empty(suboption)) { - return "first suboption"; - } - return suboption; -} - -#define _get_suboption(_type) \ - char buf[20]; \ - gs_error_t error = gs_string_get_suboption(options, suboption, buf, sizeof(buf)); \ - if (error == GS_OK) { \ - error = gs_string_to_##_type(buf, value); \ - } \ - if (error) { \ - if (error == GS_ERROR_NOT_FOUND) { \ - error = GS_OK; \ - } else { \ - log_error("Failed to extract suboption [%s] from [%s], error: %d", _suboption_name(suboption), options, error); \ - } \ - *value = def; \ - } \ - return error; \ - -gs_error_t gs_string_get_suboption_uint8(const char * options, const char * suboption, uint8_t def, uint8_t * value) -{ - _get_suboption(uint8) -} - -gs_error_t gs_string_get_suboption_uint16(const char * options, const char * suboption, uint16_t def, uint16_t * value) -{ - _get_suboption(uint16) -} - -gs_error_t gs_string_get_suboption_uint32(const char * options, const char * suboption, uint32_t def, uint32_t * value) -{ - _get_suboption(uint32) -} - -gs_error_t gs_string_get_suboption_string(const char * options, const char * suboption, const char * def, char * buf, size_t buf_size) -{ - gs_error_t error = gs_string_get_suboption(options, suboption, buf, buf_size); - if (error) { - if (error == GS_ERROR_NOT_FOUND) { - error = GS_OK; - } - error = suboption_copy(def, def ? strlen(def) : 0, buf, buf_size, error); - } - return error; -} - -gs_error_t gs_string_get_suboption_bool(const char * options, const char * suboption, bool def, bool * value) -{ - char buf[20]; - gs_error_t error = gs_string_get_suboption(options, suboption, buf, sizeof(buf)); - if (error == GS_OK) { - if (gs_string_empty(buf) || (suboption && (strcasecmp(suboption, buf) == 0))) { - // this means 'true', a=21,active,a=22 - *value = true; - } else { - error = gs_string_to_bool(buf, value); - } - } - if (error) { - if (error == GS_ERROR_NOT_FOUND) { - error = GS_OK; - } else { - log_error("Failed to extract suboption [%s] from [%s], error: %d", _suboption_name(suboption), options, error); - } - *value = def; - } - return error; -} diff --git a/gomspace/libutil/src/strtoint.c b/gomspace/libutil/src/strtoint.c deleted file mode 100644 index 152eff39..00000000 --- a/gomspace/libutil/src/strtoint.c +++ /dev/null @@ -1,399 +0,0 @@ -/*- - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * 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. [rescinded 22 July 1999] - * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. - */ - -/* - -@deftypefn Supplemental {long int} strtol (const char *@var{string}, @ - char **@var{endptr}, int @var{base}) -@deftypefnx Supplemental {unsigned long int} strtoul (const char *@var{string}, @ - char **@var{endptr}, int @var{base}) - -The @code{strtol} function converts the string in @var{string} to a -long integer value according to the given @var{base}, which must be -between 2 and 36 inclusive, or be the special value 0. If @var{base} -is 0, @code{strtol} will look for the prefixes @code{0} and @code{0x} -to indicate bases 8 and 16, respectively, else default to base 10. -When the base is 16 (either explicitly or implicitly), a prefix of -@code{0x} is allowed. The handling of @var{endptr} is as that of -@code{strtod} above. The @code{strtoul} function is the same, except -that the converted value is unsigned. - -@end deftypefn - -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#ifdef HAVE_LIMITS_H -#include -#endif -#ifdef HAVE_SYS_PARAM_H -#include -#endif -#include -#include -#include - -/* - * Convert a string to a long integer. - * - * Ignores `locale' stuff. Assumes that the upper and lower case - * alphabets and digits are each contiguous. - */ -int32_t gs_string_strto32int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) -{ - register const char *s = nptr; - register uint32_t acc; - register int c; - register uint32_t cutoff; - register int neg = 0, any, cutlim; - - /* - * Skip white space and pick up leading +/- sign if any. - * If base is 0, allow 0x for hex and 0 for octal, else - * assume decimal; if base is already 16, allow 0x. - */ - do - { - c = *s++; - } while (isspace(c)); - if (c == '-') - { - neg = 1; - c = *s++; - } else if (c == '+') - { - c = *s++; - } - if ((base == 0 || base == 16) && - c == '0' && (*s == 'x' || *s == 'X')) - { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - { - base = c == '0' ? 8 : 10; - } - - /* - * Compute the cutoff value between legal numbers and illegal - * numbers. That is the largest legal value, divided by the - * base. An input number that is greater than this value, if - * followed by a legal input character, is too big. One that - * is equal to this value may be valid or not; the limit - * between valid and invalid numbers is then based on the last - * digit. For instance, if the range for longs is - * [-2147483648..2147483647] and the input base is 10, - * cutoff will be set to 214748364 and cutlim to either - * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated - * a value > 214748364, or equal but the next digit is > 7 (or 8), - * the number is too big, and we will return a range error. - * - * Set any if any `digits' consumed; make it negative to indicate - * overflow. - */ - cutoff = neg ? -(uint32_t)INT32_MIN : INT32_MAX; - cutlim = cutoff % (uint32_t)base; - cutoff /= (uint32_t)base; - for (acc = 0, any = 0;; c = *s++) - { - if (isdigit(c)) - { - c -= '0'; - } - else if (isalpha(c)) - { - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - } - else - { - break; - } - if (c >= base) - { - break; - } - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - { - any = -1; - } - else - { - any = 1; - acc *= base; - acc += c; - } - } - if (any < 0) - { - acc = neg ? INT32_MIN : INT32_MAX; - *err = GS_ERROR_OVERFLOW; - } else if (neg) - { - acc = -acc; - } - if (endptr != 0) - { - *endptr = (char *) (any ? s - 1 : nptr); - } - return (acc); -} - - -/* - * Convert a string to an unsigned long integer. - * - * Ignores `locale' stuff. Assumes that the upper and lower case - * alphabets and digits are each contiguous. - */ -uint32_t gs_string_strto32uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) -{ - register const char *s = nptr; - register uint32_t acc; - register int32_t c; - register uint32_t cutoff; - register int32_t neg = 0, any, cutlim; - - /* - * See strtol for comments as to the logic used. - */ - do - { - c = *s++; - } while (isspace(c)); - if (c == '-') - { - neg = 1; - c = *s++; - } else if (c == '+') - { - c = *s++; - } - if ((base == 0 || base == 16) && - c == '0' && (*s == 'x' || *s == 'X')) - { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - { - base = c == '0' ? 8 : 10; - } - cutoff = (uint32_t)UINT32_MAX / (uint32_t)base; - cutlim = (uint32_t)UINT32_MAX % (uint32_t)base; - for (acc = 0, any = 0;; c = *s++) - { - if (isdigit(c)) - { - c -= '0'; - } - else if (isalpha(c)) - { - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - } - else - { - break; - } - if (c >= base) - { - break; - } - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - { - any = -1; - } - else - { - any = 1; - acc *= base; - acc += c; - } - } - if (any < 0) - { - acc = UINT32_MAX; - *err = GS_ERROR_OVERFLOW; - } else if (neg) - { - acc = -acc; - } - if (endptr != 0) - { - *endptr = (char *) (any ? s - 1 : nptr); - } - return (acc); -} - - -int64_t gs_string_strto64int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) -{ - register const char *s = nptr; - register uint64_t acc; - register int32_t c; - register uint64_t cutoff; - register int32_t neg = 0, any, cutlim; - - /* - * Skip white space and pick up leading +/- sign if any. - * If base is 0, allow 0x for hex and 0 for octal, else - * assume decimal; if base is already 16, allow 0x. - */ - do { - c = *s++; - } while (isspace(c)); - if (c == '-') { - neg = 1; - c = *s++; - } else if (c == '+') - c = *s++; - if ((base == 0 || base == 16) && - c == '0' && (*s == 'x' || *s == 'X')) { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - base = c == '0' ? 8 : 10; - - /* - * Compute the cutoff value between legal numbers and illegal - * numbers. That is the largest legal value, divided by the - * base. An input number that is greater than this value, if - * followed by a legal input character, is too big. One that - * is equal to this value may be valid or not; the limit - * between valid and invalid numbers is then based on the last - * digit. For instance, if the range for longs is - * [-2147483648..2147483647] and the input base is 10, - * cutoff will be set to 214748364 and cutlim to either - * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated - * a value > 214748364, or equal but the next digit is > 7 (or 8), - * the number is too big, and we will return a range error. - * - * Set any if any `digits' consumed; make it negative to indicate - * overflow. - */ - cutoff = neg ? -(uint64_t)INT64_MIN : INT64_MAX; - cutlim = cutoff % (uint64_t)base; - cutoff /= (uint64_t)base; - for (acc = 0, any = 0;; c = *s++) { - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else - break; - if (c >= base) - break; - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else { - any = 1; - acc *= base; - acc += c; - } - } - if (any < 0) { - acc = neg ? INT64_MIN : INT64_MAX; - *err = GS_ERROR_OVERFLOW; - } else if (neg) - acc = -acc; - if (endptr != 0) - *endptr = (char *) (any ? s - 1 : nptr); - return (acc); -} - - -/* - * Convert a string to an unsigned long integer. - * - * Ignores `locale' stuff. Assumes that the upper and lower case - * alphabets and digits are each contiguous. - */ - -uint64_t gs_string_strto64uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) -{ - register const char *s = nptr; - register uint64_t acc; - register int32_t c; - register uint64_t cutoff; - register int32_t neg = 0, any, cutlim; - - /* - * See strtol for comments as to the logic used. - */ - do { - c = *s++; - } while (isspace(c)); - if (c == '-') { - neg = 1; - c = *s++; - } else if (c == '+') - c = *s++; - if ((base == 0 || base == 16) && - c == '0' && (*s == 'x' || *s == 'X')) { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - base = c == '0' ? 8 : 10; - cutoff = (uint64_t)UINT64_MAX / (uint64_t)base; - cutlim = (uint64_t)UINT64_MAX % (uint64_t)base; - for (acc = 0, any = 0;; c = *s++) { - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else - break; - if (c >= base) - break; - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else { - any = 1; - acc *= base; - acc += c; - } - } - if (any < 0) { - acc = UINT64_MAX; - *err = GS_ERROR_OVERFLOW; - } else if (neg) - acc = -acc; - if (endptr != 0) - *endptr = (char *) (any ? s - 1 : nptr); - return (acc); -} diff --git a/gomspace/libutil/src/test/cmocka.c b/gomspace/libutil/src/test/cmocka.c deleted file mode 100644 index c3c5d171..00000000 --- a/gomspace/libutil/src/test/cmocka.c +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -void cm_print_error(const char * const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); - -#define EQUAL_TO_STRING(equal) (equal ? "!=" : "==") - -void _gs_assert_int_equal(const intptr_t left, const intptr_t right, bool equal, const char * const file, const int line) -{ - const bool cmp_equal = left == right; - if (cmp_equal != equal) { - cm_print_error("%ld %s %ld\n", left, EQUAL_TO_STRING(equal), right); - - _fail(file, line); - } -} - -void _gs_assert_uint_equal(const uintptr_t left, const uintptr_t right, bool equal, bool hex, const char * const file, const int line) -{ - const bool cmp_equal = left == right; - if (cmp_equal != equal) { - if(hex) { - cm_print_error("0x%lx %s 0x%lx\n", left, EQUAL_TO_STRING(equal), right); - } else { - cm_print_error("%lu %s %lu\n", left, EQUAL_TO_STRING(equal), right); - } - - _fail(file, line); - } -} - -void _gs_assert_error_equal(const int left, const int right, bool equal, const char * const file, const int line) -{ - const bool cmp_equal = left == right; - if (cmp_equal != equal) { - cm_print_error("%d(%s) %s %d(%s)\n", left, gs_error_string(left), EQUAL_TO_STRING(equal), right, gs_error_string(right)); - - _fail(file, line); - } -} - -void _gs_assert_float_equal(const float left, const float right, const float diff, bool equal, const char * const file, const int line) -{ - const bool cmp_equal = (fabsf(left - right) < diff); - if (cmp_equal != equal) { - cm_print_error("%e %s %e\n", left, EQUAL_TO_STRING(equal), right); - - _fail(file, line); - } -} - -void _gs_assert_double_equal(const double left, const double right, const double diff, bool equal, const char * const file, const int line) -{ - const bool cmp_equal = (fabsf(left - right) < diff); - if (cmp_equal != equal) { - cm_print_error("%e %s %e\n", left, EQUAL_TO_STRING(equal), right); - - _fail(file, line); - } -} diff --git a/gomspace/libutil/src/test/command.c b/gomspace/libutil/src/test/command.c deleted file mode 100644 index e9678523..00000000 --- a/gomspace/libutil/src/test/command.c +++ /dev/null @@ -1,176 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include -#include - -void cm_print_error(const char * const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); - -struct results { - char group[32]; - char key[32]; - char value[128]; -}; - -static FILE* g_output_file = 0; -static char g_stdout_buf[10000]; -static char g_stdin_buf[1000]; -static uint16_t g_stdin_idx; - -static struct results g_results[100]; -static uint32_t g_results_count = 0; - - -static gs_error_t test_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value) -{ - if (g_results_count >= GS_ARRAY_SIZE(g_results)) { - return GS_ERROR_ALLOC; - } - - if (group) { - strncpy(g_results[g_results_count].group, group, sizeof(g_results[0].group)); - } - if (key) { - strncpy(g_results[g_results_count].key, key, sizeof(g_results[0].key)); - } - if (value) { - strncpy(g_results[g_results_count].value, value, sizeof(g_results[0].value)); - } - g_results_count++; - return GS_OK; -} - -static gs_error_t test_flush(gs_command_context_t *ctx) -{ - fflush(ctx->out); - return GS_OK; -} - -static gs_error_t test_wait_for_key(gs_command_context_t *ctx, int *ch, int timeout_ms) -{ - if (g_stdin_buf[g_stdin_idx] == 0) { - gs_time_sleep_ms(timeout_ms); - return GS_ERROR_TIMEOUT; - } - - *ch = g_stdin_buf[g_stdin_idx]; - g_stdin_idx++; - return GS_OK; -} - -static gs_command_io_functions_t g_test_io_functions = { - .set_result = test_set_result, - .flush = test_flush, - .wait_for_key = test_wait_for_key, -}; - - -static gs_error_t prepare_validation(const char *input) -{ - g_results_count = 0; - memset(g_stdout_buf, 0, sizeof(g_stdout_buf)); - memset(g_stdin_buf, 0, sizeof(g_stdin_buf)); - g_stdin_idx = 0; - - if (input != NULL) { - memcpy(g_stdin_buf, input, strlen(input)); - } - - g_output_file = fmemopen(g_stdout_buf, sizeof(g_stdout_buf) - 1, "w"); - if (!g_output_file) { - return GS_ERROR_ALLOC; - } - - return GS_OK; -} - -static bool match(const char *first, const char * second) -{ - return (fnmatch(first, second, 0) == 0); -} - -static gs_error_t do_validation(const char *expected) -{ - fclose(g_output_file); - - if (expected == NULL) - return GS_OK; - - if (!match(expected, g_stdout_buf)) - { - return GS_ERROR_DATA; - } - return GS_OK; -} - - -void _gs_assert_command_validate(const char *cmd, gs_error_t ret, gs_error_t cmd_ret, const char *std_in, const char *std_out, - const char * const file, const int line) -{ - if (prepare_validation(std_in) != GS_OK) - { - cm_print_error("Validation function failed to allocate it's resources\n"); - _fail(file, line); - } - - gs_error_t _ret; - gs_error_t _command_ret = GS_OK; - _ret = gs_command_execute(cmd, &_command_ret, g_output_file, &g_test_io_functions, NULL); - - if (_ret != ret) { - cm_print_error("Return: %d(%s) != %d(%s)\n", _ret, gs_error_string(_ret), ret, gs_error_string(ret)); - _fail(file, line); - } - - if (_ret == GS_OK) /* Only check CMD return if command execution succeeded */ - { - if (_command_ret != cmd_ret) { - cm_print_error("Command return: %d(%s) != %d(%s)\n", _command_ret, gs_error_string(_command_ret), - cmd_ret, gs_error_string(cmd_ret)); - _fail(file, line); - } - } - - if (do_validation(std_out) != GS_OK) - { - //cm_print_error("Stdout != : \n%s\n!=\n%s\n", g_stdout_buf, std_out); - printf("Stdout != : \n%s\n!=\n%s\n", g_stdout_buf, std_out); - _fail(file, line); - } - - return; -} - -void _gs_assert_command_validate_last_result(unsigned int no, const char *group, const char *key, const char *value, - const char * const file, const int line) -{ - if (no >= g_results_count) - { - cm_print_error("Result no: %d not available. Only %d results returned from command\n", no, g_results_count); - _fail(file, line); - } - - if (group) { - if (!match(group, g_results[no].group)) { - cm_print_error("group: %s != %s\n", group, g_results[no].group); - _fail(file, line); - } - } - if (key) { - if (!match(key, g_results[no].key)) { - cm_print_error("key: %s != %s\n", key, g_results[no].key); - _fail(file, line); - } - } - if (value) { - if (!match(value, g_results[no].value)) { - cm_print_error("value: %s != %s\n", value, g_results[no].value); - _fail(file, line); - } - } - - return; -} diff --git a/gomspace/libutil/src/test/log.c b/gomspace/libutil/src/test/log.c deleted file mode 100644 index ba7671e1..00000000 --- a/gomspace/libutil/src/test/log.c +++ /dev/null @@ -1,165 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// cmocka -void cm_print_error(const char * const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); - -static gs_mutex_t g_lock; - -#define GS_TEST_LOG_MAX_LEVELS 6 -#define GS_TEST_LOG_MAX_LOG_MESSAGES 200 - -typedef struct { - // Overall count per log level. - unsigned int count[GS_TEST_LOG_MAX_LEVELS]; - // Log messages. - struct { - // Level. - gs_log_level_t level; - // Format log message. - char msg[150]; - } logs[GS_TEST_LOG_MAX_LOG_MESSAGES]; - // Index of next entry in \a logs. - unsigned int next_log; -} gs_test_log_stats_t; - -static gs_test_log_stats_t gs_test_log_stats; - -static void log_callback(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t * group, const gs_timestamp_t * ts, const char * format, va_list va) -{ - gs_mutex_lock(g_lock); - gs_test_log_stats.count[level]++; - - { - gs_bytebuffer_t bb; - gs_bytebuffer_init(&bb, - gs_test_log_stats.logs[gs_test_log_stats.next_log].msg, - sizeof(gs_test_log_stats.logs[gs_test_log_stats.next_log].msg)); - - va_list my_va; - va_copy(my_va, va); - gs_bytebuffer_printf(&bb, "%s: ", group->name); - gs_bytebuffer_vprintf(&bb, format, my_va); - va_end(my_va); - gs_bytebuffer_get_as_string(&bb, NULL); // ensure NUL termination - gs_test_log_stats.logs[gs_test_log_stats.next_log].level = level; - - ++gs_test_log_stats.next_log; - if (gs_test_log_stats.next_log >= GS_TEST_LOG_MAX_LOG_MESSAGES) { - gs_test_log_stats.next_log = 0; - } - gs_test_log_stats.logs[gs_test_log_stats.next_log].msg[0] = 0; // clear next entry - gs_test_log_stats.logs[gs_test_log_stats.next_log].level = GS_TEST_LOG_MAX_LEVELS; - } - - gs_mutex_unlock(g_lock); -} - -static gs_log_appender_driver_t g_log_test_appender_driver = { - .init = 0, - .append = log_callback, - .append_isr = log_callback, -}; - -static gs_log_appender_t g_log_test_appender = { - .name = "test_appender", - .drv = &g_log_test_appender_driver, - .drv_config = NULL, - .drv_data = NULL, - .mask = LOG_ALL_MASK, -}; - -void gs_test_log_init(bool verbose) -{ - gs_log_init(true); - - if (g_lock == NULL) { - GS_ASSERT_ERROR_EQUAL(gs_mutex_create(&g_lock), GS_OK); - - /* Add/Register appender - Only first time that init is called. */ - gs_log_appender_add(&g_log_test_appender, 1); - gs_log_group_register_appender("root", "test_appender"); - } - if (verbose) { - gs_log_appender_set_level_mask("console", LOG_ALL_MASK); - } else { - gs_log_appender_set_level_mask("console", 0); - } - - gs_test_log_clear(); -} - -void gs_test_log_clear(void) -{ - gs_mutex_lock(g_lock); - memset(&gs_test_log_stats, 0, sizeof(gs_test_log_stats)); - gs_mutex_unlock(g_lock); -} - -void gs_assert_log_count(int level, unsigned int count, const char * file, int line) -{ - if (level < 0) { - unsigned int tot = 0; - for (int i = 0; i < GS_TEST_LOG_MAX_LEVELS; ++i) { - tot += gs_test_log_stats.count[i]; - } - if (tot != count) { - cm_print_error("Unexpected total log count: %u != %u\n", tot, count); - _fail(file, line); - } - } else if (level >= GS_TEST_LOG_MAX_LEVELS) { - cm_print_error("Unknown log level: %d - valid levels 0 - %d\n", level, GS_TEST_LOG_MAX_LEVELS - 1); - _fail(file, line); - } else if (gs_test_log_stats.count[level] != count) { - cm_print_error("Unexpected log count: %u != %u\n", gs_test_log_stats.count[level], count); - _fail(file, line); - } -} - -void gs_assert_log(unsigned int stack_index, unsigned int count, gs_log_level_t level, const char * pattern, const char * file, int line) -{ - if (stack_index == UINT32_MAX) { - // loop through all logs - unsigned int next = gs_test_log_stats.next_log; - unsigned int hits = 0; - for (unsigned int i = next - 1; i != next; --i) { - if (i >= GS_TEST_LOG_MAX_LOG_MESSAGES) { - i = (GS_TEST_LOG_MAX_LOG_MESSAGES - 1); - } - if ((gs_test_log_stats.logs[i].level == level) && (gs_test_log_stats.logs[i].msg[0])) { - if (fnmatch(pattern, gs_test_log_stats.logs[i].msg, 0) == 0) { - ++hits; - } - } - } - if (hits != count) { - cm_print_error("Unexpected log count: %u != %u\n", hits, count); - _fail(file, line); - } - } else if (stack_index >= GS_TEST_LOG_MAX_LOG_MESSAGES) { - cm_print_error("Invalid stack_index: %u - valid 0 - %d\n", stack_index, GS_TEST_LOG_MAX_LOG_MESSAGES - 1); - _fail(file, line); - } else { - unsigned int i = (((gs_test_log_stats.next_log + GS_TEST_LOG_MAX_LOG_MESSAGES) - 1 - stack_index) % GS_TEST_LOG_MAX_LOG_MESSAGES); - if ((gs_test_log_stats.logs[i].level == level) && - (gs_test_log_stats.logs[i].msg[0]) && - (fnmatch(pattern, gs_test_log_stats.logs[i].msg, 0) == 0)) { - // match - } else { - cm_print_error("[%c][%s] != [%c][%s]\n", - gs_log_level_to_char(gs_test_log_stats.logs[i].level), gs_test_log_stats.logs[i].msg, - gs_log_level_to_char(level), pattern); - _fail(file, line); - } - } -} diff --git a/gomspace/libutil/src/time.c b/gomspace/libutil/src/time.c deleted file mode 100644 index 123f5994..00000000 --- a/gomspace/libutil/src/time.c +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include - -uint32_t gs_time_diff_ms(uint32_t ref_ms, uint32_t now_ms) -{ - if (now_ms >= ref_ms) { - return (now_ms - ref_ms); - } - - // assuming time wrapped at max uint32_t - return ((UINT32_MAX - ref_ms) + now_ms); -} - -bool gs_time_sleep_until_ms(uint32_t * ref_ms, uint32_t sleep_ms) -{ - const uint32_t now = gs_time_rel_ms(); - *ref_ms += sleep_ms; // this is expected to be in the future - uint32_t ms = gs_time_diff_ms(now, *ref_ms); - if (ms > sleep_ms) { - // we are behind - catch up, could be bad seed or too long processing - *ref_ms = now; - gs_time_sleep_ms(0); // yield - let others have a go - return true; - } - gs_time_sleep_ms(ms); - return false; -} diff --git a/gomspace/libutil/src/timestamp.c b/gomspace/libutil/src/timestamp.c deleted file mode 100644 index 2f7ee913..00000000 --- a/gomspace/libutil/src/timestamp.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include - -int timestamp_add(gs_timestamp_t * base, const gs_timestamp_t * add) -{ - if (!base || !add) - return -1; - - base->tv_sec += add->tv_sec; - if (base->tv_nsec + add->tv_nsec >= GS_TIMESTAMP_NSEC_PER_SEC) { - base->tv_sec++; - base->tv_nsec = (base->tv_nsec + add->tv_nsec) % GS_TIMESTAMP_NSEC_PER_SEC; - } else { - base->tv_nsec += add->tv_nsec; - } - - return 0; -} - -int timestamp_diff(gs_timestamp_t * base, const gs_timestamp_t * diff) -{ - if (!base || !diff) - return -1; - - base->tv_sec -= diff->tv_sec; - if (base->tv_nsec >= diff->tv_nsec) { - base->tv_nsec -= diff->tv_nsec; - } else { - base->tv_sec--; - base->tv_nsec = (base->tv_nsec + GS_TIMESTAMP_NSEC_PER_SEC) - diff->tv_nsec; - } - - return 0; -} - -/* Test is timestamp is greater or equal */ -int timestamp_ge(const gs_timestamp_t * base, const gs_timestamp_t * test) -{ - if (!base || !test) - return -1; - - if (test->tv_sec > base->tv_sec || - (test->tv_sec == base->tv_sec && - test->tv_nsec > base->tv_nsec)) { - return 1; - } - - return 0; -} - -int timestamp_copy(const gs_timestamp_t * from, gs_timestamp_t * to) -{ - if (!from || !to) - return -1; - - to->tv_sec = from->tv_sec; - to->tv_nsec = from->tv_nsec; - - return 0; -} diff --git a/gomspace/libutil/src/vmem/commands.c b/gomspace/libutil/src/vmem/commands.c deleted file mode 100644 index 06a37af4..00000000 --- a/gomspace/libutil/src/vmem/commands.c +++ /dev/null @@ -1,123 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -static int cmd_vmem_read(gs_command_context_t * ctx) -{ - if (gs_vmem_get_map() == NULL) { - return GS_ERROR_NOT_FOUND; - } - - void * addr; - if (gs_string_to_pointer(ctx->argv[1], &addr)) { - return GS_ERROR_ARG; - } - - uint32_t length; - if (gs_string_to_uint32(ctx->argv[2], &length)) { - return GS_ERROR_ARG; - } - - char data[length]; - void* to = gs_vmem_cpy(data, addr, length); - if (to == NULL) { - return GS_ERROR_ARG; - } - - gs_hexdump_to_stream(data, length, addr, ctx->out); - - return GS_OK; -} - -static unsigned int to_int(char c) -{ - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'A' && c <= 'F') return 10 + c - 'A'; - if (c >= 'a' && c <= 'f') return 10 + c - 'a'; - return -1; -} - -static int cmd_vmem_write(gs_command_context_t * ctx) -{ - if (gs_vmem_get_map() == NULL) { - return GS_ERROR_NOT_FOUND; - } - - void * addr; - if (gs_string_to_pointer(ctx->argv[1], &addr)) { - return GS_ERROR_ARG; - } - - int len = strlen(ctx->argv[2]) / 2; - char data[len]; - - for (int i = 0; (i < len); ++i) { - data[i] = 16 * to_int(ctx->argv[2][2*i]) + to_int(ctx->argv[2][2*i+1]); - } - - gs_vmem_cpy(addr, data, len); - return GS_OK; -} - -static int cmd_vmem_list(gs_command_context_t * ctx) -{ - return gs_vmem_list(ctx->out); -} - -static int cmd_vmem_lock(gs_command_context_t * context) -{ - return gs_vmem_lock_by_name(context->argv[1], true); -} - -static int cmd_vmem_unlock(gs_command_context_t * context) -{ - return gs_vmem_lock_by_name(context->argv[1], false); -} - -static const gs_command_t GS_COMMAND_SUB cmd_vmem_sub[] = { - { - .name = "read", - .help = "Read from virtual memory", - .usage = " ", - .handler = cmd_vmem_read, - .mandatory_args = 2, - },{ - .name = "write", - .help = "Write to virtual memory", - .usage = " ", - .handler = cmd_vmem_write, - .mandatory_args = 2, - },{ - .name = "lock", - .help = "Lock the virtual memory", - .usage = "", - .handler = cmd_vmem_lock, - .mandatory_args = 1, - },{ - .name = "unlock", - .help = "Unlock the virtual memory", - .usage = "", - .handler = cmd_vmem_unlock, - .mandatory_args = 1, - },{ - .name = "list", - .help = "Show virtual memory mappings", - .handler = cmd_vmem_list, - .mandatory_args = GS_COMMAND_NO_ARGS, - } -}; - -static const gs_command_t GS_COMMAND_ROOT cmd_vmem[] = { - { - .name = "vmem", - .help = "Virtual memory", - .chain = GS_COMMAND_INIT_CHAIN(cmd_vmem_sub), - }, -}; - -gs_error_t gs_vmem_register_commands(void) -{ - return GS_COMMAND_REGISTER(cmd_vmem); -} diff --git a/gomspace/libutil/src/vmem/vmem.c b/gomspace/libutil/src/vmem/vmem.c deleted file mode 100644 index 30068a01..00000000 --- a/gomspace/libutil/src/vmem/vmem.c +++ /dev/null @@ -1,143 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include - -static const gs_vmem_t * g_vmem_map; - -gs_error_t gs_vmem_set_map(const gs_vmem_t * map) -{ - g_vmem_map = map; - return GS_OK; -} - -const gs_vmem_t * gs_vmem_get_map(void) -{ - return g_vmem_map; -} - -gs_error_t gs_vmem_list(FILE * out) -{ - const gs_vmem_t * mem = g_vmem_map; - if (mem) { - unsigned int found = 0; - for (; mem->name; ++mem) { - if (found == 0) { - fprintf(out, "%-20s %-10s %-6s %-6s %s\r\n", "name", "virt.", "phys.", "size", "size"); - } - fprintf(out, "%-20s %p 0x%04x 0x%04x %5u\r\n", mem->name, mem->virtmem.p, (unsigned int) mem->physmem.u, (unsigned int) mem->size, (unsigned int) mem->size); - ++found; - } - if (found) { - return GS_OK; - } - } - return GS_ERROR_NOT_FOUND; -} - -const gs_vmem_t * gs_vmem_get_by_name(const char * name) -{ - if (name) { - const gs_vmem_t * mem = g_vmem_map; - if (mem) { - for (; mem->name; ++mem) { - if (strcasecmp(name, mem->name) == 0) { - return mem; - } - } - } - } - return NULL; -} - -gs_error_t gs_vmem_lock_by_name(const char * name, bool on) -{ - const gs_vmem_t * mem = gs_vmem_get_by_name(name); - if (mem) { - if (mem->drv && mem->drv->lock) { - return (mem->drv->lock)(mem, on); - } - return GS_ERROR_NOT_SUPPORTED; - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_vmem_lock_all(bool on) -{ - const gs_vmem_t * mem = g_vmem_map; - if (mem) { - unsigned int locked = 0; - for (; mem->name; ++mem) { - if (mem->drv && mem->drv->lock) { - (mem->drv->lock)(mem, on); - ++locked; - } - } - if (locked) { - return GS_OK; - } - } - return GS_ERROR_NOT_FOUND; -} - -/** - @note NO LOGGING - currently the log system uses this interface, and logging can therefor create circular/forever loops. -*/ -void * gs_vmem_cpy(void* to, const void* from, size_t size) -{ - /* Search memories */ - const gs_vmem_t *vmem_from = NULL; - const gs_vmem_t *vmem_to = NULL; - const gs_vmem_t *mem = g_vmem_map; - const gs_address_t _to = {.p = to}; - const gs_address_t _from = {.p = (void*) from}; - - if (mem) { - while(mem->size != 0) { - //printf("0x%lx 0x%lx %"PRIu32" %lu %lu\r\n", mem->start, mem->physmem_start, mem->size, to, from); - if ((_to.u >= mem->virtmem.u) && (_to.u < mem->virtmem.u + mem->size)) { - vmem_to = mem; - } - if ((_from.u >= mem->virtmem.u) && (_from.u < mem->virtmem.u + mem->size)) { - vmem_from = mem; - } - mem++; - } - } - - // VMEM -> VMEM - if (vmem_to && vmem_from) { - printf("%s: VMEM to VMEM is not supported\r\n", __FUNCTION__); - return NULL; - } - - // RAM -> VMEM - if (vmem_to) { - if ((vmem_to->drv == NULL) || (vmem_to->drv->write == NULL)) { - printf("%s: Writting to VMEM %p is not supported\r\n", __FUNCTION__, to); - return NULL; - } - gs_address_t physaddr = {.u = (_to.u - vmem_to->virtmem.u) + vmem_to->physmem.u}; - //printf("Copying from ram 0x%lx to physaddr 0x%lx %u\r\n", from, physaddr, (unsigned int) size); - vmem_to->drv->write(vmem_to, physaddr.p, from, size); - return to; - } - - // VMEM -> RAM - if (vmem_from) { - if (vmem_from->drv == NULL || (vmem_from->drv->read == NULL)) { - printf("%s: Reading from VMEM %p is not supported\r\n", __FUNCTION__, from); - return NULL; - } - gs_address_t physaddr = {.u = (_from.u - vmem_from->virtmem.u) + vmem_from->physmem.u}; - //printf("Copying from mem physaddr 0x%lx to 0x%lx %u\r\n", physaddr, to, (unsigned int) size); - vmem_from->drv->read(vmem_from, to, physaddr.p, size); - return to; - } - - // RAM -> RAM (no VMEM mapping found) - return memcpy(to, from, size); -} diff --git a/gomspace/libutil/src/watchdog/local.h b/gomspace/libutil/src/watchdog/local.h deleted file mode 100644 index 1dc2e0de..00000000 --- a/gomspace/libutil/src/watchdog/local.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include - -typedef struct { - gs_thread_t task; - bool is_running; - bool do_stop; -} gs_swwd_monitor_task_t; - -// Return monitor task instance -gs_swwd_monitor_task_t * gs_swwd_get_monitor_task(void); - -GS_LOG_GROUP_EXTERN(gs_swwd_log); -#define LOG_DEFAULT gs_swwd_log diff --git a/gomspace/libutil/src/watchdog/monitor_task.c b/gomspace/libutil/src/watchdog/monitor_task.c deleted file mode 100644 index 54d7e668..00000000 --- a/gomspace/libutil/src/watchdog/monitor_task.c +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include "local.h" -#include -#include -#include - -#define GS_SWWD_CHECK_INTERVAL_MS 1000 /* Check every 1 sec. */ - -static void * gs_swwd_monitor_task(void* parameter) -{ - gs_swwd_monitor_task_t * monitor = parameter; - - log_info("monitor task started"); - - monitor->is_running = true; - - while(!monitor->do_stop) { - - gs_time_sleep_ms(GS_SWWD_CHECK_INTERVAL_MS); - - gs_swwd_check_expired_clients(NULL); - } - - monitor->is_running = false; - - log_info("monitor task exiting"); - - return NULL; -} - -gs_error_t gs_swwd_monitor_task_start(void) -{ - gs_swwd_monitor_task_t * monitor = gs_swwd_get_monitor_task(); - GS_CHECK_SUPPORTED(monitor != NULL); /* SWWD must be initialized */ - GS_CHECK_SUPPORTED(monitor->is_running == false); /* SWWD task must not already be running */ - - /* Start the monitor task */ - gs_error_t error = gs_thread_create("SWWD", gs_swwd_monitor_task, monitor, 4000, GS_THREAD_PRIORITY_HIGH, 0, &monitor->task); - if (error) { - log_error("%s: gs_thread_create() failed, error: %s", __FUNCTION__, gs_error_string(error)); - } - return error; -} - -gs_error_t gs_swwd_monitor_task_stop(uint32_t timeout_s) -{ - gs_swwd_monitor_task_t * monitor = gs_swwd_get_monitor_task(); - GS_CHECK_SUPPORTED(monitor != NULL); /* SWWD must be initialized */ - - /* Signal the task to stop */ - monitor->do_stop = true; - - /* Wait for the task to stop */ - const uint32_t timeout = GS_SWWD_CHECK_INTERVAL_MS + (timeout_s * 1000); - uint32_t tm = 0; - while(monitor->is_running && (tm < timeout)) { - gs_thread_sleep_ms(100); - tm += 100; - } - - if (monitor->is_running) { - return GS_ERROR_BUSY; - } - - return GS_OK; -} - diff --git a/gomspace/libutil/src/watchdog/watchdog.c b/gomspace/libutil/src/watchdog/watchdog.c deleted file mode 100644 index 867601b1..00000000 --- a/gomspace/libutil/src/watchdog/watchdog.c +++ /dev/null @@ -1,292 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include "local.h" -#include -#include -#include -#include -#include - -#define GS_SWWD_DEFAULT_TIMEOUT 30 /* 30 second timeout */ - -// define log group and make it default -GS_LOG_GROUP(gs_swwd_log, "swwd", GS_LOG_CAT_DEFAULT, GS_LOG_DEFAULT_MASK); - -// watchdog state -typedef enum { - GS_SWWD_STATE_FREE = 0, - GS_SWWD_STATE_ACTIVE = 1, - GS_SWWD_STATE_EXPIRED = 2, -} gs_swwd_state_t; - -// watchdog client instance -struct gs_swwd_hdl { - // State - gs_swwd_state_t state; - // Last 'user' touch value - used for detecting if watchdog has been touched (avoid race condition) - uint32_t last_touch; - // Last detected touch time - uint32_t last_touch_ms; - - // User 'set' attributes - struct { - // Name - const char* name; - // Timeout - converted from seconds (given to API) to mS - uint32_t timeout_ms; - // Action when/if timeout occurs - gs_swwd_timeout_action_t action; - // callback - gs_swwd_callback_function_t cb; - // user data (for callback) - void * cb_userdata; - // Touch - incremented on each touch - uint32_t touch; - } user; -}; - -typedef struct gs_swwd { - gs_watchdog_device_t *wdev; - gs_mutex_t lock; - gs_swwd_monitor_task_t monitor; - uint32_t num_clients; - gs_swwd_hdl_t clients[0]; -} gs_swwd_t; - -static gs_swwd_t* g_swwd = NULL; - -gs_swwd_monitor_task_t * gs_swwd_get_monitor_task(void) -{ - if (g_swwd) { - return &g_swwd->monitor; - } - return NULL; -} - -gs_error_t gs_swwd_create(uint32_t max_clients, gs_watchdog_device_t * wdev) -{ - GS_CHECK_SUPPORTED(g_swwd == NULL); /* SWWD must not be initialized more than once */ - GS_CHECK_ARG(max_clients > 0); - if (wdev) { - // ping is the only mandatory - GS_CHECK_ARG((wdev->ops != NULL) && (wdev->ops->ping != NULL)); - } - - gs_log_group_register(LOG_DEFAULT); - - gs_swwd_t *swwd_obj = calloc(1, sizeof(*swwd_obj) + (sizeof(swwd_obj->clients[0]) * max_clients)); - if (swwd_obj == NULL) { - return GS_ERROR_ALLOC; - } - - if (gs_mutex_create(&(swwd_obj->lock))) { - free(swwd_obj); - return GS_ERROR_ALLOC; - } - - swwd_obj->num_clients = max_clients; - swwd_obj->wdev = wdev; - - if (wdev) { - if (wdev->ops->set_timeout) { - wdev->ops->set_timeout(wdev, (wdev->timeout > 0) ? wdev->timeout : GS_SWWD_DEFAULT_TIMEOUT); - } - if (wdev->ops->set_pretimeout) { - wdev->ops->set_pretimeout(wdev, (wdev->pretimeout > 0) ? wdev->pretimeout : (GS_SWWD_DEFAULT_TIMEOUT - (GS_SWWD_DEFAULT_TIMEOUT/10))); - } - if (wdev->ops->start) { - wdev->ops->start(wdev); - } - wdev->ops->ping(wdev); - - } else { - log_warning("%s: no watchdog device specifed - cannot reset system!", __FUNCTION__); - } - - g_swwd = swwd_obj; /* Set the task handle as the last operation */ - return GS_OK; -} - -gs_error_t gs_swwd_destroy(uint32_t timeout_s) -{ - GS_CHECK_SUPPORTED(g_swwd != NULL); - - if (gs_swwd_monitor_task_stop(timeout_s) != GS_OK) { - return GS_ERROR_BUSY; - } - - if (g_swwd->wdev && g_swwd->wdev->ops->stop) { - g_swwd->wdev->ops->stop(g_swwd->wdev); - } - - gs_mutex_destroy(g_swwd->lock); - free(g_swwd); - g_swwd = NULL; - - return GS_OK; -} - -static const char * get_action(gs_swwd_timeout_action_t action) -{ - switch (action) { - case GS_SWWD_TIMEOUT_ACTION_RESET: - return "reset"; - case GS_SWWD_TIMEOUT_ACTION_LOG: - return "log"; - } - return "unknown"; -} - -gs_error_t gs_swwd_check_expired_clients(uint32_t *num_expired) -{ - GS_CHECK_SUPPORTED(g_swwd != NULL); /* SWWD must be initialized */ - - uint32_t expired_clients_reset = 0; - uint32_t expired_clients_log = 0; - - gs_mutex_lock(g_swwd->lock); - for (uint32_t idx = 0; idx < g_swwd->num_clients; idx++) { - gs_swwd_hdl_t * wd = &g_swwd->clients[idx]; - - uint32_t now_ms = gs_time_rel_ms(); - if (wd->state == GS_SWWD_STATE_ACTIVE) { - if (wd->last_touch != wd->user.touch) { - // watchdog has been touched since last we checked - update touch time - wd->last_touch = wd->user.touch; - wd->last_touch_ms = now_ms; - } else { - const uint32_t elapsed_ms = gs_time_diff_ms(wd->last_touch_ms, now_ms); - if (elapsed_ms >= wd->user.timeout_ms) { - wd->state = GS_SWWD_STATE_EXPIRED; - - char logbuf[100]; - snprintf(logbuf, sizeof(logbuf), - "[%s] expired -> %s (elapsed %"PRIu32" mS, timeout %"PRIu32" mS)", - wd->user.name, - get_action(wd->user.action), - elapsed_ms, - wd->user.timeout_ms); - - gs_swwd_callback_function_t cb = wd->user.cb; - void * cb_userdata = wd->user.cb_userdata; - - // Unlock while doing log and callback - // - we accept the tiny risk, that client has deregistered and will be called with invalid data - gs_mutex_unlock(g_swwd->lock); - { - log_error("%s", logbuf); - if (cb) { - (cb)(cb_userdata); - } - } - gs_mutex_lock(g_swwd->lock); - } - } - } - if (wd->state == GS_SWWD_STATE_EXPIRED) { - switch (wd->user.action) { - case GS_SWWD_TIMEOUT_ACTION_RESET: - ++expired_clients_reset; - break; - case GS_SWWD_TIMEOUT_ACTION_LOG: - if (wd->last_touch != wd->user.touch) { - // its alive - reactive watchdog - wd->state = GS_SWWD_STATE_ACTIVE; - wd->last_touch = wd->user.touch; - wd->last_touch_ms = now_ms; - } else { - ++expired_clients_log; - } - break; - } - } - } - gs_mutex_unlock(g_swwd->lock); - - if ((expired_clients_reset == 0) && g_swwd->wdev) { - g_swwd->wdev->ops->ping(g_swwd->wdev); - } - - if (num_expired) { - *num_expired = (expired_clients_reset + expired_clients_log); - } - - return GS_OK; -} - -gs_error_t gs_swwd_register_with_action(gs_swwd_hdl_t ** user_wd, - uint32_t timeout_seconds, - gs_swwd_callback_function_t callback, void * userdata, - const char * name, - gs_swwd_timeout_action_t action) -{ - GS_CHECK_ARG(gs_string_empty(name) == false); - GS_CHECK_ARG(timeout_seconds > 0); - GS_CHECK_ARG(user_wd != NULL); - GS_CHECK_SUPPORTED(g_swwd != NULL); /* SWWD must be initialized */ - - gs_swwd_hdl_t * wd = NULL; - gs_mutex_lock(g_swwd->lock); - { - for (unsigned int idx = 0; idx < g_swwd->num_clients; idx++) { - if (g_swwd->clients[idx].state == GS_SWWD_STATE_FREE) { - wd = &g_swwd->clients[idx]; - memset(wd, 0, sizeof(*wd)); - - // set user stuff - wd->user.name = name; - wd->user.timeout_ms = (timeout_seconds * 1000); - wd->user.cb = callback; - wd->user.cb_userdata = userdata; - wd->user.action = action; - - // set internal stuff - wd->state = GS_SWWD_STATE_ACTIVE; - wd->last_touch_ms = gs_time_rel_ms(); - break; - } - } - } - gs_mutex_unlock(g_swwd->lock); - - *user_wd = wd; - - if (wd == NULL) { - log_error("[%s] cannot create instance due to no available handles", name); - return GS_ERROR_FULL; - } - - return GS_OK; -} - -gs_error_t gs_swwd_deregister(gs_swwd_hdl_t ** wd) -{ - GS_CHECK_SUPPORTED(g_swwd != NULL); /* SWWD must be initialized */ - GS_CHECK_ARG(wd != NULL); - GS_CHECK_HANDLE(*wd != NULL); - - gs_mutex_lock(g_swwd->lock); - memset((*wd), 0, sizeof(**wd)); - gs_mutex_unlock(g_swwd->lock); - *wd = NULL; - - return GS_OK; -} - -gs_error_t gs_swwd_touch(gs_swwd_hdl_t * wd) -{ - GS_CHECK_HANDLE(wd != NULL); - - ++wd->user.touch; - return GS_OK; -} - -gs_error_t gs_swwd_set_timeout(gs_swwd_hdl_t * wd, uint32_t timeout_seconds) -{ - GS_CHECK_ARG(timeout_seconds > 0); - GS_CHECK_HANDLE(wd != NULL); - - ++wd->user.touch; - wd->user.timeout_ms = (timeout_seconds * 1000); - return GS_OK; -} diff --git a/gomspace/libutil/src/zip/cppcheck-suppress.txt b/gomspace/libutil/src/zip/cppcheck-suppress.txt deleted file mode 100644 index b23b687d..00000000 --- a/gomspace/libutil/src/zip/cppcheck-suppress.txt +++ /dev/null @@ -1,5 +0,0 @@ -// we don't wanna change 3rd part code for none-critical issue -localtimeCalled:src/zip/miniz/miniz.c -utimeCalled:src/zip/miniz/miniz.c -assignIfError:src/zip/miniz/miniz.c -unreadVariable:src/zip/miniz/miniz.c diff --git a/gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES b/gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES deleted file mode 100644 index cb7adb22..00000000 --- a/gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES +++ /dev/null @@ -1,9429 +0,0 @@ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -diff --git a/src/zip/miniz/miniz.h b/src/zip/miniz/miniz.h -index 86fac4c..f92f14e 100644 ---- a/src/zip/miniz/miniz.h -+++ b/src/zip/miniz/miniz.h -@@ -447,7 +447,7 @@ typedef void *const voidpc; - #define inflate mz_inflate - #define inflateEnd mz_inflateEnd - #define uncompress mz_uncompress --#define crc32 mz_crc32 -+// #define crc32 mz_crc32 - #define adler32 mz_adler32 - #define MAX_WBITS 15 - #define MAX_MEM_LEVEL 9 - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - -diff --git a/src/zip/miniz/miniz.c b/src/zip/miniz/miniz.c -index 67318cc..960f07c 100644 ---- a/src/zip/miniz/miniz.c -+++ b/src/zip/miniz/miniz.c -@@ -1936,6 +1936,7 @@ tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_fun - d->m_pSrc = NULL; - d->m_src_buf_left = 0; - d->m_out_buf_ofs = 0; -+ memset(d->m_dict, 0, sizeof(d->m_dict)); // Initialize array to 0's - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - return TDEFL_STATUS_OKAY; -@@ -2464,7 +2465,7 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_nex - } - r->m_table_sizes[2] = 19; - } -- for (; (int)r->m_type >= 0; r->m_type--) -+ for (; ((int)r->m_type) >= 0; r->m_type--) - { - int tree_next, tree_cur; - tinfl_huff_table *pTable; -@@ -3025,7 +3026,7 @@ static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) - #define MZ_DELETE_FILE remove - - #else --#pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") -+// #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") - #ifndef MINIZ_NO_TIME - #include - #endif -@@ -3267,12 +3268,12 @@ static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) - } - - #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS --static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) -+static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) - { - #ifdef _MSC_VER - struct tm tm_struct; - struct tm *tm = &tm_struct; -- errno_t err = localtime_s(tm, &time); -+ errno_t err = localtime_s(tm, &time_); - if (err) - { - *pDOS_date = 0; -@@ -3280,7 +3281,7 @@ static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_u - return; - } - #else -- struct tm *tm = localtime(&time); -+ struct tm *tm = localtime(&time_); - #endif /* #ifdef _MSC_VER */ - - *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); -@@ -3874,7 +3875,10 @@ mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, - /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ - - if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -+ { -+ MZ_FCLOSE(pFile); - return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -+ } - - if (!mz_zip_reader_init_internal(pZip, flags)) - { -@@ -4134,7 +4138,7 @@ static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_inde - - pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); - pField_data += sizeof(mz_uint64); -- field_data_remaining -= sizeof(mz_uint64); -+ // field_data_remaining -= sizeof(mz_uint64); - } - - break; -@@ -4219,11 +4223,11 @@ static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char - - int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) - { -- mz_uint32 index; -- if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index)) -+ mz_uint32 index_; -+ if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) - return -1; - else -- return (int)index; -+ return (int)index_; - } - - mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) -@@ -5332,12 +5336,12 @@ mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) - if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) - { - mz_uint32 found_index; -- mz_zip_archive_file_stat stat; -+ mz_zip_archive_file_stat stat_; - -- if (!mz_zip_reader_file_stat(pZip, i, &stat)) -+ if (!mz_zip_reader_file_stat(pZip, i, &stat_)) - return MZ_FALSE; - -- if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index)) -+ if (!mz_zip_reader_locate_file_v2(pZip, stat_.m_filename, NULL, 0, &found_index)) - return MZ_FALSE; - - /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ -@@ -6011,6 +6015,11 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n - mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, - const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) - { -+ if(!pZip) -+ { -+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+ } -+ - mz_uint16 method = 0, dos_time = 0, dos_date = 0; - mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; - mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; -@@ -6035,7 +6044,7 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n - level = level_and_flags & 0xF; - store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); - -- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -+ if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - pState = pZip->m_pState; -@@ -6296,6 +6305,11 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n - mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, - const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) - { -+ if(!pZip) -+ { -+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+ } -+ - mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; - mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; - mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; -@@ -6315,7 +6329,7 @@ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, - level = level_and_flags & 0xF; - - /* Sanity checks */ -- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -+ if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - pState = pZip->m_pState; -@@ -6828,7 +6842,7 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * - - if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) - { -- const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); -+ // const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); - - if (field_data_size < sizeof(mz_uint64) * 2) - { -@@ -6836,8 +6850,8 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - } - -- local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); -- local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ -+ // local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); -+ // local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ - - found_zip64_ext_data_in_ldir = MZ_TRUE; - break; -@@ -6966,7 +6980,7 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - } - -- cur_src_file_ofs += n; -+ // cur_src_file_ofs += n; - cur_dst_file_ofs += n; - } - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - -diff --git a/src/zip/miniz/miniz.h b/src/zip/miniz/miniz.h -index 68f903c..e517263 100644 ---- a/src/zip/miniz/miniz.h -+++ b/src/zip/miniz/miniz.h -@@ -203,7 +203,7 @@ mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); - - #define MZ_CRC32_INIT (0) - /* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ --mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); -+// mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); - - /* Compression strategies. */ - enum -@@ -301,7 +301,7 @@ typedef struct mz_stream_s - typedef mz_stream *mz_streamp; - - /* Returns the version string of miniz.c. */ --const char *mz_version(void); -+// const char *mz_version(void); - - /* mz_deflateInit() initializes a compressor with default options: */ - /* Parameters: */ -@@ -324,7 +324,7 @@ int mz_deflateInit(mz_streamp pStream, int level); - int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); - - /* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ --int mz_deflateReset(mz_streamp pStream); -+// int mz_deflateReset(mz_streamp pStream); - - /* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */ - /* Parameters: */ -@@ -345,7 +345,7 @@ int mz_deflate(mz_streamp pStream, int flush); - int mz_deflateEnd(mz_streamp pStream); - - /* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ --mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); -+// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); - - /* Single-call compression functions mz_compress() and mz_compress2(): */ - /* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ -@@ -353,7 +353,7 @@ int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char * - int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); - - /* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */ --mz_ulong mz_compressBound(mz_ulong source_len); -+// mz_ulong mz_compressBound(mz_ulong source_len); - - /* Initializes a decompressor. */ - int mz_inflateInit(mz_streamp pStream); -@@ -386,7 +386,7 @@ int mz_inflateEnd(mz_streamp pStream); - int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); - - /* Returns a string description of the specified error code, or NULL if the error code is invalid. */ --const char *mz_error(int err); -+// const char *mz_error(int err); - - /* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */ - /* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ -@@ -436,13 +436,13 @@ typedef void *const voidpc; - #define z_stream mz_stream - #define deflateInit mz_deflateInit - #define deflateInit2 mz_deflateInit2 --#define deflateReset mz_deflateReset -+// #define deflateReset mz_deflateReset - #define deflate mz_deflate - #define deflateEnd mz_deflateEnd --#define deflateBound mz_deflateBound -+// #define deflateBound mz_deflateBound - #define compress mz_compress - #define compress2 mz_compress2 --#define compressBound mz_compressBound -+// #define compressBound mz_compressBound - #define inflateInit mz_inflateInit - #define inflateInit2 mz_inflateInit2 - #define inflate mz_inflate -@@ -452,15 +452,15 @@ typedef void *const voidpc; - #define adler32 mz_adler32 - #define MAX_WBITS 15 - #define MAX_MEM_LEVEL 9 --#define zError mz_error -+// #define zError mz_error - #define ZLIB_VERSION MZ_VERSION - #define ZLIB_VERNUM MZ_VERNUM - #define ZLIB_VER_MAJOR MZ_VER_MAJOR - #define ZLIB_VER_MINOR MZ_VER_MINOR - #define ZLIB_VER_REVISION MZ_VER_REVISION - #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION --#define zlibVersion mz_version --#define zlib_version mz_version() -+// #define zlibVersion mz_version -+// #define zlib_version mz_version() - #endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ - - #endif /* MINIZ_NO_ZLIB_APIS */ -@@ -501,15 +501,15 @@ typedef int mz_bool; - #define MZ_FILE FILE - #endif /* #ifdef MINIZ_NO_STDIO */ - --#ifdef MINIZ_NO_TIME --typedef struct mz_dummy_time_t_tag --{ -- int m_dummy; --} mz_dummy_time_t; --#define MZ_TIME_T mz_dummy_time_t --#else --#define MZ_TIME_T time_t --#endif -+// #ifdef MINIZ_NO_TIME -+// typedef struct mz_dummy_time_t_tag -+// { -+// int m_dummy; -+// } mz_dummy_time_t; -+// #define MZ_TIME_T mz_dummy_time_t -+// #else -+// #define MZ_TIME_T time_t -+// #endif - - #define MZ_ASSERT(x) assert(x) - -@@ -551,7 +551,7 @@ extern "C" { - - extern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); - extern void miniz_def_free_func(void *opaque, void *address); --extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); -+// extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); - - #define MZ_UINT16_MAX (0xFFFFU) - #define MZ_UINT32_MAX (0xFFFFFFFFU) -@@ -609,11 +609,11 @@ enum - /* Function returns a pointer to the compressed data, or NULL on failure. */ - /* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */ - /* The caller must free() the returned block when it's no longer needed. */ --void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); -+// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - - /* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ - /* Returns 0 on failure. */ --size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); -+// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - - /* Compresses an image to a compressed PNG file in memory. */ - /* On entry: */ -@@ -625,14 +625,14 @@ size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void - /* Function returns a pointer to the compressed data, or NULL on failure. */ - /* *pLen_out will be set to the size of the PNG image file. */ - /* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */ --void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); --void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); -+// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); -+// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); - - /* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ - typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); - - /* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */ --mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); -+// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - - enum - { -@@ -727,9 +727,9 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI - - /* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ - /* tdefl_compress_buffer() always consumes the entire input buffer. */ --tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); -+// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); - --tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); -+// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); - mz_uint32 tdefl_get_adler32(tdefl_compressor *d); - - /* Create tdefl_compress() flags given zlib-style compression parameters. */ -@@ -741,8 +741,8 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int - /* Allocate the tdefl_compressor structure in C so that */ - /* non-C language bindings to tdefl_ API don't need to worry about */ - /* structure size and allocation mechanism. */ --tdefl_compressor *tdefl_compressor_alloc(); --void tdefl_compressor_free(tdefl_compressor *pComp); -+// tdefl_compressor *tdefl_compressor_alloc(); -+// void tdefl_compressor_free(tdefl_compressor *pComp); - - #ifdef __cplusplus - } -@@ -775,17 +775,17 @@ enum - /* Function returns a pointer to the decompressed data, or NULL on failure. */ - /* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */ - /* The caller must call mz_free() on the returned block when it's no longer needed. */ --void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); -+// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - - /* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ - /* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ - #define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) --size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); -+// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - - /* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */ - /* Returns 1 on success or 0 on failure. */ - typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); --int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); -+// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - - struct tinfl_decompressor_tag; - typedef struct tinfl_decompressor_tag tinfl_decompressor; -@@ -794,8 +794,8 @@ typedef struct tinfl_decompressor_tag tinfl_decompressor; - /* non-C language bindings to tinfl_ API don't need to worry about */ - /* structure size and allocation mechanism. */ - --tinfl_decompressor *tinfl_decompressor_alloc(); --void tinfl_decompressor_free(tinfl_decompressor *pDecomp); -+// tinfl_decompressor *tinfl_decompressor_alloc(); -+// void tinfl_decompressor_free(tinfl_decompressor *pDecomp); - - /* Max size of LZ dictionary. */ - #define TINFL_LZ_DICT_SIZE 32768 -@@ -896,319 +896,319 @@ struct tinfl_decompressor_tag - - /* ------------------- ZIP archive reading/writing */ - --#ifndef MINIZ_NO_ARCHIVE_APIS -+// #ifndef MINIZ_NO_ARCHIVE_APIS - --#ifdef __cplusplus --extern "C" { --#endif -+// #ifdef __cplusplus -+// extern "C" { -+// #endif - --enum --{ -+// enum -+// { - /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ -- MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, -- MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, -- MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 --}; -- --typedef struct --{ -- /* Central directory file index. */ -- mz_uint32 m_file_index; -+// MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, -+// MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, -+// MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 -+// }; -+ -+// typedef struct -+// { -+// /* Central directory file index. */ -+// mz_uint32 m_file_index; -+ -+// /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ -+// mz_uint64 m_central_dir_ofs; -+ -+// /* These fields are copied directly from the zip's central dir. */ -+// mz_uint16 m_version_made_by; -+// mz_uint16 m_version_needed; -+// mz_uint16 m_bit_flag; -+// mz_uint16 m_method; -+ -+// #ifndef MINIZ_NO_TIME -+// MZ_TIME_T m_time; -+// #endif - -- /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ -- mz_uint64 m_central_dir_ofs; -+// /* CRC-32 of uncompressed data. */ -+// mz_uint32 m_crc32; - -- /* These fields are copied directly from the zip's central dir. */ -- mz_uint16 m_version_made_by; -- mz_uint16 m_version_needed; -- mz_uint16 m_bit_flag; -- mz_uint16 m_method; -+// /* File's compressed size. */ -+// mz_uint64 m_comp_size; - --#ifndef MINIZ_NO_TIME -- MZ_TIME_T m_time; --#endif -+// /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ -+// mz_uint64 m_uncomp_size; - -- /* CRC-32 of uncompressed data. */ -- mz_uint32 m_crc32; -+// /* Zip internal and external file attributes. */ -+// mz_uint16 m_internal_attr; -+// mz_uint32 m_external_attr; - -- /* File's compressed size. */ -- mz_uint64 m_comp_size; -+// /* Entry's local header file offset in bytes. */ -+// mz_uint64 m_local_header_ofs; - -- /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ -- mz_uint64 m_uncomp_size; -+// /* Size of comment in bytes. */ -+// mz_uint32 m_comment_size; - -- /* Zip internal and external file attributes. */ -- mz_uint16 m_internal_attr; -- mz_uint32 m_external_attr; -+// /* MZ_TRUE if the entry appears to be a directory. */ -+// mz_bool m_is_directory; - -- /* Entry's local header file offset in bytes. */ -- mz_uint64 m_local_header_ofs; -+// /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ -+// mz_bool m_is_encrypted; - -- /* Size of comment in bytes. */ -- mz_uint32 m_comment_size; -+// /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ -+// mz_bool m_is_supported; - -- /* MZ_TRUE if the entry appears to be a directory. */ -- mz_bool m_is_directory; -+// /* Filename. If string ends in '/' it's a subdirectory entry. */ -+// /* Guaranteed to be zero terminated, may be truncated to fit. */ -+// char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; - -- /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ -- mz_bool m_is_encrypted; -+// /* Comment field. */ -+// /* Guaranteed to be zero terminated, may be truncated to fit. */ -+// char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; - -- /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ -- mz_bool m_is_supported; -+// } mz_zip_archive_file_stat; - -- /* Filename. If string ends in '/' it's a subdirectory entry. */ -- /* Guaranteed to be zero terminated, may be truncated to fit. */ -- char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; -+// typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); -+// typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); -+// typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); - -- /* Comment field. */ -- /* Guaranteed to be zero terminated, may be truncated to fit. */ -- char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; -+// struct mz_zip_internal_state_tag; -+// typedef struct mz_zip_internal_state_tag mz_zip_internal_state; - --} mz_zip_archive_file_stat; -+// typedef enum { -+// MZ_ZIP_MODE_INVALID = 0, -+// MZ_ZIP_MODE_READING = 1, -+// MZ_ZIP_MODE_WRITING = 2, -+// MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 -+// } mz_zip_mode; - --typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); --typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); --typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); -+// typedef enum { -+// MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, -+// MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, -+// MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, -+// MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, -+ // MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ -+ // MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ -+ // MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ -+// MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, -+// MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 -+// } mz_zip_flags; - --struct mz_zip_internal_state_tag; --typedef struct mz_zip_internal_state_tag mz_zip_internal_state; -- --typedef enum { -- MZ_ZIP_MODE_INVALID = 0, -- MZ_ZIP_MODE_READING = 1, -- MZ_ZIP_MODE_WRITING = 2, -- MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 --} mz_zip_mode; -- --typedef enum { -- MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, -- MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, -- MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, -- MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, -- MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ -- MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ -- MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ -- MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, -- MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 --} mz_zip_flags; -- --typedef enum { -- MZ_ZIP_TYPE_INVALID = 0, -- MZ_ZIP_TYPE_USER, -- MZ_ZIP_TYPE_MEMORY, -- MZ_ZIP_TYPE_HEAP, -- MZ_ZIP_TYPE_FILE, -- MZ_ZIP_TYPE_CFILE, -- MZ_ZIP_TOTAL_TYPES --} mz_zip_type; -+// typedef enum { -+// MZ_ZIP_TYPE_INVALID = 0, -+// MZ_ZIP_TYPE_USER, -+// MZ_ZIP_TYPE_MEMORY, -+// MZ_ZIP_TYPE_HEAP, -+// MZ_ZIP_TYPE_FILE, -+// MZ_ZIP_TYPE_CFILE, -+// MZ_ZIP_TOTAL_TYPES -+// } mz_zip_type; - - /* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ --typedef enum { -- MZ_ZIP_NO_ERROR = 0, -- MZ_ZIP_UNDEFINED_ERROR, -- MZ_ZIP_TOO_MANY_FILES, -- MZ_ZIP_FILE_TOO_LARGE, -- MZ_ZIP_UNSUPPORTED_METHOD, -- MZ_ZIP_UNSUPPORTED_ENCRYPTION, -- MZ_ZIP_UNSUPPORTED_FEATURE, -- MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, -- MZ_ZIP_NOT_AN_ARCHIVE, -- MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, -- MZ_ZIP_UNSUPPORTED_MULTIDISK, -- MZ_ZIP_DECOMPRESSION_FAILED, -- MZ_ZIP_COMPRESSION_FAILED, -- MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, -- MZ_ZIP_CRC_CHECK_FAILED, -- MZ_ZIP_UNSUPPORTED_CDIR_SIZE, -- MZ_ZIP_ALLOC_FAILED, -- MZ_ZIP_FILE_OPEN_FAILED, -- MZ_ZIP_FILE_CREATE_FAILED, -- MZ_ZIP_FILE_WRITE_FAILED, -- MZ_ZIP_FILE_READ_FAILED, -- MZ_ZIP_FILE_CLOSE_FAILED, -- MZ_ZIP_FILE_SEEK_FAILED, -- MZ_ZIP_FILE_STAT_FAILED, -- MZ_ZIP_INVALID_PARAMETER, -- MZ_ZIP_INVALID_FILENAME, -- MZ_ZIP_BUF_TOO_SMALL, -- MZ_ZIP_INTERNAL_ERROR, -- MZ_ZIP_FILE_NOT_FOUND, -- MZ_ZIP_ARCHIVE_TOO_LARGE, -- MZ_ZIP_VALIDATION_FAILED, -- MZ_ZIP_WRITE_CALLBACK_FAILED, -- MZ_ZIP_TOTAL_ERRORS --} mz_zip_error; -- --typedef struct --{ -- mz_uint64 m_archive_size; -- mz_uint64 m_central_directory_file_ofs; -- -- /* We only support up to UINT32_MAX files in zip64 mode. */ -- mz_uint32 m_total_files; -- mz_zip_mode m_zip_mode; -- mz_zip_type m_zip_type; -- mz_zip_error m_last_error; -- -- mz_uint64 m_file_offset_alignment; -- -- mz_alloc_func m_pAlloc; -- mz_free_func m_pFree; -- mz_realloc_func m_pRealloc; -- void *m_pAlloc_opaque; -- -- mz_file_read_func m_pRead; -- mz_file_write_func m_pWrite; -- mz_file_needs_keepalive m_pNeeds_keepalive; -- void *m_pIO_opaque; -- -- mz_zip_internal_state *m_pState; -- --} mz_zip_archive; -- --typedef struct --{ -- mz_zip_archive *pZip; -- mz_uint flags; -- -- int status; --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- mz_uint file_crc32; --#endif -- mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; -- mz_zip_archive_file_stat file_stat; -- void *pRead_buf; -- void *pWrite_buf; -+// typedef enum { -+// MZ_ZIP_NO_ERROR = 0, -+// MZ_ZIP_UNDEFINED_ERROR, -+// MZ_ZIP_TOO_MANY_FILES, -+// MZ_ZIP_FILE_TOO_LARGE, -+// MZ_ZIP_UNSUPPORTED_METHOD, -+// MZ_ZIP_UNSUPPORTED_ENCRYPTION, -+// MZ_ZIP_UNSUPPORTED_FEATURE, -+// MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, -+// MZ_ZIP_NOT_AN_ARCHIVE, -+// MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, -+// MZ_ZIP_UNSUPPORTED_MULTIDISK, -+// MZ_ZIP_DECOMPRESSION_FAILED, -+// MZ_ZIP_COMPRESSION_FAILED, -+// MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, -+// MZ_ZIP_CRC_CHECK_FAILED, -+// MZ_ZIP_UNSUPPORTED_CDIR_SIZE, -+// MZ_ZIP_ALLOC_FAILED, -+// MZ_ZIP_FILE_OPEN_FAILED, -+// MZ_ZIP_FILE_CREATE_FAILED, -+// MZ_ZIP_FILE_WRITE_FAILED, -+// MZ_ZIP_FILE_READ_FAILED, -+// MZ_ZIP_FILE_CLOSE_FAILED, -+// MZ_ZIP_FILE_SEEK_FAILED, -+// MZ_ZIP_FILE_STAT_FAILED, -+// MZ_ZIP_INVALID_PARAMETER, -+// MZ_ZIP_INVALID_FILENAME, -+// MZ_ZIP_BUF_TOO_SMALL, -+// MZ_ZIP_INTERNAL_ERROR, -+// MZ_ZIP_FILE_NOT_FOUND, -+// MZ_ZIP_ARCHIVE_TOO_LARGE, -+// MZ_ZIP_VALIDATION_FAILED, -+// MZ_ZIP_WRITE_CALLBACK_FAILED, -+// MZ_ZIP_TOTAL_ERRORS -+// } mz_zip_error; -+ -+// typedef struct -+// { -+// mz_uint64 m_archive_size; -+// mz_uint64 m_central_directory_file_ofs; -+ -+// /* We only support up to UINT32_MAX files in zip64 mode. */ -+// mz_uint32 m_total_files; -+// mz_zip_mode m_zip_mode; -+// mz_zip_type m_zip_type; -+// mz_zip_error m_last_error; -+ -+// mz_uint64 m_file_offset_alignment; -+ -+// mz_alloc_func m_pAlloc; -+// mz_free_func m_pFree; -+// mz_realloc_func m_pRealloc; -+// void *m_pAlloc_opaque; -+ -+// mz_file_read_func m_pRead; -+// mz_file_write_func m_pWrite; -+// mz_file_needs_keepalive m_pNeeds_keepalive; -+// void *m_pIO_opaque; -+ -+// mz_zip_internal_state *m_pState; -+ -+// } mz_zip_archive; -+ -+// typedef struct -+// { -+// mz_zip_archive *pZip; -+// mz_uint flags; -+ -+// int status; -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// mz_uint file_crc32; -+// #endif -+// mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; -+// mz_zip_archive_file_stat file_stat; -+// void *pRead_buf; -+// void *pWrite_buf; - -- size_t out_blk_remain; -+// size_t out_blk_remain; - -- tinfl_decompressor inflator; -+// tinfl_decompressor inflator; - --} mz_zip_reader_extract_iter_state; -+// } mz_zip_reader_extract_iter_state; - - /* -------- ZIP reading */ - - /* Inits a ZIP archive reader. */ - /* These functions read and validate the archive's central directory. */ --mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); -+// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); - --mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); -+// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); - --#ifndef MINIZ_NO_STDIO -+// #ifndef MINIZ_NO_STDIO - /* Read a archive from a disk file. */ - /* file_start_ofs is the file offset where the archive actually begins, or 0. */ - /* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */ --mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); --mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); -+// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); -+// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); - - /* Read an archive from an already opened FILE, beginning at the current file position. */ - /* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */ - /* The FILE will NOT be closed when mz_zip_reader_end() is called. */ --mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); --#endif -+// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); -+// #endif - - /* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */ --mz_bool mz_zip_reader_end(mz_zip_archive *pZip); -+// mz_bool mz_zip_reader_end(mz_zip_archive *pZip); - - /* -------- ZIP reading or writing */ - - /* Clears a mz_zip_archive struct to all zeros. */ - /* Important: This must be done before passing the struct to any mz_zip functions. */ --void mz_zip_zero_struct(mz_zip_archive *pZip); -+// void mz_zip_zero_struct(mz_zip_archive *pZip); - --mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); --mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); -+// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); -+// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); - - /* Returns the total number of files in the archive. */ --mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); -+// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); - --mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); --mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); --MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); -+// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); -+// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); -+// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); - - /* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ --size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); -+// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); - - /* Attempts to locates a file in the archive's central directory. */ - /* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ - /* Returns -1 if the file cannot be found. */ --int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); -+// int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); - /* Returns MZ_FALSE if the file cannot be found. */ --mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex); -+// mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex); - - /* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */ - /* Note that the m_last_error functionality is not thread safe. */ --mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); --mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); --mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); --mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); --const char *mz_zip_get_error_string(mz_zip_error mz_err); -+// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); -+// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); -+// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); -+// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); -+// const char *mz_zip_get_error_string(mz_zip_error mz_err); - - /* MZ_TRUE if the archive file entry is a directory entry. */ --mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); -+// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); - - /* MZ_TRUE if the file is encrypted/strong encrypted. */ --mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); -+// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); - - /* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */ --mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); -+// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); - - /* Retrieves the filename of an archive file entry. */ - /* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */ --mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); -+// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); - - /* Attempts to locates a file in the archive's central directory. */ - /* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ - /* Returns -1 if the file cannot be found. */ --int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); --int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); -+// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); -+// int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); - - /* Returns detailed information about an archive file entry. */ --mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); -+// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); - - /* MZ_TRUE if the file is in zip64 format. */ - /* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */ --mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); -+// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); - - /* Returns the total central directory size in bytes. */ - /* The current max supported size is <= MZ_UINT32_MAX. */ --size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); -+// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); - - /* Extracts a archive file to a memory buffer using no memory allocation. */ - /* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ --mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); --mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); -+// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); -+// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); - - /* Extracts a archive file to a memory buffer. */ --mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); --mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); -+// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); -+// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); - - /* Extracts a archive file to a dynamically allocated heap buffer. */ - /* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ - /* Returns NULL and sets the last error on failure. */ --void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); --void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); -+// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); -+// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); - - /* Extracts a archive file using a callback function to output the file's data. */ --mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); --mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); -+// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); -+// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); - - /* Extract a file iteratively */ --mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); --mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); --size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); --mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); -+// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); -+// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); -+// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); -+// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); - --#ifndef MINIZ_NO_STDIO -+// #ifndef MINIZ_NO_STDIO - /* Extracts a archive file to a disk file and sets its last accessed and modified times. */ - /* This function only extracts files, not archive directory records. */ --mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); --mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); -+// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); -+// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); - - /* Extracts a archive file starting at the current position in the destination FILE stream. */ --mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); --mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); --#endif -+// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); -+// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); -+// #endif - - #if 0 - /* TODO */ -@@ -1233,26 +1233,26 @@ mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pA - // mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); - - /* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ --mz_bool mz_zip_end(mz_zip_archive *pZip); -+// mz_bool mz_zip_end(mz_zip_archive *pZip); - - /* -------- ZIP writing */ - --#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -+// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - - /* Inits a ZIP archive writer. */ - /*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ - /*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ --mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); --mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); -+// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); -+// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); - --mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); --mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); -+// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); -+// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); - --#ifndef MINIZ_NO_STDIO --mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); --mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); --mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); --#endif -+// #ifndef MINIZ_NO_STDIO -+// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); -+// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); -+// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); -+// #endif - - /* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */ - /* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ -@@ -1260,33 +1260,33 @@ mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint f - /* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */ - /* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */ - /* the archive is finalized the file's central directory will be hosed. */ --mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); --mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); -+// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); -+// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); - - /* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */ - /* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ - /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ --mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); -+// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); - - /* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */ - /* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ --mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -- mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); -+// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -+// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); - --mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -- mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, -- const char *user_extra_data_central, mz_uint user_extra_data_central_len); -+// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -+// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, -+// const char *user_extra_data_central, mz_uint user_extra_data_central_len); - --#ifndef MINIZ_NO_STDIO -+// #ifndef MINIZ_NO_STDIO - /* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */ - /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ --mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); -+// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - - /* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ --mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, -- const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, -- const char *user_extra_data_central, mz_uint user_extra_data_central_len); --#endif -+// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, -+// const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, -+// const char *user_extra_data_central, mz_uint user_extra_data_central_len); -+// #endif - - /* Adds a file to an archive by fully cloning the data from another archive. */ - /* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */ -@@ -1295,15 +1295,15 @@ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, - /* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ - /* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ - /* An archive must be manually finalized by calling this function for it to be valid. */ --mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); -+// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); - - /* Finalizes a heap archive, returning a poiner to the heap block and its size. */ - /* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ --mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); -+// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); - - /* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ - /* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */ --mz_bool mz_zip_writer_end(mz_zip_archive *pZip); -+// mz_bool mz_zip_writer_end(mz_zip_archive *pZip); - - /* -------- Misc. high-level helper functions: */ - -@@ -1311,19 +1311,19 @@ mz_bool mz_zip_writer_end(mz_zip_archive *pZip); - /* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */ - /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ - /* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */ --mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); --mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); -+// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); -+// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); - - /* Reads a single file from an archive into a heap block. */ - /* If pComment is not NULL, only the file with the specified comment will be extracted. */ - /* Returns NULL on failure. */ --void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); --void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); -+// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); -+// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); - --#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ -+// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ - --#ifdef __cplusplus --} --#endif -+// #ifdef __cplusplus -+// } -+// #endif - --#endif /* MINIZ_NO_ARCHIVE_APIS */ -+// #endif /* MINIZ_NO_ARCHIVE_APIS */ - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - -diff --git a/src/zip/miniz/miniz.c b/src/zip/miniz/miniz.c -index 9ee7635..910d4b1 100644 ---- a/src/zip/miniz/miniz.c -+++ b/src/zip/miniz/miniz.c -@@ -65,92 +65,92 @@ mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) - } - - /* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */ --#if 0 -- mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) -- { -- static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, -- 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; -- mz_uint32 crcu32 = (mz_uint32)crc; -- if (!ptr) -- return MZ_CRC32_INIT; -- crcu32 = ~crcu32; -- while (buf_len--) -- { -- mz_uint8 b = *ptr++; -- crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; -- crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; -- } -- return ~crcu32; -- } --#else -+// #if 0 -+// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) -+// { -+// static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, -+// 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; -+// mz_uint32 crcu32 = (mz_uint32)crc; -+// if (!ptr) -+// return MZ_CRC32_INIT; -+// crcu32 = ~crcu32; -+// while (buf_len--) -+// { -+// mz_uint8 b = *ptr++; -+// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; -+// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; -+// } -+// return ~crcu32; -+// } -+// #else - /* Faster, but larger CPU cache footprint. - */ --mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) --{ -- static const mz_uint32 s_crc_table[256] = -- { -- 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, -- 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, -- 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, -- 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, -- 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, -- 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, -- 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, -- 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, -- 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, -- 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, -- 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, -- 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, -- 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, -- 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, -- 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, -- 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, -- 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, -- 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, -- 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, -- 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, -- 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, -- 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, -- 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, -- 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, -- 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, -- 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, -- 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, -- 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, -- 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, -- 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, -- 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, -- 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, -- 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, -- 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, -- 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, -- 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, -- 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -- }; -- -- mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; -- const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; -- -- while (buf_len >= 4) -- { -- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; -- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; -- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; -- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; -- pByte_buf += 4; -- buf_len -= 4; -- } -+// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) -+// { -+// static const mz_uint32 s_crc_table[256] = -+// { -+// 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, -+// 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, -+// 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, -+// 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, -+// 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, -+// 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, -+// 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, -+// 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, -+// 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, -+// 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, -+// 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, -+// 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, -+// 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, -+// 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, -+// 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, -+// 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, -+// 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, -+// 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, -+// 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, -+// 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, -+// 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, -+// 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, -+// 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, -+// 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, -+// 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, -+// 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, -+// 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, -+// 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, -+// 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, -+// 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, -+// 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, -+// 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, -+// 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, -+// 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, -+// 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, -+// 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, -+// 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -+// }; -+ -+// mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; -+// const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; -+ -+// while (buf_len >= 4) -+// { -+// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; -+// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; -+// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; -+// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; -+// pByte_buf += 4; -+// buf_len -= 4; -+// } - -- while (buf_len) -- { -- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; -- ++pByte_buf; -- --buf_len; -- } -+// while (buf_len) -+// { -+// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; -+// ++pByte_buf; -+// --buf_len; -+// } - -- return ~crc32; --} --#endif -+// return ~crc32; -+// } -+// #endif - - void mz_free(void *p) - { -@@ -167,16 +167,16 @@ void miniz_def_free_func(void *opaque, void *address) - (void)opaque, (void)address; - MZ_FREE(address); - } --void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) --{ -- (void)opaque, (void)address, (void)items, (void)size; -- return MZ_REALLOC(address, items * size); --} -+// void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) -+// { -+// (void)opaque, (void)address, (void)items, (void)size; -+// return MZ_REALLOC(address, items * size); -+// } - --const char *mz_version(void) --{ -- return MZ_VERSION; --} -+// const char *mz_version(void) -+// { -+// return MZ_VERSION; -+// } - - #ifndef MINIZ_NO_ZLIB_APIS - -@@ -221,14 +221,14 @@ int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, - return MZ_OK; - } - --int mz_deflateReset(mz_streamp pStream) --{ -- if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) -- return MZ_STREAM_ERROR; -- pStream->total_in = pStream->total_out = 0; -- tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); -- return MZ_OK; --} -+// int mz_deflateReset(mz_streamp pStream) -+// { -+// if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) -+// return MZ_STREAM_ERROR; -+// pStream->total_in = pStream->total_out = 0; -+// tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); -+// return MZ_OK; -+// } - - int mz_deflate(mz_streamp pStream, int flush) - { -@@ -300,12 +300,12 @@ int mz_deflateEnd(mz_streamp pStream) - return MZ_OK; - } - --mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) --{ -- (void)pStream; -- /* This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) */ -- return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); --} -+// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) -+// { -+// (void)pStream; -+// This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) -+// return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); -+// } - - int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) - { -@@ -342,10 +342,10 @@ int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char * - return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); - } - --mz_ulong mz_compressBound(mz_ulong source_len) --{ -- return mz_deflateBound(NULL, source_len); --} -+// mz_ulong mz_compressBound(mz_ulong source_len) -+// { -+// return mz_deflateBound(NULL, source_len); -+// } - - typedef struct - { -@@ -551,22 +551,22 @@ int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char - return mz_inflateEnd(&stream); - } - --const char *mz_error(int err) --{ -- static struct -- { -- int m_err; -- const char *m_pDesc; -- } s_error_descs[] = -- { -- { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } -- }; -- mz_uint i; -- for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) -- if (s_error_descs[i].m_err == err) -- return s_error_descs[i].m_pDesc; -- return NULL; --} -+// const char *mz_error(int err) -+// { -+// static struct -+// { -+// int m_err; -+// const char *m_pDesc; -+// } s_error_descs[] = -+// { -+// { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } -+// }; -+// mz_uint i; -+// for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) -+// if (s_error_descs[i].m_err == err) -+// return s_error_descs[i].m_pDesc; -+// return NULL; -+// } - - #endif /*MINIZ_NO_ZLIB_APIS */ - -@@ -1049,7 +1049,7 @@ static void tdefl_start_static_block(tdefl_compressor *d) - TDEFL_PUT_BITS(1, 2); - } - --static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; -+static const mz_uint16 mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; - - #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS - static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) -@@ -1358,7 +1358,6 @@ static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p) - #endif - static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) - { -- printf("\n--------------------------------------------------- DEBUG ---------------------------------------\n"); - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; - mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; -@@ -1456,176 +1455,176 @@ static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahe - } - #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ - --#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN --static mz_bool tdefl_compress_fast(tdefl_compressor *d) --{ -- /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ -- mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; -- mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; -- mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; -+// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -+// static mz_bool tdefl_compress_fast(tdefl_compressor *d) -+// { -+// /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ -+// mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; -+// mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; -+// mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - -- while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) -- { -- const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; -- mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; -- mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); -- d->m_src_buf_left -= num_bytes_to_process; -- lookahead_size += num_bytes_to_process; -+// while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) -+// { -+// const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; -+// mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; -+// mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); -+// d->m_src_buf_left -= num_bytes_to_process; -+// lookahead_size += num_bytes_to_process; - -- while (num_bytes_to_process) -- { -- mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); -- memcpy(d->m_dict + dst_pos, d->m_pSrc, n); -- if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) -- memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); -- d->m_pSrc += n; -- dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; -- num_bytes_to_process -= n; -- } -+// while (num_bytes_to_process) -+// { -+// mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); -+// memcpy(d->m_dict + dst_pos, d->m_pSrc, n); -+// if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) -+// memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); -+// d->m_pSrc += n; -+// dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; -+// num_bytes_to_process -= n; -+// } - -- dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); -- if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) -- break; -+// dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); -+// if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) -+// break; - -- while (lookahead_size >= 4) -- { -- mz_uint cur_match_dist, cur_match_len = 1; -- mz_uint8 *pCur_dict = d->m_dict + cur_pos; -- mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; -- mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; -- mz_uint probe_pos = d->m_hash[hash]; -- d->m_hash[hash] = (mz_uint16)lookahead_pos; -- -- if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) -- { -- const mz_uint16 *p = (const mz_uint16 *)pCur_dict; -- const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); -- mz_uint32 probe_len = 32; -- do -- { -- } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && -- (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); -- cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); -- if (!probe_len) -- cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; -+// while (lookahead_size >= 4) -+// { -+// mz_uint cur_match_dist, cur_match_len = 1; -+// mz_uint8 *pCur_dict = d->m_dict + cur_pos; -+// mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; -+// mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; -+// mz_uint probe_pos = d->m_hash[hash]; -+// d->m_hash[hash] = (mz_uint16)lookahead_pos; -+ -+// if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) -+// { -+// const mz_uint16 *p = (const mz_uint16 *)pCur_dict; -+// const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); -+// mz_uint32 probe_len = 32; -+// do -+// { -+// } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && -+// (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); -+// cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); -+// if (!probe_len) -+// cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; - -- if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) -- { -- cur_match_len = 1; -- *pLZ_code_buf++ = (mz_uint8)first_trigram; -- *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -- d->m_huff_count[0][(mz_uint8)first_trigram]++; -- } -- else -- { -- mz_uint32 s0, s1; -- cur_match_len = MZ_MIN(cur_match_len, lookahead_size); -+// if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) -+// { -+// cur_match_len = 1; -+// *pLZ_code_buf++ = (mz_uint8)first_trigram; -+// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -+// d->m_huff_count[0][(mz_uint8)first_trigram]++; -+// } -+// else -+// { -+// mz_uint32 s0, s1; -+// cur_match_len = MZ_MIN(cur_match_len, lookahead_size); - -- MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); -+// MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); - -- cur_match_dist--; -+// cur_match_dist--; - -- pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); -- *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; -- pLZ_code_buf += 3; -- *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); -+// pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); -+// *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; -+// pLZ_code_buf += 3; -+// *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); - -- s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; -- s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; -- d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; -+// s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; -+// s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; -+// d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; - -- d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; -- } -- } -- else -- { -- *pLZ_code_buf++ = (mz_uint8)first_trigram; -- *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -- d->m_huff_count[0][(mz_uint8)first_trigram]++; -- } -+// d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; -+// } -+// } -+// else -+// { -+// *pLZ_code_buf++ = (mz_uint8)first_trigram; -+// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -+// d->m_huff_count[0][(mz_uint8)first_trigram]++; -+// } - -- if (--num_flags_left == 0) -- { -- num_flags_left = 8; -- pLZ_flags = pLZ_code_buf++; -- } -+// if (--num_flags_left == 0) -+// { -+// num_flags_left = 8; -+// pLZ_flags = pLZ_code_buf++; -+// } - -- total_lz_bytes += cur_match_len; -- lookahead_pos += cur_match_len; -- dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); -- cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; -- MZ_ASSERT(lookahead_size >= cur_match_len); -- lookahead_size -= cur_match_len; -+// total_lz_bytes += cur_match_len; -+// lookahead_pos += cur_match_len; -+// dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); -+// cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; -+// MZ_ASSERT(lookahead_size >= cur_match_len); -+// lookahead_size -= cur_match_len; - -- if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) -- { -- int n; -- d->m_lookahead_pos = lookahead_pos; -- d->m_lookahead_size = lookahead_size; -- d->m_dict_size = dict_size; -- d->m_total_lz_bytes = total_lz_bytes; -- d->m_pLZ_code_buf = pLZ_code_buf; -- d->m_pLZ_flags = pLZ_flags; -- d->m_num_flags_left = num_flags_left; -- if ((n = tdefl_flush_block(d, 0)) != 0) -- return (n < 0) ? MZ_FALSE : MZ_TRUE; -- total_lz_bytes = d->m_total_lz_bytes; -- pLZ_code_buf = d->m_pLZ_code_buf; -- pLZ_flags = d->m_pLZ_flags; -- num_flags_left = d->m_num_flags_left; -- } -- } -+// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) -+// { -+// int n; -+// d->m_lookahead_pos = lookahead_pos; -+// d->m_lookahead_size = lookahead_size; -+// d->m_dict_size = dict_size; -+// d->m_total_lz_bytes = total_lz_bytes; -+// d->m_pLZ_code_buf = pLZ_code_buf; -+// d->m_pLZ_flags = pLZ_flags; -+// d->m_num_flags_left = num_flags_left; -+// if ((n = tdefl_flush_block(d, 0)) != 0) -+// return (n < 0) ? MZ_FALSE : MZ_TRUE; -+// total_lz_bytes = d->m_total_lz_bytes; -+// pLZ_code_buf = d->m_pLZ_code_buf; -+// pLZ_flags = d->m_pLZ_flags; -+// num_flags_left = d->m_num_flags_left; -+// } -+// } - -- while (lookahead_size) -- { -- mz_uint8 lit = d->m_dict[cur_pos]; -+// while (lookahead_size) -+// { -+// mz_uint8 lit = d->m_dict[cur_pos]; - -- total_lz_bytes++; -- *pLZ_code_buf++ = lit; -- *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -- if (--num_flags_left == 0) -- { -- num_flags_left = 8; -- pLZ_flags = pLZ_code_buf++; -- } -+// total_lz_bytes++; -+// *pLZ_code_buf++ = lit; -+// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -+// if (--num_flags_left == 0) -+// { -+// num_flags_left = 8; -+// pLZ_flags = pLZ_code_buf++; -+// } - -- d->m_huff_count[0][lit]++; -+// d->m_huff_count[0][lit]++; - -- lookahead_pos++; -- dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); -- cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; -- lookahead_size--; -+// lookahead_pos++; -+// dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); -+// cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; -+// lookahead_size--; - -- if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) -- { -- int n; -- d->m_lookahead_pos = lookahead_pos; -- d->m_lookahead_size = lookahead_size; -- d->m_dict_size = dict_size; -- d->m_total_lz_bytes = total_lz_bytes; -- d->m_pLZ_code_buf = pLZ_code_buf; -- d->m_pLZ_flags = pLZ_flags; -- d->m_num_flags_left = num_flags_left; -- if ((n = tdefl_flush_block(d, 0)) != 0) -- return (n < 0) ? MZ_FALSE : MZ_TRUE; -- total_lz_bytes = d->m_total_lz_bytes; -- pLZ_code_buf = d->m_pLZ_code_buf; -- pLZ_flags = d->m_pLZ_flags; -- num_flags_left = d->m_num_flags_left; -- } -- } -- } -+// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) -+// { -+// int n; -+// d->m_lookahead_pos = lookahead_pos; -+// d->m_lookahead_size = lookahead_size; -+// d->m_dict_size = dict_size; -+// d->m_total_lz_bytes = total_lz_bytes; -+// d->m_pLZ_code_buf = pLZ_code_buf; -+// d->m_pLZ_flags = pLZ_flags; -+// d->m_num_flags_left = num_flags_left; -+// if ((n = tdefl_flush_block(d, 0)) != 0) -+// return (n < 0) ? MZ_FALSE : MZ_TRUE; -+// total_lz_bytes = d->m_total_lz_bytes; -+// pLZ_code_buf = d->m_pLZ_code_buf; -+// pLZ_flags = d->m_pLZ_flags; -+// num_flags_left = d->m_num_flags_left; -+// } -+// } -+// } - -- d->m_lookahead_pos = lookahead_pos; -- d->m_lookahead_size = lookahead_size; -- d->m_dict_size = dict_size; -- d->m_total_lz_bytes = total_lz_bytes; -- d->m_pLZ_code_buf = pLZ_code_buf; -- d->m_pLZ_flags = pLZ_flags; -- d->m_num_flags_left = num_flags_left; -- return MZ_TRUE; --} --#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ -+// d->m_lookahead_pos = lookahead_pos; -+// d->m_lookahead_size = lookahead_size; -+// d->m_dict_size = dict_size; -+// d->m_total_lz_bytes = total_lz_bytes; -+// d->m_pLZ_code_buf = pLZ_code_buf; -+// d->m_pLZ_flags = pLZ_flags; -+// d->m_num_flags_left = num_flags_left; -+// return MZ_TRUE; -+// } -+// #endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ - - static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) - { -@@ -1870,16 +1869,16 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI - if ((d->m_output_flush_remaining) || (d->m_finished)) - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); - --#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -- if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && -- ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && -- ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) -- { -- if (!tdefl_compress_fast(d)) -- return d->m_prev_return_status; -- } -- else --#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ -+// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -+// if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && -+// ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && -+// ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) -+// { -+// if (!tdefl_compress_fast(d)) -+// return d->m_prev_return_status; -+// } -+// else -+// #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ - { - if (!tdefl_compress_normal(d)) - return d->m_prev_return_status; -@@ -1904,11 +1903,11 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); - } - --tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) --{ -- MZ_ASSERT(d->m_pPut_buf_func); -- return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); --} -+// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) -+// { -+// MZ_ASSERT(d->m_pPut_buf_func); -+// return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); -+// } - - tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) - { -@@ -1944,92 +1943,92 @@ tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_fun - return TDEFL_STATUS_OKAY; - } - --tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) --{ -- return d->m_prev_return_status; --} -+// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) -+// { -+// return d->m_prev_return_status; -+// } - - mz_uint32 tdefl_get_adler32(tdefl_compressor *d) - { - return d->m_adler32; - } - --mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) --{ -- tdefl_compressor *pComp; -- mz_bool succeeded; -- if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) -- return MZ_FALSE; -- pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -- if (!pComp) -- return MZ_FALSE; -- succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); -- succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); -- MZ_FREE(pComp); -- return succeeded; --} -+// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -+// { -+// tdefl_compressor *pComp; -+// mz_bool succeeded; -+// if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) -+// return MZ_FALSE; -+// pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -+// if (!pComp) -+// return MZ_FALSE; -+// succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); -+// succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); -+// MZ_FREE(pComp); -+// return succeeded; -+// } - --typedef struct --{ -- size_t m_size, m_capacity; -- mz_uint8 *m_pBuf; -- mz_bool m_expandable; --} tdefl_output_buffer; -+// typedef struct -+// { -+// size_t m_size, m_capacity; -+// mz_uint8 *m_pBuf; -+// mz_bool m_expandable; -+// } tdefl_output_buffer; - --static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) --{ -- tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; -- size_t new_size = p->m_size + len; -- if (new_size > p->m_capacity) -- { -- size_t new_capacity = p->m_capacity; -- mz_uint8 *pNew_buf; -- if (!p->m_expandable) -- return MZ_FALSE; -- do -- { -- new_capacity = MZ_MAX(128U, new_capacity << 1U); -- } while (new_size > new_capacity); -- pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); -- if (!pNew_buf) -- return MZ_FALSE; -- p->m_pBuf = pNew_buf; -- p->m_capacity = new_capacity; -- } -- memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); -- p->m_size = new_size; -- return MZ_TRUE; --} -+// static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) -+// { -+// tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; -+// size_t new_size = p->m_size + len; -+// if (new_size > p->m_capacity) -+// { -+// size_t new_capacity = p->m_capacity; -+// mz_uint8 *pNew_buf; -+// if (!p->m_expandable) -+// return MZ_FALSE; -+// do -+// { -+// new_capacity = MZ_MAX(128U, new_capacity << 1U); -+// } while (new_size > new_capacity); -+// pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); -+// if (!pNew_buf) -+// return MZ_FALSE; -+// p->m_pBuf = pNew_buf; -+// p->m_capacity = new_capacity; -+// } -+// memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); -+// p->m_size = new_size; -+// return MZ_TRUE; -+// } - --void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) --{ -- tdefl_output_buffer out_buf; -- MZ_CLEAR_OBJ(out_buf); -- if (!pOut_len) -- return MZ_FALSE; -- else -- *pOut_len = 0; -- out_buf.m_expandable = MZ_TRUE; -- if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) -- return NULL; -- *pOut_len = out_buf.m_size; -- return out_buf.m_pBuf; --} -+// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -+// { -+// tdefl_output_buffer out_buf; -+// MZ_CLEAR_OBJ(out_buf); -+// if (!pOut_len) -+// return MZ_FALSE; -+// else -+// *pOut_len = 0; -+// out_buf.m_expandable = MZ_TRUE; -+// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) -+// return NULL; -+// *pOut_len = out_buf.m_size; -+// return out_buf.m_pBuf; -+// } - --size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) --{ -- tdefl_output_buffer out_buf; -- MZ_CLEAR_OBJ(out_buf); -- if (!pOut_buf) -- return 0; -- out_buf.m_pBuf = (mz_uint8 *)pOut_buf; -- out_buf.m_capacity = out_buf_len; -- if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) -- return 0; -- return out_buf.m_size; --} -+// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -+// { -+// tdefl_output_buffer out_buf; -+// MZ_CLEAR_OBJ(out_buf); -+// if (!pOut_buf) -+// return 0; -+// out_buf.m_pBuf = (mz_uint8 *)pOut_buf; -+// out_buf.m_capacity = out_buf_len; -+// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) -+// return 0; -+// return out_buf.m_size; -+// } - --static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; -+static const mz_uint16 s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; - - /* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */ - mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) -@@ -2060,102 +2059,102 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int - /* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at - http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. - This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ --void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) --{ -- /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ -- static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; -- tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -- tdefl_output_buffer out_buf; -- int i, bpl = w * num_chans, y, z; -- mz_uint32 c; -- *pLen_out = 0; -- if (!pComp) -- return NULL; -- MZ_CLEAR_OBJ(out_buf); -- out_buf.m_expandable = MZ_TRUE; -- out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); -- if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) -- { -- MZ_FREE(pComp); -- return NULL; -- } -- /* write dummy header */ -- for (z = 41; z; --z) -- tdefl_output_buffer_putter(&z, 1, &out_buf); -- /* compress image data */ -- tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); -- for (y = 0; y < h; ++y) -- { -- tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); -- tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); -- } -- if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) -- { -- MZ_FREE(pComp); -- MZ_FREE(out_buf.m_pBuf); -- return NULL; -- } -- /* write real header */ -- *pLen_out = out_buf.m_size - 41; -- { -- static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; -- mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, -- 0x0a, 0x1a, 0x0a, 0x00, 0x00, -- 0x00, 0x0d, 0x49, 0x48, 0x44, -- 0x52, 0x00, 0x00, 0x00, 0x00, -- 0x00, 0x00, 0x00, 0x00, 0x08, -- 0x00, 0x00, 0x00, 0x00, 0x00, -- 0x00, 0x00, 0x00, 0x00, 0x00, -- 0x00, 0x00, 0x49, 0x44, 0x41, -- 0x54 }; -- pnghdr[18] = (mz_uint8)(w >> 8); -- pnghdr[19] = (mz_uint8)w; -- pnghdr[22] = (mz_uint8)(h >> 8); -- pnghdr[23] = (mz_uint8)h; -- pnghdr[25] = chans[num_chans]; -- pnghdr[33] = (mz_uint8)(*pLen_out >> 24); -- pnghdr[34] = (mz_uint8)(*pLen_out >> 16); -- pnghdr[35] = (mz_uint8)(*pLen_out >> 8); -- pnghdr[36] = (mz_uint8)*pLen_out; -- c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); -- for (i = 0; i < 4; ++i, c <<= 8) -- ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); -- memcpy(out_buf.m_pBuf, pnghdr, 41); -- } -- /* write footer (IDAT CRC-32, followed by IEND chunk) */ -- if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) -- { -- *pLen_out = 0; -- MZ_FREE(pComp); -- MZ_FREE(out_buf.m_pBuf); -- return NULL; -- } -- c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); -- for (i = 0; i < 4; ++i, c <<= 8) -- (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); -- /* compute final size of file, grab compressed data buffer and return */ -- *pLen_out += 57; -- MZ_FREE(pComp); -- return out_buf.m_pBuf; --} --void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) --{ -+// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) -+// { -+// /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ -+// static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; -+// tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -+// tdefl_output_buffer out_buf; -+// int i, bpl = w * num_chans, y, z; -+// mz_uint32 c; -+// *pLen_out = 0; -+// if (!pComp) -+// return NULL; -+// MZ_CLEAR_OBJ(out_buf); -+// out_buf.m_expandable = MZ_TRUE; -+// out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); -+// if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) -+// { -+// MZ_FREE(pComp); -+// return NULL; -+// } -+// /* write dummy header */ -+// for (z = 41; z; --z) -+// tdefl_output_buffer_putter(&z, 1, &out_buf); -+// /* compress image data */ -+// tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); -+// for (y = 0; y < h; ++y) -+// { -+// tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); -+// tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); -+// } -+// if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) -+// { -+// MZ_FREE(pComp); -+// MZ_FREE(out_buf.m_pBuf); -+// return NULL; -+// } -+// /* write real header */ -+// *pLen_out = out_buf.m_size - 41; -+// { -+// static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; -+// mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, -+// 0x0a, 0x1a, 0x0a, 0x00, 0x00, -+// 0x00, 0x0d, 0x49, 0x48, 0x44, -+// 0x52, 0x00, 0x00, 0x00, 0x00, -+// 0x00, 0x00, 0x00, 0x00, 0x08, -+// 0x00, 0x00, 0x00, 0x00, 0x00, -+// 0x00, 0x00, 0x00, 0x00, 0x00, -+// 0x00, 0x00, 0x49, 0x44, 0x41, -+// 0x54 }; -+// pnghdr[18] = (mz_uint8)(w >> 8); -+// pnghdr[19] = (mz_uint8)w; -+// pnghdr[22] = (mz_uint8)(h >> 8); -+// pnghdr[23] = (mz_uint8)h; -+// pnghdr[25] = chans[num_chans]; -+// pnghdr[33] = (mz_uint8)(*pLen_out >> 24); -+// pnghdr[34] = (mz_uint8)(*pLen_out >> 16); -+// pnghdr[35] = (mz_uint8)(*pLen_out >> 8); -+// pnghdr[36] = (mz_uint8)*pLen_out; -+// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); -+// for (i = 0; i < 4; ++i, c <<= 8) -+// ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); -+// memcpy(out_buf.m_pBuf, pnghdr, 41); -+// } -+// /* write footer (IDAT CRC-32, followed by IEND chunk) */ -+// if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) -+// { -+// *pLen_out = 0; -+// MZ_FREE(pComp); -+// MZ_FREE(out_buf.m_pBuf); -+// return NULL; -+// } -+// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); -+// for (i = 0; i < 4; ++i, c <<= 8) -+// (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); -+// /* compute final size of file, grab compressed data buffer and return */ -+// *pLen_out += 57; -+// MZ_FREE(pComp); -+// return out_buf.m_pBuf; -+// } -+// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) -+// { - /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */ -- return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); --} -+// return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); -+// } - - /* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ - /* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ - /* structure size and allocation mechanism. */ --tdefl_compressor *tdefl_compressor_alloc() --{ -- return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); --} -+// tdefl_compressor *tdefl_compressor_alloc() -+// { -+// return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -+// } - --void tdefl_compressor_free(tdefl_compressor *pComp) --{ -- MZ_FREE(pComp); --} -+// void tdefl_compressor_free(tdefl_compressor *pComp) -+// { -+// MZ_FREE(pComp); -+// } - - #ifdef _MSC_VER - #pragma warning(pop) -@@ -2339,12 +2338,12 @@ extern "C" { - - tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) - { -- static const int s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; -- static const int s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; -- static const int s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; -- static const int s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; -+ static const mz_uint16 s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; -+ static const mz_uint8 s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; -+ static const mz_uint16 s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; -+ static const mz_uint8 s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; - static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; -- static const int s_min_table_sizes[3] = { 257, 1, 4 }; -+ static const mz_uint16 s_min_table_sizes[3] = { 257, 1, 4 }; - - tinfl_status status = TINFL_STATUS_FAILED; - mz_uint32 num_bits, dist, counter, num_extra; -@@ -2805,94 +2804,94 @@ common_exit: - } - - /* Higher level helper functions. */ --void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) --{ -- tinfl_decompressor decomp; -- void *pBuf = NULL, *pNew_buf; -- size_t src_buf_ofs = 0, out_buf_capacity = 0; -- *pOut_len = 0; -- tinfl_init(&decomp); -- for (;;) -- { -- size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; -- tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, -- (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); -- if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) -- { -- MZ_FREE(pBuf); -- *pOut_len = 0; -- return NULL; -- } -- src_buf_ofs += src_buf_size; -- *pOut_len += dst_buf_size; -- if (status == TINFL_STATUS_DONE) -- break; -- new_out_buf_capacity = out_buf_capacity * 2; -- if (new_out_buf_capacity < 128) -- new_out_buf_capacity = 128; -- pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); -- if (!pNew_buf) -- { -- MZ_FREE(pBuf); -- *pOut_len = 0; -- return NULL; -- } -- pBuf = pNew_buf; -- out_buf_capacity = new_out_buf_capacity; -- } -- return pBuf; --} -+// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -+// { -+// tinfl_decompressor decomp; -+// void *pBuf = NULL, *pNew_buf; -+// size_t src_buf_ofs = 0, out_buf_capacity = 0; -+// *pOut_len = 0; -+// tinfl_init(&decomp); -+// for (;;) -+// { -+// size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; -+// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, -+// (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); -+// if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) -+// { -+// MZ_FREE(pBuf); -+// *pOut_len = 0; -+// return NULL; -+// } -+// src_buf_ofs += src_buf_size; -+// *pOut_len += dst_buf_size; -+// if (status == TINFL_STATUS_DONE) -+// break; -+// new_out_buf_capacity = out_buf_capacity * 2; -+// if (new_out_buf_capacity < 128) -+// new_out_buf_capacity = 128; -+// pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); -+// if (!pNew_buf) -+// { -+// MZ_FREE(pBuf); -+// *pOut_len = 0; -+// return NULL; -+// } -+// pBuf = pNew_buf; -+// out_buf_capacity = new_out_buf_capacity; -+// } -+// return pBuf; -+// } - --size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) --{ -- tinfl_decompressor decomp; -- tinfl_status status; -- tinfl_init(&decomp); -- status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); -- return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; --} -+// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -+// { -+// tinfl_decompressor decomp; -+// tinfl_status status; -+// tinfl_init(&decomp); -+// status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); -+// return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; -+// } - --int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) --{ -- int result = 0; -- tinfl_decompressor decomp; -- mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); -- size_t in_buf_ofs = 0, dict_ofs = 0; -- if (!pDict) -- return TINFL_STATUS_FAILED; -- tinfl_init(&decomp); -- for (;;) -- { -- size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; -- tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, -- (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); -- in_buf_ofs += in_buf_size; -- if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) -- break; -- if (status != TINFL_STATUS_HAS_MORE_OUTPUT) -- { -- result = (status == TINFL_STATUS_DONE); -- break; -- } -- dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); -- } -- MZ_FREE(pDict); -- *pIn_buf_size = in_buf_ofs; -- return result; --} -+// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -+// { -+// int result = 0; -+// tinfl_decompressor decomp; -+// mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); -+// size_t in_buf_ofs = 0, dict_ofs = 0; -+// if (!pDict) -+// return TINFL_STATUS_FAILED; -+// tinfl_init(&decomp); -+// for (;;) -+// { -+// size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; -+// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, -+// (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); -+// in_buf_ofs += in_buf_size; -+// if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) -+// break; -+// if (status != TINFL_STATUS_HAS_MORE_OUTPUT) -+// { -+// result = (status == TINFL_STATUS_DONE); -+// break; -+// } -+// dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); -+// } -+// MZ_FREE(pDict); -+// *pIn_buf_size = in_buf_ofs; -+// return result; -+// } - --tinfl_decompressor *tinfl_decompressor_alloc() --{ -- tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); -- if (pDecomp) -- tinfl_init(pDecomp); -- return pDecomp; --} -+// tinfl_decompressor *tinfl_decompressor_alloc() -+// { -+// tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); -+// if (pDecomp) -+// tinfl_init(pDecomp); -+// return pDecomp; -+// } - --void tinfl_decompressor_free(tinfl_decompressor *pDecomp) --{ -- MZ_FREE(pDecomp); --} -+// void tinfl_decompressor_free(tinfl_decompressor *pDecomp) -+// { -+// MZ_FREE(pDecomp); -+// } - - #ifdef __cplusplus - } -@@ -2925,461 +2924,461 @@ void tinfl_decompressor_free(tinfl_decompressor *pDecomp) - **************************************************************************/ - - --#ifndef MINIZ_NO_ARCHIVE_APIS -+// #ifndef MINIZ_NO_ARCHIVE_APIS - --#ifdef __cplusplus --extern "C" { --#endif -+// #ifdef __cplusplus -+// extern "C" { -+// #endif - - /* ------------------- .ZIP archive reading */ - --#ifdef MINIZ_NO_STDIO --#define MZ_FILE void * --#else --#include -+// #ifdef MINIZ_NO_STDIO -+// #define MZ_FILE void * -+// #else -+// #include - --#if defined(_MSC_VER) || defined(__MINGW64__) --static FILE *mz_fopen(const char *pFilename, const char *pMode) --{ -- FILE *pFile = NULL; -- fopen_s(&pFile, pFilename, pMode); -- return pFile; --} --static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) --{ -- FILE *pFile = NULL; -- if (freopen_s(&pFile, pPath, pMode, pStream)) -- return NULL; -- return pFile; --} --#ifndef MINIZ_NO_TIME --#include --#endif --#define MZ_FOPEN mz_fopen --#define MZ_FCLOSE fclose --#define MZ_FREAD fread --#define MZ_FWRITE fwrite --#define MZ_FTELL64 _ftelli64 --#define MZ_FSEEK64 _fseeki64 --#define MZ_FILE_STAT_STRUCT _stat --#define MZ_FILE_STAT _stat --#define MZ_FFLUSH fflush --#define MZ_FREOPEN mz_freopen --#define MZ_DELETE_FILE remove --#elif defined(__MINGW32__) --#ifndef MINIZ_NO_TIME --#include --#endif --#define MZ_FOPEN(f, m) fopen(f, m) --#define MZ_FCLOSE fclose --#define MZ_FREAD fread --#define MZ_FWRITE fwrite --#define MZ_FTELL64 ftello64 --#define MZ_FSEEK64 fseeko64 --#define MZ_FILE_STAT_STRUCT _stat --#define MZ_FILE_STAT _stat --#define MZ_FFLUSH fflush --#define MZ_FREOPEN(f, m, s) freopen(f, m, s) --#define MZ_DELETE_FILE remove --#elif defined(__TINYC__) --#ifndef MINIZ_NO_TIME --#include --#endif --#define MZ_FOPEN(f, m) fopen(f, m) --#define MZ_FCLOSE fclose --#define MZ_FREAD fread --#define MZ_FWRITE fwrite --#define MZ_FTELL64 ftell --#define MZ_FSEEK64 fseek --#define MZ_FILE_STAT_STRUCT stat --#define MZ_FILE_STAT stat --#define MZ_FFLUSH fflush --#define MZ_FREOPEN(f, m, s) freopen(f, m, s) --#define MZ_DELETE_FILE remove --#elif defined(__GNUC__) && _LARGEFILE64_SOURCE --#ifndef MINIZ_NO_TIME --#include --#endif --#define MZ_FOPEN(f, m) fopen64(f, m) --#define MZ_FCLOSE fclose --#define MZ_FREAD fread --#define MZ_FWRITE fwrite --#define MZ_FTELL64 ftello64 --#define MZ_FSEEK64 fseeko64 --#define MZ_FILE_STAT_STRUCT stat64 --#define MZ_FILE_STAT stat64 --#define MZ_FFLUSH fflush --#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) --#define MZ_DELETE_FILE remove --#elif defined(__APPLE__) && _LARGEFILE64_SOURCE --#ifndef MINIZ_NO_TIME --#include --#endif --#define MZ_FOPEN(f, m) fopen(f, m) --#define MZ_FCLOSE fclose --#define MZ_FREAD fread --#define MZ_FWRITE fwrite --#define MZ_FTELL64 ftello --#define MZ_FSEEK64 fseeko --#define MZ_FILE_STAT_STRUCT stat --#define MZ_FILE_STAT stat --#define MZ_FFLUSH fflush --#define MZ_FREOPEN(p, m, s) freopen(p, m, s) --#define MZ_DELETE_FILE remove -+// #if defined(_MSC_VER) || defined(__MINGW64__) -+// static FILE *mz_fopen(const char *pFilename, const char *pMode) -+// { -+// FILE *pFile = NULL; -+// fopen_s(&pFile, pFilename, pMode); -+// return pFile; -+// } -+// static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) -+// { -+// FILE *pFile = NULL; -+// if (freopen_s(&pFile, pPath, pMode, pStream)) -+// return NULL; -+// return pFile; -+// } -+// #ifndef MINIZ_NO_TIME -+// #include -+// #endif -+// #define MZ_FOPEN mz_fopen -+// #define MZ_FCLOSE fclose -+// #define MZ_FREAD fread -+// #define MZ_FWRITE fwrite -+// #define MZ_FTELL64 _ftelli64 -+// #define MZ_FSEEK64 _fseeki64 -+// #define MZ_FILE_STAT_STRUCT _stat -+// #define MZ_FILE_STAT _stat -+// #define MZ_FFLUSH fflush -+// #define MZ_FREOPEN mz_freopen -+// #define MZ_DELETE_FILE remove -+// #elif defined(__MINGW32__) -+// #ifndef MINIZ_NO_TIME -+// #include -+// #endif -+// #define MZ_FOPEN(f, m) fopen(f, m) -+// #define MZ_FCLOSE fclose -+// #define MZ_FREAD fread -+// #define MZ_FWRITE fwrite -+// #define MZ_FTELL64 ftello64 -+// #define MZ_FSEEK64 fseeko64 -+// #define MZ_FILE_STAT_STRUCT _stat -+// #define MZ_FILE_STAT _stat -+// #define MZ_FFLUSH fflush -+// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) -+// #define MZ_DELETE_FILE remove -+// #elif defined(__TINYC__) -+// #ifndef MINIZ_NO_TIME -+// #include -+// #endif -+// #define MZ_FOPEN(f, m) fopen(f, m) -+// #define MZ_FCLOSE fclose -+// #define MZ_FREAD fread -+// #define MZ_FWRITE fwrite -+// #define MZ_FTELL64 ftell -+// #define MZ_FSEEK64 fseek -+// #define MZ_FILE_STAT_STRUCT stat -+// #define MZ_FILE_STAT stat -+// #define MZ_FFLUSH fflush -+// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) -+// #define MZ_DELETE_FILE remove -+// #elif defined(__GNUC__) && _LARGEFILE64_SOURCE -+// #ifndef MINIZ_NO_TIME -+// #include -+// #endif -+// #define MZ_FOPEN(f, m) fopen64(f, m) -+// #define MZ_FCLOSE fclose -+// #define MZ_FREAD fread -+// #define MZ_FWRITE fwrite -+// #define MZ_FTELL64 ftello64 -+// #define MZ_FSEEK64 fseeko64 -+// #define MZ_FILE_STAT_STRUCT stat64 -+// #define MZ_FILE_STAT stat64 -+// #define MZ_FFLUSH fflush -+// #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) -+// #define MZ_DELETE_FILE remove -+// #elif defined(__APPLE__) && _LARGEFILE64_SOURCE -+// #ifndef MINIZ_NO_TIME -+// #include -+// #endif -+// #define MZ_FOPEN(f, m) fopen(f, m) -+// #define MZ_FCLOSE fclose -+// #define MZ_FREAD fread -+// #define MZ_FWRITE fwrite -+// #define MZ_FTELL64 ftello -+// #define MZ_FSEEK64 fseeko -+// #define MZ_FILE_STAT_STRUCT stat -+// #define MZ_FILE_STAT stat -+// #define MZ_FFLUSH fflush -+// #define MZ_FREOPEN(p, m, s) freopen(p, m, s) -+// #define MZ_DELETE_FILE remove -+ -+// #else -+// // #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") -+// #ifndef MINIZ_NO_TIME -+// #include -+// #endif -+// #define MZ_FOPEN(f, m) fopen(f, m) -+// #define MZ_FCLOSE fclose -+// #define MZ_FREAD fread -+// #define MZ_FWRITE fwrite -+// #ifdef __STRICT_ANSI__ -+// #define MZ_FTELL64 ftell -+// #define MZ_FSEEK64 fseek -+// #else -+// #define MZ_FTELL64 ftello -+// #define MZ_FSEEK64 fseeko -+// #endif -+// #define MZ_FILE_STAT_STRUCT stat -+// #define MZ_FILE_STAT stat -+// #define MZ_FFLUSH fflush -+// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) -+// #define MZ_DELETE_FILE remove -+// #endif /* #ifdef _MSC_VER */ -+// #endif /* #ifdef MINIZ_NO_STDIO */ -+ -+// #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) - --#else --// #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") --#ifndef MINIZ_NO_TIME --#include --#endif --#define MZ_FOPEN(f, m) fopen(f, m) --#define MZ_FCLOSE fclose --#define MZ_FREAD fread --#define MZ_FWRITE fwrite --#ifdef __STRICT_ANSI__ --#define MZ_FTELL64 ftell --#define MZ_FSEEK64 fseek --#else --#define MZ_FTELL64 ftello --#define MZ_FSEEK64 fseeko --#endif --#define MZ_FILE_STAT_STRUCT stat --#define MZ_FILE_STAT stat --#define MZ_FFLUSH fflush --#define MZ_FREOPEN(f, m, s) freopen(f, m, s) --#define MZ_DELETE_FILE remove --#endif /* #ifdef _MSC_VER */ --#endif /* #ifdef MINIZ_NO_STDIO */ -+/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ -+// enum -+// { -+// /* ZIP archive identifiers and record sizes */ -+// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, -+// MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, -+// MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, -+// MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, -+// MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, -+// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, -+ -+// /* ZIP64 archive identifier and record sizes */ -+// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, -+// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, -+// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, -+// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, -+// MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, -+// MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, -+// MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, -+// MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, -+ -+// /* Central directory header record offsets */ -+// MZ_ZIP_CDH_SIG_OFS = 0, -+// MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, -+// MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, -+// MZ_ZIP_CDH_BIT_FLAG_OFS = 8, -+// MZ_ZIP_CDH_METHOD_OFS = 10, -+// MZ_ZIP_CDH_FILE_TIME_OFS = 12, -+// MZ_ZIP_CDH_FILE_DATE_OFS = 14, -+// MZ_ZIP_CDH_CRC32_OFS = 16, -+// MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, -+// MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, -+// MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, -+// MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, -+// MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, -+// MZ_ZIP_CDH_DISK_START_OFS = 34, -+// MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, -+// MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, -+// MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, -+ -+// /* Local directory header offsets */ -+// MZ_ZIP_LDH_SIG_OFS = 0, -+// MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, -+// MZ_ZIP_LDH_BIT_FLAG_OFS = 6, -+// MZ_ZIP_LDH_METHOD_OFS = 8, -+// MZ_ZIP_LDH_FILE_TIME_OFS = 10, -+// MZ_ZIP_LDH_FILE_DATE_OFS = 12, -+// MZ_ZIP_LDH_CRC32_OFS = 14, -+// MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, -+// MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, -+// MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, -+// MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, -+// MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, -+ -+// /* End of central directory offsets */ -+// MZ_ZIP_ECDH_SIG_OFS = 0, -+// MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, -+// MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, -+// MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, -+// MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, -+// MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, -+// MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, -+// MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, -+ -+// /* ZIP64 End of central directory locator offsets */ -+// MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ -+// MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ -+// MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ -+// MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ -+ -+// /* ZIP64 End of central directory header offsets */ -+// MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ -+// MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ -+// MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ -+// MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ -+// MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ -+// MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ -+// MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ -+// MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ -+// MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ -+// MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ -+// MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, -+// MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, -+// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, -+// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, -+// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, -+// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, -+// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 -+// }; -+ -+// typedef struct -+// { -+// void *m_p; -+// size_t m_size, m_capacity; -+// mz_uint m_element_size; -+// } mz_zip_array; - --#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) -+// struct mz_zip_internal_state_tag -+// { -+// mz_zip_array m_central_dir; -+// mz_zip_array m_central_dir_offsets; -+// mz_zip_array m_sorted_central_dir_offsets; - --/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ --enum --{ -- /* ZIP archive identifiers and record sizes */ -- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, -- MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, -- MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, -- MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, -- MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, -- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, -- -- /* ZIP64 archive identifier and record sizes */ -- MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, -- MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, -- MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, -- MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, -- MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, -- MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, -- MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, -- MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, -- -- /* Central directory header record offsets */ -- MZ_ZIP_CDH_SIG_OFS = 0, -- MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, -- MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, -- MZ_ZIP_CDH_BIT_FLAG_OFS = 8, -- MZ_ZIP_CDH_METHOD_OFS = 10, -- MZ_ZIP_CDH_FILE_TIME_OFS = 12, -- MZ_ZIP_CDH_FILE_DATE_OFS = 14, -- MZ_ZIP_CDH_CRC32_OFS = 16, -- MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, -- MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, -- MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, -- MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, -- MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, -- MZ_ZIP_CDH_DISK_START_OFS = 34, -- MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, -- MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, -- MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, -- -- /* Local directory header offsets */ -- MZ_ZIP_LDH_SIG_OFS = 0, -- MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, -- MZ_ZIP_LDH_BIT_FLAG_OFS = 6, -- MZ_ZIP_LDH_METHOD_OFS = 8, -- MZ_ZIP_LDH_FILE_TIME_OFS = 10, -- MZ_ZIP_LDH_FILE_DATE_OFS = 12, -- MZ_ZIP_LDH_CRC32_OFS = 14, -- MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, -- MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, -- MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, -- MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, -- MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, -- -- /* End of central directory offsets */ -- MZ_ZIP_ECDH_SIG_OFS = 0, -- MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, -- MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, -- MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, -- MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, -- MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, -- MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, -- MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, -- -- /* ZIP64 End of central directory locator offsets */ -- MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ -- MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ -- MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ -- MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ -- -- /* ZIP64 End of central directory header offsets */ -- MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ -- MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ -- MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ -- MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ -- MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ -- MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ -- MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ -- MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ -- MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ -- MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ -- MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, -- MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, -- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, -- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, -- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, -- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, -- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 --}; -+// /* The flags passed in when the archive is initially opened. */ -+// uint32_t m_init_flags; - --typedef struct --{ -- void *m_p; -- size_t m_size, m_capacity; -- mz_uint m_element_size; --} mz_zip_array; -+// /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ -+// mz_bool m_zip64; - --struct mz_zip_internal_state_tag --{ -- mz_zip_array m_central_dir; -- mz_zip_array m_central_dir_offsets; -- mz_zip_array m_sorted_central_dir_offsets; -+// /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ -+// mz_bool m_zip64_has_extended_info_fields; - -- /* The flags passed in when the archive is initially opened. */ -- uint32_t m_init_flags; -+// /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ -+// MZ_FILE *m_pFile; -+// mz_uint64 m_file_archive_start_ofs; - -- /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ -- mz_bool m_zip64; -+// void *m_pMem; -+// size_t m_mem_size; -+// size_t m_mem_capacity; -+// }; - -- /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ -- mz_bool m_zip64_has_extended_info_fields; -+// #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size - -- /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ -- MZ_FILE *m_pFile; -- mz_uint64 m_file_archive_start_ofs; -+// #if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) -+// static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) -+// { -+// MZ_ASSERT(index < pArray->m_size); -+// return index; -+// } -+// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] -+// #else -+// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] -+// #endif - -- void *m_pMem; -- size_t m_mem_size; -- size_t m_mem_capacity; --}; -+// static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) -+// { -+// memset(pArray, 0, sizeof(mz_zip_array)); -+// pArray->m_element_size = element_size; -+// } - --#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size -+// static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); -+// memset(pArray, 0, sizeof(mz_zip_array)); -+// } - --#if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) --static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) --{ -- MZ_ASSERT(index < pArray->m_size); -- return index; --} --#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] --#else --#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] --#endif -+// static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) -+// { -+// void *pNew_p; -+// size_t new_capacity = min_new_capacity; -+// MZ_ASSERT(pArray->m_element_size); -+// if (pArray->m_capacity >= min_new_capacity) -+// return MZ_TRUE; -+// if (growing) -+// { -+// new_capacity = MZ_MAX(1, pArray->m_capacity); -+// while (new_capacity < min_new_capacity) -+// new_capacity *= 2; -+// } -+// if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) -+// return MZ_FALSE; -+// pArray->m_p = pNew_p; -+// pArray->m_capacity = new_capacity; -+// return MZ_TRUE; -+// } - --static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) --{ -- memset(pArray, 0, sizeof(mz_zip_array)); -- pArray->m_element_size = element_size; --} -+// static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) -+// { -+// if (new_capacity > pArray->m_capacity) -+// { -+// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) -+// return MZ_FALSE; -+// } -+// return MZ_TRUE; -+// } - --static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) --{ -- pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); -- memset(pArray, 0, sizeof(mz_zip_array)); --} -+// static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) -+// { -+// if (new_size > pArray->m_capacity) -+// { -+// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) -+// return MZ_FALSE; -+// } -+// pArray->m_size = new_size; -+// return MZ_TRUE; -+// } - --static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) --{ -- void *pNew_p; -- size_t new_capacity = min_new_capacity; -- MZ_ASSERT(pArray->m_element_size); -- if (pArray->m_capacity >= min_new_capacity) -- return MZ_TRUE; -- if (growing) -- { -- new_capacity = MZ_MAX(1, pArray->m_capacity); -- while (new_capacity < min_new_capacity) -- new_capacity *= 2; -- } -- if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) -- return MZ_FALSE; -- pArray->m_p = pNew_p; -- pArray->m_capacity = new_capacity; -- return MZ_TRUE; --} -+// static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) -+// { -+// return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); -+// } - --static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) --{ -- if (new_capacity > pArray->m_capacity) -- { -- if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) -- return MZ_FALSE; -- } -- return MZ_TRUE; --} -+// static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) -+// { -+// size_t orig_size = pArray->m_size; -+// if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) -+// return MZ_FALSE; -+// memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); -+// return MZ_TRUE; -+// } - --static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) --{ -- if (new_size > pArray->m_capacity) -- { -- if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) -- return MZ_FALSE; -- } -- pArray->m_size = new_size; -- return MZ_TRUE; --} -+// #ifndef MINIZ_NO_TIME -+// static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) -+// { -+// struct tm tm; -+// memset(&tm, 0, sizeof(tm)); -+// tm.tm_isdst = -1; -+// tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; -+// tm.tm_mon = ((dos_date >> 5) & 15) - 1; -+// tm.tm_mday = dos_date & 31; -+// tm.tm_hour = (dos_time >> 11) & 31; -+// tm.tm_min = (dos_time >> 5) & 63; -+// tm.tm_sec = (dos_time << 1) & 62; -+// return mktime(&tm); -+// } - --static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) --{ -- return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); --} -+// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -+// static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) -+// { -+// #ifdef _MSC_VER -+// struct tm tm_struct; -+// struct tm *tm = &tm_struct; -+// errno_t err = localtime_s(tm, &time_); -+// if (err) -+// { -+// *pDOS_date = 0; -+// *pDOS_time = 0; -+// return; -+// } -+// #else -+// struct tm *tm = localtime(&time_); -+// #endif /* #ifdef _MSC_VER */ - --static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) --{ -- size_t orig_size = pArray->m_size; -- if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) -- return MZ_FALSE; -- memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); -- return MZ_TRUE; --} -+// *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); -+// *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); -+// } -+// #endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ - --#ifndef MINIZ_NO_TIME --static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) --{ -- struct tm tm; -- memset(&tm, 0, sizeof(tm)); -- tm.tm_isdst = -1; -- tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; -- tm.tm_mon = ((dos_date >> 5) & 15) - 1; -- tm.tm_mday = dos_date & 31; -- tm.tm_hour = (dos_time >> 11) & 31; -- tm.tm_min = (dos_time >> 5) & 63; -- tm.tm_sec = (dos_time << 1) & 62; -- return mktime(&tm); --} -+// #ifndef MINIZ_NO_STDIO -+// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -+// static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) -+// { -+// struct MZ_FILE_STAT_STRUCT file_stat; - --#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS --static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) --{ --#ifdef _MSC_VER -- struct tm tm_struct; -- struct tm *tm = &tm_struct; -- errno_t err = localtime_s(tm, &time_); -- if (err) -- { -- *pDOS_date = 0; -- *pDOS_time = 0; -- return; -- } --#else -- struct tm *tm = localtime(&time_); --#endif /* #ifdef _MSC_VER */ -+// /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ -+// if (MZ_FILE_STAT(pFilename, &file_stat) != 0) -+// return MZ_FALSE; - -- *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); -- *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); --} --#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ -+// *pTime = file_stat.st_mtime; - --#ifndef MINIZ_NO_STDIO --#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS --static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) --{ -- struct MZ_FILE_STAT_STRUCT file_stat; -+// return MZ_TRUE; -+// } -+// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ - -- /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ -- if (MZ_FILE_STAT(pFilename, &file_stat) != 0) -- return MZ_FALSE; -+// static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) -+// { -+// struct utimbuf t; - -- *pTime = file_stat.st_mtime; -+// memset(&t, 0, sizeof(t)); -+// t.actime = access_time; -+// t.modtime = modified_time; - -- return MZ_TRUE; --} --#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ -+// return !utime(pFilename, &t); -+// } -+// #endif /* #ifndef MINIZ_NO_STDIO */ -+// #endif /* #ifndef MINIZ_NO_TIME */ - --static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) --{ -- struct utimbuf t; -+// static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) -+// { -+// if (pZip) -+// pZip->m_last_error = err_num; -+// return MZ_FALSE; -+// } - -- memset(&t, 0, sizeof(t)); -- t.actime = access_time; -- t.modtime = modified_time; -+// static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) -+// { -+// (void)flags; -+// if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- return !utime(pFilename, &t); --} --#endif /* #ifndef MINIZ_NO_STDIO */ --#endif /* #ifndef MINIZ_NO_TIME */ -+// if (!pZip->m_pAlloc) -+// pZip->m_pAlloc = miniz_def_alloc_func; -+// if (!pZip->m_pFree) -+// pZip->m_pFree = miniz_def_free_func; -+// if (!pZip->m_pRealloc) -+// pZip->m_pRealloc = miniz_def_realloc_func; - --static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) --{ -- if (pZip) -- pZip->m_last_error = err_num; -- return MZ_FALSE; --} -+// pZip->m_archive_size = 0; -+// pZip->m_central_directory_file_ofs = 0; -+// pZip->m_total_files = 0; -+// pZip->m_last_error = MZ_ZIP_NO_ERROR; - --static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) --{ -- (void)flags; -- if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- -- if (!pZip->m_pAlloc) -- pZip->m_pAlloc = miniz_def_alloc_func; -- if (!pZip->m_pFree) -- pZip->m_pFree = miniz_def_free_func; -- if (!pZip->m_pRealloc) -- pZip->m_pRealloc = miniz_def_realloc_func; -- -- pZip->m_archive_size = 0; -- pZip->m_central_directory_file_ofs = 0; -- pZip->m_total_files = 0; -- pZip->m_last_error = MZ_ZIP_NO_ERROR; -- -- if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- -- memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); -- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); -- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); -- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); -- pZip->m_pState->m_init_flags = flags; -- pZip->m_pState->m_zip64 = MZ_FALSE; -- pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; -- -- pZip->m_zip_mode = MZ_ZIP_MODE_READING; -+// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -- return MZ_TRUE; --} -+// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); -+// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); -+// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); -+// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); -+// pZip->m_pState->m_init_flags = flags; -+// pZip->m_pState->m_zip64 = MZ_FALSE; -+// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; - --static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) --{ -- const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; -- const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); -- mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); -- mz_uint8 l = 0, r = 0; -- pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -- pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -- pE = pL + MZ_MIN(l_len, r_len); -- while (pL < pE) -- { -- if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) -- break; -- pL++; -- pR++; -- } -- return (pL == pE) ? (l_len < r_len) : (l < r); --} -+// pZip->m_zip_mode = MZ_ZIP_MODE_READING; -+ -+// return MZ_TRUE; -+// } - -+// static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) -+// { -+// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; -+// const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); -+// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// mz_uint8 l = 0, r = 0; -+// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -+// pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -+// pE = pL + MZ_MIN(l_len, r_len); -+// while (pL < pE) -+// { -+// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) -+// break; -+// pL++; -+// pR++; -+// } -+// return (pL == pE) ? (l_len < r_len) : (l < r); -+// } -+/* - #define MZ_SWAP_UINT32(a, b) \ - do \ - { \ -@@ -3388,1708 +3387,1708 @@ static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pC - b = t; \ - } \ - MZ_MACRO_END -- -+*/ - /* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */ --static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) --{ -- mz_zip_internal_state *pState = pZip->m_pState; -- const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; -- const mz_zip_array *pCentral_dir = &pState->m_central_dir; -- mz_uint32 *pIndices; -- mz_uint32 start, end; -- const mz_uint32 size = pZip->m_total_files; -- -- if (size <= 1U) -- return; -+// static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) -+// { -+// mz_zip_internal_state *pState = pZip->m_pState; -+// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; -+// const mz_zip_array *pCentral_dir = &pState->m_central_dir; -+// mz_uint32 *pIndices; -+// mz_uint32 start, end; -+// const mz_uint32 size = pZip->m_total_files; - -- pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); -+// if (size <= 1U) -+// return; - -- start = (size - 2U) >> 1U; -- for (;;) -- { -- mz_uint64 child, root = start; -- for (;;) -- { -- if ((child = (root << 1U) + 1U) >= size) -- break; -- child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); -- if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) -- break; -- MZ_SWAP_UINT32(pIndices[root], pIndices[child]); -- root = child; -- } -- if (!start) -- break; -- start--; -- } -+// pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); - -- end = size - 1; -- while (end > 0) -- { -- mz_uint64 child, root = 0; -- MZ_SWAP_UINT32(pIndices[end], pIndices[0]); -- for (;;) -- { -- if ((child = (root << 1U) + 1U) >= end) -- break; -- child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); -- if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) -- break; -- MZ_SWAP_UINT32(pIndices[root], pIndices[child]); -- root = child; -- } -- end--; -- } --} -+// start = (size - 2U) >> 1U; -+// for (;;) -+// { -+// mz_uint64 child, root = start; -+// for (;;) -+// { -+// if ((child = (root << 1U) + 1U) >= size) -+// break; -+// child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); -+// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) -+// break; -+// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); -+// root = child; -+// } -+// if (!start) -+// break; -+// start--; -+// } - --static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) --{ -- mz_int64 cur_file_ofs; -- mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; -- mz_uint8 *pBuf = (mz_uint8 *)buf_u32; -+// end = size - 1; -+// while (end > 0) -+// { -+// mz_uint64 child, root = 0; -+// MZ_SWAP_UINT32(pIndices[end], pIndices[0]); -+// for (;;) -+// { -+// if ((child = (root << 1U) + 1U) >= end) -+// break; -+// child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); -+// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) -+// break; -+// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); -+// root = child; -+// } -+// end--; -+// } -+// } - -- /* Basic sanity checks - reject files which are too small */ -- if (pZip->m_archive_size < record_size) -- return MZ_FALSE; -+// static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) -+// { -+// mz_int64 cur_file_ofs; -+// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; -+// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; - -- /* Find the record by scanning the file from the end towards the beginning. */ -- cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); -- for (;;) -- { -- int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); -+// /* Basic sanity checks - reject files which are too small */ -+// if (pZip->m_archive_size < record_size) -+// return MZ_FALSE; - -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) -- return MZ_FALSE; -+// /* Find the record by scanning the file from the end towards the beginning. */ -+// cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); -+// for (;;) -+// { -+// int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); - -- for (i = n - 4; i >= 0; --i) -- { -- mz_uint s = MZ_READ_LE32(pBuf + i); -- if (s == record_sig) -- { -- if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) -- break; -- } -- } -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) -+// return MZ_FALSE; - -- if (i >= 0) -- { -- cur_file_ofs += i; -- break; -- } -+// for (i = n - 4; i >= 0; --i) -+// { -+// mz_uint s = MZ_READ_LE32(pBuf + i); -+// if (s == record_sig) -+// { -+// if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) -+// break; -+// } -+// } - -- /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ -- if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) -- return MZ_FALSE; -+// if (i >= 0) -+// { -+// cur_file_ofs += i; -+// break; -+// } - -- cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); -- } -+// /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ -+// if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) -+// return MZ_FALSE; - -- *pOfs = cur_file_ofs; -- return MZ_TRUE; --} -+// cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); -+// } - --static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) --{ -- mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; -- mz_uint64 cdir_ofs = 0; -- mz_int64 cur_file_ofs = 0; -- const mz_uint8 *p; -+// *pOfs = cur_file_ofs; -+// return MZ_TRUE; -+// } - -- mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; -- mz_uint8 *pBuf = (mz_uint8 *)buf_u32; -- mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); -- mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -- mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; -+// static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) -+// { -+// mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; -+// mz_uint64 cdir_ofs = 0; -+// mz_int64 cur_file_ofs = 0; -+// const mz_uint8 *p; - -- mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -- mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; -+// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; -+// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; -+// mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); -+// mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -+// mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; - -- mz_uint64 zip64_end_of_central_dir_ofs = 0; -+// mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -+// mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; - -- /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ -- if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -+// mz_uint64 zip64_end_of_central_dir_ofs = 0; - -- if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) -- return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); -+// /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ -+// if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -- /* Read and verify the end of central directory record. */ -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); - -- if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) -- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -+// /* Read and verify the end of central directory record. */ -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -- if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) -- { -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) -- { -- if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) -- { -- zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); -- if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) -- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -+// if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) -+// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -- if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) -- { -- if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) -- { -- pZip->m_pState->m_zip64 = MZ_TRUE; -- } -- } -- } -- } -- } -+// if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) -+// { -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) -+// { -+// if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) -+// { -+// zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); -+// if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) -+// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -- pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); -- cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); -- num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); -- cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); -- cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); -- cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); -+// if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// { -+// if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) -+// { -+// pZip->m_pState->m_zip64 = MZ_TRUE; -+// } -+// } -+// } -+// } -+// } - -- if (pZip->m_pState->m_zip64) -- { -- mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); -- mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); -- mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); -- mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); -- mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); -+// pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); -+// cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); -+// num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); -+// cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); -+// cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); -+// cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); - -- if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// if (pZip->m_pState->m_zip64) -+// { -+// mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); -+// mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); -+// mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); -+// mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); -+// mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); - -- if (zip64_total_num_of_disks != 1U) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); -+// if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- /* Check for miniz's practical limits */ -- if (zip64_cdir_total_entries > MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// if (zip64_total_num_of_disks != 1U) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -- pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; -+// /* Check for miniz's practical limits */ -+// if (zip64_cdir_total_entries > MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - -- if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; - -- cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; -+// if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - -- /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ -- if (zip64_size_of_central_directory > MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); -+// cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; - -- cdir_size = (mz_uint32)zip64_size_of_central_directory; -+// /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ -+// if (zip64_size_of_central_directory > MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -- num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); -+// cdir_size = (mz_uint32)zip64_size_of_central_directory; - -- cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); -+// num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); - -- cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); -- } -+// cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); - -- if (pZip->m_total_files != cdir_entries_on_this_disk) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); -+// cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); -+// } - -- if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); -+// if (pZip->m_total_files != cdir_entries_on_this_disk) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -- if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -- if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- pZip->m_central_directory_file_ofs = cdir_ofs; -+// if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (pZip->m_total_files) -- { -- mz_uint i, n; -- /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ -- if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || -- (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// pZip->m_central_directory_file_ofs = cdir_ofs; - -- if (sort_central_dir) -- { -- if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- } -+// if (pZip->m_total_files) -+// { -+// mz_uint i, n; -+// /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ -+// if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || -+// (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -- if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// if (sort_central_dir) -+// { -+// if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// } - -- /* Now create an index into the central directory file records, do some basic sanity checking on each record */ -- p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; -- for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) -- { -- mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; -- mz_uint64 comp_size, decomp_size, local_header_ofs; -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -- if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// /* Now create an index into the central directory file records, do some basic sanity checking on each record */ -+// p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; -+// for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) -+// { -+// mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; -+// mz_uint64 comp_size, decomp_size, local_header_ofs; - -- MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); -+// if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (sort_central_dir) -- MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; -+// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); - -- comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -- decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); -- local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); -- filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -- ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); -+// if (sort_central_dir) -+// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; - -- if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && -- (ext_data_size) && -- (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) -- { -- /* Attempt to find zip64 extended information field in the entry's extra data */ -- mz_uint32 extra_size_remaining = ext_data_size; -+// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -+// decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); -+// local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); -+// filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); - -- if (extra_size_remaining) -- { -- const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; -+// if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && -+// (ext_data_size) && -+// (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) -+// { -+// /* Attempt to find zip64 extended information field in the entry's extra data */ -+// mz_uint32 extra_size_remaining = ext_data_size; - -- do -- { -- mz_uint32 field_id; -- mz_uint32 field_data_size; -+// if (extra_size_remaining) -+// { -+// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; - -- if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// do -+// { -+// mz_uint32 field_id; -+// mz_uint32 field_data_size; - -- field_id = MZ_READ_LE16(pExtra_data); -- field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); -+// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// field_id = MZ_READ_LE16(pExtra_data); -+// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); - -- if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -- { -- /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ -- pZip->m_pState->m_zip64 = MZ_TRUE; -- pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; -- break; -- } -+// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; -- extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; -- } while (extra_size_remaining); -- } -- } -+// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -+// { -+// /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ -+// pZip->m_pState->m_zip64 = MZ_TRUE; -+// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; -+// break; -+// } - -- /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ -- if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) -- { -- if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- } -+// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; -+// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; -+// } while (extra_size_remaining); -+// } -+// } - -- disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); -- if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); -+// /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ -+// if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) -+// { -+// if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// } - -- if (comp_size != MZ_UINT32_MAX) -- { -- if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- } -+// disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); -+// if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -- bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -- if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -+// if (comp_size != MZ_UINT32_MAX) -+// { -+// if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// } - -- if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -+// if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - -- n -= total_header_size; -- p += total_header_size; -- } -- } -+// if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (sort_central_dir) -- mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); -+// n -= total_header_size; -+// p += total_header_size; -+// } -+// } - -- return MZ_TRUE; --} -+// if (sort_central_dir) -+// mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); - --void mz_zip_zero_struct(mz_zip_archive *pZip) --{ -- if (pZip) -- MZ_CLEAR_OBJ(*pZip); --} -+// return MZ_TRUE; -+// } - --static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) --{ -- mz_bool status = MZ_TRUE; -+// void mz_zip_zero_struct(mz_zip_archive *pZip) -+// { -+// if (pZip) -+// MZ_CLEAR_OBJ(*pZip); -+// } - -- if (!pZip) -- return MZ_FALSE; -+// static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) -+// { -+// mz_bool status = MZ_TRUE; - -- if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) -- { -- if (set_last_error) -- pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; -+// if (!pZip) -+// return MZ_FALSE; - -- return MZ_FALSE; -- } -+// if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) -+// { -+// if (set_last_error) -+// pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; - -- if (pZip->m_pState) -- { -- mz_zip_internal_state *pState = pZip->m_pState; -- pZip->m_pState = NULL; -+// return MZ_FALSE; -+// } - -- mz_zip_array_clear(pZip, &pState->m_central_dir); -- mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); -- mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); -+// if (pZip->m_pState) -+// { -+// mz_zip_internal_state *pState = pZip->m_pState; -+// pZip->m_pState = NULL; - --#ifndef MINIZ_NO_STDIO -- if (pState->m_pFile) -- { -- if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -- { -- if (MZ_FCLOSE(pState->m_pFile) == EOF) -- { -- if (set_last_error) -- pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; -- status = MZ_FALSE; -- } -- } -- pState->m_pFile = NULL; -- } --#endif /* #ifndef MINIZ_NO_STDIO */ -+// mz_zip_array_clear(pZip, &pState->m_central_dir); -+// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); -+// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); - -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- } -- pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; -+// #ifndef MINIZ_NO_STDIO -+// if (pState->m_pFile) -+// { -+// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -+// { -+// if (MZ_FCLOSE(pState->m_pFile) == EOF) -+// { -+// if (set_last_error) -+// pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; -+// status = MZ_FALSE; -+// } -+// } -+// pState->m_pFile = NULL; -+// } -+// #endif /* #ifndef MINIZ_NO_STDIO */ - -- return status; --} -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// } -+// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; - --mz_bool mz_zip_reader_end(mz_zip_archive *pZip) --{ -- return mz_zip_reader_end_internal(pZip, MZ_TRUE); --} --mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) --{ -- if ((!pZip) || (!pZip->m_pRead)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return status; -+// } - -- if (!mz_zip_reader_init_internal(pZip, flags)) -- return MZ_FALSE; -+// mz_bool mz_zip_reader_end(mz_zip_archive *pZip) -+// { -+// return mz_zip_reader_end_internal(pZip, MZ_TRUE); -+// } -+// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) -+// { -+// if ((!pZip) || (!pZip->m_pRead)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- pZip->m_zip_type = MZ_ZIP_TYPE_USER; -- pZip->m_archive_size = size; -+// if (!mz_zip_reader_init_internal(pZip, flags)) -+// return MZ_FALSE; - -- if (!mz_zip_reader_read_central_dir(pZip, flags)) -- { -- mz_zip_reader_end_internal(pZip, MZ_FALSE); -- return MZ_FALSE; -- } -+// pZip->m_zip_type = MZ_ZIP_TYPE_USER; -+// pZip->m_archive_size = size; - -- return MZ_TRUE; --} -+// if (!mz_zip_reader_read_central_dir(pZip, flags)) -+// { -+// mz_zip_reader_end_internal(pZip, MZ_FALSE); -+// return MZ_FALSE; -+// } - --static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) --{ -- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -- size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); -- memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); -- return s; --} -+// return MZ_TRUE; -+// } - --mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) --{ -- if (!pMem) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -+// { -+// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -+// size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); -+// memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); -+// return s; -+// } - -- if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -+// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) -+// { -+// if (!pMem) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if (!mz_zip_reader_init_internal(pZip, flags)) -- return MZ_FALSE; -+// if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -- pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; -- pZip->m_archive_size = size; -- pZip->m_pRead = mz_zip_mem_read_func; -- pZip->m_pIO_opaque = pZip; -- pZip->m_pNeeds_keepalive = NULL; -+// if (!mz_zip_reader_init_internal(pZip, flags)) -+// return MZ_FALSE; - --#ifdef __cplusplus -- pZip->m_pState->m_pMem = const_cast(pMem); --#else -- pZip->m_pState->m_pMem = (void *)pMem; --#endif -+// pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; -+// pZip->m_archive_size = size; -+// pZip->m_pRead = mz_zip_mem_read_func; -+// pZip->m_pIO_opaque = pZip; -+// pZip->m_pNeeds_keepalive = NULL; - -- pZip->m_pState->m_mem_size = size; -+// #ifdef __cplusplus -+// pZip->m_pState->m_pMem = const_cast(pMem); -+// #else -+// pZip->m_pState->m_pMem = (void *)pMem; -+// #endif - -- if (!mz_zip_reader_read_central_dir(pZip, flags)) -- { -- mz_zip_reader_end_internal(pZip, MZ_FALSE); -- return MZ_FALSE; -- } -+// pZip->m_pState->m_mem_size = size; - -- return MZ_TRUE; --} -+// if (!mz_zip_reader_read_central_dir(pZip, flags)) -+// { -+// mz_zip_reader_end_internal(pZip, MZ_FALSE); -+// return MZ_FALSE; -+// } - --#ifndef MINIZ_NO_STDIO --static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) --{ -- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -- mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); -+// return MZ_TRUE; -+// } - -- file_ofs += pZip->m_pState->m_file_archive_start_ofs; -+// #ifndef MINIZ_NO_STDIO -+// static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -+// { -+// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -+// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - -- if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) -- return 0; -+// file_ofs += pZip->m_pState->m_file_archive_start_ofs; - -- return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); --} -+// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) -+// return 0; - --mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) --{ -- return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); --} -+// return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); -+// } - --mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) --{ -- mz_uint64 file_size; -- MZ_FILE *pFile; -+// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) -+// { -+// return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); -+// } - -- if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) -+// { -+// mz_uint64 file_size; -+// MZ_FILE *pFile; - -- pFile = MZ_FOPEN(pFilename, "rb"); -- if (!pFile) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -+// if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- file_size = archive_size; -- if (!file_size) -- { -- if (MZ_FSEEK64(pFile, 0, SEEK_END)) -- { -- MZ_FCLOSE(pFile); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); -- } -+// pFile = MZ_FOPEN(pFilename, "rb"); -+// if (!pFile) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -- file_size = MZ_FTELL64(pFile); -- } -+// file_size = archive_size; -+// if (!file_size) -+// { -+// if (MZ_FSEEK64(pFile, 0, SEEK_END)) -+// { -+// MZ_FCLOSE(pFile); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); -+// } - -- /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ -+// file_size = MZ_FTELL64(pFile); -+// } - -- if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -- { -- MZ_FCLOSE(pFile); -- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -- } -+// /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ - -- if (!mz_zip_reader_init_internal(pZip, flags)) -- { -- MZ_FCLOSE(pFile); -- return MZ_FALSE; -- } -+// if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// { -+// MZ_FCLOSE(pFile); -+// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -+// } - -- pZip->m_zip_type = MZ_ZIP_TYPE_FILE; -- pZip->m_pRead = mz_zip_file_read_func; -- pZip->m_pIO_opaque = pZip; -- pZip->m_pState->m_pFile = pFile; -- pZip->m_archive_size = file_size; -- pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; -+// if (!mz_zip_reader_init_internal(pZip, flags)) -+// { -+// MZ_FCLOSE(pFile); -+// return MZ_FALSE; -+// } - -- if (!mz_zip_reader_read_central_dir(pZip, flags)) -- { -- mz_zip_reader_end_internal(pZip, MZ_FALSE); -- return MZ_FALSE; -- } -+// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; -+// pZip->m_pRead = mz_zip_file_read_func; -+// pZip->m_pIO_opaque = pZip; -+// pZip->m_pState->m_pFile = pFile; -+// pZip->m_archive_size = file_size; -+// pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; - -- return MZ_TRUE; --} -+// if (!mz_zip_reader_read_central_dir(pZip, flags)) -+// { -+// mz_zip_reader_end_internal(pZip, MZ_FALSE); -+// return MZ_FALSE; -+// } - --mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) --{ -- mz_uint64 cur_file_ofs; -+// return MZ_TRUE; -+// } - -- if ((!pZip) || (!pFile)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -+// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) -+// { -+// mz_uint64 cur_file_ofs; - -- cur_file_ofs = MZ_FTELL64(pFile); -+// if ((!pZip) || (!pFile)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -- if (!archive_size) -- { -- if (MZ_FSEEK64(pFile, 0, SEEK_END)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); -+// cur_file_ofs = MZ_FTELL64(pFile); - -- archive_size = MZ_FTELL64(pFile) - cur_file_ofs; -+// if (!archive_size) -+// { -+// if (MZ_FSEEK64(pFile, 0, SEEK_END)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); - -- if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -- } -+// archive_size = MZ_FTELL64(pFile) - cur_file_ofs; - -- if (!mz_zip_reader_init_internal(pZip, flags)) -- return MZ_FALSE; -+// if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -+// } - -- pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; -- pZip->m_pRead = mz_zip_file_read_func; -+// if (!mz_zip_reader_init_internal(pZip, flags)) -+// return MZ_FALSE; - -- pZip->m_pIO_opaque = pZip; -- pZip->m_pState->m_pFile = pFile; -- pZip->m_archive_size = archive_size; -- pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; -+// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; -+// pZip->m_pRead = mz_zip_file_read_func; - -- if (!mz_zip_reader_read_central_dir(pZip, flags)) -- { -- mz_zip_reader_end_internal(pZip, MZ_FALSE); -- return MZ_FALSE; -- } -+// pZip->m_pIO_opaque = pZip; -+// pZip->m_pState->m_pFile = pFile; -+// pZip->m_archive_size = archive_size; -+// pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; - -- return MZ_TRUE; --} -+// if (!mz_zip_reader_read_central_dir(pZip, flags)) -+// { -+// mz_zip_reader_end_internal(pZip, MZ_FALSE); -+// return MZ_FALSE; -+// } - --#endif /* #ifndef MINIZ_NO_STDIO */ -+// return MZ_TRUE; -+// } - --static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) --{ -- if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) -- return NULL; -- return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); --} -+// #endif /* #ifndef MINIZ_NO_STDIO */ - --mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) --{ -- mz_uint m_bit_flag; -- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -- if (!p) -- { -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- return MZ_FALSE; -- } -+// static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) -+// { -+// if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) -+// return NULL; -+// return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); -+// } - -- m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -- return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; --} -+// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) -+// { -+// mz_uint m_bit_flag; -+// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -+// if (!p) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return MZ_FALSE; -+// } - --mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) --{ -- mz_uint bit_flag; -- mz_uint method; -+// m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -+// return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; -+// } - -- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -- if (!p) -- { -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- return MZ_FALSE; -- } -+// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) -+// { -+// mz_uint bit_flag; -+// mz_uint method; - -- method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); -- bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -+// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -+// if (!p) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return MZ_FALSE; -+// } - -- if ((method != 0) && (method != MZ_DEFLATED)) -- { -- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -- return MZ_FALSE; -- } -+// method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); -+// bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); - -- if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) -- { -- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -- return MZ_FALSE; -- } -+// if ((method != 0) && (method != MZ_DEFLATED)) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -+// return MZ_FALSE; -+// } - -- if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) -- { -- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); -- return MZ_FALSE; -- } -+// if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -+// return MZ_FALSE; -+// } - -- return MZ_TRUE; --} -+// if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); -+// return MZ_FALSE; -+// } - --mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) --{ -- mz_uint filename_len, attribute_mapping_id, external_attr; -- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -- if (!p) -- { -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- return MZ_FALSE; -- } -+// return MZ_TRUE; -+// } - -- filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -- if (filename_len) -- { -- if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') -- return MZ_TRUE; -- } -+// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) -+// { -+// mz_uint filename_len, attribute_mapping_id, external_attr; -+// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -+// if (!p) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return MZ_FALSE; -+// } -+ -+// filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// if (filename_len) -+// { -+// if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') -+// return MZ_TRUE; -+// } - - /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */ - /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */ - /* FIXME: Remove this check? Is it necessary - we already check the filename. */ -- attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; -- (void)attribute_mapping_id; -+// attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; -+// (void)attribute_mapping_id; - -- external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); -- if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) -- { -- return MZ_TRUE; -- } -+// external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); -+// if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) -+// { -+// return MZ_TRUE; -+// } - -- return MZ_FALSE; --} -+// return MZ_FALSE; -+// } - --static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) --{ -- mz_uint n; -- const mz_uint8 *p = pCentral_dir_header; -- -- if (pFound_zip64_extra_data) -- *pFound_zip64_extra_data = MZ_FALSE; -- -- if ((!p) || (!pStat)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- -- /* Extract fields from the central directory record. */ -- pStat->m_file_index = file_index; -- pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); -- pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); -- pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); -- pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -- pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); --#ifndef MINIZ_NO_TIME -- pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); --#endif -- pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); -- pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -- pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); -- pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); -- pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); -- pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); -- -- /* Copy as much of the filename and comment as possible. */ -- n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -- n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); -- memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); -- pStat->m_filename[n] = '\0'; -- -- n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); -- n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); -- pStat->m_comment_size = n; -- memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); -- pStat->m_comment[n] = '\0'; -- -- /* Set some flags for convienance */ -- pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); -- pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); -- pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); -- -- /* See if we need to read any zip64 extended information fields. */ -- /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ -- if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) -- { -- /* Attempt to find zip64 extended information field in the entry's extra data */ -- mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); -+// static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) -+// { -+// mz_uint n; -+// const mz_uint8 *p = pCentral_dir_header; - -- if (extra_size_remaining) -- { -- const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// if (pFound_zip64_extra_data) -+// *pFound_zip64_extra_data = MZ_FALSE; - -- do -- { -- mz_uint32 field_id; -- mz_uint32 field_data_size; -+// if ((!p) || (!pStat)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// /* Extract fields from the central directory record. */ -+// pStat->m_file_index = file_index; -+// pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); -+// pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); -+// pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); -+// pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -+// pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); -+// #ifndef MINIZ_NO_TIME -+// pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); -+// #endif -+// pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); -+// pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -+// pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); -+// pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); -+// pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); -+// pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); -+ -+// /* Copy as much of the filename and comment as possible. */ -+// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); -+// memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); -+// pStat->m_filename[n] = '\0'; -+ -+// n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); -+// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); -+// pStat->m_comment_size = n; -+// memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); -+// pStat->m_comment[n] = '\0'; -+ -+// /* Set some flags for convienance */ -+// pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); -+// pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); -+// pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); -+ -+// /* See if we need to read any zip64 extended information fields. */ -+// /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ -+// if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) -+// { -+// /* Attempt to find zip64 extended information field in the entry's extra data */ -+// mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); - -- field_id = MZ_READ_LE16(pExtra_data); -- field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); -+// if (extra_size_remaining) -+// { -+// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - -- if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// do -+// { -+// mz_uint32 field_id; -+// mz_uint32 field_data_size; - -- if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -- { -- const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; -- mz_uint32 field_data_remaining = field_data_size; -+// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (pFound_zip64_extra_data) -- *pFound_zip64_extra_data = MZ_TRUE; -+// field_id = MZ_READ_LE16(pExtra_data); -+// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); - -- if (pStat->m_uncomp_size == MZ_UINT32_MAX) -- { -- if (field_data_remaining < sizeof(mz_uint64)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- pStat->m_uncomp_size = MZ_READ_LE64(pField_data); -- pField_data += sizeof(mz_uint64); -- field_data_remaining -= sizeof(mz_uint64); -- } -+// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -+// { -+// const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; -+// mz_uint32 field_data_remaining = field_data_size; -+ -+// if (pFound_zip64_extra_data) -+// *pFound_zip64_extra_data = MZ_TRUE; -+ -+// if (pStat->m_uncomp_size == MZ_UINT32_MAX) -+// { -+// if (field_data_remaining < sizeof(mz_uint64)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+ -+// pStat->m_uncomp_size = MZ_READ_LE64(pField_data); -+// pField_data += sizeof(mz_uint64); -+// field_data_remaining -= sizeof(mz_uint64); -+// } -+ -+// if (pStat->m_comp_size == MZ_UINT32_MAX) -+// { -+// if (field_data_remaining < sizeof(mz_uint64)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+ -+// pStat->m_comp_size = MZ_READ_LE64(pField_data); -+// pField_data += sizeof(mz_uint64); -+// field_data_remaining -= sizeof(mz_uint64); -+// } -+ -+// if (pStat->m_local_header_ofs == MZ_UINT32_MAX) -+// { -+// if (field_data_remaining < sizeof(mz_uint64)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+ -+// pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); -+// pField_data += sizeof(mz_uint64); -+// // field_data_remaining -= sizeof(mz_uint64); -+// } -+ -+// break; -+// } - -- if (pStat->m_comp_size == MZ_UINT32_MAX) -- { -- if (field_data_remaining < sizeof(mz_uint64)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; -+// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; -+// } while (extra_size_remaining); -+// } -+// } - -- pStat->m_comp_size = MZ_READ_LE64(pField_data); -- pField_data += sizeof(mz_uint64); -- field_data_remaining -= sizeof(mz_uint64); -- } -+// return MZ_TRUE; -+// } - -- if (pStat->m_local_header_ofs == MZ_UINT32_MAX) -- { -- if (field_data_remaining < sizeof(mz_uint64)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) -+// { -+// mz_uint i; -+// if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) -+// return 0 == memcmp(pA, pB, len); -+// for (i = 0; i < len; ++i) -+// if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) -+// return MZ_FALSE; -+// return MZ_TRUE; -+// } - -- pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); -- pField_data += sizeof(mz_uint64); -- // field_data_remaining -= sizeof(mz_uint64); -- } -+// static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) -+// { -+// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; -+// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// mz_uint8 l = 0, r = 0; -+// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -+// pE = pL + MZ_MIN(l_len, r_len); -+// while (pL < pE) -+// { -+// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) -+// break; -+// pL++; -+// pR++; -+// } -+// return (pL == pE) ? (int)(l_len - r_len) : (l - r); -+// } - -- break; -- } -+// static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) -+// { -+// mz_zip_internal_state *pState = pZip->m_pState; -+// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; -+// const mz_zip_array *pCentral_dir = &pState->m_central_dir; -+// mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); -+// const uint32_t size = pZip->m_total_files; -+// const mz_uint filename_len = (mz_uint)strlen(pFilename); - -- pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; -- extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; -- } while (extra_size_remaining); -- } -- } -+// if (pIndex) -+// *pIndex = 0; - -- return MZ_TRUE; --} -+// if (size) -+// { -+// /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ -+// /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ -+// mz_int64 l = 0, h = (mz_int64)size - 1; - --static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) --{ -- mz_uint i; -- if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) -- return 0 == memcmp(pA, pB, len); -- for (i = 0; i < len; ++i) -- if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) -- return MZ_FALSE; -- return MZ_TRUE; --} -+// while (l <= h) -+// { -+// mz_int64 m = l + ((h - l) >> 1); -+// uint32_t file_index = pIndices[(uint32_t)m]; - --static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) --{ -- const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; -- mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); -- mz_uint8 l = 0, r = 0; -- pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -- pE = pL + MZ_MIN(l_len, r_len); -- while (pL < pE) -- { -- if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) -- break; -- pL++; -- pR++; -- } -- return (pL == pE) ? (int)(l_len - r_len) : (l - r); --} -+// int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); -+// if (!comp) -+// { -+// if (pIndex) -+// *pIndex = file_index; -+// return MZ_TRUE; -+// } -+// else if (comp < 0) -+// l = m + 1; -+// else -+// h = m - 1; -+// } -+// } - --static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) --{ -- mz_zip_internal_state *pState = pZip->m_pState; -- const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; -- const mz_zip_array *pCentral_dir = &pState->m_central_dir; -- mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); -- const uint32_t size = pZip->m_total_files; -- const mz_uint filename_len = (mz_uint)strlen(pFilename); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); -+// } - -- if (pIndex) -- *pIndex = 0; -+// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) -+// { -+// mz_uint32 index_; -+// if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) -+// return -1; -+// else -+// return (int)index_; -+// } - -- if (size) -- { -- /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ -- /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ -- mz_int64 l = 0, h = (mz_int64)size - 1; -+// mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) -+// { -+// mz_uint file_index; -+// size_t name_len, comment_len; - -- while (l <= h) -- { -- mz_int64 m = l + ((h - l) >> 1); -- uint32_t file_index = pIndices[(uint32_t)m]; -+// if (pIndex) -+// *pIndex = 0; - -- int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); -- if (!comp) -- { -- if (pIndex) -- *pIndex = file_index; -- return MZ_TRUE; -- } -- else if (comp < 0) -- l = m + 1; -- else -- h = m - 1; -- } -- } -+// if ((!pZip) || (!pZip->m_pState) || (!pName)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); --} -+// /* See if we can use a binary search */ -+// if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && -+// (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && -+// ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) -+// { -+// return mz_zip_locate_file_binary_search(pZip, pName, pIndex); -+// } - --int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) --{ -- mz_uint32 index_; -- if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) -- return -1; -- else -- return (int)index_; --} -+// /* Locate the entry by scanning the entire central directory */ -+// name_len = strlen(pName); -+// if (name_len > MZ_UINT16_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - --mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) --{ -- mz_uint file_index; -- size_t name_len, comment_len; -+// comment_len = pComment ? strlen(pComment) : 0; -+// if (comment_len > MZ_UINT16_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if (pIndex) -- *pIndex = 0; -+// for (file_index = 0; file_index < pZip->m_total_files; file_index++) -+// { -+// const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); -+// mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -+// if (filename_len < name_len) -+// continue; -+// if (comment_len) -+// { -+// mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); -+// const char *pFile_comment = pFilename + filename_len + file_extra_len; -+// if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) -+// continue; -+// } -+// if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) -+// { -+// int ofs = filename_len - 1; -+// do -+// { -+// if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) -+// break; -+// } while (--ofs >= 0); -+// ofs++; -+// pFilename += ofs; -+// filename_len -= ofs; -+// } -+// if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) -+// { -+// if (pIndex) -+// *pIndex = file_index; -+// return MZ_TRUE; -+// } -+// } - -- if ((!pZip) || (!pZip->m_pState) || (!pName)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); -+// } - -- /* See if we can use a binary search */ -- if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && -- (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && -- ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) -- { -- return mz_zip_locate_file_binary_search(pZip, pName, pIndex); -- } -+// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -+// { -+// int status = TINFL_STATUS_DONE; -+// mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; -+// mz_zip_archive_file_stat file_stat; -+// void *pRead_buf; -+// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -+// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -+// tinfl_decompressor inflator; - -- /* Locate the entry by scanning the entire central directory */ -- name_len = strlen(pName); -- if (name_len > MZ_UINT16_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- comment_len = pComment ? strlen(pComment) : 0; -- if (comment_len > MZ_UINT16_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -+// return MZ_FALSE; - -- for (file_index = 0; file_index < pZip->m_total_files; file_index++) -- { -- const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); -- mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); -- const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -- if (filename_len < name_len) -- continue; -- if (comment_len) -- { -- mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); -- const char *pFile_comment = pFilename + filename_len + file_extra_len; -- if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) -- continue; -- } -- if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) -- { -- int ofs = filename_len - 1; -- do -- { -- if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) -- break; -- } while (--ofs >= 0); -- ofs++; -- pFilename += ofs; -- filename_len -= ofs; -- } -- if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) -- { -- if (pIndex) -- *pIndex = file_index; -- return MZ_TRUE; -- } -- } -+// /* A directory or zero length file */ -+// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) -+// return MZ_TRUE; - -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); --} -+// /* Encryption and patch files are not supported. */ -+// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - --mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) --{ -- int status = TINFL_STATUS_DONE; -- mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; -- mz_zip_archive_file_stat file_stat; -- void *pRead_buf; -- mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -- mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -- tinfl_decompressor inflator; -- -- if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- -- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -- return MZ_FALSE; -- -- /* A directory or zero length file */ -- if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) -- return MZ_TRUE; -- -- /* Encryption and patch files are not supported. */ -- if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -- -- /* This function only supports decompressing stored and deflate. */ -- if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -- -- /* Ensure supplied output buffer is large enough. */ -- needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; -- if (buf_size < needed_size) -- return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); -- -- /* Read and parse the local directory entry. */ -- cur_file_ofs = file_stat.m_local_header_ofs; -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -- -- if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- -- cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -- if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- -- if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) -- { -- /* The file is stored or the caller has requested the compressed data. */ -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// /* This function only supports decompressing stored and deflate. */ -+// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); - --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) -- { -- if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) -- return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); -- } --#endif -+// /* Ensure supplied output buffer is large enough. */ -+// needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; -+// if (buf_size < needed_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); - -- return MZ_TRUE; -- } -+// /* Read and parse the local directory entry. */ -+// cur_file_ofs = file_stat.m_local_header_ofs; -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -- /* Decompress the file either directly from memory or from a file input buffer. */ -- tinfl_init(&inflator); -+// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (pZip->m_pState->m_pMem) -- { -- /* Read directly from the archive in memory. */ -- pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; -- read_buf_size = read_buf_avail = file_stat.m_comp_size; -- comp_remaining = 0; -- } -- else if (pUser_read_buf) -- { -- /* Use a user provided read buffer. */ -- if (!user_read_buf_size) -- return MZ_FALSE; -- pRead_buf = (mz_uint8 *)pUser_read_buf; -- read_buf_size = user_read_buf_size; -- read_buf_avail = 0; -- comp_remaining = file_stat.m_comp_size; -- } -- else -- { -- /* Temporarily allocate a read buffer. */ -- read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -- if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -+// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) -+// { -+// /* The file is stored or the caller has requested the compressed data. */ -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -- read_buf_avail = 0; -- comp_remaining = file_stat.m_comp_size; -- } -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) -+// { -+// if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) -+// return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); -+// } -+// #endif - -- do -- { -- /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ -- size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); -- if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) -- { -- read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -- { -- status = TINFL_STATUS_FAILED; -- mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -- break; -- } -- cur_file_ofs += read_buf_avail; -- comp_remaining -= read_buf_avail; -- read_buf_ofs = 0; -- } -- in_buf_size = (size_t)read_buf_avail; -- status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); -- read_buf_avail -= in_buf_size; -- read_buf_ofs += in_buf_size; -- out_buf_ofs += out_buf_size; -- } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); -- -- if (status == TINFL_STATUS_DONE) -- { -- /* Make sure the entire file was decompressed, and check its CRC. */ -- if (out_buf_ofs != file_stat.m_uncomp_size) -- { -- mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -- status = TINFL_STATUS_FAILED; -- } --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) -- { -- mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); -- status = TINFL_STATUS_FAILED; -- } --#endif -- } -+// return MZ_TRUE; -+// } - -- if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) -- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -+// /* Decompress the file either directly from memory or from a file input buffer. */ -+// tinfl_init(&inflator); - -- return status == TINFL_STATUS_DONE; --} -+// if (pZip->m_pState->m_pMem) -+// { -+// /* Read directly from the archive in memory. */ -+// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; -+// read_buf_size = read_buf_avail = file_stat.m_comp_size; -+// comp_remaining = 0; -+// } -+// else if (pUser_read_buf) -+// { -+// /* Use a user provided read buffer. */ -+// if (!user_read_buf_size) -+// return MZ_FALSE; -+// pRead_buf = (mz_uint8 *)pUser_read_buf; -+// read_buf_size = user_read_buf_size; -+// read_buf_avail = 0; -+// comp_remaining = file_stat.m_comp_size; -+// } -+// else -+// { -+// /* Temporarily allocate a read buffer. */ -+// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -+// if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - --mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) --{ -- mz_uint32 file_index; -- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -- return MZ_FALSE; -- return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); --} -+// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - --mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) --{ -- return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); --} -+// read_buf_avail = 0; -+// comp_remaining = file_stat.m_comp_size; -+// } - --mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) --{ -- return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); --} -+// do -+// { -+// /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ -+// size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); -+// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) -+// { -+// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -+// { -+// status = TINFL_STATUS_FAILED; -+// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -+// break; -+// } -+// cur_file_ofs += read_buf_avail; -+// comp_remaining -= read_buf_avail; -+// read_buf_ofs = 0; -+// } -+// in_buf_size = (size_t)read_buf_avail; -+// status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); -+// read_buf_avail -= in_buf_size; -+// read_buf_ofs += in_buf_size; -+// out_buf_ofs += out_buf_size; -+// } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); -+ -+// if (status == TINFL_STATUS_DONE) -+// { -+// /* Make sure the entire file was decompressed, and check its CRC. */ -+// if (out_buf_ofs != file_stat.m_uncomp_size) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -+// status = TINFL_STATUS_FAILED; -+// } -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); -+// status = TINFL_STATUS_FAILED; -+// } -+// #endif -+// } - --void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) --{ -- mz_uint64 comp_size, uncomp_size, alloc_size; -- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -- void *pBuf; -+// if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - -- if (pSize) -- *pSize = 0; -+// return status == TINFL_STATUS_DONE; -+// } - -- if (!p) -- { -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- return NULL; -- } -+// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -+// { -+// mz_uint32 file_index; -+// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -+// return MZ_FALSE; -+// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); -+// } - -- comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -- uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); -+// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) -+// { -+// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); -+// } - -- alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; -- if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) -- { -- mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -- return NULL; -- } -+// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) -+// { -+// return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); -+// } - -- if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) -- { -- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- return NULL; -- } -+// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) -+// { -+// mz_uint64 comp_size, uncomp_size, alloc_size; -+// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -+// void *pBuf; - -- if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -- return NULL; -- } -+// if (pSize) -+// *pSize = 0; - -- if (pSize) -- *pSize = (size_t)alloc_size; -- return pBuf; --} -+// if (!p) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return NULL; -+// } - --void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) --{ -- mz_uint32 file_index; -- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -- { -- if (pSize) -- *pSize = 0; -- return MZ_FALSE; -- } -- return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); --} -+// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -+// uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - --mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) --{ -- int status = TINFL_STATUS_DONE; -- mz_uint file_crc32 = MZ_CRC32_INIT; -- mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; -- mz_zip_archive_file_stat file_stat; -- void *pRead_buf = NULL; -- void *pWrite_buf = NULL; -- mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -- mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -- -- if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- -- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -- return MZ_FALSE; -- -- /* A directory or zero length file */ -- if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) -- return MZ_TRUE; -- -- /* Encryption and patch files are not supported. */ -- if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -- -- /* This function only supports decompressing stored and deflate. */ -- if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -- -- /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ -- cur_file_ofs = file_stat.m_local_header_ofs; -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -- -- if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- -- cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -- if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- -- /* Decompress the file either directly from memory or from a file input buffer. */ -- if (pZip->m_pState->m_pMem) -- { -- pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; -- read_buf_size = read_buf_avail = file_stat.m_comp_size; -- comp_remaining = 0; -- } -- else -- { -- read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -- if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; -+// if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// return NULL; -+// } - -- read_buf_avail = 0; -- comp_remaining = file_stat.m_comp_size; -- } -+// if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// return NULL; -+// } - -- if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) -- { -- /* The file is stored or the caller has requested the compressed data. */ -- if (pZip->m_pState->m_pMem) -- { -- if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -+// return NULL; -+// } - -- if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) -- { -- mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -- status = TINFL_STATUS_FAILED; -- } -- else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -- { --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); --#endif -- } -+// if (pSize) -+// *pSize = (size_t)alloc_size; -+// return pBuf; -+// } - -- cur_file_ofs += file_stat.m_comp_size; -- out_buf_ofs += file_stat.m_comp_size; -- comp_remaining = 0; -- } -- else -- { -- while (comp_remaining) -- { -- read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -- { -- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -- status = TINFL_STATUS_FAILED; -- break; -- } -+// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) -+// { -+// mz_uint32 file_index; -+// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -+// { -+// if (pSize) -+// *pSize = 0; -+// return MZ_FALSE; -+// } -+// return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); -+// } - --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -- { -- file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); -- } --#endif -+// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -+// { -+// int status = TINFL_STATUS_DONE; -+// mz_uint file_crc32 = MZ_CRC32_INIT; -+// mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; -+// mz_zip_archive_file_stat file_stat; -+// void *pRead_buf = NULL; -+// void *pWrite_buf = NULL; -+// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -+// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - -- if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -- { -- mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -- status = TINFL_STATUS_FAILED; -- break; -- } -+// if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- cur_file_ofs += read_buf_avail; -- out_buf_ofs += read_buf_avail; -- comp_remaining -= read_buf_avail; -- } -- } -- } -- else -- { -- tinfl_decompressor inflator; -- tinfl_init(&inflator); -+// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -+// return MZ_FALSE; - -- if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) -- { -- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- status = TINFL_STATUS_FAILED; -- } -- else -- { -- do -- { -- mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -- size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -- if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) -- { -- read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -- { -- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -- status = TINFL_STATUS_FAILED; -- break; -- } -- cur_file_ofs += read_buf_avail; -- comp_remaining -= read_buf_avail; -- read_buf_ofs = 0; -- } -+// /* A directory or zero length file */ -+// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) -+// return MZ_TRUE; - -- in_buf_size = (size_t)read_buf_avail; -- status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); -- read_buf_avail -= in_buf_size; -- read_buf_ofs += in_buf_size; -+// /* Encryption and patch files are not supported. */ -+// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - -- if (out_buf_size) -- { -- if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) -- { -- mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -- status = TINFL_STATUS_FAILED; -- break; -- } -+// /* This function only supports decompressing stored and deflate. */ -+// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); - --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); --#endif -- if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) -- { -- mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -- status = TINFL_STATUS_FAILED; -- break; -- } -- } -- } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); -- } -- } -+// /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ -+// cur_file_ofs = file_stat.m_local_header_ofs; -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -- if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -- { -- /* Make sure the entire file was decompressed, and check its CRC. */ -- if (out_buf_ofs != file_stat.m_uncomp_size) -- { -- mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -- status = TINFL_STATUS_FAILED; -- } --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- else if (file_crc32 != file_stat.m_crc32) -- { -- mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -- status = TINFL_STATUS_FAILED; -- } --#endif -- } -+// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (!pZip->m_pState->m_pMem) -- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -+// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -+// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (pWrite_buf) -- pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); -+// /* Decompress the file either directly from memory or from a file input buffer. */ -+// if (pZip->m_pState->m_pMem) -+// { -+// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; -+// read_buf_size = read_buf_avail = file_stat.m_comp_size; -+// comp_remaining = 0; -+// } -+// else -+// { -+// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -+// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -- return status == TINFL_STATUS_DONE; --} -+// read_buf_avail = 0; -+// comp_remaining = file_stat.m_comp_size; -+// } - --mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) --{ -- mz_uint32 file_index; -- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -- return MZ_FALSE; -+// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) -+// { -+// /* The file is stored or the caller has requested the compressed data. */ -+// if (pZip->m_pState->m_pMem) -+// { -+// if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -- return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); --} -+// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -+// status = TINFL_STATUS_FAILED; -+// } -+// else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -+// { -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); -+// #endif -+// } - --mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) --{ -- mz_zip_reader_extract_iter_state *pState; -- mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -- mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -+// cur_file_ofs += file_stat.m_comp_size; -+// out_buf_ofs += file_stat.m_comp_size; -+// comp_remaining = 0; -+// } -+// else -+// { -+// while (comp_remaining) -+// { -+// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// status = TINFL_STATUS_FAILED; -+// break; -+// } - -- /* Argument sanity check */ -- if ((!pZip) || (!pZip->m_pState)) -- return NULL; -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -+// { -+// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); -+// } -+// #endif - -- /* Allocate an iterator status structure */ -- pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); -- if (!pState) -- { -- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- return NULL; -- } -+// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -+// status = TINFL_STATUS_FAILED; -+// break; -+// } - -- /* Fetch file details */ -- if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -+// cur_file_ofs += read_buf_avail; -+// out_buf_ofs += read_buf_avail; -+// comp_remaining -= read_buf_avail; -+// } -+// } -+// } -+// else -+// { -+// tinfl_decompressor inflator; -+// tinfl_init(&inflator); - -- /* Encryption and patch files are not supported. */ -- if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -- { -- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -+// if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// status = TINFL_STATUS_FAILED; -+// } -+// else -+// { -+// do -+// { -+// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -+// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -+// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) -+// { -+// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// status = TINFL_STATUS_FAILED; -+// break; -+// } -+// cur_file_ofs += read_buf_avail; -+// comp_remaining -= read_buf_avail; -+// read_buf_ofs = 0; -+// } - -- /* This function only supports decompressing stored and deflate. */ -- if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) -- { -- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -+// in_buf_size = (size_t)read_buf_avail; -+// status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); -+// read_buf_avail -= in_buf_size; -+// read_buf_ofs += in_buf_size; - -- /* Init state - save args */ -- pState->pZip = pZip; -- pState->flags = flags; -+// if (out_buf_size) -+// { -+// if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -+// status = TINFL_STATUS_FAILED; -+// break; -+// } -+ -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); -+// #endif -+// if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -+// status = TINFL_STATUS_FAILED; -+// break; -+// } -+// } -+// } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); -+// } -+// } - -- /* Init state - reset variables to defaults */ -- pState->status = TINFL_STATUS_DONE; --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- pState->file_crc32 = MZ_CRC32_INIT; --#endif -- pState->read_buf_ofs = 0; -- pState->out_buf_ofs = 0; -- pState->pRead_buf = NULL; -- pState->pWrite_buf = NULL; -- pState->out_blk_remain = 0; -- -- /* Read and parse the local directory entry. */ -- pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; -- if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -- { -- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -+// if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -+// { -+// /* Make sure the entire file was decompressed, and check its CRC. */ -+// if (out_buf_ofs != file_stat.m_uncomp_size) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -+// status = TINFL_STATUS_FAILED; -+// } -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// else if (file_crc32 != file_stat.m_crc32) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -+// status = TINFL_STATUS_FAILED; -+// } -+// #endif -+// } - -- if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -- { -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -+// if (!pZip->m_pState->m_pMem) -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - -- pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -- if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) -- { -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -+// if (pWrite_buf) -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); - -- /* Decompress the file either directly from memory or from a file input buffer. */ -- if (pZip->m_pState->m_pMem) -- { -- pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; -- pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; -- pState->comp_remaining = pState->file_stat.m_comp_size; -- } -- else -- { -- if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) -- { -- /* Decompression required, therefore intermediate read buffer required */ -- pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); -- if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) -- { -- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -- } -- else -- { -- /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ -- pState->read_buf_size = 0; -- } -- pState->read_buf_avail = 0; -- pState->comp_remaining = pState->file_stat.m_comp_size; -- } -+// return status == TINFL_STATUS_DONE; -+// } -+ -+// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -+// { -+// mz_uint32 file_index; -+// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -+// return MZ_FALSE; -+ -+// return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); -+// } -+ -+// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) -+// { -+// mz_zip_reader_extract_iter_state *pState; -+// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -+// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -+ -+// /* Argument sanity check */ -+// if ((!pZip) || (!pZip->m_pState)) -+// return NULL; -+ -+// /* Allocate an iterator status structure */ -+// pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); -+// if (!pState) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// return NULL; -+// } -+ -+// /* Fetch file details */ -+// if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } -+ -+// /* Encryption and patch files are not supported. */ -+// if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } -+ -+// /* This function only supports decompressing stored and deflate. */ -+// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } -+ -+// /* Init state - save args */ -+// pState->pZip = pZip; -+// pState->flags = flags; -+ -+// /* Init state - reset variables to defaults */ -+// pState->status = TINFL_STATUS_DONE; -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// pState->file_crc32 = MZ_CRC32_INIT; -+// #endif -+// pState->read_buf_ofs = 0; -+// pState->out_buf_ofs = 0; -+// pState->pRead_buf = NULL; -+// pState->pWrite_buf = NULL; -+// pState->out_blk_remain = 0; -+ -+// /* Read and parse the local directory entry. */ -+// pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; -+// if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } -+ -+// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } -+ -+// pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -+// if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } - -- if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) -- { -- /* Decompression required, init decompressor */ -- tinfl_init( &pState->inflator ); -+// /* Decompress the file either directly from memory or from a file input buffer. */ -+// if (pZip->m_pState->m_pMem) -+// { -+// pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; -+// pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; -+// pState->comp_remaining = pState->file_stat.m_comp_size; -+// } -+// else -+// { -+// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) -+// { -+// /* Decompression required, therefore intermediate read buffer required */ -+// pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); -+// if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } -+// } -+// else -+// { -+// /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ -+// pState->read_buf_size = 0; -+// } -+// pState->read_buf_avail = 0; -+// pState->comp_remaining = pState->file_stat.m_comp_size; -+// } - -- /* Allocate write buffer */ -- if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) -- { -- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- if (pState->pRead_buf) -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -- } -+// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) -+// { -+// /* Decompression required, init decompressor */ -+// tinfl_init( &pState->inflator ); - -- return pState; --} -+// /* Allocate write buffer */ -+// if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// if (pState->pRead_buf) -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } -+// } - --mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) --{ -- mz_uint32 file_index; -+// return pState; -+// } - -- /* Locate file index by name */ -- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -- return NULL; -+// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) -+// { -+// mz_uint32 file_index; - -- /* Construct iterator */ -- return mz_zip_reader_extract_iter_new(pZip, file_index, flags); --} -+// /* Locate file index by name */ -+// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -+// return NULL; - --size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) --{ -- size_t copied_to_caller = 0; -+// /* Construct iterator */ -+// return mz_zip_reader_extract_iter_new(pZip, file_index, flags); -+// } - -- /* Argument sanity check */ -- if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) -- return 0; -+// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) -+// { -+// size_t copied_to_caller = 0; - -- if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) -- { -- /* The file is stored or the caller has requested the compressed data, calc amount to return. */ -- copied_to_caller = MZ_MIN( buf_size, pState->comp_remaining ); -+// /* Argument sanity check */ -+// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) -+// return 0; - -- /* Zip is in memory....or requires reading from a file? */ -- if (pState->pZip->m_pState->m_pMem) -- { -- /* Copy data to caller's buffer */ -- memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); -- pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; -- } -- else -- { -- /* Read directly into caller's buffer */ -- if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) -- { -- /* Failed to read all that was asked for, flag failure and alert user */ -- mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); -- pState->status = TINFL_STATUS_FAILED; -- copied_to_caller = 0; -- } -- } -+// if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) -+// { -+// /* The file is stored or the caller has requested the compressed data, calc amount to return. */ -+// copied_to_caller = MZ_MIN( buf_size, pState->comp_remaining ); - --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- /* Compute CRC if not returning compressed data only */ -- if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -- pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); --#endif -+// /* Zip is in memory....or requires reading from a file? */ -+// if (pState->pZip->m_pState->m_pMem) -+// { -+// /* Copy data to caller's buffer */ -+// memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); -+// pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; -+// } -+// else -+// { -+// /* Read directly into caller's buffer */ -+// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) -+// { -+// /* Failed to read all that was asked for, flag failure and alert user */ -+// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); -+// pState->status = TINFL_STATUS_FAILED; -+// copied_to_caller = 0; -+// } -+// } - -- /* Advance offsets, dec counters */ -- pState->cur_file_ofs += copied_to_caller; -- pState->out_buf_ofs += copied_to_caller; -- pState->comp_remaining -= copied_to_caller; -- } -- else -- { -- do -- { -- /* Calc ptr to write buffer - given current output pos and block size */ -- mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// /* Compute CRC if not returning compressed data only */ -+// if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -+// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); -+// #endif - -- /* Calc max output size - given current output pos and block size */ -- size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -+// /* Advance offsets, dec counters */ -+// pState->cur_file_ofs += copied_to_caller; -+// pState->out_buf_ofs += copied_to_caller; -+// pState->comp_remaining -= copied_to_caller; -+// } -+// else -+// { -+// do -+// { -+// /* Calc ptr to write buffer - given current output pos and block size */ -+// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - -- if (!pState->out_blk_remain) -- { -- /* Read more data from file if none available (and reading from file) */ -- if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) -- { -- /* Calc read size */ -- pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); -- if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) -- { -- mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); -- pState->status = TINFL_STATUS_FAILED; -- break; -- } -+// /* Calc max output size - given current output pos and block size */ -+// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - -- /* Advance offsets, dec counters */ -- pState->cur_file_ofs += pState->read_buf_avail; -- pState->comp_remaining -= pState->read_buf_avail; -- pState->read_buf_ofs = 0; -- } -+// if (!pState->out_blk_remain) -+// { -+// /* Read more data from file if none available (and reading from file) */ -+// if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) -+// { -+// /* Calc read size */ -+// pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); -+// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) -+// { -+// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); -+// pState->status = TINFL_STATUS_FAILED; -+// break; -+// } -+ -+// /* Advance offsets, dec counters */ -+// pState->cur_file_ofs += pState->read_buf_avail; -+// pState->comp_remaining -= pState->read_buf_avail; -+// pState->read_buf_ofs = 0; -+// } - -- /* Perform decompression */ -- in_buf_size = (size_t)pState->read_buf_avail; -- pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); -- pState->read_buf_avail -= in_buf_size; -- pState->read_buf_ofs += in_buf_size; -+// /* Perform decompression */ -+// in_buf_size = (size_t)pState->read_buf_avail; -+// pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); -+// pState->read_buf_avail -= in_buf_size; -+// pState->read_buf_ofs += in_buf_size; - -- /* Update current output block size remaining */ -- pState->out_blk_remain = out_buf_size; -- } -+// /* Update current output block size remaining */ -+// pState->out_blk_remain = out_buf_size; -+// } - -- if (pState->out_blk_remain) -- { -- /* Calc amount to return. */ -- size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); -+// if (pState->out_blk_remain) -+// { -+// /* Calc amount to return. */ -+// size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); - -- /* Copy data to caller's buffer */ -- memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); -+// /* Copy data to caller's buffer */ -+// memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); - --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- /* Perform CRC */ -- pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); --#endif -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// /* Perform CRC */ -+// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); -+// #endif - -- /* Decrement data consumed from block */ -- pState->out_blk_remain -= to_copy; -+// /* Decrement data consumed from block */ -+// pState->out_blk_remain -= to_copy; - -- /* Inc output offset, while performing sanity check */ -- if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) -- { -- mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); -- pState->status = TINFL_STATUS_FAILED; -- break; -- } -+// /* Inc output offset, while performing sanity check */ -+// if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) -+// { -+// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); -+// pState->status = TINFL_STATUS_FAILED; -+// break; -+// } - -- /* Increment counter of data copied to caller */ -- copied_to_caller += to_copy; -- } -- } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); -- } -+// /* Increment counter of data copied to caller */ -+// copied_to_caller += to_copy; -+// } -+// } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); -+// } - -- /* Return how many bytes were copied into user buffer */ -- return copied_to_caller; --} -+// /* Return how many bytes were copied into user buffer */ -+// return copied_to_caller; -+// } - --mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) --{ -- int status; -+// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) -+// { -+// int status; - -- /* Argument sanity check */ -- if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) -- return MZ_FALSE; -+// /* Argument sanity check */ -+// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) -+// return MZ_FALSE; - -- /* Was decompression completed and requested? */ -- if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -- { -- /* Make sure the entire file was decompressed, and check its CRC. */ -- if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) -- { -- mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -- pState->status = TINFL_STATUS_FAILED; -- } --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- else if (pState->file_crc32 != pState->file_stat.m_crc32) -- { -- mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); -- pState->status = TINFL_STATUS_FAILED; -- } --#endif -- } -+// /* Was decompression completed and requested? */ -+// if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -+// { -+// /* Make sure the entire file was decompressed, and check its CRC. */ -+// if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) -+// { -+// mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -+// pState->status = TINFL_STATUS_FAILED; -+// } -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// else if (pState->file_crc32 != pState->file_stat.m_crc32) -+// { -+// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); -+// pState->status = TINFL_STATUS_FAILED; -+// } -+// #endif -+// } - -- /* Free buffers */ -- if (!pState->pZip->m_pState->m_pMem) -- pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); -- if (pState->pWrite_buf) -- pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); -+// /* Free buffers */ -+// if (!pState->pZip->m_pState->m_pMem) -+// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); -+// if (pState->pWrite_buf) -+// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); - -- /* Save status */ -- status = pState->status; -+// /* Save status */ -+// status = pState->status; - -- /* Free context */ -- pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); -+// /* Free context */ -+// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); - -- return status == TINFL_STATUS_DONE; --} -+// return status == TINFL_STATUS_DONE; -+// } - --#ifndef MINIZ_NO_STDIO --static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) --{ -- (void)ofs; -+// #ifndef MINIZ_NO_STDIO -+// static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) -+// { -+// (void)ofs; - -- return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); --} -+// return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); -+// } - --mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) --{ -- mz_bool status; -- mz_zip_archive_file_stat file_stat; -- MZ_FILE *pFile; -+// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) -+// { -+// mz_bool status; -+// mz_zip_archive_file_stat file_stat; -+// MZ_FILE *pFile; - -- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -- return MZ_FALSE; -+// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -+// return MZ_FALSE; - -- if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); -+// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); - -- pFile = MZ_FOPEN(pDst_filename, "wb"); -- if (!pFile) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -+// pFile = MZ_FOPEN(pDst_filename, "wb"); -+// if (!pFile) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -- status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); -+// status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); - -- if (MZ_FCLOSE(pFile) == EOF) -- { -- if (status) -- mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); -+// if (MZ_FCLOSE(pFile) == EOF) -+// { -+// if (status) -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); - -- status = MZ_FALSE; -- } -+// status = MZ_FALSE; -+// } - --#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) -- if (status) -- mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); --#endif -+// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) -+// if (status) -+// mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); -+// #endif - -- return status; --} -+// return status; -+// } - --mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) --{ -- mz_uint32 file_index; -- if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) -- return MZ_FALSE; -+// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) -+// { -+// mz_uint32 file_index; -+// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) -+// return MZ_FALSE; - -- return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); --} -+// return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); -+// } - --mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) --{ -- mz_zip_archive_file_stat file_stat; -+// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) -+// { -+// mz_zip_archive_file_stat file_stat; - -- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -- return MZ_FALSE; -+// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -+// return MZ_FALSE; - -- if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); -+// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); - -- return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); --} -+// return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); -+// } - --mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) --{ -- mz_uint32 file_index; -- if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) -- return MZ_FALSE; -+// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) -+// { -+// mz_uint32 file_index; -+// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) -+// return MZ_FALSE; - -- return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); --} --#endif /* #ifndef MINIZ_NO_STDIO */ -+// return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); -+// } -+// #endif /* #ifndef MINIZ_NO_STDIO */ - - // static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) - // { -@@ -5444,1202 +5443,1202 @@ mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pA - - /* ------------------- .ZIP archive writing */ - --#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -+// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - --static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) --{ -- p[0] = (mz_uint8)v; -- p[1] = (mz_uint8)(v >> 8); --} --static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) --{ -- p[0] = (mz_uint8)v; -- p[1] = (mz_uint8)(v >> 8); -- p[2] = (mz_uint8)(v >> 16); -- p[3] = (mz_uint8)(v >> 24); --} --static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) --{ -- mz_write_le32(p, (mz_uint32)v); -- mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); --} -+// static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) -+// { -+// p[0] = (mz_uint8)v; -+// p[1] = (mz_uint8)(v >> 8); -+// } -+// static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) -+// { -+// p[0] = (mz_uint8)v; -+// p[1] = (mz_uint8)(v >> 8); -+// p[2] = (mz_uint8)(v >> 16); -+// p[3] = (mz_uint8)(v >> 24); -+// } -+// static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) -+// { -+// mz_write_le32(p, (mz_uint32)v); -+// mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); -+// } - --#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) --#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) --#define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) -+// #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) -+// #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) -+// #define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) - --static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) --{ -- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -- mz_zip_internal_state *pState = pZip->m_pState; -- mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); -+// static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -+// { -+// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -+// mz_zip_internal_state *pState = pZip->m_pState; -+// mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); - -- if (!n) -- return 0; -+// if (!n) -+// return 0; - -- /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ -- if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) -- { -- mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -- return 0; -- } -+// /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ -+// if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -+// return 0; -+// } - -- if (new_size > pState->m_mem_capacity) -- { -- void *pNew_block; -- size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); -+// if (new_size > pState->m_mem_capacity) -+// { -+// void *pNew_block; -+// size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); - -- while (new_capacity < new_size) -- new_capacity *= 2; -+// while (new_capacity < new_size) -+// new_capacity *= 2; - -- if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) -- { -- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- return 0; -- } -+// if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// return 0; -+// } - -- pState->m_pMem = pNew_block; -- pState->m_mem_capacity = new_capacity; -- } -- memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); -- pState->m_mem_size = (size_t)new_size; -- return n; --} -+// pState->m_pMem = pNew_block; -+// pState->m_mem_capacity = new_capacity; -+// } -+// memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); -+// pState->m_mem_size = (size_t)new_size; -+// return n; -+// } - --static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) --{ -- mz_zip_internal_state *pState; -- mz_bool status = MZ_TRUE; -+// static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) -+// { -+// mz_zip_internal_state *pState; -+// mz_bool status = MZ_TRUE; - -- if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) -- { -- if (set_last_error) -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- return MZ_FALSE; -- } -+// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) -+// { -+// if (set_last_error) -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return MZ_FALSE; -+// } - -- pState = pZip->m_pState; -- pZip->m_pState = NULL; -- mz_zip_array_clear(pZip, &pState->m_central_dir); -- mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); -- mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); -+// pState = pZip->m_pState; -+// pZip->m_pState = NULL; -+// mz_zip_array_clear(pZip, &pState->m_central_dir); -+// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); -+// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); - --#ifndef MINIZ_NO_STDIO -- if (pState->m_pFile) -- { -- if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -- { -- if (MZ_FCLOSE(pState->m_pFile) == EOF) -- { -- if (set_last_error) -- mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); -- status = MZ_FALSE; -- } -- } -+// #ifndef MINIZ_NO_STDIO -+// if (pState->m_pFile) -+// { -+// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -+// { -+// if (MZ_FCLOSE(pState->m_pFile) == EOF) -+// { -+// if (set_last_error) -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); -+// status = MZ_FALSE; -+// } -+// } - -- pState->m_pFile = NULL; -- } --#endif /* #ifndef MINIZ_NO_STDIO */ -+// pState->m_pFile = NULL; -+// } -+// #endif /* #ifndef MINIZ_NO_STDIO */ - -- if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); -- pState->m_pMem = NULL; -- } -+// if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); -+// pState->m_pMem = NULL; -+// } - -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; -- return status; --} -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; -+// return status; -+// } - --mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) --{ -- mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; -+// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) -+// { -+// mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; - -- if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -- { -- if (!pZip->m_pRead) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- } -+// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -+// { -+// if (!pZip->m_pRead) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// } - -- if (pZip->m_file_offset_alignment) -- { -- /* Ensure user specified file offset alignment is a power of 2. */ -- if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- } -+// if (pZip->m_file_offset_alignment) -+// { -+// /* Ensure user specified file offset alignment is a power of 2. */ -+// if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// } - -- if (!pZip->m_pAlloc) -- pZip->m_pAlloc = miniz_def_alloc_func; -- if (!pZip->m_pFree) -- pZip->m_pFree = miniz_def_free_func; -- if (!pZip->m_pRealloc) -- pZip->m_pRealloc = miniz_def_realloc_func; -+// if (!pZip->m_pAlloc) -+// pZip->m_pAlloc = miniz_def_alloc_func; -+// if (!pZip->m_pFree) -+// pZip->m_pFree = miniz_def_free_func; -+// if (!pZip->m_pRealloc) -+// pZip->m_pRealloc = miniz_def_realloc_func; - -- pZip->m_archive_size = existing_size; -- pZip->m_central_directory_file_ofs = 0; -- pZip->m_total_files = 0; -+// pZip->m_archive_size = existing_size; -+// pZip->m_central_directory_file_ofs = 0; -+// pZip->m_total_files = 0; - -- if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -- memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); -+// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); - -- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); -- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); -- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); -+// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); -+// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); -+// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); - -- pZip->m_pState->m_zip64 = zip64; -- pZip->m_pState->m_zip64_has_extended_info_fields = zip64; -+// pZip->m_pState->m_zip64 = zip64; -+// pZip->m_pState->m_zip64_has_extended_info_fields = zip64; - -- pZip->m_zip_type = MZ_ZIP_TYPE_USER; -- pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; -+// pZip->m_zip_type = MZ_ZIP_TYPE_USER; -+// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - -- return MZ_TRUE; --} -+// return MZ_TRUE; -+// } - --mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) --{ -- return mz_zip_writer_init_v2(pZip, existing_size, 0); --} -+// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) -+// { -+// return mz_zip_writer_init_v2(pZip, existing_size, 0); -+// } - --mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) --{ -- pZip->m_pWrite = mz_zip_heap_write_func; -- pZip->m_pNeeds_keepalive = NULL; -+// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) -+// { -+// pZip->m_pWrite = mz_zip_heap_write_func; -+// pZip->m_pNeeds_keepalive = NULL; - -- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -- pZip->m_pRead = mz_zip_mem_read_func; -+// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -+// pZip->m_pRead = mz_zip_mem_read_func; - -- pZip->m_pIO_opaque = pZip; -+// pZip->m_pIO_opaque = pZip; - -- if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) -- return MZ_FALSE; -+// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) -+// return MZ_FALSE; - -- pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; -+// pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; - -- if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) -- { -- if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) -- { -- mz_zip_writer_end_internal(pZip, MZ_FALSE); -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- } -- pZip->m_pState->m_mem_capacity = initial_allocation_size; -- } -+// if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) -+// { -+// if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) -+// { -+// mz_zip_writer_end_internal(pZip, MZ_FALSE); -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// } -+// pZip->m_pState->m_mem_capacity = initial_allocation_size; -+// } - -- return MZ_TRUE; --} -+// return MZ_TRUE; -+// } - --mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) --{ -- return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); --} -+// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) -+// { -+// return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); -+// } - --#ifndef MINIZ_NO_STDIO --static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) --{ -- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -- mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); -+// #ifndef MINIZ_NO_STDIO -+// static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -+// { -+// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -+// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - -- file_ofs += pZip->m_pState->m_file_archive_start_ofs; -+// file_ofs += pZip->m_pState->m_file_archive_start_ofs; - -- if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) -- { -- mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); -- return 0; -- } -+// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); -+// return 0; -+// } - -- return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); --} -+// return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); -+// } - --mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) --{ -- return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); --} -+// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) -+// { -+// return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); -+// } - --mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) --{ -- MZ_FILE *pFile; -+// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) -+// { -+// MZ_FILE *pFile; - -- pZip->m_pWrite = mz_zip_file_write_func; -- pZip->m_pNeeds_keepalive = NULL; -+// pZip->m_pWrite = mz_zip_file_write_func; -+// pZip->m_pNeeds_keepalive = NULL; - -- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -- pZip->m_pRead = mz_zip_file_read_func; -+// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -+// pZip->m_pRead = mz_zip_file_read_func; - -- pZip->m_pIO_opaque = pZip; -+// pZip->m_pIO_opaque = pZip; -+ -+// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) -+// return MZ_FALSE; -+ -+// if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) -+// { -+// mz_zip_writer_end(pZip); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -+// } - -- if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) -- return MZ_FALSE; -+// pZip->m_pState->m_pFile = pFile; -+// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; - -- if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) -- { -- mz_zip_writer_end(pZip); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -- } -+// if (size_to_reserve_at_beginning) -+// { -+// mz_uint64 cur_ofs = 0; -+// char buf[4096]; - -- pZip->m_pState->m_pFile = pFile; -- pZip->m_zip_type = MZ_ZIP_TYPE_FILE; -+// MZ_CLEAR_OBJ(buf); - -- if (size_to_reserve_at_beginning) -- { -- mz_uint64 cur_ofs = 0; -- char buf[4096]; -+// do -+// { -+// size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) -+// { -+// mz_zip_writer_end(pZip); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// } -+// cur_ofs += n; -+// size_to_reserve_at_beginning -= n; -+// } while (size_to_reserve_at_beginning); -+// } - -- MZ_CLEAR_OBJ(buf); -+// return MZ_TRUE; -+// } - -- do -- { -- size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) -- { -- mz_zip_writer_end(pZip); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- } -- cur_ofs += n; -- size_to_reserve_at_beginning -= n; -- } while (size_to_reserve_at_beginning); -- } -+// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) -+// { -+// pZip->m_pWrite = mz_zip_file_write_func; -+// pZip->m_pNeeds_keepalive = NULL; - -- return MZ_TRUE; --} -+// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -+// pZip->m_pRead = mz_zip_file_read_func; - --mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) --{ -- pZip->m_pWrite = mz_zip_file_write_func; -- pZip->m_pNeeds_keepalive = NULL; -+// pZip->m_pIO_opaque = pZip; - -- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -- pZip->m_pRead = mz_zip_file_read_func; -+// if (!mz_zip_writer_init_v2(pZip, 0, flags)) -+// return MZ_FALSE; - -- pZip->m_pIO_opaque = pZip; -+// pZip->m_pState->m_pFile = pFile; -+// pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); -+// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; - -- if (!mz_zip_writer_init_v2(pZip, 0, flags)) -- return MZ_FALSE; -+// return MZ_TRUE; -+// } -+// #endif /* #ifndef MINIZ_NO_STDIO */ - -- pZip->m_pState->m_pFile = pFile; -- pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); -- pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; -+// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) -+// { -+// mz_zip_internal_state *pState; - -- return MZ_TRUE; --} --#endif /* #ifndef MINIZ_NO_STDIO */ -+// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - --mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) --{ -- mz_zip_internal_state *pState; -+// if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) -+// { -+// /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ -+// if (!pZip->m_pState->m_zip64) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// } - -- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// /* No sense in trying to write to an archive that's already at the support max size */ -+// if (pZip->m_pState->m_zip64) -+// { -+// if (pZip->m_total_files == MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// } -+// else -+// { -+// if (pZip->m_total_files == MZ_UINT16_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - -- if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) -- { -- /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ -- if (!pZip->m_pState->m_zip64) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- } -+// if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -+// } - -- /* No sense in trying to write to an archive that's already at the support max size */ -- if (pZip->m_pState->m_zip64) -- { -- if (pZip->m_total_files == MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -- } -- else -- { -- if (pZip->m_total_files == MZ_UINT16_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// pState = pZip->m_pState; - -- if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -- } -+// if (pState->m_pFile) -+// { -+// #ifdef MINIZ_NO_STDIO -+// (void)pFilename; -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// #else -+// if (pZip->m_pIO_opaque != pZip) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- pState = pZip->m_pState; -+// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -+// { -+// if (!pFilename) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if (pState->m_pFile) -- { --#ifdef MINIZ_NO_STDIO -- (void)pFilename; -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); --#else -- if (pZip->m_pIO_opaque != pZip) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ -+// if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) -+// { -+// /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ -+// mz_zip_reader_end_internal(pZip, MZ_FALSE); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -+// } -+// } - -- if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -- { -- if (!pFilename) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// pZip->m_pWrite = mz_zip_file_write_func; -+// pZip->m_pNeeds_keepalive = NULL; -+// #endif /* #ifdef MINIZ_NO_STDIO */ -+// } -+// else if (pState->m_pMem) -+// { -+// /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ -+// if (pZip->m_pIO_opaque != pZip) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ -- if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) -- { -- /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ -- mz_zip_reader_end_internal(pZip, MZ_FALSE); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -- } -- } -+// pState->m_mem_capacity = pState->m_mem_size; -+// pZip->m_pWrite = mz_zip_heap_write_func; -+// pZip->m_pNeeds_keepalive = NULL; -+// } -+// /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ -+// else if (!pZip->m_pWrite) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- pZip->m_pWrite = mz_zip_file_write_func; -- pZip->m_pNeeds_keepalive = NULL; --#endif /* #ifdef MINIZ_NO_STDIO */ -- } -- else if (pState->m_pMem) -- { -- /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ -- if (pZip->m_pIO_opaque != pZip) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// /* Start writing new files at the archive's current central directory location. */ -+// /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ -+// pZip->m_archive_size = pZip->m_central_directory_file_ofs; -+// pZip->m_central_directory_file_ofs = 0; - -- pState->m_mem_capacity = pState->m_mem_size; -- pZip->m_pWrite = mz_zip_heap_write_func; -- pZip->m_pNeeds_keepalive = NULL; -- } -- /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ -- else if (!pZip->m_pWrite) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ -+// /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ -+// /* TODO: We could easily maintain the sorted central directory offsets. */ -+// mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); - -- /* Start writing new files at the archive's current central directory location. */ -- /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ -- pZip->m_archive_size = pZip->m_central_directory_file_ofs; -- pZip->m_central_directory_file_ofs = 0; -+// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - -- /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ -- /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ -- /* TODO: We could easily maintain the sorted central directory offsets. */ -- mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); -+// return MZ_TRUE; -+// } - -- pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; -+// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) -+// { -+// return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); -+// } - -- return MZ_TRUE; --} -+/* TODO: pArchive_name is a terrible name here! */ -+// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) -+// { -+// return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); -+// } - --mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) --{ -- return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); --} -+// typedef struct -+// { -+// mz_zip_archive *m_pZip; -+// mz_uint64 m_cur_archive_file_ofs; -+// mz_uint64 m_comp_size; -+// } mz_zip_writer_add_state; - --/* TODO: pArchive_name is a terrible name here! */ --mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) --{ -- return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); --} -+// static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) -+// { -+// mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; -+// if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) -+// return MZ_FALSE; - --typedef struct --{ -- mz_zip_archive *m_pZip; -- mz_uint64 m_cur_archive_file_ofs; -- mz_uint64 m_comp_size; --} mz_zip_writer_add_state; -+// pState->m_cur_archive_file_ofs += len; -+// pState->m_comp_size += len; -+// return MZ_TRUE; -+// } - --static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) --{ -- mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; -- if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) -- return MZ_FALSE; -+// #define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) -+// #define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) -+// static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) -+// { -+// mz_uint8 *pDst = pBuf; -+// mz_uint32 field_size = 0; - -- pState->m_cur_archive_file_ofs += len; -- pState->m_comp_size += len; -- return MZ_TRUE; --} -+// MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); -+// MZ_WRITE_LE16(pDst + 2, 0); -+// pDst += sizeof(mz_uint16) * 2; - --#define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) --#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) --static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) --{ -- mz_uint8 *pDst = pBuf; -- mz_uint32 field_size = 0; -+// if (pUncomp_size) -+// { -+// MZ_WRITE_LE64(pDst, *pUncomp_size); -+// pDst += sizeof(mz_uint64); -+// field_size += sizeof(mz_uint64); -+// } - -- MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); -- MZ_WRITE_LE16(pDst + 2, 0); -- pDst += sizeof(mz_uint16) * 2; -+// if (pComp_size) -+// { -+// MZ_WRITE_LE64(pDst, *pComp_size); -+// pDst += sizeof(mz_uint64); -+// field_size += sizeof(mz_uint64); -+// } - -- if (pUncomp_size) -- { -- MZ_WRITE_LE64(pDst, *pUncomp_size); -- pDst += sizeof(mz_uint64); -- field_size += sizeof(mz_uint64); -- } -+// if (pLocal_header_ofs) -+// { -+// MZ_WRITE_LE64(pDst, *pLocal_header_ofs); -+// pDst += sizeof(mz_uint64); -+// field_size += sizeof(mz_uint64); -+// } - -- if (pComp_size) -- { -- MZ_WRITE_LE64(pDst, *pComp_size); -- pDst += sizeof(mz_uint64); -- field_size += sizeof(mz_uint64); -- } -+// MZ_WRITE_LE16(pBuf + 2, field_size); - -- if (pLocal_header_ofs) -- { -- MZ_WRITE_LE64(pDst, *pLocal_header_ofs); -- pDst += sizeof(mz_uint64); -- field_size += sizeof(mz_uint64); -- } -+// return (mz_uint32)(pDst - pBuf); -+// } - -- MZ_WRITE_LE16(pBuf + 2, field_size); -+// static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) -+// { -+// (void)pZip; -+// memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); -+// return MZ_TRUE; -+// } - -- return (mz_uint32)(pDst - pBuf); --} -+// static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, -+// mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, -+// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, -+// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, -+// mz_uint64 local_header_ofs, mz_uint32 ext_attributes) -+// { -+// (void)pZip; -+// memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); -+// return MZ_TRUE; -+// } - --static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) --{ -- (void)pZip; -- memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); -- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); -- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); -- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); -- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); -- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); -- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); -- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); -- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); -- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); -- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); -- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); -- return MZ_TRUE; --} -+// static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, -+// const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, -+// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, -+// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, -+// mz_uint64 local_header_ofs, mz_uint32 ext_attributes, -+// const char *user_extra_data, mz_uint user_extra_data_len) -+// { -+// mz_zip_internal_state *pState = pZip->m_pState; -+// mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; -+// size_t orig_central_dir_size = pState->m_central_dir.m_size; -+// mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; - --static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, -- mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, -- mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, -- mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, -- mz_uint64 local_header_ofs, mz_uint32 ext_attributes) --{ -- (void)pZip; -- memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); -- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); -- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); -- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); -- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); -- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); -- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); -- return MZ_TRUE; --} -+// if (!pZip->m_pState->m_zip64) -+// { -+// if (local_header_ofs > 0xFFFFFFFF) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -+// } - --static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, -- const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, -- mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, -- mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, -- mz_uint64 local_header_ofs, mz_uint32 ext_attributes, -- const char *user_extra_data, mz_uint user_extra_data_len) --{ -- mz_zip_internal_state *pState = pZip->m_pState; -- mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; -- size_t orig_central_dir_size = pState->m_central_dir.m_size; -- mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; -+// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -+// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -- if (!pZip->m_pState->m_zip64) -- { -- if (local_header_ofs > 0xFFFFFFFF) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -- } -+// if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size + user_extra_data_len, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -- /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -- if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); -+// if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || -+// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || -+// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || -+// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || -+// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || -+// (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) -+// { -+// /* Try to resize the central directory array back into its original state. */ -+// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// } - -- if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size + user_extra_data_len, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// return MZ_TRUE; -+// } - -- if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || -- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || -- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || -- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || -- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || -- (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) -- { -- /* Try to resize the central directory array back into its original state. */ -- mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- } -+// static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) -+// { -+// /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ -+// if (*pArchive_name == '/') -+// return MZ_FALSE; - -- return MZ_TRUE; --} -+// while (*pArchive_name) -+// { -+// if ((*pArchive_name == '\\') || (*pArchive_name == ':')) -+// return MZ_FALSE; - --static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) --{ -- /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ -- if (*pArchive_name == '/') -- return MZ_FALSE; -+// pArchive_name++; -+// } - -- while (*pArchive_name) -- { -- if ((*pArchive_name == '\\') || (*pArchive_name == ':')) -- return MZ_FALSE; -+// return MZ_TRUE; -+// } - -- pArchive_name++; -- } -+// static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) -+// { -+// mz_uint32 n; -+// if (!pZip->m_file_offset_alignment) -+// return 0; -+// n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); -+// return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); -+// } - -- return MZ_TRUE; --} -+// static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) -+// { -+// char buf[4096]; -+// memset(buf, 0, MZ_MIN(sizeof(buf), n)); -+// while (n) -+// { -+// mz_uint32 s = MZ_MIN(sizeof(buf), n); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - --static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) --{ -- mz_uint32 n; -- if (!pZip->m_file_offset_alignment) -- return 0; -- n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); -- return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); --} -+// cur_file_ofs += s; -+// n -= s; -+// } -+// return MZ_TRUE; -+// } - --static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) --{ -- char buf[4096]; -- memset(buf, 0, MZ_MIN(sizeof(buf), n)); -- while (n) -- { -- mz_uint32 s = MZ_MIN(sizeof(buf), n); -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -+// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) -+// { -+// return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); -+// } - -- cur_file_ofs += s; -- n -= s; -- } -- return MZ_TRUE; --} -+// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, -+// mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, -+// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) -+// { -+// if(!pZip) -+// { -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// } - --mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -- mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) --{ -- return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); --} -+// mz_uint16 method = 0, dos_time = 0, dos_date = 0; -+// mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; -+// mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; -+// size_t archive_name_size; -+// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; -+// tdefl_compressor *pComp = NULL; -+// mz_bool store_data_uncompressed; -+// mz_zip_internal_state *pState; -+// mz_uint8 *pExtra_data = NULL; -+// mz_uint32 extra_size = 0; -+// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; -+// mz_uint16 bit_flags = 0; - --mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, -- mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, -- const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) --{ -- if(!pZip) -- { -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- } -+// if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -+// bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; - -- mz_uint16 method = 0, dos_time = 0, dos_date = 0; -- mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; -- mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; -- size_t archive_name_size; -- mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; -- tdefl_compressor *pComp = NULL; -- mz_bool store_data_uncompressed; -- mz_zip_internal_state *pState; -- mz_uint8 *pExtra_data = NULL; -- mz_uint32 extra_size = 0; -- mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; -- mz_uint16 bit_flags = 0; -+// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) -+// bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; - -- if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -- bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; -+// if ((int)level_and_flags < 0) -+// level_and_flags = MZ_DEFAULT_LEVEL; -+// level = level_and_flags & 0xF; -+// store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); - -- if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) -- bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; -+// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if ((int)level_and_flags < 0) -- level_and_flags = MZ_DEFAULT_LEVEL; -- level = level_and_flags & 0xF; -- store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); -+// pState = pZip->m_pState; - -- if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if (pState->m_zip64) -+// { -+// if (pZip->m_total_files == MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// } -+// else -+// { -+// if (pZip->m_total_files == MZ_UINT16_MAX) -+// { -+// pState->m_zip64 = MZ_TRUE; -+// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ -+// } -+// if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) -+// { -+// pState->m_zip64 = MZ_TRUE; -+// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -+// } -+// } - -- pState = pZip->m_pState; -+// if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if (pState->m_zip64) -- { -- if (pZip->m_total_files == MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -- } -- else -- { -- if (pZip->m_total_files == MZ_UINT16_MAX) -- { -- pState->m_zip64 = MZ_TRUE; -- /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ -- } -- if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) -- { -- pState->m_zip64 = MZ_TRUE; -- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -- } -- } -+// if (!mz_zip_writer_validate_archive_name(pArchive_name)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - -- if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// #ifndef MINIZ_NO_TIME -+// if (last_modified != NULL) -+// { -+// mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); -+// } -+// else -+// { -+// MZ_TIME_T cur_time; -+// time(&cur_time); -+// mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); -+// } -+// #endif /* #ifndef MINIZ_NO_TIME */ - -- if (!mz_zip_writer_validate_archive_name(pArchive_name)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); -+// archive_name_size = strlen(pArchive_name); -+// if (archive_name_size > MZ_UINT16_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - --#ifndef MINIZ_NO_TIME -- if (last_modified != NULL) -- { -- mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); -- } -- else -- { -- MZ_TIME_T cur_time; -- time(&cur_time); -- mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); -- } --#endif /* #ifndef MINIZ_NO_TIME */ -+// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - -- archive_name_size = strlen(pArchive_name); -- if (archive_name_size > MZ_UINT16_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); -+// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -+// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -- num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); -+// if (!pState->m_zip64) -+// { -+// /* Bail early if the archive would obviously become too large */ -+// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size -+// + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + -+// pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len -+// + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) -+// { -+// pState->m_zip64 = MZ_TRUE; -+// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -+// } -+// } - -- /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -- if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); -+// if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) -+// { -+// /* Set DOS Subdirectory attribute bit. */ -+// ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; - -- if (!pState->m_zip64) -- { -- /* Bail early if the archive would obviously become too large */ -- if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size -- + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + -- pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len -- + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) -- { -- pState->m_zip64 = MZ_TRUE; -- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -- } -- } -+// /* Subdirectories cannot contain data. */ -+// if ((buf_size) || (uncomp_size)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// } - -- if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) -- { -- /* Set DOS Subdirectory attribute bit. */ -- ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; -+// /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ -+// if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -- /* Subdirectories cannot contain data. */ -- if ((buf_size) || (uncomp_size)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- } -+// if ((!store_data_uncompressed) && (buf_size)) -+// { -+// if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// } - -- /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ -- if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// return MZ_FALSE; -+// } - -- if ((!store_data_uncompressed) && (buf_size)) -- { -- if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- } -+// local_dir_header_ofs += num_alignment_padding_bytes; -+// if (pZip->m_file_offset_alignment) -+// { -+// MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); -+// } -+// cur_archive_file_ofs += num_alignment_padding_bytes; - -- if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -- return MZ_FALSE; -- } -+// MZ_CLEAR_OBJ(local_dir_header); - -- local_dir_header_ofs += num_alignment_padding_bytes; -- if (pZip->m_file_offset_alignment) -- { -- MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); -- } -- cur_archive_file_ofs += num_alignment_padding_bytes; -+// if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -+// { -+// method = MZ_DEFLATED; -+// } - -- MZ_CLEAR_OBJ(local_dir_header); -+// if (pState->m_zip64) -+// { -+// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) -+// { -+// pExtra_data = extra_data; -+// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -+// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -+// } - -- if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -- { -- method = MZ_DEFLATED; -- } -+// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -- if (pState->m_zip64) -- { -- if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) -- { -- pExtra_data = extra_data; -- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -- } -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// cur_archive_file_ofs += sizeof(local_dir_header); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// } -+// cur_archive_file_ofs += archive_name_size; - -- cur_archive_file_ofs += sizeof(local_dir_header); -+// if (pExtra_data != NULL) -+// { -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- } -- cur_archive_file_ofs += archive_name_size; -+// cur_archive_file_ofs += extra_size; -+// } -+// } -+// else -+// { -+// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) -+// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -+// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -- if (pExtra_data != NULL) -- { -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- cur_archive_file_ofs += extra_size; -- } -- } -- else -- { -- if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) -- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// cur_archive_file_ofs += sizeof(local_dir_header); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// } -+// cur_archive_file_ofs += archive_name_size; -+// } - -- cur_archive_file_ofs += sizeof(local_dir_header); -+// if (user_extra_data_len > 0) -+// { -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- } -- cur_archive_file_ofs += archive_name_size; -- } -+// cur_archive_file_ofs += user_extra_data_len; -+// } - -- if (user_extra_data_len > 0) -- { -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -+// { -+// uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); -+// uncomp_size = buf_size; -+// if (uncomp_size <= 3) -+// { -+// level = 0; -+// store_data_uncompressed = MZ_TRUE; -+// } -+// } - -- cur_archive_file_ofs += user_extra_data_len; -- } -+// if (store_data_uncompressed) -+// { -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// } - -- if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -- { -- uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); -- uncomp_size = buf_size; -- if (uncomp_size <= 3) -- { -- level = 0; -- store_data_uncompressed = MZ_TRUE; -- } -- } -+// cur_archive_file_ofs += buf_size; -+// comp_size = buf_size; -+// } -+// else if (buf_size) -+// { -+// mz_zip_writer_add_state state; - -- if (store_data_uncompressed) -- { -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- } -+// state.m_pZip = pZip; -+// state.m_cur_archive_file_ofs = cur_archive_file_ofs; -+// state.m_comp_size = 0; - -- cur_archive_file_ofs += buf_size; -- comp_size = buf_size; -- } -- else if (buf_size) -- { -- mz_zip_writer_add_state state; -+// if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || -+// (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); -+// } - -- state.m_pZip = pZip; -- state.m_cur_archive_file_ofs = cur_archive_file_ofs; -- state.m_comp_size = 0; -+// comp_size = state.m_comp_size; -+// cur_archive_file_ofs = state.m_cur_archive_file_ofs; -+// } - -- if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || -- (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -- return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); -- } -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// pComp = NULL; - -- comp_size = state.m_comp_size; -- cur_archive_file_ofs = state.m_cur_archive_file_ofs; -- } -+// if (uncomp_size) -+// { -+// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; -+// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; - -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -- pComp = NULL; -+// MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); - -- if (uncomp_size) -- { -- mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; -- mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; -+// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); -+// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); -+// if (pExtra_data == NULL) -+// { -+// if (comp_size > MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -- MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); -+// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); -+// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); -+// } -+// else -+// { -+// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); -+// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); -+// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; -+// } - -- MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); -- MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); -- if (pExtra_data == NULL) -- { -- if (comp_size > MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) -+// return MZ_FALSE; - -- MZ_WRITE_LE32(local_dir_footer + 8, comp_size); -- MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); -- } -- else -- { -- MZ_WRITE_LE64(local_dir_footer + 8, comp_size); -- MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); -- local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; -- } -+// cur_archive_file_ofs += local_dir_footer_size; -+// } - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) -- return MZ_FALSE; -+// if (pExtra_data != NULL) -+// { -+// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -+// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -+// } - -- cur_archive_file_ofs += local_dir_footer_size; -- } -+// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, -+// comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, -+// user_extra_data_central, user_extra_data_central_len)) -+// return MZ_FALSE; - -- if (pExtra_data != NULL) -- { -- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -- } -+// pZip->m_total_files++; -+// pZip->m_archive_size = cur_archive_file_ofs; - -- if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, -- comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, -- user_extra_data_central, user_extra_data_central_len)) -- return MZ_FALSE; -+// return MZ_TRUE; -+// } - -- pZip->m_total_files++; -- pZip->m_archive_size = cur_archive_file_ofs; -+// #ifndef MINIZ_NO_STDIO -+// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -+// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) -+// { -+// if(!pZip) -+// { -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// } - -- return MZ_TRUE; --} -+// mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; -+// mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; -+// mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; -+// mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; -+// size_t archive_name_size; -+// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; -+// mz_uint8 *pExtra_data = NULL; -+// mz_uint32 extra_size = 0; -+// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; -+// mz_zip_internal_state *pState; - --#ifndef MINIZ_NO_STDIO --mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -- const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) --{ -- if(!pZip) -- { -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- } -+// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) -+// gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; - -- mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; -- mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; -- mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; -- mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; -- size_t archive_name_size; -- mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; -- mz_uint8 *pExtra_data = NULL; -- mz_uint32 extra_size = 0; -- mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; -- mz_zip_internal_state *pState; -+// if ((int)level_and_flags < 0) -+// level_and_flags = MZ_DEFAULT_LEVEL; -+// level = level_and_flags & 0xF; - -- if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) -- gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; -+// /* Sanity checks */ -+// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if ((int)level_and_flags < 0) -- level_and_flags = MZ_DEFAULT_LEVEL; -- level = level_and_flags & 0xF; -+// pState = pZip->m_pState; - -- /* Sanity checks */ -- if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) -+// { -+// /* Source file is too large for non-zip64 */ -+// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -+// pState->m_zip64 = MZ_TRUE; -+// } - -- pState = pZip->m_pState; -+// /* We could support this, but why? */ -+// if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) -- { -- /* Source file is too large for non-zip64 */ -- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -- pState->m_zip64 = MZ_TRUE; -- } -+// if (!mz_zip_writer_validate_archive_name(pArchive_name)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - -- /* We could support this, but why? */ -- if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if (pState->m_zip64) -+// { -+// if (pZip->m_total_files == MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// } -+// else -+// { -+// if (pZip->m_total_files == MZ_UINT16_MAX) -+// { -+// pState->m_zip64 = MZ_TRUE; -+// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ -+// } -+// } - -- if (!mz_zip_writer_validate_archive_name(pArchive_name)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); -+// archive_name_size = strlen(pArchive_name); -+// if (archive_name_size > MZ_UINT16_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - -- if (pState->m_zip64) -- { -- if (pZip->m_total_files == MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -- } -- else -- { -- if (pZip->m_total_files == MZ_UINT16_MAX) -- { -- pState->m_zip64 = MZ_TRUE; -- /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ -- } -- } -+// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - -- archive_name_size = strlen(pArchive_name); -- if (archive_name_size > MZ_UINT16_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); -+// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -+// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -- num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); -+// if (!pState->m_zip64) -+// { -+// /* Bail early if the archive would obviously become too large */ -+// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE -+// + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 -+// + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) -+// { -+// pState->m_zip64 = MZ_TRUE; -+// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -+// } -+// } - -- /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -- if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); -+// #ifndef MINIZ_NO_TIME -+// if (pFile_time) -+// { -+// mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); -+// } -+// #endif - -- if (!pState->m_zip64) -- { -- /* Bail early if the archive would obviously become too large */ -- if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE -- + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 -- + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) -- { -- pState->m_zip64 = MZ_TRUE; -- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -- } -- } -+// if (uncomp_size <= 3) -+// level = 0; - --#ifndef MINIZ_NO_TIME -- if (pFile_time) -- { -- mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); -- } --#endif -+// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) -+// { -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// } - -- if (uncomp_size <= 3) -- level = 0; -+// cur_archive_file_ofs += num_alignment_padding_bytes; -+// local_dir_header_ofs = cur_archive_file_ofs; - -- if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) -- { -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- } -+// if (pZip->m_file_offset_alignment) -+// { -+// MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); -+// } - -- cur_archive_file_ofs += num_alignment_padding_bytes; -- local_dir_header_ofs = cur_archive_file_ofs; -+// if (uncomp_size && level) -+// { -+// method = MZ_DEFLATED; -+// } - -- if (pZip->m_file_offset_alignment) -- { -- MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); -- } -+// MZ_CLEAR_OBJ(local_dir_header); -+// if (pState->m_zip64) -+// { -+// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) -+// { -+// pExtra_data = extra_data; -+// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -+// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -+// } - -- if (uncomp_size && level) -- { -- method = MZ_DEFLATED; -- } -+// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -- MZ_CLEAR_OBJ(local_dir_header); -- if (pState->m_zip64) -- { -- if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) -- { -- pExtra_data = extra_data; -- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -- } -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// cur_archive_file_ofs += sizeof(local_dir_header); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -+// { -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// } - -- cur_archive_file_ofs += sizeof(local_dir_header); -+// cur_archive_file_ofs += archive_name_size; - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -- { -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- } -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- cur_archive_file_ofs += archive_name_size; -+// cur_archive_file_ofs += extra_size; -+// } -+// else -+// { -+// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) -+// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -+// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- cur_archive_file_ofs += extra_size; -- } -- else -- { -- if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) -- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// cur_archive_file_ofs += sizeof(local_dir_header); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -+// { -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// } - -- cur_archive_file_ofs += sizeof(local_dir_header); -+// cur_archive_file_ofs += archive_name_size; -+// } - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -- { -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- } -+// if (user_extra_data_len > 0) -+// { -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- cur_archive_file_ofs += archive_name_size; -- } -+// cur_archive_file_ofs += user_extra_data_len; -+// } - -- if (user_extra_data_len > 0) -- { -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (uncomp_size) -+// { -+// mz_uint64 uncomp_remaining = uncomp_size; -+// void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); -+// if (!pRead_buf) -+// { -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// } - -- cur_archive_file_ofs += user_extra_data_len; -- } -+// if (!level) -+// { -+// while (uncomp_remaining) -+// { -+// mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); -+// if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// } -+// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); -+// uncomp_remaining -= n; -+// cur_archive_file_ofs += n; -+// } -+// comp_size = uncomp_size; -+// } -+// else -+// { -+// mz_bool result = MZ_FALSE; -+// mz_zip_writer_add_state state; -+// tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); -+// if (!pComp) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// } - -- if (uncomp_size) -- { -- mz_uint64 uncomp_remaining = uncomp_size; -- void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); -- if (!pRead_buf) -- { -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- } -+// state.m_pZip = pZip; -+// state.m_cur_archive_file_ofs = cur_archive_file_ofs; -+// state.m_comp_size = 0; - -- if (!level) -- { -- while (uncomp_remaining) -- { -- mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); -- if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -- } -- uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); -- uncomp_remaining -= n; -- cur_archive_file_ofs += n; -- } -- comp_size = uncomp_size; -- } -- else -- { -- mz_bool result = MZ_FALSE; -- mz_zip_writer_add_state state; -- tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); -- if (!pComp) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- } -+// if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// } - -- state.m_pZip = pZip; -- state.m_cur_archive_file_ofs = cur_archive_file_ofs; -- state.m_comp_size = 0; -+// for (;;) -+// { -+// size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -+// tdefl_status status; -+// tdefl_flush flush = TDEFL_NO_FLUSH; - -- if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -- } -+// if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// break; -+// } - -- for (;;) -- { -- size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -- tdefl_status status; -- tdefl_flush flush = TDEFL_NO_FLUSH; -+// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); -+// uncomp_remaining -= in_buf_size; - -- if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) -- { -- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -- break; -- } -+// if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) -+// flush = TDEFL_FULL_FLUSH; - -- uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); -- uncomp_remaining -= in_buf_size; -+// status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); -+// if (status == TDEFL_STATUS_DONE) -+// { -+// result = MZ_TRUE; -+// break; -+// } -+// else if (status != TDEFL_STATUS_OKAY) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); -+// break; -+// } -+// } - -- if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) -- flush = TDEFL_FULL_FLUSH; -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - -- status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); -- if (status == TDEFL_STATUS_DONE) -- { -- result = MZ_TRUE; -- break; -- } -- else if (status != TDEFL_STATUS_OKAY) -- { -- mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); -- break; -- } -- } -+// if (!result) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -+// return MZ_FALSE; -+// } - -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// comp_size = state.m_comp_size; -+// cur_archive_file_ofs = state.m_cur_archive_file_ofs; -+// } - -- if (!result) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -- return MZ_FALSE; -- } -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -+// } - -- comp_size = state.m_comp_size; -- cur_archive_file_ofs = state.m_cur_archive_file_ofs; -- } -+// { -+// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; -+// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; - -- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -- } -+// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); -+// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); -+// if (pExtra_data == NULL) -+// { -+// if (comp_size > MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -- { -- mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; -- mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; -+// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); -+// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); -+// } -+// else -+// { -+// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); -+// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); -+// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; -+// } - -- MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); -- MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); -- if (pExtra_data == NULL) -- { -- if (comp_size > MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) -+// return MZ_FALSE; - -- MZ_WRITE_LE32(local_dir_footer + 8, comp_size); -- MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); -- } -- else -- { -- MZ_WRITE_LE64(local_dir_footer + 8, comp_size); -- MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); -- local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; -- } -+// cur_archive_file_ofs += local_dir_footer_size; -+// } - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) -- return MZ_FALSE; -+// if (pExtra_data != NULL) -+// { -+// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -+// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -+// } - -- cur_archive_file_ofs += local_dir_footer_size; -- } -+// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, -+// uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, -+// user_extra_data_central, user_extra_data_central_len)) -+// return MZ_FALSE; - -- if (pExtra_data != NULL) -- { -- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -- } -+// pZip->m_total_files++; -+// pZip->m_archive_size = cur_archive_file_ofs; - -- if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, -- uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, -- user_extra_data_central, user_extra_data_central_len)) -- return MZ_FALSE; -+// return MZ_TRUE; -+// } - -- pZip->m_total_files++; -- pZip->m_archive_size = cur_archive_file_ofs; -+// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -+// { -+// MZ_FILE *pSrc_file = NULL; -+// mz_uint64 uncomp_size = 0; -+// MZ_TIME_T file_modified_time; -+// MZ_TIME_T *pFile_time = NULL; -+// mz_bool status; - -- return MZ_TRUE; --} -+// memset(&file_modified_time, 0, sizeof(file_modified_time)); - --mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) --{ -- MZ_FILE *pSrc_file = NULL; -- mz_uint64 uncomp_size = 0; -- MZ_TIME_T file_modified_time; -- MZ_TIME_T *pFile_time = NULL; -- mz_bool status; -- -- memset(&file_modified_time, 0, sizeof(file_modified_time)); -- --#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) -- pFile_time = &file_modified_time; -- if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); --#endif -+// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) -+// pFile_time = &file_modified_time; -+// if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); -+// #endif - -- pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); -- if (!pSrc_file) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -+// pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); -+// if (!pSrc_file) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -- MZ_FSEEK64(pSrc_file, 0, SEEK_END); -- uncomp_size = MZ_FTELL64(pSrc_file); -- MZ_FSEEK64(pSrc_file, 0, SEEK_SET); -+// MZ_FSEEK64(pSrc_file, 0, SEEK_END); -+// uncomp_size = MZ_FTELL64(pSrc_file); -+// MZ_FSEEK64(pSrc_file, 0, SEEK_SET); - -- status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); -+// status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); - -- MZ_FCLOSE(pSrc_file); -+// MZ_FCLOSE(pSrc_file); - -- return status; --} --#endif /* #ifndef MINIZ_NO_STDIO */ -+// return status; -+// } -+// #endif /* #ifndef MINIZ_NO_STDIO */ - - // static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) - // { -@@ -7083,491 +7082,491 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, - // return MZ_TRUE; - // } - --mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) --{ -- mz_zip_internal_state *pState; -- mz_uint64 central_dir_ofs, central_dir_size; -- mz_uint8 hdr[256]; -+// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) -+// { -+// mz_zip_internal_state *pState; -+// mz_uint64 central_dir_ofs, central_dir_size; -+// mz_uint8 hdr[256]; - -- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- pState = pZip->m_pState; -+// pState = pZip->m_pState; - -- if (pState->m_zip64) -- { -- if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -- } -- else -- { -- if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -- } -+// if (pState->m_zip64) -+// { -+// if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// } -+// else -+// { -+// if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// } - -- central_dir_ofs = 0; -- central_dir_size = 0; -- if (pZip->m_total_files) -- { -- /* Write central directory */ -- central_dir_ofs = pZip->m_archive_size; -- central_dir_size = pState->m_central_dir.m_size; -- pZip->m_central_directory_file_ofs = central_dir_ofs; -- if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- -- pZip->m_archive_size += central_dir_size; -- } -+// central_dir_ofs = 0; -+// central_dir_size = 0; -+// if (pZip->m_total_files) -+// { -+// /* Write central directory */ -+// central_dir_ofs = pZip->m_archive_size; -+// central_dir_size = pState->m_central_dir.m_size; -+// pZip->m_central_directory_file_ofs = central_dir_ofs; -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- if (pState->m_zip64) -- { -- /* Write zip64 end of central directory header */ -- mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; -- -- MZ_CLEAR_OBJ(hdr); -- MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); -- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); -- MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ -- MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); -- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); -- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); -- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); -- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); -- if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- -- pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; -- -- /* Write zip64 end of central directory locator */ -- MZ_CLEAR_OBJ(hdr); -- MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); -- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); -- MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); -- if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- -- pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; -- } -+// pZip->m_archive_size += central_dir_size; -+// } - -- /* Write end of central directory record */ -- MZ_CLEAR_OBJ(hdr); -- MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); -- MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); -- MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); -- MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); -- MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); -+// if (pState->m_zip64) -+// { -+// /* Write zip64 end of central directory header */ -+// mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; -+ -+// MZ_CLEAR_OBJ(hdr); -+// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); -+// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); -+// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ -+// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); -+// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); -+// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); -+// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); -+// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; - --#ifndef MINIZ_NO_STDIO -- if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); --#endif /* #ifndef MINIZ_NO_STDIO */ -+// /* Write zip64 end of central directory locator */ -+// MZ_CLEAR_OBJ(hdr); -+// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); -+// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); -+// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; -+// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; -+// } - -- pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; -- return MZ_TRUE; --} -+// /* Write end of central directory record */ -+// MZ_CLEAR_OBJ(hdr); -+// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); -+// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); -+// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); -+// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); -+// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); - --mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) --{ -- if ((!ppBuf) || (!pSize)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- *ppBuf = NULL; -- *pSize = 0; -+// #ifndef MINIZ_NO_STDIO -+// if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); -+// #endif /* #ifndef MINIZ_NO_STDIO */ - -- if ((!pZip) || (!pZip->m_pState)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; - -- if (pZip->m_pWrite != mz_zip_heap_write_func) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; -+// return MZ_TRUE; -+// } - -- if (!mz_zip_writer_finalize_archive(pZip)) -- return MZ_FALSE; -+// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) -+// { -+// if ((!ppBuf) || (!pSize)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- *ppBuf = pZip->m_pState->m_pMem; -- *pSize = pZip->m_pState->m_mem_size; -- pZip->m_pState->m_pMem = NULL; -- pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; -+// *ppBuf = NULL; -+// *pSize = 0; - -- return MZ_TRUE; --} -+// if ((!pZip) || (!pZip->m_pState)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - --mz_bool mz_zip_writer_end(mz_zip_archive *pZip) --{ -- return mz_zip_writer_end_internal(pZip, MZ_TRUE); --} -+// if (pZip->m_pWrite != mz_zip_heap_write_func) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - --#ifndef MINIZ_NO_STDIO --mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) --{ -- return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); --} -+// if (!mz_zip_writer_finalize_archive(pZip)) -+// return MZ_FALSE; - --mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) --{ -- mz_bool status, created_new_archive = MZ_FALSE; -- mz_zip_archive zip_archive; -- struct MZ_FILE_STAT_STRUCT file_stat; -- mz_zip_error actual_err = MZ_ZIP_NO_ERROR; -+// *ppBuf = pZip->m_pState->m_pMem; -+// *pSize = pZip->m_pState->m_mem_size; -+// pZip->m_pState->m_pMem = NULL; -+// pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; - -- mz_zip_zero_struct(&zip_archive); -- if ((int)level_and_flags < 0) -- level_and_flags = MZ_DEFAULT_LEVEL; -+// return MZ_TRUE; -+// } - -- if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) -- { -- if (pErr) -- *pErr = MZ_ZIP_INVALID_PARAMETER; -- return MZ_FALSE; -- } -+// mz_bool mz_zip_writer_end(mz_zip_archive *pZip) -+// { -+// return mz_zip_writer_end_internal(pZip, MZ_TRUE); -+// } - -- if (!mz_zip_writer_validate_archive_name(pArchive_name)) -- { -- if (pErr) -- *pErr = MZ_ZIP_INVALID_FILENAME; -- return MZ_FALSE; -- } -+// #ifndef MINIZ_NO_STDIO -+// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -+// { -+// return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); -+// } - -- /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ -- /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ -- if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) -- { -- /* Create a new archive. */ -- if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) -- { -- if (pErr) -- *pErr = zip_archive.m_last_error; -- return MZ_FALSE; -- } -+// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) -+// { -+// mz_bool status, created_new_archive = MZ_FALSE; -+// mz_zip_archive zip_archive; -+// struct MZ_FILE_STAT_STRUCT file_stat; -+// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; - -- created_new_archive = MZ_TRUE; -- } -- else -- { -- /* Append to an existing archive. */ -- if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) -- { -- if (pErr) -- *pErr = zip_archive.m_last_error; -- return MZ_FALSE; -- } -+// mz_zip_zero_struct(&zip_archive); -+// if ((int)level_and_flags < 0) -+// level_and_flags = MZ_DEFAULT_LEVEL; - -- if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) -- { -- if (pErr) -- *pErr = zip_archive.m_last_error; -+// if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) -+// { -+// if (pErr) -+// *pErr = MZ_ZIP_INVALID_PARAMETER; -+// return MZ_FALSE; -+// } - -- mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); -+// if (!mz_zip_writer_validate_archive_name(pArchive_name)) -+// { -+// if (pErr) -+// *pErr = MZ_ZIP_INVALID_FILENAME; -+// return MZ_FALSE; -+// } - -- return MZ_FALSE; -- } -- } -+// /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ -+// /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ -+// if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) -+// { -+// /* Create a new archive. */ -+// if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) -+// { -+// if (pErr) -+// *pErr = zip_archive.m_last_error; -+// return MZ_FALSE; -+// } - -- status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); -- actual_err = zip_archive.m_last_error; -+// created_new_archive = MZ_TRUE; -+// } -+// else -+// { -+// /* Append to an existing archive. */ -+// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) -+// { -+// if (pErr) -+// *pErr = zip_archive.m_last_error; -+// return MZ_FALSE; -+// } - -- /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ -- if (!mz_zip_writer_finalize_archive(&zip_archive)) -- { -- if (!actual_err) -- actual_err = zip_archive.m_last_error; -+// if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) -+// { -+// if (pErr) -+// *pErr = zip_archive.m_last_error; - -- status = MZ_FALSE; -- } -+// mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); - -- if (!mz_zip_writer_end_internal(&zip_archive, status)) -- { -- if (!actual_err) -- actual_err = zip_archive.m_last_error; -+// return MZ_FALSE; -+// } -+// } - -- status = MZ_FALSE; -- } -+// status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); -+// actual_err = zip_archive.m_last_error; - -- if ((!status) && (created_new_archive)) -- { -- /* It's a new archive and something went wrong, so just delete it. */ -- int ignoredStatus = MZ_DELETE_FILE(pZip_filename); -- (void)ignoredStatus; -- } -+// /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ -+// if (!mz_zip_writer_finalize_archive(&zip_archive)) -+// { -+// if (!actual_err) -+// actual_err = zip_archive.m_last_error; - -- if (pErr) -- *pErr = actual_err; -+// status = MZ_FALSE; -+// } - -- return status; --} -+// if (!mz_zip_writer_end_internal(&zip_archive, status)) -+// { -+// if (!actual_err) -+// actual_err = zip_archive.m_last_error; - --void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) --{ -- mz_uint32 file_index; -- mz_zip_archive zip_archive; -- void *p = NULL; -+// status = MZ_FALSE; -+// } - -- if (pSize) -- *pSize = 0; -+// if ((!status) && (created_new_archive)) -+// { -+// /* It's a new archive and something went wrong, so just delete it. */ -+// int ignoredStatus = MZ_DELETE_FILE(pZip_filename); -+// (void)ignoredStatus; -+// } - -- if ((!pZip_filename) || (!pArchive_name)) -- { -- if (pErr) -- *pErr = MZ_ZIP_INVALID_PARAMETER; -+// if (pErr) -+// *pErr = actual_err; - -- return NULL; -- } -+// return status; -+// } - -- mz_zip_zero_struct(&zip_archive); -- if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) -- { -- if (pErr) -- *pErr = zip_archive.m_last_error; -+// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) -+// { -+// mz_uint32 file_index; -+// mz_zip_archive zip_archive; -+// void *p = NULL; - -- return NULL; -- } -+// if (pSize) -+// *pSize = 0; - -- if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) -- { -- p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); -- } -+// if ((!pZip_filename) || (!pArchive_name)) -+// { -+// if (pErr) -+// *pErr = MZ_ZIP_INVALID_PARAMETER; - -- mz_zip_reader_end_internal(&zip_archive, p != NULL); -+// return NULL; -+// } - -- if (pErr) -- *pErr = zip_archive.m_last_error; -+// mz_zip_zero_struct(&zip_archive); -+// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) -+// { -+// if (pErr) -+// *pErr = zip_archive.m_last_error; - -- return p; --} -+// return NULL; -+// } - --void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) --{ -- return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); --} -+// if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) -+// { -+// p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); -+// } -+ -+// mz_zip_reader_end_internal(&zip_archive, p != NULL); -+ -+// if (pErr) -+// *pErr = zip_archive.m_last_error; -+ -+// return p; -+// } -+ -+// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) -+// { -+// return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); -+// } - --#endif /* #ifndef MINIZ_NO_STDIO */ -+// #endif /* #ifndef MINIZ_NO_STDIO */ - --#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ -+// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ - - /* ------------------- Misc utils */ - --mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) --{ -- return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; --} -+// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) -+// { -+// return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; -+// } - --mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) --{ -- return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; --} -+// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) -+// { -+// return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; -+// } - --mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) --{ -- mz_zip_error prev_err; -+// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) -+// { -+// mz_zip_error prev_err; - -- if (!pZip) -- return MZ_ZIP_INVALID_PARAMETER; -+// if (!pZip) -+// return MZ_ZIP_INVALID_PARAMETER; - -- prev_err = pZip->m_last_error; -+// prev_err = pZip->m_last_error; - -- pZip->m_last_error = err_num; -- return prev_err; --} -+// pZip->m_last_error = err_num; -+// return prev_err; -+// } - --mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) --{ -- if (!pZip) -- return MZ_ZIP_INVALID_PARAMETER; -+// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) -+// { -+// if (!pZip) -+// return MZ_ZIP_INVALID_PARAMETER; - -- return pZip->m_last_error; --} -+// return pZip->m_last_error; -+// } - --mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) --{ -- return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); --} -+// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) -+// { -+// return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); -+// } - --mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) --{ -- mz_zip_error prev_err; -+// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) -+// { -+// mz_zip_error prev_err; - -- if (!pZip) -- return MZ_ZIP_INVALID_PARAMETER; -+// if (!pZip) -+// return MZ_ZIP_INVALID_PARAMETER; - -- prev_err = pZip->m_last_error; -+// prev_err = pZip->m_last_error; - -- pZip->m_last_error = MZ_ZIP_NO_ERROR; -- return prev_err; --} -+// pZip->m_last_error = MZ_ZIP_NO_ERROR; -+// return prev_err; -+// } - --const char *mz_zip_get_error_string(mz_zip_error mz_err) --{ -- switch (mz_err) -- { -- case MZ_ZIP_NO_ERROR: -- return "no error"; -- case MZ_ZIP_UNDEFINED_ERROR: -- return "undefined error"; -- case MZ_ZIP_TOO_MANY_FILES: -- return "too many files"; -- case MZ_ZIP_FILE_TOO_LARGE: -- return "file too large"; -- case MZ_ZIP_UNSUPPORTED_METHOD: -- return "unsupported method"; -- case MZ_ZIP_UNSUPPORTED_ENCRYPTION: -- return "unsupported encryption"; -- case MZ_ZIP_UNSUPPORTED_FEATURE: -- return "unsupported feature"; -- case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: -- return "failed finding central directory"; -- case MZ_ZIP_NOT_AN_ARCHIVE: -- return "not a ZIP archive"; -- case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: -- return "invalid header or archive is corrupted"; -- case MZ_ZIP_UNSUPPORTED_MULTIDISK: -- return "unsupported multidisk archive"; -- case MZ_ZIP_DECOMPRESSION_FAILED: -- return "decompression failed or archive is corrupted"; -- case MZ_ZIP_COMPRESSION_FAILED: -- return "compression failed"; -- case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: -- return "unexpected decompressed size"; -- case MZ_ZIP_CRC_CHECK_FAILED: -- return "CRC-32 check failed"; -- case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: -- return "unsupported central directory size"; -- case MZ_ZIP_ALLOC_FAILED: -- return "allocation failed"; -- case MZ_ZIP_FILE_OPEN_FAILED: -- return "file open failed"; -- case MZ_ZIP_FILE_CREATE_FAILED: -- return "file create failed"; -- case MZ_ZIP_FILE_WRITE_FAILED: -- return "file write failed"; -- case MZ_ZIP_FILE_READ_FAILED: -- return "file read failed"; -- case MZ_ZIP_FILE_CLOSE_FAILED: -- return "file close failed"; -- case MZ_ZIP_FILE_SEEK_FAILED: -- return "file seek failed"; -- case MZ_ZIP_FILE_STAT_FAILED: -- return "file stat failed"; -- case MZ_ZIP_INVALID_PARAMETER: -- return "invalid parameter"; -- case MZ_ZIP_INVALID_FILENAME: -- return "invalid filename"; -- case MZ_ZIP_BUF_TOO_SMALL: -- return "buffer too small"; -- case MZ_ZIP_INTERNAL_ERROR: -- return "internal error"; -- case MZ_ZIP_FILE_NOT_FOUND: -- return "file not found"; -- case MZ_ZIP_ARCHIVE_TOO_LARGE: -- return "archive is too large"; -- case MZ_ZIP_VALIDATION_FAILED: -- return "validation failed"; -- case MZ_ZIP_WRITE_CALLBACK_FAILED: -- return "write calledback failed"; -- default: -- break; -- } -+// const char *mz_zip_get_error_string(mz_zip_error mz_err) -+// { -+// switch (mz_err) -+// { -+// case MZ_ZIP_NO_ERROR: -+// return "no error"; -+// case MZ_ZIP_UNDEFINED_ERROR: -+// return "undefined error"; -+// case MZ_ZIP_TOO_MANY_FILES: -+// return "too many files"; -+// case MZ_ZIP_FILE_TOO_LARGE: -+// return "file too large"; -+// case MZ_ZIP_UNSUPPORTED_METHOD: -+// return "unsupported method"; -+// case MZ_ZIP_UNSUPPORTED_ENCRYPTION: -+// return "unsupported encryption"; -+// case MZ_ZIP_UNSUPPORTED_FEATURE: -+// return "unsupported feature"; -+// case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: -+// return "failed finding central directory"; -+// case MZ_ZIP_NOT_AN_ARCHIVE: -+// return "not a ZIP archive"; -+// case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: -+// return "invalid header or archive is corrupted"; -+// case MZ_ZIP_UNSUPPORTED_MULTIDISK: -+// return "unsupported multidisk archive"; -+// case MZ_ZIP_DECOMPRESSION_FAILED: -+// return "decompression failed or archive is corrupted"; -+// case MZ_ZIP_COMPRESSION_FAILED: -+// return "compression failed"; -+// case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: -+// return "unexpected decompressed size"; -+// case MZ_ZIP_CRC_CHECK_FAILED: -+// return "CRC-32 check failed"; -+// case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: -+// return "unsupported central directory size"; -+// case MZ_ZIP_ALLOC_FAILED: -+// return "allocation failed"; -+// case MZ_ZIP_FILE_OPEN_FAILED: -+// return "file open failed"; -+// case MZ_ZIP_FILE_CREATE_FAILED: -+// return "file create failed"; -+// case MZ_ZIP_FILE_WRITE_FAILED: -+// return "file write failed"; -+// case MZ_ZIP_FILE_READ_FAILED: -+// return "file read failed"; -+// case MZ_ZIP_FILE_CLOSE_FAILED: -+// return "file close failed"; -+// case MZ_ZIP_FILE_SEEK_FAILED: -+// return "file seek failed"; -+// case MZ_ZIP_FILE_STAT_FAILED: -+// return "file stat failed"; -+// case MZ_ZIP_INVALID_PARAMETER: -+// return "invalid parameter"; -+// case MZ_ZIP_INVALID_FILENAME: -+// return "invalid filename"; -+// case MZ_ZIP_BUF_TOO_SMALL: -+// return "buffer too small"; -+// case MZ_ZIP_INTERNAL_ERROR: -+// return "internal error"; -+// case MZ_ZIP_FILE_NOT_FOUND: -+// return "file not found"; -+// case MZ_ZIP_ARCHIVE_TOO_LARGE: -+// return "archive is too large"; -+// case MZ_ZIP_VALIDATION_FAILED: -+// return "validation failed"; -+// case MZ_ZIP_WRITE_CALLBACK_FAILED: -+// return "write calledback failed"; -+// default: -+// break; -+// } - -- return "unknown error"; --} -+// return "unknown error"; -+// } - - /* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */ --mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) --{ -- if ((!pZip) || (!pZip->m_pState)) -- return MZ_FALSE; -+// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) -+// { -+// if ((!pZip) || (!pZip->m_pState)) -+// return MZ_FALSE; - -- return pZip->m_pState->m_zip64; --} -+// return pZip->m_pState->m_zip64; -+// } - --size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) --{ -- if ((!pZip) || (!pZip->m_pState)) -- return 0; -+// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) -+// { -+// if ((!pZip) || (!pZip->m_pState)) -+// return 0; - -- return pZip->m_pState->m_central_dir.m_size; --} -+// return pZip->m_pState->m_central_dir.m_size; -+// } - --mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) --{ -- return pZip ? pZip->m_total_files : 0; --} -+// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) -+// { -+// return pZip ? pZip->m_total_files : 0; -+// } - --mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) --{ -- if (!pZip) -- return 0; -- return pZip->m_archive_size; --} -+// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) -+// { -+// if (!pZip) -+// return 0; -+// return pZip->m_archive_size; -+// } - --mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) --{ -- if ((!pZip) || (!pZip->m_pState)) -- return 0; -- return pZip->m_pState->m_file_archive_start_ofs; --} -+// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) -+// { -+// if ((!pZip) || (!pZip->m_pState)) -+// return 0; -+// return pZip->m_pState->m_file_archive_start_ofs; -+// } - --MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) --{ -- if ((!pZip) || (!pZip->m_pState)) -- return 0; -- return pZip->m_pState->m_pFile; --} -+// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) -+// { -+// if ((!pZip) || (!pZip->m_pState)) -+// return 0; -+// return pZip->m_pState->m_pFile; -+// } - --size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) --{ -- if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) -+// { -+// if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); --} -+// return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); -+// } - --mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) --{ -- mz_uint n; -- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -- if (!p) -- { -- if (filename_buf_size) -- pFilename[0] = '\0'; -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- return 0; -- } -- n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -- if (filename_buf_size) -- { -- n = MZ_MIN(n, filename_buf_size - 1); -- memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); -- pFilename[n] = '\0'; -- } -- return n + 1; --} -+// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) -+// { -+// mz_uint n; -+// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -+// if (!p) -+// { -+// if (filename_buf_size) -+// pFilename[0] = '\0'; -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return 0; -+// } -+// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// if (filename_buf_size) -+// { -+// n = MZ_MIN(n, filename_buf_size - 1); -+// memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); -+// pFilename[n] = '\0'; -+// } -+// return n + 1; -+// } - --mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) --{ -- return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); --} -+// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) -+// { -+// return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); -+// } - --mz_bool mz_zip_end(mz_zip_archive *pZip) --{ -- if (!pZip) -- return MZ_FALSE; -- -- if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) -- return mz_zip_reader_end(pZip); --#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -- else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) -- return mz_zip_writer_end(pZip); --#endif -+// mz_bool mz_zip_end(mz_zip_archive *pZip) -+// { -+// if (!pZip) -+// return MZ_FALSE; - -- return MZ_FALSE; --} -+// if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) -+// return mz_zip_reader_end(pZip); -+// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -+// else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) -+// return mz_zip_writer_end(pZip); -+// #endif - --#ifdef __cplusplus --} --#endif -+// return MZ_FALSE; -+// } -+ -+// #ifdef __cplusplus -+// } -+// #endif - --#endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ -+// #endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ diff --git a/gomspace/libutil/src/zip/miniz/miniz.c b/gomspace/libutil/src/zip/miniz/miniz.c deleted file mode 100644 index 910d4b1f..00000000 --- a/gomspace/libutil/src/zip/miniz/miniz.c +++ /dev/null @@ -1,7572 +0,0 @@ -/************************************************************************** - * - * Copyright 2013-2014 RAD Game Tools and Valve Software - * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ - -#include "miniz.h" - -typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; -typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; -typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------- zlib-style API's */ - -mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) -{ - mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); - size_t block_len = buf_len % 5552; - if (!ptr) - return MZ_ADLER32_INIT; - while (buf_len) - { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) - { - s1 += ptr[0], s2 += s1; - s1 += ptr[1], s2 += s1; - s1 += ptr[2], s2 += s1; - s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; - s1 += ptr[5], s2 += s1; - s1 += ptr[6], s2 += s1; - s1 += ptr[7], s2 += s1; - } - for (; i < block_len; ++i) - s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; - buf_len -= block_len; - block_len = 5552; - } - return (s2 << 16) + s1; -} - -/* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */ -// #if 0 -// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) -// { -// static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, -// 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; -// mz_uint32 crcu32 = (mz_uint32)crc; -// if (!ptr) -// return MZ_CRC32_INIT; -// crcu32 = ~crcu32; -// while (buf_len--) -// { -// mz_uint8 b = *ptr++; -// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; -// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; -// } -// return ~crcu32; -// } -// #else -/* Faster, but larger CPU cache footprint. - */ -// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) -// { -// static const mz_uint32 s_crc_table[256] = -// { -// 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, -// 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, -// 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, -// 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, -// 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, -// 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, -// 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, -// 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, -// 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, -// 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, -// 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, -// 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, -// 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, -// 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, -// 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, -// 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, -// 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, -// 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, -// 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, -// 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, -// 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, -// 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, -// 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, -// 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, -// 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, -// 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, -// 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, -// 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, -// 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, -// 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, -// 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, -// 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, -// 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, -// 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, -// 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, -// 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, -// 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -// }; - -// mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; -// const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; - -// while (buf_len >= 4) -// { -// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; -// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; -// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; -// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; -// pByte_buf += 4; -// buf_len -= 4; -// } - -// while (buf_len) -// { -// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; -// ++pByte_buf; -// --buf_len; -// } - -// return ~crc32; -// } -// #endif - -void mz_free(void *p) -{ - MZ_FREE(p); -} - -void *miniz_def_alloc_func(void *opaque, size_t items, size_t size) -{ - (void)opaque, (void)items, (void)size; - return MZ_MALLOC(items * size); -} -void miniz_def_free_func(void *opaque, void *address) -{ - (void)opaque, (void)address; - MZ_FREE(address); -} -// void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) -// { -// (void)opaque, (void)address, (void)items, (void)size; -// return MZ_REALLOC(address, items * size); -// } - -// const char *mz_version(void) -// { -// return MZ_VERSION; -// } - -#ifndef MINIZ_NO_ZLIB_APIS - -int mz_deflateInit(mz_streamp pStream, int level) -{ - return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); -} - -int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) -{ - tdefl_compressor *pComp; - mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); - - if (!pStream) - return MZ_STREAM_ERROR; - if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) - return MZ_PARAM_ERROR; - - pStream->data_type = 0; - pStream->adler = MZ_ADLER32_INIT; - pStream->msg = NULL; - pStream->reserved = 0; - pStream->total_in = 0; - pStream->total_out = 0; - if (!pStream->zalloc) - pStream->zalloc = miniz_def_alloc_func; - if (!pStream->zfree) - pStream->zfree = miniz_def_free_func; - - pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); - if (!pComp) - return MZ_MEM_ERROR; - - pStream->state = (struct mz_internal_state *)pComp; - - if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) - { - mz_deflateEnd(pStream); - return MZ_PARAM_ERROR; - } - - return MZ_OK; -} - -// int mz_deflateReset(mz_streamp pStream) -// { -// if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) -// return MZ_STREAM_ERROR; -// pStream->total_in = pStream->total_out = 0; -// tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); -// return MZ_OK; -// } - -int mz_deflate(mz_streamp pStream, int flush) -{ - size_t in_bytes, out_bytes; - mz_ulong orig_total_in, orig_total_out; - int mz_status = MZ_OK; - - if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) - return MZ_STREAM_ERROR; - if (!pStream->avail_out) - return MZ_BUF_ERROR; - - if (flush == MZ_PARTIAL_FLUSH) - flush = MZ_SYNC_FLUSH; - - if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) - return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; - - orig_total_in = pStream->total_in; - orig_total_out = pStream->total_out; - for (;;) - { - tdefl_status defl_status; - in_bytes = pStream->avail_in; - out_bytes = pStream->avail_out; - - defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); - pStream->next_in += (mz_uint)in_bytes; - pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; - pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); - - pStream->next_out += (mz_uint)out_bytes; - pStream->avail_out -= (mz_uint)out_bytes; - pStream->total_out += (mz_uint)out_bytes; - - if (defl_status < 0) - { - mz_status = MZ_STREAM_ERROR; - break; - } - else if (defl_status == TDEFL_STATUS_DONE) - { - mz_status = MZ_STREAM_END; - break; - } - else if (!pStream->avail_out) - break; - else if ((!pStream->avail_in) && (flush != MZ_FINISH)) - { - if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) - break; - return MZ_BUF_ERROR; /* Can't make forward progress without some input. - */ - } - } - return mz_status; -} - -int mz_deflateEnd(mz_streamp pStream) -{ - if (!pStream) - return MZ_STREAM_ERROR; - if (pStream->state) - { - pStream->zfree(pStream->opaque, pStream->state); - pStream->state = NULL; - } - return MZ_OK; -} - -// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) -// { -// (void)pStream; -// This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) -// return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); -// } - -int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) -{ - int status; - mz_stream stream; - memset(&stream, 0, sizeof(stream)); - - /* In case mz_ulong is 64-bits (argh I hate longs). */ - if ((source_len | *pDest_len) > 0xFFFFFFFFU) - return MZ_PARAM_ERROR; - - stream.next_in = pSource; - stream.avail_in = (mz_uint32)source_len; - stream.next_out = pDest; - stream.avail_out = (mz_uint32)*pDest_len; - - status = mz_deflateInit(&stream, level); - if (status != MZ_OK) - return status; - - status = mz_deflate(&stream, MZ_FINISH); - if (status != MZ_STREAM_END) - { - mz_deflateEnd(&stream); - return (status == MZ_OK) ? MZ_BUF_ERROR : status; - } - - *pDest_len = stream.total_out; - return mz_deflateEnd(&stream); -} - -int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) -{ - return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); -} - -// mz_ulong mz_compressBound(mz_ulong source_len) -// { -// return mz_deflateBound(NULL, source_len); -// } - -typedef struct -{ - tinfl_decompressor m_decomp; - mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; - int m_window_bits; - mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; - tinfl_status m_last_status; -} inflate_state; - -int mz_inflateInit2(mz_streamp pStream, int window_bits) -{ - inflate_state *pDecomp; - if (!pStream) - return MZ_STREAM_ERROR; - if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) - return MZ_PARAM_ERROR; - - pStream->data_type = 0; - pStream->adler = 0; - pStream->msg = NULL; - pStream->total_in = 0; - pStream->total_out = 0; - pStream->reserved = 0; - if (!pStream->zalloc) - pStream->zalloc = miniz_def_alloc_func; - if (!pStream->zfree) - pStream->zfree = miniz_def_free_func; - - pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); - if (!pDecomp) - return MZ_MEM_ERROR; - - pStream->state = (struct mz_internal_state *)pDecomp; - - tinfl_init(&pDecomp->m_decomp); - pDecomp->m_dict_ofs = 0; - pDecomp->m_dict_avail = 0; - pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; - pDecomp->m_first_call = 1; - pDecomp->m_has_flushed = 0; - pDecomp->m_window_bits = window_bits; - - return MZ_OK; -} - -int mz_inflateInit(mz_streamp pStream) -{ - return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); -} - -int mz_inflate(mz_streamp pStream, int flush) -{ - inflate_state *pState; - mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; - size_t in_bytes, out_bytes, orig_avail_in; - tinfl_status status; - - if ((!pStream) || (!pStream->state)) - return MZ_STREAM_ERROR; - if (flush == MZ_PARTIAL_FLUSH) - flush = MZ_SYNC_FLUSH; - if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) - return MZ_STREAM_ERROR; - - pState = (inflate_state *)pStream->state; - if (pState->m_window_bits > 0) - decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; - orig_avail_in = pStream->avail_in; - - first_call = pState->m_first_call; - pState->m_first_call = 0; - if (pState->m_last_status < 0) - return MZ_DATA_ERROR; - - if (pState->m_has_flushed && (flush != MZ_FINISH)) - return MZ_STREAM_ERROR; - pState->m_has_flushed |= (flush == MZ_FINISH); - - if ((flush == MZ_FINISH) && (first_call)) - { - /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */ - decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - in_bytes = pStream->avail_in; - out_bytes = pStream->avail_out; - status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); - pState->m_last_status = status; - pStream->next_in += (mz_uint)in_bytes; - pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; - pStream->adler = tinfl_get_adler32(&pState->m_decomp); - pStream->next_out += (mz_uint)out_bytes; - pStream->avail_out -= (mz_uint)out_bytes; - pStream->total_out += (mz_uint)out_bytes; - - if (status < 0) - return MZ_DATA_ERROR; - else if (status != TINFL_STATUS_DONE) - { - pState->m_last_status = TINFL_STATUS_FAILED; - return MZ_BUF_ERROR; - } - return MZ_STREAM_END; - } - /* flush != MZ_FINISH then we must assume there's more input. */ - if (flush != MZ_FINISH) - decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; - - if (pState->m_dict_avail) - { - n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); - memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); - pStream->next_out += n; - pStream->avail_out -= n; - pStream->total_out += n; - pState->m_dict_avail -= n; - pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); - return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; - } - - for (;;) - { - in_bytes = pStream->avail_in; - out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; - - status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); - pState->m_last_status = status; - - pStream->next_in += (mz_uint)in_bytes; - pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; - pStream->adler = tinfl_get_adler32(&pState->m_decomp); - - pState->m_dict_avail = (mz_uint)out_bytes; - - n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); - memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); - pStream->next_out += n; - pStream->avail_out -= n; - pStream->total_out += n; - pState->m_dict_avail -= n; - pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); - - if (status < 0) - return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */ - else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) - return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */ - else if (flush == MZ_FINISH) - { - /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */ - if (status == TINFL_STATUS_DONE) - return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; - /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */ - else if (!pStream->avail_out) - return MZ_BUF_ERROR; - } - else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) - break; - } - - return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; -} - -int mz_inflateEnd(mz_streamp pStream) -{ - if (!pStream) - return MZ_STREAM_ERROR; - if (pStream->state) - { - pStream->zfree(pStream->opaque, pStream->state); - pStream->state = NULL; - } - return MZ_OK; -} - -int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) -{ - mz_stream stream; - int status; - memset(&stream, 0, sizeof(stream)); - - /* In case mz_ulong is 64-bits (argh I hate longs). */ - if ((source_len | *pDest_len) > 0xFFFFFFFFU) - return MZ_PARAM_ERROR; - - stream.next_in = pSource; - stream.avail_in = (mz_uint32)source_len; - stream.next_out = pDest; - stream.avail_out = (mz_uint32)*pDest_len; - - status = mz_inflateInit(&stream); - if (status != MZ_OK) - return status; - - status = mz_inflate(&stream, MZ_FINISH); - if (status != MZ_STREAM_END) - { - mz_inflateEnd(&stream); - return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; - } - *pDest_len = stream.total_out; - - return mz_inflateEnd(&stream); -} - -// const char *mz_error(int err) -// { -// static struct -// { -// int m_err; -// const char *m_pDesc; -// } s_error_descs[] = -// { -// { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } -// }; -// mz_uint i; -// for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) -// if (s_error_descs[i].m_err == err) -// return s_error_descs[i].m_pDesc; -// return NULL; -// } - -#endif /*MINIZ_NO_ZLIB_APIS */ - -#ifdef __cplusplus -} -#endif - -/* - This is free and unencumbered software released into the public domain. - - Anyone is free to copy, modify, publish, use, compile, sell, or - distribute this software, either in source code form or as a compiled - binary, for any purpose, commercial or non-commercial, and by any - means. - - In jurisdictions that recognize copyright laws, the author or authors - of this software dedicate any and all copyright interest in the - software to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and - successors. We intend this dedication to be an overt act of - relinquishment in perpetuity of all present and future rights to this - software under copyright law. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - For more information, please refer to -*/ -/************************************************************************** - * - * Copyright 2013-2014 RAD Game Tools and Valve Software - * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ - - - - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------- Low-level Compression (independent from all decompression API's) */ - -/* Purposely making these tables static for faster init and thread safety. */ -static const mz_uint16 s_tdefl_len_sym[256] = - { - 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, - 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, - 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, - 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, - 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285 - }; - -static const mz_uint8 s_tdefl_len_extra[256] = - { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 - }; - -static const mz_uint8 s_tdefl_small_dist_sym[512] = - { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 - }; - -static const mz_uint8 s_tdefl_small_dist_extra[512] = - { - 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7 - }; - -static const mz_uint8 s_tdefl_large_dist_sym[128] = - { - 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 - }; - -static const mz_uint8 s_tdefl_large_dist_extra[128] = - { - 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 - }; - -/* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. */ -typedef struct -{ - mz_uint16 m_key, m_sym_index; -} tdefl_sym_freq; -static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) -{ - mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; - tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; - MZ_CLEAR_OBJ(hist); - for (i = 0; i < num_syms; i++) - { - mz_uint freq = pSyms0[i].m_key; - hist[freq & 0xFF]++; - hist[256 + ((freq >> 8) & 0xFF)]++; - } - while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) - total_passes--; - for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) - { - const mz_uint32 *pHist = &hist[pass << 8]; - mz_uint offsets[256], cur_ofs = 0; - for (i = 0; i < 256; i++) - { - offsets[i] = cur_ofs; - cur_ofs += pHist[i]; - } - for (i = 0; i < num_syms; i++) - pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; - { - tdefl_sym_freq *t = pCur_syms; - pCur_syms = pNew_syms; - pNew_syms = t; - } - } - return pCur_syms; -} - -/* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */ -static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) -{ - int root, leaf, next, avbl, used, dpth; - if (n == 0) - return; - else if (n == 1) - { - A[0].m_key = 1; - return; - } - A[0].m_key += A[1].m_key; - root = 0; - leaf = 2; - for (next = 1; next < n - 1; next++) - { - if (leaf >= n || A[root].m_key < A[leaf].m_key) - { - A[next].m_key = A[root].m_key; - A[root++].m_key = (mz_uint16)next; - } - else - A[next].m_key = A[leaf++].m_key; - if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) - { - A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); - A[root++].m_key = (mz_uint16)next; - } - else - A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); - } - A[n - 2].m_key = 0; - for (next = n - 3; next >= 0; next--) - A[next].m_key = A[A[next].m_key].m_key + 1; - avbl = 1; - used = dpth = 0; - root = n - 2; - next = n - 1; - while (avbl > 0) - { - while (root >= 0 && (int)A[root].m_key == dpth) - { - used++; - root--; - } - while (avbl > used) - { - A[next--].m_key = (mz_uint16)(dpth); - avbl--; - } - avbl = 2 * used; - dpth++; - used = 0; - } -} - -/* Limits canonical Huffman code table's max code size. */ -enum -{ - TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 -}; -static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) -{ - int i; - mz_uint32 total = 0; - if (code_list_len <= 1) - return; - for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) - pNum_codes[max_code_size] += pNum_codes[i]; - for (i = max_code_size; i > 0; i--) - total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); - while (total != (1UL << max_code_size)) - { - pNum_codes[max_code_size]--; - for (i = max_code_size - 1; i > 0; i--) - if (pNum_codes[i]) - { - pNum_codes[i]--; - pNum_codes[i + 1] += 2; - break; - } - total--; - } -} - -static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) -{ - int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; - mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; - MZ_CLEAR_OBJ(num_codes); - if (static_table) - { - for (i = 0; i < table_len; i++) - num_codes[d->m_huff_code_sizes[table_num][i]]++; - } - else - { - tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; - int num_used_syms = 0; - const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; - for (i = 0; i < table_len; i++) - if (pSym_count[i]) - { - syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; - syms0[num_used_syms++].m_sym_index = (mz_uint16)i; - } - - pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); - tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); - - for (i = 0; i < num_used_syms; i++) - num_codes[pSyms[i].m_key]++; - - tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); - - MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); - MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); - for (i = 1, j = num_used_syms; i <= code_size_limit; i++) - for (l = num_codes[i]; l > 0; l--) - d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); - } - - next_code[1] = 0; - for (j = 0, i = 2; i <= code_size_limit; i++) - next_code[i] = j = ((j + num_codes[i - 1]) << 1); - - for (i = 0; i < table_len; i++) - { - mz_uint rev_code = 0, code, code_size; - if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) - continue; - code = next_code[code_size]++; - for (l = code_size; l > 0; l--, code >>= 1) - rev_code = (rev_code << 1) | (code & 1); - d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; - } -} - -#define TDEFL_PUT_BITS(b, l) \ - do \ - { \ - mz_uint bits = b; \ - mz_uint len = l; \ - MZ_ASSERT(bits <= ((1U << len) - 1U)); \ - d->m_bit_buffer |= (bits << d->m_bits_in); \ - d->m_bits_in += len; \ - while (d->m_bits_in >= 8) \ - { \ - if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ - *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ - d->m_bit_buffer >>= 8; \ - d->m_bits_in -= 8; \ - } \ - } \ - MZ_MACRO_END - -#define TDEFL_RLE_PREV_CODE_SIZE() \ - { \ - if (rle_repeat_count) \ - { \ - if (rle_repeat_count < 3) \ - { \ - d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ - while (rle_repeat_count--) \ - packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ - } \ - else \ - { \ - d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ - packed_code_sizes[num_packed_code_sizes++] = 16; \ - packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ - } \ - rle_repeat_count = 0; \ - } \ - } - -#define TDEFL_RLE_ZERO_CODE_SIZE() \ - { \ - if (rle_z_count) \ - { \ - if (rle_z_count < 3) \ - { \ - d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ - while (rle_z_count--) \ - packed_code_sizes[num_packed_code_sizes++] = 0; \ - } \ - else if (rle_z_count <= 10) \ - { \ - d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ - packed_code_sizes[num_packed_code_sizes++] = 17; \ - packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ - } \ - else \ - { \ - d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ - packed_code_sizes[num_packed_code_sizes++] = 18; \ - packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ - } \ - rle_z_count = 0; \ - } \ - } - -static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - -static void tdefl_start_dynamic_block(tdefl_compressor *d) -{ - int num_lit_codes, num_dist_codes, num_bit_lengths; - mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; - mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; - - d->m_huff_count[0][256] = 1; - - tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); - tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); - - for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) - if (d->m_huff_code_sizes[0][num_lit_codes - 1]) - break; - for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) - if (d->m_huff_code_sizes[1][num_dist_codes - 1]) - break; - - memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); - memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); - total_code_sizes_to_pack = num_lit_codes + num_dist_codes; - num_packed_code_sizes = 0; - rle_z_count = 0; - rle_repeat_count = 0; - - memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); - for (i = 0; i < total_code_sizes_to_pack; i++) - { - mz_uint8 code_size = code_sizes_to_pack[i]; - if (!code_size) - { - TDEFL_RLE_PREV_CODE_SIZE(); - if (++rle_z_count == 138) - { - TDEFL_RLE_ZERO_CODE_SIZE(); - } - } - else - { - TDEFL_RLE_ZERO_CODE_SIZE(); - if (code_size != prev_code_size) - { - TDEFL_RLE_PREV_CODE_SIZE(); - d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); - packed_code_sizes[num_packed_code_sizes++] = code_size; - } - else if (++rle_repeat_count == 6) - { - TDEFL_RLE_PREV_CODE_SIZE(); - } - } - prev_code_size = code_size; - } - if (rle_repeat_count) - { - TDEFL_RLE_PREV_CODE_SIZE(); - } - else - { - TDEFL_RLE_ZERO_CODE_SIZE(); - } - - tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); - - TDEFL_PUT_BITS(2, 2); - - TDEFL_PUT_BITS(num_lit_codes - 257, 5); - TDEFL_PUT_BITS(num_dist_codes - 1, 5); - - for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) - if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) - break; - num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); - TDEFL_PUT_BITS(num_bit_lengths - 4, 4); - for (i = 0; (int)i < num_bit_lengths; i++) - TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); - - for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;) - { - mz_uint code = packed_code_sizes[packed_code_sizes_index++]; - MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); - TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); - if (code >= 16) - TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); - } -} - -static void tdefl_start_static_block(tdefl_compressor *d) -{ - mz_uint i; - mz_uint8 *p = &d->m_huff_code_sizes[0][0]; - - for (i = 0; i <= 143; ++i) - *p++ = 8; - for (; i <= 255; ++i) - *p++ = 9; - for (; i <= 279; ++i) - *p++ = 7; - for (; i <= 287; ++i) - *p++ = 8; - - memset(d->m_huff_code_sizes[1], 5, 32); - - tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); - tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); - - TDEFL_PUT_BITS(1, 2); -} - -static const mz_uint16 mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS -static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) -{ - mz_uint flags; - mz_uint8 *pLZ_codes; - mz_uint8 *pOutput_buf = d->m_pOutput_buf; - mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; - mz_uint64 bit_buffer = d->m_bit_buffer; - mz_uint bits_in = d->m_bits_in; - -#define TDEFL_PUT_BITS_FAST(b, l) \ - { \ - bit_buffer |= (((mz_uint64)(b)) << bits_in); \ - bits_in += (l); \ - } - - flags = 1; - for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) - { - if (flags == 1) - flags = *pLZ_codes++ | 0x100; - - if (flags & 1) - { - mz_uint s0, s1, n0, n1, sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); - pLZ_codes += 3; - - MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); - - /* This sequence coaxes MSVC into using cmov's vs. jmp's. */ - s0 = s_tdefl_small_dist_sym[match_dist & 511]; - n0 = s_tdefl_small_dist_extra[match_dist & 511]; - s1 = s_tdefl_large_dist_sym[match_dist >> 8]; - n1 = s_tdefl_large_dist_extra[match_dist >> 8]; - sym = (match_dist < 512) ? s0 : s1; - num_extra_bits = (match_dist < 512) ? n0 : n1; - - MZ_ASSERT(d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); - } - else - { - mz_uint lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) - { - flags >>= 1; - lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) - { - flags >>= 1; - lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - } - } - } - - if (pOutput_buf >= d->m_pOutput_buf_end) - return MZ_FALSE; - - *(mz_uint64 *)pOutput_buf = bit_buffer; - pOutput_buf += (bits_in >> 3); - bit_buffer >>= (bits_in & ~7); - bits_in &= 7; - } - -#undef TDEFL_PUT_BITS_FAST - - d->m_pOutput_buf = pOutput_buf; - d->m_bits_in = 0; - d->m_bit_buffer = 0; - - while (bits_in) - { - mz_uint32 n = MZ_MIN(bits_in, 16); - TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); - bit_buffer >>= n; - bits_in -= n; - } - - TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); - - return (d->m_pOutput_buf < d->m_pOutput_buf_end); -} -#else -static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) -{ - mz_uint flags; - mz_uint8 *pLZ_codes; - - flags = 1; - for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) - { - if (flags == 1) - flags = *pLZ_codes++ | 0x100; - if (flags & 1) - { - mz_uint sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); - pLZ_codes += 3; - - MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); - - if (match_dist < 512) - { - sym = s_tdefl_small_dist_sym[match_dist]; - num_extra_bits = s_tdefl_small_dist_extra[match_dist]; - } - else - { - sym = s_tdefl_large_dist_sym[match_dist >> 8]; - num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; - } - MZ_ASSERT(d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); - } - else - { - mz_uint lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - } - } - - TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); - - return (d->m_pOutput_buf < d->m_pOutput_buf_end); -} -#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS */ - -static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) -{ - if (static_block) - tdefl_start_static_block(d); - else - tdefl_start_dynamic_block(d); - return tdefl_compress_lz_codes(d); -} - -static int tdefl_flush_block(tdefl_compressor *d, int flush) -{ - mz_uint saved_bit_buf, saved_bits_in; - mz_uint8 *pSaved_output_buf; - mz_bool comp_block_succeeded = MZ_FALSE; - int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; - mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; - - d->m_pOutput_buf = pOutput_buf_start; - d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; - - MZ_ASSERT(!d->m_output_flush_remaining); - d->m_output_flush_ofs = 0; - d->m_output_flush_remaining = 0; - - *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); - d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); - - if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) - { - TDEFL_PUT_BITS(0x78, 8); - TDEFL_PUT_BITS(0x01, 8); - } - - TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); - - pSaved_output_buf = d->m_pOutput_buf; - saved_bit_buf = d->m_bit_buffer; - saved_bits_in = d->m_bits_in; - - if (!use_raw_block) - comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); - - /* If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. */ - if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && - ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) - { - mz_uint i; - d->m_pOutput_buf = pSaved_output_buf; - d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; - TDEFL_PUT_BITS(0, 2); - if (d->m_bits_in) - { - TDEFL_PUT_BITS(0, 8 - d->m_bits_in); - } - for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) - { - TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); - } - for (i = 0; i < d->m_total_lz_bytes; ++i) - { - TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); - } - } - /* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. */ - else if (!comp_block_succeeded) - { - d->m_pOutput_buf = pSaved_output_buf; - d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; - tdefl_compress_block(d, MZ_TRUE); - } - - if (flush) - { - if (flush == TDEFL_FINISH) - { - if (d->m_bits_in) - { - TDEFL_PUT_BITS(0, 8 - d->m_bits_in); - } - if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) - { - mz_uint i, a = d->m_adler32; - for (i = 0; i < 4; i++) - { - TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); - a <<= 8; - } - } - } - else - { - mz_uint i, z = 0; - TDEFL_PUT_BITS(0, 3); - if (d->m_bits_in) - { - TDEFL_PUT_BITS(0, 8 - d->m_bits_in); - } - for (i = 2; i; --i, z ^= 0xFFFF) - { - TDEFL_PUT_BITS(z & 0xFFFF, 16); - } - } - } - - MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); - - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; - d->m_pLZ_flags = d->m_lz_code_buf; - d->m_num_flags_left = 8; - d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; - d->m_total_lz_bytes = 0; - d->m_block_index++; - - if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) - { - if (d->m_pPut_buf_func) - { - *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; - if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) - return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); - } - else if (pOutput_buf_start == d->m_output_buf) - { - int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); - d->m_out_buf_ofs += bytes_to_copy; - if ((n -= bytes_to_copy) != 0) - { - d->m_output_flush_ofs = bytes_to_copy; - d->m_output_flush_remaining = n; - } - } - else - { - d->m_out_buf_ofs += n; - } - } - - return d->m_output_flush_remaining; -} - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES -#ifdef MINIZ_UNALIGNED_USE_MEMCPY -static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8* p) -{ - mz_uint16 ret; - memcpy(&ret, p, sizeof(mz_uint16)); - return ret; -} -static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p) -{ - mz_uint16 ret; - memcpy(&ret, p, sizeof(mz_uint16)); - return ret; -} -#else -#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) -#define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p) -#endif -static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) -{ - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; - mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; - mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); - mz_uint16 s01 = TDEFL_READ_UNALIGNED_WORD2(s); - MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); - if (max_match_len <= match_len) - return; - for (;;) - { - for (;;) - { - if (--num_probes_left == 0) - return; -#define TDEFL_PROBE \ - next_probe_pos = d->m_next[probe_pos]; \ - if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ - return; \ - probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ - if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ - break; - TDEFL_PROBE; - TDEFL_PROBE; - TDEFL_PROBE; - } - if (!dist) - break; - q = (const mz_uint16 *)(d->m_dict + probe_pos); - if (TDEFL_READ_UNALIGNED_WORD2(q) != s01) - continue; - p = s; - probe_len = 32; - do - { - } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && - (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); - if (!probe_len) - { - *pMatch_dist = dist; - *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN); - break; - } - else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len) - { - *pMatch_dist = dist; - if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) - break; - c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); - } - } -} -#else -static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) -{ - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; - mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint8 *s = d->m_dict + pos, *p, *q; - mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; - MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); - if (max_match_len <= match_len) - return; - for (;;) - { - for (;;) - { - if (--num_probes_left == 0) - return; -#define TDEFL_PROBE \ - next_probe_pos = d->m_next[probe_pos]; \ - if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ - return; \ - probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ - if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \ - break; - TDEFL_PROBE; - TDEFL_PROBE; - TDEFL_PROBE; - } - if (!dist) - break; - p = s; - q = d->m_dict + probe_pos; - for (probe_len = 0; probe_len < max_match_len; probe_len++) - if (*p++ != *q++) - break; - if (probe_len > match_len) - { - *pMatch_dist = dist; - if ((*pMatch_len = match_len = probe_len) == max_match_len) - return; - c0 = d->m_dict[pos + match_len]; - c1 = d->m_dict[pos + match_len - 1]; - } - } -} -#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ - -// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -// static mz_bool tdefl_compress_fast(tdefl_compressor *d) -// { -// /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ -// mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; -// mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; -// mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - -// while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) -// { -// const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; -// mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; -// mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); -// d->m_src_buf_left -= num_bytes_to_process; -// lookahead_size += num_bytes_to_process; - -// while (num_bytes_to_process) -// { -// mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); -// memcpy(d->m_dict + dst_pos, d->m_pSrc, n); -// if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) -// memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); -// d->m_pSrc += n; -// dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; -// num_bytes_to_process -= n; -// } - -// dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); -// if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) -// break; - -// while (lookahead_size >= 4) -// { -// mz_uint cur_match_dist, cur_match_len = 1; -// mz_uint8 *pCur_dict = d->m_dict + cur_pos; -// mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; -// mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; -// mz_uint probe_pos = d->m_hash[hash]; -// d->m_hash[hash] = (mz_uint16)lookahead_pos; - -// if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) -// { -// const mz_uint16 *p = (const mz_uint16 *)pCur_dict; -// const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); -// mz_uint32 probe_len = 32; -// do -// { -// } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && -// (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); -// cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); -// if (!probe_len) -// cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; - -// if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) -// { -// cur_match_len = 1; -// *pLZ_code_buf++ = (mz_uint8)first_trigram; -// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -// d->m_huff_count[0][(mz_uint8)first_trigram]++; -// } -// else -// { -// mz_uint32 s0, s1; -// cur_match_len = MZ_MIN(cur_match_len, lookahead_size); - -// MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); - -// cur_match_dist--; - -// pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); -// *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; -// pLZ_code_buf += 3; -// *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); - -// s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; -// s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; -// d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; - -// d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; -// } -// } -// else -// { -// *pLZ_code_buf++ = (mz_uint8)first_trigram; -// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -// d->m_huff_count[0][(mz_uint8)first_trigram]++; -// } - -// if (--num_flags_left == 0) -// { -// num_flags_left = 8; -// pLZ_flags = pLZ_code_buf++; -// } - -// total_lz_bytes += cur_match_len; -// lookahead_pos += cur_match_len; -// dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); -// cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; -// MZ_ASSERT(lookahead_size >= cur_match_len); -// lookahead_size -= cur_match_len; - -// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) -// { -// int n; -// d->m_lookahead_pos = lookahead_pos; -// d->m_lookahead_size = lookahead_size; -// d->m_dict_size = dict_size; -// d->m_total_lz_bytes = total_lz_bytes; -// d->m_pLZ_code_buf = pLZ_code_buf; -// d->m_pLZ_flags = pLZ_flags; -// d->m_num_flags_left = num_flags_left; -// if ((n = tdefl_flush_block(d, 0)) != 0) -// return (n < 0) ? MZ_FALSE : MZ_TRUE; -// total_lz_bytes = d->m_total_lz_bytes; -// pLZ_code_buf = d->m_pLZ_code_buf; -// pLZ_flags = d->m_pLZ_flags; -// num_flags_left = d->m_num_flags_left; -// } -// } - -// while (lookahead_size) -// { -// mz_uint8 lit = d->m_dict[cur_pos]; - -// total_lz_bytes++; -// *pLZ_code_buf++ = lit; -// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -// if (--num_flags_left == 0) -// { -// num_flags_left = 8; -// pLZ_flags = pLZ_code_buf++; -// } - -// d->m_huff_count[0][lit]++; - -// lookahead_pos++; -// dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); -// cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; -// lookahead_size--; - -// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) -// { -// int n; -// d->m_lookahead_pos = lookahead_pos; -// d->m_lookahead_size = lookahead_size; -// d->m_dict_size = dict_size; -// d->m_total_lz_bytes = total_lz_bytes; -// d->m_pLZ_code_buf = pLZ_code_buf; -// d->m_pLZ_flags = pLZ_flags; -// d->m_num_flags_left = num_flags_left; -// if ((n = tdefl_flush_block(d, 0)) != 0) -// return (n < 0) ? MZ_FALSE : MZ_TRUE; -// total_lz_bytes = d->m_total_lz_bytes; -// pLZ_code_buf = d->m_pLZ_code_buf; -// pLZ_flags = d->m_pLZ_flags; -// num_flags_left = d->m_num_flags_left; -// } -// } -// } - -// d->m_lookahead_pos = lookahead_pos; -// d->m_lookahead_size = lookahead_size; -// d->m_dict_size = dict_size; -// d->m_total_lz_bytes = total_lz_bytes; -// d->m_pLZ_code_buf = pLZ_code_buf; -// d->m_pLZ_flags = pLZ_flags; -// d->m_num_flags_left = num_flags_left; -// return MZ_TRUE; -// } -// #endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ - -static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) -{ - d->m_total_lz_bytes++; - *d->m_pLZ_code_buf++ = lit; - *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); - if (--d->m_num_flags_left == 0) - { - d->m_num_flags_left = 8; - d->m_pLZ_flags = d->m_pLZ_code_buf++; - } - d->m_huff_count[0][lit]++; -} - -static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) -{ - mz_uint32 s0, s1; - - MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); - - d->m_total_lz_bytes += match_len; - - d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); - - match_dist -= 1; - d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); - d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); - d->m_pLZ_code_buf += 3; - - *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); - if (--d->m_num_flags_left == 0) - { - d->m_num_flags_left = 8; - d->m_pLZ_flags = d->m_pLZ_code_buf++; - } - - s0 = s_tdefl_small_dist_sym[match_dist & 511]; - s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; - d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; - - if (match_len >= TDEFL_MIN_MATCH_LEN) - d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; -} - -static mz_bool tdefl_compress_normal(tdefl_compressor *d) -{ - const mz_uint8 *pSrc = d->m_pSrc; - size_t src_buf_left = d->m_src_buf_left; - tdefl_flush flush = d->m_flush; - - while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) - { - mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; - /* Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. */ - if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) - { - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; - mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; - mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); - const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; - src_buf_left -= num_bytes_to_process; - d->m_lookahead_size += num_bytes_to_process; - while (pSrc != pSrc_end) - { - mz_uint8 c = *pSrc++; - d->m_dict[dst_pos] = c; - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; - d->m_hash[hash] = (mz_uint16)(ins_pos); - dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; - ins_pos++; - } - } - else - { - while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) - { - mz_uint8 c = *pSrc++; - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; - src_buf_left--; - d->m_dict[dst_pos] = c; - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) - { - mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; - mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; - d->m_hash[hash] = (mz_uint16)(ins_pos); - } - } - } - d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); - if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) - break; - - /* Simple lazy/greedy parsing state machine. */ - len_to_move = 1; - cur_match_dist = 0; - cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); - cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) - { - if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) - { - mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; - cur_match_len = 0; - while (cur_match_len < d->m_lookahead_size) - { - if (d->m_dict[cur_pos + cur_match_len] != c) - break; - cur_match_len++; - } - if (cur_match_len < TDEFL_MIN_MATCH_LEN) - cur_match_len = 0; - else - cur_match_dist = 1; - } - } - else - { - tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); - } - if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) - { - cur_match_dist = cur_match_len = 0; - } - if (d->m_saved_match_len) - { - if (cur_match_len > d->m_saved_match_len) - { - tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); - if (cur_match_len >= 128) - { - tdefl_record_match(d, cur_match_len, cur_match_dist); - d->m_saved_match_len = 0; - len_to_move = cur_match_len; - } - else - { - d->m_saved_lit = d->m_dict[cur_pos]; - d->m_saved_match_dist = cur_match_dist; - d->m_saved_match_len = cur_match_len; - } - } - else - { - tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); - len_to_move = d->m_saved_match_len - 1; - d->m_saved_match_len = 0; - } - } - else if (!cur_match_dist) - tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); - else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) - { - tdefl_record_match(d, cur_match_len, cur_match_dist); - len_to_move = cur_match_len; - } - else - { - d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; - d->m_saved_match_dist = cur_match_dist; - d->m_saved_match_len = cur_match_len; - } - /* Move the lookahead forward by len_to_move bytes. */ - d->m_lookahead_pos += len_to_move; - MZ_ASSERT(d->m_lookahead_size >= len_to_move); - d->m_lookahead_size -= len_to_move; - d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); - /* Check if it's time to flush the current LZ codes to the internal output buffer. */ - if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || - ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) - { - int n; - d->m_pSrc = pSrc; - d->m_src_buf_left = src_buf_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - } - } - - d->m_pSrc = pSrc; - d->m_src_buf_left = src_buf_left; - return MZ_TRUE; -} - -static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) -{ - if (d->m_pIn_buf_size) - { - *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; - } - - if (d->m_pOut_buf_size) - { - size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); - d->m_output_flush_ofs += (mz_uint)n; - d->m_output_flush_remaining -= (mz_uint)n; - d->m_out_buf_ofs += n; - - *d->m_pOut_buf_size = d->m_out_buf_ofs; - } - - return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; -} - -tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) -{ - if (!d) - { - if (pIn_buf_size) - *pIn_buf_size = 0; - if (pOut_buf_size) - *pOut_buf_size = 0; - return TDEFL_STATUS_BAD_PARAM; - } - - d->m_pIn_buf = pIn_buf; - d->m_pIn_buf_size = pIn_buf_size; - d->m_pOut_buf = pOut_buf; - d->m_pOut_buf_size = pOut_buf_size; - d->m_pSrc = (const mz_uint8 *)(pIn_buf); - d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; - d->m_out_buf_ofs = 0; - d->m_flush = flush; - - if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || - (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) - { - if (pIn_buf_size) - *pIn_buf_size = 0; - if (pOut_buf_size) - *pOut_buf_size = 0; - return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); - } - d->m_wants_to_finish |= (flush == TDEFL_FINISH); - - if ((d->m_output_flush_remaining) || (d->m_finished)) - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); - -// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -// if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && -// ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && -// ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) -// { -// if (!tdefl_compress_fast(d)) -// return d->m_prev_return_status; -// } -// else -// #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ - { - if (!tdefl_compress_normal(d)) - return d->m_prev_return_status; - } - - if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) - d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); - - if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) - { - if (tdefl_flush_block(d, flush) < 0) - return d->m_prev_return_status; - d->m_finished = (flush == TDEFL_FINISH); - if (flush == TDEFL_FULL_FLUSH) - { - MZ_CLEAR_OBJ(d->m_hash); - MZ_CLEAR_OBJ(d->m_next); - d->m_dict_size = 0; - } - } - - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); -} - -// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) -// { -// MZ_ASSERT(d->m_pPut_buf_func); -// return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); -// } - -tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - d->m_pPut_buf_func = pPut_buf_func; - d->m_pPut_buf_user = pPut_buf_user; - d->m_flags = (mz_uint)(flags); - d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; - d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; - d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; - if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) - MZ_CLEAR_OBJ(d->m_hash); - d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; - d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; - d->m_pLZ_flags = d->m_lz_code_buf; - d->m_num_flags_left = 8; - d->m_pOutput_buf = d->m_output_buf; - d->m_pOutput_buf_end = d->m_output_buf; - d->m_prev_return_status = TDEFL_STATUS_OKAY; - d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; - d->m_adler32 = 1; - d->m_pIn_buf = NULL; - d->m_pOut_buf = NULL; - d->m_pIn_buf_size = NULL; - d->m_pOut_buf_size = NULL; - d->m_flush = TDEFL_NO_FLUSH; - d->m_pSrc = NULL; - d->m_src_buf_left = 0; - d->m_out_buf_ofs = 0; - memset(d->m_dict, 0, sizeof(d->m_dict)); // Initialize array to 0's - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - return TDEFL_STATUS_OKAY; -} - -// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) -// { -// return d->m_prev_return_status; -// } - -mz_uint32 tdefl_get_adler32(tdefl_compressor *d) -{ - return d->m_adler32; -} - -// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -// { -// tdefl_compressor *pComp; -// mz_bool succeeded; -// if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) -// return MZ_FALSE; -// pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -// if (!pComp) -// return MZ_FALSE; -// succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); -// succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); -// MZ_FREE(pComp); -// return succeeded; -// } - -// typedef struct -// { -// size_t m_size, m_capacity; -// mz_uint8 *m_pBuf; -// mz_bool m_expandable; -// } tdefl_output_buffer; - -// static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) -// { -// tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; -// size_t new_size = p->m_size + len; -// if (new_size > p->m_capacity) -// { -// size_t new_capacity = p->m_capacity; -// mz_uint8 *pNew_buf; -// if (!p->m_expandable) -// return MZ_FALSE; -// do -// { -// new_capacity = MZ_MAX(128U, new_capacity << 1U); -// } while (new_size > new_capacity); -// pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); -// if (!pNew_buf) -// return MZ_FALSE; -// p->m_pBuf = pNew_buf; -// p->m_capacity = new_capacity; -// } -// memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); -// p->m_size = new_size; -// return MZ_TRUE; -// } - -// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -// { -// tdefl_output_buffer out_buf; -// MZ_CLEAR_OBJ(out_buf); -// if (!pOut_len) -// return MZ_FALSE; -// else -// *pOut_len = 0; -// out_buf.m_expandable = MZ_TRUE; -// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) -// return NULL; -// *pOut_len = out_buf.m_size; -// return out_buf.m_pBuf; -// } - -// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -// { -// tdefl_output_buffer out_buf; -// MZ_CLEAR_OBJ(out_buf); -// if (!pOut_buf) -// return 0; -// out_buf.m_pBuf = (mz_uint8 *)pOut_buf; -// out_buf.m_capacity = out_buf_len; -// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) -// return 0; -// return out_buf.m_size; -// } - -static const mz_uint16 s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; - -/* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */ -mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) -{ - mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); - if (window_bits > 0) - comp_flags |= TDEFL_WRITE_ZLIB_HEADER; - - if (!level) - comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; - else if (strategy == MZ_FILTERED) - comp_flags |= TDEFL_FILTER_MATCHES; - else if (strategy == MZ_HUFFMAN_ONLY) - comp_flags &= ~TDEFL_MAX_PROBES_MASK; - else if (strategy == MZ_FIXED) - comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; - else if (strategy == MZ_RLE) - comp_flags |= TDEFL_RLE_MATCHES; - - return comp_flags; -} - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) */ -#endif - -/* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at - http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. - This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ -// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) -// { -// /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ -// static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; -// tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -// tdefl_output_buffer out_buf; -// int i, bpl = w * num_chans, y, z; -// mz_uint32 c; -// *pLen_out = 0; -// if (!pComp) -// return NULL; -// MZ_CLEAR_OBJ(out_buf); -// out_buf.m_expandable = MZ_TRUE; -// out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); -// if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) -// { -// MZ_FREE(pComp); -// return NULL; -// } -// /* write dummy header */ -// for (z = 41; z; --z) -// tdefl_output_buffer_putter(&z, 1, &out_buf); -// /* compress image data */ -// tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); -// for (y = 0; y < h; ++y) -// { -// tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); -// tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); -// } -// if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) -// { -// MZ_FREE(pComp); -// MZ_FREE(out_buf.m_pBuf); -// return NULL; -// } -// /* write real header */ -// *pLen_out = out_buf.m_size - 41; -// { -// static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; -// mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, -// 0x0a, 0x1a, 0x0a, 0x00, 0x00, -// 0x00, 0x0d, 0x49, 0x48, 0x44, -// 0x52, 0x00, 0x00, 0x00, 0x00, -// 0x00, 0x00, 0x00, 0x00, 0x08, -// 0x00, 0x00, 0x00, 0x00, 0x00, -// 0x00, 0x00, 0x00, 0x00, 0x00, -// 0x00, 0x00, 0x49, 0x44, 0x41, -// 0x54 }; -// pnghdr[18] = (mz_uint8)(w >> 8); -// pnghdr[19] = (mz_uint8)w; -// pnghdr[22] = (mz_uint8)(h >> 8); -// pnghdr[23] = (mz_uint8)h; -// pnghdr[25] = chans[num_chans]; -// pnghdr[33] = (mz_uint8)(*pLen_out >> 24); -// pnghdr[34] = (mz_uint8)(*pLen_out >> 16); -// pnghdr[35] = (mz_uint8)(*pLen_out >> 8); -// pnghdr[36] = (mz_uint8)*pLen_out; -// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); -// for (i = 0; i < 4; ++i, c <<= 8) -// ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); -// memcpy(out_buf.m_pBuf, pnghdr, 41); -// } -// /* write footer (IDAT CRC-32, followed by IEND chunk) */ -// if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) -// { -// *pLen_out = 0; -// MZ_FREE(pComp); -// MZ_FREE(out_buf.m_pBuf); -// return NULL; -// } -// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); -// for (i = 0; i < 4; ++i, c <<= 8) -// (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); -// /* compute final size of file, grab compressed data buffer and return */ -// *pLen_out += 57; -// MZ_FREE(pComp); -// return out_buf.m_pBuf; -// } -// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) -// { - /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */ -// return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); -// } - -/* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ -/* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ -/* structure size and allocation mechanism. */ -// tdefl_compressor *tdefl_compressor_alloc() -// { -// return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -// } - -// void tdefl_compressor_free(tdefl_compressor *pComp) -// { -// MZ_FREE(pComp); -// } - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#ifdef __cplusplus -} -#endif -/************************************************************************** - * - * Copyright 2013-2014 RAD Game Tools and Valve Software - * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ - - - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------- Low-level Decompression (completely independent from all compression API's) */ - -#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) -#define TINFL_MEMSET(p, c, l) memset(p, c, l) - -#define TINFL_CR_BEGIN \ - switch (r->m_state) \ - { \ - case 0: -#define TINFL_CR_RETURN(state_index, result) \ - do \ - { \ - status = result; \ - r->m_state = state_index; \ - goto common_exit; \ - case state_index:; \ - } \ - MZ_MACRO_END -#define TINFL_CR_RETURN_FOREVER(state_index, result) \ - do \ - { \ - for (;;) \ - { \ - TINFL_CR_RETURN(state_index, result); \ - } \ - } \ - MZ_MACRO_END -#define TINFL_CR_FINISH } - -#define TINFL_GET_BYTE(state_index, c) \ - do \ - { \ - while (pIn_buf_cur >= pIn_buf_end) \ - { \ - TINFL_CR_RETURN(state_index, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \ - } \ - c = *pIn_buf_cur++; \ - } \ - MZ_MACRO_END - -#define TINFL_NEED_BITS(state_index, n) \ - do \ - { \ - mz_uint c; \ - TINFL_GET_BYTE(state_index, c); \ - bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ - num_bits += 8; \ - } while (num_bits < (mz_uint)(n)) -#define TINFL_SKIP_BITS(state_index, n) \ - do \ - { \ - if (num_bits < (mz_uint)(n)) \ - { \ - TINFL_NEED_BITS(state_index, n); \ - } \ - bit_buf >>= (n); \ - num_bits -= (n); \ - } \ - MZ_MACRO_END -#define TINFL_GET_BITS(state_index, b, n) \ - do \ - { \ - if (num_bits < (mz_uint)(n)) \ - { \ - TINFL_NEED_BITS(state_index, n); \ - } \ - b = bit_buf & ((1 << (n)) - 1); \ - bit_buf >>= (n); \ - num_bits -= (n); \ - } \ - MZ_MACRO_END - -/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */ -/* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */ -/* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */ -/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */ -#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ - do \ - { \ - temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ - if (temp >= 0) \ - { \ - code_len = temp >> 9; \ - if ((code_len) && (num_bits >= code_len)) \ - break; \ - } \ - else if (num_bits > TINFL_FAST_LOOKUP_BITS) \ - { \ - code_len = TINFL_FAST_LOOKUP_BITS; \ - do \ - { \ - temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ - } while ((temp < 0) && (num_bits >= (code_len + 1))); \ - if (temp >= 0) \ - break; \ - } \ - TINFL_GET_BYTE(state_index, c); \ - bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ - num_bits += 8; \ - } while (num_bits < 15); - -/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */ -/* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */ -/* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */ -/* The slow path is only executed at the very end of the input buffer. */ -/* v1.16: The original macro handled the case at the very end of the passed-in input buffer, but we also need to handle the case where the user passes in 1+zillion bytes */ -/* following the deflate data and our non-conservative read-ahead path won't kick in here on this code. This is much trickier. */ -#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \ - do \ - { \ - int temp; \ - mz_uint code_len, c; \ - if (num_bits < 15) \ - { \ - if ((pIn_buf_end - pIn_buf_cur) < 2) \ - { \ - TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ - } \ - else \ - { \ - bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ - pIn_buf_cur += 2; \ - num_bits += 16; \ - } \ - } \ - if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ - code_len = temp >> 9, temp &= 511; \ - else \ - { \ - code_len = TINFL_FAST_LOOKUP_BITS; \ - do \ - { \ - temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ - } while (temp < 0); \ - } \ - sym = temp; \ - bit_buf >>= code_len; \ - num_bits -= code_len; \ - } \ - MZ_MACRO_END - -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) -{ - static const mz_uint16 s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; - static const mz_uint8 s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; - static const mz_uint16 s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; - static const mz_uint8 s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; - static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - static const mz_uint16 s_min_table_sizes[3] = { 257, 1, 4 }; - - tinfl_status status = TINFL_STATUS_FAILED; - mz_uint32 num_bits, dist, counter, num_extra; - tinfl_bit_buf_t bit_buf; - const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; - mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; - size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; - - /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */ - if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) - { - *pIn_buf_size = *pOut_buf_size = 0; - return TINFL_STATUS_BAD_PARAM; - } - - num_bits = r->m_num_bits; - bit_buf = r->m_bit_buf; - dist = r->m_dist; - counter = r->m_counter; - num_extra = r->m_num_extra; - dist_from_out_buf_start = r->m_dist_from_out_buf_start; - TINFL_CR_BEGIN - - bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; - r->m_z_adler32 = r->m_check_adler32 = 1; - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - TINFL_GET_BYTE(1, r->m_zhdr0); - TINFL_GET_BYTE(2, r->m_zhdr1); - counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); - if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) - counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); - if (counter) - { - TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); - } - } - - do - { - TINFL_GET_BITS(3, r->m_final, 3); - r->m_type = r->m_final >> 1; - if (r->m_type == 0) - { - TINFL_SKIP_BITS(5, num_bits & 7); - for (counter = 0; counter < 4; ++counter) - { - if (num_bits) - TINFL_GET_BITS(6, r->m_raw_header[counter], 8); - else - TINFL_GET_BYTE(7, r->m_raw_header[counter]); - } - if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) - { - TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); - } - while ((counter) && (num_bits)) - { - TINFL_GET_BITS(51, dist, 8); - while (pOut_buf_cur >= pOut_buf_end) - { - TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); - } - *pOut_buf_cur++ = (mz_uint8)dist; - counter--; - } - while (counter) - { - size_t n; - while (pOut_buf_cur >= pOut_buf_end) - { - TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); - } - while (pIn_buf_cur >= pIn_buf_end) - { - TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); - } - n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); - TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); - pIn_buf_cur += n; - pOut_buf_cur += n; - counter -= (mz_uint)n; - } - } - else if (r->m_type == 3) - { - TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); - } - else - { - if (r->m_type == 1) - { - mz_uint8 *p = r->m_tables[0].m_code_size; - mz_uint i; - r->m_table_sizes[0] = 288; - r->m_table_sizes[1] = 32; - TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); - for (i = 0; i <= 143; ++i) - *p++ = 8; - for (; i <= 255; ++i) - *p++ = 9; - for (; i <= 279; ++i) - *p++ = 7; - for (; i <= 287; ++i) - *p++ = 8; - } - else - { - for (counter = 0; counter < 3; counter++) - { - TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); - r->m_table_sizes[counter] += s_min_table_sizes[counter]; - } - MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); - for (counter = 0; counter < r->m_table_sizes[2]; counter++) - { - mz_uint s; - TINFL_GET_BITS(14, s, 3); - r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; - } - r->m_table_sizes[2] = 19; - } - for (; ((int)r->m_type) >= 0; r->m_type--) - { - int tree_next, tree_cur; - tinfl_huff_table *pTable; - mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; - pTable = &r->m_tables[r->m_type]; - MZ_CLEAR_OBJ(total_syms); - MZ_CLEAR_OBJ(pTable->m_look_up); - MZ_CLEAR_OBJ(pTable->m_tree); - for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) - total_syms[pTable->m_code_size[i]]++; - used_syms = 0, total = 0; - next_code[0] = next_code[1] = 0; - for (i = 1; i <= 15; ++i) - { - used_syms += total_syms[i]; - next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); - } - if ((65536 != total) && (used_syms > 1)) - { - TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); - } - for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) - { - mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; - if (!code_size) - continue; - cur_code = next_code[code_size]++; - for (l = code_size; l > 0; l--, cur_code >>= 1) - rev_code = (rev_code << 1) | (cur_code & 1); - if (code_size <= TINFL_FAST_LOOKUP_BITS) - { - mz_int16 k = (mz_int16)((code_size << 9) | sym_index); - while (rev_code < TINFL_FAST_LOOKUP_SIZE) - { - pTable->m_look_up[rev_code] = k; - rev_code += (1 << code_size); - } - continue; - } - if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) - { - pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; - tree_cur = tree_next; - tree_next -= 2; - } - rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); - for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) - { - tree_cur -= ((rev_code >>= 1) & 1); - if (!pTable->m_tree[-tree_cur - 1]) - { - pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; - tree_cur = tree_next; - tree_next -= 2; - } - else - tree_cur = pTable->m_tree[-tree_cur - 1]; - } - tree_cur -= ((rev_code >>= 1) & 1); - pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; - } - if (r->m_type == 2) - { - for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) - { - mz_uint s; - TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); - if (dist < 16) - { - r->m_len_codes[counter++] = (mz_uint8)dist; - continue; - } - if ((dist == 16) && (!counter)) - { - TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); - } - num_extra = "\02\03\07"[dist - 16]; - TINFL_GET_BITS(18, s, num_extra); - s += "\03\03\013"[dist - 16]; - TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); - counter += s; - } - if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) - { - TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); - } - TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); - TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); - } - } - for (;;) - { - mz_uint8 *pSrc; - for (;;) - { - if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) - { - TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); - if (counter >= 256) - break; - while (pOut_buf_cur >= pOut_buf_end) - { - TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); - } - *pOut_buf_cur++ = (mz_uint8)counter; - } - else - { - int sym2; - mz_uint code_len; -#if TINFL_USE_64BIT_BITBUF - if (num_bits < 30) - { - bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); - pIn_buf_cur += 4; - num_bits += 32; - } -#else - if (num_bits < 15) - { - bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); - pIn_buf_cur += 2; - num_bits += 16; - } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; - do - { - sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; - } while (sym2 < 0); - } - counter = sym2; - bit_buf >>= code_len; - num_bits -= code_len; - if (counter & 256) - break; - -#if !TINFL_USE_64BIT_BITBUF - if (num_bits < 15) - { - bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); - pIn_buf_cur += 2; - num_bits += 16; - } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; - do - { - sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; - } while (sym2 < 0); - } - bit_buf >>= code_len; - num_bits -= code_len; - - pOut_buf_cur[0] = (mz_uint8)counter; - if (sym2 & 256) - { - pOut_buf_cur++; - counter = sym2; - break; - } - pOut_buf_cur[1] = (mz_uint8)sym2; - pOut_buf_cur += 2; - } - } - if ((counter &= 511) == 256) - break; - - num_extra = s_length_extra[counter - 257]; - counter = s_length_base[counter - 257]; - if (num_extra) - { - mz_uint extra_bits; - TINFL_GET_BITS(25, extra_bits, num_extra); - counter += extra_bits; - } - - TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); - num_extra = s_dist_extra[dist]; - dist = s_dist_base[dist]; - if (num_extra) - { - mz_uint extra_bits; - TINFL_GET_BITS(27, extra_bits, num_extra); - dist += extra_bits; - } - - dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; - if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) - { - TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); - } - - pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); - - if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) - { - while (counter--) - { - while (pOut_buf_cur >= pOut_buf_end) - { - TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); - } - *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; - } - continue; - } -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES - else if ((counter >= 9) && (counter <= dist)) - { - const mz_uint8 *pSrc_end = pSrc + (counter & ~7); - do - { - ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; - ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; - pOut_buf_cur += 8; - } while ((pSrc += 8) < pSrc_end); - if ((counter &= 7) < 3) - { - if (counter) - { - pOut_buf_cur[0] = pSrc[0]; - if (counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - continue; - } - } -#endif - do - { - pOut_buf_cur[0] = pSrc[0]; - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur[2] = pSrc[2]; - pOut_buf_cur += 3; - pSrc += 3; - } while ((int)(counter -= 3) > 2); - if ((int)counter > 0) - { - pOut_buf_cur[0] = pSrc[0]; - if ((int)counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - } - } - } while (!(r->m_final & 1)); - - /* Ensure byte alignment and put back any bytes from the bitbuf if we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ - /* I'm being super conservative here. A number of simplifications can be made to the byte alignment part, and the Adler32 check shouldn't ever need to worry about reading from the bitbuf now. */ - TINFL_SKIP_BITS(32, num_bits & 7); - while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) - { - --pIn_buf_cur; - num_bits -= 8; - } - bit_buf &= (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); - MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */ - - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - for (counter = 0; counter < 4; ++counter) - { - mz_uint s; - if (num_bits) - TINFL_GET_BITS(41, s, 8); - else - TINFL_GET_BYTE(42, s); - r->m_z_adler32 = (r->m_z_adler32 << 8) | s; - } - } - TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); - - TINFL_CR_FINISH - -common_exit: - /* As long as we aren't telling the caller that we NEED more input to make forward progress: */ - /* Put back any bytes from the bitbuf in case we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ - /* We need to be very careful here to NOT push back any bytes we definitely know we need to make forward progress, though, or we'll lock the caller up into an inf loop. */ - if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) && (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS)) - { - while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) - { - --pIn_buf_cur; - num_bits -= 8; - } - } - r->m_num_bits = num_bits; - r->m_bit_buf = bit_buf & (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); - r->m_dist = dist; - r->m_counter = counter; - r->m_num_extra = num_extra; - r->m_dist_from_out_buf_start = dist_from_out_buf_start; - *pIn_buf_size = pIn_buf_cur - pIn_buf_next; - *pOut_buf_size = pOut_buf_cur - pOut_buf_next; - if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) - { - const mz_uint8 *ptr = pOut_buf_next; - size_t buf_len = *pOut_buf_size; - mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; - size_t block_len = buf_len % 5552; - while (buf_len) - { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) - { - s1 += ptr[0], s2 += s1; - s1 += ptr[1], s2 += s1; - s1 += ptr[2], s2 += s1; - s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; - s1 += ptr[5], s2 += s1; - s1 += ptr[6], s2 += s1; - s1 += ptr[7], s2 += s1; - } - for (; i < block_len; ++i) - s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; - buf_len -= block_len; - block_len = 5552; - } - r->m_check_adler32 = (s2 << 16) + s1; - if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) - status = TINFL_STATUS_ADLER32_MISMATCH; - } - return status; -} - -/* Higher level helper functions. */ -// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -// { -// tinfl_decompressor decomp; -// void *pBuf = NULL, *pNew_buf; -// size_t src_buf_ofs = 0, out_buf_capacity = 0; -// *pOut_len = 0; -// tinfl_init(&decomp); -// for (;;) -// { -// size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; -// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, -// (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); -// if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) -// { -// MZ_FREE(pBuf); -// *pOut_len = 0; -// return NULL; -// } -// src_buf_ofs += src_buf_size; -// *pOut_len += dst_buf_size; -// if (status == TINFL_STATUS_DONE) -// break; -// new_out_buf_capacity = out_buf_capacity * 2; -// if (new_out_buf_capacity < 128) -// new_out_buf_capacity = 128; -// pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); -// if (!pNew_buf) -// { -// MZ_FREE(pBuf); -// *pOut_len = 0; -// return NULL; -// } -// pBuf = pNew_buf; -// out_buf_capacity = new_out_buf_capacity; -// } -// return pBuf; -// } - -// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -// { -// tinfl_decompressor decomp; -// tinfl_status status; -// tinfl_init(&decomp); -// status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); -// return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; -// } - -// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -// { -// int result = 0; -// tinfl_decompressor decomp; -// mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); -// size_t in_buf_ofs = 0, dict_ofs = 0; -// if (!pDict) -// return TINFL_STATUS_FAILED; -// tinfl_init(&decomp); -// for (;;) -// { -// size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; -// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, -// (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); -// in_buf_ofs += in_buf_size; -// if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) -// break; -// if (status != TINFL_STATUS_HAS_MORE_OUTPUT) -// { -// result = (status == TINFL_STATUS_DONE); -// break; -// } -// dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); -// } -// MZ_FREE(pDict); -// *pIn_buf_size = in_buf_ofs; -// return result; -// } - -// tinfl_decompressor *tinfl_decompressor_alloc() -// { -// tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); -// if (pDecomp) -// tinfl_init(pDecomp); -// return pDecomp; -// } - -// void tinfl_decompressor_free(tinfl_decompressor *pDecomp) -// { -// MZ_FREE(pDecomp); -// } - -#ifdef __cplusplus -} -#endif -/************************************************************************** - * - * Copyright 2013-2014 RAD Game Tools and Valve Software - * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - * Copyright 2016 Martin Raiber - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ - - -// #ifndef MINIZ_NO_ARCHIVE_APIS - -// #ifdef __cplusplus -// extern "C" { -// #endif - -/* ------------------- .ZIP archive reading */ - -// #ifdef MINIZ_NO_STDIO -// #define MZ_FILE void * -// #else -// #include - -// #if defined(_MSC_VER) || defined(__MINGW64__) -// static FILE *mz_fopen(const char *pFilename, const char *pMode) -// { -// FILE *pFile = NULL; -// fopen_s(&pFile, pFilename, pMode); -// return pFile; -// } -// static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) -// { -// FILE *pFile = NULL; -// if (freopen_s(&pFile, pPath, pMode, pStream)) -// return NULL; -// return pFile; -// } -// #ifndef MINIZ_NO_TIME -// #include -// #endif -// #define MZ_FOPEN mz_fopen -// #define MZ_FCLOSE fclose -// #define MZ_FREAD fread -// #define MZ_FWRITE fwrite -// #define MZ_FTELL64 _ftelli64 -// #define MZ_FSEEK64 _fseeki64 -// #define MZ_FILE_STAT_STRUCT _stat -// #define MZ_FILE_STAT _stat -// #define MZ_FFLUSH fflush -// #define MZ_FREOPEN mz_freopen -// #define MZ_DELETE_FILE remove -// #elif defined(__MINGW32__) -// #ifndef MINIZ_NO_TIME -// #include -// #endif -// #define MZ_FOPEN(f, m) fopen(f, m) -// #define MZ_FCLOSE fclose -// #define MZ_FREAD fread -// #define MZ_FWRITE fwrite -// #define MZ_FTELL64 ftello64 -// #define MZ_FSEEK64 fseeko64 -// #define MZ_FILE_STAT_STRUCT _stat -// #define MZ_FILE_STAT _stat -// #define MZ_FFLUSH fflush -// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) -// #define MZ_DELETE_FILE remove -// #elif defined(__TINYC__) -// #ifndef MINIZ_NO_TIME -// #include -// #endif -// #define MZ_FOPEN(f, m) fopen(f, m) -// #define MZ_FCLOSE fclose -// #define MZ_FREAD fread -// #define MZ_FWRITE fwrite -// #define MZ_FTELL64 ftell -// #define MZ_FSEEK64 fseek -// #define MZ_FILE_STAT_STRUCT stat -// #define MZ_FILE_STAT stat -// #define MZ_FFLUSH fflush -// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) -// #define MZ_DELETE_FILE remove -// #elif defined(__GNUC__) && _LARGEFILE64_SOURCE -// #ifndef MINIZ_NO_TIME -// #include -// #endif -// #define MZ_FOPEN(f, m) fopen64(f, m) -// #define MZ_FCLOSE fclose -// #define MZ_FREAD fread -// #define MZ_FWRITE fwrite -// #define MZ_FTELL64 ftello64 -// #define MZ_FSEEK64 fseeko64 -// #define MZ_FILE_STAT_STRUCT stat64 -// #define MZ_FILE_STAT stat64 -// #define MZ_FFLUSH fflush -// #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) -// #define MZ_DELETE_FILE remove -// #elif defined(__APPLE__) && _LARGEFILE64_SOURCE -// #ifndef MINIZ_NO_TIME -// #include -// #endif -// #define MZ_FOPEN(f, m) fopen(f, m) -// #define MZ_FCLOSE fclose -// #define MZ_FREAD fread -// #define MZ_FWRITE fwrite -// #define MZ_FTELL64 ftello -// #define MZ_FSEEK64 fseeko -// #define MZ_FILE_STAT_STRUCT stat -// #define MZ_FILE_STAT stat -// #define MZ_FFLUSH fflush -// #define MZ_FREOPEN(p, m, s) freopen(p, m, s) -// #define MZ_DELETE_FILE remove - -// #else -// // #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") -// #ifndef MINIZ_NO_TIME -// #include -// #endif -// #define MZ_FOPEN(f, m) fopen(f, m) -// #define MZ_FCLOSE fclose -// #define MZ_FREAD fread -// #define MZ_FWRITE fwrite -// #ifdef __STRICT_ANSI__ -// #define MZ_FTELL64 ftell -// #define MZ_FSEEK64 fseek -// #else -// #define MZ_FTELL64 ftello -// #define MZ_FSEEK64 fseeko -// #endif -// #define MZ_FILE_STAT_STRUCT stat -// #define MZ_FILE_STAT stat -// #define MZ_FFLUSH fflush -// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) -// #define MZ_DELETE_FILE remove -// #endif /* #ifdef _MSC_VER */ -// #endif /* #ifdef MINIZ_NO_STDIO */ - -// #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) - -/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ -// enum -// { -// /* ZIP archive identifiers and record sizes */ -// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, -// MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, -// MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, -// MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, -// MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, -// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, - -// /* ZIP64 archive identifier and record sizes */ -// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, -// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, -// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, -// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, -// MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, -// MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, -// MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, -// MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, - -// /* Central directory header record offsets */ -// MZ_ZIP_CDH_SIG_OFS = 0, -// MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, -// MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, -// MZ_ZIP_CDH_BIT_FLAG_OFS = 8, -// MZ_ZIP_CDH_METHOD_OFS = 10, -// MZ_ZIP_CDH_FILE_TIME_OFS = 12, -// MZ_ZIP_CDH_FILE_DATE_OFS = 14, -// MZ_ZIP_CDH_CRC32_OFS = 16, -// MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, -// MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, -// MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, -// MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, -// MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, -// MZ_ZIP_CDH_DISK_START_OFS = 34, -// MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, -// MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, -// MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, - -// /* Local directory header offsets */ -// MZ_ZIP_LDH_SIG_OFS = 0, -// MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, -// MZ_ZIP_LDH_BIT_FLAG_OFS = 6, -// MZ_ZIP_LDH_METHOD_OFS = 8, -// MZ_ZIP_LDH_FILE_TIME_OFS = 10, -// MZ_ZIP_LDH_FILE_DATE_OFS = 12, -// MZ_ZIP_LDH_CRC32_OFS = 14, -// MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, -// MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, -// MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, -// MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, -// MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, - -// /* End of central directory offsets */ -// MZ_ZIP_ECDH_SIG_OFS = 0, -// MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, -// MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, -// MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, -// MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, -// MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, -// MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, -// MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, - -// /* ZIP64 End of central directory locator offsets */ -// MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ -// MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ -// MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ -// MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ - -// /* ZIP64 End of central directory header offsets */ -// MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ -// MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ -// MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ -// MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ -// MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ -// MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ -// MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ -// MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ -// MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ -// MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ -// MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, -// MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, -// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, -// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, -// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, -// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, -// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 -// }; - -// typedef struct -// { -// void *m_p; -// size_t m_size, m_capacity; -// mz_uint m_element_size; -// } mz_zip_array; - -// struct mz_zip_internal_state_tag -// { -// mz_zip_array m_central_dir; -// mz_zip_array m_central_dir_offsets; -// mz_zip_array m_sorted_central_dir_offsets; - -// /* The flags passed in when the archive is initially opened. */ -// uint32_t m_init_flags; - -// /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ -// mz_bool m_zip64; - -// /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ -// mz_bool m_zip64_has_extended_info_fields; - -// /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ -// MZ_FILE *m_pFile; -// mz_uint64 m_file_archive_start_ofs; - -// void *m_pMem; -// size_t m_mem_size; -// size_t m_mem_capacity; -// }; - -// #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size - -// #if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) -// static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) -// { -// MZ_ASSERT(index < pArray->m_size); -// return index; -// } -// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] -// #else -// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] -// #endif - -// static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) -// { -// memset(pArray, 0, sizeof(mz_zip_array)); -// pArray->m_element_size = element_size; -// } - -// static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); -// memset(pArray, 0, sizeof(mz_zip_array)); -// } - -// static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) -// { -// void *pNew_p; -// size_t new_capacity = min_new_capacity; -// MZ_ASSERT(pArray->m_element_size); -// if (pArray->m_capacity >= min_new_capacity) -// return MZ_TRUE; -// if (growing) -// { -// new_capacity = MZ_MAX(1, pArray->m_capacity); -// while (new_capacity < min_new_capacity) -// new_capacity *= 2; -// } -// if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) -// return MZ_FALSE; -// pArray->m_p = pNew_p; -// pArray->m_capacity = new_capacity; -// return MZ_TRUE; -// } - -// static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) -// { -// if (new_capacity > pArray->m_capacity) -// { -// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) -// return MZ_FALSE; -// } -// return MZ_TRUE; -// } - -// static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) -// { -// if (new_size > pArray->m_capacity) -// { -// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) -// return MZ_FALSE; -// } -// pArray->m_size = new_size; -// return MZ_TRUE; -// } - -// static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) -// { -// return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); -// } - -// static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) -// { -// size_t orig_size = pArray->m_size; -// if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) -// return MZ_FALSE; -// memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); -// return MZ_TRUE; -// } - -// #ifndef MINIZ_NO_TIME -// static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) -// { -// struct tm tm; -// memset(&tm, 0, sizeof(tm)); -// tm.tm_isdst = -1; -// tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; -// tm.tm_mon = ((dos_date >> 5) & 15) - 1; -// tm.tm_mday = dos_date & 31; -// tm.tm_hour = (dos_time >> 11) & 31; -// tm.tm_min = (dos_time >> 5) & 63; -// tm.tm_sec = (dos_time << 1) & 62; -// return mktime(&tm); -// } - -// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -// static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) -// { -// #ifdef _MSC_VER -// struct tm tm_struct; -// struct tm *tm = &tm_struct; -// errno_t err = localtime_s(tm, &time_); -// if (err) -// { -// *pDOS_date = 0; -// *pDOS_time = 0; -// return; -// } -// #else -// struct tm *tm = localtime(&time_); -// #endif /* #ifdef _MSC_VER */ - -// *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); -// *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); -// } -// #endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ - -// #ifndef MINIZ_NO_STDIO -// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -// static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) -// { -// struct MZ_FILE_STAT_STRUCT file_stat; - -// /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ -// if (MZ_FILE_STAT(pFilename, &file_stat) != 0) -// return MZ_FALSE; - -// *pTime = file_stat.st_mtime; - -// return MZ_TRUE; -// } -// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ - -// static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) -// { -// struct utimbuf t; - -// memset(&t, 0, sizeof(t)); -// t.actime = access_time; -// t.modtime = modified_time; - -// return !utime(pFilename, &t); -// } -// #endif /* #ifndef MINIZ_NO_STDIO */ -// #endif /* #ifndef MINIZ_NO_TIME */ - -// static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) -// { -// if (pZip) -// pZip->m_last_error = err_num; -// return MZ_FALSE; -// } - -// static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) -// { -// (void)flags; -// if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (!pZip->m_pAlloc) -// pZip->m_pAlloc = miniz_def_alloc_func; -// if (!pZip->m_pFree) -// pZip->m_pFree = miniz_def_free_func; -// if (!pZip->m_pRealloc) -// pZip->m_pRealloc = miniz_def_realloc_func; - -// pZip->m_archive_size = 0; -// pZip->m_central_directory_file_ofs = 0; -// pZip->m_total_files = 0; -// pZip->m_last_error = MZ_ZIP_NO_ERROR; - -// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); -// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); -// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); -// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); -// pZip->m_pState->m_init_flags = flags; -// pZip->m_pState->m_zip64 = MZ_FALSE; -// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; - -// pZip->m_zip_mode = MZ_ZIP_MODE_READING; - -// return MZ_TRUE; -// } - -// static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) -// { -// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; -// const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); -// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// mz_uint8 l = 0, r = 0; -// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -// pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -// pE = pL + MZ_MIN(l_len, r_len); -// while (pL < pE) -// { -// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) -// break; -// pL++; -// pR++; -// } -// return (pL == pE) ? (l_len < r_len) : (l < r); -// } -/* -#define MZ_SWAP_UINT32(a, b) \ - do \ - { \ - mz_uint32 t = a; \ - a = b; \ - b = t; \ - } \ - MZ_MACRO_END -*/ -/* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */ -// static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) -// { -// mz_zip_internal_state *pState = pZip->m_pState; -// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; -// const mz_zip_array *pCentral_dir = &pState->m_central_dir; -// mz_uint32 *pIndices; -// mz_uint32 start, end; -// const mz_uint32 size = pZip->m_total_files; - -// if (size <= 1U) -// return; - -// pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); - -// start = (size - 2U) >> 1U; -// for (;;) -// { -// mz_uint64 child, root = start; -// for (;;) -// { -// if ((child = (root << 1U) + 1U) >= size) -// break; -// child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); -// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) -// break; -// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); -// root = child; -// } -// if (!start) -// break; -// start--; -// } - -// end = size - 1; -// while (end > 0) -// { -// mz_uint64 child, root = 0; -// MZ_SWAP_UINT32(pIndices[end], pIndices[0]); -// for (;;) -// { -// if ((child = (root << 1U) + 1U) >= end) -// break; -// child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); -// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) -// break; -// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); -// root = child; -// } -// end--; -// } -// } - -// static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) -// { -// mz_int64 cur_file_ofs; -// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; -// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; - -// /* Basic sanity checks - reject files which are too small */ -// if (pZip->m_archive_size < record_size) -// return MZ_FALSE; - -// /* Find the record by scanning the file from the end towards the beginning. */ -// cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); -// for (;;) -// { -// int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); - -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) -// return MZ_FALSE; - -// for (i = n - 4; i >= 0; --i) -// { -// mz_uint s = MZ_READ_LE32(pBuf + i); -// if (s == record_sig) -// { -// if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) -// break; -// } -// } - -// if (i >= 0) -// { -// cur_file_ofs += i; -// break; -// } - -// /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ -// if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) -// return MZ_FALSE; - -// cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); -// } - -// *pOfs = cur_file_ofs; -// return MZ_TRUE; -// } - -// static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) -// { -// mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; -// mz_uint64 cdir_ofs = 0; -// mz_int64 cur_file_ofs = 0; -// const mz_uint8 *p; - -// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; -// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; -// mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); -// mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -// mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; - -// mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -// mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; - -// mz_uint64 zip64_end_of_central_dir_ofs = 0; - -// /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ -// if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -// if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) -// return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); - -// /* Read and verify the end of central directory record. */ -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -// if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) -// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -// if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) -// { -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) -// { -// if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) -// { -// zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); -// if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) -// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -// if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) -// { -// if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) -// { -// pZip->m_pState->m_zip64 = MZ_TRUE; -// } -// } -// } -// } -// } - -// pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); -// cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); -// num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); -// cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); -// cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); -// cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); - -// if (pZip->m_pState->m_zip64) -// { -// mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); -// mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); -// mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); -// mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); -// mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); - -// if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if (zip64_total_num_of_disks != 1U) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -// /* Check for miniz's practical limits */ -// if (zip64_cdir_total_entries > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - -// pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; - -// if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - -// cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; - -// /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ -// if (zip64_size_of_central_directory > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -// cdir_size = (mz_uint32)zip64_size_of_central_directory; - -// num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); - -// cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); - -// cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); -// } - -// if (pZip->m_total_files != cdir_entries_on_this_disk) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -// if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -// if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// pZip->m_central_directory_file_ofs = cdir_ofs; - -// if (pZip->m_total_files) -// { -// mz_uint i, n; -// /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ -// if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || -// (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// if (sort_central_dir) -// { -// if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -// /* Now create an index into the central directory file records, do some basic sanity checking on each record */ -// p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; -// for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) -// { -// mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; -// mz_uint64 comp_size, decomp_size, local_header_ofs; - -// if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); - -// if (sort_central_dir) -// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; - -// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -// decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); -// local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); -// filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); - -// if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && -// (ext_data_size) && -// (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) -// { -// /* Attempt to find zip64 extended information field in the entry's extra data */ -// mz_uint32 extra_size_remaining = ext_data_size; - -// if (extra_size_remaining) -// { -// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; - -// do -// { -// mz_uint32 field_id; -// mz_uint32 field_data_size; - -// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// field_id = MZ_READ_LE16(pExtra_data); -// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); - -// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -// { -// /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ -// pZip->m_pState->m_zip64 = MZ_TRUE; -// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; -// break; -// } - -// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; -// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; -// } while (extra_size_remaining); -// } -// } - -// /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ -// if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) -// { -// if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// } - -// disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); -// if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -// if (comp_size != MZ_UINT32_MAX) -// { -// if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// } - -// bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -// if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - -// if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// n -= total_header_size; -// p += total_header_size; -// } -// } - -// if (sort_central_dir) -// mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); - -// return MZ_TRUE; -// } - -// void mz_zip_zero_struct(mz_zip_archive *pZip) -// { -// if (pZip) -// MZ_CLEAR_OBJ(*pZip); -// } - -// static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) -// { -// mz_bool status = MZ_TRUE; - -// if (!pZip) -// return MZ_FALSE; - -// if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) -// { -// if (set_last_error) -// pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; - -// return MZ_FALSE; -// } - -// if (pZip->m_pState) -// { -// mz_zip_internal_state *pState = pZip->m_pState; -// pZip->m_pState = NULL; - -// mz_zip_array_clear(pZip, &pState->m_central_dir); -// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); -// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); - -// #ifndef MINIZ_NO_STDIO -// if (pState->m_pFile) -// { -// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -// { -// if (MZ_FCLOSE(pState->m_pFile) == EOF) -// { -// if (set_last_error) -// pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; -// status = MZ_FALSE; -// } -// } -// pState->m_pFile = NULL; -// } -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// } -// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; - -// return status; -// } - -// mz_bool mz_zip_reader_end(mz_zip_archive *pZip) -// { -// return mz_zip_reader_end_internal(pZip, MZ_TRUE); -// } -// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) -// { -// if ((!pZip) || (!pZip->m_pRead)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (!mz_zip_reader_init_internal(pZip, flags)) -// return MZ_FALSE; - -// pZip->m_zip_type = MZ_ZIP_TYPE_USER; -// pZip->m_archive_size = size; - -// if (!mz_zip_reader_read_central_dir(pZip, flags)) -// { -// mz_zip_reader_end_internal(pZip, MZ_FALSE); -// return MZ_FALSE; -// } - -// return MZ_TRUE; -// } - -// static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -// { -// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -// size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); -// memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); -// return s; -// } - -// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) -// { -// if (!pMem) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -// if (!mz_zip_reader_init_internal(pZip, flags)) -// return MZ_FALSE; - -// pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; -// pZip->m_archive_size = size; -// pZip->m_pRead = mz_zip_mem_read_func; -// pZip->m_pIO_opaque = pZip; -// pZip->m_pNeeds_keepalive = NULL; - -// #ifdef __cplusplus -// pZip->m_pState->m_pMem = const_cast(pMem); -// #else -// pZip->m_pState->m_pMem = (void *)pMem; -// #endif - -// pZip->m_pState->m_mem_size = size; - -// if (!mz_zip_reader_read_central_dir(pZip, flags)) -// { -// mz_zip_reader_end_internal(pZip, MZ_FALSE); -// return MZ_FALSE; -// } - -// return MZ_TRUE; -// } - -// #ifndef MINIZ_NO_STDIO -// static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -// { -// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - -// file_ofs += pZip->m_pState->m_file_archive_start_ofs; - -// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) -// return 0; - -// return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); -// } - -// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) -// { -// return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); -// } - -// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) -// { -// mz_uint64 file_size; -// MZ_FILE *pFile; - -// if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pFile = MZ_FOPEN(pFilename, "rb"); -// if (!pFile) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -// file_size = archive_size; -// if (!file_size) -// { -// if (MZ_FSEEK64(pFile, 0, SEEK_END)) -// { -// MZ_FCLOSE(pFile); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); -// } - -// file_size = MZ_FTELL64(pFile); -// } - -// /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ - -// if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -// { -// MZ_FCLOSE(pFile); -// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -// } - -// if (!mz_zip_reader_init_internal(pZip, flags)) -// { -// MZ_FCLOSE(pFile); -// return MZ_FALSE; -// } - -// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; -// pZip->m_pRead = mz_zip_file_read_func; -// pZip->m_pIO_opaque = pZip; -// pZip->m_pState->m_pFile = pFile; -// pZip->m_archive_size = file_size; -// pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; - -// if (!mz_zip_reader_read_central_dir(pZip, flags)) -// { -// mz_zip_reader_end_internal(pZip, MZ_FALSE); -// return MZ_FALSE; -// } - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) -// { -// mz_uint64 cur_file_ofs; - -// if ((!pZip) || (!pFile)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -// cur_file_ofs = MZ_FTELL64(pFile); - -// if (!archive_size) -// { -// if (MZ_FSEEK64(pFile, 0, SEEK_END)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); - -// archive_size = MZ_FTELL64(pFile) - cur_file_ofs; - -// if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -// } - -// if (!mz_zip_reader_init_internal(pZip, flags)) -// return MZ_FALSE; - -// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; -// pZip->m_pRead = mz_zip_file_read_func; - -// pZip->m_pIO_opaque = pZip; -// pZip->m_pState->m_pFile = pFile; -// pZip->m_archive_size = archive_size; -// pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; - -// if (!mz_zip_reader_read_central_dir(pZip, flags)) -// { -// mz_zip_reader_end_internal(pZip, MZ_FALSE); -// return MZ_FALSE; -// } - -// return MZ_TRUE; -// } - -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) -// { -// if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) -// return NULL; -// return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); -// } - -// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) -// { -// mz_uint m_bit_flag; -// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -// if (!p) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// return MZ_FALSE; -// } - -// m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -// return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; -// } - -// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) -// { -// mz_uint bit_flag; -// mz_uint method; - -// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -// if (!p) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// return MZ_FALSE; -// } - -// method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); -// bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); - -// if ((method != 0) && (method != MZ_DEFLATED)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -// return MZ_FALSE; -// } - -// if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -// return MZ_FALSE; -// } - -// if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) -// { -// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); -// return MZ_FALSE; -// } - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) -// { -// mz_uint filename_len, attribute_mapping_id, external_attr; -// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -// if (!p) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// return MZ_FALSE; -// } - -// filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// if (filename_len) -// { -// if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') -// return MZ_TRUE; -// } - - /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */ - /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */ - /* FIXME: Remove this check? Is it necessary - we already check the filename. */ -// attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; -// (void)attribute_mapping_id; - -// external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); -// if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) -// { -// return MZ_TRUE; -// } - -// return MZ_FALSE; -// } - -// static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) -// { -// mz_uint n; -// const mz_uint8 *p = pCentral_dir_header; - -// if (pFound_zip64_extra_data) -// *pFound_zip64_extra_data = MZ_FALSE; - -// if ((!p) || (!pStat)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// /* Extract fields from the central directory record. */ -// pStat->m_file_index = file_index; -// pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); -// pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); -// pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); -// pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -// pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); -// #ifndef MINIZ_NO_TIME -// pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); -// #endif -// pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); -// pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -// pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); -// pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); -// pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); -// pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); - -// /* Copy as much of the filename and comment as possible. */ -// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); -// memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); -// pStat->m_filename[n] = '\0'; - -// n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); -// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); -// pStat->m_comment_size = n; -// memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); -// pStat->m_comment[n] = '\0'; - -// /* Set some flags for convienance */ -// pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); -// pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); -// pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); - -// /* See if we need to read any zip64 extended information fields. */ -// /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ -// if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) -// { -// /* Attempt to find zip64 extended information field in the entry's extra data */ -// mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); - -// if (extra_size_remaining) -// { -// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - -// do -// { -// mz_uint32 field_id; -// mz_uint32 field_data_size; - -// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// field_id = MZ_READ_LE16(pExtra_data); -// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); - -// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -// { -// const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; -// mz_uint32 field_data_remaining = field_data_size; - -// if (pFound_zip64_extra_data) -// *pFound_zip64_extra_data = MZ_TRUE; - -// if (pStat->m_uncomp_size == MZ_UINT32_MAX) -// { -// if (field_data_remaining < sizeof(mz_uint64)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// pStat->m_uncomp_size = MZ_READ_LE64(pField_data); -// pField_data += sizeof(mz_uint64); -// field_data_remaining -= sizeof(mz_uint64); -// } - -// if (pStat->m_comp_size == MZ_UINT32_MAX) -// { -// if (field_data_remaining < sizeof(mz_uint64)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// pStat->m_comp_size = MZ_READ_LE64(pField_data); -// pField_data += sizeof(mz_uint64); -// field_data_remaining -= sizeof(mz_uint64); -// } - -// if (pStat->m_local_header_ofs == MZ_UINT32_MAX) -// { -// if (field_data_remaining < sizeof(mz_uint64)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); -// pField_data += sizeof(mz_uint64); -// // field_data_remaining -= sizeof(mz_uint64); -// } - -// break; -// } - -// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; -// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; -// } while (extra_size_remaining); -// } -// } - -// return MZ_TRUE; -// } - -// static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) -// { -// mz_uint i; -// if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) -// return 0 == memcmp(pA, pB, len); -// for (i = 0; i < len; ++i) -// if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) -// return MZ_FALSE; -// return MZ_TRUE; -// } - -// static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) -// { -// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; -// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// mz_uint8 l = 0, r = 0; -// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -// pE = pL + MZ_MIN(l_len, r_len); -// while (pL < pE) -// { -// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) -// break; -// pL++; -// pR++; -// } -// return (pL == pE) ? (int)(l_len - r_len) : (l - r); -// } - -// static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) -// { -// mz_zip_internal_state *pState = pZip->m_pState; -// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; -// const mz_zip_array *pCentral_dir = &pState->m_central_dir; -// mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); -// const uint32_t size = pZip->m_total_files; -// const mz_uint filename_len = (mz_uint)strlen(pFilename); - -// if (pIndex) -// *pIndex = 0; - -// if (size) -// { -// /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ -// /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ -// mz_int64 l = 0, h = (mz_int64)size - 1; - -// while (l <= h) -// { -// mz_int64 m = l + ((h - l) >> 1); -// uint32_t file_index = pIndices[(uint32_t)m]; - -// int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); -// if (!comp) -// { -// if (pIndex) -// *pIndex = file_index; -// return MZ_TRUE; -// } -// else if (comp < 0) -// l = m + 1; -// else -// h = m - 1; -// } -// } - -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); -// } - -// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) -// { -// mz_uint32 index_; -// if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) -// return -1; -// else -// return (int)index_; -// } - -// mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) -// { -// mz_uint file_index; -// size_t name_len, comment_len; - -// if (pIndex) -// *pIndex = 0; - -// if ((!pZip) || (!pZip->m_pState) || (!pName)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// /* See if we can use a binary search */ -// if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && -// (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && -// ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) -// { -// return mz_zip_locate_file_binary_search(pZip, pName, pIndex); -// } - -// /* Locate the entry by scanning the entire central directory */ -// name_len = strlen(pName); -// if (name_len > MZ_UINT16_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// comment_len = pComment ? strlen(pComment) : 0; -// if (comment_len > MZ_UINT16_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// for (file_index = 0; file_index < pZip->m_total_files; file_index++) -// { -// const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); -// mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -// if (filename_len < name_len) -// continue; -// if (comment_len) -// { -// mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); -// const char *pFile_comment = pFilename + filename_len + file_extra_len; -// if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) -// continue; -// } -// if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) -// { -// int ofs = filename_len - 1; -// do -// { -// if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) -// break; -// } while (--ofs >= 0); -// ofs++; -// pFilename += ofs; -// filename_len -= ofs; -// } -// if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) -// { -// if (pIndex) -// *pIndex = file_index; -// return MZ_TRUE; -// } -// } - -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); -// } - -// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -// { -// int status = TINFL_STATUS_DONE; -// mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; -// mz_zip_archive_file_stat file_stat; -// void *pRead_buf; -// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -// tinfl_decompressor inflator; - -// if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -// return MZ_FALSE; - -// /* A directory or zero length file */ -// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) -// return MZ_TRUE; - -// /* Encryption and patch files are not supported. */ -// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - -// /* This function only supports decompressing stored and deflate. */ -// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); - -// /* Ensure supplied output buffer is large enough. */ -// needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; -// if (buf_size < needed_size) -// return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); - -// /* Read and parse the local directory entry. */ -// cur_file_ofs = file_stat.m_local_header_ofs; -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) -// { -// /* The file is stored or the caller has requested the compressed data. */ -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) -// { -// if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) -// return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); -// } -// #endif - -// return MZ_TRUE; -// } - -// /* Decompress the file either directly from memory or from a file input buffer. */ -// tinfl_init(&inflator); - -// if (pZip->m_pState->m_pMem) -// { -// /* Read directly from the archive in memory. */ -// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; -// read_buf_size = read_buf_avail = file_stat.m_comp_size; -// comp_remaining = 0; -// } -// else if (pUser_read_buf) -// { -// /* Use a user provided read buffer. */ -// if (!user_read_buf_size) -// return MZ_FALSE; -// pRead_buf = (mz_uint8 *)pUser_read_buf; -// read_buf_size = user_read_buf_size; -// read_buf_avail = 0; -// comp_remaining = file_stat.m_comp_size; -// } -// else -// { -// /* Temporarily allocate a read buffer. */ -// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -// if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// read_buf_avail = 0; -// comp_remaining = file_stat.m_comp_size; -// } - -// do -// { -// /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ -// size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); -// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) -// { -// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -// { -// status = TINFL_STATUS_FAILED; -// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -// break; -// } -// cur_file_ofs += read_buf_avail; -// comp_remaining -= read_buf_avail; -// read_buf_ofs = 0; -// } -// in_buf_size = (size_t)read_buf_avail; -// status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); -// read_buf_avail -= in_buf_size; -// read_buf_ofs += in_buf_size; -// out_buf_ofs += out_buf_size; -// } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); - -// if (status == TINFL_STATUS_DONE) -// { -// /* Make sure the entire file was decompressed, and check its CRC. */ -// if (out_buf_ofs != file_stat.m_uncomp_size) -// { -// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -// status = TINFL_STATUS_FAILED; -// } -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) -// { -// mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); -// status = TINFL_STATUS_FAILED; -// } -// #endif -// } - -// if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) -// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - -// return status == TINFL_STATUS_DONE; -// } - -// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -// { -// mz_uint32 file_index; -// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -// return MZ_FALSE; -// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); -// } - -// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) -// { -// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); -// } - -// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) -// { -// return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); -// } - -// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) -// { -// mz_uint64 comp_size, uncomp_size, alloc_size; -// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -// void *pBuf; - -// if (pSize) -// *pSize = 0; - -// if (!p) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// return NULL; -// } - -// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -// uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - -// alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; -// if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -// return NULL; -// } - -// if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) -// { -// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// return NULL; -// } - -// if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -// return NULL; -// } - -// if (pSize) -// *pSize = (size_t)alloc_size; -// return pBuf; -// } - -// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) -// { -// mz_uint32 file_index; -// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -// { -// if (pSize) -// *pSize = 0; -// return MZ_FALSE; -// } -// return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); -// } - -// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -// { -// int status = TINFL_STATUS_DONE; -// mz_uint file_crc32 = MZ_CRC32_INIT; -// mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; -// mz_zip_archive_file_stat file_stat; -// void *pRead_buf = NULL; -// void *pWrite_buf = NULL; -// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - -// if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -// return MZ_FALSE; - -// /* A directory or zero length file */ -// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) -// return MZ_TRUE; - -// /* Encryption and patch files are not supported. */ -// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - -// /* This function only supports decompressing stored and deflate. */ -// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); - -// /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ -// cur_file_ofs = file_stat.m_local_header_ofs; -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// /* Decompress the file either directly from memory or from a file input buffer. */ -// if (pZip->m_pState->m_pMem) -// { -// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; -// read_buf_size = read_buf_avail = file_stat.m_comp_size; -// comp_remaining = 0; -// } -// else -// { -// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// read_buf_avail = 0; -// comp_remaining = file_stat.m_comp_size; -// } - -// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) -// { -// /* The file is stored or the caller has requested the compressed data. */ -// if (pZip->m_pState->m_pMem) -// { -// if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) -// { -// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -// status = TINFL_STATUS_FAILED; -// } -// else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -// { -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); -// #endif -// } - -// cur_file_ofs += file_stat.m_comp_size; -// out_buf_ofs += file_stat.m_comp_size; -// comp_remaining = 0; -// } -// else -// { -// while (comp_remaining) -// { -// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// status = TINFL_STATUS_FAILED; -// break; -// } - -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -// { -// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); -// } -// #endif - -// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -// { -// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -// status = TINFL_STATUS_FAILED; -// break; -// } - -// cur_file_ofs += read_buf_avail; -// out_buf_ofs += read_buf_avail; -// comp_remaining -= read_buf_avail; -// } -// } -// } -// else -// { -// tinfl_decompressor inflator; -// tinfl_init(&inflator); - -// if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) -// { -// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// status = TINFL_STATUS_FAILED; -// } -// else -// { -// do -// { -// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) -// { -// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// status = TINFL_STATUS_FAILED; -// break; -// } -// cur_file_ofs += read_buf_avail; -// comp_remaining -= read_buf_avail; -// read_buf_ofs = 0; -// } - -// in_buf_size = (size_t)read_buf_avail; -// status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); -// read_buf_avail -= in_buf_size; -// read_buf_ofs += in_buf_size; - -// if (out_buf_size) -// { -// if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) -// { -// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -// status = TINFL_STATUS_FAILED; -// break; -// } - -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); -// #endif -// if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) -// { -// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -// status = TINFL_STATUS_FAILED; -// break; -// } -// } -// } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); -// } -// } - -// if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -// { -// /* Make sure the entire file was decompressed, and check its CRC. */ -// if (out_buf_ofs != file_stat.m_uncomp_size) -// { -// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -// status = TINFL_STATUS_FAILED; -// } -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// else if (file_crc32 != file_stat.m_crc32) -// { -// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -// status = TINFL_STATUS_FAILED; -// } -// #endif -// } - -// if (!pZip->m_pState->m_pMem) -// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - -// if (pWrite_buf) -// pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); - -// return status == TINFL_STATUS_DONE; -// } - -// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -// { -// mz_uint32 file_index; -// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -// return MZ_FALSE; - -// return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); -// } - -// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) -// { -// mz_zip_reader_extract_iter_state *pState; -// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - -// /* Argument sanity check */ -// if ((!pZip) || (!pZip->m_pState)) -// return NULL; - -// /* Allocate an iterator status structure */ -// pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); -// if (!pState) -// { -// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// return NULL; -// } - -// /* Fetch file details */ -// if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } - -// /* Encryption and patch files are not supported. */ -// if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } - -// /* This function only supports decompressing stored and deflate. */ -// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } - -// /* Init state - save args */ -// pState->pZip = pZip; -// pState->flags = flags; - -// /* Init state - reset variables to defaults */ -// pState->status = TINFL_STATUS_DONE; -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// pState->file_crc32 = MZ_CRC32_INIT; -// #endif -// pState->read_buf_ofs = 0; -// pState->out_buf_ofs = 0; -// pState->pRead_buf = NULL; -// pState->pWrite_buf = NULL; -// pState->out_blk_remain = 0; - -// /* Read and parse the local directory entry. */ -// pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; -// if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } - -// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } - -// pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -// if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } - -// /* Decompress the file either directly from memory or from a file input buffer. */ -// if (pZip->m_pState->m_pMem) -// { -// pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; -// pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; -// pState->comp_remaining = pState->file_stat.m_comp_size; -// } -// else -// { -// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) -// { -// /* Decompression required, therefore intermediate read buffer required */ -// pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); -// if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) -// { -// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } -// } -// else -// { -// /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ -// pState->read_buf_size = 0; -// } -// pState->read_buf_avail = 0; -// pState->comp_remaining = pState->file_stat.m_comp_size; -// } - -// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) -// { -// /* Decompression required, init decompressor */ -// tinfl_init( &pState->inflator ); - -// /* Allocate write buffer */ -// if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) -// { -// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// if (pState->pRead_buf) -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } -// } - -// return pState; -// } - -// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) -// { -// mz_uint32 file_index; - -// /* Locate file index by name */ -// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -// return NULL; - -// /* Construct iterator */ -// return mz_zip_reader_extract_iter_new(pZip, file_index, flags); -// } - -// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) -// { -// size_t copied_to_caller = 0; - -// /* Argument sanity check */ -// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) -// return 0; - -// if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) -// { -// /* The file is stored or the caller has requested the compressed data, calc amount to return. */ -// copied_to_caller = MZ_MIN( buf_size, pState->comp_remaining ); - -// /* Zip is in memory....or requires reading from a file? */ -// if (pState->pZip->m_pState->m_pMem) -// { -// /* Copy data to caller's buffer */ -// memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); -// pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; -// } -// else -// { -// /* Read directly into caller's buffer */ -// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) -// { -// /* Failed to read all that was asked for, flag failure and alert user */ -// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); -// pState->status = TINFL_STATUS_FAILED; -// copied_to_caller = 0; -// } -// } - -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// /* Compute CRC if not returning compressed data only */ -// if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); -// #endif - -// /* Advance offsets, dec counters */ -// pState->cur_file_ofs += copied_to_caller; -// pState->out_buf_ofs += copied_to_caller; -// pState->comp_remaining -= copied_to_caller; -// } -// else -// { -// do -// { -// /* Calc ptr to write buffer - given current output pos and block size */ -// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - -// /* Calc max output size - given current output pos and block size */ -// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - -// if (!pState->out_blk_remain) -// { -// /* Read more data from file if none available (and reading from file) */ -// if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) -// { -// /* Calc read size */ -// pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); -// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) -// { -// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); -// pState->status = TINFL_STATUS_FAILED; -// break; -// } - -// /* Advance offsets, dec counters */ -// pState->cur_file_ofs += pState->read_buf_avail; -// pState->comp_remaining -= pState->read_buf_avail; -// pState->read_buf_ofs = 0; -// } - -// /* Perform decompression */ -// in_buf_size = (size_t)pState->read_buf_avail; -// pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); -// pState->read_buf_avail -= in_buf_size; -// pState->read_buf_ofs += in_buf_size; - -// /* Update current output block size remaining */ -// pState->out_blk_remain = out_buf_size; -// } - -// if (pState->out_blk_remain) -// { -// /* Calc amount to return. */ -// size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); - -// /* Copy data to caller's buffer */ -// memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); - -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// /* Perform CRC */ -// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); -// #endif - -// /* Decrement data consumed from block */ -// pState->out_blk_remain -= to_copy; - -// /* Inc output offset, while performing sanity check */ -// if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) -// { -// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); -// pState->status = TINFL_STATUS_FAILED; -// break; -// } - -// /* Increment counter of data copied to caller */ -// copied_to_caller += to_copy; -// } -// } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); -// } - -// /* Return how many bytes were copied into user buffer */ -// return copied_to_caller; -// } - -// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) -// { -// int status; - -// /* Argument sanity check */ -// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) -// return MZ_FALSE; - -// /* Was decompression completed and requested? */ -// if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -// { -// /* Make sure the entire file was decompressed, and check its CRC. */ -// if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) -// { -// mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -// pState->status = TINFL_STATUS_FAILED; -// } -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// else if (pState->file_crc32 != pState->file_stat.m_crc32) -// { -// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); -// pState->status = TINFL_STATUS_FAILED; -// } -// #endif -// } - -// /* Free buffers */ -// if (!pState->pZip->m_pState->m_pMem) -// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); -// if (pState->pWrite_buf) -// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); - -// /* Save status */ -// status = pState->status; - -// /* Free context */ -// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); - -// return status == TINFL_STATUS_DONE; -// } - -// #ifndef MINIZ_NO_STDIO -// static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) -// { -// (void)ofs; - -// return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); -// } - -// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) -// { -// mz_bool status; -// mz_zip_archive_file_stat file_stat; -// MZ_FILE *pFile; - -// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -// return MZ_FALSE; - -// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); - -// pFile = MZ_FOPEN(pDst_filename, "wb"); -// if (!pFile) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -// status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); - -// if (MZ_FCLOSE(pFile) == EOF) -// { -// if (status) -// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); - -// status = MZ_FALSE; -// } - -// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) -// if (status) -// mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); -// #endif - -// return status; -// } - -// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) -// { -// mz_uint32 file_index; -// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) -// return MZ_FALSE; - -// return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); -// } - -// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) -// { -// mz_zip_archive_file_stat file_stat; - -// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -// return MZ_FALSE; - -// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); - -// return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); -// } - -// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) -// { -// mz_uint32 file_index; -// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) -// return MZ_FALSE; - -// return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); -// } -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -// { -// mz_uint32 *p = (mz_uint32 *)pOpaque; -// (void)file_ofs; -// *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n); -// return n; -// } - -// mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) -// { -// mz_zip_archive_file_stat file_stat; -// mz_zip_internal_state *pState; -// const mz_uint8 *pCentral_dir_header; -// mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE; -// mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; -// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -// mz_uint64 local_header_ofs = 0; -// mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32; -// mz_uint64 local_header_comp_size, local_header_uncomp_size; -// mz_uint32 uncomp_crc32 = MZ_CRC32_INIT; -// mz_bool has_data_descriptor; -// mz_uint32 local_header_bit_flags; - -// mz_zip_array file_data_array; -// mz_zip_array_init(&file_data_array, 1); - -// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (file_index > pZip->m_total_files) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pState = pZip->m_pState; - -// pCentral_dir_header = mz_zip_get_cdh(pZip, file_index); - -// if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir)) -// return MZ_FALSE; - -// /* A directory or zero length file */ -// if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size)) -// return MZ_TRUE; - -// /* Encryption and patch files are not supported. */ -// if (file_stat.m_is_encrypted) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - -// /* This function only supports stored and deflate. */ -// if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); - -// if (!file_stat.m_is_supported) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); - -// /* Read and parse the local directory entry. */ -// local_header_ofs = file_stat.m_local_header_ofs; -// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); -// local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -// local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); -// local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); -// local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS); -// local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); -// has_data_descriptor = (local_header_bit_flags & 8) != 0; - -// if (local_header_filename_len != strlen(file_stat.m_filename)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size) > pZip->m_archive_size) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if (!mz_zip_array_resize(pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE)) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// if (local_header_filename_len) -// { -// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE, file_data_array.m_p, local_header_filename_len) != local_header_filename_len) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// goto handle_failure; -// } - -// /* I've seen 1 archive that had the same pathname, but used backslashes in the local dir and forward slashes in the central dir. Do we care about this? For now, this case will fail validation. */ -// if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0) -// { -// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); -// goto handle_failure; -// } -// } - -// if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) -// { -// mz_uint32 extra_size_remaining = local_header_extra_len; -// const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p; - -// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// goto handle_failure; -// } - -// do -// { -// mz_uint32 field_id, field_data_size, field_total_size; - -// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// field_id = MZ_READ_LE16(pExtra_data); -// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); -// field_total_size = field_data_size + sizeof(mz_uint16) * 2; - -// if (field_total_size > extra_size_remaining) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -// { -// const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); - -// if (field_data_size < sizeof(mz_uint64) * 2) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// goto handle_failure; -// } - -// local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); -// local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); - -// found_zip64_ext_data_in_ldir = MZ_TRUE; -// break; -// } - -// pExtra_data += field_total_size; -// extra_size_remaining -= field_total_size; -// } while (extra_size_remaining); -// } - -// /* TODO: parse local header extra data when local_header_comp_size is 0xFFFFFFFF! (big_descriptor.zip) */ -// /* I've seen zips in the wild with the data descriptor bit set, but proper local header values and bogus data descriptors */ -// if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32)) -// { -// mz_uint8 descriptor_buf[32]; -// mz_bool has_id; -// const mz_uint8 *pSrc; -// mz_uint32 file_crc32; -// mz_uint64 comp_size = 0, uncomp_size = 0; - -// mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4; - -// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size, descriptor_buf, sizeof(mz_uint32) * num_descriptor_uint32s) != (sizeof(mz_uint32) * num_descriptor_uint32s)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// goto handle_failure; -// } - -// has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID); -// pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf; - -// file_crc32 = MZ_READ_LE32(pSrc); - -// if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) -// { -// comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32)); -// uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64)); -// } -// else -// { -// comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32)); -// uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32)); -// } - -// if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); -// goto handle_failure; -// } -// } -// else -// { -// if ((local_header_crc32 != file_stat.m_crc32) || (local_header_comp_size != file_stat.m_comp_size) || (local_header_uncomp_size != file_stat.m_uncomp_size)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); -// goto handle_failure; -// } -// } - -// mz_zip_array_clear(pZip, &file_data_array); - -// if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0) -// { -// if (!mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0)) -// return MZ_FALSE; - -// /* 1 more check to be sure, although the extract checks too. */ -// if (uncomp_crc32 != file_stat.m_crc32) -// { -// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); -// return MZ_FALSE; -// } -// } - -// return MZ_TRUE; - -// handle_failure: -// mz_zip_array_clear(pZip, &file_data_array); -// return MZ_FALSE; -// } - -// mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) -// { -// mz_zip_internal_state *pState; -// uint32_t i; - -// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pState = pZip->m_pState; - -// /* Basic sanity checks */ -// if (!pState->m_zip64) -// { -// if (pZip->m_total_files > MZ_UINT16_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -// if (pZip->m_archive_size > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -// } -// else -// { -// if (pZip->m_total_files >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -// if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -// } - -// for (i = 0; i < pZip->m_total_files; i++) -// { -// if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) -// { -// mz_uint32 found_index; -// mz_zip_archive_file_stat stat_; - -// if (!mz_zip_reader_file_stat(pZip, i, &stat_)) -// return MZ_FALSE; - -// if (!mz_zip_reader_locate_file_v2(pZip, stat_.m_filename, NULL, 0, &found_index)) -// return MZ_FALSE; - -// /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ -// if (found_index != i) -// return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); -// } - -// if (!mz_zip_validate_file(pZip, i, flags)) -// return MZ_FALSE; -// } - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr) -// { -// mz_bool success = MZ_TRUE; -// mz_zip_archive zip; -// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; - -// if ((!pMem) || (!size)) -// { -// if (pErr) -// *pErr = MZ_ZIP_INVALID_PARAMETER; -// return MZ_FALSE; -// } - -// mz_zip_zero_struct(&zip); - -// if (!mz_zip_reader_init_mem(&zip, pMem, size, flags)) -// { -// if (pErr) -// *pErr = zip.m_last_error; -// return MZ_FALSE; -// } - -// if (!mz_zip_validate_archive(&zip, flags)) -// { -// actual_err = zip.m_last_error; -// success = MZ_FALSE; -// } - -// if (!mz_zip_reader_end_internal(&zip, success)) -// { -// if (!actual_err) -// actual_err = zip.m_last_error; -// success = MZ_FALSE; -// } - -// if (pErr) -// *pErr = actual_err; - -// return success; -// } - -// #ifndef MINIZ_NO_STDIO -// mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr) -// { -// mz_bool success = MZ_TRUE; -// mz_zip_archive zip; -// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; - -// if (!pFilename) -// { -// if (pErr) -// *pErr = MZ_ZIP_INVALID_PARAMETER; -// return MZ_FALSE; -// } - -// mz_zip_zero_struct(&zip); - -// if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0)) -// { -// if (pErr) -// *pErr = zip.m_last_error; -// return MZ_FALSE; -// } - -// if (!mz_zip_validate_archive(&zip, flags)) -// { -// actual_err = zip.m_last_error; -// success = MZ_FALSE; -// } - -// if (!mz_zip_reader_end_internal(&zip, success)) -// { -// if (!actual_err) -// actual_err = zip.m_last_error; -// success = MZ_FALSE; -// } - -// if (pErr) -// *pErr = actual_err; - -// return success; -// } -// #endif /* #ifndef MINIZ_NO_STDIO */ - -/* ------------------- .ZIP archive writing */ - -// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - -// static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) -// { -// p[0] = (mz_uint8)v; -// p[1] = (mz_uint8)(v >> 8); -// } -// static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) -// { -// p[0] = (mz_uint8)v; -// p[1] = (mz_uint8)(v >> 8); -// p[2] = (mz_uint8)(v >> 16); -// p[3] = (mz_uint8)(v >> 24); -// } -// static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) -// { -// mz_write_le32(p, (mz_uint32)v); -// mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); -// } - -// #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) -// #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) -// #define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) - -// static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -// { -// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -// mz_zip_internal_state *pState = pZip->m_pState; -// mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); - -// if (!n) -// return 0; - -// /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ -// if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -// return 0; -// } - -// if (new_size > pState->m_mem_capacity) -// { -// void *pNew_block; -// size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); - -// while (new_capacity < new_size) -// new_capacity *= 2; - -// if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) -// { -// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// return 0; -// } - -// pState->m_pMem = pNew_block; -// pState->m_mem_capacity = new_capacity; -// } -// memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); -// pState->m_mem_size = (size_t)new_size; -// return n; -// } - -// static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) -// { -// mz_zip_internal_state *pState; -// mz_bool status = MZ_TRUE; - -// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) -// { -// if (set_last_error) -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// return MZ_FALSE; -// } - -// pState = pZip->m_pState; -// pZip->m_pState = NULL; -// mz_zip_array_clear(pZip, &pState->m_central_dir); -// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); -// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); - -// #ifndef MINIZ_NO_STDIO -// if (pState->m_pFile) -// { -// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -// { -// if (MZ_FCLOSE(pState->m_pFile) == EOF) -// { -// if (set_last_error) -// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); -// status = MZ_FALSE; -// } -// } - -// pState->m_pFile = NULL; -// } -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); -// pState->m_pMem = NULL; -// } - -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; -// return status; -// } - -// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) -// { -// mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; - -// if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -// { -// if (!pZip->m_pRead) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// } - -// if (pZip->m_file_offset_alignment) -// { -// /* Ensure user specified file offset alignment is a power of 2. */ -// if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// } - -// if (!pZip->m_pAlloc) -// pZip->m_pAlloc = miniz_def_alloc_func; -// if (!pZip->m_pFree) -// pZip->m_pFree = miniz_def_free_func; -// if (!pZip->m_pRealloc) -// pZip->m_pRealloc = miniz_def_realloc_func; - -// pZip->m_archive_size = existing_size; -// pZip->m_central_directory_file_ofs = 0; -// pZip->m_total_files = 0; - -// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); - -// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); -// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); -// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); - -// pZip->m_pState->m_zip64 = zip64; -// pZip->m_pState->m_zip64_has_extended_info_fields = zip64; - -// pZip->m_zip_type = MZ_ZIP_TYPE_USER; -// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) -// { -// return mz_zip_writer_init_v2(pZip, existing_size, 0); -// } - -// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) -// { -// pZip->m_pWrite = mz_zip_heap_write_func; -// pZip->m_pNeeds_keepalive = NULL; - -// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -// pZip->m_pRead = mz_zip_mem_read_func; - -// pZip->m_pIO_opaque = pZip; - -// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) -// return MZ_FALSE; - -// pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; - -// if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) -// { -// if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) -// { -// mz_zip_writer_end_internal(pZip, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } -// pZip->m_pState->m_mem_capacity = initial_allocation_size; -// } - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) -// { -// return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); -// } - -// #ifndef MINIZ_NO_STDIO -// static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -// { -// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - -// file_ofs += pZip->m_pState->m_file_archive_start_ofs; - -// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); -// return 0; -// } - -// return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); -// } - -// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) -// { -// return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); -// } - -// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) -// { -// MZ_FILE *pFile; - -// pZip->m_pWrite = mz_zip_file_write_func; -// pZip->m_pNeeds_keepalive = NULL; - -// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -// pZip->m_pRead = mz_zip_file_read_func; - -// pZip->m_pIO_opaque = pZip; - -// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) -// return MZ_FALSE; - -// if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) -// { -// mz_zip_writer_end(pZip); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -// } - -// pZip->m_pState->m_pFile = pFile; -// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; - -// if (size_to_reserve_at_beginning) -// { -// mz_uint64 cur_ofs = 0; -// char buf[4096]; - -// MZ_CLEAR_OBJ(buf); - -// do -// { -// size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) -// { -// mz_zip_writer_end(pZip); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } -// cur_ofs += n; -// size_to_reserve_at_beginning -= n; -// } while (size_to_reserve_at_beginning); -// } - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) -// { -// pZip->m_pWrite = mz_zip_file_write_func; -// pZip->m_pNeeds_keepalive = NULL; - -// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -// pZip->m_pRead = mz_zip_file_read_func; - -// pZip->m_pIO_opaque = pZip; - -// if (!mz_zip_writer_init_v2(pZip, 0, flags)) -// return MZ_FALSE; - -// pZip->m_pState->m_pFile = pFile; -// pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); -// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; - -// return MZ_TRUE; -// } -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) -// { -// mz_zip_internal_state *pState; - -// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) -// { -// /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ -// if (!pZip->m_pState->m_zip64) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// } - -// /* No sense in trying to write to an archive that's already at the support max size */ -// if (pZip->m_pState->m_zip64) -// { -// if (pZip->m_total_files == MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -// } -// else -// { -// if (pZip->m_total_files == MZ_UINT16_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - -// if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -// } - -// pState = pZip->m_pState; - -// if (pState->m_pFile) -// { -// #ifdef MINIZ_NO_STDIO -// (void)pFilename; -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// #else -// if (pZip->m_pIO_opaque != pZip) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -// { -// if (!pFilename) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ -// if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) -// { -// /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ -// mz_zip_reader_end_internal(pZip, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -// } -// } - -// pZip->m_pWrite = mz_zip_file_write_func; -// pZip->m_pNeeds_keepalive = NULL; -// #endif /* #ifdef MINIZ_NO_STDIO */ -// } -// else if (pState->m_pMem) -// { -// /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ -// if (pZip->m_pIO_opaque != pZip) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pState->m_mem_capacity = pState->m_mem_size; -// pZip->m_pWrite = mz_zip_heap_write_func; -// pZip->m_pNeeds_keepalive = NULL; -// } -// /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ -// else if (!pZip->m_pWrite) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// /* Start writing new files at the archive's current central directory location. */ -// /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ -// pZip->m_archive_size = pZip->m_central_directory_file_ofs; -// pZip->m_central_directory_file_ofs = 0; - -// /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ -// /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ -// /* TODO: We could easily maintain the sorted central directory offsets. */ -// mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); - -// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) -// { -// return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); -// } - -/* TODO: pArchive_name is a terrible name here! */ -// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) -// { -// return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); -// } - -// typedef struct -// { -// mz_zip_archive *m_pZip; -// mz_uint64 m_cur_archive_file_ofs; -// mz_uint64 m_comp_size; -// } mz_zip_writer_add_state; - -// static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) -// { -// mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; -// if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) -// return MZ_FALSE; - -// pState->m_cur_archive_file_ofs += len; -// pState->m_comp_size += len; -// return MZ_TRUE; -// } - -// #define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) -// #define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) -// static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) -// { -// mz_uint8 *pDst = pBuf; -// mz_uint32 field_size = 0; - -// MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); -// MZ_WRITE_LE16(pDst + 2, 0); -// pDst += sizeof(mz_uint16) * 2; - -// if (pUncomp_size) -// { -// MZ_WRITE_LE64(pDst, *pUncomp_size); -// pDst += sizeof(mz_uint64); -// field_size += sizeof(mz_uint64); -// } - -// if (pComp_size) -// { -// MZ_WRITE_LE64(pDst, *pComp_size); -// pDst += sizeof(mz_uint64); -// field_size += sizeof(mz_uint64); -// } - -// if (pLocal_header_ofs) -// { -// MZ_WRITE_LE64(pDst, *pLocal_header_ofs); -// pDst += sizeof(mz_uint64); -// field_size += sizeof(mz_uint64); -// } - -// MZ_WRITE_LE16(pBuf + 2, field_size); - -// return (mz_uint32)(pDst - pBuf); -// } - -// static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) -// { -// (void)pZip; -// memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); -// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); -// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); -// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); -// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); -// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); -// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); -// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); -// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); -// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); -// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); -// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); -// return MZ_TRUE; -// } - -// static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, -// mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, -// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, -// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, -// mz_uint64 local_header_ofs, mz_uint32 ext_attributes) -// { -// (void)pZip; -// memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); -// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); -// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); -// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); -// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); -// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); -// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); -// return MZ_TRUE; -// } - -// static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, -// const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, -// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, -// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, -// mz_uint64 local_header_ofs, mz_uint32 ext_attributes, -// const char *user_extra_data, mz_uint user_extra_data_len) -// { -// mz_zip_internal_state *pState = pZip->m_pState; -// mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; -// size_t orig_central_dir_size = pState->m_central_dir.m_size; -// mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; - -// if (!pZip->m_pState->m_zip64) -// { -// if (local_header_ofs > 0xFFFFFFFF) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -// } - -// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -// if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size + user_extra_data_len, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -// if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || -// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || -// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || -// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || -// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || -// (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) -// { -// /* Try to resize the central directory array back into its original state. */ -// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// return MZ_TRUE; -// } - -// static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) -// { -// /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ -// if (*pArchive_name == '/') -// return MZ_FALSE; - -// while (*pArchive_name) -// { -// if ((*pArchive_name == '\\') || (*pArchive_name == ':')) -// return MZ_FALSE; - -// pArchive_name++; -// } - -// return MZ_TRUE; -// } - -// static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) -// { -// mz_uint32 n; -// if (!pZip->m_file_offset_alignment) -// return 0; -// n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); -// return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); -// } - -// static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) -// { -// char buf[4096]; -// memset(buf, 0, MZ_MIN(sizeof(buf), n)); -// while (n) -// { -// mz_uint32 s = MZ_MIN(sizeof(buf), n); -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_file_ofs += s; -// n -= s; -// } -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) -// { -// return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); -// } - -// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, -// mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, -// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) -// { -// if(!pZip) -// { -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// } - -// mz_uint16 method = 0, dos_time = 0, dos_date = 0; -// mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; -// mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; -// size_t archive_name_size; -// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; -// tdefl_compressor *pComp = NULL; -// mz_bool store_data_uncompressed; -// mz_zip_internal_state *pState; -// mz_uint8 *pExtra_data = NULL; -// mz_uint32 extra_size = 0; -// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; -// mz_uint16 bit_flags = 0; - -// if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -// bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; - -// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) -// bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; - -// if ((int)level_and_flags < 0) -// level_and_flags = MZ_DEFAULT_LEVEL; -// level = level_and_flags & 0xF; -// store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); - -// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pState = pZip->m_pState; - -// if (pState->m_zip64) -// { -// if (pZip->m_total_files == MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -// } -// else -// { -// if (pZip->m_total_files == MZ_UINT16_MAX) -// { -// pState->m_zip64 = MZ_TRUE; -// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ -// } -// if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) -// { -// pState->m_zip64 = MZ_TRUE; -// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -// } -// } - -// if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (!mz_zip_writer_validate_archive_name(pArchive_name)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - -// #ifndef MINIZ_NO_TIME -// if (last_modified != NULL) -// { -// mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); -// } -// else -// { -// MZ_TIME_T cur_time; -// time(&cur_time); -// mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); -// } -// #endif /* #ifndef MINIZ_NO_TIME */ - -// archive_name_size = strlen(pArchive_name); -// if (archive_name_size > MZ_UINT16_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - -// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - -// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -// if (!pState->m_zip64) -// { -// /* Bail early if the archive would obviously become too large */ -// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size -// + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + -// pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len -// + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) -// { -// pState->m_zip64 = MZ_TRUE; -// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -// } -// } - -// if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) -// { -// /* Set DOS Subdirectory attribute bit. */ -// ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; - -// /* Subdirectories cannot contain data. */ -// if ((buf_size) || (uncomp_size)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// } - -// /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ -// if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// if ((!store_data_uncompressed) && (buf_size)) -// { -// if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -// return MZ_FALSE; -// } - -// local_dir_header_ofs += num_alignment_padding_bytes; -// if (pZip->m_file_offset_alignment) -// { -// MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); -// } -// cur_archive_file_ofs += num_alignment_padding_bytes; - -// MZ_CLEAR_OBJ(local_dir_header); - -// if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -// { -// method = MZ_DEFLATED; -// } - -// if (pState->m_zip64) -// { -// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) -// { -// pExtra_data = extra_data; -// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -// } - -// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += sizeof(local_dir_header); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } -// cur_archive_file_ofs += archive_name_size; - -// if (pExtra_data != NULL) -// { -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += extra_size; -// } -// } -// else -// { -// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += sizeof(local_dir_header); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } -// cur_archive_file_ofs += archive_name_size; -// } - -// if (user_extra_data_len > 0) -// { -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += user_extra_data_len; -// } - -// if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -// { -// uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); -// uncomp_size = buf_size; -// if (uncomp_size <= 3) -// { -// level = 0; -// store_data_uncompressed = MZ_TRUE; -// } -// } - -// if (store_data_uncompressed) -// { -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } - -// cur_archive_file_ofs += buf_size; -// comp_size = buf_size; -// } -// else if (buf_size) -// { -// mz_zip_writer_add_state state; - -// state.m_pZip = pZip; -// state.m_cur_archive_file_ofs = cur_archive_file_ofs; -// state.m_comp_size = 0; - -// if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || -// (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -// return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); -// } - -// comp_size = state.m_comp_size; -// cur_archive_file_ofs = state.m_cur_archive_file_ofs; -// } - -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -// pComp = NULL; - -// if (uncomp_size) -// { -// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; -// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; - -// MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); - -// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); -// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); -// if (pExtra_data == NULL) -// { -// if (comp_size > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); -// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); -// } -// else -// { -// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); -// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); -// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; -// } - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) -// return MZ_FALSE; - -// cur_archive_file_ofs += local_dir_footer_size; -// } - -// if (pExtra_data != NULL) -// { -// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -// } - -// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, -// comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, -// user_extra_data_central, user_extra_data_central_len)) -// return MZ_FALSE; - -// pZip->m_total_files++; -// pZip->m_archive_size = cur_archive_file_ofs; - -// return MZ_TRUE; -// } - -// #ifndef MINIZ_NO_STDIO -// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) -// { -// if(!pZip) -// { -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// } - -// mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; -// mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; -// mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; -// mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; -// size_t archive_name_size; -// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; -// mz_uint8 *pExtra_data = NULL; -// mz_uint32 extra_size = 0; -// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; -// mz_zip_internal_state *pState; - -// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) -// gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; - -// if ((int)level_and_flags < 0) -// level_and_flags = MZ_DEFAULT_LEVEL; -// level = level_and_flags & 0xF; - -// /* Sanity checks */ -// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pState = pZip->m_pState; - -// if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) -// { -// /* Source file is too large for non-zip64 */ -// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -// pState->m_zip64 = MZ_TRUE; -// } - -// /* We could support this, but why? */ -// if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (!mz_zip_writer_validate_archive_name(pArchive_name)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - -// if (pState->m_zip64) -// { -// if (pZip->m_total_files == MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -// } -// else -// { -// if (pZip->m_total_files == MZ_UINT16_MAX) -// { -// pState->m_zip64 = MZ_TRUE; -// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ -// } -// } - -// archive_name_size = strlen(pArchive_name); -// if (archive_name_size > MZ_UINT16_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - -// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - -// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -// if (!pState->m_zip64) -// { -// /* Bail early if the archive would obviously become too large */ -// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE -// + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 -// + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) -// { -// pState->m_zip64 = MZ_TRUE; -// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -// } -// } - -// #ifndef MINIZ_NO_TIME -// if (pFile_time) -// { -// mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); -// } -// #endif - -// if (uncomp_size <= 3) -// level = 0; - -// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) -// { -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } - -// cur_archive_file_ofs += num_alignment_padding_bytes; -// local_dir_header_ofs = cur_archive_file_ofs; - -// if (pZip->m_file_offset_alignment) -// { -// MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); -// } - -// if (uncomp_size && level) -// { -// method = MZ_DEFLATED; -// } - -// MZ_CLEAR_OBJ(local_dir_header); -// if (pState->m_zip64) -// { -// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) -// { -// pExtra_data = extra_data; -// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -// } - -// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += sizeof(local_dir_header); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -// { -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } - -// cur_archive_file_ofs += archive_name_size; - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += extra_size; -// } -// else -// { -// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += sizeof(local_dir_header); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -// { -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } - -// cur_archive_file_ofs += archive_name_size; -// } - -// if (user_extra_data_len > 0) -// { -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += user_extra_data_len; -// } - -// if (uncomp_size) -// { -// mz_uint64 uncomp_remaining = uncomp_size; -// void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); -// if (!pRead_buf) -// { -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if (!level) -// { -// while (uncomp_remaining) -// { -// mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); -// if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// } -// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); -// uncomp_remaining -= n; -// cur_archive_file_ofs += n; -// } -// comp_size = uncomp_size; -// } -// else -// { -// mz_bool result = MZ_FALSE; -// mz_zip_writer_add_state state; -// tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); -// if (!pComp) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// state.m_pZip = pZip; -// state.m_cur_archive_file_ofs = cur_archive_file_ofs; -// state.m_comp_size = 0; - -// if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -// } - -// for (;;) -// { -// size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -// tdefl_status status; -// tdefl_flush flush = TDEFL_NO_FLUSH; - -// if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// break; -// } - -// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); -// uncomp_remaining -= in_buf_size; - -// if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) -// flush = TDEFL_FULL_FLUSH; - -// status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); -// if (status == TDEFL_STATUS_DONE) -// { -// result = MZ_TRUE; -// break; -// } -// else if (status != TDEFL_STATUS_OKAY) -// { -// mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); -// break; -// } -// } - -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - -// if (!result) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -// return MZ_FALSE; -// } - -// comp_size = state.m_comp_size; -// cur_archive_file_ofs = state.m_cur_archive_file_ofs; -// } - -// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -// } - -// { -// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; -// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; - -// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); -// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); -// if (pExtra_data == NULL) -// { -// if (comp_size > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); -// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); -// } -// else -// { -// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); -// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); -// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; -// } - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) -// return MZ_FALSE; - -// cur_archive_file_ofs += local_dir_footer_size; -// } - -// if (pExtra_data != NULL) -// { -// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -// } - -// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, -// uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, -// user_extra_data_central, user_extra_data_central_len)) -// return MZ_FALSE; - -// pZip->m_total_files++; -// pZip->m_archive_size = cur_archive_file_ofs; - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -// { -// MZ_FILE *pSrc_file = NULL; -// mz_uint64 uncomp_size = 0; -// MZ_TIME_T file_modified_time; -// MZ_TIME_T *pFile_time = NULL; -// mz_bool status; - -// memset(&file_modified_time, 0, sizeof(file_modified_time)); - -// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) -// pFile_time = &file_modified_time; -// if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); -// #endif - -// pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); -// if (!pSrc_file) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -// MZ_FSEEK64(pSrc_file, 0, SEEK_END); -// uncomp_size = MZ_FTELL64(pSrc_file); -// MZ_FSEEK64(pSrc_file, 0, SEEK_SET); - -// status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); - -// MZ_FCLOSE(pSrc_file); - -// return status; -// } -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) -// { -// /* + 64 should be enough for any new zip64 data */ -// if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE)) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE); - -// if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start)) -// { -// mz_uint8 new_ext_block[64]; -// mz_uint8 *pDst = new_ext_block; -// mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); -// mz_write_le16(pDst + sizeof(mz_uint16), 0); -// pDst += sizeof(mz_uint16) * 2; - -// if (pUncomp_size) -// { -// mz_write_le64(pDst, *pUncomp_size); -// pDst += sizeof(mz_uint64); -// } - -// if (pComp_size) -// { -// mz_write_le64(pDst, *pComp_size); -// pDst += sizeof(mz_uint64); -// } - -// if (pLocal_header_ofs) -// { -// mz_write_le64(pDst, *pLocal_header_ofs); -// pDst += sizeof(mz_uint64); -// } - -// if (pDisk_start) -// { -// mz_write_le32(pDst, *pDisk_start); -// pDst += sizeof(mz_uint32); -// } - -// mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2)); - -// if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block)) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if ((pExt) && (ext_len)) -// { -// mz_uint32 extra_size_remaining = ext_len; -// const mz_uint8 *pExtra_data = pExt; - -// do -// { -// mz_uint32 field_id, field_data_size, field_total_size; - -// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// field_id = MZ_READ_LE16(pExtra_data); -// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); -// field_total_size = field_data_size + sizeof(mz_uint16) * 2; - -// if (field_total_size > extra_size_remaining) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -// { -// if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size)) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// pExtra_data += field_total_size; -// extra_size_remaining -= field_total_size; -// } while (extra_size_remaining); -// } - -// return MZ_TRUE; -// } - -/* TODO: This func is now pretty freakin complex due to zip64, split it up? */ -// mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index) -// { -// mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size; -// mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs; -// mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; -// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -// mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; -// size_t orig_central_dir_size; -// mz_zip_internal_state *pState; -// void *pBuf; -// const mz_uint8 *pSrc_central_header; -// mz_zip_archive_file_stat src_file_stat; -// mz_uint32 src_filename_len, src_comment_len, src_ext_len; -// mz_uint32 local_header_filename_size, local_header_extra_len; -// mz_uint64 local_header_comp_size, local_header_uncomp_size; -// mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; - -// /* Sanity checks */ -// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pState = pZip->m_pState; - -// /* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */ -// if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// /* Get pointer to the source central dir header and crack it */ -// if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index))) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); -// src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS); -// src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len; - -// /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32 fudge factor in case we need to add more extra data) */ -// if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - -// if (!pState->m_zip64) -// { -// if (pZip->m_total_files == MZ_UINT16_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -// } -// else -// { -// /* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */ -// if (pZip->m_total_files == MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -// } - -// if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL)) -// return MZ_FALSE; - -// cur_src_file_ofs = src_file_stat.m_local_header_ofs; -// cur_dst_file_ofs = pZip->m_archive_size; - -// /* Read the source archive's local dir header */ -// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; - -// /* Compute the total size we need to copy (filename+extra data+compressed data) */ -// local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); -// local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -// local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); -// local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); -// src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size; - -// /* Try to find a zip64 extended information field */ -// if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) -// { -// mz_zip_array file_data_array; -// const mz_uint8 *pExtra_data; -// mz_uint32 extra_size_remaining = local_header_extra_len; - -// mz_zip_array_init(&file_data_array, 1); -// if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE)) -// { -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, src_file_stat.m_local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_size, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) -// { -// mz_zip_array_clear(pZip, &file_data_array); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// } - -// pExtra_data = (const mz_uint8 *)file_data_array.m_p; - -// do -// { -// mz_uint32 field_id, field_data_size, field_total_size; - -// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -// { -// mz_zip_array_clear(pZip, &file_data_array); -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// } - -// field_id = MZ_READ_LE16(pExtra_data); -// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); -// field_total_size = field_data_size + sizeof(mz_uint16) * 2; - -// if (field_total_size > extra_size_remaining) -// { -// mz_zip_array_clear(pZip, &file_data_array); -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// } - -// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -// { -// // const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); - -// if (field_data_size < sizeof(mz_uint64) * 2) -// { -// mz_zip_array_clear(pZip, &file_data_array); -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// } - -// // local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); -// // local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ - -// found_zip64_ext_data_in_ldir = MZ_TRUE; -// break; -// } - -// pExtra_data += field_total_size; -// extra_size_remaining -= field_total_size; -// } while (extra_size_remaining); - -// mz_zip_array_clear(pZip, &file_data_array); -// } - -// if (!pState->m_zip64) -// { -// /* Try to detect if the new archive will most likely wind up too big and bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which could be present, +64 is a fudge factor). */ -// /* We also check when the archive is finalized so this doesn't need to be perfect. */ -// mz_uint64 approx_new_archive_size = cur_dst_file_ofs + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining + (sizeof(mz_uint32) * 4) + -// pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64; - -// if (approx_new_archive_size >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -// } - -// /* Write dest archive padding */ -// if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) -// return MZ_FALSE; - -// cur_dst_file_ofs += num_alignment_padding_bytes; - -// local_dir_header_ofs = cur_dst_file_ofs; -// if (pZip->m_file_offset_alignment) -// { -// MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); -// } - -// /* The original zip's local header+ext block doesn't change, even with zip64, so we can just copy it over to the dest zip */ -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; - -// /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */ -// if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining))))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// while (src_archive_bytes_remaining) -// { -// n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining); -// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// } -// cur_src_file_ofs += n; - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } -// cur_dst_file_ofs += n; - -// src_archive_bytes_remaining -= n; -// } - -// /* Now deal with the optional data descriptor */ -// bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); -// if (bit_flags & 8) -// { -// /* Copy data descriptor */ -// if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir)) -// { -// /* src is zip64, dest must be zip64 */ - -// /* name uint32_t's */ -// /* id 1 (optional in zip64?) */ -// /* crc 1 */ -// /* comp_size 2 */ -// /* uncomp_size 2 */ -// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6)) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// } - -// n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5); -// } -// else -// { -// /* src is NOT zip64 */ -// mz_bool has_id; - -// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// } - -// has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID); - -// if (pZip->m_pState->m_zip64) -// { -// /* dest is zip64, so upgrade the data descriptor */ -// const mz_uint32 *pSrc_descriptor = (const mz_uint32 *)((const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0)); -// const mz_uint32 src_crc32 = pSrc_descriptor[0]; -// const mz_uint64 src_comp_size = pSrc_descriptor[1]; -// const mz_uint64 src_uncomp_size = pSrc_descriptor[2]; - -// mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID); -// mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32); -// mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size); -// mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size); - -// n = sizeof(mz_uint32) * 6; -// } -// else -// { -// /* dest is NOT zip64, just copy it as-is */ -// n = sizeof(mz_uint32) * (has_id ? 4 : 3); -// } -// } - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } - -// // cur_src_file_ofs += n; -// cur_dst_file_ofs += n; -// } -// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - -// /* Finally, add the new central dir header */ -// orig_central_dir_size = pState->m_central_dir.m_size; - -// memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); - -// if (pState->m_zip64) -// { -// /* This is the painful part: We need to write a new central dir header + ext block with updated zip64 fields, and ensure the old fields (if any) are not included. */ -// const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len; -// mz_zip_array new_ext_block; - -// mz_zip_array_init(&new_ext_block, sizeof(mz_uint8)); - -// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX); -// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX); -// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX); - -// if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL)) -// { -// mz_zip_array_clear(pZip, &new_ext_block); -// return MZ_FALSE; -// } - -// MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size); - -// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) -// { -// mz_zip_array_clear(pZip, &new_ext_block); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len)) -// { -// mz_zip_array_clear(pZip, &new_ext_block); -// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size)) -// { -// mz_zip_array_clear(pZip, &new_ext_block); -// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len + src_ext_len, src_comment_len)) -// { -// mz_zip_array_clear(pZip, &new_ext_block); -// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// mz_zip_array_clear(pZip, &new_ext_block); -// } -// else -// { -// /* sanity checks */ -// if (cur_dst_file_ofs > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -// if (local_dir_header_ofs >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); - -// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_central_dir_following_data_size)) -// { -// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } -// } - -// /* This shouldn't trigger unless we screwed up during the initial sanity checks */ -// if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) -// { -// /* TODO: Support central dirs >= 32-bits in size */ -// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); -// } - -// n = (mz_uint32)orig_central_dir_size; -// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) -// { -// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// pZip->m_total_files++; -// pZip->m_archive_size = cur_dst_file_ofs; - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) -// { -// mz_zip_internal_state *pState; -// mz_uint64 central_dir_ofs, central_dir_size; -// mz_uint8 hdr[256]; - -// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pState = pZip->m_pState; - -// if (pState->m_zip64) -// { -// if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -// } -// else -// { -// if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -// } - -// central_dir_ofs = 0; -// central_dir_size = 0; -// if (pZip->m_total_files) -// { -// /* Write central directory */ -// central_dir_ofs = pZip->m_archive_size; -// central_dir_size = pState->m_central_dir.m_size; -// pZip->m_central_directory_file_ofs = central_dir_ofs; -// if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// pZip->m_archive_size += central_dir_size; -// } - -// if (pState->m_zip64) -// { -// /* Write zip64 end of central directory header */ -// mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; - -// MZ_CLEAR_OBJ(hdr); -// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); -// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); -// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ -// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); -// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); -// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); -// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); -// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); -// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; - -// /* Write zip64 end of central directory locator */ -// MZ_CLEAR_OBJ(hdr); -// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); -// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); -// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); -// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; -// } - -// /* Write end of central directory record */ -// MZ_CLEAR_OBJ(hdr); -// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); -// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); -// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); -// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); -// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// #ifndef MINIZ_NO_STDIO -// if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; - -// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) -// { -// if ((!ppBuf) || (!pSize)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// *ppBuf = NULL; -// *pSize = 0; - -// if ((!pZip) || (!pZip->m_pState)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (pZip->m_pWrite != mz_zip_heap_write_func) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (!mz_zip_writer_finalize_archive(pZip)) -// return MZ_FALSE; - -// *ppBuf = pZip->m_pState->m_pMem; -// *pSize = pZip->m_pState->m_mem_size; -// pZip->m_pState->m_pMem = NULL; -// pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_end(mz_zip_archive *pZip) -// { -// return mz_zip_writer_end_internal(pZip, MZ_TRUE); -// } - -// #ifndef MINIZ_NO_STDIO -// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -// { -// return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); -// } - -// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) -// { -// mz_bool status, created_new_archive = MZ_FALSE; -// mz_zip_archive zip_archive; -// struct MZ_FILE_STAT_STRUCT file_stat; -// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; - -// mz_zip_zero_struct(&zip_archive); -// if ((int)level_and_flags < 0) -// level_and_flags = MZ_DEFAULT_LEVEL; - -// if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) -// { -// if (pErr) -// *pErr = MZ_ZIP_INVALID_PARAMETER; -// return MZ_FALSE; -// } - -// if (!mz_zip_writer_validate_archive_name(pArchive_name)) -// { -// if (pErr) -// *pErr = MZ_ZIP_INVALID_FILENAME; -// return MZ_FALSE; -// } - -// /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ -// /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ -// if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) -// { -// /* Create a new archive. */ -// if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) -// { -// if (pErr) -// *pErr = zip_archive.m_last_error; -// return MZ_FALSE; -// } - -// created_new_archive = MZ_TRUE; -// } -// else -// { -// /* Append to an existing archive. */ -// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) -// { -// if (pErr) -// *pErr = zip_archive.m_last_error; -// return MZ_FALSE; -// } - -// if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) -// { -// if (pErr) -// *pErr = zip_archive.m_last_error; - -// mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); - -// return MZ_FALSE; -// } -// } - -// status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); -// actual_err = zip_archive.m_last_error; - -// /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ -// if (!mz_zip_writer_finalize_archive(&zip_archive)) -// { -// if (!actual_err) -// actual_err = zip_archive.m_last_error; - -// status = MZ_FALSE; -// } - -// if (!mz_zip_writer_end_internal(&zip_archive, status)) -// { -// if (!actual_err) -// actual_err = zip_archive.m_last_error; - -// status = MZ_FALSE; -// } - -// if ((!status) && (created_new_archive)) -// { -// /* It's a new archive and something went wrong, so just delete it. */ -// int ignoredStatus = MZ_DELETE_FILE(pZip_filename); -// (void)ignoredStatus; -// } - -// if (pErr) -// *pErr = actual_err; - -// return status; -// } - -// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) -// { -// mz_uint32 file_index; -// mz_zip_archive zip_archive; -// void *p = NULL; - -// if (pSize) -// *pSize = 0; - -// if ((!pZip_filename) || (!pArchive_name)) -// { -// if (pErr) -// *pErr = MZ_ZIP_INVALID_PARAMETER; - -// return NULL; -// } - -// mz_zip_zero_struct(&zip_archive); -// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) -// { -// if (pErr) -// *pErr = zip_archive.m_last_error; - -// return NULL; -// } - -// if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) -// { -// p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); -// } - -// mz_zip_reader_end_internal(&zip_archive, p != NULL); - -// if (pErr) -// *pErr = zip_archive.m_last_error; - -// return p; -// } - -// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) -// { -// return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); -// } - -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ - -/* ------------------- Misc utils */ - -// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) -// { -// return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; -// } - -// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) -// { -// return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; -// } - -// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) -// { -// mz_zip_error prev_err; - -// if (!pZip) -// return MZ_ZIP_INVALID_PARAMETER; - -// prev_err = pZip->m_last_error; - -// pZip->m_last_error = err_num; -// return prev_err; -// } - -// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) -// { -// if (!pZip) -// return MZ_ZIP_INVALID_PARAMETER; - -// return pZip->m_last_error; -// } - -// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) -// { -// return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); -// } - -// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) -// { -// mz_zip_error prev_err; - -// if (!pZip) -// return MZ_ZIP_INVALID_PARAMETER; - -// prev_err = pZip->m_last_error; - -// pZip->m_last_error = MZ_ZIP_NO_ERROR; -// return prev_err; -// } - -// const char *mz_zip_get_error_string(mz_zip_error mz_err) -// { -// switch (mz_err) -// { -// case MZ_ZIP_NO_ERROR: -// return "no error"; -// case MZ_ZIP_UNDEFINED_ERROR: -// return "undefined error"; -// case MZ_ZIP_TOO_MANY_FILES: -// return "too many files"; -// case MZ_ZIP_FILE_TOO_LARGE: -// return "file too large"; -// case MZ_ZIP_UNSUPPORTED_METHOD: -// return "unsupported method"; -// case MZ_ZIP_UNSUPPORTED_ENCRYPTION: -// return "unsupported encryption"; -// case MZ_ZIP_UNSUPPORTED_FEATURE: -// return "unsupported feature"; -// case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: -// return "failed finding central directory"; -// case MZ_ZIP_NOT_AN_ARCHIVE: -// return "not a ZIP archive"; -// case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: -// return "invalid header or archive is corrupted"; -// case MZ_ZIP_UNSUPPORTED_MULTIDISK: -// return "unsupported multidisk archive"; -// case MZ_ZIP_DECOMPRESSION_FAILED: -// return "decompression failed or archive is corrupted"; -// case MZ_ZIP_COMPRESSION_FAILED: -// return "compression failed"; -// case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: -// return "unexpected decompressed size"; -// case MZ_ZIP_CRC_CHECK_FAILED: -// return "CRC-32 check failed"; -// case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: -// return "unsupported central directory size"; -// case MZ_ZIP_ALLOC_FAILED: -// return "allocation failed"; -// case MZ_ZIP_FILE_OPEN_FAILED: -// return "file open failed"; -// case MZ_ZIP_FILE_CREATE_FAILED: -// return "file create failed"; -// case MZ_ZIP_FILE_WRITE_FAILED: -// return "file write failed"; -// case MZ_ZIP_FILE_READ_FAILED: -// return "file read failed"; -// case MZ_ZIP_FILE_CLOSE_FAILED: -// return "file close failed"; -// case MZ_ZIP_FILE_SEEK_FAILED: -// return "file seek failed"; -// case MZ_ZIP_FILE_STAT_FAILED: -// return "file stat failed"; -// case MZ_ZIP_INVALID_PARAMETER: -// return "invalid parameter"; -// case MZ_ZIP_INVALID_FILENAME: -// return "invalid filename"; -// case MZ_ZIP_BUF_TOO_SMALL: -// return "buffer too small"; -// case MZ_ZIP_INTERNAL_ERROR: -// return "internal error"; -// case MZ_ZIP_FILE_NOT_FOUND: -// return "file not found"; -// case MZ_ZIP_ARCHIVE_TOO_LARGE: -// return "archive is too large"; -// case MZ_ZIP_VALIDATION_FAILED: -// return "validation failed"; -// case MZ_ZIP_WRITE_CALLBACK_FAILED: -// return "write calledback failed"; -// default: -// break; -// } - -// return "unknown error"; -// } - -/* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */ -// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) -// { -// if ((!pZip) || (!pZip->m_pState)) -// return MZ_FALSE; - -// return pZip->m_pState->m_zip64; -// } - -// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) -// { -// if ((!pZip) || (!pZip->m_pState)) -// return 0; - -// return pZip->m_pState->m_central_dir.m_size; -// } - -// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) -// { -// return pZip ? pZip->m_total_files : 0; -// } - -// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) -// { -// if (!pZip) -// return 0; -// return pZip->m_archive_size; -// } - -// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) -// { -// if ((!pZip) || (!pZip->m_pState)) -// return 0; -// return pZip->m_pState->m_file_archive_start_ofs; -// } - -// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) -// { -// if ((!pZip) || (!pZip->m_pState)) -// return 0; -// return pZip->m_pState->m_pFile; -// } - -// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) -// { -// if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); -// } - -// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) -// { -// mz_uint n; -// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -// if (!p) -// { -// if (filename_buf_size) -// pFilename[0] = '\0'; -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// return 0; -// } -// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// if (filename_buf_size) -// { -// n = MZ_MIN(n, filename_buf_size - 1); -// memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); -// pFilename[n] = '\0'; -// } -// return n + 1; -// } - -// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) -// { -// return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); -// } - -// mz_bool mz_zip_end(mz_zip_archive *pZip) -// { -// if (!pZip) -// return MZ_FALSE; - -// if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) -// return mz_zip_reader_end(pZip); -// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -// else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) -// return mz_zip_writer_end(pZip); -// #endif - -// return MZ_FALSE; -// } - -// #ifdef __cplusplus -// } -// #endif - -// #endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ diff --git a/gomspace/libutil/src/zip/miniz/miniz.h b/gomspace/libutil/src/zip/miniz/miniz.h deleted file mode 100644 index e5172634..00000000 --- a/gomspace/libutil/src/zip/miniz/miniz.h +++ /dev/null @@ -1,1329 +0,0 @@ -/* miniz.c 2.0.6 beta - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing - See "unlicense" statement at the end of this file. - Rich Geldreich , last updated Oct. 13, 2013 - Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt - - Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define - MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). - - * Low-level Deflate/Inflate implementation notes: - - Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or - greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses - approximately as well as zlib. - - Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function - coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory - block large enough to hold the entire file. - - The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. - - * zlib-style API notes: - - miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in - zlib replacement in many apps: - The z_stream struct, optional memory allocation callbacks - deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound - inflateInit/inflateInit2/inflate/inflateEnd - compress, compress2, compressBound, uncompress - CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. - Supports raw deflate streams or standard zlib streams with adler-32 checking. - - Limitations: - The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. - I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but - there are no guarantees that miniz.c pulls this off perfectly. - - * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by - Alex Evans. Supports 1-4 bytes/pixel images. - - * ZIP archive API notes: - - The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to - get the job done with minimal fuss. There are simple API's to retrieve file information, read files from - existing archives, create new archives, append new files to existing archives, or clone archive data from - one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), - or you can specify custom file read/write callbacks. - - - Archive reading: Just call this function to read a single file from a disk archive: - - void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, - size_t *pSize, mz_uint zip_flags); - - For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central - directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. - - - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: - - int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); - - The locate operation can optionally check file comments too, which (as one example) can be used to identify - multiple versions of the same file in an archive. This function uses a simple linear search through the central - directory, so it's not very fast. - - Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and - retrieve detailed info on each file by calling mz_zip_reader_file_stat(). - - - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data - to disk and builds an exact image of the central directory in memory. The central directory image is written - all at once at the end of the archive file when the archive is finalized. - - The archive writer can optionally align each file's local header and file data to any power of 2 alignment, - which can be useful when the archive will be read from optical media. Also, the writer supports placing - arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still - readable by any ZIP tool. - - - Archive appending: The simple way to add a single file to an archive is to call this function: - - mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, - const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - - The archive will be created if it doesn't already exist, otherwise it'll be appended to. - Note the appending is done in-place and is not an atomic operation, so if something goes wrong - during the operation it's possible the archive could be left without a central directory (although the local - file headers and file data will be fine, so the archive will be recoverable). - - For more complex archive modification scenarios: - 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to - preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the - compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and - you're done. This is safe but requires a bunch of temporary disk space or heap memory. - - 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), - append new files as needed, then finalize the archive which will write an updated central directory to the - original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a - possibility that the archive's central directory could be lost with this method if anything goes wrong, though. - - - ZIP archive support limitations: - No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. - Requires streams capable of seeking. - - * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the - below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. - - * Important: For best perf. be sure to customize the below macros for your target platform: - #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 - #define MINIZ_LITTLE_ENDIAN 1 - #define MINIZ_HAS_64BIT_REGISTERS 1 - - * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz - uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files - (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). -*/ -#pragma once - - - - - -/* Defines to completely disable specific portions of miniz.c: - If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. */ - -/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */ -/*#define MINIZ_NO_STDIO */ - -/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */ -/* get/set file times, and the C run-time funcs that get/set times won't be called. */ -/* The current downside is the times written to your archives will be from 1979. */ -#define MINIZ_NO_TIME - -/* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */ -/*#define MINIZ_NO_ARCHIVE_APIS */ - -/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */ -/*#define MINIZ_NO_ARCHIVE_WRITING_APIS */ - -/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */ -/*#define MINIZ_NO_ZLIB_APIS */ - -/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */ -/*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ - -/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. - Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc - callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user - functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */ -/*#define MINIZ_NO_MALLOC */ - -#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) -/* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux */ -#define MINIZ_NO_TIME -#endif - -#include - -#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) -#include -#endif - -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) -/* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */ -#define MINIZ_X86_OR_X64_CPU 1 -#else -#define MINIZ_X86_OR_X64_CPU 0 -#endif - -#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU -/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ -#define MINIZ_LITTLE_ENDIAN 1 -#else -#define MINIZ_LITTLE_ENDIAN 0 -#endif - -// #if MINIZ_X86_OR_X64_CPU -/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */ -// #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 -// #else -// #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 -// #endif -#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 - -#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) -/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). */ -#define MINIZ_HAS_64BIT_REGISTERS 1 -#else -#define MINIZ_HAS_64BIT_REGISTERS 0 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------- zlib-style API Definitions. */ - -/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */ -typedef unsigned long mz_ulong; - -/* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. */ -void mz_free(void *p); - -#define MZ_ADLER32_INIT (1) -/* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */ -mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); - -#define MZ_CRC32_INIT (0) -/* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ -// mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); - -/* Compression strategies. */ -enum -{ - MZ_DEFAULT_STRATEGY = 0, - MZ_FILTERED = 1, - MZ_HUFFMAN_ONLY = 2, - MZ_RLE = 3, - MZ_FIXED = 4 -}; - -/* Method */ -#define MZ_DEFLATED 8 - -/* Heap allocation callbacks. -Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. */ -typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); -typedef void (*mz_free_func)(void *opaque, void *address); -typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); - -/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */ -enum -{ - MZ_NO_COMPRESSION = 0, - MZ_BEST_SPEED = 1, - MZ_BEST_COMPRESSION = 9, - MZ_UBER_COMPRESSION = 10, - MZ_DEFAULT_LEVEL = 6, - MZ_DEFAULT_COMPRESSION = -1 -}; - -#define MZ_VERSION "10.0.1" -#define MZ_VERNUM 0xA010 -#define MZ_VER_MAJOR 10 -#define MZ_VER_MINOR 0 -#define MZ_VER_REVISION 1 -#define MZ_VER_SUBREVISION 0 - -#ifndef MINIZ_NO_ZLIB_APIS - -/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). */ -enum -{ - MZ_NO_FLUSH = 0, - MZ_PARTIAL_FLUSH = 1, - MZ_SYNC_FLUSH = 2, - MZ_FULL_FLUSH = 3, - MZ_FINISH = 4, - MZ_BLOCK = 5 -}; - -/* Return status codes. MZ_PARAM_ERROR is non-standard. */ -enum -{ - MZ_OK = 0, - MZ_STREAM_END = 1, - MZ_NEED_DICT = 2, - MZ_ERRNO = -1, - MZ_STREAM_ERROR = -2, - MZ_DATA_ERROR = -3, - MZ_MEM_ERROR = -4, - MZ_BUF_ERROR = -5, - MZ_VERSION_ERROR = -6, - MZ_PARAM_ERROR = -10000 -}; - -/* Window bits */ -#define MZ_DEFAULT_WINDOW_BITS 15 - -struct mz_internal_state; - -/* Compression/decompression stream struct. */ -typedef struct mz_stream_s -{ - const unsigned char *next_in; /* pointer to next byte to read */ - unsigned int avail_in; /* number of bytes available at next_in */ - mz_ulong total_in; /* total number of bytes consumed so far */ - - unsigned char *next_out; /* pointer to next byte to write */ - unsigned int avail_out; /* number of bytes that can be written to next_out */ - mz_ulong total_out; /* total number of bytes produced so far */ - - char *msg; /* error msg (unused) */ - struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */ - - mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */ - mz_free_func zfree; /* optional heap free function (defaults to free) */ - void *opaque; /* heap alloc function user pointer */ - - int data_type; /* data_type (unused) */ - mz_ulong adler; /* adler32 of the source or uncompressed data */ - mz_ulong reserved; /* not used */ -} mz_stream; - -typedef mz_stream *mz_streamp; - -/* Returns the version string of miniz.c. */ -// const char *mz_version(void); - -/* mz_deflateInit() initializes a compressor with default options: */ -/* Parameters: */ -/* pStream must point to an initialized mz_stream struct. */ -/* level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */ -/* level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. */ -/* (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */ -/* Return values: */ -/* MZ_OK on success. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -/* MZ_PARAM_ERROR if the input parameters are bogus. */ -/* MZ_MEM_ERROR on out of memory. */ -int mz_deflateInit(mz_streamp pStream, int level); - -/* mz_deflateInit2() is like mz_deflate(), except with more control: */ -/* Additional parameters: */ -/* method must be MZ_DEFLATED */ -/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */ -/* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */ -int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); - -/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ -// int mz_deflateReset(mz_streamp pStream); - -/* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */ -/* Parameters: */ -/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ -/* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */ -/* Return values: */ -/* MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). */ -/* MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -/* MZ_PARAM_ERROR if one of the parameters is invalid. */ -/* MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) */ -int mz_deflate(mz_streamp pStream, int flush); - -/* mz_deflateEnd() deinitializes a compressor: */ -/* Return values: */ -/* MZ_OK on success. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -int mz_deflateEnd(mz_streamp pStream); - -/* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ -// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); - -/* Single-call compression functions mz_compress() and mz_compress2(): */ -/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ -int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); -int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); - -/* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */ -// mz_ulong mz_compressBound(mz_ulong source_len); - -/* Initializes a decompressor. */ -int mz_inflateInit(mz_streamp pStream); - -/* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: */ -/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */ -int mz_inflateInit2(mz_streamp pStream, int window_bits); - -/* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. */ -/* Parameters: */ -/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ -/* flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */ -/* On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). */ -/* MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. */ -/* Return values: */ -/* MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. */ -/* MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -/* MZ_DATA_ERROR if the deflate stream is invalid. */ -/* MZ_PARAM_ERROR if one of the parameters is invalid. */ -/* MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again */ -/* with more input data, or with more room in the output buffer (except when using single call decompression, described above). */ -int mz_inflate(mz_streamp pStream, int flush); - -/* Deinitializes a decompressor. */ -int mz_inflateEnd(mz_streamp pStream); - -/* Single-call decompression. */ -/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */ -int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); - -/* Returns a string description of the specified error code, or NULL if the error code is invalid. */ -// const char *mz_error(int err); - -/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */ -/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ -#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES -typedef unsigned char Byte; -typedef unsigned int uInt; -typedef mz_ulong uLong; -typedef Byte Bytef; -typedef uInt uIntf; -typedef char charf; -typedef int intf; -typedef void *voidpf; -typedef uLong uLongf; -typedef void *voidp; -typedef void *const voidpc; -#define Z_NULL 0 -#define Z_NO_FLUSH MZ_NO_FLUSH -#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH -#define Z_SYNC_FLUSH MZ_SYNC_FLUSH -#define Z_FULL_FLUSH MZ_FULL_FLUSH -#define Z_FINISH MZ_FINISH -#define Z_BLOCK MZ_BLOCK -#define Z_OK MZ_OK -#define Z_STREAM_END MZ_STREAM_END -#define Z_NEED_DICT MZ_NEED_DICT -#define Z_ERRNO MZ_ERRNO -#define Z_STREAM_ERROR MZ_STREAM_ERROR -#define Z_DATA_ERROR MZ_DATA_ERROR -#define Z_MEM_ERROR MZ_MEM_ERROR -#define Z_BUF_ERROR MZ_BUF_ERROR -#define Z_VERSION_ERROR MZ_VERSION_ERROR -#define Z_PARAM_ERROR MZ_PARAM_ERROR -#define Z_NO_COMPRESSION MZ_NO_COMPRESSION -#define Z_BEST_SPEED MZ_BEST_SPEED -#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION -#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION -#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY -#define Z_FILTERED MZ_FILTERED -#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY -#define Z_RLE MZ_RLE -#define Z_FIXED MZ_FIXED -#define Z_DEFLATED MZ_DEFLATED -#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS -#define alloc_func mz_alloc_func -#define free_func mz_free_func -#define internal_state mz_internal_state -#define z_stream mz_stream -#define deflateInit mz_deflateInit -#define deflateInit2 mz_deflateInit2 -// #define deflateReset mz_deflateReset -#define deflate mz_deflate -#define deflateEnd mz_deflateEnd -// #define deflateBound mz_deflateBound -#define compress mz_compress -#define compress2 mz_compress2 -// #define compressBound mz_compressBound -#define inflateInit mz_inflateInit -#define inflateInit2 mz_inflateInit2 -#define inflate mz_inflate -#define inflateEnd mz_inflateEnd -#define uncompress mz_uncompress -// #define crc32 mz_crc32 -#define adler32 mz_adler32 -#define MAX_WBITS 15 -#define MAX_MEM_LEVEL 9 -// #define zError mz_error -#define ZLIB_VERSION MZ_VERSION -#define ZLIB_VERNUM MZ_VERNUM -#define ZLIB_VER_MAJOR MZ_VER_MAJOR -#define ZLIB_VER_MINOR MZ_VER_MINOR -#define ZLIB_VER_REVISION MZ_VER_REVISION -#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION -// #define zlibVersion mz_version -// #define zlib_version mz_version() -#endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ - -#endif /* MINIZ_NO_ZLIB_APIS */ - -#ifdef __cplusplus -} -#endif -#pragma once -#include -#include -#include -#include - -/* ------------------- Types and macros */ -typedef unsigned char mz_uint8; -typedef signed short mz_int16; -typedef unsigned short mz_uint16; -typedef unsigned int mz_uint32; -typedef unsigned int mz_uint; -typedef int64_t mz_int64; -typedef uint64_t mz_uint64; -typedef int mz_bool; - -#define MZ_FALSE (0) -#define MZ_TRUE (1) - -/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */ -#ifdef _MSC_VER -#define MZ_MACRO_END while (0, 0) -#else -#define MZ_MACRO_END while (0) -#endif - -#ifdef MINIZ_NO_STDIO -#define MZ_FILE void * -#else -#include -#define MZ_FILE FILE -#endif /* #ifdef MINIZ_NO_STDIO */ - -// #ifdef MINIZ_NO_TIME -// typedef struct mz_dummy_time_t_tag -// { -// int m_dummy; -// } mz_dummy_time_t; -// #define MZ_TIME_T mz_dummy_time_t -// #else -// #define MZ_TIME_T time_t -// #endif - -#define MZ_ASSERT(x) assert(x) - -#ifdef MINIZ_NO_MALLOC -#define MZ_MALLOC(x) NULL -#define MZ_FREE(x) (void)x, ((void)0) -#define MZ_REALLOC(p, x) NULL -#else -#define MZ_MALLOC(x) malloc(x) -#define MZ_FREE(x) free(x) -#define MZ_REALLOC(p, x) realloc(p, x) -#endif - -#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) -#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) -#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) -#else -#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) -#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) -#endif - -#define MZ_READ_LE64(p) (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U)) - -#ifdef _MSC_VER -#define MZ_FORCEINLINE __forceinline -#elif defined(__GNUC__) -#define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__)) -#else -#define MZ_FORCEINLINE inline -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -extern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); -extern void miniz_def_free_func(void *opaque, void *address); -// extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); - -#define MZ_UINT16_MAX (0xFFFFU) -#define MZ_UINT32_MAX (0xFFFFFFFFU) - -#ifdef __cplusplus -} -#endif -#pragma once - - -#ifdef __cplusplus -extern "C" { -#endif -/* ------------------- Low-level Compression API Definitions */ - -/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). */ -#define TDEFL_LESS_MEMORY 0 - -/* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): */ -/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */ -enum -{ - TDEFL_HUFFMAN_ONLY = 0, - TDEFL_DEFAULT_MAX_PROBES = 128, - TDEFL_MAX_PROBES_MASK = 0xFFF -}; - -/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. */ -/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */ -/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */ -/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). */ -/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */ -/* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */ -/* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */ -/* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */ -/* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). */ -enum -{ - TDEFL_WRITE_ZLIB_HEADER = 0x01000, - TDEFL_COMPUTE_ADLER32 = 0x02000, - TDEFL_GREEDY_PARSING_FLAG = 0x04000, - TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, - TDEFL_RLE_MATCHES = 0x10000, - TDEFL_FILTER_MATCHES = 0x20000, - TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, - TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 -}; - -/* High level compression functions: */ -/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */ -/* On entry: */ -/* pSrc_buf, src_buf_len: Pointer and size of source block to compress. */ -/* flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. */ -/* On return: */ -/* Function returns a pointer to the compressed data, or NULL on failure. */ -/* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */ -/* The caller must free() the returned block when it's no longer needed. */ -// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - -/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ -/* Returns 0 on failure. */ -// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - -/* Compresses an image to a compressed PNG file in memory. */ -/* On entry: */ -/* pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */ -/* The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. */ -/* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */ -/* If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */ -/* On return: */ -/* Function returns a pointer to the compressed data, or NULL on failure. */ -/* *pLen_out will be set to the size of the PNG image file. */ -/* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */ -// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); -// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); - -/* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ -typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); - -/* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */ -// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -enum -{ - TDEFL_MAX_HUFF_TABLES = 3, - TDEFL_MAX_HUFF_SYMBOLS_0 = 288, - TDEFL_MAX_HUFF_SYMBOLS_1 = 32, - TDEFL_MAX_HUFF_SYMBOLS_2 = 19, - TDEFL_LZ_DICT_SIZE = 32768, - TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, - TDEFL_MIN_MATCH_LEN = 3, - TDEFL_MAX_MATCH_LEN = 258 -}; - -/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). */ -#if TDEFL_LESS_MEMORY -enum -{ - TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, - TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, - TDEFL_MAX_HUFF_SYMBOLS = 288, - TDEFL_LZ_HASH_BITS = 12, - TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, - TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, - TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS -}; -#else -enum -{ - TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, - TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, - TDEFL_MAX_HUFF_SYMBOLS = 288, - TDEFL_LZ_HASH_BITS = 15, - TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, - TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, - TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS -}; -#endif - -/* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. */ -typedef enum { - TDEFL_STATUS_BAD_PARAM = -2, - TDEFL_STATUS_PUT_BUF_FAILED = -1, - TDEFL_STATUS_OKAY = 0, - TDEFL_STATUS_DONE = 1 -} tdefl_status; - -/* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */ -typedef enum { - TDEFL_NO_FLUSH = 0, - TDEFL_SYNC_FLUSH = 2, - TDEFL_FULL_FLUSH = 3, - TDEFL_FINISH = 4 -} tdefl_flush; - -/* tdefl's compression state structure. */ -typedef struct -{ - tdefl_put_buf_func_ptr m_pPut_buf_func; - void *m_pPut_buf_user; - mz_uint m_flags, m_max_probes[2]; - int m_greedy_parsing; - mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; - mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; - mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; - mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; - tdefl_status m_prev_return_status; - const void *m_pIn_buf; - void *m_pOut_buf; - size_t *m_pIn_buf_size, *m_pOut_buf_size; - tdefl_flush m_flush; - const mz_uint8 *m_pSrc; - size_t m_src_buf_left, m_out_buf_ofs; - mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; - mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; - mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; - mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; - mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; -} tdefl_compressor; - -/* Initializes the compressor. */ -/* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */ -/* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. */ -/* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */ -/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */ -tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -/* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. */ -tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); - -/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ -/* tdefl_compress_buffer() always consumes the entire input buffer. */ -// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); - -// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); -mz_uint32 tdefl_get_adler32(tdefl_compressor *d); - -/* Create tdefl_compress() flags given zlib-style compression parameters. */ -/* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */ -/* window_bits may be -15 (raw deflate) or 15 (zlib) */ -/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */ -mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); - -/* Allocate the tdefl_compressor structure in C so that */ -/* non-C language bindings to tdefl_ API don't need to worry about */ -/* structure size and allocation mechanism. */ -// tdefl_compressor *tdefl_compressor_alloc(); -// void tdefl_compressor_free(tdefl_compressor *pComp); - -#ifdef __cplusplus -} -#endif -#pragma once - -/* ------------------- Low-level Decompression API Definitions */ - -#ifdef __cplusplus -extern "C" { -#endif -/* Decompression flags used by tinfl_decompress(). */ -/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. */ -/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. */ -/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */ -/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */ -enum -{ - TINFL_FLAG_PARSE_ZLIB_HEADER = 1, - TINFL_FLAG_HAS_MORE_INPUT = 2, - TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, - TINFL_FLAG_COMPUTE_ADLER32 = 8 -}; - -/* High level decompression functions: */ -/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */ -/* On entry: */ -/* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */ -/* On return: */ -/* Function returns a pointer to the decompressed data, or NULL on failure. */ -/* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */ -/* The caller must call mz_free() on the returned block when it's no longer needed. */ -// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - -/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ -/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ -#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) -// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - -/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */ -/* Returns 1 on success or 0 on failure. */ -typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); -// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -struct tinfl_decompressor_tag; -typedef struct tinfl_decompressor_tag tinfl_decompressor; - -/* Allocate the tinfl_decompressor structure in C so that */ -/* non-C language bindings to tinfl_ API don't need to worry about */ -/* structure size and allocation mechanism. */ - -// tinfl_decompressor *tinfl_decompressor_alloc(); -// void tinfl_decompressor_free(tinfl_decompressor *pDecomp); - -/* Max size of LZ dictionary. */ -#define TINFL_LZ_DICT_SIZE 32768 - -/* Return status. */ -typedef enum { - /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is indicating that no more are available. The compressed data */ - /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input but this is a BAD sign (either the data is corrupted or you called it incorrectly). */ - /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */ - TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4, - - /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, but if you get this error the calling code is wrong.) */ - TINFL_STATUS_BAD_PARAM = -3, - - /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you call it again it'll return TINFL_STATUS_DONE. */ - TINFL_STATUS_ADLER32_MISMATCH = -2, - - /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */ - TINFL_STATUS_FAILED = -1, - - /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */ - - /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte that it needed, has successfully reached the end of the deflate stream, and */ - /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If you call it again you'll just get TINFL_STATUS_DONE over and over again. */ - TINFL_STATUS_DONE = 0, - - /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */ - /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also possible (but unlikely) for the inflator to keep on demanding input to */ - /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */ - TINFL_STATUS_NEEDS_MORE_INPUT = 1, - - /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write this data into the output buffer. */ - /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed data to the caller. I've been assuming you know how much uncompressed data to expect */ - /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure streaming scenarios where you have no idea how many bytes to expect this may not be possible */ - /* so I may need to add some code to address this. */ - TINFL_STATUS_HAS_MORE_OUTPUT = 2 -} tinfl_status; - -/* Initializes the decompressor to its initial state. */ -#define tinfl_init(r) \ - do \ - { \ - (r)->m_state = 0; \ - } \ - MZ_MACRO_END -#define tinfl_get_adler32(r) (r)->m_check_adler32 - -/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */ -/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */ -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); - -/* Internal/private bits follow. */ -enum -{ - TINFL_MAX_HUFF_TABLES = 3, - TINFL_MAX_HUFF_SYMBOLS_0 = 288, - TINFL_MAX_HUFF_SYMBOLS_1 = 32, - TINFL_MAX_HUFF_SYMBOLS_2 = 19, - TINFL_FAST_LOOKUP_BITS = 10, - TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS -}; - -typedef struct -{ - mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; - mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; -} tinfl_huff_table; - -#if MINIZ_HAS_64BIT_REGISTERS -#define TINFL_USE_64BIT_BITBUF 1 -#else -#define TINFL_USE_64BIT_BITBUF 0 -#endif - -#if TINFL_USE_64BIT_BITBUF -typedef mz_uint64 tinfl_bit_buf_t; -#define TINFL_BITBUF_SIZE (64) -#else -typedef mz_uint32 tinfl_bit_buf_t; -#define TINFL_BITBUF_SIZE (32) -#endif - -struct tinfl_decompressor_tag -{ - mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; - tinfl_bit_buf_t m_bit_buf; - size_t m_dist_from_out_buf_start; - tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; - mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; -}; - -#ifdef __cplusplus -} -#endif - -#pragma once - - -/* ------------------- ZIP archive reading/writing */ - -// #ifndef MINIZ_NO_ARCHIVE_APIS - -// #ifdef __cplusplus -// extern "C" { -// #endif - -// enum -// { - /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ -// MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, -// MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, -// MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 -// }; - -// typedef struct -// { -// /* Central directory file index. */ -// mz_uint32 m_file_index; - -// /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ -// mz_uint64 m_central_dir_ofs; - -// /* These fields are copied directly from the zip's central dir. */ -// mz_uint16 m_version_made_by; -// mz_uint16 m_version_needed; -// mz_uint16 m_bit_flag; -// mz_uint16 m_method; - -// #ifndef MINIZ_NO_TIME -// MZ_TIME_T m_time; -// #endif - -// /* CRC-32 of uncompressed data. */ -// mz_uint32 m_crc32; - -// /* File's compressed size. */ -// mz_uint64 m_comp_size; - -// /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ -// mz_uint64 m_uncomp_size; - -// /* Zip internal and external file attributes. */ -// mz_uint16 m_internal_attr; -// mz_uint32 m_external_attr; - -// /* Entry's local header file offset in bytes. */ -// mz_uint64 m_local_header_ofs; - -// /* Size of comment in bytes. */ -// mz_uint32 m_comment_size; - -// /* MZ_TRUE if the entry appears to be a directory. */ -// mz_bool m_is_directory; - -// /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ -// mz_bool m_is_encrypted; - -// /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ -// mz_bool m_is_supported; - -// /* Filename. If string ends in '/' it's a subdirectory entry. */ -// /* Guaranteed to be zero terminated, may be truncated to fit. */ -// char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; - -// /* Comment field. */ -// /* Guaranteed to be zero terminated, may be truncated to fit. */ -// char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; - -// } mz_zip_archive_file_stat; - -// typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); -// typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); -// typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); - -// struct mz_zip_internal_state_tag; -// typedef struct mz_zip_internal_state_tag mz_zip_internal_state; - -// typedef enum { -// MZ_ZIP_MODE_INVALID = 0, -// MZ_ZIP_MODE_READING = 1, -// MZ_ZIP_MODE_WRITING = 2, -// MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 -// } mz_zip_mode; - -// typedef enum { -// MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, -// MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, -// MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, -// MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, - // MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ - // MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ - // MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ -// MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, -// MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 -// } mz_zip_flags; - -// typedef enum { -// MZ_ZIP_TYPE_INVALID = 0, -// MZ_ZIP_TYPE_USER, -// MZ_ZIP_TYPE_MEMORY, -// MZ_ZIP_TYPE_HEAP, -// MZ_ZIP_TYPE_FILE, -// MZ_ZIP_TYPE_CFILE, -// MZ_ZIP_TOTAL_TYPES -// } mz_zip_type; - -/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ -// typedef enum { -// MZ_ZIP_NO_ERROR = 0, -// MZ_ZIP_UNDEFINED_ERROR, -// MZ_ZIP_TOO_MANY_FILES, -// MZ_ZIP_FILE_TOO_LARGE, -// MZ_ZIP_UNSUPPORTED_METHOD, -// MZ_ZIP_UNSUPPORTED_ENCRYPTION, -// MZ_ZIP_UNSUPPORTED_FEATURE, -// MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, -// MZ_ZIP_NOT_AN_ARCHIVE, -// MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, -// MZ_ZIP_UNSUPPORTED_MULTIDISK, -// MZ_ZIP_DECOMPRESSION_FAILED, -// MZ_ZIP_COMPRESSION_FAILED, -// MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, -// MZ_ZIP_CRC_CHECK_FAILED, -// MZ_ZIP_UNSUPPORTED_CDIR_SIZE, -// MZ_ZIP_ALLOC_FAILED, -// MZ_ZIP_FILE_OPEN_FAILED, -// MZ_ZIP_FILE_CREATE_FAILED, -// MZ_ZIP_FILE_WRITE_FAILED, -// MZ_ZIP_FILE_READ_FAILED, -// MZ_ZIP_FILE_CLOSE_FAILED, -// MZ_ZIP_FILE_SEEK_FAILED, -// MZ_ZIP_FILE_STAT_FAILED, -// MZ_ZIP_INVALID_PARAMETER, -// MZ_ZIP_INVALID_FILENAME, -// MZ_ZIP_BUF_TOO_SMALL, -// MZ_ZIP_INTERNAL_ERROR, -// MZ_ZIP_FILE_NOT_FOUND, -// MZ_ZIP_ARCHIVE_TOO_LARGE, -// MZ_ZIP_VALIDATION_FAILED, -// MZ_ZIP_WRITE_CALLBACK_FAILED, -// MZ_ZIP_TOTAL_ERRORS -// } mz_zip_error; - -// typedef struct -// { -// mz_uint64 m_archive_size; -// mz_uint64 m_central_directory_file_ofs; - -// /* We only support up to UINT32_MAX files in zip64 mode. */ -// mz_uint32 m_total_files; -// mz_zip_mode m_zip_mode; -// mz_zip_type m_zip_type; -// mz_zip_error m_last_error; - -// mz_uint64 m_file_offset_alignment; - -// mz_alloc_func m_pAlloc; -// mz_free_func m_pFree; -// mz_realloc_func m_pRealloc; -// void *m_pAlloc_opaque; - -// mz_file_read_func m_pRead; -// mz_file_write_func m_pWrite; -// mz_file_needs_keepalive m_pNeeds_keepalive; -// void *m_pIO_opaque; - -// mz_zip_internal_state *m_pState; - -// } mz_zip_archive; - -// typedef struct -// { -// mz_zip_archive *pZip; -// mz_uint flags; - -// int status; -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// mz_uint file_crc32; -// #endif -// mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; -// mz_zip_archive_file_stat file_stat; -// void *pRead_buf; -// void *pWrite_buf; - -// size_t out_blk_remain; - -// tinfl_decompressor inflator; - -// } mz_zip_reader_extract_iter_state; - -/* -------- ZIP reading */ - -/* Inits a ZIP archive reader. */ -/* These functions read and validate the archive's central directory. */ -// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); - -// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); - -// #ifndef MINIZ_NO_STDIO -/* Read a archive from a disk file. */ -/* file_start_ofs is the file offset where the archive actually begins, or 0. */ -/* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */ -// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); -// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); - -/* Read an archive from an already opened FILE, beginning at the current file position. */ -/* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */ -/* The FILE will NOT be closed when mz_zip_reader_end() is called. */ -// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); -// #endif - -/* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */ -// mz_bool mz_zip_reader_end(mz_zip_archive *pZip); - -/* -------- ZIP reading or writing */ - -/* Clears a mz_zip_archive struct to all zeros. */ -/* Important: This must be done before passing the struct to any mz_zip functions. */ -// void mz_zip_zero_struct(mz_zip_archive *pZip); - -// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); -// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); - -/* Returns the total number of files in the archive. */ -// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); - -// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); -// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); -// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); - -/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ -// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); - -/* Attempts to locates a file in the archive's central directory. */ -/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ -/* Returns -1 if the file cannot be found. */ -// int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); -/* Returns MZ_FALSE if the file cannot be found. */ -// mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex); - -/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */ -/* Note that the m_last_error functionality is not thread safe. */ -// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); -// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); -// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); -// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); -// const char *mz_zip_get_error_string(mz_zip_error mz_err); - -/* MZ_TRUE if the archive file entry is a directory entry. */ -// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); - -/* MZ_TRUE if the file is encrypted/strong encrypted. */ -// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); - -/* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */ -// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); - -/* Retrieves the filename of an archive file entry. */ -/* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */ -// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); - -/* Attempts to locates a file in the archive's central directory. */ -/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ -/* Returns -1 if the file cannot be found. */ -// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); -// int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); - -/* Returns detailed information about an archive file entry. */ -// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); - -/* MZ_TRUE if the file is in zip64 format. */ -/* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */ -// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); - -/* Returns the total central directory size in bytes. */ -/* The current max supported size is <= MZ_UINT32_MAX. */ -// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); - -/* Extracts a archive file to a memory buffer using no memory allocation. */ -/* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ -// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); -// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); - -/* Extracts a archive file to a memory buffer. */ -// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); -// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); - -/* Extracts a archive file to a dynamically allocated heap buffer. */ -/* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ -/* Returns NULL and sets the last error on failure. */ -// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); -// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); - -/* Extracts a archive file using a callback function to output the file's data. */ -// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); -// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); - -/* Extract a file iteratively */ -// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); -// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); -// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); -// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); - -// #ifndef MINIZ_NO_STDIO -/* Extracts a archive file to a disk file and sets its last accessed and modified times. */ -/* This function only extracts files, not archive directory records. */ -// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); -// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); - -/* Extracts a archive file starting at the current position in the destination FILE stream. */ -// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); -// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); -// #endif - -#if 0 -/* TODO */ - typedef void *mz_zip_streaming_extract_state_ptr; - mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); - uint64_t mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); - uint64_t mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); - mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, uint64_t new_ofs); - size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size); - mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); -#endif - -/* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */ -/* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */ -// mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); - -/* Validates an entire archive by calling mz_zip_validate_file() on each file. */ -// mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags); - -/* Misc utils/helpers, valid for ZIP reading or writing */ -// mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr); -// mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); - -/* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ -// mz_bool mz_zip_end(mz_zip_archive *pZip); - -/* -------- ZIP writing */ - -// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - -/* Inits a ZIP archive writer. */ -/*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ -/*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ -// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); -// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); - -// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); -// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); - -// #ifndef MINIZ_NO_STDIO -// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); -// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); -// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); -// #endif - -/* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */ -/* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ -/* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). */ -/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */ -/* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */ -/* the archive is finalized the file's central directory will be hosed. */ -// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); -// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); - -/* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */ -/* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ -/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ -// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); - -/* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */ -/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ -// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); - -// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, -// const char *user_extra_data_central, mz_uint user_extra_data_central_len); - -// #ifndef MINIZ_NO_STDIO -/* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */ -/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ -// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - -/* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ -// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, -// const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, -// const char *user_extra_data_central, mz_uint user_extra_data_central_len); -// #endif - -/* Adds a file to an archive by fully cloning the data from another archive. */ -/* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */ -// mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index); - -/* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ -/* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ -/* An archive must be manually finalized by calling this function for it to be valid. */ -// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); - -/* Finalizes a heap archive, returning a poiner to the heap block and its size. */ -/* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ -// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); - -/* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ -/* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */ -// mz_bool mz_zip_writer_end(mz_zip_archive *pZip); - -/* -------- Misc. high-level helper functions: */ - -/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */ -/* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */ -/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ -/* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */ -// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); -// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); - -/* Reads a single file from an archive into a heap block. */ -/* If pComment is not NULL, only the file with the specified comment will be extracted. */ -/* Returns NULL on failure. */ -// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); -// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); - -// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ - -// #ifdef __cplusplus -// } -// #endif - -// #endif /* MINIZ_NO_ARCHIVE_APIS */ diff --git a/gomspace/libutil/src/zip/zip.c b/gomspace/libutil/src/zip/zip.c deleted file mode 100644 index b7fd00fc..00000000 --- a/gomspace/libutil/src/zip/zip.c +++ /dev/null @@ -1,357 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include "gs/util/zip/zip.h" -#include "miniz/miniz.h" - -#include -#include -#include - -#include - -static void cleanup(FILE *pInfile, FILE *pOutfile, uint8_t *stream_inbuf, uint8_t *stream_outbuf) -{ - if(pInfile) - fclose(pInfile); - - if(pOutfile) - fclose(pOutfile); - - if(stream_inbuf) - free(stream_inbuf); - - if(stream_outbuf) - free(stream_outbuf); -} - -int gs_zip_compress_file(const char *src, const char *dest) -{ - FILE *pInfile, *pOutfile; - uint32_t infile_size; - long file_loc; - - // Open input file. - pInfile = fopen(src, "rb"); - if (!pInfile) - { - log_error("Zip compress: Failed opening input file!"); - return GS_ERROR_IO; - } - - // Determine input file's size. - fseek(pInfile, 0, SEEK_END); - file_loc = ftell(pInfile); - fseek(pInfile, 0, SEEK_SET); - - if((file_loc < 0) || ((unsigned long)file_loc > UINT_MAX)) - { - log_error("Zip compress: File is too large to be processed."); - fclose(pInfile); - - return GS_ERROR_IO; - } - - infile_size = (uint32_t)file_loc; - uint32_t buffer_size = infile_size; - - // Allocate input buffer memory - uint8_t *stream_inbuf = malloc(buffer_size); - if (stream_inbuf == NULL) - { - log_error("Zip compress: Failed to allocate input buffer memory"); - fclose(pInfile); - - return GS_ERROR_IO; - } - - // Allocate output buffer memory - uint8_t *stream_outbuf = malloc(buffer_size); - if (stream_outbuf == NULL) - { - log_error("Zip compress: Failed to allocate output buffer memory"); - cleanup(pInfile, NULL, stream_inbuf, NULL); - - return GS_ERROR_IO; - } - - // Open output file. - pOutfile = fopen(dest, "wb"); - if (!pOutfile) - { - log_error("Zip compress: Failed opening output file!"); - cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); - - return GS_ERROR_IO; - } - - // Init the z_stream - z_stream stream; - memset(&stream, 0, sizeof(stream)); - stream.next_in = stream_inbuf; - stream.avail_in = 0; - stream.next_out = stream_outbuf; - stream.avail_out = buffer_size; - - // Compression. - uint32_t infile_remaining = infile_size; - - if(deflateInit(&stream, Z_BEST_COMPRESSION) != Z_OK) - { - log_error("Zip compress: deflateInit() failed!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_DATA; - } - - for( ; ; ) - { - int status; - if(!stream.avail_in) - { - // Input buffer is empty, so read more bytes from input file. - uint32_t n = gs_min((uint32_t)buffer_size, infile_remaining); - - if (fread(stream_inbuf, 1, n, pInfile) != n) - { - log_error("Zip compress: Failed reading from input file!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_IO; - } - - stream.next_in = stream_inbuf; - stream.avail_in = n; - - infile_remaining -= n; - } - - status = deflate(&stream, infile_remaining ? Z_NO_FLUSH : Z_FINISH); - - if((status == Z_STREAM_END) || (!stream.avail_out)) - { - // Output buffer is full, or compression is done, so write buffer to output file. - uint32_t n = buffer_size - stream.avail_out; - if (fwrite(stream_outbuf, 1, n, pOutfile) != n) - { - log_error("Zip compress: Failed writing to output file!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_IO; - } - - stream.next_out = stream_outbuf; - stream.avail_out = buffer_size; - } - - if(status == Z_STREAM_END) - { - break; - } - else if(status != Z_OK) - { - log_error("Zip compress: deflate() failed with status %i!", status); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_DATA; - } - } - - if(deflateEnd(&stream) != Z_OK) - { - log_error("Zip compress: deflateEnd() failed!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_DATA; - } - - - cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); - if(EOF == fclose(pOutfile)) - { - log_error("Zip compress: Failed writing to output file!"); - return GS_ERROR_IO; - } - - log_debug("Total input bytes: %u\n", (mz_uint32)stream.total_in); - log_debug("Total output bytes: %u\n", (mz_uint32)stream.total_out); - log_debug("Success.\n"); - - return GS_OK; -} - -int gs_zip_decompress_file(const char *src, const char *dest) -{ - FILE *pInfile, *pOutfile; - uint32_t infile_size; - long file_loc; - - // Open input file. - pInfile = fopen(src, "rb"); - if (!pInfile) - { - log_error("Zip decompress: Failed opening input file!"); - return GS_ERROR_IO; - } - - // Determine input file's size. - fseek(pInfile, 0, SEEK_END); - file_loc = ftell(pInfile); - fseek(pInfile, 0, SEEK_SET); - - if((file_loc < 0) || ((unsigned long)file_loc > UINT_MAX)) - { - log_error("Zip decompress: File is too large to be processed."); - fclose(pInfile); - - return GS_ERROR_IO; - } - - infile_size = (uint32_t)file_loc; - uint32_t buffer_size = infile_size; - - // Allocate input buffer memory - uint8_t *stream_inbuf = malloc(buffer_size); - if (stream_inbuf == NULL) - { - log_error("Zip decompress: Failed to allocate input buffer memory"); - fclose(pInfile); - - return GS_ERROR_IO; - } - - // Allocate output buffer memory - uint8_t *stream_outbuf = malloc(buffer_size); - if (stream_outbuf == NULL) - { - log_error("Zip decompress: Failed to allocate output buffer memory"); - cleanup(pInfile, NULL, stream_inbuf, NULL); - - return GS_ERROR_IO; - } - - // Open output file. - pOutfile = fopen(dest, "wb"); - if (!pOutfile) - { - log_error("Zip decompress: Failed opening output file!"); - cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); - - return GS_ERROR_IO; - } - - // Init the z_stream - z_stream stream; - memset(&stream, 0, sizeof(stream)); - stream.next_in = stream_inbuf; - stream.avail_in = 0; - stream.next_out = stream_outbuf; - stream.avail_out = buffer_size; - - // Decompression. - uint32_t infile_remaining = infile_size; - - if(inflateInit(&stream)) - { - log_error("Zip decompress: inflateInit() failed!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_DATA; - } - - for( ; ; ) - { - int status; - if(!stream.avail_in) - { - // Input buffer is empty, so read more bytes from input file. - uint32_t n = gs_min((uint32_t)buffer_size, infile_remaining); - - if(fread(stream_inbuf, 1, n, pInfile) != n) - { - log_error("Zip decompress: Failed reading from input file!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_IO; - } - - stream.next_in = stream_inbuf; - stream.avail_in = n; - - infile_remaining -= n; - } - - status = inflate(&stream, Z_SYNC_FLUSH); - - if((status == Z_STREAM_END) || (!stream.avail_out)) - { - // Output buffer is full, or decompression is done, so write buffer to output file. - uint32_t n = buffer_size - stream.avail_out; - if(fwrite(stream_outbuf, 1, n, pOutfile) != n) - { - log_error("Zip decompress: Failed writing to output file!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_IO; - } - stream.next_out = stream_outbuf; - stream.avail_out = buffer_size; - } - - if(status == Z_STREAM_END) - { - break; - } - else if(status != Z_OK) - { - log_error("Zip decompress: inflate() failed with status %i!", status); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_DATA; - } - } - - if(inflateEnd(&stream) != Z_OK) - { - log_error("Zip decompress: inflateEnd() failed!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_DATA; - } - - cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); - if(EOF == fclose(pOutfile)) - { - log_error("Zip decompress: Failed writing to output file!"); - return GS_ERROR_IO; - } - - log_debug("Total input bytes: %u", (mz_uint32)stream.total_in); - log_debug("Total output bytes: %u", (mz_uint32)stream.total_out); - log_debug("Success.\n"); - - return GS_OK; -} - -int gs_zip_compress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t *dest_len) -{ - mz_ulong cmp_len = src_len; - if(compress(dest, &cmp_len, src, (mz_ulong)src_len) != MZ_OK) - { - return GS_ERROR_DATA; - } - - *dest_len = cmp_len; - - return GS_OK; -} - -int gs_zip_decompress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t dest_len, uint32_t *decomp_len) -{ - mz_ulong tmp = dest_len; - if(uncompress(dest, &tmp, src, (mz_ulong)src_len) != MZ_OK) - return GS_ERROR_DATA; - - *decomp_len = tmp; - - return GS_OK; -} diff --git a/gomspace/libutil/wscript b/gomspace/libutil/wscript deleted file mode 100644 index 48421e39..00000000 --- a/gomspace/libutil/wscript +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -# Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. - -import gs_gcc -import gs_doc -import gs_dist -from waflib.Build import BuildContext - -APPNAME = 'util' - - -def options(ctx): - ctx.load('gs_gcc gs_doc') - gs_gcc.gs_recurse(ctx) - - gr = ctx.add_option_group('libutil options') - gr.add_option('--console-history-len', metavar='LEN', default=10, type=int, help='Command history length, 0=none') - gr.add_option('--console-input-len', metavar='LEN', default=100, type=int, help='Command input length') - gr.add_option('--util-enable-isr-logs', action='store_true', help='Enable ISR logs') - - -def configure(ctx): - ctx.load('gs_gcc gs_doc') - - ctx.env.append_unique('FILES_LIBUTIL', ['src/*.c', - 'src/gosh/**/*.c', - 'src/log/**/*.c', - 'src/vmem/**/*.c', - 'src/watchdog/**/*.c', - 'src/drivers/**/*.c']) - - if ctx.env.GS_ARCH not in ['avr8']: - ctx.env.append_unique('FILES_LIBUTIL', ['src/zip/**/*.c']) - - if ctx.gs_is_linux(): - ctx.env.append_unique('FILES_LIBUTIL', ['src/linux/**/*.c']) - - ctx.env.GS_UTIL_CMOCKA = ctx.check_cfg(package='cmocka', args='--cflags --libs', - atleast_version='1.0.1', mandatory=False) - - # Check compiler endianness - avr32 GCC doesn't support endian defines - endianness = ctx.check_endianness() - ctx.define_cond('UTIL_LITTLE_ENDIAN', endianness == 'little') - ctx.define_cond('UTIL_BIG_ENDIAN', endianness == 'big') - - ctx.define('GS_CONSOLE_HISTORY_LEN', ctx.options.console_history_len) - ctx.define('GS_CONSOLE_INPUT_LEN', ctx.options.console_input_len) - ctx.define_cond('GS_LOG_ENABLE_ISR_LOGS', ctx.options.util_enable_isr_logs) - - ctx.gs_write_config_header('include/conf_util.h', remove=True) - - ctx.gs_add_doxygen(example=['tst'], exclude=['*/include/gs/uthash/*', - '*/include/gs/util/zip/*', - '*/include/deprecated/util/*', - '*/include/deprecated/gs/gosh/*']) - - ctx.gs_register_handler(function='command_gen_4_0', filepath='./tools/waf_command.py') - - gs_gcc.gs_recurse(ctx) - - -def build(ctx): - gs_gcc.gs_recurse(ctx) - - public_include = ctx.gs_include(name=APPNAME, - includes=['include', 'include/gs', - 'include/deprecated', 'include/deprecated/gs/gosh/'], - config_header=['include/conf_util.h']) - - ctx.gs_objects(source=ctx.path.ant_glob(ctx.env.FILES_LIBUTIL), - target=APPNAME, - includes=['src'], - use=ctx.env.USE_LIBUTIL + [public_include]) - - ctx.gs_shlib(source=ctx.path.ant_glob(ctx.env.FILES_LIBUTIL), - target=APPNAME, - includes=['src'], - gs_use_shlib=ctx.env.USE_LIBUTIL, - use=[public_include], - lib=['pthread']) - - ctx.gs_python_bindings(source=ctx.path.ant_glob('src/bindings/python/*.c'), - target=APPNAME, - gs_use_shlib=ctx.env.USE_LIBUTIL + [APPNAME], - use=[public_include], - package='libutil') - - if ctx.env.GS_UTIL_CMOCKA: - ctx.gs_stlib(source=ctx.path.ant_glob('src/test/*.c'), - name=APPNAME + '_cmocka', # overwrite default naming - target=APPNAME + '_cmocka', - includes=['include']) - - -def doc(ctx): - gs_doc.gs_library_doc(ctx, keyvalues={ - 'gs_prod_name': 'lib'+APPNAME, - 'gs_prod_desc': 'Low level APIs and utilities', - 'gs_sphinx_exclude': ['CHANGELOG.rst'], - }) - - -class Doc(BuildContext): - cmd = fun = 'doc' - - -def gs_dist(ctx): - ctx.add_default_files(source_module=True) diff --git a/mission/core/InitMission.cpp b/mission/core/InitMission.cpp index 62b50418..a2697329 100644 --- a/mission/core/InitMission.cpp +++ b/mission/core/InitMission.cpp @@ -144,7 +144,7 @@ void InitMission::initTasks(){ PeriodicTaskIF* P60DockTestTask = TaskFactory::instance()-> createPeriodicTask("P60 Dock", 50 , 4096, 1, nullptr); - result = PusLowPrio->addComponent(objects::P60_DOCK_TEST_TASK); + result = PusLowPrio->addComponent(objects::P60DOCK_TEST_TASK); if(result!=HasReturnvaluesIF::RETURN_OK){ sif::error << "Object add component failed" << std::endl; } diff --git a/mission/core/ObjectFactory.cpp b/mission/core/ObjectFactory.cpp index d6bc80c4..c8f8f7bb 100644 --- a/mission/core/ObjectFactory.cpp +++ b/mission/core/ObjectFactory.cpp @@ -39,7 +39,7 @@ //#include //#include //#include -#include +#include #endif void Factory::setStaticFrameworkObjectIds(){ @@ -125,12 +125,12 @@ void ObjectFactory::produce(){ /* Test Device Handler */ #if ADD_TEST_CODE == 1 - new TestTask(objects::TEST_TASK); +// new TestTask(objects::TEST_TASK); // CookieIF* testCookie = new TestCookie(0); // new TestEchoComIF(objects::TEST_ECHO_COM_IF); // new TestDevice(objects::TEST_DEVICE_HANDLER, objects::TEST_ECHO_COM_IF, // testCookie, true); - new ArduinoComIF(objects::ARDUINO_COM_IF, true, nullptr); +// new ArduinoComIF(objects::ARDUINO_COM_IF, true, nullptr); new P60DockTestTask(objects::P60DOCK_TEST_TASK); #endif } diff --git a/mission/devices/P60DockHandler.cpp b/mission/devices/P60DockHandler.cpp index 500355d7..f3ccc925 100644 --- a/mission/devices/P60DockHandler.cpp +++ b/mission/devices/P60DockHandler.cpp @@ -9,15 +9,15 @@ #include #include "P60DockHandler.h" -P60DockHandler::P60DockHandler() { - -} - - -P60DockHandler::~P60DockHandler() { -} - - -P60DockHandler::performOperation(uint8_t operationCode) { - -} +//P60DockHandler::P60DockHandler() { +// +//} +// +// +//P60DockHandler::~P60DockHandler() { +//} +// +// +//P60DockHandler::performOperation(uint8_t operationCode) { +// +//} diff --git a/mission/devices/P60DockHandler.h b/mission/devices/P60DockHandler.h index cecd5e75..20078cd8 100644 --- a/mission/devices/P60DockHandler.h +++ b/mission/devices/P60DockHandler.h @@ -8,11 +8,11 @@ #ifndef MISSION_DEVICES_P60DOCKHANDLER_H_ #define MISSION_DEVICES_P60DOCKHANDLER_H_ -class P60DockHandler: public DeviceHandlerBase { -public: - P60DockHandler(); - virtual ~P60DockHandler(); - virtual ReturnValue_t performOperation(uint8_t operationCode = 0); -}; +//class P60DockHandler: public DeviceHandlerBase { +//public: +// P60DockHandler(); +// virtual ~P60DockHandler(); +// virtual ReturnValue_t performOperation(uint8_t operationCode = 0); +//}; #endif /* MISSION_DEVICES_P60DOCKHANDLER_H_ */ diff --git a/test/testtasks/P60DockTestTask.cpp b/test/testtasks/P60DockTestTask.cpp index 962521cb..3db66933 100644 --- a/test/testtasks/P60DockTestTask.cpp +++ b/test/testtasks/P60DockTestTask.cpp @@ -2,82 +2,100 @@ * P60DockTestTask.cpp * * Created on: 18.11.2020 - * Author: jakob + * Author: Jakob Meier */ -#include +#include + +#include #include "P60DockTestTask.h" P60DockTestTask::P60DockTestTask(object_id_t objectId_): SystemObject(objectId_){ - /* Init buffer system with 10 packets of maximum 320 bytes each */ -// csp_buffer_init(10, 320); - - uint8_t device = 0; - uint8_t csp_addr = 4; /* Current address of p60 dock */ - uint8_t mtu = 320; /* Packets larger than the set mtu will be discarded */ - char name[5] = "can0"; - - /* Init the CAN interface */ - gs_error_t result = gs_csp_can_init(device, csp_addr, mtu, name, csp_if); - if(result != GS_OK){ - sif::error << "gs_csp_can_init failed with error code: " << result - << std::endl; + if(initializeCSPStack() != HasReturnvaluesIF::RETURN_OK){ + sif::error << "P60DockTestTask creation failed" << std::endl; } } ReturnValue_t P60DockTestTask::performOperation(uint8_t operationCode) { - char data[5] = "test"; - int timeout_ms = 1000; - /* Send a csp packet to the can interface */ - g_error_t result = csp_can_tx_frame(csp_if, canExtMsgId, (uint8*) data, sizeof(data), - timeout_ms); - if(result != GS_OK){ - sif::error << "csp_can_tx_frame failed with error code " << result - << std::endl; + if(sendPacket() != HasReturnvaluesIF::RETURN_OK){ + return HasReturnvaluesIF::RETURN_FAILED; } + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t P60DockTestTask::sendPacket(void){ - /* Get packet buffer for data */ - csp_packet_t *packet = csp_buffer_get(data_size); - if (packet == NULL) { - /* Could not get buffer element */ - sif::error("Failed to get buffer element\\n"); +// char *msg = "HELLO"; +// /* Get packet buffer for data */ +// csp_packet_t *packet = csp_buffer_get(strlen(msg)); +// if (packet == NULL) { +// /* Could not get buffer element */ +// sif::error("Failed to get buffer element\\n"); +// return HasReturnvaluesIF::RETURN_FAILED; +// } +// +// /* Connect P60 Dock */ +// csp_conn_t *conn = csp_connect(CSP_PRIO_NORM, c, CSP_PING, +// 1000, CSP_O_NONE); +// +// if (conn == NULL) { +// /* Connect failed */ +// sif::error("Connection failed\\n"); +// /* Remember to free packet buffer */ +// csp_buffer_free(packet); +// return HasReturnvaluesIF::RETURN_FAILED; +// } +// +// /* Copy message to packet */ +// strcpy(packet->data, msg); +// /* Set packet length */ +// packet->length = strlen(msg); +// +// /* Send packet */ +// if (!csp_send(conn, packet, 1000)) { +// /* Send failed */ +// sif::error("Send failed\\n"); +// csp_buffer_free(packet); +// } +// /* Close connection */ +// csp_close(conn); + + uint32_t timeout = 1000; + unsigned int pingSize = 100; // 100 bytes + uint32_t replyTime = csp_ping(p60dockAddress, timeout, pingSize, CSP_O_NONE); + sif::info << "Ping address: " << p60dockAddress << ", reply after " + << replyTime << "ms" << std::endl; + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t P60DockTestTask::initializeCSPStack(void){ + /* Init CSP and CSP buffer system */ + if (csp_init(cspAddress) != CSP_ERR_NONE + || csp_buffer_init(10, 300) != CSP_ERR_NONE) { + sif::error << "Failed to init CSP\r\n" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } - /* Connect to host HOST, port PORT with regular UDP-like protocol and - * 1000 ms timeout */ - csp_conn_t *conn = csp_connect(CSP_PRIO_NORM, HOST, PORT, 1000, CSP_O_NONE); + csp_iface_t *csp_if_ptr = &csp_if; + csp_if_ptr = csp_can_socketcan_init("can0", bitrate, promisc); - if (conn == NULL) { - /* Connect failed */ - sif::error("Connection failed\\n"); - /* Remember to free packet buffer */ - csp_buffer_free(packet); - return HasReturnvaluesIF::RETURN_FAILED; + /* Set default route and start router */ + int result = csp_rtable_set(CSP_DEFAULT_ROUTE, 0, csp_if_ptr, CSP_NODE_MAC); + if(result != CSP_ERR_NONE){ + sif::error << "Failed to add can interface to router table" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; } - - /* Copy message to packet */ - char *msg = "HELLO"; - strcpy(packet->data, msg); - /* Set packet length */ - packet->length = strlen(msg); - - /* Send packet */ - if (!csp_send(conn, packet, 1000)) { - /* Send failed */ - sif::error("Send failed\\n"); - csp_buffer_free(packet); + result = csp_route_start_task(500, 0); + if(result != CSP_ERR_NONE){ + sif::error << "Failed to start route task" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; } - /* Close connection */ - csp_close(conn); - return HasReturnvaluesIF::RETURN_OK; } diff --git a/test/testtasks/P60DockTestTask.h b/test/testtasks/P60DockTestTask.h index 860a3937..bcccb487 100644 --- a/test/testtasks/P60DockTestTask.h +++ b/test/testtasks/P60DockTestTask.h @@ -8,15 +8,21 @@ #ifndef TEST_TESTTASKS_P60DOCKTESTTASK_H_ #define TEST_TESTTASKS_P60DOCKTESTTASK_H_ +#include +#include +#include + extern "C" { #include #include } -class P60DockTestTask: public ExecutableObjectIF { +class P60DockTestTask: public SystemObject, + public ExecutableObjectIF, + public HasReturnvaluesIF { public: - P60DockTestTask(); + P60DockTestTask(object_id_t objectId_); virtual ~P60DockTestTask(); virtual ReturnValue_t performOperation(uint8_t operationCode = 0); @@ -24,11 +30,15 @@ public: private: /* Interface struct for csp protocol stack */ csp_iface_t csp_if; - uint32_t canExtMsgId = 4; - /* CAN configuration struct for SocketCAN interface "can0" */ - struct csp_can_config can_conf = {.ifc = "can0"}; + uint8_t p60dockAddress = 4; + uint8_t CSP_PING = 1; + uint8_t cspAddress = 1; + const char* canIf = "can0"; + int bitrate = 1000; // bitrate of can + int promisc = 0; // set to 0 to enable filter mode ReturnValue_t sendPacket(void); + ReturnValue_t initializeCSPStack(void); }; From d0cb4f84452dacb75898adadf34a2f6b6a7992bd Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Wed, 25 Nov 2020 09:19:51 +0100 Subject: [PATCH 003/360] bring up can, readme --- README.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f4e6f2e9..3f0c7f91 100644 --- a/README.md +++ b/README.md @@ -186,11 +186,27 @@ systemctl status example ```` More detailed information about the used q7s commands can be found in the Q7S user manual. - - -### Update file in rootfs +### Bringing up CAN ```` -writeprotect 0 0 0 # qspi0 nom unlock (see also Q7S user manual) +ip link set can0 down +ip link set can0 type can loopback off +ip link set can0 up type can bitrate 1000000 +```` +Following command sends 8 bytes to device with id 99 (for petalinux) +```` +cansend can0 -i99 99 88 77 11 33 11 22 99 +```` +For Q7S use this: +```` +cansend can0 5A1#11.22.33.44.55.66.77.88 +```` +Turn loopback mode on: +```` +ip link set can0 type can bitrate 1000000 loopback on +```` +Reading data from CAN: +```` +candump can0 ```` ### Setting up UNIX environment for real-time functionalities From 6bd55e7c222c8039184f9f39154f3217920ec55d Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Thu, 26 Nov 2020 10:24:23 +0100 Subject: [PATCH 004/360] save failed integration state --- gomspace/gomspace.mk | 10 +- gomspace/libp60_client/include/p60.h | 48 + gomspace/libp60_client/include/p60_board.h | 35 + gomspace/libp60_client/include/power_if.h | 62 + gomspace/libp60_client/src/cmd/power_if_cmd.c | 147 + gomspace/libp60_client/src/p60_client.c | 33 + gomspace/libp60_client/src/power_if.c | 91 + gomspace/libp60_client/wscript | 28 + .../include/deprecated/param/param_client.h | 15 + .../include/deprecated/param/param_lock.h | 27 + .../deprecated/param/param_serializer.h | 55 + .../include/deprecated/param/param_string.h | 74 + .../include/deprecated/param/param_types.h | 92 + .../include/deprecated/param/rparam_client.h | 208 + .../include/gs/param/internal/pp/i2c/i2c.h | 42 + .../gs/param/internal/pp/i2c/slave_dispatch.h | 71 + .../gs/param/internal/pp/spi/slave_dispatch.h | 80 + .../include/gs/param/internal/pp/spi/spi.h | 65 + .../include/gs/param/internal/rparam.h | 146 + .../include/gs/param/internal/serialize.h | 29 + .../include/gs/param/internal/table.h | 19 + .../include/gs/param/internal/types.h | 129 + .../include/gs/param/pp/i2c/i2c.h | 60 + .../libparam_client/include/gs/param/pp/pp.h | 214 + .../include/gs/param/pp/spi/spi.h | 29 + .../libparam_client/include/gs/param/rparam.h | 395 + .../include/gs/param/serialize.h | 101 + .../libparam_client/include/gs/param/table.h | 428 + .../libparam_client/include/gs/param/types.h | 272 + .../src/bindings/python/pyparam.c | 1084 ++ .../libparam_client/src/pp/cmd/master_cmd.c | 418 + gomspace/libparam_client/src/pp/i2c/i2c.c | 129 + gomspace/libparam_client/src/pp/pp.c | 189 + gomspace/libparam_client/src/pp/spi/spi.c | 91 + .../src/rparam/cmd/cmd_rparam.c | 354 + .../src/rparam/deprecated_rparam.c | 6 + gomspace/libparam_client/src/rparam/query.c | 212 + gomspace/libparam_client/src/rparam/query.h | 110 + gomspace/libparam_client/src/rparam/rparam.c | 474 + gomspace/libparam_client/src/serialize.c | 353 + .../libparam_client/src/serialize_local.h | 9 + gomspace/libparam_client/src/string.c | 589 + gomspace/libparam_client/src/table.c | 393 + gomspace/libparam_client/wscript | 69 + gomspace/libutil/include/conf_util.h | 12 + .../deprecated/gs/gosh/command/command.h | 49 + .../include/deprecated/gs/gosh/gosh/getopt.h | 22 + .../include/deprecated/gs/gosh/util/console.h | 43 + .../include/deprecated/util/color_printf.h | 26 + gomspace/libutil/include/gs/uthash/utarray.h | 231 + gomspace/libutil/include/gs/uthash/uthash.h | 960 ++ gomspace/libutil/include/gs/uthash/utlist.h | 757 ++ gomspace/libutil/include/gs/uthash/utstring.h | 393 + gomspace/libutil/include/gs/util/base16.h | 90 + gomspace/libutil/include/gs/util/bytebuffer.h | 173 + gomspace/libutil/include/gs/util/byteorder.h | 341 + gomspace/libutil/include/gs/util/check.h | 54 + gomspace/libutil/include/gs/util/clock.h | 88 + gomspace/libutil/include/gs/util/crc32.h | 55 + gomspace/libutil/include/gs/util/crc8.h | 55 + gomspace/libutil/include/gs/util/delay.h | 42 + .../libutil/include/gs/util/drivers/can/can.h | 122 + .../include/gs/util/drivers/gpio/gpio.h | 91 + .../include/gs/util/drivers/i2c/common.h | 88 + .../include/gs/util/drivers/i2c/master.h | 32 + .../include/gs/util/drivers/i2c/slave.h | 79 + .../include/gs/util/drivers/spi/common.h | 66 + .../include/gs/util/drivers/spi/master.h | 95 + .../include/gs/util/drivers/spi/slave.h | 84 + .../include/gs/util/drivers/sys/memory.h | 92 + .../include/gs/util/drivers/watchdog/device.h | 61 + gomspace/libutil/include/gs/util/endian.h | 53 + gomspace/libutil/include/gs/util/error.h | 199 + gomspace/libutil/include/gs/util/fletcher.h | 89 + .../include/gs/util/function_scheduler.h | 79 + .../libutil/include/gs/util/gosh/command.h | 503 + .../libutil/include/gs/util/gosh/console.h | 123 + gomspace/libutil/include/gs/util/hexdump.h | 53 + gomspace/libutil/include/gs/util/linux/argp.h | 40 + .../include/gs/util/linux/command_line.h | 42 + .../include/gs/util/linux/drivers/can/can.h | 29 + .../include/gs/util/linux/drivers/gpio/gpio.h | 146 + .../gs/util/linux/drivers/gpio/gpio_sysfs.h | 91 + .../gs/util/linux/drivers/gpio/gpio_virtual.h | 125 + .../include/gs/util/linux/drivers/i2c/i2c.h | 198 + .../include/gs/util/linux/drivers/spi/spi.h | 175 + .../libutil/include/gs/util/linux/exitcode.h | 40 + .../libutil/include/gs/util/linux/function.h | 49 + gomspace/libutil/include/gs/util/linux/rtc.h | 28 + .../libutil/include/gs/util/linux/signal.h | 40 + .../include/gs/util/linux/sysfs_helper.h | 30 + gomspace/libutil/include/gs/util/log.h | 15 + .../include/gs/util/log/appender/appender.h | 189 + .../include/gs/util/log/appender/console.h | 57 + .../gs/util/log/appender/simple_file.h | 41 + gomspace/libutil/include/gs/util/log/log.h | 853 ++ gomspace/libutil/include/gs/util/minmax.h | 67 + gomspace/libutil/include/gs/util/mutex.h | 63 + gomspace/libutil/include/gs/util/pgm.h | 162 + gomspace/libutil/include/gs/util/queue.h | 102 + gomspace/libutil/include/gs/util/rtc.h | 62 + gomspace/libutil/include/gs/util/sem.h | 75 + gomspace/libutil/include/gs/util/stdio.h | 117 + gomspace/libutil/include/gs/util/string.h | 391 + .../libutil/include/gs/util/test/cmocka.h | 136 + .../libutil/include/gs/util/test/command.h | 80 + gomspace/libutil/include/gs/util/test/log.h | 88 + gomspace/libutil/include/gs/util/thread.h | 173 + gomspace/libutil/include/gs/util/time.h | 95 + gomspace/libutil/include/gs/util/timestamp.h | 73 + gomspace/libutil/include/gs/util/types.h | 114 + gomspace/libutil/include/gs/util/unistd.h | 32 + gomspace/libutil/include/gs/util/vmem.h | 194 + .../include/gs/util/watchdog/watchdog.h | 143 + .../include/gs/util/watchdog/watchdog_task.h | 45 + gomspace/libutil/include/gs/util/zip/zip.h | 62 + gomspace/libutil/src/base16.c | 61 + gomspace/libutil/src/bindings/python/pyutil.c | 73 + gomspace/libutil/src/bytebuffer.c | 128 + gomspace/libutil/src/byteorder.c | 323 + gomspace/libutil/src/clock.c | 113 + gomspace/libutil/src/crc32.c | 79 + gomspace/libutil/src/crc8.c | 68 + gomspace/libutil/src/drivers/can/can.c | 6 + gomspace/libutil/src/drivers/i2c/i2c.c | 6 + gomspace/libutil/src/drivers/spi/spi.c | 6 + gomspace/libutil/src/drivers/sys/memory.c | 37 + gomspace/libutil/src/error.c | 106 + gomspace/libutil/src/fletcher.c | 77 + gomspace/libutil/src/function_scheduler.c | 111 + gomspace/libutil/src/gosh/command.c | 754 ++ gomspace/libutil/src/gosh/command_local.h | 35 + gomspace/libutil/src/gosh/console.c | 758 ++ gomspace/libutil/src/gosh/console_local.h | 10 + gomspace/libutil/src/gosh/default_commands.c | 277 + gomspace/libutil/src/gosh/getopt.c | 55 + gomspace/libutil/src/hexdump.c | 92 + gomspace/libutil/src/linux/argp.c | 34 + gomspace/libutil/src/linux/clock.c | 68 + gomspace/libutil/src/linux/command_line.c | 76 + gomspace/libutil/src/linux/cwd.c | 28 + gomspace/libutil/src/linux/delay.c | 22 + gomspace/libutil/src/linux/drivers/can/can.c | 308 + .../libutil/src/linux/drivers/gpio/gpio.c | 102 + .../src/linux/drivers/gpio/gpio_sysfs.c | 145 + .../src/linux/drivers/gpio/gpio_virtual.c | 171 + gomspace/libutil/src/linux/drivers/i2c/i2c.c | 144 + gomspace/libutil/src/linux/drivers/spi/spi.c | 137 + .../libutil/src/linux/drivers/sys/memory.c | 30 + gomspace/libutil/src/linux/function.c | 41 + gomspace/libutil/src/linux/mutex.c | 59 + gomspace/libutil/src/linux/queue.c | 217 + gomspace/libutil/src/linux/rtc.c | 78 + gomspace/libutil/src/linux/sem.c | 89 + gomspace/libutil/src/linux/signal.c | 38 + gomspace/libutil/src/linux/stdio.c | 36 + gomspace/libutil/src/linux/sysfs_helper.c | 48 + gomspace/libutil/src/linux/thread.c | 89 + gomspace/libutil/src/linux/time.c | 53 + gomspace/libutil/src/lock.c | 30 + gomspace/libutil/src/lock.h | 14 + gomspace/libutil/src/log/appender/console.c | 88 + .../libutil/src/log/appender/simple_file.c | 117 + gomspace/libutil/src/log/commands.c | 392 + gomspace/libutil/src/log/local.h | 27 + gomspace/libutil/src/log/log.c | 705 ++ gomspace/libutil/src/rtc.c | 42 + gomspace/libutil/src/stdio.c | 81 + gomspace/libutil/src/string.c | 746 ++ gomspace/libutil/src/strtoint.c | 399 + gomspace/libutil/src/test/cmocka.c | 63 + gomspace/libutil/src/test/command.c | 176 + gomspace/libutil/src/test/log.c | 165 + gomspace/libutil/src/time.c | 28 + gomspace/libutil/src/timestamp.c | 61 + gomspace/libutil/src/vmem/commands.c | 123 + gomspace/libutil/src/vmem/vmem.c | 143 + gomspace/libutil/src/watchdog/local.h | 18 + gomspace/libutil/src/watchdog/monitor_task.c | 68 + gomspace/libutil/src/watchdog/watchdog.c | 292 + .../libutil/src/zip/cppcheck-suppress.txt | 5 + .../libutil/src/zip/miniz/LIST_OF_CHANGES | 9429 +++++++++++++++++ gomspace/libutil/src/zip/miniz/miniz.c | 7572 +++++++++++++ gomspace/libutil/src/zip/miniz/miniz.h | 1329 +++ gomspace/libutil/src/zip/zip.c | 357 + gomspace/libutil/wscript | 109 + .../include/gs/p60-dock/param/p60dock.h | 47 + .../include/gs/p60-dock/param/p60dock_cal.h | 35 + .../include/gs/p60-dock/param/p60dock_hk.h | 51 + .../include/gs/p60-dock/param/p60dock_param.h | 69 + gomspace/p60-dock_client/src/p60dock_client.c | 147 + gomspace/p60-dock_client/wscript | 34 + test/testtasks/P60DockTestTask.cpp | 48 + test/testtasks/P60DockTestTask.h | 7 +- 194 files changed, 45450 insertions(+), 2 deletions(-) create mode 100644 gomspace/libp60_client/include/p60.h create mode 100644 gomspace/libp60_client/include/p60_board.h create mode 100644 gomspace/libp60_client/include/power_if.h create mode 100644 gomspace/libp60_client/src/cmd/power_if_cmd.c create mode 100644 gomspace/libp60_client/src/p60_client.c create mode 100644 gomspace/libp60_client/src/power_if.c create mode 100644 gomspace/libp60_client/wscript create mode 100644 gomspace/libparam_client/include/deprecated/param/param_client.h create mode 100644 gomspace/libparam_client/include/deprecated/param/param_lock.h create mode 100644 gomspace/libparam_client/include/deprecated/param/param_serializer.h create mode 100644 gomspace/libparam_client/include/deprecated/param/param_string.h create mode 100644 gomspace/libparam_client/include/deprecated/param/param_types.h create mode 100644 gomspace/libparam_client/include/deprecated/param/rparam_client.h create mode 100644 gomspace/libparam_client/include/gs/param/internal/pp/i2c/i2c.h create mode 100644 gomspace/libparam_client/include/gs/param/internal/pp/i2c/slave_dispatch.h create mode 100644 gomspace/libparam_client/include/gs/param/internal/pp/spi/slave_dispatch.h create mode 100644 gomspace/libparam_client/include/gs/param/internal/pp/spi/spi.h create mode 100644 gomspace/libparam_client/include/gs/param/internal/rparam.h create mode 100644 gomspace/libparam_client/include/gs/param/internal/serialize.h create mode 100644 gomspace/libparam_client/include/gs/param/internal/table.h create mode 100644 gomspace/libparam_client/include/gs/param/internal/types.h create mode 100644 gomspace/libparam_client/include/gs/param/pp/i2c/i2c.h create mode 100644 gomspace/libparam_client/include/gs/param/pp/pp.h create mode 100644 gomspace/libparam_client/include/gs/param/pp/spi/spi.h create mode 100644 gomspace/libparam_client/include/gs/param/rparam.h create mode 100644 gomspace/libparam_client/include/gs/param/serialize.h create mode 100644 gomspace/libparam_client/include/gs/param/table.h create mode 100644 gomspace/libparam_client/include/gs/param/types.h create mode 100644 gomspace/libparam_client/src/bindings/python/pyparam.c create mode 100644 gomspace/libparam_client/src/pp/cmd/master_cmd.c create mode 100644 gomspace/libparam_client/src/pp/i2c/i2c.c create mode 100644 gomspace/libparam_client/src/pp/pp.c create mode 100644 gomspace/libparam_client/src/pp/spi/spi.c create mode 100644 gomspace/libparam_client/src/rparam/cmd/cmd_rparam.c create mode 100644 gomspace/libparam_client/src/rparam/deprecated_rparam.c create mode 100644 gomspace/libparam_client/src/rparam/query.c create mode 100644 gomspace/libparam_client/src/rparam/query.h create mode 100644 gomspace/libparam_client/src/rparam/rparam.c create mode 100644 gomspace/libparam_client/src/serialize.c create mode 100644 gomspace/libparam_client/src/serialize_local.h create mode 100644 gomspace/libparam_client/src/string.c create mode 100644 gomspace/libparam_client/src/table.c create mode 100644 gomspace/libparam_client/wscript create mode 100644 gomspace/libutil/include/conf_util.h create mode 100644 gomspace/libutil/include/deprecated/gs/gosh/command/command.h create mode 100644 gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h create mode 100644 gomspace/libutil/include/deprecated/gs/gosh/util/console.h create mode 100644 gomspace/libutil/include/deprecated/util/color_printf.h create mode 100644 gomspace/libutil/include/gs/uthash/utarray.h create mode 100644 gomspace/libutil/include/gs/uthash/uthash.h create mode 100644 gomspace/libutil/include/gs/uthash/utlist.h create mode 100644 gomspace/libutil/include/gs/uthash/utstring.h create mode 100644 gomspace/libutil/include/gs/util/base16.h create mode 100644 gomspace/libutil/include/gs/util/bytebuffer.h create mode 100644 gomspace/libutil/include/gs/util/byteorder.h create mode 100644 gomspace/libutil/include/gs/util/check.h create mode 100644 gomspace/libutil/include/gs/util/clock.h create mode 100644 gomspace/libutil/include/gs/util/crc32.h create mode 100644 gomspace/libutil/include/gs/util/crc8.h create mode 100644 gomspace/libutil/include/gs/util/delay.h create mode 100644 gomspace/libutil/include/gs/util/drivers/can/can.h create mode 100644 gomspace/libutil/include/gs/util/drivers/gpio/gpio.h create mode 100644 gomspace/libutil/include/gs/util/drivers/i2c/common.h create mode 100644 gomspace/libutil/include/gs/util/drivers/i2c/master.h create mode 100644 gomspace/libutil/include/gs/util/drivers/i2c/slave.h create mode 100644 gomspace/libutil/include/gs/util/drivers/spi/common.h create mode 100644 gomspace/libutil/include/gs/util/drivers/spi/master.h create mode 100644 gomspace/libutil/include/gs/util/drivers/spi/slave.h create mode 100644 gomspace/libutil/include/gs/util/drivers/sys/memory.h create mode 100644 gomspace/libutil/include/gs/util/drivers/watchdog/device.h create mode 100644 gomspace/libutil/include/gs/util/endian.h create mode 100644 gomspace/libutil/include/gs/util/error.h create mode 100644 gomspace/libutil/include/gs/util/fletcher.h create mode 100644 gomspace/libutil/include/gs/util/function_scheduler.h create mode 100644 gomspace/libutil/include/gs/util/gosh/command.h create mode 100644 gomspace/libutil/include/gs/util/gosh/console.h create mode 100644 gomspace/libutil/include/gs/util/hexdump.h create mode 100644 gomspace/libutil/include/gs/util/linux/argp.h create mode 100644 gomspace/libutil/include/gs/util/linux/command_line.h create mode 100644 gomspace/libutil/include/gs/util/linux/drivers/can/can.h create mode 100644 gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h create mode 100644 gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h create mode 100644 gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h create mode 100644 gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h create mode 100644 gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h create mode 100644 gomspace/libutil/include/gs/util/linux/exitcode.h create mode 100644 gomspace/libutil/include/gs/util/linux/function.h create mode 100644 gomspace/libutil/include/gs/util/linux/rtc.h create mode 100644 gomspace/libutil/include/gs/util/linux/signal.h create mode 100644 gomspace/libutil/include/gs/util/linux/sysfs_helper.h create mode 100644 gomspace/libutil/include/gs/util/log.h create mode 100644 gomspace/libutil/include/gs/util/log/appender/appender.h create mode 100644 gomspace/libutil/include/gs/util/log/appender/console.h create mode 100644 gomspace/libutil/include/gs/util/log/appender/simple_file.h create mode 100644 gomspace/libutil/include/gs/util/log/log.h create mode 100644 gomspace/libutil/include/gs/util/minmax.h create mode 100644 gomspace/libutil/include/gs/util/mutex.h create mode 100644 gomspace/libutil/include/gs/util/pgm.h create mode 100644 gomspace/libutil/include/gs/util/queue.h create mode 100644 gomspace/libutil/include/gs/util/rtc.h create mode 100644 gomspace/libutil/include/gs/util/sem.h create mode 100644 gomspace/libutil/include/gs/util/stdio.h create mode 100644 gomspace/libutil/include/gs/util/string.h create mode 100644 gomspace/libutil/include/gs/util/test/cmocka.h create mode 100644 gomspace/libutil/include/gs/util/test/command.h create mode 100644 gomspace/libutil/include/gs/util/test/log.h create mode 100644 gomspace/libutil/include/gs/util/thread.h create mode 100644 gomspace/libutil/include/gs/util/time.h create mode 100644 gomspace/libutil/include/gs/util/timestamp.h create mode 100644 gomspace/libutil/include/gs/util/types.h create mode 100644 gomspace/libutil/include/gs/util/unistd.h create mode 100644 gomspace/libutil/include/gs/util/vmem.h create mode 100644 gomspace/libutil/include/gs/util/watchdog/watchdog.h create mode 100644 gomspace/libutil/include/gs/util/watchdog/watchdog_task.h create mode 100644 gomspace/libutil/include/gs/util/zip/zip.h create mode 100644 gomspace/libutil/src/base16.c create mode 100644 gomspace/libutil/src/bindings/python/pyutil.c create mode 100644 gomspace/libutil/src/bytebuffer.c create mode 100644 gomspace/libutil/src/byteorder.c create mode 100644 gomspace/libutil/src/clock.c create mode 100644 gomspace/libutil/src/crc32.c create mode 100644 gomspace/libutil/src/crc8.c create mode 100644 gomspace/libutil/src/drivers/can/can.c create mode 100644 gomspace/libutil/src/drivers/i2c/i2c.c create mode 100644 gomspace/libutil/src/drivers/spi/spi.c create mode 100644 gomspace/libutil/src/drivers/sys/memory.c create mode 100644 gomspace/libutil/src/error.c create mode 100644 gomspace/libutil/src/fletcher.c create mode 100644 gomspace/libutil/src/function_scheduler.c create mode 100644 gomspace/libutil/src/gosh/command.c create mode 100644 gomspace/libutil/src/gosh/command_local.h create mode 100644 gomspace/libutil/src/gosh/console.c create mode 100644 gomspace/libutil/src/gosh/console_local.h create mode 100644 gomspace/libutil/src/gosh/default_commands.c create mode 100644 gomspace/libutil/src/gosh/getopt.c create mode 100644 gomspace/libutil/src/hexdump.c create mode 100644 gomspace/libutil/src/linux/argp.c create mode 100644 gomspace/libutil/src/linux/clock.c create mode 100644 gomspace/libutil/src/linux/command_line.c create mode 100644 gomspace/libutil/src/linux/cwd.c create mode 100644 gomspace/libutil/src/linux/delay.c create mode 100644 gomspace/libutil/src/linux/drivers/can/can.c create mode 100644 gomspace/libutil/src/linux/drivers/gpio/gpio.c create mode 100644 gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c create mode 100644 gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c create mode 100644 gomspace/libutil/src/linux/drivers/i2c/i2c.c create mode 100644 gomspace/libutil/src/linux/drivers/spi/spi.c create mode 100644 gomspace/libutil/src/linux/drivers/sys/memory.c create mode 100644 gomspace/libutil/src/linux/function.c create mode 100644 gomspace/libutil/src/linux/mutex.c create mode 100644 gomspace/libutil/src/linux/queue.c create mode 100644 gomspace/libutil/src/linux/rtc.c create mode 100644 gomspace/libutil/src/linux/sem.c create mode 100644 gomspace/libutil/src/linux/signal.c create mode 100644 gomspace/libutil/src/linux/stdio.c create mode 100644 gomspace/libutil/src/linux/sysfs_helper.c create mode 100644 gomspace/libutil/src/linux/thread.c create mode 100644 gomspace/libutil/src/linux/time.c create mode 100644 gomspace/libutil/src/lock.c create mode 100644 gomspace/libutil/src/lock.h create mode 100644 gomspace/libutil/src/log/appender/console.c create mode 100644 gomspace/libutil/src/log/appender/simple_file.c create mode 100644 gomspace/libutil/src/log/commands.c create mode 100644 gomspace/libutil/src/log/local.h create mode 100644 gomspace/libutil/src/log/log.c create mode 100644 gomspace/libutil/src/rtc.c create mode 100644 gomspace/libutil/src/stdio.c create mode 100644 gomspace/libutil/src/string.c create mode 100644 gomspace/libutil/src/strtoint.c create mode 100644 gomspace/libutil/src/test/cmocka.c create mode 100644 gomspace/libutil/src/test/command.c create mode 100644 gomspace/libutil/src/test/log.c create mode 100644 gomspace/libutil/src/time.c create mode 100644 gomspace/libutil/src/timestamp.c create mode 100644 gomspace/libutil/src/vmem/commands.c create mode 100644 gomspace/libutil/src/vmem/vmem.c create mode 100644 gomspace/libutil/src/watchdog/local.h create mode 100644 gomspace/libutil/src/watchdog/monitor_task.c create mode 100644 gomspace/libutil/src/watchdog/watchdog.c create mode 100644 gomspace/libutil/src/zip/cppcheck-suppress.txt create mode 100644 gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES create mode 100644 gomspace/libutil/src/zip/miniz/miniz.c create mode 100644 gomspace/libutil/src/zip/miniz/miniz.h create mode 100644 gomspace/libutil/src/zip/zip.c create mode 100644 gomspace/libutil/wscript create mode 100644 gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock.h create mode 100644 gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_cal.h create mode 100644 gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h create mode 100644 gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_param.h create mode 100644 gomspace/p60-dock_client/src/p60dock_client.c create mode 100644 gomspace/p60-dock_client/wscript diff --git a/gomspace/gomspace.mk b/gomspace/gomspace.mk index 675fa426..57d38da7 100644 --- a/gomspace/gomspace.mk +++ b/gomspace/gomspace.mk @@ -5,7 +5,15 @@ CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/rtable/csp_rtable_cidr.c) CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/crypto/*.c) CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/arch/posix/*.c) CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/transport/*.c) +CSRC += $(wildcard $(CURRENTPATH)/p60-dock_client/src/*.c) +CSRC += $(wildcard $(CURRENTPATH)/libparam_client/src/*.c) +CSRC += $(wildcard $(CURRENTPATH)/libparam_client/src/rparam/*.c) INCLUDES += $(CURRENTPATH)/libcsp/include INCLUDES += $(CURRENTPATH)/libcsp/include/csp/crypto -INCLUDES += $(CURRENTPATH)/libcsp \ No newline at end of file +INCLUDES += $(CURRENTPATH)/libcsp +INCLUDES += $(CURRENTPATH)/p60-dock_client/include/gs/p60-dock/param +INCLUDES += $(CURRENTPATH)/libparam_client/include +INCLUDES += $(CURRENTPATH)/libparam_client/include/deprecated +INCLUDES += $(CURRENTPATH)/libp60_client/include +INCLUDES += $(CURRENTPATH)/libutil/include \ No newline at end of file diff --git a/gomspace/libp60_client/include/p60.h b/gomspace/libp60_client/include/p60.h new file mode 100644 index 00000000..186d43f8 --- /dev/null +++ b/gomspace/libp60_client/include/p60.h @@ -0,0 +1,48 @@ +#ifndef _P60_H_ +#define _P60_H_ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#define P60_PORT_RPARAM 7 +#define P60_PORT_GNDWDT_RESET 9 +#define P60_PORT_CMDCONTROL 10 +#define P60_PORT_GSSB_SERVICE 15 +#define P60_PORT_GSCRIPT 22 + +/** FRAM MEMORY MAP */ +#define P60_FRAM_BOARD 0x0000 + +/** FRAM FILENAMES */ +#define P60_FNO_BOARD 0 +#define P60_FNO_BOARD_DFL 4 + +#define P60_FRAM_WP_BEGIN (0x1000) +#define P60_FRAM_WP_END (0x1C00 - 1) + +/** GND WD FRAM ADDR **/ +#define P60_FRAM_GNDWDT 0x1F00 + +/** PARAM INDEX MAP */ +#define P60_BOARD_PARAM 0 + +#define DEVICE_FM24CL64B 0 + +typedef enum { + UNKNOWN_RST = 0, + GND_WDT_RST, + I2C_WDT_RST, + CAN_WDT_RST, + EXT_HARD_RST, + EXT_SOFT_RST, +} p60_reset_cause_t; + +extern const uint8_t board_fallback_type; +extern const uint8_t csp_fallback_addr; +extern const uint8_t board_rs422_mode; + +extern void module_init_early(void); +extern void module_init(void); +extern void wdt_gnd_clear(void); +extern uint16_t command_control(uint8_t *packet, uint16_t length); +extern void module_task(void * pvParameters); + +#endif /* _P60_H_ */ diff --git a/gomspace/libp60_client/include/p60_board.h b/gomspace/libp60_client/include/p60_board.h new file mode 100644 index 00000000..2abd906d --- /dev/null +++ b/gomspace/libp60_client/include/p60_board.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + * NanoCom firmware + * + */ + +#ifndef P60_PARAM_H_ +#define P60_PARAM_H_ + +#include +#include + +/** + * Define memory space + */ +#define P60_BOARD_UID 0x00 +#define P60_BOARD_TYPE 0x10 +#define P60_BOARD_REV 0x11 +#define P60_BOARD_CSP_ADDR 0x12 +#define P60_BOARD_I2C_ADDR 0x13 +#define P60_BOARD_I2C_SPEED_KHZ 0x14 +#define P60_BOARD_CAN_SPEED_KHZ 0x16 +#define P60_BOARD_KISS_ENABLE 0x18 +#define P60_BOARD_RS422_MODE 0x19 +#define P60_BOARD_RS422_SPEED_KHZ 0x1C +#define P60_BOARD_RTABLE_STR 0x20 //! This one is 0x60 = 96 bytes +#define P60_BOARD_RTABLE_STR_SIZE 0x60 + +/** Define the memory size */ +#define P60_BOARD_PARAM_SIZE 0x80 + +extern const param_table_t p60_config[]; +extern const int p60_config_count; + +#endif /* P60_PARAM_H_ */ diff --git a/gomspace/libp60_client/include/power_if.h b/gomspace/libp60_client/include/power_if.h new file mode 100644 index 00000000..6762d1ec --- /dev/null +++ b/gomspace/libp60_client/include/power_if.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + * NanoPower firmware + * + */ + +#ifndef POWER_IF_H_ +#define POWER_IF_H_ + +#include + +#define POWER_IF_SET 1 +#define POWER_IF_GET 2 +#define POWER_IF_LIST 3 + +#define POWER_IF_STATUS_OK 0 +#define POWER_IF_STATUS_ERROR 1 + +#define POWER_IF_NAME_LEN 8 + +typedef struct __attribute__((packed)) { + uint8_t ch_idx; + uint8_t mode; + uint16_t on_cnt; + uint16_t off_cnt; + uint16_t cur_lu_lim; + uint16_t cur_lim; + uint16_t voltage; + int16_t current; + uint16_t latchup; + char name[POWER_IF_NAME_LEN]; +} power_if_ch_status_t; + +typedef struct __attribute__((packed)) { + uint8_t ch_idx; + uint8_t mode; + char name[8]; +} power_if_list_t; + +typedef struct __attribute__((packed)) { + uint8_t cmd; + uint8_t status; + power_if_ch_status_t ch_status; +} power_if_cmd_request_t; + +typedef struct __attribute__((packed)) { + uint8_t cmd; + uint8_t status; + power_if_ch_status_t ch_status; +} power_if_cmd_response_t; + +typedef struct __attribute__((packed)) { + uint8_t cmd; + uint8_t status; + uint8_t count; + power_if_list_t list[16]; +} power_if_cmd_list_response_t; + +int p60_power_if_cmd(uint8_t node, uint8_t port, uint32_t timeout, uint8_t cmd, void * ch_status_p); +uint8_t p60_power_if_get_ch_idx(char * ch_name, uint8_t * ch_no, uint8_t ch_no_max); + +#endif /* POWER_IF_H_ */ diff --git a/gomspace/libp60_client/src/cmd/power_if_cmd.c b/gomspace/libp60_client/src/cmd/power_if_cmd.c new file mode 100644 index 00000000..9851f912 --- /dev/null +++ b/gomspace/libp60_client/src/cmd/power_if_cmd.c @@ -0,0 +1,147 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +static uint8_t power_if_port = 10; +static uint32_t power_if_timeout = 5000; + +static int cmd_power_if_port(struct command_context * ctx) { + if (ctx->argc < 2) { + printf("Current port is %d\n", power_if_port); + return CMD_ERROR_NONE; + } + power_if_port = atoi(ctx->argv[1]); + return CMD_ERROR_NONE; +} + +static int cmd_power_if_timeout(struct command_context *ctx) { + if (ctx->argc < 2) { + printf("Current timeout is %"PRIu32"\n", power_if_timeout); + return CMD_ERROR_NONE; + } + if (sscanf(command_args(ctx), "%"SCNu32, &power_if_timeout) != 1) + return CMD_ERROR_SYNTAX; + if (power_if_timeout > 30000) { + printf("Timeout set to high, limited to 30000 ms\n"); + power_if_timeout = 30000; + } + printf("Timeout set to %"PRIu32"\n", power_if_timeout); + return CMD_ERROR_NONE; +} + +static int cmd_power_if_set_get(struct command_context * ctx) { + power_if_ch_status_t ch_status; + + if (ctx->argc < 3) { + return CMD_ERROR_SYNTAX; + } + uint8_t node = atoi(ctx->argv[1]); + memset(&ch_status, 0, sizeof(ch_status)); + strncpy(ch_status.name, ctx->argv[2], 7); + ch_status.name[7] = 0; + char * cmd = ctx->argv[0]; + if (!strcmp(cmd, "status") && (ctx->argc == 3)) { + if (!p60_power_if_cmd(node, power_if_port, power_if_timeout, POWER_IF_GET, &ch_status)) { + return CMD_ERROR_FAIL; + } + } else { + if (!strcmp(cmd, "on")) { + ch_status.mode = 1; + } else if (!strcmp(cmd, "off")) { + ch_status.mode = 0; + } + ch_status.on_cnt = (ctx->argc > 3) ? atoi(ctx->argv[3]) : 0; + ch_status.off_cnt = (ctx->argc > 4) ? atoi(ctx->argv[4]) : 0; + if (!p60_power_if_cmd(node, power_if_port, power_if_timeout, POWER_IF_SET, &ch_status)) { + return CMD_ERROR_FAIL; + } + } + printf("Node %u, Output channel '%s' (%u) is %s\r\n", node, ch_status.name, ch_status.ch_idx, (ch_status.mode ? "ON": "OFF")); + printf(" ch_idx: %u\r\n", ch_status.ch_idx); + printf(" mode: %u\r\n", ch_status.mode); + printf(" on_cnt: %u\r\n", ch_status.on_cnt); + printf(" off_cnt: %u\r\n", ch_status.off_cnt); + printf(" cur_lu_lim: %u\r\n", ch_status.cur_lu_lim); + printf(" cur_lim: %u\r\n", ch_status.cur_lim); + printf(" voltage: %u\r\n", ch_status.voltage); + printf(" current: %d\r\n", ch_status.current); + printf(" latchup: %u\r\n", ch_status.latchup); + + return CMD_ERROR_NONE; +} + +static int cmd_power_if_list(struct command_context * ctx) { + if (ctx->argc < 2) { + return CMD_ERROR_SYNTAX; + } + uint8_t node = atoi(ctx->argv[1]); + power_if_cmd_list_response_t ch_list; + if (!p60_power_if_cmd(node, power_if_port, power_if_timeout, POWER_IF_LIST, &ch_list)) { + return CMD_ERROR_FAIL; + } + printf("ch name status\r\n"); + for (uint8_t ch = 0; ch < ch_list.count; ch++) { + printf("%2u %-8s %s\r\n", ch_list.list[ch].ch_idx, ch_list.list[ch].name, ch_list.list[ch].mode ? "ON": "OFF"); + } + return CMD_ERROR_NONE; +} + +command_t power_if_commands[] = { + { + .name = "port", + .help = "Set power interface port (default is 10)", + .usage = "", + .handler = cmd_power_if_port, + }, + { + .name = "timeout", + .help = "Set power interface timeout in milliseconds", + .usage = "", + .handler = cmd_power_if_timeout, + }, + { + .name = "status", + .help = "Get power channel status", + .usage = " ", + .handler = cmd_power_if_set_get, + }, + { + .name = "on", + .help = "Turn power channel on", + .usage = " [ ]", + .handler = cmd_power_if_set_get, + }, + { + .name = "off", + .help = "Turn power channel off", + .usage = " off [ ]", + .handler = cmd_power_if_set_get, + }, + { + .name = "list", + .help = "Get list power channels", + .usage = "", + .handler = cmd_power_if_list, + }, +}; + +command_t __root_command power_if_root_command[] = { + { + .name = "power", + .help = "client: NanoPower P60", + .chain = INIT_CHAIN(power_if_commands), + } +}; + +void cmd_power_if_setup(void) { + command_register(power_if_root_command); +} diff --git a/gomspace/libp60_client/src/p60_client.c b/gomspace/libp60_client/src/p60_client.c new file mode 100644 index 00000000..76e1a905 --- /dev/null +++ b/gomspace/libp60_client/src/p60_client.c @@ -0,0 +1,33 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + * NanoCom firmware + * + */ + +#include +#include +#include +#include + +#include +#include + +/** + * Setup info about board configuration parameters + */ +const param_table_t p60_config[] = { + {.name = "uid", .addr = P60_BOARD_UID, .type = PARAM_STRING, .size = 16}, + {.name = "type", .addr = P60_BOARD_TYPE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "rev", .addr = P60_BOARD_REV, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "csp_addr", .addr = P60_BOARD_CSP_ADDR, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "i2c_addr", .addr = P60_BOARD_I2C_ADDR, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "i2c_speed", .addr = P60_BOARD_I2C_SPEED_KHZ, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, + {.name = "can_speed", .addr = P60_BOARD_CAN_SPEED_KHZ, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, + {.name = "kiss_en", .addr = P60_BOARD_KISS_ENABLE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "rs422_mode", .addr = P60_BOARD_RS422_MODE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "rs422_speed", .addr = P60_BOARD_RS422_SPEED_KHZ, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, + {.name = "csp_rtable", .addr = P60_BOARD_RTABLE_STR, .type = PARAM_STRING, .size = P60_BOARD_RTABLE_STR_SIZE}, + +}; + +const int p60_config_count = sizeof(p60_config) / sizeof(p60_config[0]); diff --git a/gomspace/libp60_client/src/power_if.c b/gomspace/libp60_client/src/power_if.c new file mode 100644 index 00000000..e9266ca0 --- /dev/null +++ b/gomspace/libp60_client/src/power_if.c @@ -0,0 +1,91 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + * NanoPower firmware + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +uint8_t p60_power_if_get_ch_idx(char * ch_name, uint8_t * ch_no, uint8_t ch_no_max) { + + uint8_t result = 1; + uint8_t len = strlen(ch_name); + for (int i = 0; i < len; i++) { + if (!isdigit(ch_name[i])) { + result = 0; + break; + } + } + if (result) { + *ch_no = atoi(ch_name); + if (*ch_no >= ch_no_max) { + result = 0; + } + } + return result; +} + +int p60_power_if_cmd(uint8_t node, uint8_t port, uint32_t timeout, uint8_t cmd, void * ch_status_p) { + + power_if_cmd_request_t req; + + if ((cmd == POWER_IF_SET) || (cmd == POWER_IF_GET)) { + power_if_cmd_response_t resp; + power_if_ch_status_t * ch_status = (power_if_ch_status_t *)ch_status_p; + if (cmd == POWER_IF_SET) { + req.cmd = POWER_IF_SET; + req.ch_status.mode = ch_status->mode; + req.ch_status.on_cnt = csp_hton16(ch_status->on_cnt); + req.ch_status.off_cnt = csp_hton16(ch_status->off_cnt); + } else { + req.cmd = POWER_IF_GET; + req.ch_status.mode = 0; + req.ch_status.on_cnt = 0; + req.ch_status.off_cnt = 0; + } + ch_status->name[POWER_IF_NAME_LEN - 1] = 0; + strcpy(req.ch_status.name, ch_status->name); + if (csp_transaction(CSP_PRIO_HIGH, node, port, timeout, &req, sizeof(power_if_cmd_request_t), &resp, sizeof(power_if_cmd_response_t))) { + if ((resp.cmd == POWER_IF_SET) || (resp.cmd == POWER_IF_GET)) { + if (resp.status == POWER_IF_STATUS_OK) { + ch_status->ch_idx = resp.ch_status.ch_idx; + ch_status->mode = resp.ch_status.mode; + ch_status->on_cnt = csp_ntoh16(resp.ch_status.on_cnt); + ch_status->off_cnt = csp_ntoh16(resp.ch_status.off_cnt); + ch_status->cur_lu_lim = csp_ntoh16(resp.ch_status.cur_lu_lim); + ch_status->cur_lim = csp_ntoh16(resp.ch_status.cur_lim); + ch_status->voltage = csp_ntoh16(resp.ch_status.voltage); + ch_status->current = csp_ntoh16(resp.ch_status.current); + ch_status->latchup = csp_ntoh16(resp.ch_status.latchup); + strncpy(ch_status->name, resp.ch_status.name, POWER_IF_NAME_LEN - 1); + /* Ensure zero termination*/ + ch_status->name[POWER_IF_NAME_LEN - 1] = 0; + return 1; + } + } + } + } else if (cmd == POWER_IF_LIST) { + power_if_cmd_list_response_t * ch_list = (power_if_cmd_list_response_t *)ch_status_p; + req.cmd = POWER_IF_LIST; + req.ch_status.mode = 0; + req.ch_status.on_cnt = 0; + req.ch_status.off_cnt = 0; + req.ch_status.name[0] = 0; + if (csp_transaction(CSP_PRIO_HIGH, node, port, timeout, &req, sizeof(power_if_cmd_request_t), ch_list, sizeof(power_if_cmd_list_response_t))) { + if ((ch_list->cmd == POWER_IF_LIST) && (ch_list->status == POWER_IF_STATUS_OK)) { + return 1; + } + } + } + + return 0; +} diff --git a/gomspace/libp60_client/wscript b/gomspace/libp60_client/wscript new file mode 100644 index 00000000..dc4dcf8a --- /dev/null +++ b/gomspace/libp60_client/wscript @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# encoding: utf-8 +# Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. + +APPNAME = 'p60_client' + + +def options(ctx): + gr = ctx.add_option_group('NanoPower-P60 library client options') + gr.add_option('--disable-libp60-cmd', action='store_true', help='Disable client cmd code for NanoPower-P60 library') + + +def configure(ctx): + ctx.env.append_unique('FILES_LIBP60_CLIENT', ['src/*.c']) + if not ctx.options.disable_libp60_cmd: + ctx.env.append_unique('FILES_LIBP60_CLIENT', ['src/cmd/*.c']) + + +def build(ctx): + public_include = APPNAME + '_h' + ctx(export_includes=['include'], name=public_include) + ctx.objects(source=ctx.path.ant_glob(ctx.env.FILES_LIBP60_CLIENT), + target=APPNAME, + use=['csp', 'gosh', 'param', 'param_client', 'util', public_include]) + + +def gs_dist(ctx): + ctx.add_default_files(source_module=True) diff --git a/gomspace/libparam_client/include/deprecated/param/param_client.h b/gomspace/libparam_client/include/deprecated/param/param_client.h new file mode 100644 index 00000000..b1755541 --- /dev/null +++ b/gomspace/libparam_client/include/deprecated/param/param_client.h @@ -0,0 +1,15 @@ +#ifndef PARAM_PARAM_CLIENT_H +#define PARAM_PARAM_CLIENT_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Legacy/deprecated include of header files for libparam client. +*/ + +#include +#include +#include +#include + +#endif diff --git a/gomspace/libparam_client/include/deprecated/param/param_lock.h b/gomspace/libparam_client/include/deprecated/param/param_lock.h new file mode 100644 index 00000000..5fab0b91 --- /dev/null +++ b/gomspace/libparam_client/include/deprecated/param/param_lock.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + * GomSpace Parameter System. + */ +#ifndef PARAM_PARAM_LOCK_H_ +#define PARAM_PARAM_LOCK_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline void param_lock(param_index_t * mem) +{ + gs_param_table_lock((gs_param_table_instance_t *) mem); +} + +static inline void param_unlock(param_index_t * mem) +{ + gs_param_table_unlock((gs_param_table_instance_t *) mem); +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libparam_client/include/deprecated/param/param_serializer.h b/gomspace/libparam_client/include/deprecated/param/param_serializer.h new file mode 100644 index 00000000..c05e782e --- /dev/null +++ b/gomspace/libparam_client/include/deprecated/param/param_serializer.h @@ -0,0 +1,55 @@ +#ifndef PARAM_PARAM_SERIALIZER_H +#define PARAM_PARAM_SERIALIZER_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + * GomSpace Parameter System + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef gs_param_serialize_flags_t param_serializer_flags; + +static inline int param_betoh(param_type_t type, void * item) +{ + return gs_param_betoh(type, item); +} + +static inline int param_htobe(param_type_t type, void * item) +{ + return gs_param_htobe(type, item); +} + +static inline int param_serialize_full_table(param_index_t * mem, unsigned int *start, uint8_t * buf, unsigned int maxbuflen, param_serializer_flags flags) +{ + unsigned int buf_pos = 0; + gs_error_t error = gs_param_serialize_full_table((gs_param_table_instance_t *) mem, start, flags, buf, maxbuflen, &buf_pos); + return (error == GS_OK) ? (int) buf_pos : -1; +} + +static inline gs_error_t param_serialize_item(const param_table_t * param, uint16_t addr, uint8_t * buf, uint16_t * pos, unsigned int maxlen, void * item, param_serializer_flags flags) +{ + unsigned int tmp_pos = *pos; + gs_error_t error = gs_param_serialize_item((const gs_param_table_row_t*) param, addr, item, flags, buf, maxlen, &tmp_pos); + *pos = tmp_pos; + return (error == GS_OK) ? 0 : -1; +} + +static inline gs_error_t param_deserialize(param_index_t * mem, uint8_t * buf, int len, param_serializer_flags flags) +{ + return (gs_param_deserialize((gs_param_table_instance_t *) mem, buf, len, flags) == GS_OK) ? 0 : -1; +} + +static inline gs_error_t param_deserialize_item(const param_table_t * param, uint16_t addr, param_index_t * mem, void * item, param_serializer_flags flags) +{ + return (gs_param_deserialize_item((gs_param_table_instance_t *) mem, (const gs_param_table_row_t*)param, addr, item, flags) == GS_OK) ? 0 : -1; +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libparam_client/include/deprecated/param/param_string.h b/gomspace/libparam_client/include/deprecated/param/param_string.h new file mode 100644 index 00000000..35e19a0b --- /dev/null +++ b/gomspace/libparam_client/include/deprecated/param/param_string.h @@ -0,0 +1,74 @@ +#ifndef PARAM_PARAM_STRING_H +#define PARAM_PARAM_STRING_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + * GomSpace Parameter System + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef union { + const param_table_t * row3; + const gs_param_table_row_t * row4; +} gs_param_row_align_t; + +static inline const param_table_t * param_find_name(const param_table_t rows[], size_t row_count, const char * name) +{ + gs_param_row_align_t row_in = {.row3 = rows}; + gs_param_row_align_t row_out = {.row4 = gs_param_row_by_name(name, row_in.row4, row_count)}; + return row_out.row3; +} + +static inline const param_table_t * param_find_addr(const param_table_t rows[], size_t row_count, uint16_t addr) +{ + gs_param_row_align_t row_in = {.row3 = rows}; + gs_param_row_align_t row_out = {.row4 = gs_param_row_by_address(addr, row_in.row4, row_count)}; + return row_out.row3; +} + +static inline void param_list_single(param_table_t * param, param_index_t * mem, int do_read) +{ + gs_param_list_single((gs_param_table_instance_t *) mem, (const gs_param_table_row_t *) param, (do_read != 0)); +} + +static inline void param_list(param_index_t * mem, int do_read) +{ + gs_param_list((gs_param_table_instance_t *) mem, (do_read != 0)); +} + +static inline gs_error_t param_from_string(const param_table_t * param , const char * string, void * value) +{ + return gs_param_from_string((const gs_param_table_row_t *)param , string, value); +} + +static inline int param_to_string(const param_table_t * param, char * buf, int pos, const void * value, int with_type, int max_size) +{ + unsigned int written = 0; + gs_param_to_string((const gs_param_table_row_t *)param, value, with_type, buf, max_size, pos, &written); + return (int) written; +} + +static inline const char * param_type_to_string(param_type_t type) +{ + return gs_param_type_to_string(type); +} + +static inline uint16_t param_index_chksum(param_index_t * mem) +{ + return gs_param_table_checksum((gs_param_table_instance_t*)mem); +} + +static inline uint16_t param_index_chksum2(param_index_t * mem) +{ + return gs_param_table_checksum2((gs_param_table_instance_t*)mem); +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libparam_client/include/deprecated/param/param_types.h b/gomspace/libparam_client/include/deprecated/param/param_types.h new file mode 100644 index 00000000..61cc8351 --- /dev/null +++ b/gomspace/libparam_client/include/deprecated/param/param_types.h @@ -0,0 +1,92 @@ +#ifndef PARAM_PARAM_TYPES_H +#define PARAM_PARAM_TYPES_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Legacy/deprecated parameter types and definitions - use . +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_PARAM_NAME_LEN GS_PARAM_MAX_NAME + +/* + Legacy parameter type definition - matches gs_param_type_t exactly. + */ +typedef gs_param_type_t param_type_t; + +/* + Legacy table row definition - matches gs_param_table_row_t exactly. +*/ +typedef struct param_table_s { + uint16_t addr; + param_type_t type; + uint8_t size; + uint8_t count; // -> array_size + uint8_t flags; + char name[MAX_PARAM_NAME_LEN]; +} param_table_t; + +#define PARAM_COUNT gs_max(GS_PGM_UINT8((param)->count), 1) +#define PARAM_SIZE GS_PARAM_SIZE(param) +#define PARAM_TYPE GS_PARAM_TYPE(param) +#define PARAM_ADDR GS_PARAM_ADDR(param) +#define PARAM_FLAGS GS_PARAM_FLAGS(param) + +#define RPARAM_QUERY_MAX_LEN GS_RPARAM_MAX_QUERY + +#define PARAM_MAX_FILESIZE 0x400 + +struct param_index_s; + +/* + Legacy callback - matches gs_param_callback_func_t exactly. +*/ +typedef void (*param_callback_func)(uint16_t addr, struct param_index_s * index); + +typedef gs_param_table_id_t param_mem; + +/* + Legacy table instance definition - matches gs_param_table_instance_t exactly. +*/ +typedef struct param_index_s { + const char * name; + param_mem mem_id; + const param_table_t * table; + unsigned int count; + void * physaddr; + unsigned int size; + const gs_param_function_interface_t function_interface; + const uint16_t table_chksum; + const uint16_t chksum2; + const uint16_t checksum_le; + const gs_mutex_t lock; + param_callback_func callback; + const char * const var1; + const char * const var2; + const void * const var3; + const void * const var4; + const void * const var5; + const void * const var6; + const void * const var7; + const uint32_t var8; +} param_index_t; + +/** + Return base size of a parameter type. +*/ +static inline uint8_t param_type_size(param_type_t type) +{ + return gs_param_type_size(type); +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libparam_client/include/deprecated/param/rparam_client.h b/gomspace/libparam_client/include/deprecated/param/rparam_client.h new file mode 100644 index 00000000..a8c2655b --- /dev/null +++ b/gomspace/libparam_client/include/deprecated/param/rparam_client.h @@ -0,0 +1,208 @@ +#ifndef PARAM_RPARAM_CLIENT_H +#define PARAM_RPARAM_CLIENT_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + * GomSpace Parameter System + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Legacy magic checksum. + @deprecated use #GS_RPARAM_MAGIC_CHECKSUM (if remote products supports it). +*/ +#define GS_RPARAM_LEGACY_MAGIC_CHECKSUM 0xb00b + +static inline int rparam_get_full_table(param_index_t* idx, int node, int port, int index_id, uint32_t timeout_ms) +{ + return (gs_rparam_get_full_table((gs_param_table_instance_t *) idx, + node, + index_id, + GS_RPARAM_LEGACY_MAGIC_CHECKSUM, + timeout_ms) == GS_OK) ? 0 : -1; +} + +static inline int rparam_download_table_spec_from_remote_and_save_to_file2(const char* fname, uint8_t node, uint8_t port, param_index_t* idx, uint16_t* return_checksum, uint32_t timeout_ms) +{ + return (gs_rparam_download_table_spec((gs_param_table_instance_t *) idx, + fname, + node, + idx->mem_id, + timeout_ms, + return_checksum) == GS_OK) ? 0 : -1; +} + +static inline int rparam_download_table_spec_from_remote_and_save_to_file(const char* fname, uint8_t node, uint8_t port, param_index_t* idx, uint16_t* checksum) +{ + return rparam_download_table_spec_from_remote_and_save_to_file2(fname, node, port, idx, checksum, 10000); +} + +static inline int rparam_load_table_spec_from_file(const char* fname, param_index_t* idx, uint16_t* return_checksum) +{ + return (gs_rparam_load_table_spec((gs_param_table_instance_t *) idx, fname, return_checksum) == GS_OK) ? 0 : -1; +} + +static inline int rparam_get_single(void * out, uint16_t addr, param_type_t type, int size, int mem_id, int node, int port, uint32_t timeout_ms) +{ + return (gs_rparam_get(node, mem_id, addr, type, GS_RPARAM_LEGACY_MAGIC_CHECKSUM, timeout_ms, out, size) == GS_OK) ? size : -1; +} + +static inline int rparam_set_single(const void * in, uint16_t addr, param_type_t type, int size, int mem_id, int node, int port, uint32_t timeout_ms) +{ + return (gs_rparam_set(node, mem_id, addr, type, GS_RPARAM_LEGACY_MAGIC_CHECKSUM, timeout_ms, in, size) == GS_OK) ? size : -1; +} + +static inline int rparam_copy(uint8_t node, uint8_t port, uint32_t timeout_ms, uint8_t from, uint8_t to) +{ + return (gs_rparam_copy(node, timeout_ms, from, to) == GS_OK) ? 1 : 0; +} + +static inline int rparam_save(uint8_t node, uint8_t port, uint32_t timeout_ms, uint8_t from, uint8_t to) +{ + return (gs_rparam_save(node, timeout_ms, from, to) == GS_OK) ? 1 : 0; +} + +static inline int rparam_load(uint8_t node, uint8_t port, uint32_t timeout_ms, uint8_t from, uint8_t to) +{ + return (gs_rparam_load(node, timeout_ms, from, to) == GS_OK) ? 1 : 0; +} + +/** + * Remote getters for parameters. + * @param out pointer to the output buffer/parameter + * @param outlen length of the supplied out-buffer, only applies to rparam_get_string() + * @param addr local address of the parameter + * @param node CSP address of the node to query + * @param port CSP port of the parameter server + * @param timeout timeout on remote CSP calls + * @returns <0 on error in which case the contents of out is invalid, >0 on success + */ +static inline int rparam_get_string(char *out, int outlen, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_get_single(out, addr, PARAM_STRING, outlen, index_id, node, port, timeout_ms); +} + +/** + * Remote setters for parameters. + * @param in pointer to the buffer/parameter value to set + * @param inlen length of the supplied in-buffer, only applies to rparam_set_string() + * @param addr local address of the parameter + * @param node CSP address of the node to query + * @param port CSP port of the parameter server + * @param timeout timeout on remote CSP calls + * @returns <0 on error in which case the contents of out is invalid, >0 on success + */ +static inline int rparam_set_string(const char *in, int inlen, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_set_single(in, addr, PARAM_STRING, inlen, index_id, node, port, timeout_ms); +} + +static inline int rparam_get_uint8(uint8_t * out, uint16_t addr, int tinst_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_get_single(out, addr, PARAM_UINT8, sizeof(uint8_t), tinst_id, node, port, timeout_ms); +} + +static inline int rparam_set_uint8(const uint8_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_set_single(in, addr, PARAM_UINT8, sizeof(uint8_t), index_id, node, port, timeout_ms); +} + +static inline int rparam_get_uint16(uint16_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_get_single(out, addr, PARAM_UINT16, sizeof(uint16_t), index_id, node, port, timeout_ms); +} + +static inline int rparam_set_uint16(const uint16_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_set_single(in, addr, PARAM_UINT16, sizeof(uint16_t), index_id, node, port, timeout_ms); +} + +static inline int rparam_get_uint32(uint32_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_get_single(out, addr, PARAM_UINT32, sizeof(uint32_t), index_id, node, port, timeout_ms); +} + +static inline int rparam_set_uint32(const uint32_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_set_single(in, addr, PARAM_UINT32, sizeof(uint32_t), index_id, node, port, timeout_ms); +} + +static inline int rparam_get_uint64(uint64_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_get_single(out, addr, PARAM_UINT64, sizeof(uint64_t), index_id, node, port, timeout_ms); +} + +static inline int rparam_set_uint64(const uint64_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_set_single(in, addr, PARAM_UINT64, sizeof(uint64_t), index_id, node, port, timeout_ms); +} + +static inline int rparam_get_int8(int8_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_get_single(out, addr, PARAM_INT8, sizeof(int8_t), index_id, node, port, timeout_ms); +} + +static inline int rparam_set_int8(const int8_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_set_single(in, addr, PARAM_INT8, sizeof(int8_t), index_id, node, port, timeout_ms); +} + +static inline int rparam_get_int16(int16_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_get_single(out, addr, PARAM_INT16, sizeof(int16_t), index_id, node, port, timeout_ms); +} + +static inline int rparam_set_int16(const int16_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_set_single(in, addr, PARAM_INT16, sizeof(int16_t), index_id, node, port, timeout_ms); +} + +static inline int rparam_get_int32(int32_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_get_single(out, addr, PARAM_INT32, sizeof(int32_t), index_id, node, port, timeout_ms); +} + +static inline int rparam_set_int32(const int32_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_set_single(in, addr, PARAM_INT32, sizeof(int32_t), index_id, node, port, timeout_ms); +} + +static inline int rparam_get_int64(int64_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_get_single(out, addr, PARAM_INT64, sizeof(int64_t), index_id, node, port, timeout_ms); +} + +static inline int rparam_set_int64(const int64_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_set_single(in, addr, PARAM_INT64, sizeof(int64_t), index_id, node, port, timeout_ms); +} + +static inline int rparam_get_float(float * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_get_single(out, addr, PARAM_FLOAT, sizeof(float), index_id, node, port, timeout_ms); +} + +static inline int rparam_set_float(const float * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_set_single(in, addr, PARAM_FLOAT, sizeof(float), index_id, node, port, timeout_ms); +} + +static inline int rparam_get_double(double * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_get_single(out, addr, PARAM_DOUBLE, sizeof(double), index_id, node, port, timeout_ms); +} + +static inline int rparam_set_double(const double * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) +{ + return rparam_set_single(in, addr, PARAM_DOUBLE, sizeof(double), index_id, node, port, timeout_ms); +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/pp/i2c/i2c.h b/gomspace/libparam_client/include/gs/param/internal/pp/i2c/i2c.h new file mode 100644 index 00000000..484d4959 --- /dev/null +++ b/gomspace/libparam_client/include/gs/param/internal/pp/i2c/i2c.h @@ -0,0 +1,42 @@ +#ifndef GS_PARAM_INTERNAL_PP_I2C_I2C_H +#define GS_PARAM_INTERNAL_PP_I2C_I2C_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#if (GS_PARAM_INTERNAL_USE) + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define GS_PARAM_I2C_LENGTH_TABLE(length, table) ((length << 3) | (table & 0x07)) +#define GS_PARAM_I2C_LENGTH_TABLE_TO_LENGTH(lt) ((lt >> 3) & 0x1f) +#define GS_PARAM_I2C_LENGTH_TABLE_TO_TABLE(lt) (lt & 0x07) + +/** + Data structure for setting parameter. +*/ +typedef struct __attribute__ ((packed)) gs_param_i2c_set_request { + gs_i2c_slave_dispatch_header_t header; + uint8_t length_table; + uint8_t addr; + uint8_t data[]; // data (+ checksum) +} gs_param_i2c_set_request_t; + +/** + Data structure for getting parameter. +*/ +typedef struct __attribute__ ((packed)) gs_param_i2c_get_request { + gs_i2c_slave_dispatch_header_t header; + uint8_t length_table; + uint8_t addr; + uint8_t checksum; // optional +} gs_param_i2c_get_request_t; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/pp/i2c/slave_dispatch.h b/gomspace/libparam_client/include/gs/param/internal/pp/i2c/slave_dispatch.h new file mode 100644 index 00000000..a3779b5d --- /dev/null +++ b/gomspace/libparam_client/include/gs/param/internal/pp/i2c/slave_dispatch.h @@ -0,0 +1,71 @@ +#ifndef GS_PARAM_INTERNAL_PP_I2C_SLAVE_DISPATCH_H +#define GS_PARAM_INTERNAL_PP_I2C_SLAVE_DISPATCH_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#if (GS_PARAM_INTERNAL_USE) + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Header for I2C slave dispatch protocol - must be first in all protocols. +*/ +typedef struct __attribute__ ((packed)) gs_i2c_slave_dispatch_header { + uint8_t domain_command; +} gs_i2c_slave_dispatch_header_t; + +/** + Make header from domain and command. +*/ +#define GS_I2C_SLAVE_DISPATCH_HEADER(domain, command) ((domain << 5) | (command & 0x1f)) + +/** + Extract domain from header. +*/ +#define GS_I2C_SLAVE_DISPATCH_HEADER_TO_DOMAIN(header) ((header >> 5) & 0x7) + +/** + Extract comman from header. +*/ +#define GS_I2C_SLAVE_DISPATCH_HEADER_TO_COMMAND(header) (header & 0x1f) + +/** + Domain handler. + + Basically same features as normal I2C slave rx callback. The generic I2C dispatch interface will parse the header (first byte) + and call the associated handler, based on the domain. + + @param[in] channel I2C channel (handle). + @param[in] cmd domain specific command. + @param[in] rx_buffer Pointer to start of rx buffer. + @param[in] rx number of bytes received so far. + @param[in] cswitch If called from within an ISR (embedded platform), this will none NULL. + @return total number of bytes to receive before next call back. Return 0 to ignore rest of data - no additional call backs will be done for current I2C transaction. +*/ +typedef void (* gs_i2c_slave_dispatch_handler_t)(uint8_t channel, uint8_t cmd, const uint8_t * rx, size_t rx_length, gs_context_switch_t * cswitch); + +/** + Dispatch domains. + + Standard domains should be assigned from the lowest value. + Application/board/product should be assigned from highest value. +*/ +typedef enum { + GS_I2C_SLAVE_DISPATCH_DOMAIN_RESERVED = 0, //! Avoid use - reserved for GSSB, GSSB broadcasts UID request on domain=0, cmd=13 + GS_I2C_SLAVE_DISPATCH_DOMAIN_USER1, //! Avoid use - overlap with GSSB commands + GS_I2C_SLAVE_DISPATCH_DOMAIN_USER2, //! Avoid use - may overlap with GSSB commands + GS_I2C_SLAVE_DISPATCH_DOMAIN_USER3, //! Avoid use - may overlap with GSSB commands + GS_I2C_SLAVE_DISPATCH_DOMAIN_PARAM, //! Reserved for libparam. + GS_I2C_SLAVE_DISPATCH_DOMAIN_USER5, + GS_I2C_SLAVE_DISPATCH_DOMAIN_USER6, + GS_I2C_SLAVE_DISPATCH_DOMAIN_USER7, +} gs_i2c_slave_dispatch_domain_t; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/pp/spi/slave_dispatch.h b/gomspace/libparam_client/include/gs/param/internal/pp/spi/slave_dispatch.h new file mode 100644 index 00000000..1a4a3959 --- /dev/null +++ b/gomspace/libparam_client/include/gs/param/internal/pp/spi/slave_dispatch.h @@ -0,0 +1,80 @@ +#ifndef GS_PARAM_INTERNAL_PP_SPI_SLAVE_DISPATCH_H +#define GS_PARAM_INTERNAL_PP_SPI_SLAVE_DISPATCH_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#if (GS_PARAM_INTERNAL_USE) + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Header for SPI slave dispatch protocol - must be first in all protocols. +*/ +typedef struct __attribute__ ((packed)) gs_spi_slave_dispatch_header { + uint8_t domain_command; +} gs_spi_slave_dispatch_header_t; + +/** + Make header from domain and command. +*/ +#define GS_SPI_SLAVE_DISPATCH_HEADER(domain, command) ((domain << 5) | (command & 0x1f)) + +/** + Extract domain from header. +*/ +#define GS_SPI_SLAVE_DISPATCH_HEADER_TO_DOMAIN(header) ((header >> 5) & 0x7) + +/** + Extract comman from header. +*/ +#define GS_SPI_SLAVE_DISPATCH_HEADER_TO_COMMAND(header) (header & 0x1f) + +/** + Domain handler. + + Basically same features as normal SPI slave rx callback. The generic SPI dispatch interface will parse the header (first byte) + and call the associated handler, based on the domain. + + @param[in] channel SPI channel (handle). + @param[in] cmd domain specific command. + @param[in] rx_buffer Pointer to start of rx buffer. + @param[in] rx number of bytes received so far. + @param[in] cswitch If called from within an ISR (embedded platform), this will none NULL. + @return total number of bytes to receive before next call back. Return 0 to ignore rest of data - no additional call backs will be done for current SPI transaction. +*/ +typedef uint8_t (* gs_spi_slave_dispatch_handler_t)(uint8_t channel, uint8_t cmd, const uint8_t * rx_buffer, size_t rx, gs_context_switch_t * cswitch); + +/** + Dispatch domains. + + Standard domains should be assigned form the lowest value. + Application/board/product should be assigned from highest value. +*/ +typedef enum { + GS_SPI_SLAVE_DISPATCH_DOMAIN_RESERVED = 0, //! Avoid using 0, + GS_SPI_SLAVE_DISPATCH_DOMAIN_USER1, + GS_SPI_SLAVE_DISPATCH_DOMAIN_USER2, + GS_SPI_SLAVE_DISPATCH_DOMAIN_USER3, + GS_SPI_SLAVE_DISPATCH_DOMAIN_PARAM, + GS_SPI_SLAVE_DISPATCH_DOMAIN_USER5, + GS_SPI_SLAVE_DISPATCH_DOMAIN_USER6, + GS_SPI_SLAVE_DISPATCH_DOMAIN_USER7, +} gs_spi_slave_dispatch_domain_t; + +/** + Slave dispatch SPI receiver. + + Must be added on the channel as receiver function, using gs_spi_slave_set_rx(). + + @param[in] cswitch If called from within an ISR (embedded platform), this will be set and allow for triggering context switch. +*/ +uint8_t gs_spi_slave_dispatch_rx(uint8_t channel, const uint8_t * rx_buffer, size_t rx, bool new_request, gs_context_switch_t * cswitch); + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/pp/spi/spi.h b/gomspace/libparam_client/include/gs/param/internal/pp/spi/spi.h new file mode 100644 index 00000000..b9303dcb --- /dev/null +++ b/gomspace/libparam_client/include/gs/param/internal/pp/spi/spi.h @@ -0,0 +1,65 @@ +#ifndef GS_PARAM_INTERNAL_PP_SPI_SPI_H +#define GS_PARAM_INTERNAL_PP_SPI_SPI_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#if (GS_PARAM_INTERNAL_USE) + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Domain commands. +*/ +typedef enum { + GS_PARAM_SPI_COMMAND_SET = 1, + GS_PARAM_SPI_COMMAND_GET = 2, + GS_PARAM_SPI_COMMAND_SET_WITH_CHECKSUM = 10, + GS_PARAM_SPI_COMMAND_GET_WITH_CHECKSUM = 11, +} gs_param_spi_command_t; + +#define GS_PARAM_SPI_LENGTH_TABLE(length, table) ((length << 3) | (table & 0x07)) +#define GS_PARAM_SPI_LENGTH_TABLE_TO_LENGTH(lt) ((lt >> 3) & 0x1f) +#define GS_PARAM_SPI_LENGTH_TABLE_TO_TABLE(lt) (lt & 0x07) + +/** + Data structure for setting parameter. +*/ +typedef struct __attribute__ ((packed)) gs_param_spi_set { + gs_spi_slave_dispatch_header_t header; + uint8_t length_table; + uint8_t addr; + uint8_t data[]; // data (+ checksum) +} gs_param_spi_set_t; + +/** + Data structure for getting parameter. +*/ +typedef struct __attribute__ ((packed)) gs_param_spi_get { + gs_spi_slave_dispatch_header_t header; + uint8_t length_table; + uint8_t addr; + uint8_t filler; // filler/delay - allow slave to find and prepare data/response + uint8_t data[]; // data +} gs_param_spi_get_t; + +/** + Data structure for getting parameter with checksum +*/ +typedef struct __attribute__ ((packed)) gs_param_spi_get_with_checksum { + gs_spi_slave_dispatch_header_t header; + uint8_t length_table; + uint8_t addr; + uint8_t checksum; + uint8_t filler; // filler/delay - allow slave to find and prepare data/response + uint8_t data[]; // data + checksum +} gs_param_spi_get_with_checksum_t; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/rparam.h b/gomspace/libparam_client/include/gs/param/internal/rparam.h new file mode 100644 index 00000000..ae70d215 --- /dev/null +++ b/gomspace/libparam_client/include/gs/param/internal/rparam.h @@ -0,0 +1,146 @@ +#ifndef GS_PARAM_INTERNAL_RPARAM_H +#define GS_PARAM_INTERNAL_RPARAM_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#if (GS_PARAM_INTERNAL_USE) + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Max query payload in a single message (bytes). +*/ +#define GS_RPARAM_QUERY_MAX_PAYLOAD 180 + +/** + Macro for calculating total query message size, header + payload. +*/ +#define RPARAM_QUERY_LENGTH(query, payload_size) (sizeof(*query) - sizeof(query->payload) + payload_size) + +/** + R(emote) parameter request codes. +*/ +typedef enum { + /** + Get one or more parameters. + */ + RPARAM_GET = 0x00, + /** + Reply to a request. + */ + RPARAM_REPLY = 0x55, + /** + Set one or more parameters. + */ + RPARAM_SET = 0xFF, + // RPARAM_SET_TO_FILE = 0xEE, + /** + Download table specification. + */ + RPARAM_TABLE = 0x44, + /** + Copy memory slot to memory slot. + @version 4.x: Not supported. + */ + RPARAM_COPY = 0x77, + /** + Load from file (slot) to memory (slot). + @version 4.x: Only load from primary store - file (slot) is ignored. + */ + RPARAM_LOAD = 0x88, + /** + Load from file (slot) to memory (slot). + @version 4.x: load by name(s). + */ + RPARAM_LOAD_FROM_STORE = 0x89, + /** + Save from memory (slot) to file (slot). + @version 4.x: Only save to primary store - file (slot) is ignored. + */ + RPARAM_SAVE = 0x99, + /** + Save from memory (slot) to file (slot). + @version 4.x: save by name(s). + */ + RPARAM_SAVE_TO_STORE = 0x9a, + // RPARAM_CLEAR = 0xAA, - completely removed +} gs_rparam_action_t; + +/** + R(emote) parameter reply/completion codes. +*/ +typedef enum { + RPARAM_SET_OK = 1, + RPARAM_LOAD_OK = 2, + RPARAM_SAVE_OK = 3, + RPARAM_COPY_OK = 4, + // RPARAM_CLEAR_OK = 5, + RPARAM_ERROR = 0xFF, +} gs_rparam_reply_t; + +/** + Payload - save/load to/from stores + @version 4 +*/ +typedef struct __attribute__ ((packed)) { + char table[25 + 1]; + char store[25 + 1]; + char slot[25 + 1]; +} gs_rparam_query_payload_store_t; + +/** + Payload. +*/ +typedef union __attribute__ ((packed)) { + uint16_t addr[0]; //! action = RPARAM_GET + uint8_t packed[0]; //! action = RPARAM_REPLY | RPARAM_SET + struct { //! action = RPARAM_COPY | RPARAM_LOAD | RPARM_SAVE + uint8_t from; + uint8_t to; + } copy; +} gs_rparam_query_payload_t; + +/** + Protocol between client and server. + @version 4.x: layout (size) has not changed - only naming of certain fields. +*/ +typedef struct __attribute__ ((packed)) { + /** + Request (gs_rparam_action_t) or Reply (gs_rparam_reply_t). + */ + uint8_t action; + /** + Table id. + Name changed in 4.0 from \a mem. + */ + uint8_t table_id; + /** + Length/size of \a payload in bytes. + */ + uint16_t length; + /** + Fletcher's checksum. + */ + uint16_t checksum; + /** + Sequence number when split over multiple frames (messages). + */ + uint16_t seq; + /** + Total number of frames. + */ + uint16_t total; + /** + Payload. + */ + gs_rparam_query_payload_t payload; +} gs_rparam_query_t; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/serialize.h b/gomspace/libparam_client/include/gs/param/internal/serialize.h new file mode 100644 index 00000000..704b67f5 --- /dev/null +++ b/gomspace/libparam_client/include/gs/param/internal/serialize.h @@ -0,0 +1,29 @@ +#ifndef GS_PARAM_INTERNAL_SERIALIZE_H +#define GS_PARAM_INTERNAL_SERIALIZE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#if (GS_PARAM_INTERNAL_USE) + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Serialize data + * @param mem Pointer to indexed parameter table + * @param addr Array of addresses to serialize + * @param addr_count number of items in addr array + * @param[in|out] param_offset table parameter offset + * @param flags Set options using combination of flags + * @param buf Pointer to output + * @param buf_size Size of \a buf. + */ +gs_error_t gs_param_serialize_list(gs_param_table_instance_t * tinst, const uint16_t addr[], unsigned int addr_count, unsigned int * param_pos, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos); + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/table.h b/gomspace/libparam_client/include/gs/param/internal/table.h new file mode 100644 index 00000000..11b123bc --- /dev/null +++ b/gomspace/libparam_client/include/gs/param/internal/table.h @@ -0,0 +1,19 @@ +#ifndef GS_PARAM_INTERNAL_TABLE_H +#define GS_PARAM_INTERNAL_TABLE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#if (GS_PARAM_INTERNAL_USE) + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +gs_error_t gs_param_parse_name_and_array_index(const char * inp, char * name, size_t size_name, uint8_t * array_index, bool * return_is_array); + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/types.h b/gomspace/libparam_client/include/gs/param/internal/types.h new file mode 100644 index 00000000..5cefc4c0 --- /dev/null +++ b/gomspace/libparam_client/include/gs/param/internal/types.h @@ -0,0 +1,129 @@ +#ifndef GS_PARAM_INTERNAL_TYPES_H +#define GS_PARAM_INTERNAL_TYPES_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#if (GS_PARAM_INTERNAL_USE) + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Table instance. +*/ +struct gs_param_table_instance { + /** + Name of table. + */ + const char * name; + + /** + Table id. + */ + gs_param_table_id_t id; + + /** + Table elements/rows. + */ + const gs_param_table_row_t * rows; + /** + Table element/row count. + */ + unsigned int row_count; + + /** + Table memory - volatile parameter store. + The allocated size must be at least \a memory_size bytes. + */ + void * memory; + + /** + Size of table data memory in bytes, normally size of memory allocated \a memory. + Size must always be specified, even when using function interface and no memory is allocated. + */ + unsigned int memory_size; + + /** + Function interface, e.g. get/set. + */ + gs_param_function_interface_t function_interface; + + /** + Checksum - based on host order (e.g. le or be). + @see gs_param_table_checksum() + */ + uint16_t checksum; + + /** + Checksum - based on big-endian (address converted to big-endian). + @see gs_param_table_checksum_be() + */ + uint16_t checksum_be; + + /** + Checksum - based on little-endian (address converted to little-endian). + @see gs_param_table_checksum_le() + */ + uint16_t checksum_le; + + /** + Lock. + Internal access/use only, use gs_param_lock() and gs_param_unlock() to lock and un-lock table. + */ + gs_mutex_t lock; + + /** + Callback for table (data) change. + */ + void (*callback)(uint16_t addr, gs_param_table_instance_t * tinst); + + /** + Store location(s). + CSV format, e.g. \"persistent,protected\". + */ + const char * stores; + + /** + Auto-persist. + */ + struct { + /** + Store. + */ + const char * store; + + /** + User context(s) for the \a set function. + */ + void * context1; + void * context2; + + /** + Set/write parameter. + */ + gs_error_t (*set)(gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, const void * item, size_t size, uint32_t flags); + } auto_persist; + + /** + Function for initializing table. + */ + gs_error_t (*initializer_function)(gs_param_table_instance_t * tinst); + + /** + Default values for initializing table. + */ + const void * default_values; + + /** + Future flags. + */ + uint32_t flags; +}; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/gomspace/libparam_client/include/gs/param/pp/i2c/i2c.h b/gomspace/libparam_client/include/gs/param/pp/i2c/i2c.h new file mode 100644 index 00000000..7ffdfd1b --- /dev/null +++ b/gomspace/libparam_client/include/gs/param/pp/i2c/i2c.h @@ -0,0 +1,60 @@ +#ifndef GS_PARAM_PP_I2C_I2C_H +#define GS_PARAM_PP_I2C_I2C_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + I2C param protocol client interface. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Commands. +*/ +typedef enum { + /** + Set parameter. + */ + GS_PARAM_I2C_COMMAND_SET = 1, + /** + Get parameter. + */ + GS_PARAM_I2C_COMMAND_GET = 2, + /** + Lock table. + */ + GS_PARAM_I2C_COMMAND_SET_LOCK_WITH_CHECKSUM = 3, + /** + Get table lock state. + */ + GS_PARAM_I2C_COMMAND_GET_LOCK_WITH_CHECKSUM = 4, + /** + Set parameter with checksum. + */ + GS_PARAM_I2C_COMMAND_SET_WITH_CHECKSUM = 10, + /** + Get parameter with checksum. + */ + GS_PARAM_I2C_COMMAND_GET_WITH_CHECKSUM = 11, +} gs_param_i2c_command_t; + +/** + Initialize the param protocol handle for I2C. + + @param[in] pp handle. + @param[in] bus bus to communicate on. + @param[in] addr address of node. + @param[in] big_endian \a true if slave is big endian. Used to convert to host endian. + @return_gs_error_t +*/ +gs_error_t gs_pp_i2c_init(gs_pp_t * pp, uint8_t bus, uint8_t addr, bool big_endian); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libparam_client/include/gs/param/pp/pp.h b/gomspace/libparam_client/include/gs/param/pp/pp.h new file mode 100644 index 00000000..a3bbb539 --- /dev/null +++ b/gomspace/libparam_client/include/gs/param/pp/pp.h @@ -0,0 +1,214 @@ +#ifndef GS_PARAM_PP_PP_H +#define GS_PARAM_PP_PP_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Param Protocol (PP) API - generic interface for getting/setting parameters over SPI, I2C, etc. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Flags used in gs_pp_xxx() functions. + @{ +*/ +/** + Use checksum in transfer. + @see gs_pp_checksum8() +*/ +#define GS_PP_FLAG_CHECKSUM 0x0001 +/**@}*/ + +/** + Handle for a protocol connection. +*/ +typedef struct gs_pp gs_pp_t; + +/** + Callback for getting a parameter. +*/ +typedef gs_error_t (*gs_pp_get_t)(gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, uint32_t flags); + +/** + Callback for setting a parameter. +*/ +typedef gs_error_t (*gs_pp_set_t)(gs_pp_t * pp, uint8_t table_id, uint16_t addr, const void * value, size_t value_size, uint32_t flags); + +/** + Callback for setting table lock. +*/ +typedef gs_error_t (*gs_pp_get_table_lock_t)(gs_pp_t * pp, uint8_t table_id, bool * value, uint32_t flags); + +/** + Callback for setting table lock. +*/ +typedef gs_error_t (*gs_pp_set_table_lock_t)(gs_pp_t * pp, uint8_t table_id, const bool * value, uint32_t flags); + +/** + Handle for a protocol connection. +*/ +struct gs_pp { + /** + Endian type of slave. + */ + bool big_endian; + /** + Callback function for \a get. + */ + gs_pp_get_t get; + /** + Callback function for \a set. + */ + gs_pp_set_t set; + /** + Callback function for \a get_table_lock. + */ + gs_pp_get_table_lock_t get_table_lock; + /** + Callback function for \a set_table_lock. + */ + gs_pp_set_table_lock_t set_table_lock; + /** + Protocol specifics. + */ + union { + /** + SPI connection. + */ + struct { + /** + SPI slave id. + */ + uint8_t slave; + } spi; + /** + I2C connection. + */ + struct { + /** + I2C bus. + */ + uint8_t bus; + /** + I2C address. + */ + uint8_t addr; + } i2c; + } pp; +}; + +/** + Calculate very simple 8 bit checksum. + The checksum is calculated by adding all bytes. If the checksum is 0 (zero), the checksum is set to 1 (one). + @param[in] data data to calculate checksum for. + @param[in] length data length. + @return checksum +*/ +uint8_t gs_pp_checksum8(const void * data, size_t length); + +/** + Get lock value + + @param[in] pp Handle for connection + @param[in] table_id Table ID + @param[out] value Lock state (0 = unlocked, 1 = locked) + @param[in] flags + @return_gs_error_t + */ +gs_error_t gs_pp_get_table_lock(gs_pp_t * pp, uint8_t table_id, bool * value, uint32_t flags); + +/** + Set lock value + + @param[in] pp Handle for connection + @param[in] table_id Table ID + @param[in] value Lock state (0 = unlocked, 1 = locked) + @param[in] flags + @return_gs_error_t +*/ +gs_error_t gs_pp_set_table_lock(gs_pp_t * pp, uint8_t table_id, const bool * value, uint32_t flags); + +/** + Get int8. +*/ +gs_error_t gs_pp_get_int8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int8_t * value, size_t count, uint32_t flags); + +/** + Set int8. +*/ +gs_error_t gs_pp_set_int8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int8_t * value, size_t count, uint32_t flags); + +/** + Get uint8. +*/ +gs_error_t gs_pp_get_uint8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint8_t * value, size_t count, uint32_t flags); + +/** + Set uint8. +*/ +gs_error_t gs_pp_set_uint8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint8_t * value, size_t count, uint32_t flags); + +/** + Get int16. +*/ +gs_error_t gs_pp_get_int16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int16_t * value, size_t count, uint32_t flags); + +/** + Set int16. +*/ +gs_error_t gs_pp_set_int16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int16_t * value, size_t count, uint32_t flags); + +/** + Get uint16. +*/ +gs_error_t gs_pp_get_uint16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint16_t * value, size_t count, uint32_t flags); + +/** + Set uint16. +*/ +gs_error_t gs_pp_set_uint16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint16_t * value, size_t count, uint32_t flags); + +/** + Get int32. +*/ +gs_error_t gs_pp_get_int32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int32_t * value, size_t count, uint32_t flags); + +/** + Set int32. +*/ +gs_error_t gs_pp_set_int32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int32_t * value, size_t count, uint32_t flags); + +/** + Get uint32. +*/ +gs_error_t gs_pp_get_uint32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint32_t * value, size_t count, uint32_t flags); + +/** + Set uint32. +*/ +gs_error_t gs_pp_set_uint32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint32_t * value, size_t count, uint32_t flags); + +/** + Get float. +*/ +gs_error_t gs_pp_get_float(gs_pp_t * pp, uint8_t table_id, uint8_t addr, float * value, size_t count, uint32_t flags); + +/** + Set float. +*/ +gs_error_t gs_pp_set_float(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const float * value, size_t count, uint32_t flags); + +/** + Register commands. +*/ +gs_error_t gs_pp_register_commands(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libparam_client/include/gs/param/pp/spi/spi.h b/gomspace/libparam_client/include/gs/param/pp/spi/spi.h new file mode 100644 index 00000000..32006c45 --- /dev/null +++ b/gomspace/libparam_client/include/gs/param/pp/spi/spi.h @@ -0,0 +1,29 @@ +#ifndef GS_PARAM_PP_SPI_SPI_H +#define GS_PARAM_PP_SPI_SPI_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + SPI Param Protocol (pp) client interface. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Initialize the param protocol handle for SPI. + + @param[in] pp handle. + @param[in] slave slave to communicate with. + @param[in] big_endian \a true if slave is big endian. Used to convert to host endian. + @return_gs_error_t +*/ +gs_error_t gs_pp_spi_init(gs_pp_t * pp, uint8_t slave, bool big_endian); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libparam_client/include/gs/param/rparam.h b/gomspace/libparam_client/include/gs/param/rparam.h new file mode 100644 index 00000000..950e22cf --- /dev/null +++ b/gomspace/libparam_client/include/gs/param/rparam.h @@ -0,0 +1,395 @@ +#ifndef GS_PARAM_REMOTE_H +#define GS_PARAM_REMOTE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Remote parameter API - pending refactoring. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Magic checksum. + If specifying a magic checksum, the rparam server will ignore/skip checksum validation. +*/ +#define GS_RPARAM_MAGIC_CHECKSUM 0x0bb0 + +/** + Register rparam commands. + @return_gs_error_t +*/ +gs_error_t gs_rparam_register_commands(void); + +/** + Download all (data) values from a remote table to a local instance. + + @param[in] tinst local table instance. + @param[in] node CSP address. + @param[in] table_id remote table id to download. + @param[in] checksum table checksum. + @param[in] timeout_ms timeout. + @return_gs_error_t +*/ +gs_error_t gs_rparam_get_full_table(gs_param_table_instance_t * tinst, + uint8_t node, + gs_param_table_id_t table_id, + uint16_t checksum, + uint32_t timeout_ms); + +/** + Download a table specification from a remote node, store it in memory and save it to local file system. + + @note Will free existing rows - do not use this on table instances with static assigned rows. + + Table memory will be (re)allocated to match specification. + + @param[in] tinst local table instance. + @param[in] fname name of the file to store the table specification in. If NULL, no file will be stored. + @param[in] node CSP address + @param[in] table_id remote table id to download. + @param[in] timeout_ms timeout. + @param[out] return_checksum fletcher16 checksum of downloaded specification "as is" - before network/host swapping. + @return_gs_error_t + @see gs_param_table_free() +*/ +gs_error_t gs_rparam_download_table_spec(gs_param_table_instance_t * tinst, + const char * fname, + uint8_t node, + gs_param_table_id_t table_id, + uint32_t timeout_ms, + uint16_t * return_checksum); + +/** + Load a table specification from a local file and store it in memory. + + @note Will free existing rows - do not use this on table instances with static assigned rows. + + Table memory will be (re)allocated to match specification. + + @param[in] tinst local table instance. + @param[in] fname name of the file to load the table specification from. + @param[out] return_checksum fletcher16 checksum stored in file. + @return_gs_error_t + @see gs_param_table_free() +*/ +gs_error_t gs_rparam_load_table_spec(gs_param_table_instance_t * tinst, const char* fname, uint16_t * return_checksum); + +/** + Copy from one table to another table. + + @deprecated Not supported by a param 4 backend and future versions. + + @param[in] node CSP address + @param[in] timeout_ms timeout on remote CSP calls + @param[in] from from table-id. + @param[in] to to table-id. + @return_gs_error_t +*/ +gs_error_t gs_rparam_copy(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to); + +/** + Save table. + + @note On a param 4 backend, the table will always be saved to it's primary store. + + @param[in] node CSP address + @param[in] timeout_ms timeout on remote CSP calls + @param[in] id table to save. + @param[in] to to file slot - ignored on param 4 backends. + @return_gs_error_t +*/ +gs_error_t gs_rparam_save(uint8_t node, uint32_t timeout_ms, gs_param_table_id_t id, uint8_t to); + +/** + Save table. + + @version 4 + @param[in] node CSP address + @param[in] timeout_ms timeout on remote CSP calls + @param[in] table_id remote table id. + @param[in] store store name. + @param[in] slot slot within store. + @return_gs_error_t +*/ +gs_error_t gs_rparam_save_to_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id, + const char * store, const char * slot); + +/** + Load table from store. + + @note On a param 4 backend, the specified table will be loadded from it's primary store. + + @param[in] node CSP address + @param[in] timeout_ms timeout on remote CSP calls + @param[in] from from file slot - ignored on param 4 backends. + @param[in] id table to load. + @return_gs_error_t +*/ +gs_error_t gs_rparam_load(uint8_t node, uint32_t timeout_ms, uint8_t from, gs_param_table_id_t id); + +/** + Load table from store. + + @version 4 + @param[in] node CSP address + @param[in] timeout_ms timeout on remote CSP calls + @param[in] table_id remote table id. + @param[in] store store name. + @param[in] slot slot within store. + @return_gs_error_t +*/ +gs_error_t gs_rparam_load_from_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id, + const char * store, const char * slot); + +/** + Get parameter. + + @param[in] node CSP address + @param[in] table_id remote table id. + @param[in] addr parameter address (remote table). + @param[in] type parameter type. + @param[in] checksum checksum + @param[in] timeout_ms timeout + @param[out] value returned value (user allocated) + @param[in] value_size size of \a value buffer. + @return_gs_error_t +*/ +gs_error_t gs_rparam_get(uint8_t node, + gs_param_table_id_t table_id, + uint16_t addr, + gs_param_type_t type, + uint16_t checksum, + uint32_t timeout_ms, + void * value, + size_t value_size); + +/** + Set parameter. + + @param[in] node CSP address + @param[in] table_id remote table id. + @param[in] addr parameter address (remote table). + @param[in] type parameter type. + @param[in] checksum checksum + @param[in] timeout_ms timeout + @param[in] value value to set + @param[in] value_size size of \a value. + @return_gs_error_t +*/ +gs_error_t gs_rparam_set(uint8_t node, + gs_param_table_id_t table_id, + uint16_t addr, + gs_param_type_t type, + uint16_t checksum, + uint32_t timeout_ms, + const void * value, + size_t value_size); + +/** + Get string. +*/ +static inline gs_error_t gs_rparam_get_string(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, char * value, size_t value_size) +{ + return gs_rparam_get(node, table_id, addr, GS_PARAM_STRING, checksum, timeout_ms, value, value_size); +} + +/** + Set string. +*/ +static inline gs_error_t gs_rparam_set_string(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, const char * value, size_t value_size) +{ + return gs_rparam_set(node, table_id, addr, GS_PARAM_STRING, checksum, timeout_ms, value, (value_size == 0) ? (strlen(value) + 1) : value_size); +} + +/** + Get int8. +*/ +static inline gs_error_t gs_rparam_get_int8(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, int8_t * value) +{ + return gs_rparam_get(node, table_id, addr, GS_PARAM_INT8, checksum, timeout_ms, value, sizeof(*value)); +} + +/** + Set int8. +*/ +static inline gs_error_t gs_rparam_set_int8(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, int8_t value) +{ + return gs_rparam_set(node, table_id, addr, GS_PARAM_INT8, checksum, timeout_ms, &value, sizeof(value)); +} + +/** + Get uint8. +*/ +static inline gs_error_t gs_rparam_get_uint8(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, uint8_t * value) +{ + return gs_rparam_get(node, table_id, addr, GS_PARAM_UINT8, checksum, timeout_ms, value, sizeof(*value)); +} + +/** + Set uint8. +*/ +static inline gs_error_t gs_rparam_set_uint8(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, uint8_t value) +{ + return gs_rparam_set(node, table_id, addr, GS_PARAM_UINT8, checksum, timeout_ms, &value, sizeof(value)); +} + +/** + Get int16. +*/ +static inline gs_error_t gs_rparam_get_int16(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, int16_t * value) +{ + return gs_rparam_get(node, table_id, addr, GS_PARAM_INT16, checksum, timeout_ms, value, sizeof(*value)); +} + +/** + Set int16. +*/ +static inline gs_error_t gs_rparam_set_int16(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, int16_t value) +{ + return gs_rparam_set(node, table_id, addr, GS_PARAM_INT16, checksum, timeout_ms, &value, sizeof(value)); +} + +/** + Get uint16. +*/ +static inline gs_error_t gs_rparam_get_uint16(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, uint16_t * value) +{ + return gs_rparam_get(node, table_id, addr, GS_PARAM_UINT16, checksum, timeout_ms, value, sizeof(*value)); +} + +/** + Set uint16. +*/ +static inline gs_error_t gs_rparam_set_uint16(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, uint16_t value) +{ + return gs_rparam_set(node, table_id, addr, GS_PARAM_UINT16, checksum, timeout_ms, &value, sizeof(value)); +} + +/** + Get int32. +*/ +static inline gs_error_t gs_rparam_get_int32(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, int32_t * value) +{ + return gs_rparam_get(node, table_id, addr, GS_PARAM_INT32, checksum, timeout_ms, value, sizeof(*value)); +} + +/** + Set int32. +*/ +static inline gs_error_t gs_rparam_set_int32(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, int32_t value) +{ + return gs_rparam_set(node, table_id, addr, GS_PARAM_INT32, checksum, timeout_ms, &value, sizeof(value)); +} + +/** + Get uint32. +*/ +static inline gs_error_t gs_rparam_get_uint32(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, uint32_t * value) +{ + return gs_rparam_get(node, table_id, addr, GS_PARAM_UINT32, checksum, timeout_ms, value, sizeof(*value)); +} + +/** + Set uint32. +*/ +static inline gs_error_t gs_rparam_set_uint32(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, uint32_t value) +{ + return gs_rparam_set(node, table_id, addr, GS_PARAM_UINT32, checksum, timeout_ms, &value, sizeof(value)); +} + +/** + Get int64. +*/ +static inline gs_error_t gs_rparam_get_int64(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, int64_t * value) +{ + return gs_rparam_get(node, table_id, addr, GS_PARAM_INT64, checksum, timeout_ms, value, sizeof(*value)); +} + +/** + Set int64. +*/ +static inline gs_error_t gs_rparam_set_int64(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, int64_t value) +{ + return gs_rparam_set(node, table_id, addr, GS_PARAM_INT64, checksum, timeout_ms, &value, sizeof(value)); +} + +/** + Get uint64. +*/ +static inline gs_error_t gs_rparam_get_uint64(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, uint64_t * value) +{ + return gs_rparam_get(node, table_id, addr, GS_PARAM_UINT64, checksum, timeout_ms, value, sizeof(*value)); +} + +/** + Set uint64. +*/ +static inline gs_error_t gs_rparam_set_uint64(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, uint64_t value) +{ + return gs_rparam_set(node, table_id, addr, GS_PARAM_UINT64, checksum, timeout_ms, &value, sizeof(value)); +} + +/** + Get float. +*/ +static inline gs_error_t gs_rparam_get_float(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, float * value) +{ + return gs_rparam_get(node, table_id, addr, GS_PARAM_FLOAT, checksum, timeout_ms, value, sizeof(*value)); +} + +/** + Set float. +*/ +static inline gs_error_t gs_rparam_set_float(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, float value) +{ + return gs_rparam_set(node, table_id, addr, GS_PARAM_FLOAT, checksum, timeout_ms, &value, sizeof(value)); +} + +/** + Get double. +*/ +static inline gs_error_t gs_rparam_get_double(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, double * value) +{ + return gs_rparam_get(node, table_id, addr, GS_PARAM_DOUBLE, checksum, timeout_ms, value, sizeof(*value)); +} + +/** + Set double. +*/ +static inline gs_error_t gs_rparam_set_double(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, + uint16_t checksum, uint32_t timeout_ms, double value) +{ + return gs_rparam_set(node, table_id, addr, GS_PARAM_DOUBLE, checksum, timeout_ms, &value, sizeof(value)); +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libparam_client/include/gs/param/serialize.h b/gomspace/libparam_client/include/gs/param/serialize.h new file mode 100644 index 00000000..9b935e3d --- /dev/null +++ b/gomspace/libparam_client/include/gs/param/serialize.h @@ -0,0 +1,101 @@ +#ifndef GS_PARAM_CLIENT_SERIALIZE_H +#define GS_PARAM_CLIENT_SERIALIZE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Serialize API - pending refactoring. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Serialize/deserialize flags + Flags must be in range: bit 8 - 15, to avoid clash with other parts of the parameter system. +*/ +typedef enum { + GS_PARAM_SF_DRY_RUN = (1 << 8), //!< F_DRY_RUN do not write to memory + GS_PARAM_SF_TO_BIG_ENDIAN = (1 << 9), //!< F_TO_BIG_ENDIAN Convert from host to big endian + GS_PARAM_SF_FROM_BIG_ENDIAN = (1 << 10), //!< F_FROM_BIG_ENDIAN Confert from big endian to host order + GS_PARAM_SF_PACKED = (1 << 11), //!< F_PACKED Do not pack addresses + + F_DRY_RUN = GS_PARAM_SF_DRY_RUN, + F_TO_BIG_ENDIAN = GS_PARAM_SF_TO_BIG_ENDIAN, + F_FROM_BIG_ENDIAN = GS_PARAM_SF_FROM_BIG_ENDIAN, + F_PACKED = GS_PARAM_SF_PACKED, +} gs_param_serialize_flags_t; + +/** + * In-place conversion of a single parameter from big endian to host byte order + * @param type param type + * @param item pointer to parameter memory + * @return 1 if memory has been swapped, 0 if not + */ +bool gs_param_betoh(gs_param_type_t type, void * item); + +/** + * In-place conversion of a single parameter from host byte order to big endian + * @param type param type + * @param item porinter to parameter memory + * @return 1 if memory has been swapped, 0 if not + */ +bool gs_param_htobe(gs_param_type_t type, void * item); + +/** + Serialize data + + @param[in] tinst table. + @param[in,out] param_pos parameter iterator. + @param[in] flags flags. + @param[out] buf user supplied buffer of \a buf_size. + @param[in] buf_size of size of \a buf + @param[in,out] buf_pos index into \a buf + @return_gs_error_t +*/ +gs_error_t gs_param_serialize_full_table(gs_param_table_instance_t * tinst, unsigned int * param_pos, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos); + +/** + Serialize single item + + @param[in] param parameter to serialize + @param[in] addr Address of item + @param[in] item item to serialize. + @param[in] flags flags. + @param[out] buf user supplied buffer of \a buf_size. + @param[in] buf_size of size of \a buf + @param[in,out] buf_pos index into \a buf + @return_gs_error_t +*/ +gs_error_t gs_param_serialize_item(const gs_param_table_row_t * param, uint16_t addr, const void * item, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos); + +/** + Deserialize packed parameters into memory + + @param[in] tinst table. + @param[in] buf serialized data. + @param[in] buf_size size \a buf containing serialized data + @param[in] flags flags. + @return_gs_error_t +*/ +gs_error_t gs_param_deserialize(gs_param_table_instance_t * tinst, const uint8_t * buf, unsigned int buf_size, uint32_t flags); + +/** + Deserialize a sginle item from a string into memory + + @param[in] tinst table. + @param param Pointer to specific parameter to deserialize + @param addr Address of parameter + @param item Pointer to memory area where item should be written + @param flags Set options using combination of flags + @return_gs_error_t +*/ +gs_error_t gs_param_deserialize_item(gs_param_table_instance_t * tinst, const gs_param_table_row_t * param, uint16_t addr, const void * item, uint32_t flags); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libparam_client/include/gs/param/table.h b/gomspace/libparam_client/include/gs/param/table.h new file mode 100644 index 00000000..0b5e153d --- /dev/null +++ b/gomspace/libparam_client/include/gs/param/table.h @@ -0,0 +1,428 @@ +#ifndef GS_PARAM_TABLE_H +#define GS_PARAM_TABLE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Client table API. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Allocate table memory when creating a table. + + Flags must be in range: bit 16 - 23, to avoid clash with other parts of the parameter system. +*/ +#define GS_PARAM_TABLE_F_ALLOC_MEMORY 0x0100 +/** + Allocate table rows. + + Flags must be in range: bit 16 - 23, to avoid clash with other parts of the parameter system. +*/ +#define GS_PARAM_TABLE_F_ALLOC_ROWS 0x0200 +/** + Disable table locking. + + Flags must be in range: bit 16 - 23, to avoid clash with other parts of the parameter system. +*/ +#define GS_PARAM_TABLE_F_NO_LOCK 0x0400 + +/** + Calculate memory size based on table rows. + + @param[in] rows rows + @param[in] row_count row count. + @return size of table or 0 in case of invalid arguments. +*/ +size_t gs_param_calc_table_size(const gs_param_table_row_t * rows, size_t row_count); + +/** + Return size of table instance. +*/ +size_t gs_param_table_instance_size(void); + +/** + Clear (and check size) of memory for table instance. + + @param[in] var user allocated space of at least gs_param_table_instance_size() bytes. + @param[in] var_size of \a var. + @return table instance + @see gs_param_table_instance_size() + @see #GS_PARAM_TINST_VAR +*/ +gs_param_table_instance_t * gs_param_table_instance_clear(void * var, size_t var_size); + +/** + Allocates aligned space on the stack for a table instance structure. + @param[in] var name of table instsance variable. +*/ +#define GS_PARAM_TINST_VAR(var) uint8_t var##__data [gs_param_table_instance_size()] __attribute__ ((aligned(4))); gs_param_table_instance_t * var = gs_param_table_instance_clear(var##__data, sizeof(var##__data)) + +/** + Allocate memory for table instance. + + Use gs_param_table_free() to free any internal resources. + + Use standard free() to free allocated memory. + + @return table instance on success, otherwise NULL. +*/ +gs_param_table_instance_t * gs_param_table_instance_alloc(void); + +/** + Find row by name. + + @param[in] name parameter name. + @param[in] rows rows + @param[in] row_count row count. + @return row or NULL if not found. +*/ +const gs_param_table_row_t * gs_param_row_by_name(const char * name, const gs_param_table_row_t * rows, size_t row_count); + +/** + Find row by address. + + @param[in] addr parameter address. + @param[in] rows rows + @param[in] row_count row count. + @return row or NULL if not found. +*/ +const gs_param_table_row_t * gs_param_row_by_address(uint16_t addr, const gs_param_table_row_t * rows, size_t row_count); + +/** + Return table memory. + + @note handle with care - any read/write should be atomic to prevent inconsistent data. + + @param[in] tinst table instance + @param[out] return_size if not NULL, the memory size is returned. + @return pointer to the table's data memory. +*/ +void * gs_param_table_get_memory(gs_param_table_instance_t * tinst, size_t * return_size); + +/** + Return table rows. + + @param[in] tinst table instance + @param[out] return_count if not NULL, the row count is returned. + @return pointer to the table rows. +*/ +const gs_param_table_row_t * gs_param_table_get_rows(gs_param_table_instance_t * tinst, size_t * return_count); + +/** + Lock table (recursive). + + @param[in] tinst table instance + @return_gs_error_t +*/ +gs_error_t gs_param_table_lock(gs_param_table_instance_t * tinst); + +/** + Unlock table. + + Unlock must be called once for every time gs_param_table_lock() has been called. + + @param[in] tinst table instance + @return_gs_error_t +*/ +gs_error_t gs_param_table_unlock(gs_param_table_instance_t * tinst); + +/** + Free internal resources and clears instance. + + @param[in] tinst table instance + @return_gs_error_t +*/ +gs_error_t gs_param_table_free(gs_param_table_instance_t * tinst); + +/** + Print a single parameter on stream. + + @param[in] tinst table instanc. + @param[in] row row to print. + @param[in] list_data \a true includes parameter value. + @param[in] flags flags to control output format: #GS_PARAM_F_SHOW_SCIENTIFIC, #GS_PARAM_F_SHOW_HEX. + @param[in] out output stream. + @return_gs_error_t +*/ +gs_error_t gs_param_list_single_to_stream(gs_param_table_instance_t * tinst, const gs_param_table_row_t * row, bool list_data, uint32_t flags, FILE * out); + +/** + Print a single parameter on stdout. + + @param[in] tinst table instanc. + @param[in] row row to print. + @param[in] list_data \a true includes parameter value. + @return_gs_error_t +*/ +static inline gs_error_t gs_param_list_single(gs_param_table_instance_t * tinst, const gs_param_table_row_t * row, bool list_data) +{ + return gs_param_list_single_to_stream(tinst, row, list_data, 0, stdout); +} + +/** + Print entire table on stream. + + @param[in] tinst table instanc. + @param[in] list_data \a true includes parameter value. + @param[in] flags flags to control output format: #GS_PARAM_F_SHOW_SCIENTIFIC, #GS_PARAM_F_SHOW_HEX. + @param[in] out output stream. + @return_gs_error_t +*/ +gs_error_t gs_param_list_to_stream(gs_param_table_instance_t * tinst, bool list_data, uint32_t flags, FILE * out); + +/** + Print entire table on stdout. + + @param[in] tinst table instanc. + @param[in] list_data \a true includes parameter value. + @return_gs_error_t +*/ +static inline gs_error_t gs_param_list(gs_param_table_instance_t * tinst, bool list_data) +{ + return gs_param_list_to_stream(tinst, list_data, 0, stdout); +} + +/** + Convert string to parameter. + + @param[in] row row defining the parameter to convert. + @param[in] string string to convert. + @param[out] return_value user supplied buffer for returning the value - must be at least the size specified in \a row + @return_gs_error_t +*/ +gs_error_t gs_param_from_string(const gs_param_table_row_t * row, const char * string, void * return_value); + +/** + Convert parameter to string. + + @param[in] row row defining the parameter to convert. + @param[in] value parameter value to convert. + @param[in] with_type \a true includes data type. + @param[in] flags flags to control output format: #GS_PARAM_F_SHOW_SCIENTIFIC, #GS_PARAM_F_SHOW_HEX. + @param[out] buf user supplied buffer of \a buf_size bytes. + @param[in] buf_size size of \a buf in bytes. + @param[in] buf_pos buffer position to insert string. + @param[out] return_buf_written number of bytes written to \a buf. + @return_gs_error_t +*/ +gs_error_t gs_param_to_string2(const gs_param_table_row_t * row, const void * value, bool with_type, uint32_t flags, char * buf, unsigned int buf_size, unsigned int buf_pos, unsigned int * return_buf_written); + +/** + Convert parameter to string. + + @param[in] row row defining the parameter to convert. + @param[in] value parameter value to convert. + @param[in] with_type \a true includes data type. + @param[out] buf user supplied buffer of \a buf_size bytes. + @param[in] buf_size size of \a buf in bytes. + @param[in] buf_pos buffer position to insert string. + @param[out] return_buf_written number of bytes written to \a buf. + @return_gs_error_t +*/ +static inline gs_error_t gs_param_to_string(const gs_param_table_row_t * row, const void * value, bool with_type, char * buf, unsigned int buf_size, unsigned int buf_pos, unsigned int * return_buf_written) +{ + return gs_param_to_string2(row, value, with_type, 0, buf, buf_size, buf_pos, return_buf_written); +} + +/** + Convert parameter type to string. + + @param[in] type parameter type. + @return pointer to a static string. +*/ +const char * gs_param_type_to_string(gs_param_type_t type); + +/** + Return size of parameter type. + + @param[in] type parameter type. + @return size of parameter type in bytes. +*/ +uint8_t gs_param_type_size(gs_param_type_t type); + +/** + Get table checksum - little-endian. + @note Use/exchange gs_param_table_checksum_be(), as this is calculated the same on all platforms. + @param[in] tinst table instance. + @returns 16-bit fletcher checksum +*/ +uint16_t gs_param_table_checksum_le(gs_param_table_instance_t * tinst); + +/** + Get table checksum - big-endian/network-order (prefered). + @param[in] tinst table instance. + @returns 16-bit fletcher checksum +*/ +uint16_t gs_param_table_checksum_be(gs_param_table_instance_t * tinst); + +/** + Get table checksum - host-order (not cross-platform). + @deprecated use gs_param_table_checksum_be() + @param[in] tinst table instance. + @returns 16-bit fletcher checksum +*/ +uint16_t gs_param_table_checksum(gs_param_table_instance_t * tinst); + +/** + Get table checksum - big-endian. + @deprecated use gs_param_table_checksum_be() + @param[in] tinst table instance. + @returns 16-bit fletcher checksum +*/ +static inline uint16_t gs_param_table_checksum2(gs_param_table_instance_t * tinst) +{ + return gs_param_table_checksum_be(tinst); +} + +/** + Get/read parameter from table. + + @param[in] tinst table instanc. + @param[in] addr parameter address (offset in table). + @param[in] type parameter type. + @param[out] return_value value of parameter - user supplied memory of at least \a size size. + @param[in] size number of bytes to get/read - must match \a type, e.g. 4 bytes for an uint32_t. + @param[in] flags flags. + @return_gs_error_t +*/ +gs_error_t gs_param_get(gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, void * return_value, size_t size, uint32_t flags); + +/** + Set/write parameter in table. + + @param[in] tinst table instanc. + @param[in] addr parameter address (offset in table). + @param[in] type parameter type. + @param[in] value value of parameter. + @param[in] size number of bytes to set/write - must match \a type, e.g. 4 bytes for an uint32_t. + @param[in] flags flags. + @return_gs_error_t +*/ +gs_error_t gs_param_set(gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, const void * value, size_t size, uint32_t flags); + +/** + Get string parameter. + + @param[in] tinst table instanc. + @param[in] addr parameter address (offset in table). + @param[out] buf value of parameter - user supplied memory of at least parameter size + 1 to hold NUL termination. + @param[in] buf_size size of \a buf - ensure room for NUL termination. + @param[in] flags flags. + @return GS_ERROR_OVERFLOW if string + NUL termination exceeds \a buf_size. + @return_gs_error_t +*/ +gs_error_t gs_param_get_string(gs_param_table_instance_t * tinst, uint16_t addr, char * buf, size_t buf_size, uint32_t flags); + +/** + Set string parameter. + + @param[in] tinst table. + @param[in] addr parameter address (offset in table). + @param[in] value string to save - parameter must be able to hold string + NUL termination. + @param[in] flags flags. + @return GS_ERROR_OVERFLOW if string + NUL termination exceeds parameter size. + @return_gs_error_t +*/ +gs_error_t gs_param_set_string(gs_param_table_instance_t * tinst, uint16_t addr, const char * value, uint32_t flags); + +/** + Get data parameter. + + @param[in] tinst table instanc. + @param[in] addr parameter address (offset in table). + @param[out] buf value of parameter - user supplied memory of at least parameter size. + @param[in] buf_size size of \a buf. + @param[in] flags flags. + @return GS_ERROR_OVERFLOW if parameter size is greater than \a buf_size. + @return_gs_error_t +*/ +gs_error_t gs_param_get_data(gs_param_table_instance_t * tinst, uint16_t addr, void * buf, size_t buf_size, uint32_t flags); + +/** + Set data parameter. + + @param[in] tinst table instanc. + @param[in] addr parameter address (offset in table). + @param[in] value value of parameter. + @param[in] value_size size of \a value. + @param[in] flags flags. + @return GS_ERROR_OVERFLOW if parameter size is greater than \a buf_size. + @return_gs_error_t +*/ +gs_error_t gs_param_set_data(gs_param_table_instance_t * tinst, uint16_t addr, const void * value, size_t value_size, uint32_t flags); + +/** + Macro for expanding get/set functions. + @param[in] name function suffix name. + @param[in] native_type native type + @param[in] param_type parameter type +*/ +#define GS_PARAM_PASTE(name, native_type, param_type) \ + static inline gs_error_t gs_param_get_##name(gs_param_table_instance_t * tinst, uint16_t addr, native_type * buf, uint32_t flags) { \ + return gs_param_get(tinst, addr, param_type, buf, sizeof(*buf), flags); \ + } \ + static inline native_type gs_param_get_##name##_nc(gs_param_table_instance_t * tinst, uint16_t addr, uint32_t flags) { \ + native_type value = 0; \ + gs_param_get(tinst, addr, param_type, &value, sizeof(value), flags); \ + return value; \ + } \ + static inline gs_error_t gs_param_set_##name(gs_param_table_instance_t * tinst, uint16_t addr, native_type value, uint32_t flags) { \ + return gs_param_set(tinst, addr, param_type, &value, sizeof(value), flags); \ + } + +/** + Get/set boolean. +*/ +GS_PARAM_PASTE(bool, bool, GS_PARAM_BOOL) +/** + Get/set uint8. +*/ +GS_PARAM_PASTE(uint8, uint8_t, GS_PARAM_UINT8) +/** + Get/set uint16. +*/ +GS_PARAM_PASTE(uint16, uint16_t, GS_PARAM_UINT16) +/** + Get/set uint32. +*/ +GS_PARAM_PASTE(uint32, uint32_t, GS_PARAM_UINT32) +/** + Get/set uint64. +*/ +GS_PARAM_PASTE(uint64, uint64_t, GS_PARAM_UINT64) +/** + Get/set int8. +*/ +GS_PARAM_PASTE(int8, int8_t, GS_PARAM_INT8) +/** + Get/set int16. +*/ +GS_PARAM_PASTE(int16, int16_t, GS_PARAM_INT16) +/** + Get/set int32. +*/ +GS_PARAM_PASTE(int32, int32_t, GS_PARAM_INT32) +/** + Get/set int64. +*/ +GS_PARAM_PASTE(int64, int64_t, GS_PARAM_INT64) +/** + Get/set double. +*/ +GS_PARAM_PASTE(double, double, GS_PARAM_DOUBLE) +/** + Get/set float. +*/ +GS_PARAM_PASTE(float, float, GS_PARAM_FLOAT) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libparam_client/include/gs/param/types.h b/gomspace/libparam_client/include/gs/param/types.h new file mode 100644 index 00000000..61efbb10 --- /dev/null +++ b/gomspace/libparam_client/include/gs/param/types.h @@ -0,0 +1,272 @@ +#ifndef GS_PARAM_TYPES_H +#define GS_PARAM_TYPES_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Parameter types. +*/ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Macros for accessing table row members. + These macros can be used to access members in a cross-platform way, compensating for the AVR8's memory model. + @{ +*/ +#define GS_PARAM_ARRAY_SIZE(p) gs_max(GS_PGM_UINT8((p)->array_size), 1) +#define GS_PARAM_SIZE(p) GS_PGM_UINT8((p)->size) +#define GS_PARAM_TYPE(p) GS_PGM_UINT8((p)->type) +#define GS_PARAM_ADDR(p) GS_PGM_UINT16((p)->addr) +#define GS_PARAM_FLAGS(p) GS_PGM_UINT8((p)->flags) +/** @} */ + +/** + Max parameter name - including 0 termination. + @note In some rare/old table definitions, the name may not be NULL terminated. +*/ +#define GS_PARAM_MAX_NAME 14 + +/** + Parameter flags. + Flags must be in range: bit 0 - 7, to avoid clash with other parts of the parameter system. +*/ +typedef enum { + /** + Parameter will be stored in configured auto-persist store when set. + @note Flag must be specified when setting the parameter. + */ + GS_PARAM_F_AUTO_PERSIST = (1 << 0), + /** + @deprecated Not supported in version 4.0 + */ + PARAM_F_READONLY = (1 << 1), + /** + Skip callback, when parameter is set. + @note Flag must be specified when setting the parameter. + */ + GS_PARAM_F_NO_CALLBACK = (1 << 2), + /** + Show/display parameter in hex. + */ + GS_PARAM_F_SHOW_HEX = (1 << 3), + /** + Show double/float using scientific notation. + */ + GS_PARAM_F_SHOW_SCIENTIFIC = (1 << 4), + + PARAM_F_NOCALLBACK = GS_PARAM_F_NO_CALLBACK, + PARAM_F_PERSIST = GS_PARAM_F_AUTO_PERSIST, +} gs_param_flags_t; + +/** + * Parameter types. + */ +typedef enum __attribute__((__packed__)) { + /** + Unsigned 8 bit (uint8_t). + */ + GS_PARAM_UINT8 = 0, + /** + Unsigned 16 bit (uint16_t). + */ + GS_PARAM_UINT16 = 1, + /** + Unsigned 32 bit (uint32_t). + */ + GS_PARAM_UINT32 = 2, + /** + Unsigned 64 bit (uint64_t). + */ + GS_PARAM_UINT64 = 3, + /** + Signed 8 bit (int8_t). + */ + GS_PARAM_INT8 = 4, + /** + Signed 16 bit (int16_t). + */ + GS_PARAM_INT16 = 5, + /** + Signed 32 bit (int32_t). + */ + GS_PARAM_INT32 = 6, + /** + Signed 64 bit (int64_t). + */ + GS_PARAM_INT64 = 7, + /** + @deprecated - use #GS_PARAM_UINT8 and #GS_PARAM_F_SHOW_HEX. + */ + PARAM_X8 = 8, + /** + @deprecated - use #GS_PARAM_UINT16 and #GS_PARAM_F_SHOW_HEX. + */ + PARAM_X16 = 9, + /** + @deprecated - use #GS_PARAM_UINT32 and #GS_PARAM_F_SHOW_HEX. + */ + PARAM_X32 = 10, + /** + @deprecated - use #GS_PARAM_UINT64 and #GS_PARAM_F_SHOW_HEX. + */ + PARAM_X64 = 11, + /** + Double. + */ + GS_PARAM_DOUBLE = 12, + /** + Float. + */ + GS_PARAM_FLOAT = 13, + /** + C or null-terminated string. + @note The specified \a size must include space for the NUL character. + */ + GS_PARAM_STRING = 14, + /** + Data (binary blob). + Binary blob: [0, 0x40, 0x4f] -> '00404f' + */ + GS_PARAM_DATA = 15, + /** + Boolean. + Expected same size as uint8_t. + */ + GS_PARAM_BOOL = 16, + + PARAM_UINT8 = GS_PARAM_UINT8, + PARAM_UINT16 = GS_PARAM_UINT16, + PARAM_UINT32 = GS_PARAM_UINT32, + PARAM_UINT64 = GS_PARAM_UINT64, + PARAM_INT8 = GS_PARAM_INT8, + PARAM_INT16 = GS_PARAM_INT16, + PARAM_INT32 = GS_PARAM_INT32, + PARAM_INT64 = GS_PARAM_INT64, + PARAM_DOUBLE = GS_PARAM_DOUBLE, + PARAM_FLOAT = GS_PARAM_FLOAT, + PARAM_STRING = GS_PARAM_STRING, + PARAM_DATA = GS_PARAM_DATA, + PARAM_BOOL = GS_PARAM_BOOL, +} gs_param_type_t; + +/** + Table row. + + A table row defines one parameter, and a table is defined by one or more rows. + + @note Make sure to update gs_param_table_checksum2(), if adding fields > 1 byte. + + @note AVR8: Table definitions must be located in \a program memory, i.e. must be const. +*/ +typedef struct __attribute__((__packed__)) { + /** + Address (or offset) in table. + */ + uint16_t addr; + /** + Type. + */ + gs_param_type_t type; + /** + Size of element. + uint32_t = 4, string[5] = 5 (4 characters + 1 for NUL), etc. + */ + uint8_t size; + /** + Array size. + Size greater than 1, will make the parameter an array - if the value is 0 or 1, the parameter is not an array. + */ + uint8_t array_size; + /** + Flags. + @see gs_param_flags_t + */ + uint8_t flags; + /** + Name (C string). + @note In some rare/old table definitions, the name may not be NUL terminated. + */ + char name[GS_PARAM_MAX_NAME]; +} gs_param_table_row_t; + +/** + Table instance. +*/ +typedef struct gs_param_table_instance gs_param_table_instance_t; + +/** + Table id. + + Tables can be associated with a number/id, which normally is unique on a specific node. +*/ +typedef uint8_t gs_param_table_id_t; + +/** + Undefined table id. +*/ +#define GS_PARAM_UNDEFINED_TABLE_ID 255 + +/** + Function for setting a parameter. + + @param[in] context user context/reference. + @param[in] tinst table instance. + @param[in] addr parameter address. + @param[in] type parameter type. + @param[in] item parameter value. + @param[in] size parameter size (e.g. how many bytes to copy from \a item). + @param[in] flags flags related to the operation - these may vary depending on the context. + @return_gs_error_t +*/ +typedef gs_error_t (*gs_param_table_function_set_t)(void * context, gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, const void * item, size_t size, uint32_t flags); + +/** + Function for getting a parameter. + + @param[in] context user context/reference. + @param[in] tinst table instance. + @param[in] addr parameter address. + @param[in] type parameter type. + @param[out] item parameter buffer (provided by the caller). + @param[in] size parameter size (e.g. how many bytes to copy to \a item). + @param[in] flags flags related to the operation - these may vary depending on the context. + @return_gs_error_t +*/ +typedef gs_error_t (*gs_param_table_function_get_t)(void * context, gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, void * item, size_t size, uint32_t flags); + +/** + Function interface for setting and getting parameters. + Functions will be invoked, when set/get is called on the table instance. +*/ +typedef struct { + /** + User context, provided in the callback functions. + */ + void * context; + /** + Called when setting a parameter. + */ + gs_param_table_function_set_t set; + /** + Called when getting a parameter. + */ + gs_param_table_function_get_t get; +} gs_param_function_interface_t; + +/** + Callback function for changed parameter. + See gs_param_table_create() for details. +*/ +typedef void (*gs_param_callback_func_t)(uint16_t addr, gs_param_table_instance_t * tinst); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libparam_client/src/bindings/python/pyparam.c b/gomspace/libparam_client/src/bindings/python/pyparam.c new file mode 100644 index 00000000..bbb35b7a --- /dev/null +++ b/gomspace/libparam_client/src/bindings/python/pyparam.c @@ -0,0 +1,1084 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +#include +#include + +#include +#include +#include +#include + +#if PY_MAJOR_VERSION == 3 +#define IS_PY3 +#endif + +static inline int to_int(char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'A' && c <= 'F') return 10 + c - 'A'; + if (c >= 'a' && c <= 'f') return 10 + c - 'a'; + return -1; +} + +/* static inline int rparam_get_string(char *out, int outlen, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_get_string(PyObject *self, PyObject *args) +{ + uint16_t addr; + uint16_t string_size; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "HHii|ii", &addr, &string_size, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + char buffer[string_size]; + memset(&buffer, 0, string_size); + int result = rparam_get_string(&buffer[0], string_size, addr, index_id, node, port, timeout); + return Py_BuildValue("is", result, buffer); +} + +/* static inline int rparam_set_string(char *in, int inlen, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_set_string(PyObject *self, PyObject *args) +{ + char* in; + int inlen; + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "siHii|ii", &in, &inlen, &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + return Py_BuildValue("i", rparam_set_string(in, inlen, addr, index_id, node, port, timeout)); +} + +/* static inline int rparam_get_string(char *out, int outlen, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_get_data(PyObject *self, PyObject *args) +{ + uint16_t addr; + uint16_t data_size; + int index_id; + int node; + int port = 7; + int timeout = 1000; + + if (!PyArg_ParseTuple(args, "HHii|ii", &addr, &data_size, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + char buffer[data_size]; + memset(&buffer, 0, data_size); + + //Reading as raw string: + int result = rparam_get_string(&buffer[0], data_size, addr, index_id, node, port, timeout); + + //Convert to string of HEX bytes + uint16_t bblen=2*data_size; + char bb[bblen+1]; + memset(bb,0, sizeof(bb)); + + char *bb_ptr = &bb[0]; + for (int i = 0; i < data_size; i++) { + sprintf(bb_ptr, "%02"PRIX8, ((uint8_t *) buffer)[i]); + bb_ptr+=2; + } + + return Py_BuildValue("is", result, bb); +} + +/* static inline int rparam_set_string(char *in, int inlen, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_set_data(PyObject *self, PyObject *args) +{ + char* in; + int inlen; + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + gs_error_t error = GS_OK; + + if (!PyArg_ParseTuple(args, "siHii|ii", &in, &inlen, &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + //inlen is number of bytes in DATA param in table, in reality the string will be twice as long, since it contains HEX-string... + // e.g., DEADBEEF00000000 is 16 characters but only corresponds to 8 bytes + char outbuffer[inlen]; + memset(outbuffer, 0, sizeof(outbuffer)); + + if ((inlen % 2) == 0) { + // validate data first - not to end up with invalid/strange data + for (int i = 0; i < inlen; ++i) { + if (to_int(in[i]) < 0) { + error = GS_ERROR_DATA; + break; + } + } + if (error == GS_OK) { + uint8_t * out = (uint8_t *) outbuffer; + for (int i = 0; i < inlen; i += 2, ++out) { + *out = (16 * to_int(in[i])) + to_int(in[i+1]); + } + error = GS_OK; + } + } else { + error = GS_ERROR_DATA; + } + + if (error != GS_OK) { + return Py_BuildValue("i", error); + } else { + return Py_BuildValue("i", rparam_set_string(outbuffer, inlen, addr, index_id, node, port, timeout)); + } +} + +/* static inline int rparam_get_uint8(uint8_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_get_uint8(PyObject *self, PyObject *args) +{ + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + uint8_t value; + int result = rparam_get_uint8(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("iB", result, value); +} + +/* static inline int rparam_set_uint8(uint8_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_set_uint8(PyObject *self, PyObject *args) +{ + uint8_t value; + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "BHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + int result = rparam_set_uint8(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("i", result); +} + +/* static inline int rparam_get_uint16(uint16_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_get_uint16(PyObject *self, PyObject *args) +{ + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + uint16_t value; + int result = rparam_get_uint16(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("iH", result, value); +} + +/* static inline int rparam_set_uint16(uint16_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_set_uint16(PyObject *self, PyObject *args) +{ + uint16_t value; + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "HHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + int result = rparam_set_uint16(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("i", result); +} + +/* static inline int rparam_get_uint32(uint32_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_get_uint32(PyObject *self, PyObject *args) +{ + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + uint32_t value; + int result = rparam_get_uint32(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("iI", result, value); +} + +/* static inline int rparam_set_uint32(uint32_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_set_uint32(PyObject *self, PyObject *args) +{ + uint32_t value; + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "IHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + int result = rparam_set_uint32(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("i", result); +} + +/* static inline int rparam_get_uint64(uint64_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_get_uint64(PyObject *self, PyObject *args) +{ + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + uint64_t value; + int result = rparam_get_uint64(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("iK", result, value); +} + +/* static inline int rparam_set_uint64(uint64_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_set_uint64(PyObject *self, PyObject *args) +{ + uint64_t value; + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "KHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + int result = rparam_set_uint64(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("i", result); +} + +/* static inline int rparam_get_int8(int8_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_get_int8(PyObject *self, PyObject *args) +{ + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + int8_t value; + int result = rparam_get_int8(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("hb", result, value); +} + +/* static inline int rparam_set_int8(int8_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_set_int8(PyObject *self, PyObject *args) +{ + int8_t value; + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "bHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + int result = rparam_set_int8(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("i", result); +} + +/* static inline int rparam_get_int16(int16_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_get_int16(PyObject *self, PyObject *args) +{ + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + int16_t value; + int result = rparam_get_int16(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("ih", result, value); +} + +/* static inline int rparam_set_int16(int16_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_set_int16(PyObject *self, PyObject *args) +{ + int16_t value; + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "hHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + int result = rparam_set_int16(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("i", result); +} + +/* static inline int rparam_get_int32(int32_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_get_int32(PyObject *self, PyObject *args) +{ + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + int32_t value; + int result = rparam_get_int32(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("il", result, value); +} + +/* static inline int rparam_set_int32(int32_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_set_int32(PyObject *self, PyObject *args) +{ + int32_t value; + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "lHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + int result = rparam_set_int32(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("i", result); +} + +/* static inline int rparam_get_int64(int64_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_get_int64(PyObject *self, PyObject *args) +{ + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + int64_t value; + int result = rparam_get_int64(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("iL", result, value); +} + +/* static inline int rparam_set_int64(int64_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_set_int64(PyObject *self, PyObject *args) +{ + int64_t value; + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "LHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + int result = rparam_set_int64(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("i", result); +} + +/* static inline int rparam_get_float(float * out, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_get_float(PyObject *self, PyObject *args) +{ + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + float value; + int result = rparam_get_float(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("if", result, value); +} + +/* static inline int rparam_set_float(float * in, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_set_float(PyObject *self, PyObject *args) +{ + float value; + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "fHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + int result = rparam_set_float(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("i", result); +} + +/* static inline int rparam_get_double(double * out, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_get_double(PyObject *self, PyObject *args) +{ + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + double value; + int result = rparam_get_double(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("id", result, value); +} + +/* static inline int rparam_set_double(double * in, uint16_t addr, int index_id, int node, int port, int timeout) */ +static PyObject* pyrparam_set_double(PyObject *self, PyObject *args) +{ + double value; + uint16_t addr; + int index_id; + int node; + int port = 7; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "dHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { + Py_RETURN_NONE; + } + + int result = rparam_set_double(&value, addr, index_id, node, port, timeout); + return Py_BuildValue("i", result); +} + +/*gs_error_t gs_rparam_save_to_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id, + const char * store, const char * slot)*/ +static PyObject* pyrparam_save_to_store(PyObject *self, PyObject *args) +{ + uint8_t table_id; + char* store; + int node; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "Bsi|i", &table_id, &store, &node, &timeout)) { + Py_RETURN_NONE; + } + + int result = gs_rparam_save_to_store(node, timeout, table_id, store, NULL); + return Py_BuildValue("i", result); +} +/*gs_error_t gs_rparam_load_from_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id, + const char * store, const char * slot)*/ +static PyObject* pyrparam_load_from_store(PyObject *self, PyObject *args) +{ + uint8_t table_id; + char* store; + int node; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "Bsi|i", &table_id, &store, &node, &timeout)) { + Py_RETURN_NONE; + } + + int result = gs_rparam_load_from_store(node, timeout, table_id, store, NULL); + return Py_BuildValue("i", result); +} + +/*gs_error_t gs_rparam_save(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to) */ +static PyObject* pyrparam_save(PyObject *self, PyObject *args) +{ + uint8_t table_id; + uint8_t file_id; + int node; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "BBi|i", &table_id, &file_id, &node, &timeout)) { + Py_RETURN_NONE; + } + + int result = gs_rparam_save(node, timeout, table_id, file_id); + return Py_BuildValue("i", result); +} + +/*gs_error_t gs_rparam_load(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to) */ +static PyObject* pyrparam_load(PyObject *self, PyObject *args) +{ + uint8_t table_id; + uint8_t file_id; + int node; + int timeout = 1000; + if (!PyArg_ParseTuple(args, "BBi|i", &file_id, &table_id, &node, &timeout)) { + Py_RETURN_NONE; + } + + int result = gs_rparam_load(node, timeout, file_id, table_id); + return Py_BuildValue("i", result); +} + +/*int rparam_download_table_spec_from_remote_and_save_to_file2(const char* fname, uint8_t node, uint8_t port, param_index_t* index, uint16_t* checksum, uint32_t timeout);*/ +static PyObject* pyrparam_download_table_spec_from_remote_and_save_to_file2(PyObject *self, PyObject *args) +{ + char* fname; + int fname_len; + int mem_id; + int node; + int port; + uint16_t checksum; + int timeout; + if (!PyArg_ParseTuple(args, "s#iiiHi", &fname, &fname_len, &node, &port, &mem_id, &checksum, &timeout)) { + Py_RETURN_NONE; + } + + GS_PARAM_TINST_VAR(tinst); + int result = gs_rparam_download_table_spec(tinst, fname, node, mem_id, timeout, &checksum); + gs_param_table_free(tinst); // free allocated resources by gs_rparam_download_table_spec() + return Py_BuildValue("i", result); +} + +/* gs_error_t gs_param_io_i2c_init(gs_param_io_t * io, uint8_t bus, uint8_t addr, bool big_endian); */ + +static PyObject* pyioparam_i2c_init(PyObject *self, PyObject *args) +{ + uint8_t bus; + uint8_t addr; + uint8_t big_endian; + if (!PyArg_ParseTuple(args, "BBB", &bus, &addr, &big_endian)) { + Py_RETURN_NONE; + } + gs_pp_t* io = malloc(sizeof(gs_pp_t)); + gs_error_t error = gs_pp_i2c_init(io, bus, addr, big_endian); + return Py_BuildValue("iO", error, PyCapsule_New(io, "gs_pp_t", NULL)); +} + +static PyObject* pyioparam_io_free(PyObject *self, PyObject *args) +{ + PyObject *io_capsule; + if (!PyArg_ParseTuple(args, "O", &io_capsule)) { + Py_RETURN_NONE; + } + free(PyCapsule_GetPointer(io_capsule, "gs_pp_t")); + Py_RETURN_NONE; +} + +/* +gs_error_t gs_pp_get_int8( + gs_pp_t * io, + uint8_t table_id, + uint8_t addr, + int8_t * value, + size_t count, + uint32_t flags); +*/ +static PyObject* pyioparam_io_get_int8(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint8_t addr; + int8_t value; + if (!PyArg_ParseTuple(args, "OBB", &io_capsule, &table_id, &addr)) { + Py_RETURN_NONE; + } + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_get_int8(tmp, table_id, addr, &value, 1, 0); + if (error) { + value = 0; + } + return Py_BuildValue("ib", error, value); +} + +/* +gs_error_t gs_pp_set_int8( + gs_pp_t * io, + uint8_t table_id, + uint8_t addr, + const int8_t * value, + size_t count, + uint32_t flags); +*/ +static PyObject* pyioparam_io_set_int8(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint8_t addr; + int8_t value; + if (!PyArg_ParseTuple(args, "ObBB", &io_capsule, &value, &table_id, &addr)) { + Py_RETURN_NONE; + } + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_set_int8(tmp, table_id, addr, &value, 1, 0); + return Py_BuildValue("i", error); +} + +/* +gs_error_t gs_pp_get_uint8( + gs_pp_t * io, + uint8_t table_id, + uint8_t addr, + uint8_t * value, + size_t count, + uint32_t flags); +*/ +static PyObject* pyioparam_io_get_uint8(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint8_t addr; + uint8_t value; + if (!PyArg_ParseTuple(args, "OBB", &io_capsule, &table_id, &addr)) { + Py_RETURN_NONE; + } + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_get_uint8(tmp, table_id, addr, &value, 1, 0); + if (error) { + value = 0; + } + return Py_BuildValue("iB", error, value); +} + +/* +gs_error_t gs_pp_set_uint8( + gs_pp_t * io, + uint8_t table_id, + uint8_t addr, + const uint8_t * value, + size_t count, + uint32_t flags); +*/ +static PyObject* pyioparam_io_set_uint8(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint8_t addr; + uint8_t value; + if (!PyArg_ParseTuple(args, "OBBB", &io_capsule, &value, &table_id, &addr)) { + Py_RETURN_NONE; + } + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_set_uint8(tmp, table_id, addr, &value, 1, 0); + return Py_BuildValue("i", error); +} + +/* +gs_error_t gs_pp_get_int16( + gs_pp_t * io, + uint8_t table_id, + uint8_t addr, + int16_t * value, + size_t count, + uint32_t flags); +*/ +static PyObject* pyioparam_io_get_int16(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint8_t addr; + int16_t value; + if (!PyArg_ParseTuple(args, "OBB", &io_capsule, &table_id, &addr)) { + Py_RETURN_NONE; + } + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_get_int16(tmp, table_id, addr, &value, 1, 0); + if (error) { + value = 0; + } + return Py_BuildValue("ih", error, value); +} + +/* +gs_error_t gs_pp_set_int16( + gs_pp_t * io, + uint8_t table_id, + uint8_t addr, + const int16_t * value, + size_t count, + uint32_t flags); +*/ +static PyObject* pyioparam_io_set_int16(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint8_t addr; + int16_t value; + if (!PyArg_ParseTuple(args, "OhBB", &io_capsule, &value, &table_id, &addr)) { + Py_RETURN_NONE; + } + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_set_int16(tmp, table_id, addr, &value, 1, 0); + return Py_BuildValue("i", error); +} + +/* +gs_error_t gs_pp_get_uint16( + gs_pp_t * io, + uint8_t table_id, + uint8_t addr, + uint16_t * value, + size_t count, + uint32_t flags); +*/ +static PyObject* pyioparam_io_get_uint16(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint8_t addr; + uint16_t value; + if (!PyArg_ParseTuple(args, "OBB", &io_capsule, &table_id, &addr)) { + Py_RETURN_NONE; + } + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_get_uint16(tmp, table_id, addr, &value, 1, 0); + if (error) { + value = 0; + } + return Py_BuildValue("iH", error, value); +} + +/* +gs_error_t gs_pp_set_uint16( + gs_pp_t * io, + uint8_t table_id, + uint8_t addr, + const uint16_t * value, + size_t count, + uint32_t flags); +*/ +static PyObject* pyioparam_io_set_uint16(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint8_t addr; + uint16_t value; + if (!PyArg_ParseTuple(args, "OHBB", &io_capsule, &value, &table_id, &addr)) { + Py_RETURN_NONE; + } + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_set_uint16(tmp, table_id, addr, &value, 1, 0); + return Py_BuildValue("i", error); +} + +/* +gs_error_t gs_pp_get_int32( + gs_pp_t * io, + uint8_t table_id, + uint8_t addr, + int32_t * value, + size_t count, + uint32_t flags); +*/ +static PyObject* pyioparam_io_get_int32(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint8_t addr; + int32_t value; + if (!PyArg_ParseTuple(args, "OBB", &io_capsule, &table_id, &addr)) { + Py_RETURN_NONE; + } + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_get_int32(tmp, table_id, addr, &value, 1, 0); + if (error) { + value = 0; + } + return Py_BuildValue("ii", error, value); +} + +/* +gs_error_t gs_pp_set_int32( + gs_pp_t * io, + uint8_t table_id, + uint8_t addr, + const int32_t * value, + size_t count, + uint32_t flags); +*/ +static PyObject* pyioparam_io_set_int32(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint8_t addr; + int32_t value; + if (!PyArg_ParseTuple(args, "OiBB", &io_capsule, &value, &table_id, &addr)) { + Py_RETURN_NONE; + } + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_set_int32(tmp, table_id, addr, &value, 1, 0); + return Py_BuildValue("i", error); +} + +/* +gs_error_t gs_pp_get_uint32( + gs_pp_t * io, + uint8_t table_id, + uint8_t addr, + uint32_t * value, + size_t count, + uint32_t flags); +*/ +static PyObject* pyioparam_io_get_uint32(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint8_t addr; + uint32_t value; + if (!PyArg_ParseTuple(args, "OBB", &io_capsule, &table_id, &addr)) { + Py_RETURN_NONE; + } + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_get_uint32(tmp, table_id, addr, &value, 1, 0); + if (error) { + value = 0; + } + return Py_BuildValue("iI", error, value); +} +/* +gs_error_t gs_pp_set_uint32( + gs_pp_t * io, + uint8_t table_id, + uint8_t addr, + const uint32_t * value, + size_t count, + uint32_t flags); +*/ + +static PyObject* pyioparam_io_set_uint32(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint8_t addr; + uint32_t value; + if (!PyArg_ParseTuple(args, "OIBB", &io_capsule, &value, &table_id, &addr)) { + Py_RETURN_NONE; + } + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_set_uint32(tmp, table_id, addr, &value, 1, 0); + return Py_BuildValue("i", error); +} +/* +gs_error_t gs_pp_get_float( + gs_pp_t * io, + uint8_t table_id, + uint8_t addr, + float * value, + size_t count, + uint32_t flags); +*/ +static PyObject* pyioparam_io_get_float(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint8_t addr; + float value; + if (!PyArg_ParseTuple(args, "OBB", &io_capsule, &table_id, &addr)) { + Py_RETURN_NONE; + } + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_get_float(tmp, table_id, addr, &value, 1, 0); + if (error) { + value = 0; + } + return Py_BuildValue("if", error, value); +} + +/* +gs_error_t gs_pp_set_float( + gs_pp_t * io, + uint8_t table_id, + uint8_t addr, + const float * value, + size_t count, + uint32_t flags); +*/ +static PyObject* pyioparam_io_set_float(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint8_t addr; + float value; + if (!PyArg_ParseTuple(args, "OfBB", &io_capsule, &value, &table_id, &addr)) { + Py_RETURN_NONE; + } + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_set_float(tmp, table_id, addr, &value, 1, 0); + return Py_BuildValue("i", error); +} + +static PyObject* pyioparam_spi_init(PyObject* self, PyObject* args) +{ + uint8_t addr; + uint8_t big_endian; + if (!PyArg_ParseTuple(args, "BB", &addr, &big_endian)) { + Py_RETURN_NONE; + } + gs_pp_t* io = malloc(sizeof(gs_pp_t)); + gs_error_t error = gs_pp_spi_init(io, addr, big_endian); + return Py_BuildValue("iO", error, PyCapsule_New(io, "gs_pp_t", NULL)); +} + +/** + Get lock value + + @param[in] pp Handle for connection + @param[in] table_id Table ID + @param[out] value Lock state (0 = unlocked, 1 = locked) + @param[in] flags + @return_gs_error_t +gs_error_t gs_pp_get_table_lock(gs_pp_t * pp, uint8_t table_id, bool * value, uint32_t flags); +*/ + +static PyObject* pyioparam_get_table_lock(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint32_t flags = 0; + if (!PyArg_ParseTuple(args, "OB|I", &io_capsule, &table_id, &flags)) { + Py_RETURN_NONE; + } + bool result; + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_get_table_lock(tmp, table_id, &result, flags); + + uint8_t retval = result ? 1 : 0; + return Py_BuildValue("iB", error, retval); +} +/** + Set lock value + + @param[in] pp Handle for connection + @param[in] table_id Table ID + @param[in] value Lock state (0 = unlocked, 1 = locked) + @param[in] flags + @return_gs_error_t + + gs_error_t gs_pp_set_table_lock(gs_pp_t * pp, uint8_t table_id, const bool * value, uint32_t flags); + */ + +static PyObject* pyioparam_set_table_lock(PyObject* self, PyObject* args) +{ + PyObject* io_capsule; + uint8_t table_id; + uint32_t flags = 0; + uint8_t status; + if (!PyArg_ParseTuple(args, "OBB|I", &io_capsule, &table_id, &status, &flags)) { + Py_RETURN_NONE; + } + bool setval = status ? true : false; + gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); + gs_error_t error = gs_pp_set_table_lock(tmp, table_id, &setval, flags); + return Py_BuildValue("i", error); +} +static PyMethodDef methods[] = { + + /* param/rparam_client.h */ + {"rparam_get_string", pyrparam_get_string, METH_VARARGS, ""}, + {"rparam_set_string", pyrparam_set_string, METH_VARARGS, ""}, + + {"rparam_get_float", pyrparam_get_float, METH_VARARGS, ""}, + {"rparam_set_float", pyrparam_set_float, METH_VARARGS, ""}, + {"rparam_get_double", pyrparam_get_double, METH_VARARGS, ""}, + {"rparam_set_double", pyrparam_set_double, METH_VARARGS, ""}, + + {"rparam_get_uint8", pyrparam_get_uint8, METH_VARARGS, ""}, + {"rparam_set_uint8", pyrparam_set_uint8, METH_VARARGS, ""}, + {"rparam_get_uint16", pyrparam_get_uint16, METH_VARARGS, ""}, + {"rparam_set_uint16", pyrparam_set_uint16, METH_VARARGS, ""}, + {"rparam_get_uint32", pyrparam_get_uint32, METH_VARARGS, ""}, + {"rparam_set_uint32", pyrparam_set_uint32, METH_VARARGS, ""}, + {"rparam_get_uint64", pyrparam_get_uint64, METH_VARARGS, ""}, + {"rparam_set_uint64", pyrparam_set_uint64, METH_VARARGS, ""}, + + {"rparam_get_int8", pyrparam_get_int8, METH_VARARGS, ""}, + {"rparam_set_int8", pyrparam_set_int8, METH_VARARGS, ""}, + {"rparam_get_int16", pyrparam_get_int16, METH_VARARGS, ""}, + {"rparam_set_int16", pyrparam_set_int16, METH_VARARGS, ""}, + {"rparam_get_int32", pyrparam_get_int32, METH_VARARGS, ""}, + {"rparam_set_int32", pyrparam_set_int32, METH_VARARGS, ""}, + {"rparam_get_int64", pyrparam_get_int64, METH_VARARGS, ""}, + {"rparam_set_int64", pyrparam_set_int64, METH_VARARGS, ""}, + + {"rparam_get_data", pyrparam_get_data, METH_VARARGS, ""}, + {"rparam_set_data", pyrparam_set_data, METH_VARARGS, ""}, + + {"rparam_save_to_store", pyrparam_save_to_store, METH_VARARGS, "" }, + {"rparam_load_from_store", pyrparam_load_from_store, METH_VARARGS, "" }, + {"rparam_save", pyrparam_save, METH_VARARGS, "" }, + {"rparam_load", pyrparam_load, METH_VARARGS, "" }, + + {"rparam_download_table_spec_from_remote_and_save_to_file2", pyrparam_download_table_spec_from_remote_and_save_to_file2, METH_VARARGS, ""}, + + + /* param/rparam_client.h */ + {"pp_i2c_init", pyioparam_i2c_init, METH_VARARGS, ""}, + {"pp_spi_init", pyioparam_spi_init, METH_VARARGS, ""}, + {"pp_get_int8", pyioparam_io_get_int8, METH_VARARGS, ""}, + {"pp_get_uint8", pyioparam_io_get_uint8, METH_VARARGS, ""}, + {"pp_set_int8", pyioparam_io_set_int8, METH_VARARGS, ""}, + {"pp_set_uint8", pyioparam_io_set_uint8, METH_VARARGS, ""}, + {"pp_get_int16", pyioparam_io_get_int16, METH_VARARGS, ""}, + {"pp_get_uint16", pyioparam_io_get_uint16, METH_VARARGS, ""}, + {"pp_set_int16", pyioparam_io_set_int16, METH_VARARGS, ""}, + {"pp_set_uint16", pyioparam_io_set_uint16, METH_VARARGS, ""}, + {"pp_get_int32", pyioparam_io_get_int32, METH_VARARGS, ""}, + {"pp_get_uint32", pyioparam_io_get_uint32, METH_VARARGS, ""}, + {"pp_set_int32", pyioparam_io_set_int32, METH_VARARGS, ""}, + {"pp_set_uint32", pyioparam_io_set_uint32, METH_VARARGS, ""}, + {"pp_get_float", pyioparam_io_get_float, METH_VARARGS, ""}, + {"pp_set_float", pyioparam_io_set_float, METH_VARARGS, ""}, + {"pp_io_free", pyioparam_io_free, METH_VARARGS, ""}, + {"pp_get_table_lock", pyioparam_get_table_lock, METH_VARARGS, ""}, + {"pp_set_table_lock", pyioparam_set_table_lock, METH_VARARGS, ""}, + + /* sentinel */ + {NULL, NULL, 0, NULL} +}; + +#ifdef IS_PY3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "libgsparam_client_py3", + NULL, /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ + methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +#ifdef IS_PY3 +PyMODINIT_FUNC PyInit_libgsparam_client_py3(void) { +#else +PyMODINIT_FUNC initlibgsparam_client_py2(void) +{ +#endif + +#ifdef IS_PY3 + PyObject* m = PyModule_Create(&moduledef); +#else + Py_InitModule("libgsparam_client_py2", methods); +#endif + +#ifdef IS_PY3 + return m; +#endif +} diff --git a/gomspace/libparam_client/src/pp/cmd/master_cmd.c b/gomspace/libparam_client/src/pp/cmd/master_cmd.c new file mode 100644 index 00000000..404f5472 --- /dev/null +++ b/gomspace/libparam_client/src/pp/cmd/master_cmd.c @@ -0,0 +1,418 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include +#include + +static bool use_checksum; + +static gs_pp_t gs_pp; + +static int cmd_spi_init(gs_command_context_t *ctx) +{ + uint8_t slave; + gs_error_t error = gs_string_to_uint8(ctx->argv[1], &slave); + if (error) { + return error; + } + + bool big_endian = false; + if (ctx->argc > 2) { + error = gs_string_to_bool(ctx->argv[2], &big_endian); + if (error) { + return error; + } + } + + error = gs_pp_spi_init(&gs_pp, slave, big_endian); + if (error) { + memset(&gs_pp, 0, sizeof(gs_pp)); + return error; + } + + return GS_OK; +} + +static int cmd_i2c_init(gs_command_context_t *ctx) +{ + uint8_t bus; + gs_error_t error = gs_string_to_uint8(ctx->argv[1], &bus); + if (error) { + return GS_ERROR_ARG; + } + + uint8_t addr; + error = gs_string_to_uint8(ctx->argv[2], &addr); + if (error) { + return GS_ERROR_ARG; + } + + bool big_endian = false; + if (ctx->argc > 3) { + error = gs_string_to_bool(ctx->argv[3], &big_endian); + if (error) { + return GS_ERROR_ARG; + } + } + + error = gs_pp_i2c_init(&gs_pp, bus, addr, big_endian); + if (error) { + memset(&gs_pp, 0, sizeof(gs_pp)); + return error; + } + + return GS_OK; +} + +static int cmd_checksum(gs_command_context_t *ctx) +{ + if (ctx->argc > 1) { + if (gs_string_to_bool(ctx->argv[1], &use_checksum)) { + return GS_ERROR_ARG; + } + } + printf("Use CHECKSUM: %d\r\n", use_checksum); + return GS_OK; +} + +// get_xxxx +static int cmd_parse(gs_command_context_t *ctx, + uint32_t * table, uint32_t * addr) +{ + if (ctx->argc < 3) { + return GS_ERROR_ARG; + } + + gs_error_t error = gs_string_to_uint32(ctx->argv[1], table); + if (error || (*table > 7)) { + return GS_ERROR_ARG; + } + + error = gs_string_to_uint32(ctx->argv[2], addr); + if (error || (*addr > 255)) { + return GS_ERROR_ARG; + } + + return GS_OK; +} + +static int cmd_get_parse(gs_command_context_t * ctx, + uint32_t * table, uint32_t * addr, uint32_t * count) +{ + int res = cmd_parse(ctx, table, addr); + if (res == GS_OK) { + *count = 1; + if (ctx->argc > 3) { + gs_error_t error = gs_string_to_uint32(ctx->argv[3], count); + if (error || (*count > 100)) { + return GS_ERROR_ARG; + } + } + } + + return res; +} + +#define CMD_GET(_ctx, _type, _func, _format) \ + { \ + uint32_t table; \ + uint32_t addr; \ + uint32_t count; \ + int res = cmd_get_parse(_ctx, &table, &addr, &count); \ + if (res == GS_OK) { \ + _type value[count]; \ + gs_error_t error = _func(&gs_pp, table, addr, value, count, use_checksum ? GS_PP_FLAG_CHECKSUM : 0); \ + if (error) { \ + return error; \ + } \ + printf("value(s): "); \ + for (unsigned int i = 0; i < count; ++i) { \ + printf("%" _format " ", value[i]); \ + } \ + printf("\r\n"); \ + } \ + return res; \ + } + +static int cmd_get_int8(gs_command_context_t * ctx) +{ + CMD_GET(ctx, int8_t, gs_pp_get_int8, PRId8); +} + +static int cmd_get_int16(gs_command_context_t * ctx) +{ + CMD_GET(ctx, int16_t, gs_pp_get_int16, PRId16); +} + +static int cmd_get_int32(gs_command_context_t * ctx) +{ + CMD_GET(ctx, int32_t, gs_pp_get_int32, PRId32); +} + +static int cmd_get_uint8(gs_command_context_t * ctx) +{ + CMD_GET(ctx, uint8_t, gs_pp_get_uint8, PRIu8); +} + +static int cmd_get_uint16(gs_command_context_t * ctx) +{ + CMD_GET(ctx, uint16_t, gs_pp_get_uint16, PRIu16); +} + +static int cmd_get_uint32(gs_command_context_t * ctx) +{ + CMD_GET(ctx, uint32_t, gs_pp_get_uint32, PRIu32); +} + +static int cmd_get_float(gs_command_context_t * ctx) +{ + CMD_GET(ctx, float, gs_pp_get_float, "f"); +} + +#define CMD_SET(_ctx, _type, _func, _convert) \ + { \ + const unsigned int MAX_VALUES = 20; \ + uint32_t table; \ + uint32_t addr; \ + int res = cmd_parse(_ctx, &table, &addr); \ + if (res == GS_OK) { \ + _type value[MAX_VALUES]; \ + unsigned int count = 0; \ + for (int i = 3; (i < _ctx->argc) && (count < MAX_VALUES); ++i, ++count) { \ + res = _convert(_ctx->argv[i], &value[count]); \ + if (res) { \ + return GS_ERROR_DATA; \ + } \ + } \ + res = _func(&gs_pp, table, addr, value, count, use_checksum ? GS_PP_FLAG_CHECKSUM : 0); \ + } \ + return res; \ + } + +static int cmd_set_int8(gs_command_context_t * ctx) +{ + CMD_SET(ctx, int8_t, gs_pp_set_int8, gs_string_to_int8); +} + +static int cmd_set_int16(gs_command_context_t * ctx) +{ + CMD_SET(ctx, int16_t, gs_pp_set_int16, gs_string_to_int16); +} + +static int cmd_set_int32(gs_command_context_t * ctx) +{ + CMD_SET(ctx, int32_t, gs_pp_set_int32, gs_string_to_int32); +} + +static int cmd_set_uint8(gs_command_context_t * ctx) +{ + CMD_SET(ctx, uint8_t, gs_pp_set_uint8, gs_string_to_uint8); +} + +static int cmd_set_uint16(gs_command_context_t * ctx) +{ + CMD_SET(ctx, uint16_t, gs_pp_set_uint16, gs_string_to_uint16); +} + +static int cmd_set_uint32(gs_command_context_t * ctx) +{ + CMD_SET(ctx, uint32_t, gs_pp_set_uint32, gs_string_to_uint32); +} + +static int cmd_set_float(gs_command_context_t * ctx) +{ + CMD_SET(ctx, float, gs_pp_set_float, gs_string_to_float); +} + +static int cmd_get_table_lock(gs_command_context_t * ctx) +{ + uint32_t table; + gs_error_t res = gs_string_to_uint32(ctx->argv[1], &table); + if (res == GS_OK) { + if (table <= 7) { + bool lock; + res = gs_pp_get_table_lock(&gs_pp, table, &lock, GS_PP_FLAG_CHECKSUM); + if (res == GS_OK) { + const char locked[] = "locked\n"; + const char unlocked[] = "unlocked\n"; + const char * lock_state = (lock) ? locked : unlocked; + printf("Table %s", lock_state); + } + } else { + res = GS_ERROR_ARG; + } + } + return res; +} + +static int cmd_set_table_lock(gs_command_context_t * ctx) +{ + uint32_t table; + gs_error_t res = gs_string_to_uint32(ctx->argv[1], &table); + if (res == GS_OK) { + if (table <= 7) { + uint32_t lock; + res = gs_string_to_uint32(ctx->argv[2], &lock); + if (res == GS_OK) { + if(lock <= 1) { + res = gs_pp_set_table_lock(&gs_pp, table, (bool *)&lock, GS_PP_FLAG_CHECKSUM); + } else { + res = GS_ERROR_ARG; + } + } + } else { + res = GS_ERROR_ARG; + } + } + return res; +} + +static const gs_command_t gs_param_cmd_master_pp_sub[] = { + { + .name = "spi_init", + .help = "Initialize/setup SPI device", + .usage = " [big_endian]", + .handler = cmd_spi_init, + .mandatory_args = 1, + .optional_args = 1, + },{ + .name = "i2c_init", + .help = "Initialize/setup I2C device", + .usage = " [big_endian]", + .handler = cmd_i2c_init, + .mandatory_args = 2, + .optional_args = 1, + },{ + .name = "checksum", + .help = "Enable/disable checksum", + .usage = "[0|1]", + .handler = cmd_checksum, + .optional_args = 1, + },{ + .name = "get_table_lock", + .help = "Get table lock (0 = unlocked, 1 = locked)", + .usage = "
", + .mandatory_args = 1, + .handler = cmd_get_table_lock, + },{ + .name = "set_table_lock", + .help = "Set table lock (0 = unlocked, 1 = locked)", + .usage = "
", + .mandatory_args = 2, + .handler = cmd_set_table_lock, + },{ + .name = "get_int8", + .help = "Get int8", + .usage = "
[count]", + .handler = cmd_get_int8, + .mandatory_args = 2, + .optional_args = 1, + },{ + .name = "get_int16", + .help = "Get int16", + .usage = "
[count]", + .handler = cmd_get_int16, + .mandatory_args = 2, + .optional_args = 1, + },{ + .name = "get_int32", + .help = "Get int32", + .usage = "
[count]", + .handler = cmd_get_int32, + .mandatory_args = 2, + .optional_args = 1, + },{ + .name = "get_uint8", + .help = "Get uint8", + .usage = "
[count]", + .handler = cmd_get_uint8, + .mandatory_args = 2, + .optional_args = 1, + },{ + .name = "get_uint16", + .help = "Get uint16", + .usage = "
[count]", + .handler = cmd_get_uint16, + .mandatory_args = 2, + .optional_args = 1, + },{ + .name = "get_uint32", + .help = "Get uint32", + .usage = "
[count]", + .handler = cmd_get_uint32, + .mandatory_args = 2, + .optional_args = 1, + },{ + .name = "get_float", + .help = "Get float", + .usage = "
[count]", + .handler = cmd_get_float, + .mandatory_args = 2, + .optional_args = 1, + },{ + .name = "set_int8", + .help = "Set int8", + .usage = "
[data] ...", + .handler = cmd_set_int8, + .mandatory_args = 3, + .optional_args = 20, + },{ + .name = "set_int16", + .help = "Set int16", + .usage = "
[data] ...", + .handler = cmd_set_int16, + .mandatory_args = 3, + .optional_args = 20, + },{ + .name = "set_int32", + .help = "Set int32", + .usage = "
[data] ...", + .handler = cmd_set_int32, + .mandatory_args = 3, + .optional_args = 20, + },{ + .name = "set_uint8", + .help = "Set uint8", + .usage = "
[data] ...", + .handler = cmd_set_uint8, + .mandatory_args = 3, + .optional_args = 20, + },{ + .name = "set_uint16", + .help = "Set uint16", + .usage = "
[data] ...", + .handler = cmd_set_uint16, + .mandatory_args = 3, + .optional_args = 20, + },{ + .name = "set_uint32", + .help = "Set uint32", + .usage = "
[data] ...", + .handler = cmd_set_uint32, + .mandatory_args = 3, + .optional_args = 20, + },{ + .name = "set_float", + .help = "Set float", + .usage = "
[data] ...", + .handler = cmd_set_float, + .mandatory_args = 3, + .optional_args = 20, + } +}; + +static const gs_command_t GS_COMMAND_ROOT gs_param_cmd_master_pp[] = { + { + .name = "pp", + .help = "Param Protocol interface", + .chain = GS_COMMAND_INIT_CHAIN(gs_param_cmd_master_pp_sub), + } +}; + +gs_error_t gs_pp_register_commands(void) +{ + return GS_COMMAND_REGISTER(gs_param_cmd_master_pp); +} diff --git a/gomspace/libparam_client/src/pp/i2c/i2c.c b/gomspace/libparam_client/src/pp/i2c/i2c.c new file mode 100644 index 00000000..912bbeb5 --- /dev/null +++ b/gomspace/libparam_client/src/pp/i2c/i2c.c @@ -0,0 +1,129 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#define GS_PARAM_INTERNAL_USE 1 + +#include +#include +#include +#include +#include + +static gs_error_t gs_pp_i2c_write(gs_param_i2c_command_t cmd, gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, bool checksum) +{ + GS_CHECK_RANGE(table_id <= 7); + GS_CHECK_RANGE(addr <= 255); + GS_CHECK_RANGE((value_size > 0) && (value_size <= 31)); + + gs_param_i2c_set_request_t * request; + const size_t size = (sizeof(*request) + value_size + (checksum ? 1 : 0)); + request = alloca(size); + + request->header.domain_command = GS_I2C_SLAVE_DISPATCH_HEADER(GS_I2C_SLAVE_DISPATCH_DOMAIN_PARAM, cmd); + request->length_table = GS_PARAM_I2C_LENGTH_TABLE(value_size, table_id); + request->addr = addr; + memcpy(request->data, value, value_size); + + if (checksum) { + request->data[value_size] = gs_pp_checksum8(request, size - 1); + } + return gs_i2c_master_transaction(pp->pp.i2c.bus, pp->pp.i2c.addr, request, size, NULL, 0, 1000); + +} + +static gs_error_t gs_pp_i2c_read(gs_param_i2c_command_t cmd, gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, bool checksum) +{ + GS_CHECK_RANGE(table_id <= 7); + GS_CHECK_RANGE(addr <= 255); + GS_CHECK_RANGE((value_size > 0) && (value_size <= 31)); + + gs_param_i2c_get_request_t request; + memset(&request, 0, sizeof(request)); + request.length_table = GS_PARAM_I2C_LENGTH_TABLE(value_size, table_id); + request.addr = addr; + size_t request_size; + + uint8_t reply[value_size + sizeof(request.checksum)]; // + for checksum + memset(reply, 0, sizeof(reply)); + size_t reply_size; + + request.header.domain_command = GS_I2C_SLAVE_DISPATCH_HEADER(GS_I2C_SLAVE_DISPATCH_DOMAIN_PARAM, cmd); + + if (checksum) { + request.checksum = gs_pp_checksum8(&request, (sizeof(request) - sizeof(request.checksum))); + request_size = sizeof(request); + reply_size = sizeof(reply); + } else { + request_size = sizeof(request) - sizeof(request.checksum); + reply_size = sizeof(reply) - sizeof(request.checksum); + } + + gs_error_t error = gs_i2c_master_transaction(pp->pp.i2c.bus, pp->pp.i2c.addr, &request, request_size, reply, reply_size, 1000); + if (error == GS_OK) { + if (checksum) { + if (gs_pp_checksum8(reply, value_size) != reply[value_size]) { + return GS_ERROR_DATA; + } + } + memcpy(value, reply, value_size); + } + return error; + +} + +static gs_error_t gs_pp_i2c_get(gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, uint32_t flags) +{ + gs_param_i2c_command_t cmd; + bool checksum = false; + if (flags & GS_PP_FLAG_CHECKSUM) { + checksum = true; + cmd = GS_PARAM_I2C_COMMAND_GET_WITH_CHECKSUM; + } else { + cmd = GS_PARAM_I2C_COMMAND_GET; + } + return gs_pp_i2c_read(cmd, pp, table_id, addr, value, value_size, checksum); +} + +static gs_error_t gs_pp_i2c_set(gs_pp_t * pp, uint8_t table_id, uint16_t addr, const void * value, size_t value_size, uint32_t flags) +{ + gs_param_i2c_command_t cmd; + bool checksum = false; + if (flags & GS_PP_FLAG_CHECKSUM) { + checksum = true; + cmd = GS_PARAM_I2C_COMMAND_SET_WITH_CHECKSUM; + } else { + cmd = GS_PARAM_I2C_COMMAND_SET; + } + return gs_pp_i2c_write(cmd, pp, table_id, addr, (void *)value, value_size, checksum); +} + +static gs_error_t gs_pp_i2c_set_table_lock(gs_pp_t * pp, uint8_t table_id, const bool * value, uint32_t flags) +{ + gs_param_i2c_command_t cmd = GS_PARAM_I2C_COMMAND_SET_LOCK_WITH_CHECKSUM; + bool checksum = true; + return gs_pp_i2c_write(cmd, pp, table_id, 0, (void *)value, 1, checksum); +} + +static gs_error_t gs_pp_i2c_get_table_lock(gs_pp_t * pp, uint8_t table_id, bool * value, uint32_t flags) +{ + gs_param_i2c_command_t cmd = GS_PARAM_I2C_COMMAND_GET_LOCK_WITH_CHECKSUM; + bool checksum = true; + return gs_pp_i2c_read(cmd, pp, table_id, 0, value, 1, checksum); +} + +gs_error_t gs_pp_i2c_init(gs_pp_t * pp, uint8_t bus, uint8_t addr, bool big_endian) +{ + GS_CHECK_HANDLE(pp != NULL); + + memset(pp, 0, sizeof(*pp)); + + pp->get = gs_pp_i2c_get; + pp->set = gs_pp_i2c_set; + pp->set_table_lock = gs_pp_i2c_set_table_lock; + pp->get_table_lock = gs_pp_i2c_get_table_lock; + pp->big_endian = big_endian; + + pp->pp.i2c.bus = bus; + pp->pp.i2c.addr = addr; + + return GS_OK; +} diff --git a/gomspace/libparam_client/src/pp/pp.c b/gomspace/libparam_client/src/pp/pp.c new file mode 100644 index 00000000..e9a20cfd --- /dev/null +++ b/gomspace/libparam_client/src/pp/pp.c @@ -0,0 +1,189 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include + +static inline bool gs_pp_endian_convert(gs_pp_t * pp) +{ + return (pp && (pp->big_endian != gs_endian_big())); +} + +static gs_error_t gs_pp_get(gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, uint32_t flags) +{ + if (pp == NULL) { + return GS_ERROR_HANDLE; + } + if (pp->get == NULL) { + return GS_ERROR_NOT_IMPLEMENTED; + } + return pp->get(pp, table_id, addr, value, value_size, flags); +} + +static gs_error_t gs_pp_set(gs_pp_t * pp, uint8_t table_id, uint16_t addr, const void * value, size_t value_size, uint32_t flags) +{ + if (pp == NULL) { + return GS_ERROR_HANDLE; + } + if (pp->set == NULL) { + return GS_ERROR_NOT_IMPLEMENTED; + } + return pp->set(pp, table_id, addr, value, value_size, flags); +} + +uint8_t gs_pp_checksum8(const void * data_in, size_t length) +{ + const uint8_t * data = data_in; + unsigned int checksum = 0; + for (unsigned int i = 0; i < length; ++i) { + checksum += *data++; + } + checksum &= 0xff; + return checksum ? checksum : 1; +} + +gs_error_t gs_pp_get_table_lock(gs_pp_t * pp, uint8_t table_id, bool * value, uint32_t flags) +{ + GS_CHECK_ARG(value != NULL); + GS_CHECK_HANDLE(pp != NULL); + if (pp->get_table_lock == NULL) { + return GS_ERROR_NOT_IMPLEMENTED; + } + return pp->get_table_lock(pp, table_id, value, flags); +} + +gs_error_t gs_pp_set_table_lock(gs_pp_t * pp, uint8_t table_id, const bool * value, uint32_t flags) +{ + GS_CHECK_ARG(value != NULL); + GS_CHECK_HANDLE(pp != NULL); + if (pp->set_table_lock == NULL) { + return GS_ERROR_NOT_IMPLEMENTED; + } + return pp->set_table_lock(pp, table_id, value, flags); +} + +// int8_t +gs_error_t gs_pp_get_int8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int8_t * value, size_t count, uint32_t flags) +{ + return gs_pp_get_uint8(pp, table_id, addr, (uint8_t *) value, count, flags); +} + +gs_error_t gs_pp_set_int8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int8_t * value, size_t count, uint32_t flags) +{ + return gs_pp_set_uint8(pp, table_id, addr, (const uint8_t *) value, count, flags); +} + +// uint8_t + +gs_error_t gs_pp_get_uint8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint8_t * value, size_t count, uint32_t flags) +{ + GS_CHECK_ARG(value != NULL); + GS_CHECK_ARG(count > 0); + return gs_pp_get(pp, table_id, addr, value, (sizeof(*value) * count), flags); +} + +gs_error_t gs_pp_set_uint8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint8_t * value, size_t count, uint32_t flags) +{ + GS_CHECK_ARG(value != NULL); + GS_CHECK_ARG(count > 0); + return gs_pp_set(pp, table_id, addr, value, (sizeof(*value) * count), flags); +} + +// int16_t + +gs_error_t gs_pp_get_int16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int16_t * value, size_t count, uint32_t flags) +{ + return gs_pp_get_uint16(pp, table_id, addr, (uint16_t *) value, count, flags); +} + +gs_error_t gs_pp_set_int16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int16_t * value, size_t count, uint32_t flags) +{ + return gs_pp_set_uint16(pp, table_id, addr, (const uint16_t *) value, count, flags); +} + +// uint16_t + +gs_error_t gs_pp_get_uint16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint16_t * value, size_t count, uint32_t flags) +{ + GS_CHECK_ARG(value != NULL); + GS_CHECK_ARG(count > 0); + gs_error_t error = gs_pp_get(pp, table_id, addr, value, (sizeof(*value) * count), flags); + if (gs_pp_endian_convert(pp)) { + gs_bswap_16_array(value, value, count); + } + return error; +} + +gs_error_t gs_pp_set_uint16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint16_t * value, size_t count, uint32_t flags) +{ + GS_CHECK_ARG(value != NULL); + GS_CHECK_ARG(count > 0); + uint16_t _converted[count]; + if (gs_pp_endian_convert(pp)) { + gs_bswap_16_array(value, _converted, count); + value = _converted; + } + return gs_pp_set(pp, table_id, addr, value, (sizeof(*value) * count), flags); +} + +// int32_t + +gs_error_t gs_pp_get_int32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int32_t * value, size_t count, uint32_t flags) +{ + return gs_pp_get_uint32(pp, table_id, addr, (uint32_t *) value, count, flags); +} + +gs_error_t gs_pp_set_int32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int32_t * value, size_t count, uint32_t flags) +{ + return gs_pp_set_uint32(pp, table_id, addr, (const uint32_t *) value, count, flags); +} + +// uint32_t + +gs_error_t gs_pp_get_uint32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint32_t * value, size_t count, uint32_t flags) +{ + GS_CHECK_ARG(value != NULL); + GS_CHECK_ARG(count > 0); + gs_error_t error = gs_pp_get(pp, table_id, addr, value, (sizeof(*value) * count), flags); + if (gs_pp_endian_convert(pp)) { + gs_bswap_32_array(value, value, count); + } + return error; +} + +gs_error_t gs_pp_set_uint32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint32_t * value, size_t count, uint32_t flags) +{ + GS_CHECK_ARG(value != NULL); + GS_CHECK_ARG(count > 0); + uint32_t _converted[count]; + if (gs_pp_endian_convert(pp)) { + gs_bswap_32_array(value, _converted, count); + value = _converted; + } + return gs_pp_set(pp, table_id, addr, value, (sizeof(*value) * count), flags); +} + +gs_error_t gs_pp_get_float(gs_pp_t * pp, uint8_t table_id, uint8_t addr, float * value, size_t count, uint32_t flags) +{ + GS_CHECK_ARG(value != NULL); + GS_CHECK_ARG(count > 0); + gs_error_t error = gs_pp_get(pp, table_id, addr, value, (sizeof(*value) * count), flags); + if (gs_pp_endian_convert(pp)) { + gs_bswap_float_array(value, value, count); + } + return error; +} + +gs_error_t gs_pp_set_float(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const float * value, size_t count, uint32_t flags) +{ + GS_CHECK_ARG(value != NULL); + GS_CHECK_ARG(count > 0); + float _converted[count]; + if (gs_pp_endian_convert(pp)) { + gs_bswap_float_array(value, _converted, count); + value = _converted; + } + return gs_pp_set(pp, table_id, addr, value, (sizeof(*value) * count), flags); +} diff --git a/gomspace/libparam_client/src/pp/spi/spi.c b/gomspace/libparam_client/src/pp/spi/spi.c new file mode 100644 index 00000000..7e594e9f --- /dev/null +++ b/gomspace/libparam_client/src/pp/spi/spi.c @@ -0,0 +1,91 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#define GS_PARAM_INTERNAL_USE 1 + +#include +#include +#include +#include +#include + +static gs_error_t gs_pp_spi_get(gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, uint32_t flags) +{ + GS_CHECK_RANGE(table_id <= 7); + GS_CHECK_RANGE(addr <= 255); + + if (flags & GS_PP_FLAG_CHECKSUM) { + gs_param_spi_get_with_checksum_t * request; + const size_t size = (sizeof(*request) + value_size + 1); // +1 for CHECKSUM in returned data + request = alloca(size); + memset(request, 0, size); + request->header.domain_command = GS_SPI_SLAVE_DISPATCH_HEADER(GS_SPI_SLAVE_DISPATCH_DOMAIN_PARAM, GS_PARAM_SPI_COMMAND_GET_WITH_CHECKSUM); + request->length_table = GS_PARAM_SPI_LENGTH_TABLE(value_size, table_id); + request->addr = addr; + request->checksum = gs_pp_checksum8(request, (sizeof(*request) - sizeof(request->filler))); + + gs_error_t error = gs_spi_master_transaction(pp->pp.spi.slave, request, request, size, 1000); + if (error == GS_OK) { + if (gs_pp_checksum8(request->data, value_size) != request->data[value_size]) { + return GS_ERROR_DATA; + } + memcpy(value, request->data, value_size); + } + return error; + + } else { + gs_param_spi_get_t * request; + const size_t size = (sizeof(*request) + value_size); + request = alloca(size); + memset(request, 0, size); + request->header.domain_command = GS_SPI_SLAVE_DISPATCH_HEADER(GS_SPI_SLAVE_DISPATCH_DOMAIN_PARAM, GS_PARAM_SPI_COMMAND_GET); + request->length_table = GS_PARAM_SPI_LENGTH_TABLE(value_size, table_id); + request->addr = addr; + + gs_error_t error = gs_spi_master_transaction(pp->pp.spi.slave, request, request, size, 1000); + if (error == GS_OK) { + memcpy(value, request->data, value_size); + } + return error; + } +} + +static gs_error_t gs_pp_spi_set(gs_pp_t * pp, uint8_t table_id, uint16_t addr, const void * value, size_t value_size, uint32_t flags) +{ + GS_CHECK_RANGE(table_id <= 7); + GS_CHECK_RANGE(addr <= 255); + + gs_param_spi_set_t * request; + const size_t size = (sizeof(*request) + value_size + ((flags & GS_PP_FLAG_CHECKSUM) ? 1 : 0)); + request = alloca(size); + if (flags & GS_PP_FLAG_CHECKSUM) { + request->header.domain_command = GS_SPI_SLAVE_DISPATCH_HEADER(GS_SPI_SLAVE_DISPATCH_DOMAIN_PARAM, GS_PARAM_SPI_COMMAND_SET_WITH_CHECKSUM); + } else { + request->header.domain_command = GS_SPI_SLAVE_DISPATCH_HEADER(GS_SPI_SLAVE_DISPATCH_DOMAIN_PARAM, GS_PARAM_SPI_COMMAND_SET); + } + request->length_table = GS_PARAM_SPI_LENGTH_TABLE(value_size, table_id); + request->addr = addr; + memcpy(request->data, value, value_size); + + if (flags & GS_PP_FLAG_CHECKSUM) { + request->data[value_size] = gs_pp_checksum8(request, size - 1); + } + + return gs_spi_master_transaction(pp->pp.spi.slave, request, NULL, size, 1000); +} + +gs_error_t gs_pp_spi_init(gs_pp_t * pp, uint8_t slave, bool big_endian) +{ + GS_CHECK_HANDLE(pp != NULL); + + memset(pp, 0, sizeof(*pp)); + + pp->get = gs_pp_spi_get; + pp->set = gs_pp_spi_set; + pp->set_table_lock = NULL; // Not implemented + pp->get_table_lock = NULL; // Not implemented + pp->big_endian = big_endian; + + pp->pp.spi.slave = slave; + + return GS_OK; +} diff --git a/gomspace/libparam_client/src/rparam/cmd/cmd_rparam.c b/gomspace/libparam_client/src/rparam/cmd/cmd_rparam.c new file mode 100644 index 00000000..de1bd6d8 --- /dev/null +++ b/gomspace/libparam_client/src/rparam/cmd/cmd_rparam.c @@ -0,0 +1,354 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#define GS_PARAM_INTERNAL_USE 1 + +#include +#include +#include +#include +#include "../query.h" +#include +#include +#include +#include +#include +#include + +#define MAX_FILENAME 100 + +/** Remote param system setup */ +static gs_param_table_instance_t rparam_tinst; +static gs_rparam_query_handle_t rquery = {.timeout_ms = 10000}; +static char * rparam_wd; + +#define CHECK_TABLE() \ + if (rparam_tinst.rows == NULL) { \ + fprintf(ctx->out, "Run download or init to setup table\n"); \ + return GS_ERROR_NOT_FOUND; \ + } + +static int cmd_rparam_list(gs_command_context_t *ctx) +{ + CHECK_TABLE(); + return gs_param_list_to_stream(&rparam_tinst, true, 0, ctx->out); +} + +static void make_filename(char * fname, size_t fname_size) +{ + char cwd[MAX_FILENAME + 1]; + const char * wd; + if (gs_string_empty(rparam_wd) == false) { + wd = rparam_wd; + } else if (gs_getcwd(cwd, sizeof(cwd)) == GS_OK) { + wd = cwd; + } else { + wd = NULL; + } + if (gs_string_empty(wd) == false) { + snprintf(fname, fname_size, "%s/param-%d-%u.bin", wd, rquery.node, rquery.table_id); + } else { + fname[0] = 0; + } +} + +static int cmd_rparam_init_from_local_file(gs_command_context_t *ctx) +{ + if (gs_string_to_uint8(ctx->argv[1], &rquery.node)) { + return GS_ERROR_ARG; + } + if (ctx->argc > 2) { + if (gs_string_to_uint8(ctx->argv[2], &rquery.table_id)) { + return GS_ERROR_ARG; + } + } + + char fname[100]; + make_filename(fname, sizeof(fname)); + return gs_rparam_load_table_spec(&rparam_tinst, fname, &rquery.checksum); +} + +static int cmd_rparam_init_from_remote_node(gs_command_context_t *ctx) +{ + if (gs_string_to_uint8(ctx->argv[1], &rquery.node)) { + return GS_ERROR_ARG; + } + if (ctx->argc > 2) { + if (gs_string_to_uint8(ctx->argv[2], &rquery.table_id)) { + return GS_ERROR_ARG; + } + } + + char fname[100]; + make_filename(fname, sizeof(fname)); + return gs_rparam_download_table_spec(&rparam_tinst, fname, rquery.node, rquery.table_id, rquery.timeout_ms, &rquery.checksum); +} + +static int cmd_rparam_send(gs_command_context_t *ctx) +{ + CHECK_TABLE(); + + gs_error_t error = gs_rparam_query_send(&rquery, &rparam_tinst); + if (error == GS_OK) { + if (rquery.action == RPARAM_GET) { + const gs_param_table_row_t * last_print = NULL; + for (unsigned int i = 0; i < rquery.length / 2; ++i) { + const gs_param_table_row_t * row = gs_param_row_by_address(rquery.payload.addr[i], rparam_tinst.rows, rparam_tinst.row_count); + if (row != last_print) { // work-around to avoid duplicate lines for elements within same array + gs_param_list_single_to_stream(&rparam_tinst, row, true, 0, ctx->out); + last_print = row; + } + } + } + gs_rparam_query_reset(&rquery); + } + return error; +} + +static int cmd_rparam_get(gs_command_context_t *ctx) +{ + CHECK_TABLE(); + + gs_rparam_query_set_quiet(&rquery, false); + gs_error_t error = gs_rparam_query_get(&rquery, &rparam_tinst, ctx->argv[1]); + if ((error == GS_OK) && rquery.auto_send) { + error = cmd_rparam_send(ctx); + } + + return error; +} + +static int cmd_rparam_getall(gs_command_context_t *ctx) +{ + CHECK_TABLE(); + + fprintf(ctx->out, "Downloading table content for table %i from server %u\n", rquery.table_id, rquery.node); + gs_error_t error = gs_rparam_get_full_table(&rparam_tinst, rquery.node, rquery.table_id, rquery.checksum, rquery.timeout_ms); + if (error == GS_OK) { + gs_param_list_to_stream(&rparam_tinst, true, 0, ctx->out); + } + return error; +} + +static int cmd_rparam_set(gs_command_context_t *ctx) +{ + CHECK_TABLE(); + + gs_error_t error = gs_rparam_query_set(&rquery, &rparam_tinst, ctx->argv[1], &ctx->argv[2], ctx->argc - 2); + if ((error == GS_OK) && rquery.auto_send) { + error = cmd_rparam_send(ctx); + } + + return error; +} + +static int cmd_rparam_copy(gs_command_context_t *ctx) +{ + uint8_t from; + if (gs_string_to_uint8(ctx->argv[1], &from)) { + return GS_ERROR_ARG; + } + + uint8_t to; + if (gs_string_to_uint8(ctx->argv[2], &to)) { + return GS_ERROR_ARG; + } + + return gs_rparam_copy(rquery.node, rquery.timeout_ms, from, to); +} + +static int cmd_rparam_load(gs_command_context_t *ctx) +{ + uint8_t table_id; + if (gs_string_to_uint8(ctx->argv[2], &table_id)) { + return GS_ERROR_ARG; + } + uint8_t file_id; + if (gs_string_to_uint8(ctx->argv[1], &file_id)) { + // This may be a store - no way of validating + return gs_rparam_load_from_store(rquery.node, rquery.timeout_ms, table_id, ctx->argv[1], NULL); + } + + return gs_rparam_load(rquery.node, rquery.timeout_ms, file_id, table_id); +} + +static int cmd_rparam_save(gs_command_context_t *ctx) +{ + uint8_t table_id; + if (gs_string_to_uint8(ctx->argv[1], &table_id)) { + return GS_ERROR_ARG; + } + uint8_t file_id; + if (gs_string_to_uint8(ctx->argv[2], &file_id)) { + // This may be a store - no way of validating + return gs_rparam_save_to_store(rquery.node, rquery.timeout_ms, table_id, ctx->argv[2], NULL); + } + + return gs_rparam_save(rquery.node, rquery.timeout_ms, table_id, file_id); +} + +static int cmd_rparam_reset(gs_command_context_t *ctx) +{ + gs_rparam_query_reset(&rquery); + return GS_OK; +} + +static int cmd_rparam_set_autosend(gs_command_context_t *ctx) +{ + if (ctx->argc > 1) { + if (gs_string_to_bool(ctx->argv[1], &rquery.auto_send)) { + return GS_ERROR_ARG; + } + } + fprintf(ctx->out, "auto send: %d\r\n", rquery.auto_send); + return GS_OK; +} + +static int cmd_set_wd(gs_command_context_t *ctx) +{ + if (ctx->argc > 1) { + if (rparam_wd == NULL) { + rparam_wd = malloc(MAX_FILENAME + 1); + if (rparam_wd == NULL) { + return GS_ERROR_ALLOC; + } + } + strcpy(rparam_wd, ctx->argv[1]); + } + fprintf(ctx->out, "working directory: %s\r\n", rparam_wd ? rparam_wd : "not set"); + return GS_OK; +} + +static int cmd_rparam_set_timeout(gs_command_context_t *ctx) +{ + if (ctx->argc > 1) { + if (gs_string_to_uint32(ctx->argv[1], &rquery.timeout_ms)) { + return GS_ERROR_ARG; + } + } + fprintf(ctx->out, "timeout: %"PRIu32" mS\r\n", rquery.timeout_ms); + return GS_OK; +} + +static int cmd_rparam_set_checksum(gs_command_context_t *ctx) +{ + if (ctx->argc > 1) { + if (strcasecmp(ctx->argv[1], "magic") == 0) { + rquery.checksum = GS_RPARAM_MAGIC_CHECKSUM; + } else if (gs_string_to_uint16(ctx->argv[1], &rquery.checksum)) { + return GS_ERROR_ARG; + } + } + fprintf(ctx->out, "checksum: 0x%04x (magic: 0x%04x)\r\n", rquery.checksum, GS_RPARAM_MAGIC_CHECKSUM); + return GS_OK; +} + +static const gs_command_t rparam_commands[] = { + { + .name = "init", + .help = "Set server and load table spec. from file", + .usage = " [table-id]", + .handler = cmd_rparam_init_from_local_file, + .mandatory_args = 1, + .optional_args = 1, + },{ + .name = "download", + .help = "Set server and download table spec.", + .usage = " [table-id]", + .handler = cmd_rparam_init_from_remote_node, + .mandatory_args = 1, + .optional_args = 1, + },{ + .name = "getall", + .help = "Download full table contents from server", + .handler = cmd_rparam_getall, + .mandatory_args = GS_COMMAND_NO_ARGS, + },{ + .name = "list", + .help = "Lists the table specification", + .handler = cmd_rparam_list, + .mandatory_args = GS_COMMAND_NO_ARGS, + },{ + .name = "get", + .help = "Add a 'get' to the current query transaction", + .usage = "", + .handler = cmd_rparam_get, + .mandatory_args = 1, + },{ + .name = "set", + .help = "Add a 'set' to the current query transaction", + .usage = " [value] ...", + .handler = cmd_rparam_set, + .mandatory_args = 2, + .optional_args = 100, + },{ + .name = "copy", + .usage = " ", + .help = "Copy table to table (version <= 3 only)", + .handler = cmd_rparam_copy, + .mandatory_args = 2, + },{ + .name = "load", + .usage = " ", + .help = "Load table", + .handler = cmd_rparam_load, + .mandatory_args = 2, + },{ + .name = "save", + .usage = " ", + .help = "Save table", + .handler = cmd_rparam_save, + .mandatory_args = 2, + /* },{ */ + /* .name = "print", */ + /* .help = "Print the current query", */ + /* .handler = cmd_rparam_print, */ + /* .mandatory_args = GS_COMMAND_NO_ARGS, */ + },{ + .name = "reset", + .help = "Reset the current query", + .handler = cmd_rparam_reset, + .mandatory_args = GS_COMMAND_NO_ARGS, + },{ + .name = "send", + .help = "Send the current query", + .handler = cmd_rparam_send, + .mandatory_args = GS_COMMAND_NO_ARGS, + },{ + .name = "wd", + .help = "Set working directory for init/download", + .usage = "[path]", + .handler = cmd_set_wd, + .optional_args = 1, + },{ + .name = "timeout", + .help = "Set timeout", + .usage = "[timeout mS]", + .handler = cmd_rparam_set_timeout, + .optional_args = 1, + },{ + .name = "checksum", + .help = "Set checksum", + .usage = "[magic|]", + .handler = cmd_rparam_set_checksum, + .optional_args = 1, + },{ + .name = "autosend", + .usage = "[bool]", + .help = "Enable/disable autosend for set and get queries", + .handler = cmd_rparam_set_autosend, + .optional_args = 1, + } +}; + +static const gs_command_t GS_COMMAND_ROOT rparam_root_command[] = { + { + .name = "rparam", + .help = "Remote access to Parameter System", + .chain = GS_COMMAND_INIT_CHAIN(rparam_commands), + }, +}; + +gs_error_t gs_rparam_register_commands(void) +{ + return GS_COMMAND_REGISTER(rparam_root_command); +} diff --git a/gomspace/libparam_client/src/rparam/deprecated_rparam.c b/gomspace/libparam_client/src/rparam/deprecated_rparam.c new file mode 100644 index 00000000..418f468c --- /dev/null +++ b/gomspace/libparam_client/src/rparam/deprecated_rparam.c @@ -0,0 +1,6 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +// Old deprecated API uses common data - making it not thread-safe. +//gs_rparam_handle_t rparam_handle; diff --git a/gomspace/libparam_client/src/rparam/query.c b/gomspace/libparam_client/src/rparam/query.c new file mode 100644 index 00000000..79144e33 --- /dev/null +++ b/gomspace/libparam_client/src/rparam/query.c @@ -0,0 +1,212 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#define GS_PARAM_INTERNAL_USE 1 + +#include "query.h" +#include +#include +#include +#include "../serialize_local.h" +#include +#include + +bool gs_rparam_query_is_set(gs_rparam_query_handle_t * handle) +{ + return (handle->length > 0); +} + +void gs_rparam_query_reset(gs_rparam_query_handle_t * handle) +{ + handle->action = RPARAM_GET; + handle->length = 0; + handle->get_size = 0; +} + +void gs_rparam_query_set_quiet(gs_rparam_query_handle_t * handle, bool quiet) +{ + handle->quiet = quiet; +} + +gs_error_t gs_rparam_query_get(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst, const char* param_name) +{ + if (tinst->rows == NULL) + return GS_ERROR_NOT_FOUND; + + /* Ensure correct header */ + if (handle->action != RPARAM_GET) { + gs_rparam_query_reset(handle); + handle->action = RPARAM_GET; + } + + char shortname[GS_PARAM_MAX_NAME + 20]; + uint8_t array_index = 0; + bool is_array; + if (gs_param_parse_name_and_array_index(param_name, shortname, sizeof(shortname), &array_index, &is_array)) { + return GS_ERROR_ARG; + } + + const gs_param_table_row_t * param = gs_param_row_by_name(shortname, tinst->rows, tinst->row_count); + if (param == NULL) { + return GS_ERROR_NOT_FOUND; + } + + if (array_index >= GS_PARAM_ARRAY_SIZE(param)) { + return GS_ERROR_RANGE; + } + + unsigned int start; + unsigned int end; + if (is_array) { + start = array_index; + end = start + 1; + } else { + start = 0; + end = GS_PARAM_ARRAY_SIZE(param); + } + for (unsigned int i = start; i < end; ++i) { + + /* Size check */ + if (handle->get_size + param->size + sizeof(uint16_t) > GS_RPARAM_QUERY_MAX_PAYLOAD) { + return GS_ERROR_OVERFLOW; + } + + /* Add to query */ + handle->payload.addr[handle->length/2] = param->addr + (param->size * i); + handle->length += sizeof(uint16_t); + handle->get_size += param->size + sizeof(uint16_t); + } + + return GS_OK; +} + +gs_error_t gs_rparam_query_set(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst, const char* param_name, char * values[], uint8_t value_count) +{ + /* Ensure correct header */ + if (handle->action != RPARAM_SET) { + gs_rparam_query_reset(handle); + handle->action = RPARAM_SET; + } + + char shortname[GS_PARAM_MAX_NAME + 20]; + uint8_t array_index = 0; + if (gs_param_parse_name_and_array_index(param_name, shortname, sizeof(shortname), &array_index, NULL)) { + return GS_ERROR_ARG; + } + + const gs_param_table_row_t * param = gs_param_row_by_name(shortname, tinst->rows, tinst->row_count); + if (param == NULL) { + return GS_ERROR_NOT_FOUND; + } + + if (array_index >= GS_PARAM_ARRAY_SIZE(param)) { + return GS_ERROR_RANGE; + } + + for (unsigned int i = 0; i < value_count; i++) { + + /* Parse input */ + uint8_t value[param->size]; + gs_error_t error = gs_param_from_string(param, values[i], value); + if (error) { + return error; + } + + unsigned int bytes = 0; + error = gs_param_serialize_item(param, param->addr + (param->size * (array_index + i)), value, F_TO_BIG_ENDIAN, + &handle->payload.packed[handle->length], GS_RPARAM_QUERY_MAX_PAYLOAD - handle->length, &bytes); + if (error) { + return error; + } + handle->length += bytes; + } + + return GS_OK; +} + +gs_error_t gs_rparam_query_send(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst) +{ + if (tinst->rows == NULL) { + return GS_ERROR_NOT_FOUND; + } + + if (handle->length == 0) { + return GS_ERROR_NO_DATA; + } + + gs_rparam_query_t * query; + + /* Allocate outgoing buffer */ + csp_packet_t * packet = csp_buffer_get(RPARAM_QUERY_LENGTH(query, GS_RPARAM_QUERY_MAX_PAYLOAD)); + if (packet == NULL) { + return GS_ERROR_NO_BUFFERS; + } + + csp_conn_t * conn = csp_connect(CSP_PRIO_HIGH, handle->node, GS_CSP_PORT_RPARAM, handle->timeout_ms, CSP_O_CRC32); + if (conn == NULL) { + csp_buffer_free(packet); + return GS_ERROR_IO; + } + + query = (gs_rparam_query_t *) packet->data; + + query->action = handle->action; + query->table_id = handle->table_id; + query->seq = 0; + query->total = 0; + query->length = csp_hton16(handle->length); + query->checksum = csp_hton16(handle->checksum); + + /* Copy payload to message */ + packet->length = RPARAM_QUERY_LENGTH(query, handle->length); + memcpy(&query->payload, &handle->payload, handle->length); + + /* Deal with endianness */ + if (handle->action == RPARAM_GET) { + for (unsigned int i = 0; i < (handle->length/2); i++) { + query->payload.addr[i] = csp_hton16(query->payload.addr[i]); + } + } + + /* Send packet */ + if (!csp_send(conn, packet, 0)) { + csp_buffer_free(packet); + csp_close(conn); + return GS_ERROR_IO; + } + + /* Read reply */ + packet = csp_read(conn, handle->timeout_ms); + if (packet == NULL) { + csp_close(conn); + return GS_ERROR_TIMEOUT; + } + + if (packet->length <= 1) { + gs_error_t error = GS_OK; + if (packet->length == 1) { + if (packet->data[0] == RPARAM_ERROR) { + error = GS_ERROR_DATA; + } + } else { + error = GS_ERROR_NO_DATA; + } + csp_buffer_free(packet); + csp_close(conn); + return error; + } + + /* We have a reply */ + gs_rparam_query_t * reply = (gs_rparam_query_t *) packet->data; + reply->length = csp_ntoh16(reply->length); + + gs_error_t error; + if (reply->action == RPARAM_REPLY) { + error = gs_param_deserialize(tinst, reply->payload.packed, reply->length, F_FROM_BIG_ENDIAN); + } else { + error = GS_ERROR_TYPE; + } + + csp_buffer_free(packet); + csp_close(conn); + return error; +} diff --git a/gomspace/libparam_client/src/rparam/query.h b/gomspace/libparam_client/src/rparam/query.h new file mode 100644 index 00000000..507a870a --- /dev/null +++ b/gomspace/libparam_client/src/rparam/query.h @@ -0,0 +1,110 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + + +#include + +/** + Rparam query handle. +*/ +typedef struct { + /** + CSP node. + */ + uint8_t node; + /** + Remote table id. + */ + gs_param_table_id_t table_id; + /** + Remote table (definition) checksum. + */ + uint16_t checksum; + /** + Timeout (mS). + */ + uint32_t timeout_ms; + /** + If quite - no output to stdout. + */ + bool quiet; + /** + Auto send. + */ + bool auto_send; + /** + Type/action. + */ + int action; + /** + Size of current query. + */ + unsigned int length; + /** + Estimated total 'get' size. + */ + unsigned int get_size; + /** + Space for payload data. + @note must be last in struct. + */ + union { + uint16_t addr[0]; + uint8_t packed[GS_RPARAM_QUERY_MAX_PAYLOAD]; + } payload; +} gs_rparam_query_handle_t; + +/** + Set whether rparam API should print to stdout or not. + + @param[in] handle handle + @param[in] quiet \a true print to stdout. +*/ +void gs_rparam_query_set_quiet(gs_rparam_query_handle_t * handle, bool quiet); + +/** + Return true if any query has been set. + + @param[in] handle handle + @return \a true if any query has been set. +*/ +bool gs_rparam_query_is_set(gs_rparam_query_handle_t * handle); + +/** + Add a 'get' query to the current query, after a succesfull rparam_query_send() + the parameter value can be read using rparam_queury_get_value() + + @param[in] handle handle + @param[in] tinst table. + @param[in] param_name name of the parameter. + @return_gs_error_t + @see rparam_query_send() +*/ +gs_error_t gs_rparam_query_get(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst, const char* param_name); + +/** + Add a 'set' query to the current query. Use rparam_query_send() to execute the set query. + + @param[in] handle handle + @param[in] tinst table. + @param[in] param_name name of the parameter to set + @param[in] values array of values to set, multiple values can be set for array type parameters + @param[in] value_count number of elements in \a values + @return_gs_error_t + @see rparam_query_send() +*/ +gs_error_t gs_rparam_query_set(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst, const char* param_name, char * values[], uint8_t value_count); + +/** + Send the current query + + @param[in] handle handle + @param[in] tinst table. + @return_gs_error_t +*/ +gs_error_t gs_rparam_query_send(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst); + +/** + Reset/clear the current query + @param[in] handle handle +*/ +void gs_rparam_query_reset(gs_rparam_query_handle_t * handle); diff --git a/gomspace/libparam_client/src/rparam/rparam.c b/gomspace/libparam_client/src/rparam/rparam.c new file mode 100644 index 00000000..d8ba79bd --- /dev/null +++ b/gomspace/libparam_client/src/rparam/rparam.c @@ -0,0 +1,474 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#define GS_PARAM_INTERNAL_USE 1 + +#include +#include +#include +#include "../serialize_local.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static gs_error_t gs_rparam_command(uint8_t node, uint32_t timeout_ms, uint8_t action, uint8_t table_id, + const void * payload, size_t payload_size, char reply_ok) +{ + gs_rparam_query_t * query = alloca(RPARAM_QUERY_LENGTH(query, payload_size)); + query->action = action; + query->table_id = table_id; + query->length = csp_hton16(payload_size); + query->checksum = csp_hton16(GS_RPARAM_MAGIC_CHECKSUM); // Ignore checksum + query->seq = 0; + query->total = 0; + memcpy(&query->payload, payload, payload_size); + + /* Run single packet transaction */ + char reply = 0; + if (csp_transaction2(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, query, RPARAM_QUERY_LENGTH(query, payload_size), + &reply, 1, CSP_O_CRC32) <= 0) { + return GS_ERROR_IO; + } + + return (reply == reply_ok) ? GS_OK : GS_ERROR_UNKNOWN; +} + +gs_error_t gs_rparam_copy(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to) +{ + gs_rparam_query_payload_t payload; + payload.copy.from = from; + payload.copy.to = to; + return gs_rparam_command(node, timeout_ms, RPARAM_COPY, from, &payload, sizeof(payload.copy), RPARAM_COPY_OK); +} + +static gs_error_t gs_rparam_store(uint8_t node, uint32_t timeout_ms, uint8_t action, char reply_ok, uint8_t table_id, + const char * table, const char * store, const char * slot) +{ + gs_rparam_query_payload_store_t payload; + memset(&payload, 0, sizeof(payload)); + if (table && (gs_string_empty(table) == false)) { + GS_STRNCPY(payload.table, table); + } + if (store && (gs_string_empty(store) == false)) { + GS_STRNCPY(payload.store, store); + } + if (slot && (gs_string_empty(slot) == false)) { + GS_STRNCPY(payload.slot, slot); + } + return gs_rparam_command(node, timeout_ms, action, table_id, &payload, sizeof(payload), reply_ok); +} + +gs_error_t gs_rparam_save_to_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id, + const char * store, const char * slot) +{ + return gs_rparam_store(node, timeout_ms, RPARAM_SAVE_TO_STORE, RPARAM_SAVE_OK, table_id, NULL, store, slot); +} + +gs_error_t gs_rparam_load_from_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id, + const char * store, const char * slot) +{ + return gs_rparam_store(node, timeout_ms, RPARAM_LOAD_FROM_STORE, RPARAM_LOAD_OK, table_id, NULL, store, slot); +} + +gs_error_t gs_rparam_save(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to) +{ + gs_rparam_query_payload_t payload; + payload.copy.from = from; + payload.copy.to = to; + return gs_rparam_command(node, timeout_ms, RPARAM_SAVE, from, &payload, sizeof(payload.copy), RPARAM_SAVE_OK); +} + +gs_error_t gs_rparam_load(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to) +{ + gs_rparam_query_payload_t payload; + payload.copy.from = from; + payload.copy.to = to; + return gs_rparam_command(node, timeout_ms, RPARAM_LOAD, to, &payload, sizeof(payload.copy), RPARAM_LOAD_OK); +} + +static gs_error_t update_table(const char * func, + gs_param_table_instance_t * tinst, + gs_param_table_row_t * rows, unsigned int row_count, + uint16_t checksum) +{ + size_t memory_size = gs_param_calc_table_size(rows, row_count); + if ((tinst->memory == NULL) || (tinst->memory_size < memory_size)) { + // (re)allocate memory + if (memory_size == 0) { + return GS_ERROR_NOT_SUPPORTED; + } + memory_size = gs_max(1000U, memory_size); + void * memory = calloc(1, memory_size); + if (memory == NULL) { + return GS_ERROR_ALLOC; + } + + free(tinst->memory); + tinst->memory = memory; + tinst->memory_size = memory_size; + tinst->flags |= GS_PARAM_TABLE_F_ALLOC_MEMORY; + } + + free((void*)tinst->rows); + tinst->rows = rows; + tinst->row_count = row_count; + tinst->checksum_be = tinst->checksum_le = 0; + tinst->flags |= GS_PARAM_TABLE_F_ALLOC_ROWS; + + if ((checksum != gs_param_table_checksum_le(tinst)) && (checksum != gs_param_table_checksum_be(tinst))) { + log_error("%s: table specification has invalid checksum: %u - different from LE: %u and BE: %u", + func, checksum, gs_param_table_checksum_le(tinst), gs_param_table_checksum_be(tinst)); + return GS_ERROR_DATA; + } + + return GS_OK; +} + +gs_error_t gs_rparam_load_table_spec(gs_param_table_instance_t * tinst, const char* fname, uint16_t * return_checksum) +{ + GS_CHECK_HANDLE(tinst != NULL); + GS_CHECK_ARG(fname != NULL); + + FILE * fd = fopen(fname, "r"); + if (fd == NULL) { + return GS_ERROR_NOT_FOUND; + } + + struct stat file_stat; + if (fstat(fileno(fd), &file_stat) != 0) { + log_error("%s: failed to stat file [%s]", __FUNCTION__, fname); + fclose(fd); + return GS_ERROR_IO; + } + + void * rows = calloc(file_stat.st_size, 1); + if (rows == NULL) { + fclose(fd); + return GS_ERROR_ALLOC; + } + + uint16_t checksum = 0; + size_t rs1 = fread(&checksum, 1, sizeof(checksum), fd); + size_t rs2 = fread(rows, 1, file_stat.st_size, fd); + fclose(fd); + + const unsigned int single_row_size = sizeof(*tinst->rows); + const unsigned int all_row_size = (file_stat.st_size - sizeof(checksum)); + const unsigned int row_count = (all_row_size) / single_row_size; + if ((rs1 != sizeof(checksum)) || (rs2 != all_row_size) || (rs2 != (single_row_size * row_count))) { + log_error("%s: incomplete/invalid read, expected %u + %u - read %u + %u, single row size: %u", __FUNCTION__, + (unsigned int) sizeof(checksum), row_count, + (unsigned int) rs1, (unsigned int) rs2, single_row_size); + free(rows); + return GS_ERROR_IO; + } + + gs_error_t error = update_table(__FUNCTION__, tinst, rows, row_count, checksum); + + if (error == GS_OK) { + if (return_checksum) { + *return_checksum = checksum; + } + } + + return error; +} + +gs_error_t gs_rparam_download_table_spec(gs_param_table_instance_t * tinst, + const char * fname, + uint8_t node, + gs_param_table_id_t table_id, + uint32_t timeout_ms, + uint16_t * return_checksum) +{ + csp_conn_t * conn = csp_connect(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, CSP_O_CRC32); + if (conn == NULL) { + return GS_ERROR_IO; + } + + /* Allocate outgoing buffer */ + gs_rparam_query_t * query; + csp_packet_t * packet = csp_buffer_get(RPARAM_QUERY_LENGTH(query, 0)); + if (packet == NULL) { + csp_close(conn); + return GS_ERROR_NO_BUFFERS; + } + + // setup request + query = (gs_rparam_query_t *) packet->data; + query->action = RPARAM_TABLE; + query->table_id = table_id; + query->length = 0; + query->checksum = csp_hton16(GS_RPARAM_MAGIC_CHECKSUM); // Ignore checksum + query->seq = 0; + query->total = 0; + + packet->length = RPARAM_QUERY_LENGTH(query, 0); + if (!csp_send(conn, packet, 0)) { + csp_buffer_free(packet); + csp_close(conn); + return GS_ERROR_IO; + } + + /* Receive remote parameter table, in host byte order + * Note: This is necessary, because the SFP functions does not know the dataformat + * and hence cannot be converted server-side. */ + void * dataout = NULL; + int totalsize = 0; + int result = csp_sfp_recv(conn, &dataout, &totalsize, timeout_ms); + csp_close(conn); + + if (result < 0) { + free(dataout); + return GS_ERROR_IO; + } + + gs_param_table_row_t * rows = dataout; + const uint8_t row_count = totalsize / sizeof(*rows); + + /* Calculate checksum on table (before converting endians!) */ + const uint16_t checksum = gs_fletcher16(rows, totalsize); + + /* Autodetect Endians */ + int sum_first = 0; + int sum_last = 0; + for (unsigned int i = 0; i < row_count; i++) { + sum_first += (rows[i].addr & 0xFF00) >> 8; + sum_last += rows[i].addr & 0xFF; + } + + /* Correct endians */ + if (sum_first > sum_last) { + for (unsigned int i = 0; i < row_count; i++) { + rows[i].addr = (((rows[i].addr & 0xff00) >> 8) | ((rows[i].addr & 0x00ff) << 8)); + } + } + + gs_error_t error = update_table(__FUNCTION__, tinst, rows, row_count, checksum); + if (error == GS_OK) { + + if (return_checksum) { + *return_checksum = checksum; + } + + // If filename provided, store table specification to file. + if (gs_string_empty(fname) == false) { + FILE * fd = fopen(fname, "w"); + if (fd == NULL) { + log_error("%s: failed to open/create file: [%s]", __FUNCTION__, fname); + return GS_ERROR_IO; + } + const size_t ws1_size = sizeof(checksum); + const size_t ws1 = fwrite(&checksum, 1, ws1_size, fd); + const size_t ws2 = fwrite(rows, 1, totalsize, fd); + fclose(fd); + if ((ws1 != ws1_size) || (ws2 != (size_t) totalsize)) { + log_error("%s: failed to write %u + %d - wrote %u + %u", __FUNCTION__, + (unsigned int) sizeof(checksum), totalsize, (unsigned int) ws1, (unsigned int) ws2); + return GS_ERROR_IO; + } + } + } + + return error; +} + +gs_error_t gs_rparam_get_full_table(gs_param_table_instance_t * tinst, + uint8_t node, + gs_param_table_id_t table_id, + uint16_t checksum, + uint32_t timeout_ms) +{ + GS_CHECK_HANDLE(tinst != NULL); + GS_CHECK_HANDLE(tinst->rows != NULL); + GS_CHECK_HANDLE(tinst->memory != NULL); + + unsigned int expected_bytes = 0; + { + unsigned int param_pos = 0; + gs_error_t error = gs_param_serialize_full_table(tinst, ¶m_pos, GS_PARAM_SF_DRY_RUN, NULL, 10000, &expected_bytes); + if (error) { + return error; + } + } + + gs_rparam_query_t * query; + csp_packet_t * request = csp_buffer_get(RPARAM_QUERY_LENGTH(query, 0)); + if (request == NULL) { + return GS_ERROR_NO_BUFFERS; + } + + csp_conn_t * conn = csp_connect(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, CSP_O_CRC32); + if (!conn) { + csp_buffer_free(request); + return GS_ERROR_IO; + } + + query = (gs_rparam_query_t *) request->data; + query->action = RPARAM_GET; + query->table_id = table_id; + query->length = 0; // == get full table + query->checksum = csp_hton16(checksum); + query->seq = 0; + query->total = 0; + + request->length = RPARAM_QUERY_LENGTH(query, 0); + if (!csp_send(conn, request, timeout_ms)) { + csp_buffer_free(request); + csp_close(conn); + return GS_ERROR_IO; + } + + csp_packet_t * reply; + gs_error_t error = GS_OK; + unsigned int total_bytes = 0; + while ((reply = csp_read(conn, timeout_ms)) != NULL) { + + /* We have a reply */ + query = (void *) reply->data; + const uint16_t qlength = csp_ntoh16(query->length); + total_bytes += qlength; + const uint16_t seq = csp_ntoh16(query->seq); + const uint16_t total = csp_ntoh16(query->total); + + if (query->action == RPARAM_REPLY) { + error = gs_param_deserialize(tinst, query->payload.packed, qlength, F_FROM_BIG_ENDIAN); + } + csp_buffer_free(reply); + + if (error || (seq >= total)) { + break; + } + } + + if (reply == NULL) { + error = GS_ERROR_TIMEOUT; + } + + if ((error == GS_OK) && (expected_bytes != total_bytes)) { + log_warning("%s: expected %u != received %u bytes", __FUNCTION__, expected_bytes, total_bytes); + error = GS_ERROR_DATA; + } + + csp_close(conn); + + return error; +} + +gs_error_t gs_rparam_get(uint8_t node, + gs_param_table_id_t table_id, + uint16_t addr, + gs_param_type_t type, + uint16_t checksum, + uint32_t timeout_ms, + void * value, + size_t value_size) +{ + /* Calculate length */ + gs_rparam_query_t * query; + const size_t query_size = RPARAM_QUERY_LENGTH(query, sizeof(query->payload.addr[0])); + const size_t reply_payload_size = (value_size + sizeof(query->payload.addr[0])); + const size_t reply_size = RPARAM_QUERY_LENGTH(query, reply_payload_size); + + query = alloca(reply_size); + query->action = RPARAM_GET; + query->table_id = table_id; + query->checksum = csp_hton16(checksum); + query->seq = 0; + query->total = 0; + query->payload.addr[0] = csp_hton16(addr); + query->length = csp_hton16(sizeof(query->payload.addr[0])); + + /* Run single packet transaction */ + if (csp_transaction2(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, query, query_size, query, reply_size, CSP_O_CRC32) <= 0) { + return GS_ERROR_IO; + } + + /* We have a reply */ + query->length = csp_ntoh16(query->length); + + if (query->length != reply_payload_size) { + log_warning("%s: Invalid reply size %u - expected %u", __FUNCTION__, query->length, (unsigned int) reply_payload_size); + return GS_ERROR_DATA; + } + + /* Read address */ + query->payload.addr[0] = csp_betoh16(query->payload.addr[0]); + if (query->payload.addr[0] != addr) { + log_warning("%s: Invalid address in reply %u", __FUNCTION__, query->payload.addr[0]); + return GS_ERROR_DATA; + } + + /* Read value */ + memcpy(value, &query->payload.packed[2], value_size); + gs_param_betoh(type, value); + + return GS_OK; +} + +gs_error_t gs_rparam_set(uint8_t node, + gs_param_table_id_t table_id, + uint16_t addr, + gs_param_type_t type, + uint16_t checksum, + uint32_t timeout_ms, + const void * value, + size_t value_size) +{ + /* Calculate length */ + gs_rparam_query_t * query; + const size_t payload_size = (value_size + sizeof(query->payload.addr[0])); + const size_t query_size = RPARAM_QUERY_LENGTH(query, payload_size); + + query = alloca(query_size); + query->action = RPARAM_SET; + query->table_id = table_id; + query->seq = 0; + query->total = 0; + query->checksum = csp_hton16(checksum); + + /* Actual set query */ + unsigned int bytes = 0; + gs_error_t error = gs_param_serialize_item_direct(type, value_size, addr, value, F_TO_BIG_ENDIAN, query->payload.packed, payload_size, &bytes); + if (error) { + return error; + } + + /* Add to query */ + query->length = csp_hton16(bytes); + + /* Run single packet transaction */ + if (csp_transaction2(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, query, query_size, query, 1, CSP_O_CRC32) <= 0) { + return GS_ERROR_IO; + } + + /* We have a reply */ + query->length = csp_ntoh16(query->length); + + if ((query->action != RPARAM_SET_OK) || (query->length != bytes)) { + log_warning("%s: Invalid reply: size %u - expected %u, action %u - expected %u", + __FUNCTION__, query->length, bytes, query->action, RPARAM_SET_OK); + return GS_ERROR_DATA; + } + + return GS_OK; +} + +gs_error_t gs_rparam_query_get_value(gs_param_table_instance_t * tinst, const char* param_name, uint16_t param_no, void* val_p, size_t val_size) +{ + const gs_param_table_row_t * t = gs_param_row_by_name(param_name, tinst->rows, tinst->row_count); + if (t == NULL) { + return GS_ERROR_NOT_FOUND; + } + + if (val_size < t->size) { + return GS_ERROR_OVERFLOW; + } + + return gs_param_get(tinst, t->addr + (param_no * t->size), t->type, val_p, t->size, 0); +} diff --git a/gomspace/libparam_client/src/serialize.c b/gomspace/libparam_client/src/serialize.c new file mode 100644 index 00000000..d55fea98 --- /dev/null +++ b/gomspace/libparam_client/src/serialize.c @@ -0,0 +1,353 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#define GS_PARAM_INTERNAL_USE 1 + +#include "serialize_local.h" +#include +#include +#include +#include +#include +#include +#include + +#include // need PARM_X??? definitions + +bool gs_param_betoh(gs_param_type_t type, void * item) +{ + if (item) { + switch (type) { + case GS_PARAM_UINT16: + case GS_PARAM_INT16: + case PARAM_X16: + { + *(uint16_t *) item = util_betoh16(*(uint16_t *) item); + return true; + } + case GS_PARAM_UINT32: + case GS_PARAM_INT32: + case PARAM_X32: + { + *(uint32_t *) item = util_betoh32(*(uint32_t *) item); + return true; + } + case GS_PARAM_UINT64: + case GS_PARAM_INT64: + case PARAM_X64: + { + *(uint64_t *) item = util_betoh64(*(uint64_t *) item); + return true; + } + case GS_PARAM_FLOAT: + { + *(float *) item = util_ntohflt(*(float *) item); + return true; + } + case GS_PARAM_DOUBLE: + { + *(double *) item = util_ntohdbl(*(double *) item); + return true; + } + + case GS_PARAM_UINT8: + case GS_PARAM_INT8: + case PARAM_X8: + case GS_PARAM_STRING: + case GS_PARAM_DATA: + case GS_PARAM_BOOL: + // no swap + break; + } + } + return false; +} + +bool gs_param_htobe(gs_param_type_t type, void * item) +{ + if (item) { + switch (type) { + case PARAM_UINT16: + case PARAM_INT16: + case PARAM_X16: + { + *(uint16_t *) item = util_htobe16(*(uint16_t *) item); + return true; + } + case PARAM_UINT32: + case PARAM_INT32: + case PARAM_X32: + { + *(uint32_t *) item = util_htobe32(*(uint32_t *) item); + return true; + } + case PARAM_UINT64: + case PARAM_INT64: + case PARAM_X64: + { + *(uint64_t *) item = util_htobe64(*(uint64_t *) item); + return true; + } + case PARAM_FLOAT: + { + *(float *) item = util_htonflt(*(float *) item); + return true; + } + case PARAM_DOUBLE: + { + *(double *) item = util_htondbl(*(double *) item); + return true; + } + + case PARAM_UINT8: + case PARAM_INT8: + case PARAM_X8: + case PARAM_STRING: + case PARAM_DATA: + case PARAM_BOOL: + // no swap + break; + } + } + return false; +} + +static bool gs_param_require_endian_swap(gs_param_type_t type) +{ + switch (type) { + case PARAM_UINT16: + case PARAM_INT16: + case PARAM_X16: + case PARAM_UINT32: + case PARAM_INT32: + case PARAM_X32: + case PARAM_UINT64: + case PARAM_INT64: + case PARAM_X64: + case PARAM_FLOAT: + case PARAM_DOUBLE: + // swap + break; + + case PARAM_UINT8: + case PARAM_INT8: + case PARAM_X8: + case PARAM_STRING: + case PARAM_DATA: + case PARAM_BOOL: + // no swap + return false; + + default: + break; + } + return true; +} + +static gs_error_t gs_param_serialize_array(gs_param_table_instance_t * tinst, const gs_param_table_row_t * param, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos) +{ + const unsigned int param_size = GS_PARAM_SIZE(param); + const unsigned int param_array_size = GS_PARAM_ARRAY_SIZE(param); + const gs_param_type_t param_type = GS_PARAM_TYPE(param); + + /* Calculate total parameter size (full array) */ + { + unsigned int size = param_size * param_array_size; + if ((flags & F_PACKED) == 0) { + size += param_array_size * sizeof(uint16_t); // address + } + + /* Return if parameter array would exceed maxbuf */ + if (*buf_pos + size > buf_size) { + return GS_ERROR_OVERFLOW; + } + } + + uint8_t value[param_size]; + gs_error_t error = GS_OK; + for (unsigned int j = 0; (j < param_array_size) && (error == GS_OK); j++) { + const uint16_t addr = GS_PARAM_ADDR(param) + (param_size * j); + error = gs_param_get(tinst, addr, param_type, value, param_size, 0); + if (error == GS_OK) { + error = gs_param_serialize_item(param, addr, value, flags, buf, buf_size, buf_pos); + } + } + + return error; +} + +gs_error_t gs_param_serialize_item_direct(gs_param_type_t param_type, unsigned int param_size, uint16_t addr, const void * item, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos) +{ + /* Check length */ + if ((((flags & F_PACKED) ? 0 : sizeof(addr)) + param_size + *buf_pos) > buf_size) { + return GS_ERROR_OVERFLOW; + } + + /* Include address if not packed */ + if ((flags & F_PACKED) == 0) { + + if (flags & F_TO_BIG_ENDIAN) { + addr = util_htobe16(addr); + } + + if ((flags & F_DRY_RUN) == 0) { + memcpy(&buf[*buf_pos], &addr, sizeof(addr)); + } + + *buf_pos += sizeof(addr); + } + + if ((flags & F_DRY_RUN) == 0) { + if (flags & F_TO_BIG_ENDIAN) { + void * tmp = alloca(param_size); // this must be aligned + memcpy(tmp, item, param_size); + gs_param_htobe(param_type, tmp); + item = tmp; + } + memcpy(&buf[*buf_pos], item, param_size); + } + + *buf_pos += param_size; + + return GS_OK; +} + +gs_error_t gs_param_serialize_item(const gs_param_table_row_t * param, uint16_t addr, const void * item, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos) +{ + const gs_param_type_t param_type = GS_PARAM_TYPE(param); + const unsigned int param_size = GS_PARAM_SIZE(param); + return gs_param_serialize_item_direct(param_type, param_size, addr, item, flags, buf, buf_size, buf_pos); +} + +gs_error_t gs_param_serialize_full_table(gs_param_table_instance_t * tinst, unsigned int * param_pos, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos) +{ + if (flags & GS_PARAM_SF_DRY_RUN) { + buf = NULL; + buf_size = -1; // Max size + } + gs_error_t error = GS_OK; + unsigned int i = *param_pos; + for (; i < tinst->row_count; i++) { + const gs_param_table_row_t * param = &tinst->rows[i]; + error = gs_param_serialize_array(tinst, param, flags, buf, buf_size, buf_pos); + if (error) { + break; + } + } + *param_pos = i; + return error; +} + +gs_error_t gs_param_serialize_list(gs_param_table_instance_t * tinst, + const uint16_t addr[], unsigned int addr_count, + unsigned int * param_pos, uint32_t flags, + uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos) +{ + if (tinst == NULL) { + return GS_ERROR_HANDLE; + } + + gs_error_t error = GS_OK; + unsigned int i = *param_pos; + for (; i < addr_count; ++i) { + const gs_param_table_row_t * param = gs_param_row_by_address(addr[i], tinst->rows, tinst->row_count); + if (param == NULL) { + continue; + } + + const gs_param_type_t param_type = GS_PARAM_TYPE(param); + const unsigned int param_size = GS_PARAM_SIZE(param); + uint8_t value[param_size]; + error = gs_param_get(tinst, addr[i], param_type, value, param_size, 0); + if (error) { + break; + } + error = gs_param_serialize_item(param, addr[i], value, flags, buf, buf_size, buf_pos); + if (error) { + break; + } + } + *param_pos = i; + + return error; +} + +gs_error_t gs_param_deserialize_item(gs_param_table_instance_t * tinst, + const gs_param_table_row_t * param, + uint16_t addr, + const void * item, + uint32_t flags) +{ + const gs_param_type_t param_type = GS_PARAM_TYPE(param); + const unsigned int param_size = GS_PARAM_SIZE(param); + + if (flags & F_FROM_BIG_ENDIAN) { + if (gs_param_require_endian_swap(param_type)) { + + // Copy to temporary storage, so we don't mess with input memory + void * tmp = alloca(param_size); + memcpy(tmp, item, param_size); + + gs_param_betoh(param_type, tmp); + + // Replace input pointer + item = tmp; + } + } + + gs_error_t error = GS_OK; + if ((flags & F_DRY_RUN) == 0) { + error = gs_param_set(tinst, addr, param_type, item, param_size, GS_PARAM_FLAGS(param)); + } + + return error; +} + +gs_error_t gs_param_deserialize(gs_param_table_instance_t * tinst, const uint8_t * buf, unsigned int buf_size, uint32_t flags) +{ + unsigned int pos = 0; + unsigned int count = 0; + gs_error_t error = GS_OK; + while ((pos < buf_size) && (error == GS_OK)) { + + if (flags & F_PACKED) { + /** PACKED */ + + /* Find in table */ + const gs_param_table_row_t * param = &tinst->rows[count]; + const unsigned int param_array_size = GS_PARAM_ARRAY_SIZE(param); + const unsigned int param_size = GS_PARAM_SIZE(param); + + /* For each item in array */ + for (unsigned int j = 0; (j < param_array_size) && (error == GS_OK); j++) { + uint16_t addr = GS_PARAM_ADDR(param) + (param_size * j); + error = gs_param_deserialize_item(tinst, param, addr, &buf[pos], flags); + pos += param_size; + } + + } else { + /** NOT PACKED */ + + /* Read address from data */ + uint16_t addr; + memcpy(&addr, &buf[pos], sizeof(addr)); + if (flags & F_FROM_BIG_ENDIAN) { + addr = util_betoh16(addr); + } + pos += sizeof(addr); + + /* Find in table */ + const gs_param_table_row_t * param = gs_param_row_by_address(addr, tinst->rows, tinst->row_count); + if (param == NULL) { + return GS_ERROR_NOT_FOUND; + } + + /* Copy value */ + error = gs_param_deserialize_item(tinst, param, addr, &buf[pos], flags); + pos += GS_PARAM_SIZE(param); + } + + count++; + } + + return error; +} diff --git a/gomspace/libparam_client/src/serialize_local.h b/gomspace/libparam_client/src/serialize_local.h new file mode 100644 index 00000000..15de4a51 --- /dev/null +++ b/gomspace/libparam_client/src/serialize_local.h @@ -0,0 +1,9 @@ +#ifndef SRC_SERIALIZE_LOCAL_H +#define SRC_SERIALIZE_LOCAL_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +gs_error_t gs_param_serialize_item_direct(gs_param_type_t param_type, unsigned int param_size, uint16_t addr, const void * item, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos); + +#endif diff --git a/gomspace/libparam_client/src/string.c b/gomspace/libparam_client/src/string.c new file mode 100644 index 00000000..ddbc5094 --- /dev/null +++ b/gomspace/libparam_client/src/string.c @@ -0,0 +1,589 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#define GS_PARAM_INTERNAL_USE 1 + +#include +#include +#include +#include +#include +#include +#include + +size_t gs_param_calc_table_size(const gs_param_table_row_t * rows, size_t row_count) +{ + if (rows && row_count) { + const gs_param_table_row_t * last_row = rows; + // table rows may not be in assending address- so we have to run through the entire table. + for (size_t i = 0; i < row_count; ++i, ++rows) { + if (GS_PARAM_ADDR(rows) > GS_PARAM_ADDR(last_row)) { + last_row = rows; + } + } + return (GS_PARAM_ADDR(last_row) + (GS_PARAM_SIZE(last_row) * GS_PARAM_ARRAY_SIZE(last_row))); + } + return 0; +} + +const gs_param_table_row_t * gs_param_row_by_name(const char * name, const gs_param_table_row_t * rows, size_t row_count) +{ + if (rows) { + for (unsigned int i = 0; i < row_count; ++i, ++rows) { + if (GS_PGM_STRNCASECMP(name, rows->name, GS_PARAM_MAX_NAME) == 0) { + return rows; + } + } + } + return NULL; +} + +const gs_param_table_row_t * gs_param_row_by_address(uint16_t addr, const gs_param_table_row_t * rows, size_t row_count) +{ + if (rows) { + for (unsigned int i = 0; i < row_count; ++i, ++rows) { + const unsigned int param_array_size = GS_PARAM_ARRAY_SIZE(rows); + const unsigned int param_size = GS_PARAM_SIZE(rows); + const unsigned int param_addr = GS_PARAM_ADDR(rows); + for (unsigned int j = 0; j < param_array_size; ++j) { + if ((param_addr + (j * param_size)) == addr) { + return rows; + } + } + } + } + return NULL; +} + +/** + memcpy is used, because data/value may not be aligned correctly and cause crash if accessed directly. +*/ +gs_error_t gs_param_to_string_buffer(const gs_param_table_row_t * param, const void * value, bool with_type, uint32_t flags, gs_bytebuffer_t *bb) +{ + flags |= param->flags; + const uint8_t param_type = GS_PARAM_TYPE(param); + switch (param_type) { + case GS_PARAM_BOOL: { + if (with_type == 1) { + gs_bytebuffer_printf(bb, "BL "); + } + gs_bytebuffer_printf(bb, "%s", *(uint8_t *) value ? "true" : "false"); + break; + } + case GS_PARAM_INT8: { + if (with_type == 1) { + gs_bytebuffer_printf(bb, "I8 "); + } + gs_bytebuffer_printf(bb, "%d", *(int8_t *) value); + break; + } + case PARAM_X8: + flags |= GS_PARAM_F_SHOW_HEX; + // fallthrough + case GS_PARAM_UINT8: { + if (with_type == 1) { + gs_bytebuffer_printf(bb, "U8 "); + } + if (flags & GS_PARAM_F_SHOW_HEX) { + gs_bytebuffer_printf(bb, "0x%02"PRIx8, *(uint8_t *) value); + } else { + gs_bytebuffer_printf(bb, "%u", *(uint8_t *) value); + } + break; + } + case GS_PARAM_INT16: { + int16_t tmp; + memcpy(&tmp, value, sizeof(tmp)); + if (with_type == 1) { + gs_bytebuffer_printf(bb, "I16 "); + } + gs_bytebuffer_printf(bb, "%"PRId16, tmp); + break; + } + case PARAM_X16: + flags |= GS_PARAM_F_SHOW_HEX; + // fallthrough + case GS_PARAM_UINT16: { + uint16_t tmp; + memcpy(&tmp, value, sizeof(tmp)); + if (with_type == 1) { + gs_bytebuffer_printf(bb, "U16 "); + } + if (flags & GS_PARAM_F_SHOW_HEX) { + gs_bytebuffer_printf(bb, "0x%04"PRIx16, tmp); + } else { + gs_bytebuffer_printf(bb, "%"PRIu16, tmp); + } + break; + } + case GS_PARAM_INT32: { + int32_t tmp; + memcpy(&tmp, value, sizeof(tmp)); + if (with_type == 1) { + gs_bytebuffer_printf(bb, "I32 "); + } + gs_bytebuffer_printf(bb, "%"PRId32, tmp); + break; + } + case PARAM_X32: + flags |= GS_PARAM_F_SHOW_HEX; + // fallthrough + case GS_PARAM_UINT32: { + uint32_t tmp; + memcpy(&tmp, value, sizeof(tmp)); + if (with_type == 1) { + gs_bytebuffer_printf(bb, "U32 "); + } + if (flags & GS_PARAM_F_SHOW_HEX) { + gs_bytebuffer_printf(bb, "0x%08"PRIx32, tmp); + } else { + gs_bytebuffer_printf(bb, "%"PRIu32, tmp); + } + break; + } +#ifdef PRIu64 + case GS_PARAM_INT64: { + int64_t tmp; + memcpy(&tmp, value, sizeof(tmp)); + if (with_type == 1) { + gs_bytebuffer_printf(bb, "I64 "); + } + gs_bytebuffer_printf(bb, "%"PRId64, tmp); + break; + } + case PARAM_X64: + flags |= GS_PARAM_F_SHOW_HEX; + // fallthrough + case GS_PARAM_UINT64: { + uint64_t tmp; + memcpy(&tmp, value, sizeof(tmp)); + if (with_type == 1) { + gs_bytebuffer_printf(bb, "U64 "); + } + if (flags & GS_PARAM_F_SHOW_HEX) { + gs_bytebuffer_printf(bb, "0x%016"PRIx64, tmp); + } else { + gs_bytebuffer_printf(bb, "%"PRIu64, tmp); + } + break; + } +#endif + case GS_PARAM_FLOAT: { + float tmp; + memcpy(&tmp, value, sizeof(tmp)); + if (with_type == 1) { + gs_bytebuffer_printf(bb, "FLT "); + } + if (flags & GS_PARAM_F_SHOW_SCIENTIFIC) { + gs_bytebuffer_printf(bb, "%e", (double) tmp); + } else { + gs_bytebuffer_printf(bb, "%f", (double) tmp); + } + break; + } + case GS_PARAM_DOUBLE: { + double tmp; + memcpy(&tmp, value, sizeof(tmp)); + if (with_type == 1) { + gs_bytebuffer_printf(bb, "DBL "); + } + if (flags & GS_PARAM_F_SHOW_SCIENTIFIC) { + gs_bytebuffer_printf(bb, "%e", tmp); + } else { + gs_bytebuffer_printf(bb, "%f", tmp); + } + break; + } + case GS_PARAM_STRING: { + if (with_type == 1) { + gs_bytebuffer_printf(bb, "STR "); + } + gs_bytebuffer_append(bb, "\"", 1); + // handle missing NUL termination. + const size_t len = strnlen((const char*)value, GS_PARAM_SIZE(param)); + gs_bytebuffer_append(bb, value, len); + gs_bytebuffer_append(bb, "\"", 1); + break; + } + case GS_PARAM_DATA: { + if (with_type == 1) { + gs_bytebuffer_printf(bb, "DAT "); + } + for (int i = 0; i < GS_PARAM_SIZE(param); i++) { + gs_bytebuffer_printf(bb, "%02"PRIX8, ((uint8_t *) value)[i]); + } + break; + } + default: { + log_error("%s: Unknown param type %u", __FUNCTION__, param_type); + break; + } + } + + return GS_OK; +} + +gs_error_t gs_param_to_string2(const gs_param_table_row_t * param, const void * value, bool with_type, uint32_t flags, char * buf, unsigned int buf_size, unsigned int buf_pos, unsigned int * buf_written) +{ + GS_CHECK_ARG(buf_pos <= buf_size); + gs_bytebuffer_t bb; + gs_bytebuffer_init(&bb, &buf[buf_pos], (buf_size - buf_pos)); + gs_error_t error = gs_param_to_string_buffer(param, value, with_type, flags, &bb); + if (error == GS_OK) { + gs_bytebuffer_get_as_string(&bb, &error); // this will add NUL termination, but may truncate buffer + error = gs_bytebuffer_get_state(&bb); + if (buf_written) { + *buf_written = bb.used; + } + } + return error; +} + +const char * gs_param_type_to_string(gs_param_type_t type) +{ + switch (type) { + case GS_PARAM_BOOL: return "bool"; + case GS_PARAM_UINT8: return "uint8_t"; + case GS_PARAM_UINT16: return "uint16_t"; + case GS_PARAM_UINT32: return "uint32_t"; + case GS_PARAM_UINT64: return "uint65_t"; + case GS_PARAM_INT8: return "int8_t"; + case GS_PARAM_INT16: return "int16_t"; + case GS_PARAM_INT32: return "int32_t"; + case GS_PARAM_INT64: return "int64_t"; + case PARAM_X8: return "uint8_t"; + case PARAM_X16: return "uint16_t"; + case PARAM_X32: return "uint32_t"; + case PARAM_X64: return "uint64_t"; + case GS_PARAM_FLOAT: return "float"; + case GS_PARAM_DOUBLE: return "double"; + case GS_PARAM_STRING: return "char"; + case GS_PARAM_DATA: return "char"; + } + return ""; +} + +static inline int to_int(char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'A' && c <= 'F') return 10 + c - 'A'; + if (c >= 'a' && c <= 'f') return 10 + c - 'a'; + return -1; +} + +gs_error_t gs_param_from_string(const gs_param_table_row_t * param, const char * string, void * value) +{ + if ((param == NULL) || (string == NULL) || (value == NULL)) { + return GS_ERROR_ARG; + } + + if (GS_PARAM_TYPE(param) != GS_PARAM_STRING) { + // skip only space - not white-space, e.g. isspace() + for (; *string == ' '; ++string); + } + + gs_error_t error = GS_OK; + + switch(GS_PARAM_TYPE(param)) { + + case GS_PARAM_BOOL: + { + bool parsein = false; + error = gs_string_to_bool(string, &parsein); + if (error == GS_OK) { + *((uint8_t *) value) = parsein; + } + } + break; + + case GS_PARAM_UINT8: + { + uint8_t parsein; + error = gs_string_to_uint8(string, &parsein); + if (error == GS_OK) { + *((uint8_t *) value) = parsein; + } + } + break; + + case GS_PARAM_UINT16: + { + uint16_t parsein; + error = gs_string_to_uint16(string, &parsein); + if (error == GS_OK) { + *((uint16_t *) value) = parsein; + } + } + break; + + case GS_PARAM_UINT32: + { + uint32_t parsein; + error = gs_string_to_uint32(string, &parsein); + if (error == GS_OK) { + *((uint32_t *) value) = parsein; + } + } + break; + + case GS_PARAM_UINT64: + { + uint64_t parsein; + error = gs_string_to_uint64(string, &parsein); + if (error == GS_OK) { + *((uint64_t *) value) = parsein; + } + } + break; + + case GS_PARAM_INT8: + { + int8_t parsein; + error = gs_string_to_int8(string, &parsein); + if (error == GS_OK) { + *((int8_t *) value) = parsein; + } + } + break; + + case GS_PARAM_INT16: + { + int16_t parsein; + error = gs_string_to_int16(string, &parsein); + if (error == GS_OK) { + *((int16_t *) value) = parsein; + } + } + break; + + case GS_PARAM_INT32: + { + int32_t parsein; + error = gs_string_to_int32(string, &parsein); + if (error == GS_OK) { + *((int32_t *) value) = parsein; + } + } + break; + + case GS_PARAM_INT64: + { + int64_t parsein; + error = gs_string_to_int64(string, &parsein); + if (error == GS_OK) { + *((int64_t *) value) = parsein; + } + } + break; + + case PARAM_X8: + { + uint32_t parsein; + error = gs_string_hex_to_uint32(string, &parsein); + if (error == GS_OK) { + if (parsein <= UINT8_MAX) { + *((uint8_t *) value) = parsein; + } else { + error = GS_ERROR_OVERFLOW; + } + } + } + break; + + case PARAM_X16: + { + uint32_t parsein; + error = gs_string_hex_to_uint32(string, &parsein); + if (error == GS_OK) { + if (parsein <= UINT16_MAX) { + *((uint16_t *) value) = parsein; + } else { + error = GS_ERROR_OVERFLOW; + } + } + } + break; + + case PARAM_X32: + { + uint32_t parsein; + error = gs_string_hex_to_uint32(string, &parsein); + if (error == GS_OK) { + *((uint32_t *) value) = parsein; + } + } + break; + + case PARAM_X64: + { + uint64_t parsein; + error = gs_string_hex_to_uint64(string, &parsein); + if (error == GS_OK) { + *((uint64_t *) value) = parsein; + } + } + break; + + case GS_PARAM_FLOAT: + { + float parsein; + error = gs_string_to_float(string, &parsein); + if (error == GS_OK) { + *((float *) value) = parsein; + } + } + break; + + case GS_PARAM_DOUBLE: + { + double parsein; + error = gs_string_to_double(string, &parsein); + if (error == GS_OK) { + *((double *) value) = parsein; + } + } + break; + + case GS_PARAM_STRING: + { + const size_t ilen = strnlen(string, GS_PARAM_SIZE(param) + 1); // 0 terminator + if (ilen <= GS_PARAM_SIZE(param)) { + memset(value, 0, GS_PARAM_SIZE(param)); + memcpy(value, string, ilen); + } else { + error = GS_ERROR_OVERFLOW; + } + } + break; + + case GS_PARAM_DATA: + { + const size_t MAX_LEN = (GS_PARAM_SIZE(param) * 2); + const size_t ilen = strnlen(string, MAX_LEN + 1); + if (ilen > MAX_LEN) { + error = GS_ERROR_OVERFLOW; + } else if ((ilen % 2) == 0) { + + // validate data first - not to end up with invalid/strange data + for (unsigned int i = 0; i < ilen; ++i) { + if (to_int(string[i]) < 0) { + error = GS_ERROR_DATA; + break; + } + } + if (error == GS_OK) { + uint8_t * out = (uint8_t *) value; + memset(out, 0, GS_PARAM_SIZE(param)); + for (unsigned int i = 0; i < ilen; i += 2, ++out) { + *out = (16 * to_int(string[i])) + to_int(string[i+1]); + } + error = GS_OK; + } + } else { + error = GS_ERROR_DATA; + } + } + break; + } + + return error; +} + +gs_error_t gs_param_list_single_to_stream(gs_param_table_instance_t * tinst, const gs_param_table_row_t * param, + bool list_data, uint32_t flags, FILE * out) +{ + if (param == NULL) { + return GS_ERROR_HANDLE; + } + + gs_error_t error = GS_OK; + const uint16_t addr = GS_PARAM_ADDR(param); + + fprintf(out, " 0x%04X %-16.14"GS_PGM_FMT_STR, addr, param->name); // ensure missing NUL termination doesn't cause problems. + + if (list_data) { + const gs_param_type_t param_type = GS_PARAM_TYPE(param); + const unsigned int param_array_size = GS_PARAM_ARRAY_SIZE(param); + const unsigned int param_size = GS_PARAM_SIZE(param); + uint8_t value[param_size]; + char buf[100]; + for (unsigned int j = 0; (j < param_array_size) && (error == GS_OK); j++) { + error = gs_param_get(tinst, addr + (param_size * j), param_type, value, param_size, 0); + if (error == GS_OK) { + gs_param_to_string2(param, value, (j == 0) ? 1 : 0, flags, buf, sizeof(buf), 0, NULL); + fprintf(out, "%s ", buf); + } + } + } + fprintf(out, "\r\n"); + return error; +} + +gs_error_t gs_param_list_to_stream(gs_param_table_instance_t * tinst, bool list_data, uint32_t flags, FILE * out) +{ + GS_CHECK_HANDLE(tinst != NULL); + + gs_error_t error = GS_OK; + for (unsigned int i = 0; (i < tinst->row_count) && (error == GS_OK); ++i) { + error = gs_param_list_single_to_stream(tinst, &tinst->rows[i], list_data, flags, out); + } + + return error; +} + +gs_error_t gs_param_parse_name_and_array_index(const char * inp, char * name, size_t size_name, uint8_t * return_index, bool * return_is_array) +{ + if (inp == NULL) { + return GS_ERROR_ARG; + } + + uint8_t a_index; + size_t name_len; + gs_error_t error; + bool is_array; + const char * pai = strchr(inp, '['); // look for array index + if (pai) { + name_len = pai - inp; + char tmp[20]; + GS_STRNCPY(tmp, pai+1); + char * endp = strchr(tmp, ']'); + if (endp) { + *endp = 0; + } + error = gs_string_to_uint8(tmp, &a_index); + is_array = true; + } else { + error = GS_OK; + name_len = strlen(inp); + is_array = false; + a_index = 0; + } + + if (error == GS_OK) { + if (name_len >= size_name) { + error = GS_ERROR_OVERFLOW; + } else { + strncpy(name, inp, name_len); + name[name_len] = 0; + + // remove trailing white-space + if (name_len) { + for (int i = name_len-1; i >= 0; --i) { + if (name[i] && isspace((int)name[i])) { + name[i] = 0; + } else { + break; + } + } + } + + if (return_index) { + *return_index = (is_array) ? a_index : 0; + } + if (return_is_array) { + *return_is_array = is_array; + } + } + } + + return error; +} diff --git a/gomspace/libparam_client/src/table.c b/gomspace/libparam_client/src/table.c new file mode 100644 index 00000000..3aea93ad --- /dev/null +++ b/gomspace/libparam_client/src/table.c @@ -0,0 +1,393 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#define GS_PARAM_INTERNAL_USE 1 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static void _copy_data(gs_param_type_t type, void * dst, const void * src, size_t size) +{ +#if (GS_PARAM_ATOMIC_ACCESS) + switch (type) { + case GS_PARAM_UINT8: + case GS_PARAM_INT8: + case PARAM_X8: + case GS_PARAM_STRING: + case GS_PARAM_DATA: + case GS_PARAM_BOOL: + break; + + case GS_PARAM_UINT16: + case GS_PARAM_INT16: + case PARAM_X16: + if (!((intptr_t)src & 1) && !((intptr_t)dst & 1)) { + // (u)int16 aligned correctly + const uint16_t * s = src; + uint16_t * d = dst; + const unsigned int count = (size / sizeof(*d)); + for (unsigned int i = 0; i < count; ++i, ++d, ++s) { + *d = *s; + } + //printf("%s:int16\r\n", __FUNCTION__); + return; + } + break; + + case GS_PARAM_UINT32: + case GS_PARAM_INT32: + case PARAM_X32: + case GS_PARAM_FLOAT: + if (!((intptr_t)src & 3) && !((intptr_t)dst & 3)) { + // (u)int32 aligned correctly + const uint32_t * s = src; + uint32_t * d = dst; + const unsigned int count = (size / sizeof(*d)); + for (unsigned int i = 0; i < count; ++i, ++d, ++s) { + *d = *s; + } + //printf("%s:int32\r\n", __FUNCTION__); + return; + } + break; + + case GS_PARAM_UINT64: + case GS_PARAM_INT64: + case PARAM_X64: + case GS_PARAM_DOUBLE: + break; + } +#endif + + // fallback - do byte copy + memcpy(dst, src, size); +} + +gs_error_t gs_param_table_lock(gs_param_table_instance_t * tinst) +{ + if (tinst->lock) { + return gs_mutex_lock(tinst->lock); + } + return GS_OK; +} + +gs_error_t gs_param_table_unlock(gs_param_table_instance_t * tinst) +{ + if (tinst->lock) { + return gs_mutex_unlock(tinst->lock); + } + return GS_OK; +} + +static gs_error_t gs_param_table_lock_free(gs_param_table_instance_t * tinst) +{ + if (tinst && tinst->lock) { + gs_mutex_destroy(tinst->lock); + tinst->lock = NULL; + } + return GS_OK; +} + +gs_error_t gs_param_table_free(gs_param_table_instance_t * tinst) +{ + if (tinst) { + if (tinst->flags & GS_PARAM_TABLE_F_ALLOC_MEMORY) { + free(tinst->memory); + } + if (tinst->flags & GS_PARAM_TABLE_F_ALLOC_ROWS) { + free((void*)tinst->rows); + } + if (tinst->lock) { + gs_param_table_lock_free(tinst); + } + memset(tinst, 0, sizeof(*tinst)); + } + return GS_OK; +} + +static void checksum_update(gs_param_table_instance_t * tinst) +{ + const uint16_t no_swap = gs_fletcher16(tinst->rows, (sizeof(*tinst->rows) * tinst->row_count)); + + // fletcher16 with swapped fields > 1 byte + gs_fletcher16_t f16; + gs_fletcher16_init(&f16); + for (unsigned int i = 0; i < tinst->row_count; ++i) { + gs_param_table_row_t row = tinst->rows[i]; + row.addr = gs_bswap_16(row.addr); + gs_fletcher16_update(&f16, &row, sizeof(row)); + } + const uint16_t swap = gs_fletcher16_finalize(&f16); + + if (gs_endian_big()) { + tinst->checksum_be = no_swap; + tinst->checksum_le = swap; + } else { + tinst->checksum_be = swap; + tinst->checksum_le = no_swap; + } +} + +uint16_t gs_param_table_checksum_be(gs_param_table_instance_t * tinst) +{ + if (tinst && tinst->rows && tinst->row_count) { + if (tinst->checksum_be == 0) { + checksum_update(tinst); + } + return tinst->checksum_be; + } + return 0; +} + +uint16_t gs_param_table_checksum_le(gs_param_table_instance_t * tinst) +{ + if (tinst && tinst->rows && tinst->row_count) { + if (tinst->checksum_le == 0) { + checksum_update(tinst); + } + return tinst->checksum_le; + } + return 0; +} + +uint16_t gs_param_table_checksum(gs_param_table_instance_t * tinst) +{ + if (gs_endian_big()) { + return gs_param_table_checksum_be(tinst); + } else { + return gs_param_table_checksum_le(tinst); + } +} + +gs_error_t gs_param_get(gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, void * value, size_t value_size, uint32_t flags) +{ + if (tinst == NULL) { + return GS_ERROR_HANDLE; + } + + if ((addr + value_size) > tinst->memory_size) { + return GS_ERROR_RANGE; + } + + gs_error_t error = GS_ERROR_NOT_SUPPORTED; + if (tinst->function_interface.get) { + error = (tinst->function_interface.get)(tinst->function_interface.context, tinst, addr, type, value, value_size, flags); + } else if (tinst->memory) { + gs_param_table_lock(tinst); + _copy_data(type, value, ((uint8_t*)(tinst->memory)) + addr, value_size); + gs_param_table_unlock(tinst); + error = GS_OK; + } + + if ((error == GS_OK) && (flags & GS_PARAM_SF_TO_BIG_ENDIAN) && !gs_endian_big()) { + gs_param_htobe(type, value); + } + + return error; +} + +gs_error_t gs_param_set(gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, const void * value, size_t value_size, uint32_t flags) +{ + if (tinst == NULL) { + return GS_ERROR_HANDLE; + } + + if ((addr + value_size) > tinst->memory_size) { + return GS_ERROR_RANGE; + } + + if ((flags & GS_PARAM_SF_FROM_BIG_ENDIAN) && !gs_endian_big()) { + void * tmp = alloca(value_size); // this must be aligned + memcpy(tmp, value, value_size); + value = tmp; + gs_param_betoh(type, tmp); + } + + gs_error_t error = GS_ERROR_NOT_SUPPORTED; + if (tinst->function_interface.set) { + error = (tinst->function_interface.set)(tinst->function_interface.context, tinst, addr, type, value, value_size, flags); + } else if (tinst->memory) { + gs_param_table_lock(tinst); + _copy_data(type, ((uint8_t*)(tinst->memory)) + addr, value, value_size); + gs_param_table_unlock(tinst); + + if (tinst->auto_persist.set && (flags & GS_PARAM_F_AUTO_PERSIST)) { + (tinst->auto_persist.set)(tinst, addr, type, value, value_size, flags); + } + error = GS_OK; + } + + // Callbacks + if ((error == GS_OK) && tinst->callback && ((flags & GS_PARAM_F_NO_CALLBACK) == 0)) { + (tinst->callback)(addr, tinst); + } + + return error; +} + +uint8_t gs_param_type_size(gs_param_type_t type) +{ + switch (type) { + case GS_PARAM_UINT8: + case GS_PARAM_INT8: + case PARAM_X8: + case GS_PARAM_STRING: + case GS_PARAM_DATA: + return sizeof(int8_t); + case GS_PARAM_INT16: + case GS_PARAM_UINT16: + case PARAM_X16: + return sizeof(int16_t); + case GS_PARAM_INT32: + case GS_PARAM_UINT32: + case PARAM_X32: + return sizeof(int32_t); + case GS_PARAM_INT64: + case GS_PARAM_UINT64: + case PARAM_X64: + return sizeof(int64_t); + case GS_PARAM_DOUBLE: + return sizeof(double); + case GS_PARAM_FLOAT: + return sizeof(float); + case GS_PARAM_BOOL: + return sizeof(bool); + } + return 0; +} + +void * gs_param_table_get_memory(gs_param_table_instance_t * tinst, size_t * return_size) +{ + if (tinst && tinst->memory) { + if (return_size) { + *return_size = tinst->memory_size; + } + return tinst->memory; + } + return NULL; +} + +const gs_param_table_row_t * gs_param_table_get_rows(gs_param_table_instance_t * tinst, size_t * return_count) +{ + if (tinst && tinst->rows && tinst->row_count) { + if (return_count) { + *return_count = tinst->row_count; + } + return tinst->rows; + } + return NULL; +} + +size_t gs_param_table_instance_size(void) +{ + return sizeof(gs_param_table_instance_t); +} + +gs_param_table_instance_t * gs_param_table_instance_clear(void * var, size_t var_size) +{ + gs_param_table_instance_t * tinst = NULL; + if (var && (var_size >= sizeof(*tinst))) { + tinst = (gs_param_table_instance_t *) var; + memset(tinst, 0, sizeof(*tinst)); + } + return tinst; +} + +gs_param_table_instance_t * gs_param_table_instance_alloc(void) +{ + return calloc(1, sizeof(gs_param_table_instance_t)); +} + +gs_error_t gs_param_get_string(gs_param_table_instance_t * tinst, uint16_t addr, char * buf, size_t buf_size, uint32_t flags) +{ + if (tinst == NULL) { + return GS_ERROR_HANDLE; + } + if (buf == NULL) { + return GS_ERROR_ARG; + } + + const gs_param_table_row_t * param = gs_param_row_by_address(addr, tinst->rows, tinst->row_count); + if (param == NULL) { + return GS_ERROR_RANGE; + } + + if (buf_size <= param->size) { + return GS_ERROR_OVERFLOW; + } + + gs_error_t error = gs_param_get(tinst, addr, param->type, buf, param->size, flags); + buf[param->size] = 0; + return error; +} + +gs_error_t gs_param_set_string(gs_param_table_instance_t * tinst, uint16_t addr, const char * value, uint32_t flags) +{ + if (tinst == NULL) { + return GS_ERROR_HANDLE; + } + if (value == NULL) { + return GS_ERROR_ARG; + } + + const gs_param_table_row_t * param = gs_param_row_by_address(addr, tinst->rows, tinst->row_count); + if (param == NULL) { + return GS_ERROR_RANGE; + } + + const size_t len = strlen(value) + 1; + if (len > GS_PARAM_SIZE(param)) { + return GS_ERROR_OVERFLOW; + } + + return gs_param_set(tinst, addr, param->type, value, len, flags); // flags have full control +} + +gs_error_t gs_param_get_data(gs_param_table_instance_t * tinst, uint16_t addr, void * buf, size_t buf_size, uint32_t flags) +{ + if (tinst == NULL) { + return GS_ERROR_HANDLE; + } + if (buf == NULL) { + return GS_ERROR_ARG; + } + + const gs_param_table_row_t * param = gs_param_row_by_address(addr, tinst->rows, tinst->row_count); + if (param == NULL) { + return GS_ERROR_RANGE; + } + + if (buf_size < param->size) { + return GS_ERROR_OVERFLOW; + } + + return gs_param_get(tinst, addr, param->type, buf, param->size, flags); +} + +gs_error_t gs_param_set_data(gs_param_table_instance_t * tinst, uint16_t addr, const void * value, size_t value_size, uint32_t flags) +{ + if (tinst == NULL) { + return GS_ERROR_HANDLE; + } + if (value == NULL) { + return GS_ERROR_ARG; + } + + const gs_param_table_row_t * param = gs_param_row_by_address(addr, tinst->rows, tinst->row_count); + if (param == NULL) { + return GS_ERROR_RANGE; + } + + if (value_size > GS_PARAM_SIZE(param)) { + return GS_ERROR_OVERFLOW; + } + + return gs_param_set(tinst, addr, param->type, value, value_size, flags); // flags have full control +} diff --git a/gomspace/libparam_client/wscript b/gomspace/libparam_client/wscript new file mode 100644 index 00000000..ea023583 --- /dev/null +++ b/gomspace/libparam_client/wscript @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# encoding: utf-8 +# Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. + +import os +import gs_gcc +import gs_doc + +APPNAME = 'param_client' + + +def options(ctx): + ctx.load('gs_gcc gs_doc') + gs_gcc.gs_recurse(ctx) + + gr = ctx.add_option_group('libparam client options') + gr.add_option('--param_client-disable-cmd', action='store_true', help='Disable GOSH commands') + gr.add_option('--param-enable-atomic-access', action='store_true', help='Enable atomic read/write of 16/32/float') + + +def configure(ctx): + ctx.load('gs_gcc gs_doc') + + ctx.env.append_unique('USE_PARAM_CLIENT', ['gscsp', 'util']) + + ctx.env.append_unique('FILES_PARAM_CLIENT', ['src/*.c', 'src/rparam/*.c', + 'src/pp/*.c', 'src/pp/i2c/*.c', 'src/pp/spi/*.c']) + + if not ctx.options.param_client_disable_cmd: + ctx.env.append_unique('FILES_PARAM_CLIENT', ['src/rparam/cmd/*.c', 'src/pp/cmd/*.c']) + + if ctx.options.param_enable_atomic_access: + ctx.env.append_unique('DEFINES_PARAM_CLIENT', ['GS_PARAM_ATOMIC_ACCESS=1']) + + ctx.gs_register_handler(function='param_gen_4_0', filepath='./tools/waf_param.py') + ctx.gs_register_handler(function='param_gen_4_2', filepath='./tools/waf_param.py') + ctx.gs_register_handler(function='param_gen_4_3', filepath='./tools/waf_param.py') + + ctx.gs_add_doxygen(exclude=['*/include/deprecated/param/*', '*/include/gs/param/internal/*']) + + gs_gcc.gs_recurse(ctx) + + +def build(ctx): + gs_gcc.gs_recurse(ctx) + + public_include = ctx.gs_include(name=APPNAME, + includes=['include', 'include/deprecated', 'include/deprecated/param']) + + if ctx.env.GS_ARCH not in ['avr8']: + ctx.gs_objects(source=ctx.path.ant_glob(ctx.env.FILES_PARAM_CLIENT), + target=APPNAME, + defines=ctx.env.DEFINES_PARAM_CLIENT, + use=ctx.env.USE_PARAM_CLIENT + [public_include]) + + ctx.gs_shlib(source=ctx.path.ant_glob(ctx.env.FILES_PARAM_CLIENT), + target=APPNAME, + defines=ctx.env.DEFINES_PARAM_CLIENT, + gs_use_shlib=ctx.env.USE_PARAM_CLIENT + [public_include]) + + ctx.gs_python_bindings(source=ctx.path.ant_glob('src/bindings/python/pyparam.c'), + target=APPNAME, + gs_use_shlib=ctx.env.USE_PARAM_CLIENT + [APPNAME, public_include], + package='libparam') + + +def gs_dist(ctx): + gs_gcc.gs_recurse(ctx) + ctx.add_default_files(source_module=True) diff --git a/gomspace/libutil/include/conf_util.h b/gomspace/libutil/include/conf_util.h new file mode 100644 index 00000000..d96c3665 --- /dev/null +++ b/gomspace/libutil/include/conf_util.h @@ -0,0 +1,12 @@ +/* WARNING! All changes made to this file will be lost! */ + +#ifndef W_INCLUDE_CONF_UTIL_H_WAF +#define W_INCLUDE_CONF_UTIL_H_WAF + +#define UTIL_LITTLE_ENDIAN 1 +/* #undef UTIL_BIG_ENDIAN */ +#define GS_CONSOLE_HISTORY_LEN 10 +#define GS_CONSOLE_INPUT_LEN 100 +/* #undef GS_LOG_ENABLE_ISR_LOGS */ + +#endif /* W_INCLUDE_CONF_UTIL_H_WAF */ diff --git a/gomspace/libutil/include/deprecated/gs/gosh/command/command.h b/gomspace/libutil/include/deprecated/gs/gosh/command/command.h new file mode 100644 index 00000000..540afea4 --- /dev/null +++ b/gomspace/libutil/include/deprecated/gs/gosh/command/command.h @@ -0,0 +1,49 @@ +#ifndef GS_GOSH_COMMAND_COMMAND_H +#define GS_GOSH_COMMAND_COMMAND_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + Legacy header file - use gs/util/gosh/command.h +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CMD_ERROR_NONE GS_OK +#define CMD_ERROR_FAIL GS_ERROR_UNKNOWN +#define CMD_ERROR_SYNTAX GS_ERROR_ARG +#define CMD_ERROR_NOMEM GS_ERROR_ALLOC +#define CMD_ERROR_INVALID GS_ERROR_DATA +#define CMD_ERROR_NOTFOUND GS_ERROR_NOT_FOUND + +#define CMD_HIDDEN GS_COMMAND_FLAG_HIDDEN + +#define __root_command GS_COMMAND_ROOT +#define __sub_command GS_COMMAND_SUB + +#define INIT_CHAIN(__list) GS_COMMAND_INIT_CHAIN(__list) +#define command_register(__cmd) GS_COMMAND_REGISTER(__cmd) + +typedef struct command command_t; + +static inline const char * command_args(gs_command_context_t *ctx) +{ + return gs_command_args(ctx); +} + +static inline int command_run(char *line) +{ + gs_error_t result = GS_OK; + gs_error_t error = gs_command_run(line, &result); + if (error == GS_OK) { + return result; + } + return error; +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h b/gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h new file mode 100644 index 00000000..e0e40329 --- /dev/null +++ b/gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h @@ -0,0 +1,22 @@ +#ifndef GS_GOSH_GOSH_GETOPT_H +#define GS_GOSH_GOSH_GETOPT_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + Legacy header file - use gs/util/gosh/getopt.h +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline int gosh_getopt(gs_command_context_t *ctx, const char *opts) +{ + return gs_command_getopt(ctx, opts); +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/deprecated/gs/gosh/util/console.h b/gomspace/libutil/include/deprecated/gs/gosh/util/console.h new file mode 100644 index 00000000..a8d1c94d --- /dev/null +++ b/gomspace/libutil/include/deprecated/gs/gosh/util/console.h @@ -0,0 +1,43 @@ +#ifndef GS_GOSH_UTIL_CONSOLE_H +#define GS_GOSH_UTIL_CONSOLE_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + Legacy header file - use gs/util/gosh/console.h +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline int console_init(void) +{ + return gs_console_init(); +} + +static inline int console_exit(void) +{ + return gs_console_exit(); +} + +static inline void console_set_hostname(const char *host) +{ + gs_console_set_prompt(host); +} + +static inline void console_clear(void) +{ + gs_console_clear(); +} + +static inline void console_update(void) +{ + gs_console_update(); +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/deprecated/util/color_printf.h b/gomspace/libutil/include/deprecated/util/color_printf.h new file mode 100644 index 00000000..a2129460 --- /dev/null +++ b/gomspace/libutil/include/deprecated/util/color_printf.h @@ -0,0 +1,26 @@ +#ifndef DEPRECATED_UTIL_COLOR_PRINTF_H +#define DEPRECATED_UTIL_COLOR_PRINTF_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +typedef enum color_printf_e { + /* Colors */ + COLOR_COLORS = GS_COLOR_COLORS, + COLOR_NONE = GS_COLOR_NONE, + COLOR_BLACK = GS_COLOR_BLACK, + COLOR_RED = GS_COLOR_RED, + COLOR_GREEN = GS_COLOR_GREEN, + COLOR_YELLOW = GS_COLOR_YELLOW, + COLOR_BLUE = GS_COLOR_BLUE, + COLOR_MAGENTA = GS_COLOR_MAGENTA, + COLOR_CYAN = GS_COLOR_CYAN, + COLOR_WHITE = GS_COLOR_WHITE, + /* Attributes */ + COLOR_ATTRS = GS_COLOR_ATTRS, + COLOR_BOLD = GS_COLOR_BOLD, +} color_printf_t; + +#define color_printf gs_color_printf + +#endif diff --git a/gomspace/libutil/include/gs/uthash/utarray.h b/gomspace/libutil/include/gs/uthash/utarray.h new file mode 100644 index 00000000..145f3631 --- /dev/null +++ b/gomspace/libutil/include/gs/uthash/utarray.h @@ -0,0 +1,231 @@ +/* +Copyright (c) 2008-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +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. +*/ + +/* a dynamic array implementation using macros + */ +#ifndef UTARRAY_H +#define UTARRAY_H + +#define UTARRAY_VERSION 1.9.9 + +#ifdef __GNUC__ +#define _UNUSED_ __attribute__ ((__unused__)) +#else +#define _UNUSED_ +#endif + +#include /* size_t */ +#include /* memset, etc */ +#include /* exit */ + +#define oom() exit(-1) + +typedef void (ctor_f)(void *dst, const void *src); +typedef void (dtor_f)(void *elt); +typedef void (init_f)(void *elt); +typedef struct { + size_t sz; + init_f *init; + ctor_f *copy; + dtor_f *dtor; +} UT_icd; + +typedef struct { + unsigned i,n;/* i: index of next available slot, n: num slots */ + UT_icd icd; /* initializer, copy and destructor functions */ + char *d; /* n slots of size icd->sz*/ +} UT_array; + +#define utarray_init(a,_icd) do { \ + memset(a,0,sizeof(UT_array)); \ + (a)->icd=*_icd; \ +} while(0) + +#define utarray_done(a) do { \ + if ((a)->n) { \ + if ((a)->icd.dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ + } \ + } \ + free((a)->d); \ + } \ + (a)->n=0; \ +} while(0) + +#define utarray_new(a,_icd) do { \ + a=(UT_array*)malloc(sizeof(UT_array)); \ + utarray_init(a,_icd); \ +} while(0) + +#define utarray_free(a) do { \ + utarray_done(a); \ + free(a); \ +} while(0) + +#define utarray_reserve(a,by) do { \ + if (((a)->i+by) > ((a)->n)) { \ + while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \ + if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd.sz)) == NULL) oom(); \ + } \ +} while(0) + +#define utarray_push_back(a,p) do { \ + utarray_reserve(a,1); \ + if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \ + else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \ +} while(0) + +#define utarray_pop_back(a) do { \ + if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \ + else { (a)->i--; } \ +} while(0) + +#define utarray_extend_back(a) do { \ + utarray_reserve(a,1); \ + if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \ + else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \ + (a)->i++; \ +} while(0) + +#define utarray_len(a) ((a)->i) + +#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL) +#define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd.sz*(j) ))) + +#define utarray_insert(a,p,j) do { \ + if (j > (a)->i) utarray_resize(a,j); \ + utarray_reserve(a,1); \ + if ((j) < (a)->i) { \ + memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd.sz)); \ + } \ + if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \ + else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \ + (a)->i++; \ +} while(0) + +#define utarray_inserta(a,w,j) do { \ + if (utarray_len(w) == 0) break; \ + if (j > (a)->i) utarray_resize(a,j); \ + utarray_reserve(a,utarray_len(w)); \ + if ((j) < (a)->i) { \ + memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \ + _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd.sz)); \ + } \ + if ((a)->icd.copy) { \ + size_t _ut_i; \ + for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \ + (a)->icd.copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \ + } \ + } else { \ + memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \ + utarray_len(w)*((a)->icd.sz)); \ + } \ + (a)->i += utarray_len(w); \ +} while(0) + +#define utarray_resize(dst,num) do { \ + size_t _ut_i; \ + if (dst->i > (size_t)(num)) { \ + if ((dst)->icd.dtor) { \ + for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \ + (dst)->icd.dtor(utarray_eltptr(dst,_ut_i)); \ + } \ + } \ + } else if (dst->i < (size_t)(num)) { \ + utarray_reserve(dst,num-dst->i); \ + if ((dst)->icd.init) { \ + for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \ + (dst)->icd.init(utarray_eltptr(dst,_ut_i)); \ + } \ + } else { \ + memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd.sz*(num-dst->i)); \ + } \ + } \ + dst->i = num; \ +} while(0) + +#define utarray_concat(dst,src) do { \ + utarray_inserta((dst),(src),utarray_len(dst)); \ +} while(0) + +#define utarray_erase(a,pos,len) do { \ + if ((a)->icd.dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < len; _ut_i++) { \ + (a)->icd.dtor(utarray_eltptr((a),pos+_ut_i)); \ + } \ + } \ + if ((a)->i > (pos+len)) { \ + memmove( _utarray_eltptr((a),pos), _utarray_eltptr((a),pos+len), \ + (((a)->i)-(pos+len))*((a)->icd.sz)); \ + } \ + (a)->i -= (len); \ +} while(0) + +#define utarray_renew(a,u) do { \ + if (a) utarray_clear(a); \ + else utarray_new((a),(u)); \ +} while(0) + +#define utarray_clear(a) do { \ + if ((a)->i > 0) { \ + if ((a)->icd.dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ + } \ + } \ + (a)->i = 0; \ + } \ +} while(0) + +#define utarray_sort(a,cmp) do { \ + qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \ +} while(0) + +#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp) + +#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL) +#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL)) +#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL)) +#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL) +#define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(size_t)(a)->icd.sz) : -1) + +/* last we pre-define a few icd for common utarrays of ints and strings */ +static void utarray_str_cpy(void *dst, const void *src) { + char **_src = (char**)src, **_dst = (char**)dst; + *_dst = (*_src == NULL) ? NULL : strdup(*_src); +} +static void utarray_str_dtor(void *elt) { + char **eltc = (char**)elt; + if (*eltc) free(*eltc); +} +static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor}; +static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL}; +static const UT_icd ut_ptr_icd _UNUSED_ = {sizeof(void*),NULL,NULL,NULL}; + +#endif /* UTARRAY_H */ diff --git a/gomspace/libutil/include/gs/uthash/uthash.h b/gomspace/libutil/include/gs/uthash/uthash.h new file mode 100644 index 00000000..c8c6d25c --- /dev/null +++ b/gomspace/libutil/include/gs/uthash/uthash.h @@ -0,0 +1,960 @@ +/* +Copyright (c) 2003-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +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. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#include /* memcmp,strlen */ +#include /* ptrdiff_t */ +#include /* exit() */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define DECLTYPE(x) +#endif +#elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__) +#define NO_DECLTYPE +#define DECLTYPE(x) +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while(0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while(0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */ +#if defined (_WIN32) +#if defined(_MSC_VER) && _MSC_VER >= 1600 +#include +#elif defined(__WATCOMC__) +#include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif +#else +#include +#endif + +#define UTHASH_VERSION 1.9.9 + +#ifndef uthash_fatal +#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ +#endif +#ifndef uthash_malloc +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#endif +#ifndef uthash_free +#define uthash_free(ptr,sz) free(ptr) /* free fcn */ +#endif + +#ifndef uthash_noexpand_fyi +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#endif +#ifndef uthash_expand_fyi +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#endif + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhe */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + out=NULL; \ + if (head) { \ + unsigned _hf_bkt,_hf_hashv; \ + HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ + keyptr,keylen,out); \ + } \ + } \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) +#define HASH_BLOOM_MAKE(tbl) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ + memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ +} while (0) + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0) + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#else +#define HASH_BLOOM_MAKE(tbl) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#define HASH_BLOOM_BYTELEN 0 +#endif + +#define HASH_MAKE_TABLE(hh,head) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ + sizeof(UT_hash_table)); \ + if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl->buckets, 0, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ +} while(0) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add) + +#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ +do { \ + replaced=NULL; \ + HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced); \ + if (replaced!=NULL) { \ + HASH_DELETE(hh,head,replaced); \ + }; \ + HASH_ADD(hh,head,fieldname,keylen_in,add); \ +} while(0) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_bkt; \ + (add)->hh.next = NULL; \ + (add)->hh.key = (char*)(keyptr); \ + (add)->hh.keylen = (unsigned)(keylen_in); \ + if (!(head)) { \ + head = (add); \ + (head)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh,head); \ + } else { \ + (head)->hh.tbl->tail->next = (add); \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail = &((add)->hh); \ + } \ + (head)->hh.tbl->num_items++; \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ + (add)->hh.hashv, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ + HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ + HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ + HASH_FSCK(hh,head); \ +} while(0) + +#define HASH_TO_BKT( hashv, num_bkts, bkt ) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1)); \ +} while(0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ +do { \ + struct UT_hash_handle *_hd_hh_del; \ + if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + head = NULL; \ + } else { \ + unsigned _hd_bkt; \ + _hd_hh_del = &((delptr)->hh); \ + if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ + (head)->hh.tbl->tail = \ + (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho); \ + } \ + if ((delptr)->hh.prev) { \ + ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ + } else { \ + DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ + } \ + if (_hd_hh_del->next) { \ + ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \ + (head)->hh.tbl->hho))->prev = \ + _hd_hh_del->prev; \ + } \ + HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh,head); \ +} while (0) + + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ + HASH_FIND(hh,head,findstr,(unsigned)strlen(findstr),out) +#define HASH_ADD_STR(head,strfield,add) \ + HASH_ADD(hh,head,strfield[0],strlen(add->strfield),add) +#define HASH_REPLACE_STR(head,strfield,add,replaced) \ + HASH_REPLACE(hh,head,strfield[0],(unsigned)strlen(add->strfield),add,replaced) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_REPLACE_INT(head,intfield,add,replaced) \ + HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ + HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head) \ +do { \ + struct UT_hash_handle *_thh; \ + if (head) { \ + unsigned _bkt_i; \ + unsigned _count; \ + char *_prev; \ + _count = 0; \ + for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ + unsigned _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("invalid hh_prev %p, actual %p\n", \ + _thh->hh_prev, _prev ); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("invalid bucket count %u, actual %u\n", \ + (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid hh item count %u, actual %u\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + /* traverse hh in app order; check next/prev integrity, count */ \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev !=(char*)(_thh->prev)) { \ + HASH_OOPS("invalid prev %p, actual %p\n", \ + _thh->prev, _prev ); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ + (head)->hh.tbl->hho) : NULL ); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid app item count %u, actual %u\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ +#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hb_keylen=keylen; \ + char *_hb_key=(char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen--) { (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; } \ + bkt = (hashv) & (num_bkts-1); \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _sx_i; \ + char *_hs_key=(char*)(key); \ + hashv = 0; \ + for(_sx_i=0; _sx_i < keylen; _sx_i++) \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + bkt = hashv & (num_bkts-1); \ +} while (0) +/* FNV-1a variation */ +#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _fn_i; \ + char *_hf_key=(char*)(key); \ + hashv = 2166136261UL; \ + for(_fn_i=0; _fn_i < keylen; _fn_i++) { \ + hashv = hashv ^ _hf_key[_fn_i]; \ + hashv = hashv * 16777619; \ + } \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _ho_i; \ + char *_ho_key=(char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + unsigned char *_hj_key=(unsigned char*)(key); \ + hashv = 0xfeedbeef; \ + _hj_i = _hj_j = 0x9e3779b9; \ + _hj_k = (unsigned)(keylen); \ + while (_hj_k >= 12) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12; \ + } \ + hashv += keylen; \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ + case 5: _hj_j += _hj_key[4]; \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned char *_sfh_key=(unsigned char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = keylen; \ + \ + int _sfh_rem = _sfh_len & 3; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabe; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = (uint32_t)(get16bits (_sfh_key+2)) << 11 ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)] << 18); \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * MurmurHash uses the faster approach only on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) +#define MUR_GETBLOCK(p,i) p[i] +#else /* non intel */ +#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) +#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) +#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) +#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) +#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) +#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) +#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) +#else /* assume little endian non-intel */ +#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) +#endif +#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ + (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ + (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ + MUR_ONE_THREE(p)))) +#endif +#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define MUR_FMIX(_h) \ +do { \ + _h ^= _h >> 16; \ + _h *= 0x85ebca6b; \ + _h ^= _h >> 13; \ + _h *= 0xc2b2ae35l; \ + _h ^= _h >> 16; \ +} while(0) + +#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ +do { \ + const uint8_t *_mur_data = (const uint8_t*)(key); \ + const int _mur_nblocks = (keylen) / 4; \ + uint32_t _mur_h1 = 0xf88D5353; \ + uint32_t _mur_c1 = 0xcc9e2d51; \ + uint32_t _mur_c2 = 0x1b873593; \ + uint32_t _mur_k1 = 0; \ + const uint8_t *_mur_tail; \ + const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ + int _mur_i; \ + for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ + _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + \ + _mur_h1 ^= _mur_k1; \ + _mur_h1 = MUR_ROTL32(_mur_h1,13); \ + _mur_h1 = _mur_h1*5+0xe6546b64; \ + } \ + _mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ + _mur_k1=0; \ + switch((keylen) & 3) { \ + case 3: _mur_k1 ^= _mur_tail[2] << 16; \ + case 2: _mur_k1 ^= _mur_tail[1] << 8; \ + case 1: _mur_k1 ^= _mur_tail[0]; \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + _mur_h1 ^= _mur_k1; \ + } \ + _mur_h1 ^= (keylen); \ + MUR_FMIX(_mur_h1); \ + hashv = _mur_h1; \ + bkt = hashv & (num_bkts-1); \ +} while(0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* key comparison function; return 0 if keys equal */ +#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ +do { \ + if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ + else out=NULL; \ + while (out) { \ + if ((out)->hh.keylen == keylen_in) { \ + if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \ + } \ + if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \ + else out = NULL; \ + } \ +} while(0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,addhh) \ +do { \ + head.count++; \ + (addhh)->hh_next = head.hh_head; \ + (addhh)->hh_prev = NULL; \ + if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ + (head).hh_head=addhh; \ + if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ + && (addhh)->tbl->noexpand != 1) { \ + HASH_EXPAND_BUCKETS((addhh)->tbl); \ + } \ +} while(0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(hh,head,hh_del) \ + (head).count--; \ + if ((head).hh_head == hh_del) { \ + (head).hh_head = hh_del->hh_next; \ + } \ + if (hh_del->hh_prev) { \ + hh_del->hh_prev->hh_next = hh_del->hh_next; \ + } \ + if (hh_del->hh_next) { \ + hh_del->hh_next->hh_prev = hh_del->hh_prev; \ + } + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(tbl) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ + memset(_he_new_buckets, 0, \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + tbl->ideal_chain_maxlen = \ + (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ + ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ + tbl->nonideal_items = 0; \ + for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ + { \ + _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ + if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ + tbl->nonideal_items++; \ + _he_newbkt->expand_mult = _he_newbkt->count / \ + tbl->ideal_chain_maxlen; \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ + _he_thh; \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + tbl->num_buckets *= 2; \ + tbl->log2_num_buckets++; \ + tbl->buckets = _he_new_buckets; \ + tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ + (tbl->ineff_expands+1) : 0; \ + if (tbl->ineff_expands > 1) { \ + tbl->noexpand=1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ +} while(0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ + _hs_psize++; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + if (! (_hs_q) ) break; \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ + if (_hs_psize == 0) { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ + _hs_e = _hs_p; \ + if (_hs_p){ \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + } \ + _hs_psize--; \ + } else if (( \ + cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ + ) <= 0) { \ + _hs_e = _hs_p; \ + if (_hs_p){ \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + } \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail ) { \ + _hs_tail->next = ((_hs_e) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + if (_hs_e) { \ + _hs_e->prev = ((_hs_tail) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ + } \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + if (_hs_tail){ \ + _hs_tail->next = NULL; \ + } \ + if ( _hs_nmerges <= 1 ) { \ + _hs_looping=0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2; \ + } \ + HASH_FSCK(hh,head); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt=NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if (src) { \ + for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ + if (!dst) { \ + DECLTYPE_ASSIGN(dst,_elt); \ + HASH_MAKE_TABLE(hh_dst,dst); \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ + (dst)->hh_dst.tbl->num_items++; \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst,dst); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if (head) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)=NULL; \ + } \ +} while(0) + +#define HASH_OVERHEAD(hh,head) \ + ((head) ? ( \ + (size_t)((((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + (sizeof(UT_hash_table)) + \ + (HASH_BLOOM_BYTELEN)))) : 0) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1 +#define HASH_BLOOM_SIGNATURE 0xb12220f2 + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + char bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/gomspace/libutil/include/gs/uthash/utlist.h b/gomspace/libutil/include/gs/uthash/utlist.h new file mode 100644 index 00000000..b5f3f04c --- /dev/null +++ b/gomspace/libutil/include/gs/uthash/utlist.h @@ -0,0 +1,757 @@ +/* +Copyright (c) 2007-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +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. +*/ + +#ifndef UTLIST_H +#define UTLIST_H + +#define UTLIST_VERSION 1.9.9 + +#include + +/* + * This file contains macros to manipulate singly and doubly-linked lists. + * + * 1. LL_ macros: singly-linked lists. + * 2. DL_ macros: doubly-linked lists. + * 3. CDL_ macros: circular doubly-linked lists. + * + * To use singly-linked lists, your structure must have a "next" pointer. + * To use doubly-linked lists, your structure must "prev" and "next" pointers. + * Either way, the pointer to the head of the list must be initialized to NULL. + * + * ----------------.EXAMPLE ------------------------- + * struct item { + * int id; + * struct item *prev, *next; + * } + * + * struct item *list = NULL: + * + * int main() { + * struct item *item; + * ... allocate and populate item ... + * DL_APPEND(list, item); + * } + * -------------------------------------------------- + * + * For doubly-linked lists, the append and delete macros are O(1) + * For singly-linked lists, append and delete are O(n) but prepend is O(1) + * The sort macro is O(n log(n)) for all types of single/double/circular lists. + */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ code), this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#ifdef _MSC_VER /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define LDECLTYPE(x) decltype(x) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define LDECLTYPE(x) char* +#endif +#elif defined(__ICCARM__) +#define NO_DECLTYPE +#define LDECLTYPE(x) char* +#else /* GNU, Sun and other compilers */ +#define LDECLTYPE(x) __typeof(x) +#endif + +/* for VS2008 we use some workarounds to get around the lack of decltype, + * namely, we always reassign our tmp variable to the list head if we need + * to dereference its prev/next pointers, and save/restore the real head.*/ +#ifdef NO_DECLTYPE +#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } +#define _NEXT(elt,list,next) ((char*)((list)->next)) +#define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } +/* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */ +#define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } +#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } +#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } +#else +#define _SV(elt,list) +#define _NEXT(elt,list,next) ((elt)->next) +#define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to) +/* #define _PREV(elt,list,prev) ((elt)->prev) */ +#define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) +#define _RS(list) +#define _CASTASGN(a,b) (a)=(b) +#endif + +/****************************************************************************** + * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * + * Unwieldy variable names used here to avoid shadowing passed-in variables. * + *****************************************************************************/ +#define LL_SORT(list, cmp) \ + LL_SORT2(list, cmp, next) + +#define LL_SORT2(list, cmp, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + _CASTASGN(_ls_p,list); \ + list = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + } else { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + } \ + if (_ls_tail) { \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ + } else { \ + _CASTASGN(list,_ls_e); \ + } \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + if (_ls_tail) { \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ + } \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + + +#define DL_SORT(list, cmp) \ + DL_SORT2(list, cmp, prev, next) + +#define DL_SORT2(list, cmp, prev, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + _CASTASGN(_ls_p,list); \ + list = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + } else { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + } \ + if (_ls_tail) { \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ + } else { \ + _CASTASGN(list,_ls_e); \ + } \ + _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + _CASTASGN(list->prev, _ls_tail); \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + +#define CDL_SORT(list, cmp) \ + CDL_SORT2(list, cmp, prev, next) + +#define CDL_SORT2(list, cmp, prev, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + LDECLTYPE(list) _ls_oldhead; \ + LDECLTYPE(list) _tmp; \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + _CASTASGN(_ls_p,list); \ + _CASTASGN(_ls_oldhead,list); \ + list = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + _SV(_ls_q,list); \ + if (_NEXT(_ls_q,list,next) == _ls_oldhead) { \ + _ls_q = NULL; \ + } else { \ + _ls_q = _NEXT(_ls_q,list,next); \ + } \ + _RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ + } else { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ + } \ + if (_ls_tail) { \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ + } else { \ + _CASTASGN(list,_ls_e); \ + } \ + _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + _CASTASGN(list->prev,_ls_tail); \ + _CASTASGN(_tmp,list); \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list); \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + +/****************************************************************************** + * singly linked list macros (non-circular) * + *****************************************************************************/ +#define LL_PREPEND(head,add) \ + LL_PREPEND2(head,add,next) + +#define LL_PREPEND2(head,add,next) \ +do { \ + (add)->next = head; \ + head = add; \ +} while (0) + +#define LL_CONCAT(head1,head2) \ + LL_CONCAT2(head1,head2,next) + +#define LL_CONCAT2(head1,head2,next) \ +do { \ + LDECLTYPE(head1) _tmp; \ + if (head1) { \ + _tmp = head1; \ + while (_tmp->next) { _tmp = _tmp->next; } \ + _tmp->next=(head2); \ + } else { \ + (head1)=(head2); \ + } \ +} while (0) + +#define LL_APPEND(head,add) \ + LL_APPEND2(head,add,next) + +#define LL_APPEND2(head,add,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + (add)->next=NULL; \ + if (head) { \ + _tmp = head; \ + while (_tmp->next) { _tmp = _tmp->next; } \ + _tmp->next=(add); \ + } else { \ + (head)=(add); \ + } \ +} while (0) + +#define LL_DELETE(head,del) \ + LL_DELETE2(head,del,next) + +#define LL_DELETE2(head,del,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if ((head) == (del)) { \ + (head)=(head)->next; \ + } else { \ + _tmp = head; \ + while (_tmp->next && (_tmp->next != (del))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = ((del)->next); \ + } \ + } \ +} while (0) + +/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ +#define LL_APPEND_VS2008(head,add) \ + LL_APPEND2_VS2008(head,add,next) + +#define LL_APPEND2_VS2008(head,add,next) \ +do { \ + if (head) { \ + (add)->next = head; /* use add->next as a temp variable */ \ + while ((add)->next->next) { (add)->next = (add)->next->next; } \ + (add)->next->next=(add); \ + } else { \ + (head)=(add); \ + } \ + (add)->next=NULL; \ +} while (0) + +#define LL_DELETE_VS2008(head,del) \ + LL_DELETE2_VS2008(head,del,next) + +#define LL_DELETE2_VS2008(head,del,next) \ +do { \ + if ((head) == (del)) { \ + (head)=(head)->next; \ + } else { \ + char *_tmp = (char*)(head); \ + while ((head)->next && ((head)->next != (del))) { \ + head = (head)->next; \ + } \ + if ((head)->next) { \ + (head)->next = ((del)->next); \ + } \ + { \ + char **_head_alias = (char**)&(head); \ + *_head_alias = _tmp; \ + } \ + } \ +} while (0) +#ifdef NO_DECLTYPE +#undef LL_APPEND +#define LL_APPEND LL_APPEND_VS2008 +#undef LL_DELETE +#define LL_DELETE LL_DELETE_VS2008 +#undef LL_DELETE2 +#define LL_DELETE2 LL_DELETE2_VS2008 +#undef LL_APPEND2 +#define LL_APPEND2 LL_APPEND2_VS2008 +#undef LL_CONCAT /* no LL_CONCAT_VS2008 */ +#undef DL_CONCAT /* no DL_CONCAT_VS2008 */ +#endif +/* end VS2008 replacements */ + +#define LL_COUNT(head,el,counter) \ + LL_COUNT2(head,el,counter,next) \ + +#define LL_COUNT2(head,el,counter,next) \ +{ \ + counter = 0; \ + LL_FOREACH2(head,el,next){ ++counter; } \ +} + +#define LL_FOREACH(head,el) \ + LL_FOREACH2(head,el,next) + +#define LL_FOREACH2(head,el,next) \ + for(el=head;el;el=(el)->next) + +#define LL_FOREACH_SAFE(head,el,tmp) \ + LL_FOREACH_SAFE2(head,el,tmp,next) + +#define LL_FOREACH_SAFE2(head,el,tmp,next) \ + for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) + +#define LL_SEARCH_SCALAR(head,out,field,val) \ + LL_SEARCH_SCALAR2(head,out,field,val,next) + +#define LL_SEARCH_SCALAR2(head,out,field,val,next) \ +do { \ + LL_FOREACH2(head,out,next) { \ + if ((out)->field == (val)) break; \ + } \ +} while(0) + +#define LL_SEARCH(head,out,elt,cmp) \ + LL_SEARCH2(head,out,elt,cmp,next) + +#define LL_SEARCH2(head,out,elt,cmp,next) \ +do { \ + LL_FOREACH2(head,out,next) { \ + if ((cmp(out,elt))==0) break; \ + } \ +} while(0) + +#define LL_REPLACE_ELEM(head, el, add) \ +do { \ + LDECLTYPE(head) _tmp; \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + (add)->next = (el)->next; \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + _tmp = head; \ + while (_tmp->next && (_tmp->next != (el))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (add); \ + } \ + } \ +} while (0) + +#define LL_PREPEND_ELEM(head, el, add) \ +do { \ + LDECLTYPE(head) _tmp; \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + (add)->next = (el); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + _tmp = head; \ + while (_tmp->next && (_tmp->next != (el))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (add); \ + } \ + } \ +} while (0) \ + + +/****************************************************************************** + * doubly linked list macros (non-circular) * + *****************************************************************************/ +#define DL_PREPEND(head,add) \ + DL_PREPEND2(head,add,prev,next) + +#define DL_PREPEND2(head,add,prev,next) \ +do { \ + (add)->next = head; \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev = (add); \ + } else { \ + (add)->prev = (add); \ + } \ + (head) = (add); \ +} while (0) + +#define DL_APPEND(head,add) \ + DL_APPEND2(head,add,prev,next) + +#define DL_APPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev->next = (add); \ + (head)->prev = (add); \ + (add)->next = NULL; \ + } else { \ + (head)=(add); \ + (head)->prev = (head); \ + (head)->next = NULL; \ + } \ +} while (0) + +#define DL_CONCAT(head1,head2) \ + DL_CONCAT2(head1,head2,prev,next) + +#define DL_CONCAT2(head1,head2,prev,next) \ +do { \ + LDECLTYPE(head1) _tmp; \ + if (head2) { \ + if (head1) { \ + _tmp = (head2)->prev; \ + (head2)->prev = (head1)->prev; \ + (head1)->prev->next = (head2); \ + (head1)->prev = _tmp; \ + } else { \ + (head1)=(head2); \ + } \ + } \ +} while (0) + +#define DL_DELETE(head,del) \ + DL_DELETE2(head,del,prev,next) + +#define DL_DELETE2(head,del,prev,next) \ +do { \ + assert((del)->prev != NULL); \ + if ((del)->prev == (del)) { \ + (head)=NULL; \ + } else if ((del)==(head)) { \ + (del)->next->prev = (del)->prev; \ + (head) = (del)->next; \ + } else { \ + (del)->prev->next = (del)->next; \ + if ((del)->next) { \ + (del)->next->prev = (del)->prev; \ + } else { \ + (head)->prev = (del)->prev; \ + } \ + } \ +} while (0) + +#define DL_COUNT(head,el,counter) \ + DL_COUNT2(head,el,counter,next) \ + +#define DL_COUNT2(head,el,counter,next) \ +{ \ + counter = 0; \ + DL_FOREACH2(head,el,next){ ++counter; } \ +} + +#define DL_FOREACH(head,el) \ + DL_FOREACH2(head,el,next) + +#define DL_FOREACH2(head,el,next) \ + for(el=head;el;el=(el)->next) + +/* this version is safe for deleting the elements during iteration */ +#define DL_FOREACH_SAFE(head,el,tmp) \ + DL_FOREACH_SAFE2(head,el,tmp,next) + +#define DL_FOREACH_SAFE2(head,el,tmp,next) \ + for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) + +/* these are identical to their singly-linked list counterparts */ +#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR +#define DL_SEARCH LL_SEARCH +#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 +#define DL_SEARCH2 LL_SEARCH2 + +#define DL_REPLACE_ELEM(head, el, add) \ +do { \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + (add)->next = (el)->next; \ + if ((el)->next == NULL) { \ + (add)->prev = (add); \ + } else { \ + (add)->prev = (el)->prev; \ + (add)->next->prev = (add); \ + } \ + } else { \ + (add)->next = (el)->next; \ + (add)->prev = (el)->prev; \ + (add)->prev->next = (add); \ + if ((el)->next == NULL) { \ + (head)->prev = (add); \ + } else { \ + (add)->next->prev = (add); \ + } \ + } \ +} while (0) + +#define DL_PREPEND_ELEM(head, el, add) \ +do { \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->prev->next = (add); \ + } \ +} while (0) \ + + +/****************************************************************************** + * circular doubly linked list macros * + *****************************************************************************/ +#define CDL_PREPEND(head,add) \ + CDL_PREPEND2(head,add,prev,next) + +#define CDL_PREPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (add)->prev->next = (add); \ + } else { \ + (add)->prev = (add); \ + (add)->next = (add); \ + } \ +(head)=(add); \ +} while (0) + +#define CDL_DELETE(head,del) \ + CDL_DELETE2(head,del,prev,next) + +#define CDL_DELETE2(head,del,prev,next) \ +do { \ + if ( ((head)==(del)) && ((head)->next == (head))) { \ + (head) = 0L; \ + } else { \ + (del)->next->prev = (del)->prev; \ + (del)->prev->next = (del)->next; \ + if ((del) == (head)) (head)=(del)->next; \ + } \ +} while (0) + +#define CDL_COUNT(head,el,counter) \ + CDL_COUNT2(head,el,counter,next) \ + +#define CDL_COUNT2(head, el, counter,next) \ +{ \ + counter = 0; \ + CDL_FOREACH2(head,el,next){ ++counter; } \ +} + +#define CDL_FOREACH(head,el) \ + CDL_FOREACH2(head,el,next) + +#define CDL_FOREACH2(head,el,next) \ + for(el=head;el;el=((el)->next==head ? 0L : (el)->next)) + +#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ + CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) + +#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \ + for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ + (el) && ((tmp2)=(el)->next, 1); \ + ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) + +#define CDL_SEARCH_SCALAR(head,out,field,val) \ + CDL_SEARCH_SCALAR2(head,out,field,val,next) + +#define CDL_SEARCH_SCALAR2(head,out,field,val,next) \ +do { \ + CDL_FOREACH2(head,out,next) { \ + if ((out)->field == (val)) break; \ + } \ +} while(0) + +#define CDL_SEARCH(head,out,elt,cmp) \ + CDL_SEARCH2(head,out,elt,cmp,next) + +#define CDL_SEARCH2(head,out,elt,cmp,next) \ +do { \ + CDL_FOREACH2(head,out,next) { \ + if ((cmp(out,elt))==0) break; \ + } \ +} while(0) + +#define CDL_REPLACE_ELEM(head, el, add) \ +do { \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + if ((el)->next == (el)) { \ + (add)->next = (add); \ + (add)->prev = (add); \ + (head) = (add); \ + } else { \ + (add)->next = (el)->next; \ + (add)->prev = (el)->prev; \ + (add)->next->prev = (add); \ + (add)->prev->next = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } \ + } \ +} while (0) + +#define CDL_PREPEND_ELEM(head, el, add) \ +do { \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + (add)->prev->next = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } \ +} while (0) \ + +#endif /* UTLIST_H */ + diff --git a/gomspace/libutil/include/gs/uthash/utstring.h b/gomspace/libutil/include/gs/uthash/utstring.h new file mode 100644 index 00000000..867442c8 --- /dev/null +++ b/gomspace/libutil/include/gs/uthash/utstring.h @@ -0,0 +1,393 @@ +/* +Copyright (c) 2008-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +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. +*/ + +/* a dynamic string implementation using macros + */ +#ifndef UTSTRING_H +#define UTSTRING_H + +#define UTSTRING_VERSION 1.9.9 + +#ifdef __GNUC__ +#define _UNUSED_ __attribute__ ((__unused__)) +#else +#define _UNUSED_ +#endif + +#include +#include +#include +#include +#define oom() exit(-1) + +typedef struct { + char *d; + size_t n; /* allocd size */ + size_t i; /* index of first unused byte */ +} UT_string; + +#define utstring_reserve(s,amt) \ +do { \ + if (((s)->n - (s)->i) < (size_t)(amt)) { \ + (s)->d = (char*)realloc((s)->d, (s)->n + amt); \ + if ((s)->d == NULL) oom(); \ + (s)->n += amt; \ + } \ +} while(0) + +#define utstring_init(s) \ +do { \ + (s)->n = 0; (s)->i = 0; (s)->d = NULL; \ + utstring_reserve(s,100); \ + (s)->d[0] = '\0'; \ +} while(0) + +#define utstring_done(s) \ +do { \ + if ((s)->d != NULL) free((s)->d); \ + (s)->n = 0; \ +} while(0) + +#define utstring_free(s) \ +do { \ + utstring_done(s); \ + free(s); \ +} while(0) + +#define utstring_new(s) \ +do { \ + s = (UT_string*)calloc(sizeof(UT_string),1); \ + if (!s) oom(); \ + utstring_init(s); \ +} while(0) + +#define utstring_renew(s) \ +do { \ + if (s) { \ + utstring_clear(s); \ + } else { \ + utstring_new(s); \ + } \ +} while(0) + +#define utstring_clear(s) \ +do { \ + (s)->i = 0; \ + (s)->d[0] = '\0'; \ +} while(0) + +#define utstring_bincpy(s,b,l) \ +do { \ + utstring_reserve((s),(l)+1); \ + if (l) memcpy(&(s)->d[(s)->i], b, l); \ + (s)->i += l; \ + (s)->d[(s)->i]='\0'; \ +} while(0) + +#define utstring_concat(dst,src) \ +do { \ + utstring_reserve((dst),((src)->i)+1); \ + if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \ + (dst)->i += (src)->i; \ + (dst)->d[(dst)->i]='\0'; \ +} while(0) + +#define utstring_len(s) ((unsigned)((s)->i)) + +#define utstring_body(s) ((s)->d) + +_UNUSED_ static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) { + int n; + va_list cp; + while (1) { +#ifdef _WIN32 + cp = ap; +#else + va_copy(cp, ap); +#endif + n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp); + va_end(cp); + + if ((n > -1) && ((size_t) n < (s->n-s->i))) { + s->i += n; + return; + } + + /* Else try again with more space. */ + if (n > -1) utstring_reserve(s,n+1); /* exact */ + else utstring_reserve(s,(s->n)*2); /* 2x */ + } +} +#ifdef __GNUC__ +/* support printf format checking (2=the format string, 3=start of varargs) */ +static void utstring_printf(UT_string *s, const char *fmt, ...) + __attribute__ (( format( printf, 2, 3) )); +#endif +_UNUSED_ static void utstring_printf(UT_string *s, const char *fmt, ...) { + va_list ap; + va_start(ap,fmt); + utstring_printf_va(s,fmt,ap); + va_end(ap); +} + +/******************************************************************************* + * begin substring search functions * + ******************************************************************************/ +/* Build KMP table from left to right. */ +_UNUSED_ static void _utstring_BuildTable( + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + + i = 0; + j = i - 1; + P_KMP_Table[i] = j; + while (i < (long) P_NeedleLen) + { + while ( (j > -1) && (P_Needle[i] != P_Needle[j]) ) + { + j = P_KMP_Table[j]; + } + i++; + j++; + if (i < (long) P_NeedleLen) + { + if (P_Needle[i] == P_Needle[j]) + { + P_KMP_Table[i] = P_KMP_Table[j]; + } + else + { + P_KMP_Table[i] = j; + } + } + else + { + P_KMP_Table[i] = j; + } + } + + return; +} + + +/* Build KMP table from right to left. */ +_UNUSED_ static void _utstring_BuildTableR( + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + + i = P_NeedleLen - 1; + j = i + 1; + P_KMP_Table[i + 1] = j; + while (i >= 0) + { + while ( (j < (long) P_NeedleLen) && (P_Needle[i] != P_Needle[j]) ) + { + j = P_KMP_Table[j + 1]; + } + i--; + j--; + if (i >= 0) + { + if (P_Needle[i] == P_Needle[j]) + { + P_KMP_Table[i + 1] = P_KMP_Table[j + 1]; + } + else + { + P_KMP_Table[i + 1] = j; + } + } + else + { + P_KMP_Table[i + 1] = j; + } + } + + return; +} + + +/* Search data from left to right. ( Multiple search mode. ) */ +_UNUSED_ static long _utstring_find( + const char *P_Haystack, + size_t P_HaystackLen, + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + long V_FindPosition = -1; + + /* Search from left to right. */ + i = j = 0; + while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) ) + { + while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) ) + { + i = P_KMP_Table[i]; + } + i++; + j++; + if (i >= (int)P_NeedleLen) + { + /* Found. */ + V_FindPosition = j - i; + break; + } + } + + return V_FindPosition; +} + + +/* Search data from right to left. ( Multiple search mode. ) */ +_UNUSED_ static long _utstring_findR( + const char *P_Haystack, + size_t P_HaystackLen, + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + long V_FindPosition = -1; + + /* Search from right to left. */ + j = (P_HaystackLen - 1); + i = (P_NeedleLen - 1); + while ( (j >= 0) && (j >= i) ) + { + while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) ) + { + i = P_KMP_Table[i + 1]; + } + i--; + j--; + if (i < 0) + { + /* Found. */ + V_FindPosition = j + 1; + break; + } + } + + return V_FindPosition; +} + + +/* Search data from left to right. ( One time search mode. ) */ +_UNUSED_ static long utstring_find( + UT_string *s, + long P_StartPosition, /* Start from 0. -1 means last position. */ + const char *P_Needle, + size_t P_NeedleLen) +{ + long V_StartPosition; + long V_HaystackLen; + long *V_KMP_Table; + long V_FindPosition = -1; + + if (P_StartPosition < 0) + { + V_StartPosition = s->i + P_StartPosition; + } + else + { + V_StartPosition = P_StartPosition; + } + V_HaystackLen = s->i - V_StartPosition; + if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) + { + V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); + if (V_KMP_Table != NULL) + { + _utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table); + + V_FindPosition = _utstring_find(s->d + V_StartPosition, + V_HaystackLen, + P_Needle, + P_NeedleLen, + V_KMP_Table); + if (V_FindPosition >= 0) + { + V_FindPosition += V_StartPosition; + } + + free(V_KMP_Table); + } + } + + return V_FindPosition; +} + + +/* Search data from right to left. ( One time search mode. ) */ +_UNUSED_ static long utstring_findR( + UT_string *s, + long P_StartPosition, /* Start from 0. -1 means last position. */ + const char *P_Needle, + size_t P_NeedleLen) +{ + long V_StartPosition; + long V_HaystackLen; + long *V_KMP_Table; + long V_FindPosition = -1; + + if (P_StartPosition < 0) + { + V_StartPosition = s->i + P_StartPosition; + } + else + { + V_StartPosition = P_StartPosition; + } + V_HaystackLen = V_StartPosition + 1; + if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) + { + V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); + if (V_KMP_Table != NULL) + { + _utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table); + + V_FindPosition = _utstring_findR(s->d, + V_HaystackLen, + P_Needle, + P_NeedleLen, + V_KMP_Table); + + free(V_KMP_Table); + } + } + + return V_FindPosition; +} +/******************************************************************************* + * end substring search functions * + ******************************************************************************/ + +#endif /* UTSTRING_H */ diff --git a/gomspace/libutil/include/gs/util/base16.h b/gomspace/libutil/include/gs/util/base16.h new file mode 100644 index 00000000..0fddccc5 --- /dev/null +++ b/gomspace/libutil/include/gs/util/base16.h @@ -0,0 +1,90 @@ +#ifndef GS_UTIL_BASE16_H +#define GS_UTIL_BASE16_H +/* + * Copyright (C) 2010 Michael Brown . + * + * This program 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 2 of the + * License, or any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/** + @file + + Encoding and decoding base16 arrays to and from strings. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Calculate length of base16-encoded data + + @param raw_len Raw data length + @return Encoded string length (excluding NUL) +*/ +static inline size_t base16_encoded_len(size_t raw_len) +{ + return (2 * raw_len); +} + +/** + Calculate maximum length of base16-decoded string + @param encoded Encoded string + @return Maximum length of raw data +*/ +static inline size_t base16_decoded_max_len(const char *encoded) +{ + return ((strlen(encoded) + 1) / 2); +} + +/** + Base16-encode data + + The buffer must be the correct length for the encoded string. Use + something like + + char buf[ base16_encoded_len ( len ) + 1 ]; + + (the +1 is for the terminating NUL) to provide a buffer of the + correct size. + + @param raw Raw data + @param len Length of raw data + @param encoded Buffer for encoded string +*/ +void base16_encode(const uint8_t *raw, size_t len, char *encoded); + +/** + Base16-decode data + + The buffer must be large enough to contain the decoded data. Use + something like + + char buf[ base16_decoded_max_len ( encoded ) ]; + + to provide a buffer of the correct size. + + @param encoded Encoded string + @param raw Raw data + @return Length of raw data, or negative error (gs_error_t) +*/ +int base16_decode(const char *encoded, uint8_t *raw); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/bytebuffer.h b/gomspace/libutil/include/gs/util/bytebuffer.h new file mode 100644 index 00000000..ad727e01 --- /dev/null +++ b/gomspace/libutil/include/gs/util/bytebuffer.h @@ -0,0 +1,173 @@ +#ifndef GS_UTIL_BYTEBUFFER_h +#define GS_UTIL_BYTEBUFFER_h +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Byte buffer provides formatting/serialzing of text/binary data. The buffer keeps track of used space, and prevents overrun. + + The current buffer state can be checked using gs_bytebuffer_state(). + + @dontinclude bytebuffer/bytebuffer_test.c + @skip TEST_gs_bytebuffer_use_case + @until } +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Buffer handle. + Never access handle members directly. +*/ +typedef struct { + /** + Internal: Pointer to user supplied buffer. + @see gs_bytebuffer_init() + */ + uint8_t * buffer; + /** + Internal: Size of user supplied buffer. + @see gs_bytebuffer_init() + */ + size_t size; + /** + Internal: Number of bytes used. + */ + size_t used; + /** + Internal: FUTURE: Committed used + */ + size_t committed_used; + /** + Internal: flags to keep track of buffer state. + */ + uint8_t flags; +} gs_bytebuffer_t; + +/** + Initialize buffer. + + @param[in] bb handle. + @param[in] buffer user supplied buffer of \a buffer_size size (bytes). If NULL, the buffer will keep track of required bytes. + @param[in] buffer_size size of \a buffer. + @return_gs_error_t +*/ +gs_error_t gs_bytebuffer_init(gs_bytebuffer_t * bb, void * buffer, size_t buffer_size); + +/** + Insert data using vprintf. + + @param[in] bb handle. + @param[in] format printf syntax for formatting data + @param[in] ap variable argument list. +*/ +void gs_bytebuffer_vprintf(gs_bytebuffer_t * bb, const char * format, va_list ap); + +/** + Insert data using printf. + + @param[in] bb handle. + @param[in] format printf syntax for formatting data +*/ +void gs_bytebuffer_printf(gs_bytebuffer_t * bb, const char * format, ...) __attribute__ ((format (__printf__, 2, 3))); + +/** + Append data to buffer. + + @param[in] bb handle. + @param[in] data data to append to buffer. + @param[in] length length of data (bytes). +*/ +void gs_bytebuffer_append(gs_bytebuffer_t * bb, const void * data, size_t length); + +/** + Append string to buffer. + + @param[in] bb handle. + @param[in] string string to append to buffer. +*/ +void gs_bytebuffer_append_string(gs_bytebuffer_t * bb, const char * string); + +/** + Append string to buffer. + + @param[in] bb handle. + @param[in] string string to append to buffer. + @param[in] max_length max characters to append from \a string. +*/ +void gs_bytebuffer_append_string_max(gs_bytebuffer_t * bb, const char * string, size_t max_length); + +/** + Return buffer as string - enforcing NUL termination. + + This will always add a NUL termination (zero), which may lead to overflow/truncation of the string. + The NUL termination is NOT added to \a used count. + + @param[in] bb handle. + @param[out] error optional, state of buffer - see gs_bytebuffer_error(). + @return C-string (NUL terminated) +*/ +char * gs_bytebuffer_get_as_string(gs_bytebuffer_t * bb, gs_error_t * error); + +/** + Return buffer state. + + @param[in] bb handle. + @return GS_ERROR_OVERFLOW if data has been truncated. + @return GS_ERROR_DATA in case of error during formatting. + @return_gs_error_t +*/ +gs_error_t gs_bytebuffer_get_state(gs_bytebuffer_t * bb); + +/** + Return buffer (user supplied). + + @param[in] bb handle. +*/ +static inline void * gs_bytebuffer_get_buffer(gs_bytebuffer_t * bb) +{ + return bb->buffer; +} + +/** + Return buffer size (user supplied). + + @param[in] bb handle. + @return buffer size +*/ +static inline size_t gs_bytebuffer_get_size(gs_bytebuffer_t * bb) +{ + return bb->size; +} + +/** + Return number of free bytes. + + @param[in] bb handle. + @return number of free bytes. +*/ +static inline size_t gs_bytebuffer_get_free(gs_bytebuffer_t * bb) +{ + return (bb->size) ? (bb->size - bb->used) : 0; +} + +/** + Return number of used bytes. + + @param[in] bb handle. + @return used bytes. +*/ +static inline size_t gs_bytebuffer_get_used(gs_bytebuffer_t * bb) +{ + return bb->used; +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/byteorder.h b/gomspace/libutil/include/gs/util/byteorder.h new file mode 100644 index 00000000..3d2d6bef --- /dev/null +++ b/gomspace/libutil/include/gs/util/byteorder.h @@ -0,0 +1,341 @@ +#ifndef GS_UTIL_BYTEORDER_H +#define GS_UTIL_BYTEORDER_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Convert numbers between host and network order. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Convert value from host order to network order + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_htons(uint16_t value); + +/** + Convert value from network order to host order + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_ntohs(uint16_t value); + +/** + Convert value from host order to network order + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_htonl(uint32_t value); + +/** + Convert value from network order to host order + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_ntohl(uint32_t value); + +/** + Convert value from host order to network order + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_hton16(uint16_t value); + +/** + Convert value from host order to network order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_hton16_array(const uint16_t * from, uint16_t * to, size_t count); + +/** + Convert value from network order to host order + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_ntoh16(uint16_t value); + +/** + Convert value from network order to host order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_ntoh16_array(const uint16_t * from, uint16_t * to, size_t count); + +/** + Convert value from host order to network order + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_hton32(uint32_t value); + +/** + Convert value from host order to network order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_hton32_array(const uint32_t * from, uint32_t * to, size_t count); + +/** + Convert value from network order to host order + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_ntoh32(uint32_t value); + +/** + Convert value from network order to host order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_ntoh32_array(const uint32_t * from, uint32_t * to, size_t count); + +/** + Convert value from host order to network order + @param[in] value value to convert. + @return converted value. +*/ +uint64_t util_hton64(uint64_t value); + +/** + Convert value from host order to network order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_hton64_array(const uint64_t * from, uint64_t * to, size_t count); + +/** + Convert value from network order to host order + @param[in] value value to convert. + @return converted value. +*/ +uint64_t util_ntoh64(uint64_t value); + +/** + Convert value from network order to host order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_ntoh64_array(const uint64_t * from, uint64_t * to, size_t count); + +/** + Convert value from host order to network order + @param[in] value value to convert. + @return converted value. +*/ +float util_htonflt(float value); + +/** + Convert value from host order to network order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_htonflt_array(const float * from, float * to, size_t count); + +/** + Convert value from network order to host order + @param[in] value value to convert. + @return converted value. +*/ +float util_ntohflt(float value); + +/** + Convert value from network order to host order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_ntohflt_array(const float * from, float * to, size_t count); + +/** + Convert value from host order to network order + @param[in] value value to convert. + @return converted value. +*/ +double util_htondbl(double value); + +/** + Convert value from host order to network order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_htondbl_array(const double * from, double * to, size_t count); + +/** + Convert value from network order to host order + @param[in] value value to convert. + @return converted value. +*/ +double util_ntohdbl(double value); + +/** + Convert value from network order to host order + @param[in] from value to convert. + @param[out] to value converted. + @param[in] count element count +*/ +void util_ntohdbl_array(const double * from, double * to, size_t count); + +/** + Convert value from host order to big endian. + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_htobe16(uint16_t value); + +/** + Convert value from host order to little endian. + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_htole16(uint16_t value); + +/** + Convert value from big endian to host order. + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_betoh16(uint16_t value); + +/** + Convert value from little endian to host order. + @param[in] value value to convert. + @return converted value. +*/ +uint16_t util_letoh16(uint16_t value); + +/** + Convert value from host order to big endian. + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_htobe32(uint32_t value); + +/** + Convert value from host order to little endian. + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_htole32(uint32_t value); + +/** + Convert value from big endian to host order. + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_betoh32(uint32_t value); + +/** + Convert value from little endian to host order. + @param[in] value value to convert. + @return converted value. +*/ +uint32_t util_letoh32(uint32_t value); + +/** + Convert value from host order to big endian. + @param[in] value value to convert. + @return converted value. +*/ +uint64_t util_htobe64(uint64_t value); + +/** + Convert value from host order to little endian. + @param[in] value value to convert. + @return converted value. +*/ +uint64_t util_htole64(uint64_t value); + +/** + Convert value from big endian to host order. + @param[in] value value to convert. + @return converted value. +*/ +uint64_t util_betoh64(uint64_t value); + +/** + Convert value from little endian to host order. + @param[in] value value to convert. + @return converted value. +*/ +uint64_t util_letoh64(uint64_t value); + +/** + Byte swap. + @param[in] value value to byteswap. + @return swapped value +*/ +uint16_t gs_bswap_16(uint16_t value); + +/** + Byte swap array. + @param[in] from from address. + @param[out] to to address. + @param[in] count element count. +*/ +void gs_bswap_16_array(const uint16_t * from, uint16_t * to, size_t count); + +/** + Byte swap. + @param[in] value value to byteswap. + @return swapped value +*/ +uint32_t gs_bswap_32(uint32_t value); + +/** + Byte swap array. + @param[in] from from address. + @param[out] to to address. + @param[in] count element count. +*/ +void gs_bswap_32_array(const uint32_t * from, uint32_t * to, size_t count); + +/** + Byte swap. + @param[in] value value to byteswap. + @return swapped value +*/ +uint64_t gs_bswap_64(uint64_t value); + +/** + Byte swap array. + @param[in] from from address. + @param[out] to to address. + @param[in] count element count. +*/ +void gs_bswap_64_array(const uint64_t * from, uint64_t * to, size_t count); + +/** + Byte swap. + @param[in] value value to byteswap. + @return swapped value +*/ +float gs_bswap_float(float value); + +/** + Byte swap array. + @param[in] from from address. + @param[out] to to address. + @param[in] count element count. +*/ +void gs_bswap_float_array(const float * from, float * to, size_t count); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/check.h b/gomspace/libutil/include/gs/util/check.h new file mode 100644 index 00000000..23920161 --- /dev/null +++ b/gomspace/libutil/include/gs/util/check.h @@ -0,0 +1,54 @@ +#ifndef GS_UTIL_CHECK_H +#define GS_UTIL_CHECK_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Argument checking. + + Logs can be enabled through a define. +*/ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if (GS_CHECK_LOG) +#define GS_CHECK_HANDLE(check) if (!(check)) { log_error("Invalid handle - assert: " GS_DEF2STRING(check)); return GS_ERROR_HANDLE;} +#define GS_CHECK_ARG(check) if (!(check)) { log_error("Invalid argument - assert: " GS_DEF2STRING(check)); return GS_ERROR_ARG;} +#define GS_CHECK_SUPPORTED(check) if (!(check)) { log_error("Not supported - assert: " GS_DEF2STRING(check)); return GS_ERROR_NOT_SUPPORTED;} +#define GS_CHECK_RANGE(check) if (!(check)) { log_error("Invalid range - assert: " GS_DEF2STRING(check)); return GS_ERROR_RANGE;} +#else +/** + Perform evalution of 'check' and return GS_ERROR_HANDLE if not 'true'. +*/ +#define GS_CHECK_HANDLE(check) if (!(check)) { return GS_ERROR_HANDLE;} +/** + Perform evalution of 'check' and return GS_ERROR_ARG if not 'true'. +*/ +#define GS_CHECK_ARG(check) if (!(check)) { return GS_ERROR_ARG;} +/** + Perform evalution of 'check' and return GS_ERROR_NOT_SUPPORTED if not 'true'. +*/ +#define GS_CHECK_SUPPORTED(check) if (!(check)) { return GS_ERROR_NOT_SUPPORTED;} +/** + Perform evalution of 'check' and return GS_ERROR_RANGE if not 'true'. +*/ +#define GS_CHECK_RANGE(check) if (!(check)) { return GS_ERROR_RANGE;} +#endif + +/** + Assert on 'value'. + + @deprecated use GS_STATIC_ASSERT() +*/ +#define GS_CHECK_STATIC_ASSERT(condition, name) GS_STATIC_ASSERT(condition, name) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/clock.h b/gomspace/libutil/include/gs/util/clock.h new file mode 100644 index 00000000..1d4a9548 --- /dev/null +++ b/gomspace/libutil/include/gs/util/clock.h @@ -0,0 +1,88 @@ +#ifndef GS_UTIL_CLOCK_H +#define GS_UTIL_CLOCK_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Get/set time (including RTC), convert to/from string. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Returns real time/clock (UTC - time since Epoch/1970). + + If the platform supports a Real Time Clock, the RTC is normally read on first call. An offset is calculated for the relative clock, which + then is used to calculate the actual time. + + @note clock_get_time() is proto-typed in libcsp as weak, but with different argument which MUST match gs_timestamp_t. + @param[out] time user allocated buffer, contaning the current UTC time. +*/ +void gs_clock_get_time(gs_timestamp_t * time); + +/** + Set real time/clock (UTC). + If the platform supports a Real Time Clock, the RTC is also updated. + @param[in] time UTC time. + @return_gs_error_t +*/ +gs_error_t gs_clock_set_time(const gs_timestamp_t * time); + +/** + Returns elapsed time since some unspecified starting point. + @param[out] time user allocated buffer, receives elapsed time. + @see gs_time_rel_ms() +*/ +void gs_clock_get_monotonic(gs_timestamp_t * time); + +/** + Returns number of elapsed nano-seconds since some unspecified starting point. + @return nano-seconds. +*/ +uint64_t gs_clock_get_nsec(void); + +/** + Buffer length for containing full ISO8601 timestamp - including zero (0) termination. +*/ +#define GS_CLOCK_ISO8601_BUFFER_LENGTH 21 + +/** + Convert UTC to a ISO8601 string. + ISO8601 timestamp: 2017-03-30T06:20:45Z + @param[in] utc_time UTC time. + @param[out] buffer user allocated buffer. + @param[in] buffer_size size of \a buf. + @return_gs_error_t +*/ +gs_error_t gs_clock_to_iso8601_string(const gs_timestamp_t * utc_time, char * buffer, size_t buffer_size); + +/** + Convert UTC to a ISO8601 string. + ISO8601 timestamp: 2017-03-30T06:20:45Z + @param[in] utc_sec UTC seconds. + @param[out] buffer user allocated buffer. + @param[in] buffer_size size of \a buf. + @return_gs_error_t +*/ +gs_error_t gs_clock_to_iso8601_string2(uint32_t utc_sec, char * buffer, size_t buffer_size); + +/** + Convert string (UTC time) to timstamp. + Parse string as: + 1. \.\ - number of seconds elapsed since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). + 2. YYYY-MM-DDTHH:MM:SSZ - ISO8601 + @param[in] str time + @param[out] ts time + @return_gs_error_t +*/ +gs_error_t gs_clock_from_string(const char * str, gs_timestamp_t * ts); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/crc32.h b/gomspace/libutil/include/gs/util/crc32.h new file mode 100644 index 00000000..f2be6775 --- /dev/null +++ b/gomspace/libutil/include/gs/util/crc32.h @@ -0,0 +1,55 @@ +#ifndef GS_UTIL_CRC32_H +#define GS_UTIL_CRC32_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + CRC32 checksumes. + + https://en.wikipedia.org/wiki/Cyclic_redundancy_check. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Return init/seed value for CRC-32. + @return initial/seed value for CRC-32, using 0xffffffff. + @see gs_crc32_update(), gs_crc32_finalize() +*/ +uint32_t gs_crc32_init(void); + +/** + Update CRC-32. + @param[in] crc current CRC-32 + @param[in] block start of memory block. + @param[in] length length of \a block. + @return updated CRC-32. + @see gs_crc32_init(), gs_crc32_finalize() +*/ +uint32_t gs_crc32_update(uint32_t crc, const void * block, size_t length); + +/** + Return finalized CRC-32. + @param[in] crc Checksum is finalized by xor'ing 0xffffffff. + @return finalized CRC-32. + @see gs_crc32_init(), gs_crc32_update() +*/ +uint32_t gs_crc32_finalize(uint32_t crc); + +/** + Return finalized CRC-32 on amemory block. + + @param[in] block block to calculate CRC-32 on. + @param[in] length length/size of \a block. + @return finalized CRC-32. +*/ +uint32_t gs_crc32(const void *block, size_t length); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/crc8.h b/gomspace/libutil/include/gs/util/crc8.h new file mode 100644 index 00000000..99b14d0a --- /dev/null +++ b/gomspace/libutil/include/gs/util/crc8.h @@ -0,0 +1,55 @@ +#ifndef GS_UTIL_CRC8_H +#define GS_UTIL_CRC8_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + CRC8 checksumes. + + https://en.wikipedia.org/wiki/Cyclic_redundancy_check. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Return init/seed value for CRC-8. + @return initial/seed value for CRC-8, using 0xff. + @see gs_crc8_update(), gs_crc8_finalize() +*/ +uint8_t gs_crc8_init(void); + +/** + Update CRC-8. + @param[in] crc current CRC-8 + @param[in] block start of memory block. + @param[in] length length of \a block. + @return updated CRC-8. + @see gs_crc8_init(), gs_crc8_finalize() +*/ +uint8_t gs_crc8_update(uint8_t crc, const void * block, size_t length); + +/** + Return finalized CRC-8. + @param[in] crc Checksum is finalized by xor'ing 0xffffffff. + @return finalized CRC-8. + @see gs_crc8_init(), gs_crc8_update() +*/ +uint8_t gs_crc8_finalize(uint8_t crc); + +/** + Return finalized CRC-8 on amemory block. + + @param[in] block block to calculate CRC-8 on. + @param[in] length length/size of \a block. + @return finalized CRC-8. +*/ +uint8_t gs_crc8(const void *block, size_t length); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/delay.h b/gomspace/libutil/include/gs/util/delay.h new file mode 100644 index 00000000..d205b48c --- /dev/null +++ b/gomspace/libutil/include/gs/util/delay.h @@ -0,0 +1,42 @@ +#ifndef GS_UTIL_DELAY_H +#define GS_UTIL_DELAY_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Delay execution. + + @note Most implementations uses busy waiting. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Delay for number of microseconds. + @note Linux doesn't busy wait. + @param us Number of microseconds to wait +*/ +void gs_delay_us(uint32_t us); + +/** + Return current counter used for us delays + @return timestamp in us +*/ +uint16_t gs_delay_ts_get(void); + +/** + Wait until delay has passed since timestamp + + @param[in] ts Timestamp in us + @param[in] delay The requested delay since ts +*/ +void gs_delay_from_ts(uint16_t ts, uint16_t delay); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/can/can.h b/gomspace/libutil/include/gs/util/drivers/can/can.h new file mode 100644 index 00000000..27f7acd5 --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/can/can.h @@ -0,0 +1,122 @@ +#ifndef GS_UTIL_DRIVERS_CAN_CAN_H +#define GS_UTIL_DRIVERS_CAN_CAN_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + CAN interface. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Default log group for CAN driver. +*/ +GS_LOG_GROUP_EXTERN(gs_can_log); + +/** + Bit-rate (default). +*/ +#define GS_CAN_DEFAULT_BPS 1000000 + +/** + Callback for handling received data (from CAN driver). + @param[in] device hardware device + @param[in] canMsgId standard or extended message id. + @param[in] extendedMsgId \a true if extended id, \a false if standard id. + @param[in] data pointer to data. + @param[in] data_size size of data. + @param[in] nowMs current relative time in mS. + @param[in] user_data user data. + @param[in] cswitch If called from within an ISR (embedded platform), this will none NULL. +*/ +typedef void (*gs_can_rxdata_callback_t)(int hdl, + uint32_t canMsgId, + bool extendedMsgId, + const void * data, + size_t data_size, + uint32_t nowMs, + void * user_data, + gs_context_switch_t * cswitch); + +/** + Send CAN message with standard id (11 bits). + @param[in] device hardware device + @param[in] canMsgId standard CAN message id. + @param[in] data pointer to data. + @param[in] data_size size of data. + @param[in] timeout_ms timeout in mS. + @return GS_ERROR_FULL if Tx queue is full + @return_gs_error_t +*/ +gs_error_t gs_can_send_standard(uint8_t device, uint32_t canMsgId, const void * data, size_t data_size, int timeout_ms); + +/** + Send CAN message with exended id (29 bits). + @param[in] device hardware device + @param[in] canExtMsgId exteneded message id. + @param[in] data pointer to data. + @param[in] data_size size of data. + @param[in] timeout_ms timeout in mS. + @return GS_ERROR_FULL if Tx queue is full + @return_gs_error_t +*/ +gs_error_t gs_can_send_extended(uint8_t device, uint32_t canExtMsgId, const void * data, size_t data_size, int timeout_ms); + +/** + Set filter and callback for standard message id. + @param[in] device hardware device + @param[in] canMsgId standard message id. + @param[in] mask filter mask. + @param[in] rx_callback callback function. + @param[in] rx_user_data user data provided in callback. + @return GS_ERROR_FULL if all message id slots are used. + @return_gs_error_t +*/ +gs_error_t gs_can_set_standard_filter_mask(uint8_t device, uint32_t canMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * rx_user_data); + +/** + Set filter and callback for extended message id. + @param[in] device hardware device + @param[in] canExtMsgId extended message id. + @param[in] mask filter mask. + @param[in] rx_callback callback function. + @param[in] rx_user_data user data provided in callback. + @return GS_ERROR_FULL if all message id slots are used. + @return_gs_error_t +*/ +gs_error_t gs_can_set_extended_filter_mask(uint8_t device, uint32_t canExtMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * rx_user_data); + +/** + Stop CAN layer. + If a CAN transceiver is present and controlled, it will be disabled. + @param[in] device hardware device + @return_gs_error_t +*/ +gs_error_t gs_can_stop(uint8_t device); + +/** + Start CAN layer. + Clear all buffers and start CAN. + If a CAN transceiver is present and controlled, it will be enabled. + @param[in] device hardware device + @return_gs_error_t +*/ +gs_error_t gs_can_start(uint8_t device); + +/** + Get current CAN layer error state. + @param[in] device hardware device + @param[out] restart_required \a true if CAN layer should be re-started. Pass NULL, if not wanted. + @return_gs_error_t +*/ +gs_error_t gs_can_error_state(uint8_t device, bool * restart_required); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/gpio/gpio.h b/gomspace/libutil/include/gs/util/drivers/gpio/gpio.h new file mode 100644 index 00000000..ff2803c0 --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/gpio/gpio.h @@ -0,0 +1,91 @@ +#ifndef GS_UTIL_DRIVERS_GPIO_GPIO_H +#define GS_UTIL_DRIVERS_GPIO_GPIO_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + GPIO interface provides a generic interface toward hardware GPIO's. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + GPIO definition. +*/ +typedef struct { + //! Chip/group/port number which the GPIO belongs to. + uint16_t port; + //! The pin number of the GPIO. + uint16_t pin; +} gs_gpio_t; + +/** + GPIO interrupt function. +*/ +typedef void (*gs_gpio_isr_t)(gs_context_switch_t * cswitch); + +/** + Configuration for interrupt related to a GPIO. +*/ +typedef struct { + //! True if it shall trigger on rising edge. + bool rising_edge; + //! True if it shall trigger on falling edge. + bool falling_edge; + //! True if it shall have high priority (if nested isr supported). + bool high_priority; + //! ISR to be called on trigger. + gs_gpio_isr_t isr; +} gs_interrupt_conf_t; + +/** + GPIO get value + + @param[in] gpio The gpio to read + @param[in] value Returned GPIO value (true/false = High/Low) + @return_gs_error_t +*/ +gs_error_t gs_gpio_get(gs_gpio_t gpio, bool *value); + +/** + GPIO get value without error check + + @param[in] gpio The gpio to read + @return GPIO value (true/false = High/Low) +*/ +bool gs_gpio_get_nc(gs_gpio_t gpio); + +/** + GPIO set value + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @return_gs_error_t +*/ +gs_error_t gs_gpio_set(gs_gpio_t gpio, bool value); + +/** + GPIO set value without error check + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) +*/ +void gs_gpio_set_nc(gs_gpio_t gpio, bool value); + +/** + Initialize GPIO as an external interrupt pin. + + @param[in] gpio The gpio to configure + @param[in] conf Configuration of interrupt pin + @return_gs_error_t + */ +gs_error_t gs_gpio_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/i2c/common.h b/gomspace/libutil/include/gs/util/drivers/i2c/common.h new file mode 100644 index 00000000..895847d3 --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/i2c/common.h @@ -0,0 +1,88 @@ +#ifndef GS_UTIL_DRIVERS_I2C_COMMON_H +#define GS_UTIL_DRIVERS_I2C_COMMON_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Common (master and slave) I2C definitions. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Default log group for I2C driver. +*/ +GS_LOG_GROUP_EXTERN(gs_i2c_log); + +/** + I2C mode. +*/ +typedef enum { + //! Master mode + GS_I2C_MASTER = 0, + //! Multimaster mode + GS_I2C_MULTI_MASTER = 1, + //! Slave mode + GS_I2C_SLAVE = 2, +} gs_i2c_mode_t; + +/** + Cross-platform I2C configuration. +*/ +typedef struct { + //! Data order, True: MSB first, False: LSB first (default = True) + bool data_order_msb; + //! Device mode (master, multimaster, or slave) + gs_i2c_mode_t mode; + //! Address of node in multimaster and slave mode (not used in master mode) + uint16_t addr; + //! Bits per second (default is #GS_I2C_DEFAULT_BPS) + uint32_t bps; + //! Address size in bits, 7, 8 or 10 bits (default/prefered is #GS_I2C_DEFAULT_ADDRESS_SIZE) + uint8_t addrbits; +} gs_i2c_config_t; + +/** + Cross-platform I2C configuration. + @deprecated use gs_i2c_config_t. +*/ +typedef gs_i2c_config_t gs_i2c_bus_config_t; + +/** + Default bit-rate. +*/ +#define GS_I2C_DEFAULT_BPS 100000 + +/** + Default address size. +*/ +#define GS_I2C_DEFAULT_ADDRESS_SIZE 7 + +/** + Default data order (MSB). +*/ +#define GS_I2C_DEFAULT_DATA_ORDER_MSB 1 + +/** + Speed (command line sub-option). +*/ +#define GS_I2C_COMMAND_LINE_SPEED "speed" + +/** + Device (command line sub-option). +*/ +#define GS_I2C_COMMAND_LINE_DEVICE "device" + +/** + Address (command line sub-option). +*/ +#define GS_I2C_COMMAND_LINE_ADDRESS "address" + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/i2c/master.h b/gomspace/libutil/include/gs/util/drivers/i2c/master.h new file mode 100644 index 00000000..169d5d2a --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/i2c/master.h @@ -0,0 +1,32 @@ +#ifndef GS_UTIL_DRIVERS_I2C_MASTER_H +#define GS_UTIL_DRIVERS_I2C_MASTER_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + I2C master interface. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Perform transaction to I2C slave. + @param[in] device hardware device (bus) + @param[in] addr slave address + @param[in] tx transmit buffer + @param[in] txlen number of bytes to transmit + @param[out] rx receive buffer - can be NULL. + @param[in] rxlen number of bytes to receive. + @param[in] timeout_ms timeout in milliseconds, primarily for locking the I2C channel. + @return_gs_error_t +*/ +gs_error_t gs_i2c_master_transaction(uint8_t device, uint8_t addr, const void * tx, size_t txlen, void * rx, size_t rxlen, int timeout_ms); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/i2c/slave.h b/gomspace/libutil/include/gs/util/drivers/i2c/slave.h new file mode 100644 index 00000000..540000e3 --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/i2c/slave.h @@ -0,0 +1,79 @@ +#ifndef GS_UTIL_DRIVERS_I2C_SLAVE_H +#define GS_UTIL_DRIVERS_I2C_SLAVE_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + I2C slave interface. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Start/enable I2C bus reception. + + Reception should not automatically be enabled by their init() functions, as this will complicate adding additional layers/hooks. + + @param[in] device I2C bus (handle) + @return_gs_error_t +*/ +gs_error_t gs_i2c_slave_start(uint8_t device); + +/** + Rx callback. + + Function called when data has been received on the bus (I2C write operation complete). + + @param[in] device I2C bus (handle). + @param[in] rx receive buffer. + @param[in] rx_length number of bytes received. + @param_cswitch +*/ +typedef void (* gs_i2c_slave_receive_t)(uint8_t device, const uint8_t * rx, size_t rx_length, gs_context_switch_t * cswitch); + +/** + Set rx callback. + + @param[in] device I2C bus (handle). + @param[in] rx Rx callback. + @return_gs_error_t +*/ +gs_error_t gs_i2c_slave_set_rx(uint8_t device, gs_i2c_slave_receive_t rx); + +/** + Get rx buffer callback. + + Function called from driver, for getting a pointer to the rx buffer. + + @param[in] device I2C bus (handle). +*/ +typedef void * (* gs_i2c_slave_get_rx_buf_t)(uint8_t device); + +/** + Set rx buffer get callback. + + @param[in] device I2C bus (handle). + @param[in] get_rx_buf get rx buffer callback. + @param[in] buf_length length of buffer retrieved with this callback. + @return_gs_error_t +*/ +gs_error_t gs_i2c_slave_set_get_rx_buf(uint8_t device, gs_i2c_slave_get_rx_buf_t get_rx_buf, size_t buf_length); + +/** + Set response data. + + @param[in] device I2C bus (handle). + @param[in] tx pointer to data. NOTE: data is not copied due to performance, so data must stay valid until the response has been sent. + @param[in] tx_length length of data. + @return_gs_error_t +*/ +gs_error_t gs_i2c_slave_set_response(uint8_t device, const uint8_t * tx, size_t tx_length); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/spi/common.h b/gomspace/libutil/include/gs/util/drivers/spi/common.h new file mode 100644 index 00000000..069a346e --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/spi/common.h @@ -0,0 +1,66 @@ +#ifndef GS_UTIL_DRIVERS_SPI_COMMON_H +#define GS_UTIL_DRIVERS_SPI_COMMON_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Common (master and slave) SPI definitions. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Default log group for SPI driver. +*/ +GS_LOG_GROUP_EXTERN(gs_spi_log); + +/** + SPI mode - clock polarity and phase. +*/ +typedef enum { + /** + Polarity = 0, Phase = 0 (default). + */ + GS_SPI_MODE_CPOL0_CPHA0 = 0, + /** + Polarity = 0, Phase = 1. + */ + GS_SPI_MODE_CPOL0_CPHA1 = 1, + /** + Polarity = 1, Phase = 0. + */ + GS_SPI_MODE_CPOL1_CPHA0 = 2, + /** + Polarity = 1, Phase = 1. + */ + GS_SPI_MODE_CPOL1_CPHA1 = 3 +} gs_spi_mode_t; + +/** + Default bit-rate. +*/ +#define GS_SPI_DEFAULT_BPS 400000 + +/** + Speed (command line sub-option). +*/ +#define GS_SPI_COMMAND_LINE_SPEED "speed" + +/** + Slave (command line sub-option). +*/ +#define GS_SPI_COMMAND_LINE_SLAVE "slave" + +/** + Device (command line sub-option). +*/ +#define GS_SPI_COMMAND_LINE_DEVICE "device" + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/spi/master.h b/gomspace/libutil/include/gs/util/drivers/spi/master.h new file mode 100644 index 00000000..986f1ce4 --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/spi/master.h @@ -0,0 +1,95 @@ +#ifndef GS_UTIL_DRIVERS_SPI_MASTER_H +#define GS_UTIL_DRIVERS_SPI_MASTER_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + SPI master interface. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Cross-platform master SPI configuration. +*/ +typedef struct { + /** + Data order, \a True: MSB first, \a False: LSB first + Default: \a True. + */ + bool data_order_msb; + /** + Bits per second. + Default: #GS_SPI_DEFAULT_BPS. + */ + uint32_t bps; + /** + Mode, specifying polarity and phase. + Default: #GS_SPI_MODE_CPOL0_CPHA0. + */ + gs_spi_mode_t mode; + /** + Character size in bits, 8-16 bits. + Default: 8 bits (prefered). + */ + uint8_t bits; +} gs_spi_master_slave_config_t; + +/** + Single master transaction. +*/ +typedef struct { + /** + Pointer to tx data, or NULL if no tx. + */ + const void *tx; + /** + Pointer to rx buffer, or NULL if no rx. + */ + void *rx; + /** + Size/length of rx/tx (bytes). + */ + size_t size; +} gs_spi_master_trans_t; + +/** + Close/free slave. + Freeing resources associated with the slave. + @param[in] slave SPI slave + @return_gs_error_t +*/ +gs_error_t gs_spi_master_close_slave(uint8_t slave); + +/** + Perform transaction to/from a pre-configured SPI slave. + Basically for i < size: send tx[i] and receive rx[i]. + @note: 8 bit SPI character size required! + @param[in] slave SPI slave + @param[in] tx tx buffer + @param[out] rx rx buffer - can be NULL. + @param[in] size number of to send and also receive. + @param[in] timeout_ms timeout in milliseconds, primarily for locking the SPI device. + @return_gs_error_t +*/ +gs_error_t gs_spi_master_transaction(uint8_t slave, const void * tx, void * rx, size_t size, int timeout_ms); + +/** + Perform N transaction to/from a pre-configured SPI slave within one chip selection + @note: 8 bit SPI character size required! + @param[in] slave SPI slave + @param[in] trans Pointer to transactions + @param[in] count Number of transactions (rx and/or tx) to complete + @param[in] timeout_ms timeout in milliseconds, primarily for locking the SPI device. + @return_gs_error_t +*/ +gs_error_t gs_spi_master_transactions(uint8_t slave, gs_spi_master_trans_t *trans, size_t count, int timeout_ms); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/spi/slave.h b/gomspace/libutil/include/gs/util/drivers/spi/slave.h new file mode 100644 index 00000000..0be02a8e --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/spi/slave.h @@ -0,0 +1,84 @@ +#ifndef GS_UTIL_DRIVERS_SPI_SLAVE_H +#define GS_UTIL_DRIVERS_SPI_SLAVE_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + SPI slave interface. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Cross-platform slave SPI configuration. +*/ +typedef struct { + /** + Data order, \a True: MSB first, \a False: LSB first + Default: \a True. + */ + bool data_order_msb; + /** + Mode, specifying polarity and phase. + Default: #GS_SPI_MODE_CPOL0_CPHA0. + */ + gs_spi_mode_t mode; + /** + Character size in bits, 8-16 bits. + Default: 8 bits (prefered). + */ + uint8_t bits; +} gs_spi_slave_config_t; + +/** + Start/enable SPI device reception. + + Reception should not automatically be enabled by their init() functions, as this will complicate adding additional layers/hooks. + + @param[in] device SPI device (handle) + @return_gs_error_t +*/ +gs_error_t gs_spi_slave_start(uint8_t device); + +/** + Rx callback. + + Function called as data is recevied on the device. + + @param[in] device SPI device (handle). + @param[in] rx_buffer Pointer to start of rx buffer. + @param[in] rx number of bytes received so far. + @param[in] new_request \a true on the first callback of new data, \a false on receiving additional data during same \a chip-select. Can be used to bring receiver back in sync with new request. + @param_cswitch + @return total number of bytes to receive before next call back. Return 0 to ignore rest of data - no additional call backs will be done for current SPI transaction. +*/ +typedef uint8_t (* gs_spi_slave_receive_t)(uint8_t device, const uint8_t * rx_buffer, size_t rx, bool new_request, gs_context_switch_t * cswitch); + +/** + Set rx callback. + + @param[in] device SPI device (handle). + @param[in] rx Rx callback. + @return_gs_error_t +*/ +gs_error_t gs_spi_slave_set_rx(uint8_t device, gs_spi_slave_receive_t rx); + +/** + Set response data. + + @param[in] device SPI device (handle). + @param[in] offset offset (in bytes) for the response, counted from start of request, i.e. offset of 2 means data will be sent as the 3rd byte. + @param[in] tx pointer to data. NOTE: data is not copied due to performance, so data must stay valid until the response has been sent. + @param[in] size size of data. + @return_gs_error_t +*/ +gs_error_t gs_spi_slave_set_response(uint8_t device, size_t offset, const uint8_t * tx, size_t size); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/sys/memory.h b/gomspace/libutil/include/gs/util/drivers/sys/memory.h new file mode 100644 index 00000000..ca3862df --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/sys/memory.h @@ -0,0 +1,92 @@ +#ifndef GS_UTIL_DRIVERS_SYS_MEMORY_H +#define GS_UTIL_DRIVERS_SYS_MEMORY_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Cross platform memory status API. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + RAM status + Containing different size parameters describing RAM usage. + All sizes are in bytes. + If a parameter is not available/supported on a specific platform, the parameter is set to -1. + */ +typedef struct { + //! total size of RAM + long total; + //! max available RAM for allocation after initialization of of global/static variables + long max_available; + //! available RAM at runtime for dynamic allocation + long available; + //! Lowest registered available RAM since boot + long min_available; +} gs_mem_ram_stat_t; + +/** + RAM types + Defines the different RAM types (external/internal) supported on + the various platforms. + */ +typedef enum { + GS_MEM_RAM_TYPE_INTERNAL = 0,//!< Internal RAM type + GS_MEM_RAM_TYPE_EXTERNAL //!< External RAM type +} gs_mem_ram_type_t; + +/** + Get status of internal RAM + + @param[out] ram_stat RAM status, each member of struct is -1 if not supported on specific platform + @return_gs_error_t + */ +gs_error_t gs_mem_get_int_ram_stat(gs_mem_ram_stat_t * ram_stat); + +/** + Get status of external RAM + + @param[out] ram_stat RAM status, each member of struct is -1 if not supported on specific platform + @return_gs_error_t + */ +gs_error_t gs_mem_get_ext_ram_stat(gs_mem_ram_stat_t * ram_stat); + + +/** + Get status of selected RAM + + @param[in] type RAM type to query status for + @param[out] ram_stat RAM status, each member of struct is -1 if not supported on specific platform + @return_gs_error_t + */ +gs_error_t gs_mem_get_ram_stat(gs_mem_ram_type_t type, gs_mem_ram_stat_t * ram_stat); + + +/** + Get default RAM type + + returns the default RAM type used for allocations (Heap). + @return gs_mem_ram_type_t + */ +gs_mem_ram_type_t gs_mem_get_ram_default(); + + +/** + Print RAM status. + + @param[in] ram_stat RAM status + @param[in] out output stream + @return_gs_error_t + */ +gs_error_t gs_mem_print_ram_stat(gs_mem_ram_stat_t * ram_stat, FILE * out); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/drivers/watchdog/device.h b/gomspace/libutil/include/gs/util/drivers/watchdog/device.h new file mode 100644 index 00000000..613e511e --- /dev/null +++ b/gomspace/libutil/include/gs/util/drivers/watchdog/device.h @@ -0,0 +1,61 @@ +#ifndef GS_UTIL_DRIVERS_HW_WATCHDOG_H +#define GS_UTIL_DRIVERS_HW_WATCHDOG_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Hardward watchdog (HWWD) device interface. + + Hardware Watchdog interface which provides a generic interface towards + any HWWD. Most HWWD implementation should be able to fit behind + this interface, with just a small "adaption" layer needed. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Hardware watchdog driver interface. +*/ +typedef struct gs_watchdog_dev_ops gs_watchdog_dev_ops_t; + +/** + Hardware watchdog (HWWD) device structure + + Structure that describes the HWWD device and holds + the parameters needed for storing e.g. timeout values etc. +*/ +typedef struct gs_watchdog_device { + int id; /**< An ID for the HWWD device - This is currently not used. */ + const gs_watchdog_dev_ops_t *ops; /**< Pointer to ops struct defining the operations a HWWD device supports. */ + unsigned int timeout; /**< The timeout value that the HWWD device should be configured with. */ + unsigned int pretimeout; /**< The pretimeout (if supported) by the HWWD device */ + unsigned int min_timeout; /**< Minimum timeout value supported by the HWWD device */ + unsigned int max_timeout; /**< Maximum timeout value supported by the HWWD device */ + void *driver_data; /**< Pointer to driver specific data can be used by the HWWD driver impl. */ +} gs_watchdog_device_t; + +/** + Hardware watchdog driver interface. +*/ +struct gs_watchdog_dev_ops +{ + /* mandatory operations */ + gs_error_t (*start)(gs_watchdog_device_t *); /**< Starts the HWWD device */ + gs_error_t (*stop)(gs_watchdog_device_t *); /**< Stops the HWWD device */ + gs_error_t (*ping)(gs_watchdog_device_t *); /**< Polls the HWWD device and restart count-down */ + /* optional operations */ + gs_error_t (*set_timeout)(gs_watchdog_device_t *, unsigned int); /**< (Optional) Set timeout of the HWWD device */ + gs_error_t (*set_pretimeout)(gs_watchdog_device_t *, unsigned int); /**< (Optional) Set Pre-timeout of the HWWD device */ + gs_error_t (*restart)(gs_watchdog_device_t *); /**< (Optional) Restart the HWWD device */ + unsigned int (*get_timeleft)(gs_watchdog_device_t *); /**< (Optional) Get time left until HWWD device times out. */ + int (*status)(gs_watchdog_device_t *); /**< (Optional) Reads status of the HWWD device */ +}; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/endian.h b/gomspace/libutil/include/gs/util/endian.h new file mode 100644 index 00000000..15e22ae1 --- /dev/null +++ b/gomspace/libutil/include/gs/util/endian.h @@ -0,0 +1,53 @@ +#ifndef GS_UTIL_ENDIAN_H +#define GS_UTIL_ENDIAN_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Detecting endian type. +*/ + +// generated by waf configure, defines either UTIL_BIG_ENDIAN or UTIL_LITTLE_ENDIAN +#include "../../conf_util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if !UTIL_BIG_ENDIAN && !UTIL_LITTLE_ENDIAN + #error No endian defined +#endif +#if UTIL_BIG_ENDIAN && UTIL_LITTLE_ENDIAN + #error Both big and little endian defined +#endif + +#include + +/** + Returns \a true if platform is big endian. +*/ +static inline bool gs_endian_big(void) +{ +#if (UTIL_BIG_ENDIAN) + return true; +#else + return false; +#endif +} + +/** + Returns \a true if platform is little endian. +*/ +static inline bool gs_endian_little(void) +{ +#if (UTIL_LITTLE_ENDIAN) + return true; +#else + return false; +#endif +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/error.h b/gomspace/libutil/include/gs/util/error.h new file mode 100644 index 00000000..d1743165 --- /dev/null +++ b/gomspace/libutil/include/gs/util/error.h @@ -0,0 +1,199 @@ +#ifndef GS_UTIL_ERROR_H +#define GS_UTIL_ERROR_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Common error code definitions. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Common/generic error codes. + Based on POSIX \a errno values, but negative instead of positive. +*/ +typedef enum gs_error_t { + /** + Success - ok (POSIX). + */ + GS_OK = 0, + /** + Operation not permitted (POSIX.1: EPERM). + */ + GS_ERROR_PERM = -1, + /** + Interrupted system call (or Interrupted function call) (POSIX: EINTR). + */ + GS_ERROR_INTR = -4, + /** + Input/output error (POSIX.1: EIO) + */ + GS_ERROR_IO = -5, + /** + Resource temporarily unavailable (may be the same value as EWOULDBLOCK) (POSIX.1: EAGAIN). + */ + GS_ERROR_AGAIN = -11, + /** + Cannot allocate memory (or Not enough space) (POSIX.1: ENOMEM). + */ + GS_ERROR_ALLOC = -12, + /** + Permission denied (POSIX.1: EACCES). + */ + GS_ERROR_ACCESS = -13, + /** + Device or resource busy (POSIX.1: EBUSY). + */ + GS_ERROR_BUSY = -16, + /** + File exists (POSIX.1-2001: EEXIST). + */ + GS_ERROR_EXIST = -17, + /** + Invalid argument (POSIX.1: EINVAL). + */ + GS_ERROR_ARG = -22, + /** + Function not implemented (POSIX.1: ENOSYS) + */ + GS_ERROR_NOT_IMPLEMENTED = -38, + /** + Value too large to be stored in data type (POSIX.1: EOVERFLOW). + Example: trying to put 50 characters into a 10 character array. + @see GS_ERROR_RANGE. + */ + GS_ERROR_OVERFLOW = -75, + /** + Operation not supported (POSIX.1: ENOTSUP) + */ + GS_ERROR_NOT_SUPPORTED = -95, + /** + Address already in use (POSIX.1: EADDRINUSE). + */ + GS_ERROR_IN_USE = -98, + /** + Connection reset (POSIX.1-2001: ECONNRESET). + */ + GS_ERROR_CONNECTION_RESET = -104, + /** + No buffer space available (POSIX.1 (XSI STREAMS option): ENOBUFS). + */ + GS_ERROR_NO_BUFFERS = -105, + /** + Timeout (POSIX.1-2001: ETIMEDOUT). + */ + GS_ERROR_TIMEOUT = -110, + /** + Connection already in progress (POSIX.1-2001: EALREADY). + */ + GS_ERROR_ALREADY_IN_PROGRESS = -114, + + /** + Handle error (GOMspace). + */ + GS_ERROR_HANDLE = -2000, // from errno.h: #define __ELASTERROR 2000 /* Users can add values starting here */ + /** + Not found (GOMspace). + */ + GS_ERROR_NOT_FOUND = -2001, + /** + Full (GOMspace). + */ + GS_ERROR_FULL = -2002, + /** + Range error (GOMspace). + Example: specifying 120 hours, where only 0-23 is valid. + @see GS_ERROR_OVERFLOW + */ + GS_ERROR_RANGE = -2003, + /** + Data error (GOMspace). + */ + GS_ERROR_DATA = -2004, + /** + Unknown error (GOMspace). + @note avoid use - use specific error to improve debugging/troubleshooting. + */ + GS_ERROR_UNKNOWN = -2005, + /** + No data available (GOMspace). + */ + GS_ERROR_NO_DATA = -2006, + /** + Stale data - not updated (GOMspace). + */ + GS_ERROR_STALE = -2007, + /** + Type error (GOMspace). + */ + GS_ERROR_TYPE = -2008, + /** + Ambiguous error (GOMspace). + */ + GS_ERROR_AMBIGUOUS = -2009, + /** + State error (GOMspace). + */ + GS_ERROR_STATE = -2010, + +} gs_error_t; + +/** + * Convert an error code to a string. + * Uses standard POSIX strerror() under the hood. + * @param[in] error error to convert. If negative (e.g. \a gs_error_t), it is first converted to a positive value. + * @return string usefull for logging purposes (should not be used for programatically processing). + */ +const char * gs_error_string(int error); + +/** + Convert standard POSIX \a errno to gs_error_t. + @param[in] error POSIX error code (errno). + @return convert error code, by simply converting to a negative number. +*/ +gs_error_t gs_error(int error); + +#if (GS_UTIL_DEPRECATED_ERROR_CODES) +/** + Legacy error definitions. + @deprecated Use standard gs_error_t codes - these defines are only kept, so very old code (not yet update to use #gs_error_t) can compile. + @{ +*/ +#define E_NO_ERR -1 +#define E_NO_DEVICE -2 +#define E_MALLOC_FAIL -3 +#define E_THREAD_FAIL -4 +#define E_NO_QUEUE -5 +#define E_INVALID_BUF_SIZE -6 +#define E_INVALID_PARAM -7 +#define E_NO_SS -8 +#define E_GARBLED_BUFFER -9 +#define E_FLASH_ERROR -10 +#define E_BOOT_SER -13 +#define E_BOOT_DEBUG -14 +#define E_BOOT_FLASH -15 +#define E_TIMEOUT -16 +#define E_NO_BUFFER -17 +#define E_OUT_OF_MEM -18 +#define E_FAIL -19 +/** @} */ + +/** + Converts legacy error definitions to string. + @deprecated Use standard gs_error_t codes - this function is only kept, so very old code (not yet update to use #gs_error_t) can compile. + @param[in] code error code + @return string describing the error. +*/ +const char * error_string(int code) __attribute__((deprecated)); + +#endif // GS_UTIL_DEPRECATED_ERROR_CODES + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/fletcher.h b/gomspace/libutil/include/gs/util/fletcher.h new file mode 100644 index 00000000..5b24c23c --- /dev/null +++ b/gomspace/libutil/include/gs/util/fletcher.h @@ -0,0 +1,89 @@ +#ifndef GS_UTIL_FLETCHER_H +#define GS_UTIL_FLETCHER_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Fletcher16 checksum, +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Fletcher16 checksum (read using copy function). + + Data is read from \a data, using the specified \a memcpyfcn function. + + @param[in] data data. + @param[in] size number of \a data bytes. + @param[in] memcpyfcn memory copy function. If NULL is specified, standard memcpy will be used. + @returns fletcher16 checksum +*/ +uint16_t gs_fletcher16_memcpy(const void * data, size_t size, void * (*memcpyfcn)(void *, const void *, size_t)); + +/** + Fletcher16 checksum (read from program memory). + + AVR8: reads from program memory. + Other architectures: identical to gs_fletcher16(). + + @param[in] data_in data. + @param[in] size number of \a data bytes. + @returns fletcher16 checksum +*/ +uint16_t gs_fletcher16_P(const void * data_in, size_t size); + +/** + Fletcher16 checksum. + + @param[in] data data. + @param[in] size number of \a data bytes. + @returns fletcher16 checksum +*/ +uint16_t gs_fletcher16(const void * data, size_t size); + +/** + Fletcher16 working set. + @see gs_fletcher16_init(), gs_fletcher16_update(), gs_fletcher16_finalize() +*/ +typedef struct { + /** + Sum1 - internal. + */ + uint16_t sum1; + /** + Sum2 - internal. + */ + uint16_t sum2; +} gs_fletcher16_t; + +/** + Initialize fletcher16 working set. + @param[in] f16 working set. +*/ +void gs_fletcher16_init(gs_fletcher16_t * f16); + +/** + Update fletcher16 checksum. + @param[in] f16 working set. + @param[in] data data. + @param[in] size number of \a data bytes. +*/ +void gs_fletcher16_update(gs_fletcher16_t * f16, const void * data, size_t size); + +/** + Finalize fletcher16 checksum and return it. + + @param[in] f16 working set. + @returns fletcher16 checksum +*/ +uint16_t gs_fletcher16_finalize(gs_fletcher16_t * f16); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/function_scheduler.h b/gomspace/libutil/include/gs/util/function_scheduler.h new file mode 100644 index 00000000..229c5031 --- /dev/null +++ b/gomspace/libutil/include/gs/util/function_scheduler.h @@ -0,0 +1,79 @@ +#ifndef GS_UTIL_FUNCTION_SCHEDULER +#define GS_UTIL_FUNCTION_SCHEDULER +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Function scheduler. + + Simple framework for invoking functions at intervals. + + Instead of creating a lot of tasks (which uses memory), this framework can be used to schedule execution of functions at specified intervals. + + Once setup, calling gs_function_scheduler_execute_ms() will execute all functions timed out and return the time, until the next function has + to be executed or max timeout specified (or max wait time supported on the platform). + + The API supports multiple schedulers, but is not thread-safe. + + @note Do NOT use for time critical control, as the actual time interval is influenced by the host thread and other scheduled functions. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Scheduler handle. +*/ +typedef struct gs_function_scheduler gs_function_scheduler_t; + +/** + Function callback. + + @return timeout in mS until next callback. +*/ +typedef uint32_t (*gs_function_scheduler_function_t)(void * user_data); + +/** + Initialize scheduler. + Memory is allocated once for \a max_entries. + @param[in] max_timeout_ms max timeout in mS. + @param[in] max_entries max number of entries for this scheduler. + @param[out] scheduler reference to created scheduler. + @return_gs_error_t +*/ +gs_error_t gs_function_scheduler_create(uint32_t max_timeout_ms, unsigned int max_entries, gs_function_scheduler_t ** scheduler); + +/** + Free scheduler (release resources). + @param[in] scheduler scheduler. + @return_gs_error_t +*/ +gs_error_t gs_function_scheduler_destroy(gs_function_scheduler_t * scheduler); + +/** + Execute scheduled function(s) and returns number of mS until next execute must be called again. + + @note Return type is \a int to prevent overflow on platforms where int is less than 32 bits. + + @param[in] scheduler scheduler. + @return next timeout in mS. +*/ +int gs_function_scheduler_execute_ms(gs_function_scheduler_t * scheduler); + +/** + Register function to be executed at mS intervals. + @param[in] scheduler scheduler. + @param[in] first_timeout_ms mS until first execution. + @param[in] func function to execute. + @param[in] user_data function user data. + @return_gs_error_t +*/ +gs_error_t gs_function_scheduler_register_ms(gs_function_scheduler_t * scheduler, uint32_t first_timeout_ms, gs_function_scheduler_function_t func, void * user_data); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/gosh/command.h b/gomspace/libutil/include/gs/util/gosh/command.h new file mode 100644 index 00000000..8187152e --- /dev/null +++ b/gomspace/libutil/include/gs/util/gosh/command.h @@ -0,0 +1,503 @@ +#ifndef GS_UTIL_GOSH_COMMAND_H +#define GS_UTIL_GOSH_COMMAND_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Command framework. + + Provides a simple way of organizing commands in a hierarchy. A command is a text string mapping to a function - supporting arguments. +*/ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Max langth of a command (including NUL termination). +*/ +#define GS_COMMAND_MAX_LEN_COMMAND 20 + +/** + Flag for hiding command in help and tab-complete. +*/ +#define GS_COMMAND_FLAG_HIDDEN 0x02 + +/** + 'root' command attribute. + + On embedded (none Linux) systems, it is prefered to store as much as possible in \a program memory, in order to save RAM. + This is accomplished by tagging all \a root commands with this attribute, which instructs the linker to put all commands in a named + section. This section is then through the linker-script, placed in \a program memory. + The command framework can read commands directly from this section, and therefore doesn't need an RAM to maintain the list. + + The gs_command_register() must still be called for all \a root commands, which ensures that the linker doesn't throw away the + command objects, due to missing code reference. + + On a Linux system, the commands are not group in a section. Instead gs_command_register() dynamicly builds a list with the commands. + + @see gs_command_register() +*/ +#if (__linux__ == 0) +#define GS_COMMAND_ROOT __attribute__ ((section(".commands"))) +#else +#define GS_COMMAND_ROOT +#endif + +/** + Sub command attribute, + + Only necesasry on AVR8, due to its memory model. +*/ +#define GS_COMMAND_SUB GS_PGM_OBJECT + +/** + Macro for initializing command chains. +*/ +#define GS_COMMAND_INIT_CHAIN(__list) {.list = __list, .count = GS_ARRAY_SIZE(__list)} + +/** + Macro for registering commands. + + @see gs_command_register() +*/ +#define GS_COMMAND_REGISTER(__cmd) gs_command_register(__cmd, GS_ARRAY_SIZE(__cmd)) + +/** + Command reference. + @note Use gs_command_t instead of 'struct command'. +*/ +typedef struct command gs_command_t; + +/** + Commands context reference + @note Use gs_command_context_t instead of struct command_context + */ +typedef struct command_context gs_command_context_t; + +/** + Command output interface +*/ +typedef struct command_io_functions { + /** + Function interface for setting result + @param output_ctx pointer to output context for the given impl. + @param group Group name specifies the group that a given key/value pair belongs to. + @param key key name + @param value string value of the result + @return_gs_error_t + */ + gs_error_t (*set_result)(gs_command_context_t *ctx, const char *group, const char *key, const char *value); + /** + Function interface for flushing results. Used by the command handler to ensure output/results + are flushed to stdout/File or any other receiver of the output. + @param output_ctx pointer to output context for the given impl. + @return_gs_error_t + */ + gs_error_t (*flush)(gs_command_context_t *ctx); + /** + Function interface for waiting for key/input + @param output_ctx pointer to output context for the given impl. + @param ch pointer to character returned by function + @param timeout_ms maximum time to wait of the character. + @return_gs_error_t + */ + gs_error_t (*wait_for_key)(gs_command_context_t *ctx, int *ch, int timeout_ms); +} gs_command_io_functions_t; + + + +/** + Command context for executing a command. +*/ +struct command_context { + /** + Input (raw) command line, including arguments. + */ + const char * command_line; + + /** + Command being executed. + */ + const gs_command_t * command; + + /** + Number of arguments (standard argc style). + */ + int argc; + + /** + Argument array (standard argv style). + */ + char **argv; + + /** + FILE handle for capturing stdout from command. + */ + FILE* out; + + /** + getopt variable. + */ + int optind; + + /** + getopt variable. + */ + int optopt; + + /** + getopt variable. + */ + char *optarg; + + /** + getopt variable. + */ + int optsp; + + /** + Function interface for I/O operations + */ + const gs_command_io_functions_t *io_functions; + + /** + Pointer for storing the context used by the I/O functions + */ + void * io_ctx; +}; + +/** + Command logging call-back + + logs information on the command called. + @param[in] cmd_line command line string + @param[in] ret return code from command execution framework + @param[in] cmd_ret return code from the executed command + @param[in] start time_stamp when command execution started. + @param[in] end time_stamp when command execution completed. + @param[in] ctx context pointer for the logger. + @return_gs_error_t +*/ +typedef gs_error_t (*gs_command_log_t)(const char *cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t start, gs_timestamp_t end, void * ctx); + +/** + Command handler. +*/ +typedef int (*gs_command_handler_t)(gs_command_context_t * ctx); + +/** + Completer call-back (tab complete). + + @param[in] ctx command context. + @param[in] arg_to_complete argument to complete + @return #GS_OK Found at least 1 match. + The \a completer is expected to have completed more of the command line. + If the framework detects multiple matches, the framework will proceed as if #GS_ERROR_AMBIGUOUS was returned. + The framework doesn't expect anything to be printed to \a out, but will update/refresh the console line. + @return #GS_ERROR_AMBIGUOUS Ambiguous - multiple matches or force the framework to show help. + The \a completer may have extended/completed more of the command line. + The framework expects the \a completer to have printed to \a out, and will show help/usage for the command on a new line. + @return #GS_ERROR_NOT_FOUND (or others) No matches found or no more arguments to complete. + The framewrok doesn't expect anything to be printed to \a out, and will not update the console. +*/ +typedef gs_error_t (*gs_command_completer_t)(gs_command_context_t * ctx, int arg_to_complete); + +/** + Add token - helper to 'tab complete' argument(s). + + @param[in] ctx command context. + @param[in] token possible completion - the API will find the common part. + @param[in] exact \a true if \a token is an exact match - all other added tokens will be ignored. + @return number of tokens added. +*/ +unsigned int gs_command_completer_add_token(gs_command_context_t * ctx, const char * token, bool exact); + +/** + Chain element for chaning sub-commands. +*/ +typedef struct { + /** + Command list. + */ + const gs_command_t * list; + /** + Number of commands in the \a list. + */ + unsigned int count; +} gs_command_chain_t; + +/** + Signals no command arguments in command definition, see mandatory arguments. +*/ +#define GS_COMMAND_NO_ARGS 255 + +/** + Command definition. +*/ +struct command { +#if (__AVR__) + char name[GS_COMMAND_MAX_LEN_COMMAND]; + char help[50]; + char usage[50]; +#else + /** + Name. + */ + const char * const name; + /** + Help text. + */ + const char * const help; + /** + Usage text. + */ + const char * const usage; +#endif + /** + Command handler - the "actual command function". + */ + gs_command_handler_t handler; +#if (__AVR__ == 0) + /** + Completer function - helps completing an argument. + */ + gs_command_completer_t completer; +#endif + /** + Sub-command (if any). + */ + gs_command_chain_t chain; + /** + Mode/flags. + See #GS_COMMAND_FLAG_HIDDEN. + */ + unsigned int mode; + /** + Number of mandatory (minimum) arguments. + + @note Due to backwards compatibility, 0 (zero) cannot be used to signal no arguments - use #GS_COMMAND_NO_ARGS instead, if command doesn't take any arguments (mandatory or optional). + */ + uint8_t mandatory_args; + /** + Number of optional arguments. + */ + uint8_t optional_args; + /** + Filler for future use. + */ + uint8_t filler[2]; +}; + +/** + Returns the arguments as a string, where arguments are separated by spaces. + @param ctx command context. + @return Pointer to concatenated arguments +*/ +const char * gs_command_args(gs_command_context_t *ctx); + +/** + Execute command. + @deprecated Replaced by gs_command_execute & gs_command_execute_stdio + + Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return + result is stored in \a command_result. + + @param[in] command Command to execute, including arguments separated by spaces. + @param[out] command_result Result returned by \a command (if executed). Use \a NULL to ignore result. + @return #GS_ERROR_NOT_FOUND if command wasn't found. + @return #GS_ERROR_ARG if number of argumenets exceeds \a mandatory + \a optional count. + @return_gs_error_t +*/ +gs_error_t gs_command_run(const char * command, gs_error_t * command_result); + +/** + Execute command. + + Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return + result is stored in \a command_result. + + @param[in] command Command to execute, including arguments separated by spaces. + @param[out] command_result Result returned by \a command (if executed). Use \a NULL to ignore result. + @param[in] out output (FILE) stream + @param[in] iof Pointer to function interface of IO operations + @param[in] iof_ctx Pointer to context used by the IO function interface + @return #GS_ERROR_NOT_FOUND if command wasn't found. + @return #GS_ERROR_ARG if number of argumenets exceeds \a mandatory + \a optional count. + @return_gs_error_t +*/ +gs_error_t gs_command_execute(const char * command, gs_error_t * command_result, FILE *out, const gs_command_io_functions_t * iof, void * iof_ctx); + +/** + Execute command. + + Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return + result is stored in \a command_result. The results are printed on stdout and input captured on stdin. + + @param[in] command Command to execute, including arguments separated by spaces. + @param[out] command_result Result from command. Use \a NULL to ignore result. + @return #GS_OK if command was executed - result returned in \a command_result. Otherwise an error indicating why the command wasn't executed. +*/ +gs_error_t gs_command_execute_stdio(const char * command, gs_error_t * command_result); + +/** + Set output + + Sets output from command, using the io function struct in ctx. + + @param[in] ctx the command context + @param[in] group a string specifying the group of the result. Leave blank if not used. + @param[in] key a string specifying the key/name of the result variable. + @param[in] value a string representation of the result value. + @return_gs_error_t +*/ +gs_error_t gs_command_set_output(gs_command_context_t *ctx, const char* group, const char* key, const char* value); + +/** + Set output + + Sets output from command using printf formatting, using the io function struct in ctx. + + @param[in] ctx the command context + @param[in] group a string specifying the group of the result. Leave blank if not used. + @param[in] key a string specifying the key/name of the result variable. + @param[in] format printf syntax for formatting data + @return_gs_error_t +*/ +gs_error_t gs_command_set_output_printf(gs_command_context_t *ctx, const char* group, const char* key, const char * format, ...); + +/** + Flush output/Results + + Instruct the command output stream & results to be flushed from it's buffers. + + @param[in] ctx the command context + @return_gs_error_t +*/ +gs_error_t gs_command_flush_output(gs_command_context_t *ctx); + +/** + Wait for any key input + + Instruct the command input stream to wait for any key. + + @param[in] ctx the command context + @param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milliseconds. + @return true if command should proceed (either because of key press present or if no input stream available) +*/ +bool gs_command_wait_any_key(gs_command_context_t *ctx, int timeout_ms); + +/** + Wait for key input + + Instruct the io stream to wait for a key, and return the pressed key in ch. + + @param[in] ctx the command context + @param[out] ch the character that was read on the input stream + @param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milliseconds. + @return #GS_OK if key was read + @return #GS_ERROR_HANDLE if no input stream is present + @return #GS_ERROR_TIMEOUT on timeout. +*/ +gs_error_t gs_command_wait_key(gs_command_context_t *ctx, int* ch, int timeout_ms); + +/** + Register commands. + + gs_command_init() must be called prior to registering any commands. + + See #GS_COMMAND_ROOT for details. + + @param[in] cmds Pointer to command array + @param[in] cmd_count Number of commands in command array + @return_gs_error_t +*/ +gs_error_t gs_command_register(const gs_command_t * cmds, size_t cmd_count); + +/** + Initialize command system and register default commands. + + Registers following commands: gs_log_register_commands() and gs_command_register_default_commands(). + + @param[in] min_stack_size Minimum stack size required for executing commands. The stack size will be used by other sub-systems such as gs_console, g-script. Stack size may be ignored on some platforms, e.g. Linux. + @return_gs_error_t + @see gs_command_init_no_commands() +*/ +gs_error_t gs_command_init(size_t min_stack_size); + +/** + Initialize command system (without any default commands). + + @param[in] min_stack_size Minimum stack size required for executing commands. The stack size will be used by other sub-systems such as gs_console, g-script. Stack size may be ignored on some platforms, e.g. Linux. + @return_gs_error_t + @see gs_command_init() +*/ +gs_error_t gs_command_init_no_commands(size_t min_stack_size); + + +/** + Register a call-back used for logging of command execution. + + @param[in] log_cb the logging call back. + @param[in] log_ctx pointer to context data. Set to NULL if not used. + @return_gs_error_t +*/ +gs_error_t gs_command_register_logger(gs_command_log_t log_cb, void *log_ctx); + +/** + Default implementation of the command logger, that can be used if no other + custom command logger is provided by the system. + + @param[in] cmd_line command line string + @param[in] ret return code provided by the command execution function. + @param[in] cmd_ret return code provided by the executed command. + @param[in] t_start time stamp when command execution started. + @param[in] t_end time stamp when command execution completed. + @param[in] log_ctx context for the command logger. + @return_gs_error_t +*/ +gs_error_t gs_command_logger_default(const char* cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t t_start, gs_timestamp_t t_end, void * log_ctx); + +/** + Return minimum stack size. + @return minimm stack size required for executing commands. The minimum stack size is set by call to gs_command_init(). +*/ +size_t gs_command_get_stack_size(void); + +/** + Register set of default commands. + @return_gs_error_t +*/ +gs_error_t gs_command_register_default_commands(void); + +/** + Split line into argc/argv. + + @param[in] line line to split - the line will be chop up into argv. + @param[out] argc argc count. + @param[out] argv argv array. + @param[in] max_argc max argv elements. + @return \a true if successfull, else \a false. +*/ +bool gs_command_build_argv(char *line, int *argc, char **argv, int max_argc); + +/** + Parse options. + + Adapted from AT&T public domain source from: + http://www.informatica.co.cr/unix-source-code/research/1985/1103.html + + @param[in] ctx command context. + @param[in] opts options + @return option character +*/ +int gs_command_getopt(gs_command_context_t *ctx, const char *opts); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/gosh/console.h b/gomspace/libutil/include/gs/util/gosh/console.h new file mode 100644 index 00000000..e0c9c42a --- /dev/null +++ b/gomspace/libutil/include/gs/util/gosh/console.h @@ -0,0 +1,123 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +#ifndef GS_UTIL_GOSH_CONSOLE_H +#define GS_UTIL_GOSH_CONSOLE_H +/** + @file + + Console (stdin/stdout) interface for running commands. + + This assumes a VT102 terminal emulator, and tries to fix some of minicom's quirks with e.g. home/end keys. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Initialize the API and console. + + @deprecated version 3.4, use gs_console_start() + + @return_gs_error_t +*/ +gs_error_t gs_console_init(void); + +/** + Restores terminal settings (only relevant on Linux). + + @deprecated version 3.4, this is handled by an installed exit-handler in gs_console_start(). + + @return_gs_error_t +*/ +gs_error_t gs_console_exit(void); + +/** + Set console prompt. + + @param[in] prompt user prompt - the API only stores the pointer, so do not modify/delete content. NULL or empty string is ignored (no change). +*/ +void gs_console_set_prompt(const char * prompt); + +/** + Clear the console screen +*/ +void gs_console_clear(void); + +/** + Update console. +*/ +void gs_console_update(void); + +/** + Create console thread. + + The console thread reads from stdin and writes to stdout. + + The thread is created with low priority, #GS_THREAD_PRIORITY_LOW. + + @deprecated version 3.4, use gs_console_start() + + @param[out] handle handle to created thread - thread will be created joinable if supported by platform. Use NULL, if not wanted. + @return_gs_error_t +*/ +gs_error_t gs_console_create_thread(gs_thread_t * handle); + +/** + Create console thread with priority. + + The console thread reads from stdin and writes to stdout. + + @deprecated version 3.4, use gs_console_start() + + @param[in] priority thread priority, normally #GS_THREAD_PRIORITY_LOW. + @param[out] handle handle to created thread - thread will be created joinable if supported by platform. Use NULL, if not wanted. + @return_gs_error_t +*/ +gs_error_t gs_console_create_thread_with_priority(gs_thread_priority_t priority, gs_thread_t * handle); + +/** + @anchor GS_CONSOLE_F + @defgroup GS_CONSOLE_F Console flags. + Use with gs_console_start() to configure behaviour. + @{ +*/ +/** + Linux only: no signal handlers installed (e.g. to catch SIG_TERM). + @see gs_console_start() +*/ +#define GS_CONSOLE_F_NO_SIGNAL_HANDLER 0x0001 +/** @} */ + +/** + Start console thread (priority: #GS_THREAD_PRIORITY_LOW). + + The console thread reads from stdin and writes to stdout. The thread is created with low priority, #GS_THREAD_PRIORITY_LOW. + + Linux: Changes terminal settings and installs an atexit() handler to restore the settings, Signal handlers will be installed to catch SIG_TERM -> exit() and ignore SIG_INT (controlled by option on command line) - unless #GS_CONSOLE_F_NO_SIGNAL_HANDLER is specified. + + @param[in] prompt set console prompt by calling gs_console_set_prompt(). + @param[in] flags configure behaviour, see @ref GS_CONSOLE_F definitions. + @return #GS_ERROR_EXIST if console thread already created. + @return_gs_error_t +*/ +gs_error_t gs_console_start(const char * prompt, uint32_t flags); + +/** + Stop (and join with) console thread. + + @note This is only supported on Linux. + + The thread is interrupted using pthread_cancel(), which does not guarantee \a clean shutdown if the thread is busy executing a command. + + @return #GS_ERROR_NOT_SUPPORTED if not supported on current platform. + @return #GS_ERROR_HANDLE if no console has been started with gs_console_start(). + @return_gs_error_t +*/ +gs_error_t gs_console_stop(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/hexdump.h b/gomspace/libutil/include/gs/util/hexdump.h new file mode 100644 index 00000000..43a085e5 --- /dev/null +++ b/gomspace/libutil/include/gs/util/hexdump.h @@ -0,0 +1,53 @@ +#ifndef GS_UTIL_HEXDUMP_H +#define GS_UTIL_HEXDUMP_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Dump memory as hex numbers and ascii characters. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Dump memory to an output stream. + @param[in] src memory address. + @param[in] len number of bytes to dump. + @param[in] disp_addr display address, used instead of \a src. + @param[in] out output stream. +*/ +void gs_hexdump_to_stream(const void * src, size_t len, const void * disp_addr, FILE* out); + +/** + Dump memory on stdout. + + @param[in] src memory address. + @param[in] len number of bytes to dump. +*/ +static inline void gs_hexdump(const void *src, size_t len) +{ + gs_hexdump_to_stream(src, len, src, stdout); +} + +/** + Dump memory on stdout. + @param[in] src memory address. + @param[in] len number of bytes to dump. + @param[in] disp_addr display address, used instead of \a src. +*/ +static inline void gs_hexdump_addr(const void * src, size_t len, const void * disp_addr) +{ + gs_hexdump_to_stream(src, len, disp_addr, stdout); +} + +#ifdef __cplusplus +} +#endif +#endif + + diff --git a/gomspace/libutil/include/gs/util/linux/argp.h b/gomspace/libutil/include/gs/util/linux/argp.h new file mode 100644 index 00000000..b8eff835 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/argp.h @@ -0,0 +1,40 @@ +#ifndef GS_UTIL_LINUX_ARGP_H +#define GS_UTIL_LINUX_ARGP_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Extensions to GNU argp parser (convenience functions). +*/ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Wrapper for argp_parse. + + This function will call exit/terminate the process, if parsing fails. + + \a argv may be re-organized. + + @param[in] argp argp struct. + @param[in] argc argument count, i.e. standard argc. + @param[in] argv argument array, i.e. standard argv. + @param[in] flags future use. + @param[out] arg_index first unparsed option (-> argv modified). + @param[in] revision program revision, e.g. 3.0.1-12-g0cf1b59+. +*/ +void gs_argp_parse(const struct argp * argp, + int argc, char ** argv, + unsigned int flags, int * arg_index, + const char * revision); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/command_line.h b/gomspace/libutil/include/gs/util/linux/command_line.h new file mode 100644 index 00000000..d9dbc3a3 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/command_line.h @@ -0,0 +1,42 @@ +#ifndef GS_UTIL_LINUX_COMMAND_LINE_H +#define GS_UTIL_LINUX_COMMAND_LINE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Command line support. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Command line options for ignoring CTRL-C +*/ +extern const struct argp_child gs_console_command_line_ignore_ctrlc_argp; + +/** + Command line options for adding -h (help). +*/ +const struct argp_child gs_help_command_line_argp; + +/** + Return if ctrl-c ignored on command line. + @return \a true i ctrl-c ignored. +*/ +bool gs_command_line_ignore_ctrlc(void); + +/** + Return program name based on argv[0]. + @param[in] argv expected to be argv[0] amd point to the program name (possibly with full path). + @return program name. +*/ +const char * gs_command_line_program_name(const char * argv); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/can/can.h b/gomspace/libutil/include/gs/util/linux/drivers/can/can.h new file mode 100644 index 00000000..f04b3f83 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/drivers/can/can.h @@ -0,0 +1,29 @@ +#ifndef GS_UTIL_LINUX_DRIVERS_CAN_CAN_H +#define GS_UTIL_LINUX_DRIVERS_CAN_CAN_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Linux CAN interface. + + @note Only 1 filter/mask can be set, using gs_can_set_standard_filter_mask() or gs_can_set_extended_filter_mask() +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Open and initialize a CAN handle. + @param[in] ifname name of CAN interface. + @param[out] handle opened CAN handle. + @return_gs_error_t +*/ +gs_error_t gs_can_open(const char * ifname, int * handle); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h new file mode 100644 index 00000000..f04cc1f5 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h @@ -0,0 +1,146 @@ +#ifndef GS_UTIL_LINUX_DRIVERS_GPIO_H +#define GS_UTIL_LINUX_DRIVERS_GPIO_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + @brief GPIO interface + + GPIO interface provides a generic interface where specific GPIO drivers can be plugged in. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + GomSpace linux driver GPIO get value + + @param[in] gpio The gpio to read + @param[in] value Returned GPIO value (true/false = High/Low) + @param[in] driver_data data to specific driver + + @return_gs_error_t +*/ +typedef gs_error_t (*gs_gpio_get_t)(gs_gpio_t gpio, bool *value, void * driver_data); + +/** + GomSpace linux driver GPIO get value without error check + + @param[in] gpio The gpio to read + @param[in] driver_data data to specific driver + + @return GPIO value (true/false = High/Low) +*/ +typedef bool (*gs_gpio_get_nc_t)(gs_gpio_t gpio, void * driver_data); + +/** + GomSpace linux driver GPIO set value + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @param[in] driver_data data to specific driver + + @return_gs_error_t +*/ +typedef gs_error_t (*gs_gpio_set_t)(gs_gpio_t gpio, bool value, void * driver_data); + +/** + GomSpace linux driver GPIO set value without error check + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @param[in] driver_data data to specific driver +*/ +typedef void (*gs_gpio_set_nc_t)(gs_gpio_t gpio, bool value, void * driver_data); + +/** + GomSpace linux driver initialize GPIO as an external interrupt pin + + @param[in] gpio The gpio to configure + @param[in] conf Configuration of interrupt pin + @param[in] driver_data data to specific driver + + @return_gs_error_t + */ +typedef gs_error_t (*gs_gpio_init_as_interrupt_t)(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data); + + +/** + Every port. + */ +#define GS_GPIO_ALL_PORTS UINT16_MAX + +/** + Every pin. + */ +#define GS_GPIO_ALL_PINS UINT16_MAX + +/** + GPIO driver. + */ +typedef struct { + /** + Function for handling GPIO get. + */ + gs_gpio_get_t get_handler; + /** + Function for handling GPIO get no check. + */ + gs_gpio_get_nc_t get_nc_handler; + /** + Function for handling GPIO set. + */ + gs_gpio_set_t set_handler; + /** + Function for handling GPIO set no check. + */ + gs_gpio_set_nc_t set_nc_handler; + /** + Function for handling GPIO initialize as interrupt. + */ + gs_gpio_init_as_interrupt_t init_as_interrupt_handler; +} gs_gpio_driver_t; + + +/** + GPIO driver entry + */ +typedef struct { + /** + GPIO port, to which the driver is used (if GS_GPIO_ALL_PORTS, then all ports uses this driver). + */ + uint16_t port; + /** + GPIO pin, to which the driver is used (if GS_GPIO_ALL_PINS, then all pins uses this driver). + */ + uint16_t pin; + /** + GPIO driver. + */ + const gs_gpio_driver_t * driver; + /** + Driver specific data. + */ + void * driver_data; +} gs_gpio_driver_entry_t; + +/** + Register a driver. + + A specific driver can be assigned to a port and pin or it can be assigned to all pins and/or all ports. + + The latest registered driver, which fit the GPIO, is the one used. + + @param[in] driver_entry driver and configuration to be registered + @return_gs_error_t + */ +gs_error_t gs_gpio_register_driver(const gs_gpio_driver_entry_t * driver_entry); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h new file mode 100644 index 00000000..0f95e5aa --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h @@ -0,0 +1,91 @@ +#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_SYSFS_H_ +#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_SYSFS_H_ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + @brief Linux GPIO driver based on sysfs. + This driver needs to be registered in the generic GPIO linux driver @see 'gs/util/linux/drivers/gpio/gpio.h' +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + GPIO sysfs driver data. + + @note Driver takes no driver data, so a NULL pointer is valid +*/ +typedef void * gs_gpio_sysfs_driver_data_t; + +/** + GPIO sysfs driver interface. +*/ +extern const gs_gpio_driver_t gs_gpio_sysfs_driver; + +/** + GPIO sysfs initialize + + @param[in] gpio The gpio to initialize + @param[in] output Direction of pin (True/False = Output/Input) + @param[in] init_value Pin state if configured as output (True/False = High/Low) + @param[in] active_low if set pin is configured as active low (so a gs_gpio_sysfs_set with 1 will actually set value low) + @return_gs_error_t + */ +gs_error_t gs_gpio_sysfs_initialize(gs_gpio_t gpio, bool output, bool init_value, bool active_low); + +/** + GPIO sysfs get value + + @param[in] gpio The gpio to read + @param[in] value Returned GPIO value (true/false = High/Low) + @param[in] driver_data data to driver (not used) + @return_gs_error_t +*/ +gs_error_t gs_gpio_sysfs_get(gs_gpio_t gpio, bool *value, void * driver_data); + +/** + GPIO sysfs get value without error check + + @param[in] gpio The gpio to read + @param[in] driver_data data to driver (not used) + @return GPIO value (true/false = High/Low) +*/ +bool gs_gpio_sysfs_get_nc(gs_gpio_t gpio, void * driver_data); + +/** + GPIO sysfs set value + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @param[in] driver_data data to driver (not used) + @return_gs_error_t +*/ +gs_error_t gs_gpio_sysfs_set(gs_gpio_t gpio, bool value, void * driver_data); + +/** + GPIO sysfs set value without error check + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @param[in] driver_data data to driver (not used) +*/ +void gs_gpio_sysfs_set_nc(gs_gpio_t gpio, bool value, void * driver_data); + +/** + Initialize GPIO sysfs as an external interrupt pin + + @param[in] gpio The gpio to configure + @param[in] conf Configuration of interrupt pin + @param[in] driver_data data to driver (not used) + @return_gs_error_t + */ +gs_error_t gs_gpio_sysfs_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h new file mode 100644 index 00000000..e61b70a4 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h @@ -0,0 +1,125 @@ +#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_VIRTUAL_H_ +#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_VIRTUAL_H_ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + @brief Linux GPIO driver to be used in unit tests. + This driver needs to be registered in the generic GPIO linux driver @see 'gs/util/linux/drivers/gpio/gpio.h' +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + GPIO virtual driver data. + + @note Driver takes no driver data, so a NULL pointer is valid +*/ +typedef void * gs_gpio_virtual_driver_data_t; + +/** + GPIO virtual driver interface. +*/ +extern const gs_gpio_driver_t gs_gpio_virtual_driver; + +/** + GPIO virtual driver entry, where all ports and pins are routed to virtual driver + */ +extern const gs_gpio_driver_entry_t gs_gpio_virtual_driver_entry_all; + +/** + GPIO virtual initialize + + @param[in] gpio The gpio to initialize + @param[in] output Direction of pin (True/False = Output/Input) + @param[in] value Pin state if configured as output (True/False = High/Low) + @return_gs_error_t + */ +gs_error_t gs_gpio_virtual_initialize(gs_gpio_t gpio, bool output, bool value); + +/** + GPIO virtual get value + + @param[in] gpio The gpio to read + @param[in] value Returned GPIO value (true/false = High/Low) + @param[in] driver_data data to driver (not used) + @return_gs_error_t +*/ +gs_error_t gs_gpio_virtual_get(gs_gpio_t gpio, bool *value, void * driver_data); + +/** + GPIO virtual get value without error check + + @param[in] gpio The gpio to read + @param[in] driver_data data to driver (not used) + @return GPIO value (true/false = High/Low) +*/ +bool gs_gpio_virtual_get_nc(gs_gpio_t gpio, void * driver_data); + +/** + GPIO virtual set value + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @param[in] driver_data data to driver (not used) + @return_gs_error_t +*/ +gs_error_t gs_gpio_virtual_set(gs_gpio_t gpio, bool value, void * driver_data); + +/** + GPIO virtual set value without error check + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @param[in] driver_data data to driver (not used) +*/ +void gs_gpio_virtual_set_nc(gs_gpio_t gpio, bool value, void * driver_data); + +/** + Initialize GPIO virtual as an external interrupt pin + + @param[in] gpio The gpio to configure + @param[in] conf Configuration of interrupt pin + @param[in] driver_data data to driver (not used) + @return_gs_error_t + */ +gs_error_t gs_gpio_virtual_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data); + +/** + Force set a pin + + This sets a pin regardless if it is configured as input, output or interrupt + If the pin is configured as interrupt, the registered ISR's will be called within this function, + if the transition matches (rising/falling) + + @note This function is specific to this driver and is should not be registered. + + @param[in] gpio The gpio to set + @param[in] value GPIO value (true/false = High/Low) + @return_gs_error_t + */ +gs_error_t gs_gpio_virtual_force_set(gs_gpio_t gpio, bool value); + +/** + Get transitions + + This gives the number of transitions ((high -> low) + (low -> high)), + since last time this function was called at this pin. This function resets the counter of the pin. + An even number means, that the pin has the same state as it was initialized to. + + @note This function is specific to this driver and should not be registered + + @param[in] gpio The gpio, of which transitions are given + @param[out] transitions Number of transitions + @return + */ +gs_error_t gs_gpio_virtual_get_transistions(gs_gpio_t gpio, uint32_t * transitions); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h b/gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h new file mode 100644 index 00000000..858c26a2 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h @@ -0,0 +1,198 @@ +#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_I2C_I2C_H_ +#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_I2C_I2C_H_ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + @brief Linux I2C plugin driver +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + GomSpace linux driver I2C master transaction. + + @see 'gs/util/drivers/i2c/master.h' + + @param[in] device I2C device + @param[in] addr I2C address + @param[in] tx tx buffer + @param[in] txlen bytes to be sent + @param[out] rx rx buffer + @param[in] rxlen bytes to be received + @param[in] timeout_ms timeout in milliseconds + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (* gs_i2c_master_transaction_t)(uint8_t device, uint8_t addr, const void * tx, size_t txlen, + void * rx, size_t rxlen, int timeout_ms, void * driver_data); + +/** + GomSpace linux driver I2C slave start. + + @see 'gs/util/drivers/i2c/slave.h' + + @param[in] device I2C device + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (* gs_i2c_slave_start_t)(uint8_t device, void * driver_data); + +/** + GomSpace linux driver I2C set rx callback + + @see 'gs/util/drivers/i2c/slave.h' + + @param[in] device I2C device + @param[in] rx rx callback + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (* gs_i2c_slave_set_rx_t)(uint8_t device, gs_i2c_slave_receive_t rx, void * driver_data); + +/** + GomSpace linux driver I2C slave set 'get_rx_buffer' callback. + + @see 'gs/util/drivers/i2c/slave.h' + + @param[in] device I2C device + @param[in] get_rx_buf get_rx_buf callback + @param[in] buf_length length of buffer received by calling callback + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (* gs_i2c_slave_set_get_rx_buf_t)(uint8_t device, gs_i2c_slave_get_rx_buf_t get_rx_buf, size_t buf_length, void * driver_data); + +/** + GomSpace linux driver I2C slave set slave response. + + @see 'gs/util/drivers/i2c/slave.h' + + @param[in] device I2C device + @param[in] tx tx buffer + @param[in] tx_length bytes to be send + @param[in] driver_data data to specific driver + @return_gs_error_t +*/ +typedef gs_error_t (* gs_i2c_slave_set_response_t)(uint8_t device, const uint8_t * tx, size_t tx_length, void * driver_data); + +/** + Every I2C device ([0 : 254]). + */ +#define GS_I2C_ALL_DEVICES 255 + +/** + Every I2C address (0 : 127]). + */ +#define GS_I2C_ALL_ADDR 255 + +/** + I2C master driver. + */ +typedef struct { + /** + Function for handling master transactions. + */ + gs_i2c_master_transaction_t master_transaction_handler; +} gs_i2c_master_driver_t; + + +/** + I2C master driver entry + */ +typedef struct { + /** + I2C device, to which the driver is used (if GS_I2C_ALL_DEVICES, then all devices uses this driver). + */ + uint8_t device; + /** + I2C addr, to which the driver is used (if GS_I2C_ALL_ADDR, then all addr on given device uses this driver). + */ + uint8_t addr; + /** + I2C master driver. + */ + const gs_i2c_master_driver_t * driver; + /** + Driver specific data. + */ + void * driver_data; +} gs_i2c_master_driver_entry_t; + + +/** + I2C slave driver + */ +typedef struct { + /** + Function for handling slave start. + */ + gs_i2c_slave_start_t start_handler; + /** + Function for handling the 'setting of rx callback'. + */ + gs_i2c_slave_set_rx_t set_rx_handler; + /** + Function for handling setting of an 'rx buff get' function. + */ + gs_i2c_slave_set_get_rx_buf_t set_get_rx_buf_handler; + /** + Function for handling 'set response'. + */ + gs_i2c_slave_set_response_t set_response_handler; +} gs_i2c_slave_driver_t; + + +/** + I2C slave driver entry. + */ +typedef struct { + /** + I2C device, to which the driver is used (if GS_I2C_ALL_DEVICES, then all devices uses this driver). + */ + uint8_t device; + /** + I2C slave driver. + */ + const gs_i2c_slave_driver_t * driver; + /** + Driver specific data. + */ + void * driver_data; +} gs_i2c_slave_driver_entry_t; + + +/** + Register a master driver. + + A specific driver can be assigned to a specific address and device + or it can be registered to every address on a device or every address on every device. + + The latest registered driver, which fit the device an address, is the one used. + + @param[in] driver_entry driver and configuration to be registered + @return_gs_error_t + */ +gs_error_t gs_i2c_master_register_driver(const gs_i2c_master_driver_entry_t * driver_entry); + +/** + Register a slave driver + + A specific driver can be assigned to a specific device or a driver can be assigned to every device. + + The latest registered driver, which fit the device, is the one used. + + @param[in] driver_entry driver and configuration to be registered + @return_gs_error_t + */ +gs_error_t gs_i2c_slave_register_driver(const gs_i2c_slave_driver_entry_t * driver_entry); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h b/gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h new file mode 100644 index 00000000..24e5ae22 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h @@ -0,0 +1,175 @@ +#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_SPI_SPI_H_ +#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_SPI_SPI_H_ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Linux SPI plugin driver +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Linux driver SPI master transactions. + + @see 'gs/util/drivers/spi/master.h' + + @param[in] slave SPI slave + @param[in] trans Pointer to transactions + @param[in] count Number of transactions (rx and/or tx) to complete + @param[in] timeout_ms timeout in milliseconds, primarily for locking the SPI device. + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (*gs_spi_master_transactions_t)(uint8_t slave, gs_spi_master_trans_t *trans, size_t count, + int timeout_ms, void * driver_data); + +/** + Linux driver SPI slave start. + + @see 'gs/util/drivers/spi/slave.h' + + @param[in] device SPI device (handle) + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (* gs_spi_slave_start_t)(uint8_t device, void * driver_data); + +/** + Linux driver SPI set rx callback + + @see 'gs/util/drivers/spi/slave.h' + + @param[in] device SPI device (handle). + @param[in] rx Rx callback. + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (* gs_spi_slave_set_rx_t)(uint8_t device, gs_spi_slave_receive_t rx, void * driver_data); + +/** + Linux driver SPI slave set slave response. + + @see 'gs/util/drivers/spi/slave.h' + + @param[in] device SPI device (handle). + @param[in] offset offset (in bytes) for the response, counted from start of request, i.e. offset of 2 means data will be sent as the 3rd byte. + @param[in] tx pointer to data. NOTE: data is not copied due to performance, so data must stay valid until the response has been sent. + @param[in] size size of data. + @param[in] driver_data data to specific driver + @return_gs_error_t + */ +typedef gs_error_t (* gs_spi_slave_set_response_t)(uint8_t device, size_t offset, const uint8_t * tx, size_t size, void * driver_data); + +/** + Every SPI slave ([0 : 254]). + */ +#define GS_SPI_ALL_SLAVES 255 + +/** + Every SPI device (0 : 254]). + */ +#define GS_SPI_ALL_DEVICES 255 + + +/** + SPI master driver. + */ +typedef struct { + /** + Function for handling master transactions. + */ + gs_spi_master_transactions_t master_transactions_handler; +} gs_spi_master_driver_t; + + +/** + SPI master driver entry + */ +typedef struct { + /** + SPI slave, to which the driver is used (if #GS_SPI_ALL_SLAVES, then all slaves uses this driver). + */ + uint8_t slave; + /** + SPI master driver. + */ + const gs_spi_master_driver_t * driver; + /** + Driver specific data. + */ + void * driver_data; +} gs_spi_master_driver_entry_t; + + +/** + SPI slave driver + */ +typedef struct { + /** + Function for handling slave start. + */ + gs_spi_slave_start_t start_handler; + /** + Function for handling the 'setting of rx callback'. + */ + gs_spi_slave_set_rx_t set_rx_handler; + /** + Function for handling 'set response'. + */ + gs_spi_slave_set_response_t set_response_handler; +} gs_spi_slave_driver_t; + + +/** + SPI slave driver entry. + */ +typedef struct { + /** + SPI device, to which the driver is used (if #GS_SPI_ALL_DEVICES, then all devices uses this driver). + */ + uint8_t device; + /** + SPI slave driver. + */ + const gs_spi_slave_driver_t * driver; + /** + Driver specific data. + */ + void * driver_data; +} gs_spi_slave_driver_entry_t; + + +/** + Register a master driver. + + A specific driver can be assigned to a slave or it can be assigned to every slave. + + The latest registered driver, which fit the slave, is the one used. + + @param[in] driver_entry driver and configuration to be registered + @return_gs_error_t + */ +gs_error_t gs_spi_master_register_driver(const gs_spi_master_driver_entry_t * driver_entry); + +/** + Register a slave driver + + A specific driver can be assigned to a specific device or a driver can be assigned to every device. + + The latest registered driver, which fit the device, is the one used. + + @param[in] driver_entry driver and configuration to be registered + @return_gs_error_t + */ +gs_error_t gs_spi_slave_register_driver(const gs_spi_slave_driver_entry_t * driver_entry); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/exitcode.h b/gomspace/libutil/include/gs/util/linux/exitcode.h new file mode 100644 index 00000000..35e89f06 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/exitcode.h @@ -0,0 +1,40 @@ +#ifndef GS_UTIL_LINUX_EXITCODE_H +#define GS_UTIL_LINUX_EXITCODE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + "standard" Linux exit codes. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Program completed ok (from stdlib.h) +*/ +#define GS_EXITCODE_OK EXIT_SUCCESS + +/** + Program terminated due to an error (from stdlib.h). +*/ +#define GS_EXITCODE_ERROR EXIT_FAILURE + +/** + Program terminated due to invalid usage, eg argument (from sysexits.h). +*/ +#define GS_EXITCODE_USAGE EX_USAGE + +/** + Program terminated due to a signal (from [TLDP](http://www.tldp.org/LDP/abs/html/exitcodes.html)). +*/ +#define GS_EXITCODE_SIGNAL(sig) (128 + sig) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/function.h b/gomspace/libutil/include/gs/util/linux/function.h new file mode 100644 index 00000000..b918993d --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/function.h @@ -0,0 +1,49 @@ +#ifndef GS_UTIL_LINUX_FUNCTION_H +#define GS_UTIL_LINUX_FUNCTION_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Function interface - invokes a function by name. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Function prototype. + @param[in] arg argument provided to gs_function_invoke(). + @return_gs_error_t +*/ +typedef gs_error_t (*gs_function_t)(void * arg); + +/** + Register \a function by name. + + @param[in] short_name short name for function, used by gs_function_invoke() to find function to invoke. + @param[in] long_name long name (unique) for function, used by gs_function_invoke() to find function to invoke. + @param[in] function function to be invoked by gs_function_invoke() + @return #GS_ERROR_FULL if registry is full. + @return_gs_error_t +*/ +gs_error_t gs_function_register(const char * short_name, const char * long_name, gs_function_t function); + +/** + Invoke \a function by name. + + The return value is from the registered function, except for #GS_ERROR_NOT_IMPLEMENTED. + + @param[in] name registered function name. + @param[in] arg argument for function. + @return #GS_ERROR_NOT_IMPLEMENTED if the \a name isn't found. + @return_gs_error_t +*/ +gs_error_t gs_function_invoke(const char * name, void * arg); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/rtc.h b/gomspace/libutil/include/gs/util/linux/rtc.h new file mode 100644 index 00000000..fa063f76 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/rtc.h @@ -0,0 +1,28 @@ +#ifndef GS_UTIL_LINUX_RTC_H +#define GS_UTIL_LINUX_RTC_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Real Time Clock interface (linux). +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Register Real Time Clock interface. + @note Setting the RTC will normally require special permission. + @param[in] get if true, get will be registered. + @param[in] set if true, set will be registered. + @return_gs_error_t +*/ +gs_error_t gs_rtc_register_linux(bool get, bool set); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/signal.h b/gomspace/libutil/include/gs/util/linux/signal.h new file mode 100644 index 00000000..b3c280e7 --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/signal.h @@ -0,0 +1,40 @@ +#ifndef GS_UTIL_LINUX_SIGNAL_H +#define GS_UTIL_LINUX_SIGNAL_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Signal helpers - catch and ignore. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Standard Linux signal handler. +*/ +typedef void (*gs_signal_handler)(int signal, siginfo_t *si, void *context); + +/** + Register/catch signal and invoke handler. + @param[in] signal signal to catch. + @param[in] handler signal handler. If \a handler is NULL, a default handler will be invoked, which calls exit(#GS_EXITCODE_SIGNAL + signal). + @return_gs_error_t +*/ +gs_error_t gs_signal_catch(int signal, gs_signal_handler handler); + +/** + Ignore signal + @param[in] signal signal to ignore. + @return_gs_error_t +*/ +gs_error_t gs_signal_ignore(int signal); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/linux/sysfs_helper.h b/gomspace/libutil/include/gs/util/linux/sysfs_helper.h new file mode 100644 index 00000000..ad05a6fe --- /dev/null +++ b/gomspace/libutil/include/gs/util/linux/sysfs_helper.h @@ -0,0 +1,30 @@ +#ifndef GS_UTIL_SYSFS_HELPER_H +#define GS_UTIL_SYSFS_HELPER_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Sysfs interface. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Sysfs write (GPIO). +*/ +gs_error_t gs_sysfs_write_file(const char *path, const char *value); + +/** + Sysfs read (GPIO). +*/ +gs_error_t gs_sysfs_read_file(const char *path, char *value, size_t len); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/log.h b/gomspace/libutil/include/gs/util/log.h new file mode 100644 index 00000000..13659adf --- /dev/null +++ b/gomspace/libutil/include/gs/util/log.h @@ -0,0 +1,15 @@ +#ifndef GS_UTIL_LOG_H +#define GS_UTIL_LOG_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Log interface. + + The log interface supports logging to different group. + + Logging is done through groups (domains), which can runtime be re-configured with level. +*/ +#include + +#endif diff --git a/gomspace/libutil/include/gs/util/log/appender/appender.h b/gomspace/libutil/include/gs/util/log/appender/appender.h new file mode 100644 index 00000000..29a0c140 --- /dev/null +++ b/gomspace/libutil/include/gs/util/log/appender/appender.h @@ -0,0 +1,189 @@ +#ifndef GS_UTIL_LOG_APPENDER_APPENDER_H +#define GS_UTIL_LOG_APPENDER_APPENDER_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Log Appender interface. + + The log appender interface supports logging to different "stores". + Logging is done through groups, which can be registered to different log appenders. + Each log appender has it's own filter (level mask). + Examples of log appenders could be: console, file, vmem, ... +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + Log appender (forward declaration) + All log groups log to one or more appenders. The Log appender is responsible + for putting the actual log data to a store/console or some other log medium. +*/ +typedef struct gs_log_appender gs_log_appender_t; + +/** + Log appender record iterator callback function + + @param[in] ctx context data for iterator. + @param[in] level log level of record being iterated + @param[in] ts timestamp of record being iterated + @param[in] group group string (zero terminated) of record being iterated + @param[in] msg message string (zero terminated) of record being iterated + @return true/false: Return false to discontinue iteration. +*/ +typedef bool (*gs_log_record_iterator_t)(void *ctx, gs_log_level_t level, const gs_timestamp_t *ts, const char *group, const char *msg); + +/** + Log appender driver interface +*/ +typedef struct { + /** appender init function */ + gs_error_t (*init)(gs_log_appender_t *appender); + /** appender function */ + void (*append)(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va); + /** appender function for isr context */ + void (*append_isr)(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va); + /** appender function for getting appender details string */ + void (*info)(gs_log_appender_t *appender, char * info_str, uint8_t str_size); + /** appender function for iterating stored appenders log history */ + void (*hist)(gs_log_appender_t *appender, void * ctx, gs_log_record_iterator_t iter); + /** appender function for clearing it's log history */ + void (*clear)(gs_log_appender_t *appender); + /** appender function for flushing cached log entries to it's store. + This is only relevant for appenders implementing a log cache. */ + void (*flush)(gs_log_appender_t *appender); +} gs_log_appender_driver_t; + +/** + Log appender + All log groups log to one or more appenders. The Log appender is responsible + for putting the actual log data to a store/console or some other log medium. +*/ +struct gs_log_appender { + /** Name of the appender */ + const char * name; + /** appender driver interface */ + const gs_log_appender_driver_t * drv; + /** appender driver configuration data */ + const void * drv_config; + /** appender driver data - dynamic/internal data */ + void * drv_data; + /** appender level mask */ + uint8_t mask; +}; + +/** + Register an appender for the given log group. + All logging, where the mask matches the groups \a level_mask, will be forwarded to this appender. + + @param[in] group_name Name of the group. + @param[in] appender_name Name of appender to register for this group. + @return gs_error_t +*/ +gs_error_t gs_log_group_register_appender(const char * group_name, const char * appender_name); + +/** + Log appender iterator callback function + + @param[in] ctx context data for iterator. + @param[in] appender log appender being iterated + + @return true/false: Return false to discontinue iteration. +*/ +typedef bool (*gs_log_appender_iterator_t)(void *ctx, gs_log_appender_t * appender); + +/** + Iterate all or specific log appender(s). + + @param[in] name name of log appender, or NULL/\"all\" for all groups. + @param[in] ctx user context data. + @param[in] iter iterator, return \a true to continue, \a false to break iteration. + @return_gs_error_t +*/ +gs_error_t gs_log_appender_iterate(const char * name, void * ctx, gs_log_appender_iterator_t iter); + +/** + Iterate registered appenders for a specific group. + + @param[in] group log group to iterate appenders on. + @param[in] ctx user context data. + @param[in] iter appender iterator, return \a true to continue, \a false to break iteration. + @return gs_error_t +*/ +gs_error_t gs_log_group_appender_iterate(gs_log_group_t * group, void * ctx, gs_log_appender_iterator_t iter); + +/** + Register log appender. + + The log appender will be registered and initialized (if the appender has en init function, see #gs_log_appender_driver_t) + + The appender will not be attached to any log groups. For registering an appender to a group, use gs_log_group_register_appender() + + @param[in] appender appender - must stay in memory during the life-time of the application + @return_gs_error_t +*/ +gs_error_t gs_log_appender_register(gs_log_appender_t *appender); + +/** + Add log appender(s). + + The log appender will be registered and initialized (if the appender has en init function, see #gs_log_appender_driver_t) + + The appender will not be attached to any log groups. For registering an appender to a group, use gs_log_group_register_appender() + + @deprecated impossible to determine which appender fails, use gs_log_appender_register() + @param[in] appenders array of appender(s) - must stay in memory during the life-time of the application + @param[in] count array count - number of appenders. + @return_gs_error_t +*/ +gs_error_t gs_log_appender_add(gs_log_appender_t *appenders, uint16_t count); + +/** + Set log appender level mask. + + @param[in] appender_name log appender name + @param[in] mask level mask to set. + @return_gs_error_t +*/ +gs_error_t gs_log_appender_set_level_mask(const char * appender_name, uint8_t mask); + +/** + Get log appender level mask. + + @param[in] appender_name log appender name + @param[out] mask returned current level mask. + @return_gs_error_t +*/ +gs_error_t gs_log_appender_get_level_mask(const char * appender_name, uint8_t *mask); + +/** + Iterate log history for all or specific log appender. + + @param[in] name name of log appender, or NULL/\"all\" for all appenders. + @param[in] ctx user context data for iterator. + @param[in] iter iterator, return \a true to continue, \a false to break iteration. + @return gs_error_t +*/ +gs_error_t gs_log_appender_history_iterate(const char * name, void * ctx, gs_log_record_iterator_t iter); + +/** + Flush all log appenders data to storage. + + This will call the flush API (if implemented) for all log appenders + available on the system. This should be called on regular basis from + a system thread to ensure all cached data is correctly flushed to their + stores. + + @return gs_error_t +*/ +gs_error_t gs_log_appender_flush_all(); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/log/appender/console.h b/gomspace/libutil/include/gs/util/log/appender/console.h new file mode 100644 index 00000000..37f63fc5 --- /dev/null +++ b/gomspace/libutil/include/gs/util/log/appender/console.h @@ -0,0 +1,57 @@ +#ifndef GS_UTIL_LOG_APPENDER_CONSOLE_H +#define GS_UTIL_LOG_APPENDER_CONSOLE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Console log appender - logs to stdout. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Log appender for console + + This log appender is the standard appender which is always available + on any system. The appender should be registered to the root group, + in order to get console/stdio logs. +*/ +extern gs_log_appender_t gs_log_appender_console; + +/** + Log appender for console callback type + + This callback function can be used for registering a user defined logger function if + the default can not be used for the given system. + + @param[in] appender pointer to the console appender. + @param[in] level log level for log message + @param[in] group log group for log message + @param[in] ts timestamp for log message + @param[in] format format of message in printf style + @param[in] va variable argument list in printf style + + @return void +*/ +typedef void (*gs_log_appender_console_cb_t)(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va); + +/** + Set Log appender for console callback + + When set, the given callback is called instead of the default console log function. + To revert back to the default console log function, call this function with NULL as parameter. + + @param[in] cb callback to use for console logging. + + @return gs_error_t +*/ +gs_error_t gs_log_appender_console_set_cb(gs_log_appender_console_cb_t cb); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/log/appender/simple_file.h b/gomspace/libutil/include/gs/util/log/appender/simple_file.h new file mode 100644 index 00000000..ab2537a6 --- /dev/null +++ b/gomspace/libutil/include/gs/util/log/appender/simple_file.h @@ -0,0 +1,41 @@ +#ifndef GS_UTIL_LOG_APPENDER_SIMPLE_FILE_H +#define GS_UTIL_LOG_APPENDER_SIMPLE_FILE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Simple log-file appender. +*/ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Simple File Log Appender driver configuration +*/ +typedef struct gs_log_appender_simple_file_config { + /** + Name of file to create/write logs to + */ + const char *filename; + /** + Truncate the file, when opening the log file. + */ + bool truncate; + /** + Uee local time stamps when logging to log file, otherwise UTC. + */ + bool use_local_time; +} gs_log_appender_simple_file_config_t; + +/** + Log appender for file. +*/ +extern const gs_log_appender_driver_t gs_log_appender_simple_file_driver; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/log/log.h b/gomspace/libutil/include/gs/util/log/log.h new file mode 100644 index 00000000..53470a75 --- /dev/null +++ b/gomspace/libutil/include/gs/util/log/log.h @@ -0,0 +1,853 @@ +#ifndef GS_UTIL_LOG_LOG_H +#define GS_UTIL_LOG_LOG_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Log interface. + + Logging is done through groups (domains), where the level mask can be changed runtime. +*/ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Name of the root log group +*/ +#define GS_LOG_GROUP_ROOT "root" + +/** + Log levels. + + The levels can easily be mapped to standard syslog severity levels (https://en.wikipedia.org/wiki/Syslog). +*/ +typedef enum { + /** + Trace (more detailed than \a debug). + + syslog: maps to \a debug (or \a trace if supported). + */ + GS_LOG_TRACE = 0, + /** + Debug. + + syslog: maps to \a debug. + */ + GS_LOG_DEBUG = 1, + /** + Informational. + + syslog: maps to \a informational. + */ + GS_LOG_INFO = 2, + /** + Normal but significant conditions. + + syslog: maps to \a notice. + */ + GS_LOG_NOTICE = 3, + /** + Warning. + + syslog: maps to \a warning. + */ + GS_LOG_WARNING = 4, + /** + Error. + + syslog: maps to \a error. + */ + GS_LOG_ERROR = 5, + + /** + Trace (more detailed than \a debug). + @deprecated use #GS_LOG_TRACE + */ + LOG_TRACE = GS_LOG_TRACE, + /** + Debug. + @deprecated use #GS_LOG_DEBUG + */ + LOG_DEBUG = GS_LOG_DEBUG, + /** + Informational. + @deprecated use #GS_LOG_INFO + */ + LOG_INFO = GS_LOG_INFO, + /** + Normal but significant conditions. + @deprecated use #GS_LOG_NOTICE + */ + LOG_NOTICE = GS_LOG_NOTICE, + /** + Warning. + @deprecated use #GS_LOG_WARNING + */ + LOG_WARNING = GS_LOG_WARNING, + /** + Error. + @deprecated use #GS_LOG_ERROR + */ + LOG_ERROR = GS_LOG_ERROR, +} gs_log_level_t; + +/** + Log categories. + + The category is a way of grouping information about which sub-systems have logged. It is primarily used in the \a + telemetry table, to indicate what sub-systems have logged an \a error or \a warning - indicating a possible problem. + + Up to 32 categories are supported (stored in a uint32). + + Categories should be unique within a single node. However, nothing happens if categories clashes - it will only be more difficult to determine what part of the system logged. + + Standard categories are defined from #GS_LOG_CAT_1 and up. Products or mission specific software should start from #GS_LOG_CAT_32 and down. +*/ +typedef enum { + //! Standard, used for #GS_LOG_CAT_DEFAULT + GS_LOG_CAT_1 = 1 << 0, + //! Standard, used for #GS_LOG_CAT_DRIVER + GS_LOG_CAT_2 = 1 << 1, + //! Standard, used for #GS_LOG_CAT_CSP + GS_LOG_CAT_3 = 1 << 2, + //! Standard, used for #GS_LOG_CAT_PARAM + GS_LOG_CAT_4 = 1 << 3, + //! Standard, used for #GS_LOG_CAT_FILE_SYSTEM + GS_LOG_CAT_5 = 1 << 4, + //! Standard, used for #GS_LOG_CAT_COMMAND + GS_LOG_CAT_6 = 1 << 5, + //! Standard, used for #GS_LOG_CAT_HK + GS_LOG_CAT_7 = 1 << 6, + //! Standard, used for #GS_LOG_CAT_FP + GS_LOG_CAT_8 = 1 << 7, + //! Standard, used for #GS_LOG_CAT_ADCS + GS_LOG_CAT_9 = 1 << 8, + GS_LOG_CAT_10 = 1 << 9, + GS_LOG_CAT_11 = 1 << 10, + GS_LOG_CAT_12 = 1 << 11, + GS_LOG_CAT_13 = 1 << 12, + GS_LOG_CAT_14 = 1 << 13, + GS_LOG_CAT_15 = 1 << 14, + GS_LOG_CAT_16 = 1 << 15, +#if (__AVR__ == 0) + GS_LOG_CAT_17 = 1 << 16, + GS_LOG_CAT_18 = 1 << 17, + GS_LOG_CAT_19 = 1 << 18, + GS_LOG_CAT_20 = 1 << 19, + GS_LOG_CAT_21 = 1 << 20, + GS_LOG_CAT_22 = 1 << 21, + GS_LOG_CAT_23 = 1 << 22, + GS_LOG_CAT_24 = 1 << 23, + GS_LOG_CAT_25 = 1 << 24, + GS_LOG_CAT_26 = 1 << 25, + GS_LOG_CAT_27 = 1 << 26, + GS_LOG_CAT_28 = 1 << 27, + GS_LOG_CAT_29 = 1 << 28, + GS_LOG_CAT_30 = 1 << 29, + GS_LOG_CAT_31 = 1 << 30, + //! Product or mission specific - start here and down + GS_LOG_CAT_32 = 1 << 31, +#endif +} gs_log_category_t; + +/** + @defgroup reserved_log_categories Reserved/assigned log categories. + These categories are assigned/reserved for certain sub-systems. + @{ +*/ + /** + Default, used if nothing else fits. + */ +#define GS_LOG_CAT_DEFAULT GS_LOG_CAT_1 + /** + Driver layer. + */ +#define GS_LOG_CAT_DRIVER GS_LOG_CAT_2 + /** + CSP. + */ +#define GS_LOG_CAT_CSP GS_LOG_CAT_3 + /** + Parameter system. + */ +#define GS_LOG_CAT_PARAM GS_LOG_CAT_4 + /** + File system. + */ +#define GS_LOG_CAT_FILE_SYSTEM GS_LOG_CAT_5 + /** + Command framework and execution. + */ +#define GS_LOG_CAT_COMMAND GS_LOG_CAT_6 + /** + Housekeeping System. + */ +#define GS_LOG_CAT_HK GS_LOG_CAT_7 + /** + Flight Planner. + */ +#define GS_LOG_CAT_FP GS_LOG_CAT_8 + /** + ADCS + */ +#define GS_LOG_CAT_ADCS GS_LOG_CAT_9 +/** @} */ + +struct gs_log_list; /* forward declared private log list struct */ +/** + Log list type (private) + + Private gs_log_list type. +*/ +typedef struct gs_log_list gs_log_list_t; + +/** + Log group. + All logs are logged to a \a group. The group contains the current log level mask, + which controls whether the log is carried through or not. +*/ +typedef struct { + /** + Name of log group. + */ + const char * name; + /** + Category, see #gs_log_category_t. + */ + uint32_t category; + /** + Current level mask, see #gs_log_level_t. + */ + uint8_t mask; + /** + Is group additive, if \a true (default) logging will be done on both root appenders and this groups appenders - if \a false, logging will only be done to this groups appenders. + */ + bool additivity; + /** + Private list of appenders. + */ + gs_log_list_t * appenders; +#if (__AVR__) + uint16_t dummy_align; +#endif +} gs_log_group_t; + +/** + Log masks (levels converted to mask). + @{ +*/ +/** + Trace level enabled. +*/ +#define GS_LOG_TRACE_MASK (1 << GS_LOG_TRACE) +/** + Debug level enabled. +*/ +#define GS_LOG_DEBUG_MASK (1 << GS_LOG_DEBUG) +/** + Info level enabled. +*/ +#define GS_LOG_INFO_MASK (1 << GS_LOG_INFO) +/** + Notice level enabled. +*/ +#define GS_LOG_NOTICE_MASK (1 << GS_LOG_NOTICE) +/** + Warning level enabled. +*/ +#define GS_LOG_WARNING_MASK (1 << GS_LOG_WARNING) +/** + Error level enabled. +*/ +#define GS_LOG_ERROR_MASK (1 << GS_LOG_ERROR) +/** + All levels enabled. +*/ +#define GS_LOG_ALL_MASK (GS_LOG_TRACE_MASK | GS_LOG_DEBUG_MASK | GS_LOG_INFO_MASK | GS_LOG_NOTICE_MASK | GS_LOG_WARNING_MASK | GS_LOG_ERROR_MASK) +/** + Default levels enabled - #GS_LOG_ERROR, #GS_LOG_WARNING and #GS_LOG_NOTICE. +*/ +#define GS_LOG_DEFAULT_MASK (GS_LOG_ERROR_MASK | GS_LOG_WARNING_MASK | GS_LOG_NOTICE_MASK) +/** + Trace level enabled. + @deprecated use #GS_LOG_TRACE_MASK +*/ +#define LOG_TRACE_MASK GS_LOG_TRACE_MASK +/** + Debug level enabled. + @deprecated use #GS_LOG_DEBUG_MASK +*/ +#define LOG_DEBUG_MASK GS_LOG_DEBUG_MASK +/** + Info level enabled. + @deprecated use #GS_LOG_INFO_MASK +*/ +#define LOG_INFO_MASK GS_LOG_INFO_MASK +/** + Notice level enabled. + @deprecated use #GS_LOG_NOTICE_MASK +*/ +#define LOG_NOTICE_MASK GS_LOG_NOTICE_MASK +/** + Warning level enabled. + @deprecated use #GS_LOG_WARNING_MASK +*/ +#define LOG_WARNING_MASK GS_LOG_WARNING_MASK +/** + Error level enabled. + @deprecated use #GS_LOG_ERROR_MASK +*/ +#define LOG_ERROR_MASK GS_LOG_ERROR_MASK +/** + All levels enabled. + @deprecated use #GS_LOG_ALL_MASK +*/ +#define LOG_ALL_MASK GS_LOG_ALL_MASK +/** + Default levels enabled - #GS_LOG_ERROR, #GS_LOG_WARNING and #GS_LOG_NOTICE. + @deprecated use #GS_LOG_DEFAULT_MASK +*/ +#define LOG_DEFAULT_MASK GS_LOG_DEFAULT_MASK +/**@}*/ + +/** + Define/Create a log group. + + @note name clash: This defines a variable, which potentially is \a global, meaning possibility of name clashes. Therefore log group should always + be prefixed with something that makes it fairly unique, i.e. component name. Example: gs_a3200dock_log - log group used by liba3200dock library. + + @param[in] group name of variables created. See note above about name clash. + @param[in] name_in display name + @param[in] cat_in log group category + @param[in] level_mask log level mask. +*/ +#define GS_LOG_GROUP(group, name_in, cat_in, level_mask) \ + gs_log_group_t group##_s = {.name = name_in, .category = cat_in, \ + .mask = level_mask, .additivity = true, \ + .appenders = NULL}; \ + gs_log_group_t * group = &group##_s + +/** + Define log group with initial mask for \a print and \a store. + + @note name clash: This defines a variable, which potentially is \a global, meaning possibility of name clashes. Therefore log group should always + be prefixed with something that makes it fairly unique, i.e. component name. Example: gs_a3200dock_log - log group used by liba3200dock library. + + @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(...) instead. + + @param[in] group name of variables created. See note above about name clash. + @param[in] name_in display name + @param[in] print_mask enable mask for \a print. + @param[in] store_mask enable mask for \a store. +*/ +#define LOG_GROUP_MASKED(group, name_in, print_mask, store_mask) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, (print_mask | store_mask)) + +/** + Declare log group as external (defined else where). + + @param[in] group the log group variable defined elsewhere. +*/ +#define GS_LOG_GROUP_EXTERN(group) extern gs_log_group_t * group + +/** + Define log group - levels are #GS_LOG_DEFAULT_MASK + + @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(..) instead. +*/ +#define LOG_GROUP(group, name_in) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, LOG_DEFAULT_MASK) + +/** + Define verbose log group - all levels are enabled (#GS_LOG_ALL_MASK) + + @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(..) instead. +*/ +#define LOG_GROUP_VERBOSE(group, name_in) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, LOG_ALL_MASK) + +/** + Define silent log group - all levels are disabled. + + @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(..) instead. +*/ +#define LOG_GROUP_SILENT(group, name_in) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, 0) + +/** + Declare log group as external (defined else where). + + @deprecated use #GS_LOG_GROUP_EXTERN(...) instead. +*/ +#define LOG_GROUP_EXTERN(group) GS_LOG_GROUP_EXTERN(group) + +/** + Default log group. + This can be overridden by a define +*/ +extern gs_log_group_t * LOG_DEFAULT; + +/** + Initializes the log system. + + @param[in] with_console_appender Enable/Disable console log appender + @return_gs_error_t +*/ +gs_error_t gs_log_init(bool with_console_appender); + +/** + Set log group level mask. + + @param[in] group_name log group name + @param[in] mask level mask to set. + @return_gs_error_t +*/ +gs_error_t gs_log_group_set_level_mask(const char * group_name, uint8_t mask); + +/** + Get log group level mask. + + @param[in] group_name log group name + @param[out] mask returned current level mask. + @return_gs_error_t +*/ +gs_error_t gs_log_group_get_level_mask(const char * group_name, uint8_t *mask); + +/** + Log group iterator callback function + + @param[in] ctx context data for iterator. + @param[in] group log group being iterated. + + @return true/false: Return false to discontinue iteration. +*/ +typedef bool (*gs_log_group_iterator_t)(void *ctx, gs_log_group_t * group); + +/** + Iterate all or specific log group(s). + + @param[in] group_name name of log group, or NULL/\"all\" for all groups. + @param[in] ctx user context data. + @param[in] iter iterator, return \a true to continue, \a false to break iteration. + @return_gs_error_t +*/ +gs_error_t gs_log_group_iterate(const char * group_name, void * ctx, gs_log_group_iterator_t iter); + +/** + Register a log group in the log system. + + The log group will be added to a system wide list of log groups, enabling list and set of level. + + @note The group must remain valid during the life-time of the application. + + @param[in] group The log group to be added to the system. + @return_gs_error_t +*/ +gs_error_t gs_log_group_register(gs_log_group_t *group); + +/** + Register a log group in the log system. + + @note The group must stay in memory during the life-time of the application + @see gs_log_group_register() + @param[in] group The log group to be added to the system. + @return_gs_error_t +*/ +static inline gs_error_t gs_log_group_add(gs_log_group_t *group) +{ + return gs_log_group_register(group); +} + +/** + Checks if a level is enabled on a log group + + @param[in] group The log group to check. + @param[in] level The log level to check if it's set on the group. + @return bool (true if enabled / false if not enabled) +*/ +bool gs_log_group_is_level_enabled(gs_log_group_t *group, gs_log_level_t level); + +/** + Convert string to log level. + + @param[in] str log level. + @param[out] return_level converted log level. + @return_gs_error_t +*/ +gs_error_t gs_log_string_to_level(const char * str, gs_log_level_t * return_level); + +/** + Convert level to single character. + + @param[in] level log level + @return single character representing the \a level. +*/ +char gs_log_level_to_char(gs_log_level_t level); + + +/** + Register Log commands. + @return_gs_error_t +*/ +gs_error_t gs_log_register_commands(void); + +/** + Generic log. + @note This function should not be called directly, use log macros. + + @param level log level + @param group log group. If NULL, the \a default log group will be used. + @param format Format string (printf style). +*/ +void gs_log(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) __attribute__ ((format (__printf__, 3, 4))); + +/** + Generic log from ISR. + @note This function should not be called directly, use log macros. + + @param level log level + @param group log group. If NULL, the \a default log group will be used. + @param format Format string (printf style). +*/ +void gs_log_isr(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) __attribute__ ((format (__printf__, 3, 4))); + +/** + Generic log (va_list). + @note This function should not be called directly, use log macros. + + @param level log level + @param group log group. If NULL, the \a default log group will be used. + @param format Format string (printf style). + @param args arguments for \a format. +*/ +void gs_log_va(gs_log_level_t level, gs_log_group_t * group, const char * format, va_list args); + +/** + Enable/disable color in \a print logs. + Default is \a enabled/true. + + @param[in] color \a true to enable color, \a false disable color. +*/ +void gs_log_set_print_color(bool color); + +/** + Level to color (begin). + + @param[in] level log level. + @return color string. +*/ +const char * gs_log_level_to_color_begin(gs_log_level_t level); + +/** + Level to color (end). + + @return color string. +*/ +const char * gs_log_level_to_color_end(void); + +/** + Take a level as input an create a level mask enabling all + levels with priority >= level. + + If level is e.g. LOG_INFO, the mask will enable Error, Warn & Info. + + * @param level the log level. + * @return level mask + */ +uint8_t gs_log_level_to_mask(gs_log_level_t level); + +/** + Convert string to log mask. + + Format: [+-]level[,[+-]level] + + + add level, - remove level. + + @param[in] str log mask + @param[in] current_mask current mask, used when input format contains + or -. + @param[out] return_mask converted log mask. + @return_gs_error_t +*/ +gs_error_t gs_log_string_to_mask(const char *str, uint8_t current_mask, uint8_t * return_mask); + +#if !(__DOXYGEN__) +/** + Internal macro for checking if log is enabled, before making log. +*/ +#define __gs_log(level, group, format, ...) \ + if (group->mask & (1 << level)) { \ + gs_log(level, group, GS_PGM_STR(format), ##__VA_ARGS__); \ + } + +/** + Internal macro for checking if log is enabled for isr, before making log. +*/ +#define __gs_log_isr(level, group, format, ...) \ + if (group->mask & (1 << level)) { \ + gs_log_isr(level, group, GS_PGM_STR(format), ##__VA_ARGS__); \ + } + +/** + Internal macro used for performing a log only once. + @note This creates a \a static \a variable. +*/ +#define __gs_log_once(level, group, format, ...) \ + ({ \ + static bool print_once; \ + if (!print_once) { \ + print_once = true; \ + __gs_log(level, group, format, ##__VA_ARGS__); \ + } \ + }) +#endif // __DOXYGEN__ + +/** + Default compile-time enabling/disabling of all levels + Unless levels are individually defined, this will be the default value. +*/ +#if !defined(GS_LOG_DISABLE_ALL) +#define GS_LOG_DISABLE_ALL 0 +#endif + +/** + Disable \a error level compile-time by defining a value > 0 +*/ +#if !defined(GS_LOG_DISABLE_ERROR) +#define GS_LOG_DISABLE_ERROR GS_LOG_DISABLE_ALL +#endif + +/** + Disable \a warning level compile-time by defining a value > 0 +*/ +#if !defined(GS_LOG_DISABLE_WARNING) +#define GS_LOG_DISABLE_WARNING GS_LOG_DISABLE_ALL +#endif + +/** + Disable \a notice level compile-time by defining a value > 0 +*/ +#if !defined(GS_LOG_DISABLE_NOTICE) +#define GS_LOG_DISABLE_NOTICE GS_LOG_DISABLE_ALL +#endif + +/** + Disable \a info level compile-time by defining a value > 0 +*/ +#if !defined(GS_LOG_DISABLE_INFO) +#define GS_LOG_DISABLE_INFO GS_LOG_DISABLE_ALL +#endif + +/** + Disable \a debug level compile-time by defining a value > 0 +*/ +#if !defined(GS_LOG_DISABLE_DEBUG) +#define GS_LOG_DISABLE_DEBUG GS_LOG_DISABLE_ALL +#endif + +/** + Disable \a trace level compile-time by defining a value > 0 +*/ +#if !defined(GS_LOG_DISABLE_TRACE) +#define GS_LOG_DISABLE_TRACE GS_LOG_DISABLE_ALL +#endif + +/** + Log \a error to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_error(format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log(LOG_ERROR, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a error from ISR to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_error_isr(format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log_isr(LOG_ERROR, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a error to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_error_group(group, format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log(LOG_ERROR, (group), format, ##__VA_ARGS__); } + +/** + Log \a error only once to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_error_once(format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log_once(LOG_ERROR, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a error only once to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_error_once_group(group, format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log_once(LOG_ERROR, (group), format, ##__VA_ARGS__); } + +/** + Log \a warning to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_warning(format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log(LOG_WARNING, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a warning from ISR to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_warning_isr(format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log_isr(LOG_WARNING, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a warning to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_warning_group(group, format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log(LOG_WARNING, (group), format, ##__VA_ARGS__); } + +/** + Log \a warning only once to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_warning_once(format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log_once(LOG_WARNING, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a warning only once to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_warning_once_group(group, format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log_once(LOG_WARNING, (group), format, ##__VA_ARGS__); } + +/** + Log \a notice to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_notice(format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log(LOG_NOTICE, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a notice from ISR to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_notice_isr(format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log_isr(LOG_NOTICE, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a notice to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_notice_group(group, format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log(LOG_NOTICE, (group), format, ##__VA_ARGS__); } + +/** + Log \a notice only once to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_notice_once(format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log_once(LOG_NOTICE, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a notice only once to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_notice_once_group(group, format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log_once(LOG_NOTICE, (group), format, ##__VA_ARGS__); } + +/** + Log \a info to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_info(format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log(LOG_INFO, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a info from ISR to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_info_isr(format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log_isr(LOG_INFO, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a info to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_info_group(group, format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log(LOG_INFO, (group), format, ##__VA_ARGS__); } + +/** + Log \a info only once to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_info_once(format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log_once(LOG_INFO, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a info only once to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_info_once_group(group, format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log_once(LOG_INFO, (group), format, ##__VA_ARGS__); } + +/** + Log \a debug to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_debug(format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log(LOG_DEBUG, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a debug from ISR to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_debug_isr(format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log_isr(LOG_DEBUG, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a debug to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_debug_group(group, format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log(LOG_DEBUG, (group), format, ##__VA_ARGS__); } + +/** + Log \a debug only once to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_debug_once(format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log_once(LOG_DEBUG, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a debug only once to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_debug_once_group(group, format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log_once(LOG_DEBUG, (group), format, ##__VA_ARGS__); } + +/** + Log \a trace to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_trace(format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log(LOG_TRACE, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a trace from ISR to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_trace_isr(format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log_isr(LOG_TRACE, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a trace to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_trace_group(group, format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log(LOG_TRACE, (group), format, ##__VA_ARGS__); } + +/** + Log \a trace only once to default group (LOG_DEFAULT). + @param[in] format Format string (printf style). +*/ +#define log_trace_once(format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log_once(LOG_TRACE, LOG_DEFAULT, format, ##__VA_ARGS__); } + +/** + Log \a trace only once to group. + @param[in] group log group (gs_log_group_t *). + @param[in] format Format string (printf style). +*/ +#define log_trace_once_group(group, format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log_once(LOG_TRACE, (group), format, ##__VA_ARGS__); } + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/minmax.h b/gomspace/libutil/include/gs/util/minmax.h new file mode 100644 index 00000000..4b9edf74 --- /dev/null +++ b/gomspace/libutil/include/gs/util/minmax.h @@ -0,0 +1,67 @@ +#ifndef GS_UTIL_MINMAX_H +#define GS_UTIL_MINMAX_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Min/max utilities. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Return minimum value. + @param[in] x value + @param[in] y value + @return the lowest value of the input parameters. +*/ +#define gs_min(x,y) ({ \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + _x < _y ? _x : _y; }) + +/** + Return maximum value. + @param[in] x value + @param[in] y value + @return the maximum value of the input parameters. +*/ +#define gs_max(x,y) ({ \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + _x > _y ? _x : _y; }) + +/** + Return minimum value. + @param[in] x value + @param[in] y value + @param[in] z value + @return the lowest value of the input parameters. +*/ +#define gs_min3(x,y,z) gs_min(gs_min((x),(y)), (z)) + +/** + Return maximum value. + @param[in] x value + @param[in] y value + @param[in] z value + @return the maximum value of the input parameters. +*/ +#define gs_max3(x,y,z) gs_max(gs_max((x),(y)), (z)) + +/** + Clamp value within min/max. + @param[in] x value + @param[in] _max max value + @param[in] _min min value + @return value between min and max. +*/ +#define gs_clamp(x, _min, _max) ({ \ + gs_min(gs_max((x), (_min)), (_max)); }) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/mutex.h b/gomspace/libutil/include/gs/util/mutex.h new file mode 100644 index 00000000..b5a411f7 --- /dev/null +++ b/gomspace/libutil/include/gs/util/mutex.h @@ -0,0 +1,63 @@ +#ifndef GS_UTIL_MUTEX_H +#define GS_UTIL_MUTEX_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Mutex (recursive). + + The mutex API wraps POSIX \a pthread_mutex and FreeRTOS \a mutex. + + @note Mutex can not be used from within an ISR routine - use gs_sem instead. +*/ + +#include +#if __linux__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if __linux__ +/** + Mutex handle. +*/ +typedef pthread_mutex_t * gs_mutex_t; +#else +typedef struct gs_freertos_mutex_t * gs_mutex_t; +#endif + +/** + Create mutex. + @param[out] mutex handle. + @return error code. +*/ +gs_error_t gs_mutex_create(gs_mutex_t * mutex); + +/** + Destroy mutex - free resources. + @param[in] mutex handle. + @return error code. +*/ +gs_error_t gs_mutex_destroy(gs_mutex_t mutex); + +/** + Lock mutex. + @param[in] mutex handle. + @return error code. +*/ +gs_error_t gs_mutex_lock(gs_mutex_t mutex); + +/** + Unlock mutex. + @param[in] mutex handle. + @return error code. +*/ +gs_error_t gs_mutex_unlock(gs_mutex_t mutex); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/pgm.h b/gomspace/libutil/include/gs/util/pgm.h new file mode 100644 index 00000000..04e39013 --- /dev/null +++ b/gomspace/libutil/include/gs/util/pgm.h @@ -0,0 +1,162 @@ +#ifndef GS_UTIL_PROGMEM_H +#define GS_UTIL_PROGMEM_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Macros for handling special memory access. + + On most targets/processors, constant data/strings are located in the program space and can be read in the same way as data in the data space. + However, on a few targets (e.g. avr/avr8), data/strings must be marked in a special way in order to go into the program space, see #GS_PGM_STR() + + Using following macros, will make it easier to make cross-platform code and avoid \#if/\#endif. + These macros should only be used where the code also needs to run on avr/avr8. + + @note Including this header on avr/avr8 will REDEFINE printf!. + + http://www.atmel.com/webdoc/avrlibcreferencemanual/group__avr__pgmspace.html. + http://www.nongnu.org/avr-libc/user-manual/pgmspace.html. +*/ + +#include +#if defined(__AVR__) +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__AVR__) || (__DOXYGEN__) +/** + Special program/data memory handling. +*/ +#define GS_PGM 1 + +/** + Place object in program space (must be const). + Example: static const uint8_t data8[] GS_PGM_OBJECT = {1, 255}; +*/ +#define GS_PGM_OBJECT PROGMEM + +/** + Place const string in program space. + By default the string goes into data, uses thereby uses up space. + Once the string is placed in program space, xx_P functions must be used to access them - see #GS_PGM_PRINTF. + @note printf is re-defined by including this header +*/ +#define GS_PGM_STR(str) PSTR(str) + +/** + Read uint8 from program space (near). +*/ +#define GS_PGM_UINT8(value) pgm_read_byte(&(value)) + +/** + Read uint8 from program space using a pointer (near). +*/ +#define GS_PGM_UINT8_BY_PTR(value) pgm_read_byte(value) + +/** + Read word from program space (near). +*/ +#define GS_PGM_UINT16(value) pgm_read_word(&(value)) +/** + Read word from program space using a pointer (near). +*/ +#define GS_PGM_UINT16_BY_PTR(value) pgm_read_word(value) + +/** + Read dword from program space (near). +*/ +#define GS_PGM_UINT32(value) pgm_read_dword(&(value)) +/** + Read word from program space using a pointer (near). +*/ +#define GS_PGM_UINT32_BY_PTR(value) pgm_read_dword(value) + +/** + Memcpy from program space (near). + @param[in] dst destination. + @param[in] src source - program space. + @param[in] n number of bytes to copy +*/ +#define GS_PGM_MEMCPY(dst, src, n) memcpy_P(dst, src, n) + +/** + String compare (program space) + @param[in] s1 string 1 + @param[in] s2 string 2 - program space. + @param[in] n max number of bytes to compare +*/ +#define GS_PGM_STRNCMP(s1,s2,n) strncmp_P(s1, s2, n) + +/** + String compare (program space) + @param[in] s1 string 1 + @param[in] s2 string 2 - program space. + @param[in] n max number of bytes to compare +*/ +#define GS_PGM_STRNCASECMP(s1,s2,n) strncasecmp_P(s1, s2, n) + +/** + String formatting character for referencing a string placed in programs space. +*/ +#define GS_PGM_FMT_STR "S" + +/** + printf (format string in program space). + Example: print \a param->name (from prgram space) and \a value from data space, using a format string in program space. + GS_PGM_PRINTF(GS_PGM_STR("%"GS_PGM_FMT_STR", %d"), param->name, value) +*/ +#define GS_PGM_PRINTF(format, ...) printf_P(format, ##__VA_ARGS__) + +/** + vprintf (format string in program space). +*/ +#define GS_PGM_VPRINTF(format, va) vfprintf_P(stdout, format, va) + +/** + snprintf (format string in program space). +*/ +#define GS_PGM_SNPRINTF(buf, bufsize, format, ...) snprintf_P(buf, bufsize, format, ##__VA_ARGS__) + +/** + vsnprintf (format string in program space). +*/ +#define GS_PGM_VSNPRINTF(buf, bufsize, format, va) vsnprintf_P(buf, bufsize, format, va) + +/** + redefines printf (puts format string in program space) + */ +#undef printf +#define printf(format, ...) GS_PGM_PRINTF(GS_PGM_STR(format), ## __VA_ARGS__) + +#else + +#undef GS_PGM + +#define GS_PGM_OBJECT +#define GS_PGM_STR(str) (str) +#define GS_PGM_UINT8(value) (value) +#define GS_PGM_UINT8_BY_PTR(value) (*(value)) +#define GS_PGM_UINT16(value) (value) +#define GS_PGM_UINT16_BY_PTR(value) (*(value)) +#define GS_PGM_UINT32(value) (value) +#define GS_PGM_UINT32_BY_PTR(value) (*(value)) +#define GS_PGM_MEMCPY(dst, src, size) memcpy(dst, src, size) +#define GS_PGM_STRNCMP(s1,pgmstr,size) strncmp(s1, pgmstr, size) +#define GS_PGM_STRNCASECMP(s1,pgmstr,size) strncasecmp(s1, pgmstr, size) + +#define GS_PGM_FMT_STR "s" +#define GS_PGM_PRINTF(format, ...) printf(format, ## __VA_ARGS__) +#define GS_PGM_VPRINTF(format, va) vprintf(format, va) +#define GS_PGM_SNPRINTF(buf, bufsize, format, ...) snprintf(buf, bufsize, format, ##__VA_ARGS__) +#define GS_PGM_VSNPRINTF(buf, bufsize, format, va) vsnprintf(buf, bufsize, format, va) + +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/queue.h b/gomspace/libutil/include/gs/util/queue.h new file mode 100644 index 00000000..43b7e9ae --- /dev/null +++ b/gomspace/libutil/include/gs/util/queue.h @@ -0,0 +1,102 @@ +#ifndef GS_UTIL_QUEUE_H +#define GS_UTIL_QUEUE_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Queue. + + The queue API wraps FreeRTOS \a queue. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if __linux__ +/** + Queue handle. +*/ +typedef struct gs_pthread_queue * gs_queue_t; +#else +typedef struct gs_freertos_queue_t * gs_queue_t; +#endif + +/** + Create queue. + + @param[in] items max number of items on the queue. + @param[in] item_size size of item (bytes). + @param[out] queue created queue. + @return_gs_error_t +*/ +gs_error_t gs_queue_create(size_t items, size_t item_size, gs_queue_t * queue); + +/** + Destroy queue - free resources. + + @param[in] queue handle. + @return_gs_error_t +*/ +gs_error_t gs_queue_destroy(gs_queue_t queue); + +/** + Enqueue object on queue. + @param[in] queue handle. + @param[in] value pointer to object, size specified at gs_queue_create(). + @param_int_timeout_ms + @return_gs_error_timeout + @return_gs_error_t +*/ +gs_error_t gs_queue_enqueue(gs_queue_t queue, const void *value, int timeout_ms); + +/** + Enqueue object on queue from within an ISR. + @param[in] queue handle. + @param[in] value pointer to object, size specified at gs_queue_create(). + @param[in] cswitch context switch. + @return GS_ERROR_FULL if queue is full. + @return_gs_error_t +*/ +gs_error_t gs_queue_enqueue_isr(gs_queue_t queue, const void * value, gs_context_switch_t * cswitch); + +/** + Dequeue object from queue. + @param[in] queue handle. + @param[out] buf element - size specified in gs_queue_create(). + @param_int_timeout_ms + @return_gs_error_timeout + @return_gs_error_t +*/ +gs_error_t gs_queue_dequeue(gs_queue_t queue, int timeout_ms, void *buf); + +/** + Dequeue object from queue from within an ISR. + @param[in] queue handle. + @param[in] cswitch context switch. + @param[out] buf element - size specified in gs_queue_create(). + @return GS_ERROR_NOT_FOUND if no elements in queue. + @return_gs_error_t +*/ +gs_error_t gs_queue_dequeue_isr(gs_queue_t queue, gs_context_switch_t * cswitch, void * buf); + +/** + Return queue size. + @param[in] queue handle. + @return queue size +*/ +unsigned int gs_queue_size(gs_queue_t queue); + +/** + Return queue size from within an ISR. + @param[in] queue handle. + @return queue size +*/ +unsigned int gs_queue_size_isr(gs_queue_t queue); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/rtc.h b/gomspace/libutil/include/gs/util/rtc.h new file mode 100644 index 00000000..b1988925 --- /dev/null +++ b/gomspace/libutil/include/gs/util/rtc.h @@ -0,0 +1,62 @@ +#ifndef GS_UTIL_RTC_H +#define GS_UTIL_RTC_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Real Time Clock interface. + + The RTC driver is used by gs_clock_get_time() and gs_clock_set_time(). +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Platform supporting RTC must register the driver, before the rest of the system can access it. + @see gs_rtc_register() +*/ +typedef struct { + /** + Call-back for getting RTC time. + @param[out] time user allocated struct for returning time. + */ + gs_error_t (*get_time)(void * driver_data, gs_timestamp_t * time); + /** + Call-back for setting RTC time. + @param[in] time user allocated struct for returning time. + */ + gs_error_t (*set_time)(void * driver_data, const gs_timestamp_t * time); +} gs_rtc_driver_t; + +/** + Register RTC driver. + @param[in] driver driver - data/struct must remain valid as long as registered. + @param[in] driver_data driver specific data, forwarded to driver when set/get is called. + @return_gs_error_t +*/ +gs_error_t gs_rtc_register(const gs_rtc_driver_t * driver, void * driver_data); + +/** + Return GS_OK if RTC is supported. +*/ +gs_error_t gs_rtc_supported(void); + +/** + Set RTC. +*/ +gs_error_t gs_rtc_get_time(gs_timestamp_t * time); + +/** + Get RTC. +*/ +gs_error_t gs_rtc_set_time(const gs_timestamp_t * time); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/sem.h b/gomspace/libutil/include/gs/util/sem.h new file mode 100644 index 00000000..4afd4d7d --- /dev/null +++ b/gomspace/libutil/include/gs/util/sem.h @@ -0,0 +1,75 @@ +#ifndef GS_UTIL_SEM_H +#define GS_UTIL_SEM_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Semaphore. + + The semaphore API wraps POSIX \a semaphore and FreeRTOS \a counted semaphore. + + Main difference is that FreeRTOS uses different API calls, when called from within + an ISR routine. +*/ + +#include +#if __linux__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if __linux__ +/** + Semaphore handle. +*/ +typedef sem_t * gs_sem_t; +#else +typedef struct gs_freertos_sem_t * gs_sem_t; +#endif + +/** + Create semaphore. + @param[in] initialValue initial value. + @param[out] sem created semaphore. + @return_gs_error_t +*/ +gs_error_t gs_sem_create(unsigned int initialValue, gs_sem_t * sem); + +/** + Destroy semaphore - free resources. + @param[in] sem handle. + @return_gs_error_t +*/ +gs_error_t gs_sem_destroy(gs_sem_t sem); + +/** + Wait for semaphore to be signaled. + @param[in] sem handle. + @param_int_timeout_ms + @return_gs_error_timeout + @return_gs_error_t +*/ +gs_error_t gs_sem_wait(gs_sem_t sem, int timeout_ms); + +/** + Post/signal semaphore. + @param[in] sem handle. + @return_gs_error_t +*/ +gs_error_t gs_sem_post(gs_sem_t sem); + +/** + Post/signal semaphore from within a ISR. + @param[in] sem handle. + @param[in] cswitch context switch. + @return_gs_error_t +*/ +gs_error_t gs_sem_post_isr(gs_sem_t sem, gs_context_switch_t * cswitch); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/stdio.h b/gomspace/libutil/include/gs/util/stdio.h new file mode 100644 index 00000000..992d4dda --- /dev/null +++ b/gomspace/libutil/include/gs/util/stdio.h @@ -0,0 +1,117 @@ +#ifndef GS_UTIL_STDIO_H +#define GS_UTIL_STDIO_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + GomSpace extensions to standard \a stdio.h. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Put character on stdout. +*/ +gs_error_t gs_stdio_putchar(int ch); + +/** + Read character from stdin with timeout. + @param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milli seconds. + @param[out] ch character read. If NULL, one character from stdin is still consumed - but nothing returned. + @return GS_ERROR_TIMEOUT on timeout + @return_gs_error_t +*/ +gs_error_t gs_stdio_getchar_timed(int timeout_ms, int *ch); + +/** + Read character from stdin. + Blocks until a character is available. + @param[out] ch character read. If NULL, one character from stdin is still consumed - but nothing returned. + @return_gs_error_t +*/ +static inline gs_error_t gs_stdio_getchar(int * ch) +{ + return gs_stdio_getchar_timed(-1, ch); +} + +/** + Read characters from stdin. + Blocks until all characters are read. + @param[in,out] buf user supplied buffer for receiving characters. + @param[in] n number of characters to read. + @return_gs_error_t +*/ +gs_error_t gs_stdio_get(char * buf, size_t n); + +/** + Write characters to stdout. + Blocks until characters are written. + @param[in] buf characters to write. + @param[in] n number of characters to write. + @param[in] text if \a true, new lines (\\n) are converted to \\r\\n. + @return_gs_error_t +*/ +gs_error_t gs_stdio_put(const char * buf, size_t n, bool text); + +/** + Pattern for printing a byte as binary. + @see GS_STDIO_BYTETOBINARY() +*/ +#define GS_STDIO_BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d" + +/** + Macro for splitting a byte info 'bits'. +*/ +#define GS_STDIO_BYTETOBINARY(byte) \ + (byte & 0x80 ? 1 : 0), \ + (byte & 0x40 ? 1 : 0), \ + (byte & 0x20 ? 1 : 0), \ + (byte & 0x10 ? 1 : 0), \ + (byte & 0x08 ? 1 : 0), \ + (byte & 0x04 ? 1 : 0), \ + (byte & 0x02 ? 1 : 0), \ + (byte & 0x01 ? 1 : 0) + +/** + Color definitions for gs_color_printf() + @see gs_color_printf() +*/ +typedef enum { + /** + Colors. + */ + GS_COLOR_COLORS = 0x00ff, + GS_COLOR_NONE = 0, + GS_COLOR_BLACK = 1, + GS_COLOR_RED = 2, + GS_COLOR_GREEN = 3, + GS_COLOR_YELLOW = 4, + GS_COLOR_BLUE = 5, + GS_COLOR_MAGENTA = 6, + GS_COLOR_CYAN = 7, + GS_COLOR_WHITE = 8, + /** + Attributes + */ + GS_COLOR_ATTRS = 0xff00, + GS_COLOR_BOLD = 0x100, +} gs_color_printf_t; + +/** + Printf with colors on stdout. + + Using the standard terminal escape sequences for setting the color. + @param[in] color color settings. + @param[in] format standard printf format string. +*/ +void gs_color_printf(gs_color_printf_t color, const char * format, ...) __attribute__ ((format (__printf__, 2, 3))); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/string.h b/gomspace/libutil/include/gs/util/string.h new file mode 100644 index 00000000..034af8c6 --- /dev/null +++ b/gomspace/libutil/include/gs/util/string.h @@ -0,0 +1,391 @@ +#ifndef GS_UTIL_STRING_H +#define GS_UTIL_STRING_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + String utilitizes. + + All string parsing functions will return #GS_OK if the string was parsed entirely. + If the string contains characters that are not part of the selected base, the functions will return #GS_ERROR_DATA. + If the value parsed is bigger than the output type, the functions will return #GS_ERROR_OVERFLOW. + Spaces are ignored by all functions. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Macro helper for concatening tokens. +*/ +#define GS_STRINGZ(x) #x + +/** + Stringify a preprocessing token. +*/ +#define GS_DEF2STRING(x) GS_STRINGZ(x) + +/** + * Strncpy (using size of destination) and forced zero termination. + */ +#define GS_STRNCPY(dst,src) strncpy(dst,src,GS_ARRAY_SIZE(dst));dst[GS_ARRAY_SIZE(dst)-1] = 0 + +/** + Convert string to int32 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_int32(const char * string, int32_t * value); + +/** + Convert string to uint32 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_uint32(const char * string, uint32_t * value); + +/** + Convert string to int64 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_int64(const char * string, int64_t * value); + +/** + Convert string to uint64 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_uint64(const char * string, uint64_t * value); + +/** + Convert string to int8 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 12 (decimal), 0x12 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_int8(const char * string, int8_t * value); + +/** + Convert string to uint8 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 12 (decimal), 0x12 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_uint8(const char * string, uint8_t * value); + +/** + Convert string to int16 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_int16(const char * string, int16_t * value); + +/** + Convert string to uint16 (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_uint16(const char * string, uint16_t * value); + +/** + Convert string to uint32 (hexadecimal). + Accepts: hexadecimal (no leading 0x), e.g. a123, A123. + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_hex_to_uint32(const char * string, uint32_t * value); + +/** + Convert string to uint64 (hexadecimal). + Accepts: hexadecimal (no leading 0x), e.g. a123, A123. + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_hex_to_uint64(const char * string, uint64_t * value); + +/** + Convert string to boolean. + Accepts: true, false, on, off, 1, 0 (ignores case) + @param[in] string string to convert. + @param[out] pvalue converted value + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_bool(const char * string, bool * pvalue); + +/** + Convert string to float. + @param[in] string string to convert. + @param[out] pvalue converted value + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_float(const char * string, float * pvalue); + +/** + Convert string to double. + @param[in] string string to convert. + @param[out] pvalue converted value + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_double(const char * string, double * pvalue); + +/** + Return string for boolean value (true or false). + @param[in] value value + @return \a 'true' if input is true, else \a 'false'. +*/ +const char * gs_string_from_bool(bool value); + +/** + Convert string to pointer (decimal or hexadecimal). + Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) + @param[in] string string to convert. + @param[out] value converted value + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +gs_error_t gs_string_to_pointer(const char * string, void ** value); + +/** + Format size as Bytes, Kilo or Mega. + + Output examples: \a 512.0B, \a 1.0K and \a 1.0M. + + @param[in] size size in bytes + @param[out] buffer formatted size + @param[in] buffer_size size of \a buf + @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type + @return GS_ERROR_DATA if the input string could not be parsed completely + @return GS_ERROR_ARG if the input string is a NULL pointer +*/ +char * gs_string_bytesize(long size, char *buffer, size_t buffer_size); + +/** + GS implementation of gcc's strtol + Instead of setting errno this function takes a pointer to err which is set + the same way as with gcc's strtol + + @param[in] nptr input string + @param[out] endptr the pointer to the end of the string parsed + @param[in] base number system (10 or 16) + @param[out] err return value if overflow + @return converted value +*/ +int32_t gs_string_strto32int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); + +/** + GS implementation of gcc's strtoul + Instead of setting errno this function takes a pointer to err which is set + the same way as with gcc's strtoul + + @param[in] nptr input string + @param[out] endptr the pointer to the end of the string parsed + @param[in] base number system (10 or 16) + @param[out] err return value if overflow + @return converted value +*/ +uint64_t gs_string_strto64uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); + +/** + GS implementation of gcc's strtoul + Instead of setting errno this function takes a pointer to err which is set + the same way as with gcc's strtoul + + @param[in] nptr input string + @param[out] endptr the pointer to the end of the string parsed + @param[in] base number system (10 or 16) + @param[out] err return value if overflow + @return converted value +*/ +int64_t gs_string_strto64int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); + +/** + GS implementation of gcc's strtoul + Instead of setting errno this function takes a pointer to err which is set + the same way as with gcc's strtoul + + @param[in] nptr input string + @param[out] endptr the pointer to the end of the string parsed + @param[in] base number system (10 or 16) + @param[out] err return value if overflow + @return converted value +*/ +uint32_t gs_string_strto32uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); + +/** + Returns pointer to first none-space character. + + @param[in] string string + @return NULL if \a string is NULL, otherwise first none-space character. +*/ +const char * gs_string_skip_leading_spaces(const char * string); + +/** + Check if a string is NULL or empty. + + @param[in] string string + @return true if string is empty or NULL. +*/ +bool gs_string_empty(const char * string); + +/** + Case-insentive wilcard match (similiar to fnmatch). + + Supports following wildcard(s): + - * (asterix) zero or more characters. + + This may be extended in future versions and will not be considered a break of the API. + + @param[in] pattern pattern to match against \a string. + @param[in] string string to match against \a pattern + @return \a true if match, else \ false +*/ +bool gs_string_match(const char * pattern, const char * string); + +/** + Returns \a true if string contains wildcards. + + @param[in] string string to check for wildcards. + @return \a true if string contains wildcards recognized by gs_string_match(). +*/ +bool gs_string_has_wildcards(const char * string); + +/** + Trim string in buffer by removing leading/trailing white space. + + Uses isspace(c). + + @param[in] buffer buffer to trim. + @param[in] buffer_size size of \a buffer. +*/ +void gs_string_trim(char * buffer, size_t buffer_size); + +/** + Returns \a true if string ends with endswith. + + @param[in] string string to check + @param[in] endswith string that string should end with + @return \a true if string endswith endswith +*/ +bool gs_string_endswith(const char * string, const char * endswith); + +/** + Extract suboption from a string. + + @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". + @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). + @param[out] buf user buffer for returning value of sub-option. + @param[in] buf_size size of \a buf user buffer. + @return_gs_error_t +*/ +gs_error_t gs_string_get_suboption(const char * options, const char * suboption, char * buf, size_t buf_size); + +/** + Extract suboption (as string) from a string. + + @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". + @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). + @param[in] def default value, returned if sub-option isn't found. + @param[out] buf user buffer for returning value of sub-option. + @param[in] buf_size size of \a buf user buffer. + @return If the sub-option isn't found, the \a def default value will be copied to \a buf and #GS_OK will be returned. + @return_gs_error_t +*/ +gs_error_t gs_string_get_suboption_string(const char * options, const char * suboption, const char * def, char * buf, size_t buf_size); + +/** + Extract suboption (as uint8) from a string. + + @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". + @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). + @param[in] def default value, returned if sub-option isn't found. + @param[out] value user supplied buffer for returning the value. + @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. + @return_gs_error_t +*/ +gs_error_t gs_string_get_suboption_uint8(const char * options, const char * suboption, uint8_t def, uint8_t * value); + +/** + Extract suboption (as uint16) from a string. + + @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". + @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). + @param[in] def default value, returned if sub-option isn't found. + @param[out] value user supplied buffer for returning the value. + @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. + @return_gs_error_t +*/ +gs_error_t gs_string_get_suboption_uint16(const char * options, const char * suboption, uint16_t def, uint16_t * value); + +/** + Extract suboption (as uint32) from a string. + + @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". + @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). + @param[in] def default value, returned if sub-option isn't found. + @param[out] value user supplied buffer for returning the value. + @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. + @return_gs_error_t +*/ +gs_error_t gs_string_get_suboption_uint32(const char * options, const char * suboption, uint32_t def, uint32_t * value); + +/** + Extract suboption (as bool) from a string. + + @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". + @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). + @param[in] def default value, returned if sub-option isn't found. + @param[out] value user supplied buffer for returning the value. + @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. + @return_gs_error_t +*/ +gs_error_t gs_string_get_suboption_bool(const char * options, const char * suboption, bool def, bool * value); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/test/cmocka.h b/gomspace/libutil/include/gs/util/test/cmocka.h new file mode 100644 index 00000000..43648627 --- /dev/null +++ b/gomspace/libutil/include/gs/util/test/cmocka.h @@ -0,0 +1,136 @@ +#ifndef GS_UTIL_TEST_CMOCKA_H +#define GS_UTIL_TEST_CMOCKA_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Cmocka extensions. + + Official site for cmocka https://cmocka.org. +*/ + +#include + +// cmocka +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if !(__DOXYGEN__) +// internal helpers - use macros +void _gs_assert_int_equal(const intptr_t a, const intptr_t b, bool equal, const char * const file, const int line); +void _gs_assert_uint_equal(const uintptr_t a, const uintptr_t b, bool equal, bool hex, const char * const file, const int line); +void _gs_assert_error_equal(const int a, const int b, bool equal, const char * const file, const int line); +void _gs_assert_float_equal(const float a, const float b, const float diff, bool equal, const char * const file, const int line); +void _gs_assert_double_equal(const double a, const double b, const double diff, bool equal, const char * const file, const int line); +#endif + +/** + Assert int (print value as signed). +*/ +#define GS_ASSERT_INT_EQUAL(a,b) _gs_assert_int_equal((intptr_t) (a), (intptr_t) (b), true, __FILE__, __LINE__) +/** + Assert unsigned int (print value as unsigned). +*/ +#define GS_ASSERT_UINT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, false, __FILE__, __LINE__) +/** + Assert int (print value as hex). +*/ +#define GS_ASSERT_XINT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, true, __FILE__, __LINE__) +/** + Assert #gs_error_t (print value and error text). +*/ +#define GS_ASSERT_ERROR_EQUAL(a,b) _gs_assert_error_equal(a, b, true, __FILE__, __LINE__) +/** + Assert #GS_OK (print value and error text). +*/ +#define GS_ASSERT_ERROR_OK(a) _gs_assert_error_equal(a, GS_OK, true, __FILE__, __LINE__) +/** + Assert float (print value as signed). +*/ +#define GS_ASSERT_FLOAT_EQUAL(a,b,diff) _gs_assert_float_equal(a, b, diff, true, __FILE__, __LINE__) +/** + Assert double (print value as signed). +*/ +#define GS_ASSERT_DOUBLE_EQUAL(a,b,diff) _gs_assert_double_equal(a, b, diff, true, __FILE__, __LINE__) + +/** + Assert int (print value as signed). +*/ +#define GS_ASSERT_INT_NOT_EQUAL(a,b) _gs_assert_int_equal((intptr_t) (a), (intptr_t) (b), false, __FILE__, __LINE__) +/** + Assert unsigned int (print value as unsigned). +*/ +#define GS_ASSERT_UINT_NOT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), false, false, __FILE__, __LINE__) +/** + Assert int (print value as hex). +*/ +#define GS_ASSERT_XINT_NOT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), false, true, __FILE__, __LINE__) +/** + Assert #GS_OK (print value and error text). +*/ +#define GS_ASSERT_ERROR_NOT_EQUAL(a,b) _gs_assert_error_equal(a, b, false, __FILE__, __LINE__) + +/** + Code reference. +*/ +#define GS_REF() __FILE__,__LINE__ +/** + Assert int with code reference (print value as signed). +*/ +#define GS_ASSERT_INT_EQUAL_REF(a,b,file,line) _gs_assert_int_equal((intptr_t) (a), (intptr_t) (b), true, file, file, line) +/** + Assert unsigned int with code reference (print value as unsigned). +*/ +#define GS_ASSERT_UINT_EQUAL_REF(a,b,file,line) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, false, file, line) +/** + Assert int with code reference (print value as hex). +*/ +#define GS_ASSERT_XINT_EQUAL_REF(a,b,file,line) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, true, file, line) +/** + Assert #gs_error_t with code reference (print value and error text). +*/ +#define GS_ASSERT_ERROR_EQUAL_REF(a,b,file,line) _gs_assert_error_equal(a, b, true, file, line) +/** + Assert #GS_OK with code reference (print value and error text). +*/ +#define GS_ASSERT_ERROR_OK_REF(a,file,line) _gs_assert_error_equal(a, GS_OK, true, file, line) + +/** + Run \a cmocka test group. + + @param[in] name name of test. If name is \a tests and GS_TEST_NAME is set, GS_TEST_NAME will be used instead. + @param[in] tests array of tests. + @param[in] num_tests number of tests. + @param[in] setup setup function, can be NULL. + @param[in] teardown teardown function, can be NULL. + @return 0 on success. +*/ +static inline int gs_cmocka_run_group_tests(const char *name, + const struct CMUnitTest * const tests, + const size_t num_tests, + CMFixtureFunction setup, + CMFixtureFunction teardown) +{ +#ifdef GS_TEST_NAME // set by buildtools::gs_test_cmocka.py + if (strcasecmp(name, "tests") == 0) { + name = GS_DEF2STRING(GS_TEST_NAME); + } +#endif + return _cmocka_run_group_tests(name, tests, num_tests, setup, teardown); +} + +#ifdef GS_TEST_NAME +// hi-jack cmocka's macro +#undef cmocka_run_group_tests +#define cmocka_run_group_tests(tests, setup, teardown) gs_cmocka_run_group_tests(GS_DEF2STRING(tests), tests, GS_ARRAY_SIZE(tests), setup, teardown) +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/test/command.h b/gomspace/libutil/include/gs/util/test/command.h new file mode 100644 index 00000000..d2227017 --- /dev/null +++ b/gomspace/libutil/include/gs/util/test/command.h @@ -0,0 +1,80 @@ +#ifndef GS_UTIL_TEST_COMMAND_H +#define GS_UTIL_TEST_COMMAND_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Command Test framework. + + Provides a simple way of unit-testing/validating commands. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Validate command execution. + + Runs a commands and validates the output/results agains the inputs. + Asserts if the results does not match. + + @param[in] cmd command (including arguments) to execute. + @param[in] ret expected return code from the command execution framework. + @param[in] cmd_ret expected return code from the commands handler. This is only validated if (ret = GS_OK). + @param[in] std_in string with expected command input. + @param[in] std_out string with expected command output. Wildcards (*\/?) are supported. + @param[in] file string with file name. + @param[in] line string with line no. + @return void +*/ +void _gs_assert_command_validate(const char *cmd, gs_error_t ret, gs_error_t cmd_ret, const char *std_in, const char *std_out, const char * const file, const int line); + +/** + Validate command results returned from last command execution. + Asserts if the results does not match. + + @param[in] no the result no to verify. + @param[in] group string with expected group id. Wildcards (*\/?) are supported. + @param[in] key string with expected key. Wildcards (*\/?) are supported. + @param[in] value string with expected value. Wildcards (*\/?) are supported. + @param[in] file string with file name. + @param[in] line string with line no. + @return void +*/ +void _gs_assert_command_validate_last_result(unsigned int no, const char *group, const char *key, const char *value, const char * const file, const int line); + +/** + Validate command execution. + + Runs a commands and validates the output/results agains the inputs. + Asserts if the results does not match. + + @param[in] cmd command (including arguments) to execute. + @param[in] ret expected return code from the command execution framework. + @param[in] cmd_ret expected return code from the commands handler. This is only validated if (ret = GS_OK). + @param[in] std_in string with expected command input. + @param[in] std_out string with expected command output. Wildcards (*\/?) are supported. + @return void +*/ +#define GS_ASSERT_COMMAND(cmd,ret,cmd_ret,std_in,std_out) _gs_assert_command_validate(cmd,ret,cmd_ret,std_in,std_out, __FILE__, __LINE__); + +/** + Validate command results returned from last command execution. + Asserts if the results does not match. + + @param[in] no the result no to verify. + @param[in] group string with expected group id. Wildcards (*\/?) are supported. + @param[in] key string with expected key. Wildcards (*\/?) are supported. + @param[in] value string with expected value. Wildcards (*\/?) are supported. + @return void +*/ +#define GS_ASSERT_COMMAND_RESULT(no,group,key,value) _gs_assert_command_validate_last_result(no,group,key,value, __FILE__, __LINE__); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/test/log.h b/gomspace/libutil/include/gs/util/test/log.h new file mode 100644 index 00000000..13322953 --- /dev/null +++ b/gomspace/libutil/include/gs/util/test/log.h @@ -0,0 +1,88 @@ +#ifndef GS_UTIL_TEST_LOG_H +#define GS_UTIL_TEST_LOG_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Log Test framework. + + Provides a simple way of veriyfing logs generated during unit-testing. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Assert log count - internal helper function. +*/ +void gs_assert_log_count(int level, unsigned int count, const char * file, int line); + +/** + Assert log messag and count - internal helper function. +*/ +void gs_assert_log(unsigned int stack_index, unsigned int count, gs_log_level_t level, const char * pattern, const char * file, int line); + +/** + Initialize framework, by installing a callback for \a print. + @param[in] verbose of \a true, logs will be printed on stdout. +*/ +void gs_test_log_init(bool verbose); + +/** + Clear log stats. +*/ +void gs_test_log_clear(void); + +/** + Assert number of error logs. +*/ +#define GS_ASSERT_LOG_ERROR(cnt) gs_assert_log_count(LOG_ERROR, cnt, __FILE__, __LINE__); + +/** + Assert number of warning logs. +*/ +#define GS_ASSERT_LOG_WARNING(cnt) gs_assert_log_count(LOG_WARNING, cnt, __FILE__, __LINE__); + +/** + Assert number of notice logs. +*/ +#define GS_ASSERT_LOG_NOTICE(cnt) gs_assert_log_count(LOG_NOTICE, cnt, __FILE__, __LINE__); + +/** + Assert number of info logs. +*/ +#define GS_ASSERT_LOG_INFO(cnt) gs_assert_log_count(LOG_INFO, cnt, __FILE__, __LINE__); + +/** + Assert number of debug logs. +*/ +#define GS_ASSERT_LOG_DEBUG(cnt) gs_assert_log_count(LOG_DEBUG, cnt, __FILE__, __LINE__); + +/** + Assert number of trace logs. +*/ +#define GS_ASSERT_LOG_TRACE(cnt) gs_assert_log_count(LOG_TRACE, cnt, __FILE__, __LINE__); + +/** + Assert number of all logs. +*/ +#define GS_ASSERT_LOG_ALL(cnt) gs_assert_log_count(-1, cnt, __FILE__, __LINE__); + +/** + Assert/find number of entries matching level and pattern. +*/ +#define GS_ASSERT_LOG(count,level,pattern) gs_assert_log(-1, count, level, pattern, __FILE__, __LINE__) + +/** + Assert log at stack index against matching level and pattern. +*/ +#define GS_ASSERT_LOG_AT(stack_index,level,pattern) gs_assert_log(stack_index, 1, level, pattern, __FILE__, __LINE__) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/thread.h b/gomspace/libutil/include/gs/util/thread.h new file mode 100644 index 00000000..37340818 --- /dev/null +++ b/gomspace/libutil/include/gs/util/thread.h @@ -0,0 +1,173 @@ +#ifndef GS_UTIL_THREAD_H +#define GS_UTIL_THREAD_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Thread/task API based on POSIX standard. + + The thread API wraps POSIX \a pthread and FreeRTOS \a task. +*/ + +#include +#if __linux__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if __linux__ +/** + Thread handle. +*/ +typedef pthread_t gs_thread_t; +#else +typedef struct gs_freertos_task_t * gs_thread_t; +#endif + +/** + Type used to declare thread stack buffer for gs_thread_create_with_stack. +*/ +typedef uint32_t gs_stack_type_t; + +/** + Thread priorities. + These values are mapped to platform specific values. +*/ +typedef enum { + /** + Idle (lowest) priority. + Typical use: Not much - runs when nothing else runs. + FreeRTOS: Idle thread. + */ + GS_THREAD_PRIORITY_IDLE = 5, + /** + Low priority. + Typical use: Service applications, e.g. servicing requests from the outside. + GOMspace: housekeeping, GOSH. + */ + GS_THREAD_PRIORITY_LOW = 10, + /** + Normal priority. + Typical use: Control - the primary application(s). + */ + GS_THREAD_PRIORITY_NORMAL = 15, + /** + High priority. + Typical use: Drivers off loading data from hardware to software buffers. + GOMspace: csp_route_task. + */ + GS_THREAD_PRIORITY_HIGH = 20, + /** + High priority. + Typical use: Very time critical threads. No long, time consuming processing. + FreeRTOS: Timer thread. + */ + GS_THREAD_PRIORITY_CRITICAL = 25, +} gs_thread_priority_t; + +/** + Thread function. +*/ +typedef void * (*gs_thread_func_t)(void * parameter); + +/** + Create thread as joinable. + @note only supported on linux. The thread must be joined to free all resources. +*/ +#define GS_THREAD_CREATE_JOINABLE 0x0001 + +/** + Create thread (or task on some platforms). + + pthread/Posix supports exit value and join, FreeRTOS supports neither (perhaps in the future), so API is designed after Posix. + + FreeRTOS: a thread must always terminate with a call to gs_thread_exit(). + linux: a thread is by default created detached, unless #GS_THREAD_CREATE_JOINABLE is specified. + + @param[in] name name of thread. Ignored on Linux. + @param[in] func function for thread to execute. + @param[in] parameter parameter parsed to the thread function. + @param[in] stack_size number of bytes to allocate for stack - not used/supported on all platforms. Ignored on Linux. + @param[in] priority thread priority. Ignored on Linux. + @param[in] flags flags to control creation, see #GS_THREAD_CREATE_JOINABLE. + @param[out] handle handle to the created thread, use NULL if not wanted. + @return_gs_error_t +*/ +gs_error_t gs_thread_create(const char * const name, + gs_thread_func_t func, + void * parameter, + size_t stack_size, + gs_thread_priority_t priority, + uint32_t flags, + gs_thread_t * handle); + +/** + Create thread (or task on some platforms) with user supplied buffer for stack. + + pthread/Posix supports exit value and join, FreeRTOS supports neither (perhaps in the future), so API is designed after Posix. + + FreeRTOS: a thread must always terminate with a call to gs_thread_exit(). + FreeRTOS v9.0 must be compiled with configSUPPORT_STATIC_ALLOCTION set to 1 - otherwise warning log is printed and user supplied + stack buffer is discarded + linux: a thread is by default created detached, unless #GS_THREAD_CREATE_JOINABLE is specified. + stack_buf is ignored. + + @param[in] name name of thread. Ignored on Linux. + @param[in] func function for thread to execute. + @param[in] parameter parameter parsed to the thread function. + @param[in] stack_size size of the user supplied stack buffer - not used/supported on all platforms. Ignored on Linux. + @param[in] stack_buf User supplied stack buffer - not used/supported on all platforms. Ignored on Linux. + @param[in] priority thread priority. Ignored on Linux. + @param[in] flags flags to control creation, see #GS_THREAD_CREATE_JOINABLE. + @param[out] handle handle to the created thread, use NULL if not wanted. + @return_gs_error_t +*/ +gs_error_t gs_thread_create_with_stack(const char * const name, + gs_thread_func_t func, + void * parameter, + size_t stack_size, + gs_stack_type_t *stack_buf, + gs_thread_priority_t priority, + uint32_t flags, + gs_thread_t * handle); + +/** + Exit current thread. + @param[in] exit_value exit value. +*/ +void gs_thread_exit(void * exit_value) __attribute__ ((noreturn)); + +/** + Sleep for X milli-seconds. + @note FreeRTOS: minimum sleep time depends on ticks per milli-second. A thread is suspended minimum 1 tick - unless \a time_ms is 0, in which case yield is called. + @deprecated use gs_time_sleep_ms() + @param[in] time_ms milli-seconds to sleep. +*/ +void gs_thread_sleep_ms(uint32_t time_ms); + +/** + Join with a terminated thread. + + @note Only supported on Linux and primarily used for testing. + @note This is not based on pthread_cancel(), so the user must have signaled the thread to stop - otherwise this will hang forever. + + @param[in] thread handle. + @param[out] return_retval return value from thread, use NULL if not wanted. + @return_gs_error_t +*/ +gs_error_t gs_thread_join(gs_thread_t thread, void ** return_retval); + +/** + Block thread forever. + + Primarily used in Linux applications main() to block main thread. +*/ +void gs_thread_block(void) __attribute__ ((noreturn)); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/time.h b/gomspace/libutil/include/gs/util/time.h new file mode 100644 index 00000000..d4425906 --- /dev/null +++ b/gomspace/libutil/include/gs/util/time.h @@ -0,0 +1,95 @@ +#ifndef GS_UTIL_TIME_H +#define GS_UTIL_TIME_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Releative time. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Converts minutes to seconds. +*/ +#define GS_TIME_MINS_TO_SECS(m) (m * 60) + +/** + Converts hours to seconds. +*/ +#define GS_TIME_HOURS_TO_SECS(h) (h * GS_TIME_MINS_TO_SECS(60)) + +/** + Converts days to seconds. +*/ +#define GS_TIME_DAYS_TO_SECS(d) (d * GS_TIME_HOURS_TO_SECS(24)) + +/** + Return relative time (milli seconds). + @note This will eventually wrap on all platforms - platform must wrap on 32 bit. + @return relativ milli seconds +*/ +uint32_t gs_time_rel_ms(void); + +/** + Return relative time (milli seconds). + @note This will eventually wrap on all platforms - platform must wrap on 32 bit. + @return relativ milli seconds +*/ +uint32_t gs_time_rel_ms_isr(void); + +/** + Returns seconds since process started. + @note On some platforms (e.g. Linux), first call will set offset and + first call it therefor not thread-safe. + @return seconds since boot (or process startup). +*/ +uint32_t gs_time_uptime(void); + +/** + Return time difference, compensating for time wrap due to 32 bit. + @note the function can not detect multiple time wraps, so function using it should + take action within 32 bit time. + @param[in] ref_ms reference time. + @param[in] now_ms current time. + @returns ms difference, compensating for time wrapping (if now_ms is less than ref_ms). +*/ +uint32_t gs_time_diff_ms(uint32_t ref_ms, uint32_t now_ms); + +/** + Sleep for X milli-seconds. + No busy waiting. + @note FreeRTOS: minimum sleep time depends on ticks per second. Suspends execution for minimum 1 tick - unless \a time is 0, in which case yield is called. + @param[in] time_ms milli-seconds to sleep. +*/ +void gs_time_sleep_ms(uint32_t time_ms); + +/** + Sleep X milli-seconds relative to reference. + + This sleep function uses a reference \a ref_ms to compensate for variance in processing time. + + No busy waiting. + + @param[in,out] ref_ms time reference. + @param[in] sleep_ms how many milli-seconds to sleep - relative to reference. + @return \a true if sleep time relative to last reference couldn't be done (reference reset), \a false if normal sleep was done. +*/ +bool gs_time_sleep_until_ms(uint32_t * ref_ms, uint32_t sleep_ms); + +/** + Sleep for X nano-seconds. + No busy waiting. + @note FreeRTOS: minimum sleep time depends on ticks per second. Suspends execution for minimum 1 tick - unless \a time is 0, in which case yield is called. + @param[in] time_ns nano-seconds to sleep. +*/ +void gs_time_sleep_ns(uint64_t time_ns); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/timestamp.h b/gomspace/libutil/include/gs/util/timestamp.h new file mode 100644 index 00000000..80fef6da --- /dev/null +++ b/gomspace/libutil/include/gs/util/timestamp.h @@ -0,0 +1,73 @@ +#ifndef GS_UTIL_TIMESTAMP_H +#define GS_UTIL_TIMESTAMP_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Timestamp utilities, for add, subtract, compare, copy, etc. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Number of nano seconds per second. +*/ +#define GS_TIMESTAMP_NSEC_PER_SEC 1000000000 + +/** + Portable time structure. + + Stanadard timespec_t is non-portable, so this structure must be used instead +*/ +typedef struct { + /** Seconds. */ + uint32_t tv_sec; + /** Nano seconds. */ + uint32_t tv_nsec; +} gs_timestamp_t; + +/** + @deprecated Use gs_timestamp_t +*/ +typedef gs_timestamp_t timestamp_t; + +/** + Add 2 timestamp's (t1 = t1 + t2). + @param[in,out] t1 timestamp + @param[in] t2 timestamp. + @return 0 on success, otherwise -1 +*/ +int timestamp_add(gs_timestamp_t * t1, const gs_timestamp_t * t2); + +/** + Subtract 2 timestamp's (t1 = t1 - t2) + @param[in,out] t1 timestamp + @param[in] t2 timestamp. + @return 0 on success, otherwise -1 +*/ +int timestamp_diff(gs_timestamp_t * t1, const gs_timestamp_t * t2); + +/** + Check if t2 is greate than t1. + @param[in] t1 time to compare + @param[in] t2 time to compare + @return 1 if t2 > t1, else 0. -1 on bad arguments. +*/ +int timestamp_ge(const gs_timestamp_t * t1, const gs_timestamp_t * t2); + +/** + Copy timestamp. + @param[in] from from timestamp + @param[out] to to timestamp + @return 0 on success, otherwise -1 +*/ +int timestamp_copy(const gs_timestamp_t * from, gs_timestamp_t * to); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/types.h b/gomspace/libutil/include/gs/util/types.h new file mode 100644 index 00000000..2c0d0597 --- /dev/null +++ b/gomspace/libutil/include/gs/util/types.h @@ -0,0 +1,114 @@ +#ifndef GS_UTIL_TYPES_H +#define GS_UTIL_TYPES_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Base type definitions and functions. + + In some rare cases, it is impossible to make code that works on all platforms. In these cases the following defines may be used to + exclude/include code: + | define | Platform | + | :----: | :---- | + | \_\_AVR\_\_ | 8 bit, e.g. atmega1281, atmega2560, attiny25, attiny44, attiny84 | + | \_\_linux\_\_ | 32/64 bit, Linux based | + + +*/ + +#include // intXX_t +#include // bool +#include // size_t + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Control static declaration at compile time. + Allows unit tests to access internal functions or variables. + @note Static declared variables are initialized to zero by the compiler - BUT if you use GS_NO_STATIC instead of static, they will not be initialized. +*/ +#if GS_NO_STATIC +#define GS_STATIC +#else +#define GS_STATIC static +#endif + +/** + Convert integer to pointer. +*/ +#define GS_TYPES_INT2PTR(value) ((void*)(intptr_t)(value)) + +/** + Convert integer to pointer. +*/ +#define GS_TYPES_UINT2PTR(value) ((void*)(uintptr_t)(value)) + +/** + Convert pointer to integer. +*/ +#define GS_TYPES_PTR2INT(value) ((intptr_t)(void*)(value)) + +/** + Convert pointer to integer. +*/ +#define GS_TYPES_PTR2UINT(value) ((uintptr_t)(void*)(value)) + +/** + Assert on 'value'. + + Example: + GS_STATIC_ASSERT(sizeof(int) >= 2, int_must_be_at_least_16bit); + fails if size of (int) is less than 2 bytes. +*/ +#define GS_STATIC_ASSERT(condition, name) typedef char name[(condition) ? 1 : -1] + +/** + Context switch state. + Used by FreeRTOS when waking a higher priority task/thread from within an ISR. + The actual struct is defined in libembed. +*/ +typedef struct gs_context_switch gs_context_switch_t; + +/** + Return element count of array. +*/ +#define GS_ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) + +/** + Address union. +*/ +typedef union { + /** + Normal address pointer. + */ + void* p; + /** + Address pointer as an unsigned value. + */ + uintptr_t u; +} gs_address_t; + +/** + @cond HIDDEN_SYMBOLS + Compile check size of primitives (just to be sure, that they are what we expect). +*/ +GS_STATIC_ASSERT(sizeof(gs_address_t) == sizeof(void*), unexpected_address_void_pointer_size); +GS_STATIC_ASSERT(sizeof(gs_address_t) == sizeof(uintptr_t), unexpected_address_uintptr_size); +GS_STATIC_ASSERT(sizeof(bool) == sizeof(uint8_t), unexpected_bool_size); +GS_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), unexpected_float_size); +#if (__AVR__) +// avr/avr8 is 8 bit +GS_STATIC_ASSERT(sizeof(int) == sizeof(int16_t), unexpected_int_size_on_avr8); +#else +// rest should be 32 or 64 bit +GS_STATIC_ASSERT(sizeof(int) == sizeof(int32_t), unexpected_int_size); +GS_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t), unexpected_double_size); +#endif +/** @endcond */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/unistd.h b/gomspace/libutil/include/gs/util/unistd.h new file mode 100644 index 00000000..a8b65845 --- /dev/null +++ b/gomspace/libutil/include/gs/util/unistd.h @@ -0,0 +1,32 @@ +#ifndef GS_UTIL_UNISTD_H +#define GS_UTIL_UNISTD_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + GomSpace extensions to standard \a unistd.h. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Get current working directory. + + @note Linux uses standard getcwd(). + + @param[out] buf user supplied buffer for returning path. + @param[in] bufsize size of \a buf. + @return #GS_ERROR_NOT_FOUND if no current directory is set. + @return #GS_ERROR_RANGE if \a buf is too small + @return_gs_error_t +*/ +gs_error_t gs_getcwd(char * buf, size_t bufsize); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/vmem.h b/gomspace/libutil/include/gs/util/vmem.h new file mode 100644 index 00000000..19576a63 --- /dev/null +++ b/gomspace/libutil/include/gs/util/vmem.h @@ -0,0 +1,194 @@ +#ifndef GS_UTIL_VMEM_H +#define GS_UTIL_VMEM_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Virtual memory interface. + + The API provides support for accessing different hardware components using a common API, by providing a component specific driver. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Virtual memory mapping. +*/ +typedef struct gs_vmem gs_vmem_t; + +/** + VMEM driver write. + + @param[in] vmem vmem entry. + @param[in] to Address where to write data to. + @param[in] from Address where to write data from. + @param[in] size Number of bytes to write. + @return_gs_error_t +*/ +typedef gs_error_t (*gs_vmem_write_function_t)(const gs_vmem_t * vmem, void* to, const void * from, size_t size); + +/** + VMEM driver read. + + @param[in] vmem vmem entry. + @param[in] to Address where to read data to. + @param[in] from Address where to read data from. + @param[in] size Number of bytes to read. + @return_gs_error_t +*/ +typedef gs_error_t (*gs_vmem_read_function_t)(const gs_vmem_t * vmem, void* to, const void * from, size_t size); + +/** + VMEM driver lock. + + @param[in] vmem vmem entry. + @param[in] on Enable/Disable lock. + @return_gs_error_t +*/ +typedef gs_error_t (*gs_vmem_lock_function_t)(const gs_vmem_t * vmem, bool on); + +/** + VMEM driver information. + + Return relevant information for the VMEM driver. + + @param[in] vmem vmem entry. + @param[in] buffer user allocated buffer for returning information. + @param[in] buffer_size size (length) of \a buffer. + @return_gs_error_t +*/ +typedef gs_error_t (*gs_vmem_info_function_t)(const gs_vmem_t * vmem, char * buffer, size_t buffer_size); + +/** + VMEM driver interface. +*/ +typedef struct { + /** + Write function. + */ + const gs_vmem_write_function_t write; + /** + Read function. + */ + const gs_vmem_read_function_t read; + /** + Lock function. + */ + const gs_vmem_lock_function_t lock; + /** + Information function. + */ + const gs_vmem_info_function_t info; +} gs_vmem_driver_t; + +/** + Virtual memory mapping. + + @note Call gs_vmem_set_map() for registering mappings. +*/ +struct gs_vmem { + /** + Logical name of enry. + */ + const char *const name; + /** + Virtual memory start. + */ + gs_address_t virtmem; + /** + Physical memory start. + This address only makes sense for the VMEM driver. + */ + gs_address_t physmem; + /** + Size of memory block. + */ + const size_t size; + /** + Driver function. + */ + const gs_vmem_driver_t* drv; + /** + Driver data. + */ + const void* drv_data; +}; + +/** + Set VMEM mapping. + Must be done for the API to work. + @param[in] map VMEM mapping table, must be terminated with an NULL entry. + @return_gs_error_t +*/ +gs_error_t gs_vmem_set_map(const gs_vmem_t * map); + +/** + Return VMEM map. +*/ +const gs_vmem_t * gs_vmem_get_map(void); + +/** + Print all VMEM entries to stdout. + @param[in] out output stream + @return_gs_error_t +*/ +gs_error_t gs_vmem_list(FILE * out); + +/** + Get VMEM entry by name. + @param[in] name name of VMEM entry. + @return VMEM mapping or NULL if not found. +*/ +const gs_vmem_t * gs_vmem_get_by_name(const char * name); + +/** + Lock/un-lock VMEM area. + @param[in] name name of VMEM entry. + @param[in] on Enable/Disable lock. + @return GS_ERROR_NOT_FOUND area not found. + @return GS_ERROR_NOT_SUPPORTED if locking isn't supported. + @return_gs_error_t +*/ +gs_error_t gs_vmem_lock_by_name(const char * name, bool on); + +/** + Lock/un-lock all VMEM areas. + @param[in] on lock on or off. + @return_gs_error_t +*/ +gs_error_t gs_vmem_lock_all(bool on); + +/** + memcpy on VMEM. + @note if no VMEM entries are found, a normal memcpy is called with the provided pointers. + @param[in] to to location. + @param[in] from from location. + @param[in] size number of bytes to copy. +*/ +void* gs_vmem_cpy(void* to, const void* from, size_t size); + +/** + Macro for calling gs_vmem_cpy(). +*/ +#define GS_VMEM_CPY(to, from, size) gs_vmem_cpy(to, from, size) + +/** + Macro for calling gs_vmem_cpy(). + @deprecated Use gs_vmem_cpy() directly. +*/ +#define VMEM_CPY(to, from, size) gs_vmem_cpy(to, from, size) + +/** + Register VMEM commands. + @return_gs_error_t +*/ +gs_error_t gs_vmem_register_commands(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/watchdog/watchdog.h b/gomspace/libutil/include/gs/util/watchdog/watchdog.h new file mode 100644 index 00000000..30d2bd30 --- /dev/null +++ b/gomspace/libutil/include/gs/util/watchdog/watchdog.h @@ -0,0 +1,143 @@ +#ifndef GS_UTIL_WATCHDOG_WATCHDOG_H +#define GS_UTIL_WATCHDOG_WATCHDOG_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Software watchdog client interface. + + The software watchdog (SWWD) enables having multiple instances of a Watchdog. + The software watchdog manages the HW watchdog, and will ultimately + trigger the HW watchdog, if one or more clients are not servicing the + software watchdog. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Software Watchdog handle +*/ +typedef struct gs_swwd_hdl gs_swwd_hdl_t; + +/** + Software watchdog callback function. + + Called by the SWWD upon timeout. + @param[in] userdata user data provided on gs_swwd_register() +*/ +typedef void (*gs_swwd_callback_function_t)(void * userdata); + +/** + Watchdog timeout action. +*/ +typedef enum { + /** + Reset system on timeout (stops touching the hardware watchdog). + Once the watchdog has timeout, the watchdog cannot be re-activated. + */ + GS_SWWD_TIMEOUT_ACTION_RESET = 0, + /** + Log 'warning' on timeout, but otherwise ignore the timeout. + The watchdog can re-activated by touching the watchdog again. + */ + GS_SWWD_TIMEOUT_ACTION_LOG = 1, +} gs_swwd_timeout_action_t; + +/** + Create the software watchdog back-end. + + Only one SWWD back-end can exist at any given time. + + @param[in] max_clients The maximum number of Software Watchog clients supported. + @param[in] dev The HW Watchdog device to use. + @return_gs_error_t +*/ +gs_error_t gs_swwd_create(uint32_t max_clients, gs_watchdog_device_t *dev); + +/** + Destroy the Software Watchdog back-end (and stop the SWWD monitor task if started). + + @param[in] timeout_s Maximum number of seconds to allow this operation to complete. + @return_gs_error_t +*/ +gs_error_t gs_swwd_destroy(uint32_t timeout_s); + +/** + Check for expired software watchdog clients. This function is only to be used if the + SWWD monitor task is not started. Otherwise the SWWD task will handle this in the back- + ground. I.e: + - In passive mode this function must be called periodically to check for expired + clients, and service the HW watchdog. + - In active mode this function is called in background by the SWWD monitor task. + + The interval between these checks should be much less that the HW watchdog + timeout period, to ensure that the HW Watchdog is correctly serviced. + Calling this e.g. every 1-3 seconds will be a good default. + + @param[out] num_expired The number of SW Watchog clients currently expired. + @return_gs_error_t +*/ +gs_error_t gs_swwd_check_expired_clients(uint32_t *num_expired); + +/** + Register/create a new software watchdog instance + + @param[out] wdt_handle A reference to software watchdog handle + @param[in] timeout Timeout in seconds. + @param[in] callback Callback function which is called on timeout. NULL if unused. + @param[in] userdata Pointer to user data used in the callback function. Ignored if callback is NULL. + @param[in] client_name A descriptive name given by the user in order to identify the watchdog/client - the pointer must remain valid as long as the watchdog is registered. + @param[in] action what action to take, when/if the watchdog times out. + @return_gs_error_t +*/ +gs_error_t gs_swwd_register_with_action(gs_swwd_hdl_t ** wdt_handle, uint32_t timeout, gs_swwd_callback_function_t callback, void * userdata, const char *client_name, gs_swwd_timeout_action_t action); + +/** + Register/create a software watchdog with action \a reset on timeout. + + @param[out] wdt_handle A reference to software watchdog handle + @param[in] timeout Timeout in seconds before the software watchdog fires. + @param[in] callback Callback function which is called on timeout. NULL if unused. + @param[in] userdata Pointer to user data used in the callback function. Ignored if callback is NULL. + @param[in] client_name A descriptive name given by the user in order to identify the watchdog/client - the pointer must remain valid as long as the watchdog is registered. + @return_gs_error_t +*/ +static inline gs_error_t gs_swwd_register(gs_swwd_hdl_t ** wdt_handle, uint32_t timeout, gs_swwd_callback_function_t callback, void * userdata, const char *client_name) +{ + return gs_swwd_register_with_action(wdt_handle, timeout, callback, userdata, client_name, GS_SWWD_TIMEOUT_ACTION_RESET); +} + +/** + De-Register a Software Watchdog instance + + @param[in] wdt_handle A software watchdog handle + @return_gs_error_t +*/ +gs_error_t gs_swwd_deregister(gs_swwd_hdl_t ** wdt_handle); + +/** + Touch Software Watchdog to reset the timer + + @param[in] wdt_handle A software watchdog handle + @return_gs_error_t +*/ +gs_error_t gs_swwd_touch(gs_swwd_hdl_t * wdt_handle); + +/** + Set timeout of the Software Watchdog. + + @param[in] wdt_handle A software watchdog handle + @param[in] timeout Timeout in seconds before the SWWD fires. + @return_gs_error_t +*/ +gs_error_t gs_swwd_set_timeout(gs_swwd_hdl_t * wdt_handle, uint32_t timeout); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/watchdog/watchdog_task.h b/gomspace/libutil/include/gs/util/watchdog/watchdog_task.h new file mode 100644 index 00000000..833f1511 --- /dev/null +++ b/gomspace/libutil/include/gs/util/watchdog/watchdog_task.h @@ -0,0 +1,45 @@ +#ifndef GS_UTIL_WATCHDOG_WATCHDOG_TASK_H +#define GS_UTIL_WATCHDOG_WATCHDOG_TASK_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Software Watchdog server/task interface + + The Software Watchdog task implements the core (backend) functionality of the the software watchdog. + The Client API for the SW watchdog is implemented in watchdog.h + + @note This API is not thread safe! +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Start the Software Watchdog monitor task if the SWWD is to be used as a + separate task (active mode). + In this case the SWWD task will monitor expired clients in the background + and the polling API gs_swwd_check_expired_clients() needs not to be called by + the user. + + @return_gs_error_t +*/ + +gs_error_t gs_swwd_monitor_task_start(); + +/** + Stops the Software Watchdog monitor task + + @param[in] timeout_s Maximum number of seconds to allow this operation to complete. + + @return_gs_error_t +*/ +gs_error_t gs_swwd_monitor_task_stop(uint32_t timeout_s); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libutil/include/gs/util/zip/zip.h b/gomspace/libutil/include/gs/util/zip/zip.h new file mode 100644 index 00000000..04c87974 --- /dev/null +++ b/gomspace/libutil/include/gs/util/zip/zip.h @@ -0,0 +1,62 @@ +#ifndef LIBUTIL_ZIP_ZIP_UTILS_H +#define LIBUTIL_ZIP_ZIP_UTILS_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Compress/decompress API based on zlib compressed data format specification standards. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + Compress file. + + @param[in] src file to be compressed. + @param[out] dest compressed output file. + @return_gs_error_t +*/ +int gs_zip_compress_file(const char *src, const char *dest); + +/** + Decompress file. + + @param[in] src file to be secompressed. + @param[out] dest decompressed output file. + @return_gs_error_t +*/ +int gs_zip_decompress_file(const char *src, const char *dest); + +/** + Compress data. + + @param[in] src pointer to the data to be compressed. + @param[in] src_len size of the data. + @param[out] dest pointer to the compressed data. + @param[out] dest_len pointer to the size of the compressed data. + @return_gs_error_t +*/ +int gs_zip_compress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t *dest_len); + +/** + Decompress data. + + @param[in] src pointer to the data to be decompressed. + @param[in] src_len size of the data. + @param[out] dest pointer to the decompressed data. + @param[out] dest_len size of the destination memory area. + @param[out] decomp_len pointer to the size of the decompressed data. + @return_gs_error_t +*/ +int gs_zip_decompress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t dest_len, uint32_t *decomp_len); + + +#ifdef __cplusplus +} +#endif +#endif /* LIBUTIL_ZIP_ZIP_UTILS_H */ diff --git a/gomspace/libutil/src/base16.c b/gomspace/libutil/src/base16.c new file mode 100644 index 00000000..da3a83c6 --- /dev/null +++ b/gomspace/libutil/src/base16.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010 Michael Brown . + * + * This program 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 2 of the + * License, or any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +void base16_encode(const uint8_t * raw, size_t len, char *encoded) +{ + const uint8_t *raw_bytes = raw; + char *encoded_bytes = encoded; + size_t remaining = len; + + for (; remaining--; encoded_bytes += 2) + snprintf(encoded_bytes, 3, "%02X", *(raw_bytes++)); + +} + +int base16_decode(const char *encoded, uint8_t *raw) +{ + uint8_t *raw_bytes = raw; + if (encoded) { + const char *encoded_bytes = encoded; + char buf[3]; + char *endp; + + while (encoded_bytes[0]) { + if (!encoded_bytes[1]) { + log_error("Base16-encoded string \"%s\" has invalid length\n", + encoded); + return GS_ERROR_ARG; + } + memcpy(buf, encoded_bytes, 2); + buf[2] = '\0'; + *(raw_bytes++) = (uint8_t) strtoul(buf, &endp, 16); + if (*endp != '\0') { + log_error("Base16-encoded string \"%s\" has invalid byte \"%s\"\n", + encoded, buf); + return GS_ERROR_ARG; + } + encoded_bytes += 2; + } + } + return (int)(raw_bytes - raw); +} diff --git a/gomspace/libutil/src/bindings/python/pyutil.c b/gomspace/libutil/src/bindings/python/pyutil.c new file mode 100644 index 00000000..b2924ba6 --- /dev/null +++ b/gomspace/libutil/src/bindings/python/pyutil.c @@ -0,0 +1,73 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +#if PY_MAJOR_VERSION == 3 +#define IS_PY3 +#endif + +/** + * Helpers + */ + +static PyObject* pyutil_get_clock_time(PyObject *self, PyObject *args) { + gs_timestamp_t ts; + gs_clock_get_time(&ts); + return Py_BuildValue("II", ts.tv_sec, ts.tv_nsec); +} + + +static PyObject* pyutil_error_string(PyObject *self, PyObject *args) +{ + int error; + if (!PyArg_ParseTuple(args, "i", &error)) + { + Py_RETURN_NONE; + } + return Py_BuildValue("s", gs_error_string(error)); +} + +static PyMethodDef methods[] = { + + /* helpers */ + {"get_clock_time", pyutil_get_clock_time, METH_NOARGS, ""}, + {"error_string", pyutil_error_string, METH_VARARGS, ""}, + + /* sentinel */ + {NULL, NULL, 0, NULL} +}; + +#ifdef IS_PY3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "libgsutil_py3", + NULL, /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, + or -1 if the module keeps state in global variables. */ + methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +#ifdef IS_PY3 +PyMODINIT_FUNC PyInit_libgsutil_py3(void) { +#else +PyMODINIT_FUNC initlibgsutil_py2(void) { +#endif + +#ifdef IS_PY3 + PyObject* m = PyModule_Create(&moduledef); +#else + Py_InitModule("libgsutil_py2", methods); +#endif + +#ifdef IS_PY3 + return m; +#endif +} + diff --git a/gomspace/libutil/src/bytebuffer.c b/gomspace/libutil/src/bytebuffer.c new file mode 100644 index 00000000..49b5a495 --- /dev/null +++ b/gomspace/libutil/src/bytebuffer.c @@ -0,0 +1,128 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +#define GS_BYTEBUFFER_F_FAILED 0x01 +#define GS_BYTEBUFFER_F_OVERRUN 0x02 + +gs_error_t gs_bytebuffer_init(gs_bytebuffer_t * bb, void * buffer, size_t buffer_size) +{ + GS_CHECK_HANDLE(bb != NULL); + memset(bb, 0, sizeof(*bb)); + if (buffer) { + if (buffer_size < 2) { + // must always have room for NUL termination. + return GS_ERROR_ARG; + } + bb->buffer = buffer; + bb->size = buffer_size; + } else { + // dry run - don't insert anything in buffer, but increment used + } + + return GS_OK; +} + +void gs_bytebuffer_vprintf(gs_bytebuffer_t * bb, const char * format, va_list ap) +{ + int res; + if (bb->buffer == NULL) { + // dry run + char buf[3]; + res = vsnprintf(buf, 0, format, ap); + if (res >= 0) { + bb->used += res; + } + } else { + const size_t free_bytes = gs_bytebuffer_get_free(bb); + res = vsnprintf((char*)&bb->buffer[bb->used], free_bytes, format, ap); + if (res > 0) { + if ((size_t)res >= free_bytes) { + // over run + bb->flags |= GS_BYTEBUFFER_F_OVERRUN; + bb->used = bb->size; + bb->buffer[bb->size - 1] = 0; + } else { + bb->used += res; + } + } + } + if (res < 0) { + bb->flags |= GS_BYTEBUFFER_F_FAILED; + } +} + +void gs_bytebuffer_printf(gs_bytebuffer_t * bb, const char * format, ...) +{ + va_list ap; + va_start(ap, format); + gs_bytebuffer_vprintf(bb, format, ap); + va_end(ap); +} + +void gs_bytebuffer_append(gs_bytebuffer_t * bb, const void * data, size_t length) +{ + if (bb->buffer == NULL) { + // dry run + bb->used += length; + } else { + const size_t free_bytes = gs_bytebuffer_get_free(bb); + if (free_bytes >= length) { + memcpy(&bb->buffer[bb->used], data, length); + bb->used += length; + } else { + memcpy(&bb->buffer[bb->used], data, free_bytes); + bb->flags |= GS_BYTEBUFFER_F_OVERRUN; + bb->used += free_bytes; + } + } +} + +void gs_bytebuffer_append_string(gs_bytebuffer_t * bb, const char * string) +{ + if (gs_string_empty(string) == false) { + gs_bytebuffer_append(bb, string, strlen(string)); + } +} + +void gs_bytebuffer_append_string_max(gs_bytebuffer_t * bb, const char * string, size_t max_length) +{ + if (gs_string_empty(string) == false) { + gs_bytebuffer_append(bb, string, strnlen(string, max_length)); + } +} + +char * gs_bytebuffer_get_as_string(gs_bytebuffer_t * bb, gs_error_t * error) +{ + if (bb && bb->buffer) { + // handle NUL termination + if (bb->used < bb->size) { + bb->buffer[bb->used] = 0; + } else { + // overrun - truncation buffer + bb->flags |= GS_BYTEBUFFER_F_OVERRUN; + bb->buffer[bb->used - 1] = 0; + } + if (error) { + *error = gs_bytebuffer_get_state(bb); + } + return (char*) bb->buffer; + } + return NULL; +} + +gs_error_t gs_bytebuffer_get_state(gs_bytebuffer_t * bb) +{ + if (bb) { + if (bb->flags & GS_BYTEBUFFER_F_FAILED) { + return GS_ERROR_DATA; + } + if (bb->flags & GS_BYTEBUFFER_F_OVERRUN) { + return GS_ERROR_OVERFLOW; + } + return GS_OK; + } + return GS_ERROR_HANDLE; +} diff --git a/gomspace/libutil/src/byteorder.c b/gomspace/libutil/src/byteorder.c new file mode 100644 index 00000000..e00c9737 --- /dev/null +++ b/gomspace/libutil/src/byteorder.c @@ -0,0 +1,323 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include + +/* Convert 16-bit number from host byte order to network byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_hton16(uint16_t h16) { +#if UTIL_BIG_ENDIAN + return h16; + +#elif UTIL_LITTLE_ENDIAN + return (uint16_t)(((h16 & 0xff00) >> 8) | + ((h16 & 0x00ff) << 8)); +#endif +} + +/* Convert 16-bit number from network byte order to host byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_ntoh16(uint16_t n16) { + return util_hton16(n16); +} + +/* Convert 32-bit number from host byte order to network byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_hton32(uint32_t h32) { +#if UTIL_BIG_ENDIAN + return h32; + +#elif UTIL_LITTLE_ENDIAN + return (((h32 & 0xff000000) >> 24) | + ((h32 & 0x000000ff) << 24) | + ((h32 & 0x0000ff00) << 8) | + ((h32 & 0x00ff0000) >> 8)); +#endif +} + +/* Convert 32-bit number from network byte order to host byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_ntoh32(uint32_t n32) { + return util_hton32(n32); +} + +/* Convert 64-bit number from host byte order to network byte order */ +extern inline uint64_t __attribute__ ((__const__)) util_hton64(uint64_t h64) { +#if UTIL_BIG_ENDIAN + return h64; + +#elif UTIL_LITTLE_ENDIAN + return (((h64 & 0xff00000000000000LL) >> 56) | + ((h64 & 0x00000000000000ffLL) << 56) | + ((h64 & 0x00ff000000000000LL) >> 40) | + ((h64 & 0x000000000000ff00LL) << 40) | + ((h64 & 0x0000ff0000000000LL) >> 24) | + ((h64 & 0x0000000000ff0000LL) << 24) | + ((h64 & 0x000000ff00000000LL) >> 8) | + ((h64 & 0x00000000ff000000LL) << 8)); +#endif +} + +/* Convert 64-bit number from host byte order to network byte order */ +extern inline uint64_t __attribute__ ((__const__)) util_ntoh64(uint64_t n64) { + return util_hton64(n64); +} + +/* Convert float from host byte order to network byte order */ +extern inline float __attribute__ ((__const__)) util_htonflt(float f) { +#if UTIL_BIG_ENDIAN + return f; + +#elif UTIL_LITTLE_ENDIAN + union v { + float f; + uint32_t i; + }; + union v val; + val.f = f; + val.i = util_hton32(val.i); + return val.f; +#endif +} + +/* Convert float from host byte order to network byte order */ +extern inline float __attribute__ ((__const__)) util_ntohflt(float f) { + return util_htonflt(f); +} + +/* Convert double from host byte order to network byte order */ +extern inline double __attribute__ ((__const__)) util_htondbl(double d) { +#if UTIL_BIG_ENDIAN + return d; + +#elif UTIL_LITTLE_ENDIAN + union v { + double d; + uint64_t i; + }; + union v val; + val.d = d; + val.i = util_hton64(val.i); + return val.d; +#endif +} + +/* Convert float from host byte order to network byte order */ +extern inline double __attribute__ ((__const__)) util_ntohdbl(double d) { + return util_htondbl(d); +} + +/* Convert 16-bit number from host byte order to big endian byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_htobe16(uint16_t h16) { + return util_hton16(h16); +} + +/* Convert 16-bit number from host byte order to little endian byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_htole16(uint16_t h16) { +#if UTIL_LITTLE_ENDIAN + return h16; + +#elif UTIL_BIG_ENDIAN + return (uint16_t)(((h16 & 0xff00) >> 8) | + ((h16 & 0x00ff) << 8)); +#endif +} + +/* Convert 16-bit number from big endian byte order to little endian byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_betoh16(uint16_t be16) { + return util_ntoh16(be16); +} + +/* Convert 16-bit number from little endian byte order to host byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_letoh16(uint16_t le16) { + return util_htole16(le16); +} + +/* Convert 32-bit number from host byte order to big endian byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_htobe32(uint32_t h32) { + return util_hton32(h32); +} + +/* Convert 32-bit number from little endian byte order to host byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_htole32(uint32_t h32) { +#if UTIL_LITTLE_ENDIAN + return h32; + +#elif UTIL_BIG_ENDIAN + return (((h32 & 0xff000000) >> 24) | + ((h32 & 0x000000ff) << 24) | + ((h32 & 0x0000ff00) << 8) | + ((h32 & 0x00ff0000) >> 8)); +#endif +} + +/* Convert 32-bit number from big endian byte order to host byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_betoh32(uint32_t be32) { + return util_ntoh32(be32); +} + +/* Convert 32-bit number from little endian byte order to host byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_letoh32(uint32_t le32) { + return util_htole32(le32); +} + +/* Convert 64-bit number from host byte order to big endian byte order */ +extern inline uint64_t __attribute__ ((__const__)) util_htobe64(uint64_t h64) { + return util_hton64(h64); +} + +/* Convert 64-bit number from host byte order to little endian byte order */ +extern inline uint64_t __attribute__ ((__const__)) util_htole64(uint64_t h64) { +#if UTIL_LITTLE_ENDIAN + return h64; + +#elif UTIL_BIG_ENDIAN + return (((h64 & 0xff00000000000000LL) >> 56) | + ((h64 & 0x00000000000000ffLL) << 56) | + ((h64 & 0x00ff000000000000LL) >> 40) | + ((h64 & 0x000000000000ff00LL) << 40) | + ((h64 & 0x0000ff0000000000LL) >> 24) | + ((h64 & 0x0000000000ff0000LL) << 24) | + ((h64 & 0x000000ff00000000LL) >> 8) | + ((h64 & 0x00000000ff000000LL) << 8)); +#endif +} + +/* Convert 64-bit number from big endian byte order to host byte order */ +extern inline uint64_t __attribute__ ((__const__)) util_betoh64(uint64_t be64) { + return util_ntoh64(be64); +} + +/* Convert 64-bit number from little endian byte order to host byte order */ +extern inline uint64_t __attribute__ ((__const__)) util_letoh64(uint64_t le64) { + return util_htole64(le64); +} + +/* Convert 16-bit number from host byte order to network byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_htons(uint16_t h16) { + return util_hton16(h16); +} + +/* Convert 16-bit number from network byte order to host byte order */ +extern inline uint16_t __attribute__ ((__const__)) util_ntohs(uint16_t n16) { + return util_ntoh16(n16); +} + +/* Convert 32-bit number from host byte order to network byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_htonl(uint32_t h32) { + return util_hton32(h32); +} + +/* Convert 32-bit number from network byte order to host byte order */ +extern inline uint32_t __attribute__ ((__const__)) util_ntohl(uint32_t n32) { + return util_ntoh32(n32); +} + +#define BYTEORDER_ARRAY(convert, from, to, count) { \ + for (unsigned int i = 0; i < count; ++i, ++from, ++to) { \ + *to = convert(*from); \ + } \ + } + +void util_hton16_array(const uint16_t * from, uint16_t * to, size_t count) +{ + BYTEORDER_ARRAY(util_hton16, from, to, count); +} + +void util_hton32_array(const uint32_t * from, uint32_t * to, size_t count) +{ + BYTEORDER_ARRAY(util_hton32, from, to, count); +} + +void util_hton64_array(const uint64_t * from, uint64_t * to, size_t count) +{ + BYTEORDER_ARRAY(util_hton64, from, to, count); +} + +void util_ntoh16_array(const uint16_t * from, uint16_t * to, size_t count) +{ + BYTEORDER_ARRAY(util_ntoh16, from, to, count); +} + +void util_ntoh32_array(const uint32_t * from, uint32_t * to, size_t count) +{ + BYTEORDER_ARRAY(util_ntoh32, from, to, count); +} + +void util_ntoh64_array(const uint64_t * from, uint64_t * to, size_t count) +{ + BYTEORDER_ARRAY(util_ntoh64, from, to, count); +} + +void util_htonflt_array(const float * from, float * to, size_t count) +{ + BYTEORDER_ARRAY(util_htonflt, from, to, count); +} + +void util_ntohflt_array(const float * from, float * to, size_t count) +{ + BYTEORDER_ARRAY(util_ntohflt, from, to, count); +} + +void util_htondbl_array(const double * from, double * to, size_t count) +{ + BYTEORDER_ARRAY(util_htondbl, from, to, count); +} + +void util_ntohdbl_array(const double * from, double * to, size_t count) +{ + BYTEORDER_ARRAY(util_ntohdbl, from, to, count); +} + +uint16_t gs_bswap_16(uint16_t value) +{ + return (uint16_t)(((value & 0xff00) >> 8) | + ((value & 0x00ff) << 8)); +} + +void gs_bswap_16_array(const uint16_t * from, uint16_t * to, size_t count) +{ + BYTEORDER_ARRAY(gs_bswap_16, from, to, count); +} + +uint32_t gs_bswap_32(uint32_t value) +{ + return (((value & 0xff000000) >> 24) | + ((value & 0x000000ff) << 24) | + ((value & 0x0000ff00) << 8) | + ((value & 0x00ff0000) >> 8)); +} + +void gs_bswap_32_array(const uint32_t * from, uint32_t * to, size_t count) +{ + BYTEORDER_ARRAY(gs_bswap_32, from, to, count); +} + +uint64_t gs_bswap_64(uint64_t value) +{ + return (((value & 0xff00000000000000LL) >> 56) | + ((value & 0x00000000000000ffLL) << 56) | + ((value & 0x00ff000000000000LL) >> 40) | + ((value & 0x000000000000ff00LL) << 40) | + ((value & 0x0000ff0000000000LL) >> 24) | + ((value & 0x0000000000ff0000LL) << 24) | + ((value & 0x000000ff00000000LL) >> 8) | + ((value & 0x00000000ff000000LL) << 8)); +} + +void gs_bswap_64_array(const uint64_t * from, uint64_t * to, size_t count) +{ + BYTEORDER_ARRAY(gs_bswap_64, from, to, count); +} + +float gs_bswap_float(float value) +{ + union v { + float f; + uint32_t i; + } val; + val.f = value; + val.i = gs_bswap_32(val.i); + return val.f; +} + +void gs_bswap_float_array(const float * from, float * to, size_t count) +{ + BYTEORDER_ARRAY(gs_bswap_float, from, to, count); +} diff --git a/gomspace/libutil/src/clock.c b/gomspace/libutil/src/clock.c new file mode 100644 index 00000000..ac215df6 --- /dev/null +++ b/gomspace/libutil/src/clock.c @@ -0,0 +1,113 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include + +#if !__AVR__ +#include +#endif + +gs_error_t gs_clock_to_iso8601_string2(uint32_t utc_sec, char * buf, size_t buf_size) +{ + if ((buf == NULL) || (buf_size == 0)) { + return GS_ERROR_ARG; + } + +#if __AVR__ + int res = snprintf(buf, buf_size, "%"PRIu32"Z", utc_sec); + if ((res < 0) || ((size_t)res >= buf_size)) { + buf[buf_size - 1] = 0; + return GS_ERROR_RANGE; + } +#else + const time_t time_seconds = (time_t) utc_sec; + struct tm tm_buf; + struct tm * tm = gmtime_r(&time_seconds, &tm_buf); + if (tm == NULL) { + int res = snprintf(buf, buf_size, "%ldZ", time_seconds); + if ((res < 0) || ((size_t)res >= buf_size)) { + buf[buf_size - 1] = 0; + } + return GS_ERROR_DATA; + } + + // ISO8601 timestamp: 2017-03-30T06:20:45Z + int res = snprintf(buf, buf_size, "%04d-%02d-%02dT%02d:%02d:%02dZ", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + if ((res < 0) || ((size_t)res >= buf_size)) { + buf[buf_size - 1] = 0; + return GS_ERROR_RANGE; + } +#endif + + return GS_OK; +} + +gs_error_t gs_clock_to_iso8601_string(const gs_timestamp_t * utc_time, char * buf, size_t buf_size) +{ + if (utc_time == NULL) { + return GS_ERROR_ARG; + } + + return gs_clock_to_iso8601_string2(utc_time->tv_sec, buf, buf_size); +} + +gs_error_t gs_clock_from_string(const char * str, gs_timestamp_t * ts) +{ + if (!str || !str[0] || !ts) { + return GS_ERROR_ARG; + } + + // check for . + { + uint32_t sec; + uint32_t nsec; + int res = sscanf(str, "%" SCNu32 ".%" SCNu32, &sec, &nsec); + if (res == 2) { + ts->tv_sec = sec; + ts->tv_nsec = nsec; + return GS_OK; + } + } + +#if !__AVR__ + // check for ISO8601 + { + struct tm tm; + memset(&tm, 0, sizeof(tm)); // no daylight saving + //int res = sscanf(str, "%" SCNd32 "-%" SCNd32 "-%" SCNd32 "T%" SCNd32 ":%" SCNd32 ":%" SCNd32 "Z", + int res = sscanf(str, "%d-%d-%dT%d:%d:%dZ", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec); + if ((res == 6) && + (tm.tm_year >= 1970) && (tm.tm_year <= 2038) && + (tm.tm_mon >= 1) && (tm.tm_mon <= 12) && + (tm.tm_mday >= 1) && (tm.tm_mday <= 31) && + (tm.tm_hour >= 0) && (tm.tm_hour <= 23) && + (tm.tm_min >= 0) && (tm.tm_min <= 59) && + (tm.tm_sec >= 0) && (tm.tm_sec <= 60)) + { + tm.tm_year -= 1900; + tm.tm_mon -= 1; + +#if __linux__ + // not posix compliant + time_t sec = timegm(&tm); +#else + // embedded platforms do not have timezones/daylight-saving - so standard mktime works + time_t sec = mktime(&tm); +#endif + if (sec >= 0) { + ts->tv_sec = (uint32_t) sec; + ts->tv_nsec = 0; + return GS_OK; + } + } + } +#endif + + return GS_ERROR_DATA; +} diff --git a/gomspace/libutil/src/crc32.c b/gomspace/libutil/src/crc32.c new file mode 100644 index 00000000..90d21832 --- /dev/null +++ b/gomspace/libutil/src/crc32.c @@ -0,0 +1,79 @@ +/* + * efone - Distributed internet phone system. + * + * (c) 1999,2000 Krzysztof Dabrowski + * (c) 1999,2000 ElysiuM deeZine + * + * This program 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 + * 2 of the License, or (at your option) any later version. + * + * Based on implementation by Finn Yannick Jacobs + */ + +#include +#include + +static const uint32_t crc_tab[256] GS_PGM_OBJECT = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +#define CALC_CRC32_STEP(crc,byte) (((crc >> 8) & 0x00FFFFFF) ^ GS_PGM_UINT32_BY_PTR(&crc_tab[(crc ^ byte) & (uint32_t) 0xFF])) + +uint32_t gs_crc32_init(void) +{ + return 0xFFFFFFFF; +} + +uint32_t gs_crc32_update(uint32_t crc, const void * block, size_t length) +{ + if (block && length) { + const uint8_t * u8 = block; + for (unsigned int i = 0; i < length; i++) { + crc = CALC_CRC32_STEP(crc, *u8++); + } + } + return crc; +} + +uint32_t gs_crc32_finalize(uint32_t crc) +{ + return (crc ^ 0xFFFFFFFF); +} + +uint32_t gs_crc32(const void * block, size_t length) +{ + return gs_crc32_finalize(gs_crc32_update(gs_crc32_init(), block, length)); +} diff --git a/gomspace/libutil/src/crc8.c b/gomspace/libutil/src/crc8.c new file mode 100644 index 00000000..aa810b31 --- /dev/null +++ b/gomspace/libutil/src/crc8.c @@ -0,0 +1,68 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +static const uint8_t crc_tab[256] GS_PGM_OBJECT = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, + 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, + 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, + 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, + 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, + 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, + 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, + 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, + 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, + 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, + 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, + 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, + 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, + 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, + 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, + 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, + 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, + 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 +}; + + +#define CALC_CRC8_STEP(crc,byte) ((crc >> 8) ^ GS_PGM_UINT8_BY_PTR(&crc_tab[(crc ^ byte) & (uint8_t) 0xFF])) + +uint8_t gs_crc8_init(void) +{ + return 0xFF; +} + +uint8_t gs_crc8_update(uint8_t crc, const void * block, size_t length) +{ + if (block && length) { + const uint8_t * u8 = block; + for (unsigned int i = 0; i < length; i++) { + crc = CALC_CRC8_STEP(crc, *u8++); + } + } + return crc; +} + +uint8_t gs_crc8_finalize(uint8_t crc) +{ + return (crc ^ 0x00); +} + +uint8_t gs_crc8(const void * block, size_t length) +{ + return gs_crc8_finalize(gs_crc8_update(gs_crc8_init(), block, length)); +} diff --git a/gomspace/libutil/src/drivers/can/can.c b/gomspace/libutil/src/drivers/can/can.c new file mode 100644 index 00000000..c08eaddb --- /dev/null +++ b/gomspace/libutil/src/drivers/can/can.c @@ -0,0 +1,6 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +// deifne common log group. +GS_LOG_GROUP(gs_can_log, "can", GS_LOG_CAT_DRIVER, GS_LOG_DEFAULT_MASK); diff --git a/gomspace/libutil/src/drivers/i2c/i2c.c b/gomspace/libutil/src/drivers/i2c/i2c.c new file mode 100644 index 00000000..acd9e60e --- /dev/null +++ b/gomspace/libutil/src/drivers/i2c/i2c.c @@ -0,0 +1,6 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +// define common log group. +GS_LOG_GROUP(gs_i2c_log, "i2c", GS_LOG_CAT_DRIVER, GS_LOG_DEFAULT_MASK); diff --git a/gomspace/libutil/src/drivers/spi/spi.c b/gomspace/libutil/src/drivers/spi/spi.c new file mode 100644 index 00000000..eea8153a --- /dev/null +++ b/gomspace/libutil/src/drivers/spi/spi.c @@ -0,0 +1,6 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +// define common log group. +GS_LOG_GROUP(gs_spi_log, "spi", GS_LOG_CAT_DRIVER, GS_LOG_DEFAULT_MASK); diff --git a/gomspace/libutil/src/drivers/sys/memory.c b/gomspace/libutil/src/drivers/sys/memory.c new file mode 100644 index 00000000..365dcf4a --- /dev/null +++ b/gomspace/libutil/src/drivers/sys/memory.c @@ -0,0 +1,37 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +static const char * long_to_string(char * buf, size_t buf_size, long lvalue) +{ + if (lvalue >= 0) { + snprintf(buf, buf_size, "%ld", lvalue); + return buf; + } + return "Unknown"; +} + +gs_error_t gs_mem_get_ram_stat(gs_mem_ram_type_t type, gs_mem_ram_stat_t * ram_stat) +{ + if (type == GS_MEM_RAM_TYPE_INTERNAL) { + return gs_mem_get_int_ram_stat(ram_stat); + } else if (type == GS_MEM_RAM_TYPE_EXTERNAL) { + return gs_mem_get_ext_ram_stat(ram_stat); + } + + /* Unsupported memory type */ + return GS_ERROR_NOT_SUPPORTED; +} + +gs_error_t gs_mem_print_ram_stat(gs_mem_ram_stat_t * ram_stat, FILE * out) +{ + GS_CHECK_ARG(ram_stat != NULL); + char buf[20]; + + fprintf(out, "Total: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->total)); + fprintf(out, "Max available: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->max_available)); + fprintf(out, "Min available: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->min_available)); + fprintf(out, "Available: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->available)); + return GS_OK; +} diff --git a/gomspace/libutil/src/error.c b/gomspace/libutil/src/error.c new file mode 100644 index 00000000..57e42abd --- /dev/null +++ b/gomspace/libutil/src/error.c @@ -0,0 +1,106 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#define GS_UTIL_DEPRECATED_ERROR_CODES 1 + +#include +#include +#include +#include + +#ifdef __AVR__ +const char * gs_error_string(int error) +{ + /** + avr: const strings are not automatically stored in program space (see gs/util/pgm.h), and if stored + in program space, they require special formatting in logs (i.e. "%S"). + So we settle for simple error string, with the error nnumber - no need to change log/(s)printf etc. + @note: solution is not 100% thread/task safe. + */ + static char buffer[15]; // large enough to always keep zero termination, due to no thread/task lock + snprintf(buffer, sizeof(buffer), "%d", error); + return buffer; +} +#else +const char * gs_error_string(int error) +{ + switch (error) { + case GS_OK: return "GS_OK(0)"; + case GS_ERROR_PERM: return GS_DEF2STRING(GS_ERROR_PERM) "(-1)"; + case GS_ERROR_INTR: return GS_DEF2STRING(GS_ERROR_INTR) "(-4)"; + case GS_ERROR_IO: return GS_DEF2STRING(GS_ERROR_IO) "(-5)"; + case GS_ERROR_AGAIN: return GS_DEF2STRING(GS_ERROR_AGAIN) "(-11)"; + case GS_ERROR_ALLOC: return GS_DEF2STRING(GS_ERROR_ALLOC) "(-12)"; + case GS_ERROR_ACCESS: return GS_DEF2STRING(GS_ERROR_ACCESS) "(-13)"; + case GS_ERROR_BUSY: return GS_DEF2STRING(GS_ERROR_BUSY) "(-16)"; + case GS_ERROR_EXIST: return GS_DEF2STRING(GS_ERROR_EXIST) "(-17)"; + case GS_ERROR_ARG: return GS_DEF2STRING(GS_ERROR_ARG) "(-22)"; + case GS_ERROR_NOT_IMPLEMENTED: return GS_DEF2STRING(GS_ERROR_NOT_IMPLEMENTED) "(-38)"; + case GS_ERROR_OVERFLOW: return GS_DEF2STRING(GS_ERROR_OVERFLOW) "(-75)"; + case GS_ERROR_NOT_SUPPORTED: return GS_DEF2STRING(GS_ERROR_NOT_SUPPORTED) "(-95)"; + case GS_ERROR_IN_USE: return GS_DEF2STRING(GS_ERROR_IN_USE) "(-98)"; + case GS_ERROR_CONNECTION_RESET: return GS_DEF2STRING(GS_ERROR_CONNECTION_RESET) "(-104)"; + case GS_ERROR_NO_BUFFERS: return GS_DEF2STRING(GS_ERROR_NO_BUFFERS) "(-105)"; + case GS_ERROR_TIMEOUT: return GS_DEF2STRING(GS_ERROR_TIMEOUT) "(-110)"; + case GS_ERROR_ALREADY_IN_PROGRESS: return GS_DEF2STRING(GS_ERROR_ALREADY_IN_PROGRESS) "(-114)"; + + case GS_ERROR_HANDLE: return GS_DEF2STRING(GS_ERROR_HANDLE) "(-2000)"; + case GS_ERROR_NOT_FOUND: return GS_DEF2STRING(GS_ERROR_NOT_FOUND) "(-2001)"; + case GS_ERROR_FULL: return GS_DEF2STRING(GS_ERROR_FULL) "(-2002)"; + case GS_ERROR_RANGE: return GS_DEF2STRING(GS_ERROR_RANGE) "(-2003)"; + case GS_ERROR_DATA: return GS_DEF2STRING(GS_ERROR_DATA) "(-2004)"; + case GS_ERROR_UNKNOWN: return GS_DEF2STRING(GS_ERROR_UNKNOWN) "(-2005)"; + case GS_ERROR_NO_DATA: return GS_DEF2STRING(GS_ERROR_NO_DATA) "(-2006)"; + case GS_ERROR_STALE: return GS_DEF2STRING(GS_ERROR_STALE) "(-2007)"; + case GS_ERROR_TYPE: return GS_DEF2STRING(GS_ERROR_TYPE) "(-2008)"; + case GS_ERROR_AMBIGUOUS: return GS_DEF2STRING(GS_ERROR_AMBIGUOUS) "(-2009)"; + case GS_ERROR_STATE: return GS_DEF2STRING(GS_ERROR_STATE) "(-2010)"; + } + + // as fallback we use standard POSIX error string + const int posix_error = abs(error); + return strerror(posix_error); +} +#endif + +gs_error_t gs_error(int error) +{ + return (abs(error) * -1); +} + +#ifndef __AVR__ +const char * error_string(int code) +{ + switch (code) { + case E_NO_ERR: + return "No error"; + case E_NO_DEVICE: + return "No device"; + case E_MALLOC_FAIL: + return "Malloc fail"; + case E_THREAD_FAIL: + return "Thread failure"; + case E_NO_QUEUE: + return "No such queue"; + case E_INVALID_BUF_SIZE: + return "Invalid buffer size"; + case E_INVALID_PARAM: + return "Invalid paramater"; + case E_NO_SS: + return "No such subsystem"; + case E_GARBLED_BUFFER: + return "Rubbish in buffer"; + case E_FLASH_ERROR: + return "FLASH error"; + case E_BOOT_SER: + return "Thread boot fail: serial driver"; + case E_BOOT_DEBUG: + return "Thread boot fail: debug console"; + case E_BOOT_FLASH: + return "Thread boot fail: flash driver"; + case E_NO_BUFFER: + return "No buffer"; + default: + return "Unknown error"; + } +} +#endif diff --git a/gomspace/libutil/src/fletcher.c b/gomspace/libutil/src/fletcher.c new file mode 100644 index 00000000..a9dab265 --- /dev/null +++ b/gomspace/libutil/src/fletcher.c @@ -0,0 +1,77 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +uint16_t gs_fletcher16_memcpy(const void * data_in, size_t count, void * (*memcpyfcn)(void *, const void *, size_t)) +{ + if (memcpyfcn == NULL) { + memcpyfcn = &memcpy; + } + + uint16_t sum1 = 0; + uint16_t sum2 = 0; + + if (data_in && count) { + const uint8_t * data = data_in; + for (unsigned int idx = 0; idx < count; ++idx) { + uint8_t byte; + (*memcpyfcn)(&byte, &data[idx], 1); + sum1 = (uint16_t)((sum1 + byte) % 255); + sum2 = (uint16_t)((sum2 + sum1) % 255); + } + } + return (uint16_t)((sum2 << 8) | sum1); +} + +uint16_t gs_fletcher16_P(const void * data_in, size_t count) +{ + uint16_t sum1 = 0; + uint16_t sum2 = 0; + + if (data_in && count) { + const uint8_t * data = data_in; + for (unsigned int idx = 0; idx < count; ++idx) { + sum1 = (uint16_t)((sum1 + GS_PGM_UINT8_BY_PTR(data++)) % 255); + sum2 = (uint16_t)((sum2 + sum1) % 255); + } + } + return (uint16_t)((sum2 << 8) | sum1); +} + +uint16_t gs_fletcher16(const void * data_in, size_t size) +{ + uint16_t sum1 = 0; + uint16_t sum2 = 0; + + if (data_in && size) { + const uint8_t * data = data_in; + for (unsigned int idx = 0; idx < size; ++idx) { + sum1 = (uint16_t)((sum1 + (*data++)) % 255); + sum2 = (uint16_t)((sum2 + sum1) % 255); + } + } + return (uint16_t)((sum2 << 8) | sum1); +} + +void gs_fletcher16_init(gs_fletcher16_t * f16) +{ + f16->sum1 = f16->sum2 = 0; +} + +void gs_fletcher16_update(gs_fletcher16_t * f16, const void * data_in, size_t size) +{ + if (f16 && data_in && size) { + const uint8_t * data = data_in; + for (unsigned int idx = 0; idx < size; ++idx) { + f16->sum1 = (uint16_t)((f16->sum1 + (*data++)) % 255); + f16->sum2 = (uint16_t)((f16->sum2 + f16->sum1) % 255); + } + } +} + +uint16_t gs_fletcher16_finalize(gs_fletcher16_t * f16) +{ + return (uint16_t)((f16->sum2 << 8) | f16->sum1); +} diff --git a/gomspace/libutil/src/function_scheduler.c b/gomspace/libutil/src/function_scheduler.c new file mode 100644 index 00000000..a89c8db2 --- /dev/null +++ b/gomspace/libutil/src/function_scheduler.c @@ -0,0 +1,111 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include + +#include +#include +#include +#include +#include +#include + +typedef struct { + // function to call + gs_function_scheduler_function_t function; + // function's user data + void * user_data; + // timeout in mS + uint32_t timeout_ms; + // last execution time in mS + uint32_t last_exec_ms; +} gs_function_scheduler_entry_t; + +struct gs_function_scheduler { + // Max timeout in mS + uint32_t max_timeout_ms; + // allocated entries + unsigned int max_entries; + // entries + gs_function_scheduler_entry_t * entries; +}; + +GS_CHECK_STATIC_ASSERT(sizeof(int) >= 2, int_must_be_at_least_16bit); + +gs_error_t gs_function_scheduler_create(uint32_t max_timeout_ms, unsigned int max_entries, gs_function_scheduler_t ** return_scheduler) +{ + GS_CHECK_ARG(max_timeout_ms <= INT_MAX); + GS_CHECK_ARG(max_entries > 0); + GS_CHECK_ARG(return_scheduler != NULL); + + gs_function_scheduler_entry_t * entries = calloc(max_entries, sizeof(*entries)); + if (entries == NULL) { + return GS_ERROR_ALLOC; + } + + gs_function_scheduler_t * scheduler = calloc(1, sizeof(*scheduler)); + if (scheduler == NULL) { + free (entries); + return GS_ERROR_ALLOC; + } + + scheduler->max_timeout_ms = max_timeout_ms; + scheduler->entries = entries; + scheduler->max_entries = max_entries; + + *return_scheduler = scheduler; + + return GS_OK; +} + +gs_error_t gs_function_scheduler_destroy(gs_function_scheduler_t * scheduler) +{ + GS_CHECK_HANDLE(scheduler); + free(scheduler->entries); + free(scheduler); + return GS_OK; +} + +gs_error_t gs_function_scheduler_register_ms(gs_function_scheduler_t * scheduler, + uint32_t first_timeout_ms, gs_function_scheduler_function_t func, void * user_data) +{ + GS_CHECK_HANDLE(scheduler != NULL); + GS_CHECK_ARG(func != NULL); + + gs_function_scheduler_entry_t * entry = scheduler->entries; + for (unsigned int i = 0; i < scheduler->max_entries; ++i, ++entry) { + if (entry->function == NULL) { + entry->function = func; + entry->user_data = user_data; + entry->timeout_ms = first_timeout_ms; + entry->last_exec_ms = gs_time_rel_ms(); + return GS_OK; + } + } + + return GS_ERROR_FULL; +} + +int gs_function_scheduler_execute_ms(gs_function_scheduler_t * scheduler) +{ + uint32_t timeout_ms = 5000; // max timeout to ensure gs_time_rel_ms() works correctly (wrapping more than once is bad) + + if (scheduler) { + timeout_ms = scheduler->max_timeout_ms; + uint32_t now_ms = gs_time_rel_ms(); + + gs_function_scheduler_entry_t * entry = scheduler->entries; + for (unsigned int i = 0; i < scheduler->max_entries; ++i, ++entry) { + if (entry->function) { + uint32_t elapsed = gs_time_diff_ms(entry->last_exec_ms, now_ms); + if (elapsed >= entry->timeout_ms) { + entry->timeout_ms = (entry->function)(entry->user_data); + entry->last_exec_ms = now_ms = gs_time_rel_ms(); + elapsed = 0; + } + timeout_ms = gs_min(timeout_ms, (entry->timeout_ms - elapsed)); + } + } + } + + return (int)((timeout_ms < INT_MAX) ? timeout_ms : INT_MAX); +} diff --git a/gomspace/libutil/src/gosh/command.c b/gomspace/libutil/src/gosh/command.c new file mode 100644 index 00000000..b68d6c82 --- /dev/null +++ b/gomspace/libutil/src/gosh/command.c @@ -0,0 +1,754 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include "command_local.h" + +#include +#include + +#include // register commands +#include // register commands +#include +#include +#include "../lock.h" + +#define MAX_ARGC 30 + +#ifdef __AVR__ +#include +#define cmd_strcmp strcmp_P +#define cmd_strncmp strncmp_P +#define cmd_strlen strlen_P +#define cmd_strcpy strcpy_P +#define cmd_read_ptr(ptr) ((void *) pgm_read_word(ptr)) +#define cmd_read_int(ptr) pgm_read_word(ptr) +#else +#define cmd_strcmp strcmp +#define cmd_strncmp strncmp +#define cmd_strlen strlen +#define cmd_strcpy strcpy +#define cmd_read_ptr(ptr) *ptr +#define cmd_read_int(ptr) *ptr +#endif + +// define common command log group. +static GS_LOG_GROUP(gs_command_log, "command", GS_LOG_CAT_COMMAND, LOG_DEFAULT_MASK | LOG_INFO_MASK); +#define LOG_DEFAULT gs_command_log + +/** + Compile check that size of gs_command_t is multiplum of 4. +*/ +GS_STATIC_ASSERT((sizeof(gs_command_t) % 4) == 0, gs_command_t_is_not_a_multiplum_of_4); + +// Private context +typedef struct process_context { + // command context - must be first, as it is used to access private context (same address) + gs_command_context_t context; + // process function + gs_error_t (*process)(const gs_command_t * const cmds, int cmd_count, int arg_offset, struct process_context * pc); + // command error + gs_error_t error; + // only exact match (space after last argument) + bool requires_exact_match; + // first command match + const gs_command_t * cmd; + // number of hits when hunting commands, completion etc. + unsigned int hits; + // complete result + struct { + char * line; + size_t token_start; + } complete; +} private_context_t; + +// command block +typedef struct gs_command_block { + //! Pointer to command block. + const gs_command_t * commands; + //! Number of commands in command block. + size_t count; + //! Reference to next command block. + struct gs_command_block * next; +} gs_command_block_t; + +// commands +static gs_command_block_t g_commands; + +// minimum stack size in bytes. +static size_t g_stack_size; + +// command logger callback +static gs_command_log_t g_command_logger = NULL; +static void * g_command_logger_ctx = NULL; + +static gs_error_t command_stdio_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value) +{ + static const char* printed_group_header = NULL; + /* Print Group header if Group string is non-empty */ + if ((group != NULL) && (group[0] != '\0')) { + if (printed_group_header != group) { + fprintf(ctx->out, "%s:\r\n", group); + printed_group_header = group; + } + } + /* Print ": " if key string is non-empty */ + if (key != NULL) { + if (key[0] != '\0') { + if ((group != NULL) && (group[0] != '\0')) { + fprintf(ctx->out, " %s: ", key); + } else { + fprintf(ctx->out, "%s: ", key); + } + } + } + fprintf(ctx->out, "%s\r\n", value); + return GS_OK; +} + +gs_error_t gs_command_stdio_flush(gs_command_context_t *ctx) +{ + fflush(ctx->out); + return GS_OK; +} + +gs_error_t gs_command_stdio_wait_for_key(gs_command_context_t *ctx, int *ch, int timeout_ms) +{ + return gs_stdio_getchar_timed(timeout_ms, ch); +} + +static const gs_command_io_functions_t stdio_functions = { + .set_result = command_stdio_set_result, + .flush = gs_command_stdio_flush, + .wait_for_key = gs_command_stdio_wait_for_key +}; + +const char * gs_command_args(gs_command_context_t *ctx) +{ + if (ctx->argc > 1) { + // find first matching argument (= starts with) - this is not 100% and doesn't handle arguments with spaces (quoted) + const char * arg = ctx->command_line; + while (arg && arg[0]) { + if (strncmp(arg, ctx->argv[1], strlen(ctx->argv[1])) == 0) { + return arg; + } + // skip argument + for (; *arg && (*arg != ' '); ++arg); + // skip spaces + // cppcheck-suppress redundantCondition + for (; *arg && (*arg == ' '); ++arg); + } + } + return ""; +} + +bool gs_command_build_argv(char *line, int *argc, char **argv, int max_argc) +{ + // Skip spaces + for (; line && *line && isspace((unsigned int)*line); ++line); + + *argc = 0; + argv[*argc] = line; + + char quote = 0; + + while (*line) { + // check for quote's: ' or " + if ((*line == '\'') || (*line == '\"')) { + if (quote == 0) { + quote = *line; + argv[*argc]++; + } else if (quote == *line) { + quote = 0; + *line = '\0'; + } + } + // check for whitespace and no quotes active + else if (isspace((unsigned int)*line) && quote == 0) { + /* Delete space */ + *line++ = '\0'; + + // skip spaces + for (; *line && isspace((unsigned int)*line); ++line); + + /* If there is more data, we have another argument */ + if (*line) { + (*argc)++; + if (*argc >= max_argc) { + return false; + } + argv[*argc] = line; + } + + continue; + } + + line++; + } + + (*argc)++; + if (*argc >= max_argc) { + return false; + } + + // According to C11 section 5.1.2.2.1, argv[argc] must be NULL + argv[*argc] = NULL; + + // Check for invalid number of quotes + return (quote == 0) ? true : false; +} + +static inline gs_error_t command_logger(const char *cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t ts, gs_timestamp_t te) +{ + gs_lock_lock(); + gs_command_log_t logger = g_command_logger; + void * log_ctx = g_command_logger_ctx; + gs_lock_unlock(); + + if (logger) { + return logger(cmd_line, ret, cmd_ret, ts, te, log_ctx); + } + return GS_OK; +} + +static gs_error_t command_execute(const gs_command_t * const cmds, int cmd_count, int arg_offset, private_context_t * pc) +{ + for (int i = 0; i < cmd_count; i++) { + const gs_command_t * cmd = &cmds[i]; + + if (cmd_strcmp(pc->context.argv[arg_offset], cmd->name) == 0) { + // check for sub-commands + const gs_command_t * list = (void*) cmd_read_ptr(&cmd->chain.list); + if (list) { + ++arg_offset; + if (arg_offset >= pc->context.argc) { + return GS_ERROR_TYPE; + } + return command_execute(list, cmd_read_int(&cmd->chain.count), arg_offset, pc); + } + + gs_command_handler_t handler = (void *) cmd_read_ptr(&cmd->handler); + if (handler == NULL) { + return GS_ERROR_NOT_IMPLEMENTED; + } + + pc->context.argc -= arg_offset; + pc->context.argv = &pc->context.argv[arg_offset]; + pc->context.command = cmd; + + // check arguments - if specified + if (cmd->mandatory_args || cmd->optional_args) { + const int min_args = (cmd->mandatory_args == GS_COMMAND_NO_ARGS) ? 0 : cmd->mandatory_args; + const int args = (pc->context.argc - 1); + if (args < min_args) { + return GS_ERROR_ARG; + } + if (args > (min_args + cmd->optional_args)) { + return GS_ERROR_ARG; + } + } + + pc->error = handler(&pc->context); + return GS_OK; // command was excecuted + } + } + + return GS_ERROR_NOT_FOUND; +} + +static gs_error_t command_process(private_context_t * pc) +{ + const char * command = gs_string_skip_leading_spaces(pc->context.command_line); + + // Make copy of string, because command parser mangles destroys it + const size_t command_len = strlen(command); + char command_copy[command_len + 1]; + strcpy(command_copy, command); + + if (command_len && command[command_len-1] == ' ') { + pc->requires_exact_match = true; + } + + pc->context.optsp = 1; + pc->context.optind = 1; + pc->context.optopt = '?'; + pc->context.command_line = command; + + // split into arguments + char *argv[MAX_ARGC + 1]; + if (gs_command_build_argv(command_copy, &pc->context.argc, argv, MAX_ARGC + 1) == false) { + return GS_ERROR_ARG; + } + pc->context.argv = argv; + + gs_error_t error = GS_ERROR_NOT_FOUND; + for (const gs_command_block_t * block = &g_commands; block && (error == GS_ERROR_NOT_FOUND); block = block->next) { + if (block->commands) { + error = (pc->process)(block->commands, block->count, 0, pc); + } + } + + return error; +} + +gs_error_t gs_command_run(const char * command, gs_error_t * return_command_result) +{ + return gs_command_execute_stdio(command, return_command_result); +} + +gs_error_t gs_command_execute_stdio(const char * command, gs_error_t * return_command_result) +{ + return gs_command_execute(command, return_command_result, stdout, &stdio_functions, NULL); +} + +gs_error_t gs_command_execute(const char * command, gs_error_t * return_command_result, FILE *out, + const gs_command_io_functions_t *iof, void *iof_ctx) +{ + command = gs_string_skip_leading_spaces(command); + GS_CHECK_ARG(gs_string_empty(command) == false); + + private_context_t pc = { + .process = command_execute, + .error = GS_OK, + .context = { + .command_line = command, + .out = out, + .io_functions = iof, + .io_ctx = iof_ctx, + } + }; + gs_timestamp_t tm_start, tm_end; + gs_clock_get_time(&tm_start); + gs_error_t error = command_process(&pc); + gs_clock_get_time(&tm_end); + command_logger(pc.context.command_line, error, pc.error, tm_start, tm_end); + if ((error == GS_OK) && return_command_result) { + *return_command_result = pc.error; + } + return error; +} + +gs_error_t gs_command_set_output(gs_command_context_t *ctx, const char* group, const char* key, const char* value) +{ + GS_CHECK_ARG(ctx); + + if (ctx->io_functions && ctx->io_functions->set_result) { + return ctx->io_functions->set_result(ctx, group, key, value); + } + + /* If no IO-function set - ignore the data and send Success */ + return GS_OK; +} + +gs_error_t gs_command_set_output_printf(gs_command_context_t *ctx, const char* group, const char* key, const char * format, ...) +{ + GS_CHECK_ARG(ctx); + + if (ctx->io_functions && ctx->io_functions->set_result) + { + va_list args; + va_start(args, format); + char value[256]; + int size = vsnprintf(value, sizeof(value), format, args); + va_end(args); + + /* Don't allow to set truncated results - Return error in this case */ + if (size >= (int)sizeof(value)) { + return GS_ERROR_ALLOC; + } + + return ctx->io_functions->set_result(ctx, group, key, value); + } + + /* If no IO-function set - ignore the data and send Success */ + return GS_OK; +} + +gs_error_t gs_command_flush_output(gs_command_context_t *ctx) +{ + GS_CHECK_ARG(ctx); + + if (ctx->io_functions && ctx->io_functions->flush) { + return ctx->io_functions->flush(ctx); + } + + /* If no IO-function set - ignore the data and send Success */ + return GS_OK; +} + +bool gs_command_wait_any_key(gs_command_context_t *ctx, int timeout_ms) +{ + int ch; + gs_error_t ret = gs_command_wait_key(ctx, &ch, timeout_ms); + + if (ret == GS_ERROR_TIMEOUT) { + return false; + } + + /* Ensure that a commands handler will not stall if IO function if not available etc. + False will only be returned in case of a positive timeout */ + return true; +} + +gs_error_t gs_command_wait_key(gs_command_context_t *ctx, int* ch, int timeout_ms) +{ + if (ctx && ctx->io_functions && ctx->io_functions->wait_for_key) + { + return ctx->io_functions->wait_for_key(ctx, ch, timeout_ms); + } + + /* If no IO-function set set return GS_ERROR_HANDLE */ + return GS_ERROR_HANDLE; +} + +unsigned int gs_command_completer_add_token(gs_command_context_t * ctx, const char * token, bool exact) +{ + private_context_t * pc = (private_context_t *) ctx; + char * line = &pc->complete.line[pc->complete.token_start]; + + if (token == NULL) { + // mark any pending partial token as exact + if ((line[0] == 0) || (pc->hits != 1)) { + return pc->hits; + } + exact = true; + } + + if (exact) { + if (token) { + strcpy(line, token); + } + strcat(line, " "); + pc->complete.token_start = strlen(pc->complete.line); + pc->hits = 1; + } else { + if (pc->hits == 0) { + strcpy(line, token); + } else { + for (; *line && *token && (*line == *token); ++line, ++token); + *line = 0; + } + ++pc->hits; + } + + return pc->hits; +} + +static unsigned int command_complete_add(private_context_t * pc, const gs_command_t * cmd, bool exact) +{ + if (cmd) { + pc->cmd = cmd; + return gs_command_completer_add_token(&pc->context, cmd->name, exact); + } else { + return gs_command_completer_add_token(&pc->context, NULL, exact); + } +} + +static gs_error_t command_complete(const gs_command_t * const cmds, int cmd_count, int arg_offset, private_context_t * pc) +{ + if (arg_offset > 0) { + // command we are looking for must be in this block + pc->hits = 0; + } + pc->cmd = NULL; + bool exact_match = false; + + for (int i = 0; i < cmd_count; i++) { + const gs_command_t * cmd = &cmds[i]; + + if (cmd_read_int(&cmd->mode) & GS_COMMAND_FLAG_HIDDEN) { + continue; + } + + if (gs_string_empty(pc->context.argv[arg_offset])) { + // exceeding known token(s) - partial match + command_complete_add(pc, cmd, false); + continue; + } + + if (pc->requires_exact_match || ((arg_offset+1) < pc->context.argc)) { + // must be an exact match + if (cmd_strcmp(pc->context.argv[arg_offset], cmd->name) == 0) { + command_complete_add(pc, cmd, true); + exact_match = true; + break; + } + } else if (cmd_strncmp(pc->context.argv[arg_offset], cmd->name, + strlen(pc->context.argv[arg_offset])) == 0) { + // partial match + command_complete_add(pc, cmd, false); + } + } + + if (exact_match || ((arg_offset > 0) && (pc->hits == 1))) { + command_complete_add(pc, NULL, true); + + if (strlen(pc->complete.line) > strlen(pc->context.command_line)) { + return GS_OK; + } + + if (pc->cmd->chain.list) { + return command_complete(pc->cmd->chain.list, pc->cmd->chain.count, arg_offset+1, pc); + } + + // command arguments + pc->context.argc -= arg_offset; + pc->context.argv = &pc->context.argv[arg_offset]; + pc->context.command = pc->cmd; + + // add the "already" completed ones + int arg_to_complete = 1; + for (; arg_to_complete < (pc->context.argc - 1); ++arg_to_complete) { + gs_command_completer_add_token(&pc->context, pc->context.argv[arg_to_complete], true); + } + // add the last - if its completed (space after) + if ((arg_to_complete < pc->context.argc) && pc->requires_exact_match) { + // cppcheck-suppress unreadVariable - not used on __AVR__ because it doesn't support 'completer' + gs_command_completer_add_token(&pc->context, pc->context.argv[arg_to_complete], true); + ++arg_to_complete; + } + +#if (__AVR__ == 0) + if (pc->cmd->completer) { + pc->hits = 0; + (pc->cmd->completer)(&pc->context, arg_to_complete); + } else +#endif + { + pc->hits = 1; // no completer - assume single hit + } + + return GS_OK; // only used for breaking loop + } + + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_command_complete(char *line, size_t max_line_length, FILE* out) +{ + const size_t line_len = strlen(line); + char buffer[max_line_length]; + buffer[0] = 0; + private_context_t pc = { + .process = command_complete, + .context = { + .command_line = line, + .out = out, + }, + .complete = { + .line = buffer, + }, + }; + command_process(&pc); + gs_command_completer_add_token(&pc.context, NULL, true); + if (strlen(buffer) > line_len ) { + strcpy(line, buffer); + } + switch (pc.hits) { + case 0: + return GS_ERROR_NOT_FOUND; + case 1: + return GS_OK; + default: + return GS_ERROR_AMBIGUOUS; + } +} + +static void command_help_print(const gs_command_t * const cmd, private_context_t * pc) +{ + if (pc->hits == 1) { + if (cmd->help) { + fprintf(pc->context.out, "%s\r\n", cmd->help); + } + if (cmd->chain.count == 0) { + fprintf(pc->context.out, "usage: %s %s\r\n", cmd->name, cmd->usage ? cmd->usage : ""); + } else { + for (unsigned int i = 0; i < cmd->chain.count; ++i) { + const gs_command_t * scmd = &cmd->chain.list[i]; + + if (scmd->mode & GS_COMMAND_FLAG_HIDDEN) { + continue; + } + fprintf(pc->context.out, " %-19s %s\r\n", scmd->name, scmd->help ? scmd->help : ""); + } + } + } else { + fprintf(pc->context.out, " %-19s %s\r\n", cmd->name, cmd->help ? cmd->help : ""); + } +} + +static void command_help_hit(const gs_command_t * const cmd, private_context_t * pc) +{ + pc->error = GS_OK; + ++pc->hits; + if (pc->hits == 1) { + // single hit so far - hold off printing until we know if we get more + pc->cmd = cmd; + } else { + if (pc->cmd) { + command_help_print(pc->cmd, pc); + pc->cmd = NULL; + } + command_help_print(cmd, pc); + } +} + +static gs_error_t command_help(const gs_command_t * const cmds, int cmd_count, int arg_offset, private_context_t * pc) +{ + for (int i = 0; i < cmd_count; i++) { + const gs_command_t * cmd = &cmds[i]; + + if (cmd_read_int(&cmd->mode) & GS_COMMAND_FLAG_HIDDEN) { + continue; + } + + if (pc->requires_exact_match || ((arg_offset+1) < pc->context.argc)) { + // must be an exact match + if (cmd_strcmp(pc->context.argv[arg_offset], cmd->name) == 0) { + const gs_command_t * list = (void*) cmd_read_ptr(&cmd->chain.list); + if (list && ((arg_offset+1) < pc->context.argc)) { + return command_help(list, cmd_read_int(&cmd->chain.count), arg_offset+1, pc); + } + command_help_hit(cmd, pc); + } + + } else if (cmd_strncmp(pc->context.argv[arg_offset], cmd->name, + strlen(pc->context.argv[arg_offset])) == 0) { + command_help_hit(cmd, pc); + } + } + + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_command_show_help(const char * command, FILE* out) +{ + private_context_t pc = { + .process = command_help, + .error = GS_ERROR_NOT_FOUND, + .context = { + .command_line = command, + .out = out, + } + }; + gs_error_t error = command_process(&pc); + if (pc.cmd) { + command_help_print(pc.cmd, &pc); + error = GS_OK; + } else if ((error == GS_ERROR_NOT_FOUND) && pc.hits) { + error = GS_OK; + } + return error; +} + +gs_error_t gs_command_register(const gs_command_t * commands, size_t count) +{ + GS_CHECK_ARG(commands != NULL); + GS_CHECK_ARG(count > 0); + + gs_error_t error = GS_OK; + + gs_lock_lock(); + { + // check if command block already installed + gs_command_block_t * last_block = NULL; + for (gs_command_block_t * block = &g_commands; block; block = block->next) { + if (block->commands) { + const gs_command_t * cmd = block->commands; + // loop through because it may be in the linked blocks + for (size_t i = 0; i < block->count; ++i, ++cmd) { + if (cmd == commands) { + error = GS_ERROR_EXIST; + break; + } + } + } + last_block = block; + } + + if (error == GS_OK) { + gs_command_block_t * block = calloc(1, sizeof(*block)); + if (block) { + // Insert command last, so lock isn't needed when accessing commands + block->commands = commands; + block->count = count; + block->next = NULL; + last_block->next = block; + } else { + error = GS_ERROR_ALLOC; + } + } + } + gs_lock_unlock(); + + return (error != GS_ERROR_EXIST) ? error : GS_OK; +} + +size_t gs_command_get_stack_size(void) +{ + return g_stack_size; +} + +gs_error_t gs_command_init_no_commands(size_t stack_size) +{ + g_stack_size = stack_size; + + gs_error_t error = gs_lock_init(); + if (error) { + return error; + } + + gs_log_group_register(gs_command_log); + +#if (__linux__ == 0) + // look up static linked commands - only embedded (= none linux) systems + gs_command_block_t * block = &g_commands; + extern volatile unsigned int __command_start __attribute__ ((__weak__)); + extern volatile unsigned int __command_end __attribute__ ((__weak__)); + if (&__command_start) { + block->count = ((ptrdiff_t)&__command_end - (ptrdiff_t)&__command_start) / sizeof(gs_command_t); + block->commands = (gs_command_t *) &__command_start; + } +#endif + + return GS_OK; +} + +gs_error_t gs_command_init(size_t stack_size) +{ + gs_error_t error = gs_command_init_no_commands(stack_size); + if (error == GS_OK) { + // register default commands + gs_command_register_default_commands(); + gs_log_register_commands(); + } + return error; +} + +gs_error_t gs_command_logger_default(const char* cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t t_start, gs_timestamp_t t_end, void *log_ctx) +{ + (void)log_ctx; + + timestamp_diff(&t_end, &t_start); + if (ret == GS_OK) { + log_info_group(gs_command_log, "'%s' returned '%s' [" + "t: <%04"PRIu32".%06"PRIu32">, dt: <%01"PRIu32".%06"PRIu32">]", + cmd_line, gs_error_string(cmd_ret), + t_start.tv_sec, t_start.tv_nsec/1000, t_end.tv_sec, t_end.tv_nsec/1000); + } else { + log_info_group(gs_command_log, "'%s' could not be run, returned '%s' [" + "t: <%04"PRIu32".%06"PRIu32">]", + cmd_line, gs_error_string(ret), + t_start.tv_sec, t_start.tv_nsec/1000); + } + return GS_OK; +} + +gs_error_t gs_command_register_logger(gs_command_log_t log_cb, void *log_ctx) +{ + gs_lock_lock(); + g_command_logger = log_cb; + g_command_logger_ctx = log_ctx; + gs_lock_unlock(); + + return GS_OK; +} + diff --git a/gomspace/libutil/src/gosh/command_local.h b/gomspace/libutil/src/gosh/command_local.h new file mode 100644 index 00000000..69f715e1 --- /dev/null +++ b/gomspace/libutil/src/gosh/command_local.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +/** + Command I/O function - flush stdout. +*/ +gs_error_t gs_command_stdio_flush(gs_command_context_t *ctx); + +/** + Command I/O function - wait for a key. +*/ +gs_error_t gs_command_stdio_wait_for_key(gs_command_context_t *ctx, int *ch, int timeout_ms); + +/** + Complete command. + @param[in] line command line to complete + @param[in] max \a length (size) + @param[in] out output stream, e.g. stdout +*/ +gs_error_t gs_command_complete(char *line, size_t max_line_length, FILE* out); + +/** + Show help. + @param line command line to show help for. + @param out output stream, e.g. stdout +*/ +gs_error_t gs_command_show_help(const char * command, FILE * out); + +/** + Change console mode. + @param[in] mode console mode, 'cci' + @return_gs_error_t +*/ +int gs_console_change_mode(const char * mode); diff --git a/gomspace/libutil/src/gosh/console.c b/gomspace/libutil/src/gosh/console.c new file mode 100644 index 00000000..99b04aac --- /dev/null +++ b/gomspace/libutil/src/gosh/console.c @@ -0,0 +1,758 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + The console interface provides support for executing commands over stdout (typically a serial port). + + The connection can run in 2 modes: + - normal, standard GOSH interface (Human Machine Interface), echo characters, prompt, etc. + - cci, Computer Computer Interface. Simple text interface, but with tagged output format - easier to parse by a computer. +*/ +#include "console_local.h" +#include "command_local.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include // console defines set through Waf options + +#if (__linux__) +#include +#include +#include +#include +#endif + +/* Max history length (elements) */ +#ifndef GS_CONSOLE_HISTORY_LEN +#define GS_CONSOLE_HISTORY_LEN 10 +#endif + +/* Max input length */ +#ifndef GS_CONSOLE_INPUT_LEN +#define GS_CONSOLE_INPUT_LEN 100 +#endif + +#define CONTROL(X) ((X) - '@') + +typedef enum { + CONSOLE_NORMAL = 0, + CONSOLE_ESCAPE = 1, + CONSOLE_PRE_ESCAPE = 2, +} console_escape_t; + +static const char hash_prompt[] = "\033[1;30m # "; + +static const char backspace_char = '\b'; +static const char space_char = ' '; +static const char cr_char = '\r'; +static const char nl_char = '\n'; + +static const char * user_prompt = "gosh"; + +static console_escape_t escape = CONSOLE_NORMAL; + +#if (GS_CONSOLE_HISTORY_LEN > 0) +static int history_elements; +static int history_cur; +static int history_browse; +static char history[GS_CONSOLE_HISTORY_LEN][GS_CONSOLE_INPUT_LEN+1]; +#endif + +static int size; +static int pos; +static char buf[GS_CONSOLE_INPUT_LEN+1]; +static gs_thread_t console_thread; + +#if (__linux__) +static bool termios_changed; +static struct termios old_stdin; +static struct termios old_stdout; +#endif + +static gs_mutex_t g_cci_lock; // Lock for protecting stdout for async output, e.g. log messages +static gs_error_t command_io_cci_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value); +static const gs_command_io_functions_t cci_io_functions = { + .set_result = command_io_cci_set_result, + .flush = gs_command_stdio_flush, + .wait_for_key = gs_command_stdio_wait_for_key, +}; +#define CCI_START_TAG "[X[" +#define CCI_END_TAG "]X]" + +static void gs_console_write(const char *str, int length) +{ + for (int i = 0; i < length; i++) { + putchar(str[i]); + } +} + +static void gs_console_prompt(void) +{ + static const char col_start[] = "\033[1;32m"; + static const char col_end[] = "\033[0m"; + + gs_console_write(col_start, sizeof(col_start) - 1); + gs_console_write(user_prompt, strlen(user_prompt)); + gs_console_write(hash_prompt, sizeof(hash_prompt) - 1); + gs_console_write(col_end, sizeof(col_end) - 1); +} + +void gs_console_set_prompt(const char * _prompt) +{ + if (gs_string_empty(_prompt) == false) { + user_prompt = _prompt; + } +} + +static void gs_console_reset(void) +{ + pos = size = 0; + buf[pos] = 0; + gs_console_prompt(); +} + +static void gs_console_rewind(void) +{ + int plen = strlen(hash_prompt) + strlen(user_prompt); + gs_console_write(&cr_char, 1); + while (size-- + plen) { + gs_console_write(&space_char, 1); + } + pos = size = 0; + gs_console_write(&cr_char, 1); +} + +void gs_console_clear(void) +{ + static const char clear[] = "\033[H\033[2J"; + gs_console_write(clear, sizeof(clear) - 1); + gs_console_rewind(); + gs_console_reset(); +} + +void gs_console_update(void) +{ + gs_console_rewind(); + gs_console_prompt(); + pos = size = strlen(buf); + gs_console_write(buf, size); +} + +#if (GS_CONSOLE_HISTORY_LEN > 0) + +static void gs_console_history_add(void) +{ + strncpy(history[history_cur], buf, GS_CONSOLE_INPUT_LEN); + history[history_cur][GS_CONSOLE_INPUT_LEN] = 0; + + history_browse = 0; + history_cur = (history_cur + 1) % GS_CONSOLE_HISTORY_LEN; + + if (history_elements < GS_CONSOLE_HISTORY_LEN) { + history_elements++; + } +} + +static void gs_console_last_line(void) +{ + if (history_elements < 1) { + return; + } + + if (history_browse >= history_elements) { + return; + } + + gs_console_rewind(); + history_browse++; + strcpy(buf, history[(history_cur - history_browse + GS_CONSOLE_HISTORY_LEN) % GS_CONSOLE_HISTORY_LEN]); + gs_console_update(); +} + +static void gs_console_next_line(void) +{ + if (history_elements < 1) { + return; + } + + if (history_browse < 1) { + return; + } + + gs_console_rewind(); + history_browse--; + if (history_browse > 0) { + strcpy(buf, history[(history_cur - history_browse + GS_CONSOLE_HISTORY_LEN) % GS_CONSOLE_HISTORY_LEN]); + } else { + buf[0] = '\0'; + } + gs_console_update(); +} + +#endif + +static void gs_console_forward_char(void) +{ + if (pos < size) { + gs_console_write(&buf[pos], 1); + pos++; + } +} + +static void gs_console_end_of_line(void) +{ + while (pos < size) { + gs_console_forward_char(); + } +} + +static void gs_console_backward_char(void) +{ + if (pos > 0) { + pos--; + gs_console_write(&backspace_char, 1); + } +} + +static void gs_console_beginning_of_line(void) +{ + while (pos) { + gs_console_backward_char(); + } +} + +static void gs_console_newline(void) +{ + gs_console_write(&cr_char, 1); + gs_console_write(&nl_char, 1); +} + +static bool gs_command_not_empty(const char *ibuf) +{ + while (*ibuf) { + if (!isblank((int) *ibuf++)) { + return true; + } + } + return false; +} + +static void show_help(const char * command) +{ + gs_error_t error = gs_command_show_help(command, stdout); + if (error) { + printf("Could not show help for \'%s\': %s (%d)\r\n", command, gs_error_string(error), error); + } +} + +static void gs_console_execute(void) +{ + gs_console_newline(); + buf[GS_CONSOLE_INPUT_LEN] = 0; // ensure 0 termination + if (size > 0 && gs_command_not_empty(buf)) { +#if (GS_CONSOLE_HISTORY_LEN > 0) + gs_console_history_add(); +#endif + gs_error_t result = GS_OK; + gs_error_t error = gs_command_execute_stdio(buf, &result); + if (error == GS_ERROR_TYPE) { + show_help(buf); + } else if (error == GS_ERROR_NOT_FOUND) { + printf("Unknown command \'%s\'\r\n", buf); + } else if (error == GS_ERROR_ARG) { + show_help(buf); + } else if (error) { + printf("Command \'%s\' did not execute: %s (%d)\r\n", buf, gs_error_string(error), error); + } else if (result == GS_ERROR_ARG) { + show_help(buf); + } else if (result) { + printf("Command \'%s\' executed, but returned error: %s (%d)\r\n", buf, gs_error_string(result), result); + } + } + gs_console_reset(); +} + +static void gs_console_complete(void) +{ + /* We don't expand in the middle of a line */ + if (size != pos) { + return; + } + + const size_t old_buf_len = strlen(buf); + gs_error_t ret = gs_command_complete(buf, sizeof(buf), stdout); + if ((ret == GS_OK) && (old_buf_len == strlen(buf))) { + // completed (again) and no change - show help + ret = GS_ERROR_AMBIGUOUS; + } + switch (ret) { + case GS_ERROR_AMBIGUOUS: + gs_console_newline(); + show_help(buf); + gs_console_update(); + break; + case GS_OK: + gs_console_update(); + break; + default: + case GS_ERROR_NOT_FOUND: + break; + } +} + +static void gs_console_insert(char c) +{ + int i; + int diff = size - pos; + + if (size >= GS_CONSOLE_INPUT_LEN) { + return; + } + + memmove(&buf[pos + 1], &buf[pos], diff); + buf[pos] = c; + + gs_console_write(&buf[pos], diff + 1); + for (i = 0; i < diff; i++) { + gs_console_write(&backspace_char, 1); + } + + size++; + pos++; + buf[size] = '\0'; +} + +static void gs_console_insert_overwrite(char c) +{ + buf[pos++] = c; + + if (pos > size) { + size++; + } + + gs_console_write(&c, 1); +} + +static void gs_console_delete(void) +{ + int i; + int diff = size - pos; + + /* Nothing to delete */ + if (size == pos) { + return; + } + + size--; + memmove(&buf[pos], &buf[pos + 1], diff - 1); + buf[size] = '\0'; + + gs_console_write(&buf[pos], diff - 1); + gs_console_write(&space_char, 1); + for (i = 0; i < diff; i++) { + gs_console_write(&backspace_char, 1); + } +} + +static void gs_console_backspace(void) +{ + if (pos < 1) { + return; + } + + gs_console_backward_char(); + gs_console_delete(); +} + +static void gs_console_kill_line(void) +{ + int i; + int diff; + + diff = size - pos; + + if (diff == 0) { + return; + } + + for (i = 0; i < diff; i++) { + gs_console_write(&space_char, 1); + } + for (i = 0; i < diff; i++) { + gs_console_write(&backspace_char, 1); + } + + memset(&buf[pos], 0, diff); + size = pos; +} + +static void gs_console_kill_line_from_beginning(void) +{ + gs_console_beginning_of_line(); + gs_console_kill_line(); +} + +static void gs_console_backward_kill_word(void) +{ + while (pos > 0 && buf[pos - 1] == ' ') { + gs_console_backspace(); + } + while (pos > 0 && buf[pos - 1] != ' ') { + gs_console_backspace(); + } +} + +static void gs_console_transpose_chars(void) +{ + char c1, c2; + + if (size < 2 || pos < 1) { + return; + } + + if (pos == size) { + c1 = buf[pos - 1]; + c2 = buf[pos - 2]; + + gs_console_backward_char(); + gs_console_backward_char(); + gs_console_insert_overwrite(c1); + gs_console_insert_overwrite(c2); + } else { + c1 = buf[pos]; + c2 = buf[pos - 1]; + + gs_console_backward_char(); + gs_console_insert_overwrite(c1); + gs_console_insert_overwrite(c2); + } +} + +static void gs_console_normal(char c) +{ + switch (c) { + case CONTROL('A'): + gs_console_beginning_of_line(); + break; + case CONTROL('B'): + gs_console_backward_char(); + break; + case CONTROL('C'): + // Either ignored or handled through signals + break; + case CONTROL('D'): + gs_console_delete(); + break; + case CONTROL('E'): + gs_console_end_of_line(); + break; + case CONTROL('F'): + gs_console_forward_char(); + break; + case CONTROL('K'): + gs_console_kill_line(); + break; + case CONTROL('L'): + gs_console_clear(); + break; +#if (GS_CONSOLE_HISTORY_LEN > 0) + case CONTROL('N'): + gs_console_next_line(); + break; + case CONTROL('P'): + gs_console_last_line(); + break; +#endif + case CONTROL('T'): + gs_console_transpose_chars(); + break; + case CONTROL('U'): + gs_console_kill_line_from_beginning(); + break; + case CONTROL('W'): + gs_console_backward_kill_word(); + break; + case CONTROL('Z'): + // We cannot suspend + break; + case CONTROL('H'): + case 0x7f: + gs_console_backspace(); + break; + case '\r': + case '\n': + gs_console_execute(); + break; + case '\t': + gs_console_complete(); + break; + case '\033': + escape = CONSOLE_ESCAPE; + break; + default: + if (escape == CONSOLE_ESCAPE) { + if ((c == '[') || (c == 'O')) { + c = getchar(); + if (c == 'F') + gs_console_end_of_line(); + if (c == 'H') + gs_console_beginning_of_line(); +#if (GS_CONSOLE_HISTORY_LEN > 0) + if (c == 'A') + gs_console_last_line(); + if (c == 'B') + gs_console_next_line(); +#endif + if (c == 'C') + gs_console_forward_char(); + if (c == 'D') + gs_console_backward_char(); + if (c == '1') + if (getchar() == '~') + gs_console_beginning_of_line(); + if (c == '3') + if (getchar() == '~') + gs_console_delete(); + } + escape = CONSOLE_NORMAL; + break; + } + + if (isprint((unsigned char) c)) { + gs_console_insert(c); + } + + break; + } +} + +static gs_error_t command_io_cci_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value) +{ + gs_mutex_lock(g_cci_lock); + { + printf(CCI_START_TAG "cmd_res,%s,%s,%s" CCI_END_TAG, group, key, value); + } + gs_mutex_unlock(g_cci_lock); + return GS_OK; +} + +static void gs_console_cci_log(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) +{ + va_list my_va; + va_copy(my_va, va); + + gs_mutex_lock(g_cci_lock); + { + printf(CCI_START_TAG "log,%04"PRIu32".%06"PRIu32",%c,%s,", ts->tv_sec, ts->tv_nsec / 1000, gs_log_level_to_char(level), group->name); + vprintf(format, my_va); + printf(CCI_END_TAG "\r\n"); + } + gs_mutex_unlock(g_cci_lock); + + va_end(my_va); +} + +static void gs_console_cci(char c) +{ + switch (c) { + case CONTROL('C'): + case CONTROL('L'): + size = 0; + buf[0] = 0; + break; + case '\r': + case '\n': + buf[GS_CONSOLE_INPUT_LEN] = 0; // ensure 0 termination + if (size > 0 && gs_command_not_empty(buf)) { + static unsigned int seq; // simple sequence number keep incrementing + + gs_mutex_lock(g_cci_lock); + ++seq; + printf(CCI_START_TAG "cmd_exec_begin,%u,%s" CCI_END_TAG "\r\n", seq, buf); + gs_mutex_unlock(g_cci_lock); + + gs_error_t result = GS_OK; + gs_error_t error = gs_command_execute(buf, &result, stdout, &cci_io_functions, NULL); + + gs_mutex_lock(g_cci_lock); + printf(CCI_START_TAG "cmd_exec_end,%u,%d,%d" CCI_END_TAG "\r\n", seq, error, result); + gs_mutex_unlock(g_cci_lock); + } + size = 0; + buf[0] = 0; + break; + default: + if (isprint((unsigned char) c) && (size < GS_CONSOLE_INPUT_LEN)) { + buf[size++] = c; + buf[size] = 0; + } + break; + } +} + +// Currrent mode handler, switch by sending command +static void (*console_handler)(char c) = gs_console_normal; + +int gs_console_change_mode(const char * mode) +{ + if (strcasecmp(mode, "cci") == 0) { + gs_error_t error = GS_OK; + if (console_handler != gs_console_cci) { + error = gs_mutex_create(&g_cci_lock); + if (error == GS_OK) { + gs_log_appender_console_set_cb(gs_console_cci_log); + console_handler = gs_console_cci; // change console handler + } + } + return error; + } + return GS_ERROR_NOT_SUPPORTED; +} + +static void * gs_console_thread(void * param) +{ + gs_console_reset(); + while (1) { + char c = getchar(); + console_handler(c); + } + + gs_thread_exit(NULL); +} + +gs_error_t gs_console_exit(void) +{ +#if (__linux__) + if (termios_changed) { + tcsetattr(STDIN_FILENO, TCSANOW, &old_stdin); + tcsetattr(STDOUT_FILENO, TCSANOW, &old_stdout); + } +#endif + return GS_OK; +} + +#if (__linux__) +static inline void exithandler(void) +{ + printf("\n"); + gs_console_exit(); +} +#endif + +static gs_error_t gs_console_init2(uint32_t flags) +{ +#if (__linux__) + // save current stdio setting, for restoring when terminating process + tcgetattr(STDIN_FILENO, &old_stdin); + tcgetattr(STDOUT_FILENO, &old_stdout); + + // change stdin settings + { + struct termios new = old_stdin; + new.c_iflag &= ~(IGNCR | ICRNL); + new.c_lflag &= ~(ECHO | ICANON | IEXTEN); + new.c_cc[VTIME]=0; + new.c_cc[VMIN]=1; + tcsetattr(STDIN_FILENO, TCSANOW, &new); + } + // change stdout settings + { + struct termios new = old_stdout; + new.c_iflag &= ~(IGNCR | ICRNL); + new.c_lflag &= ~(ECHO | ICANON | IEXTEN); + new.c_cc[VTIME]=0; + new.c_cc[VMIN]=1; + tcsetattr(STDOUT_FILENO, TCSANOW, &new); + } + + termios_changed = true; + + // add exit-handler to restore original termianl settings + atexit(exithandler); + + // install signal handlers to ensure terminal settings are restored + if ((flags & GS_CONSOLE_F_NO_SIGNAL_HANDLER) == 0) { + // install signal handler(s) to ensure atexit() is called + gs_signal_catch(SIGTERM, NULL); + + if (gs_command_line_ignore_ctrlc() == false) { + gs_signal_catch(SIGINT, NULL); + } + } +#endif + +#if (__AVR__ == 0) + /** This is very important on AVR32 */ + setvbuf(stdin, NULL, _IONBF, 0); + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); +#endif + return GS_OK; +} + +gs_error_t gs_console_init() +{ + return gs_console_init2(0); +} + +static gs_error_t _console_create_thread(gs_thread_priority_t priority, gs_thread_t * handle, uint32_t thread_create_flags) +{ + gs_error_t error = gs_thread_create("CONSOLE", + gs_console_thread, NULL, + gs_command_get_stack_size(), + priority, + thread_create_flags, + handle); + if (error == GS_OK) { + // give thread a few moments to print prompt + gs_time_sleep_ms(20); + } + return error; +} + +gs_error_t gs_console_create_thread(gs_thread_t * handle) +{ + return _console_create_thread(GS_THREAD_PRIORITY_LOW, handle, 0); +} + +gs_error_t gs_console_create_thread_with_priority(gs_thread_priority_t priority, gs_thread_t * handle) +{ + return _console_create_thread(priority, handle, 0); +} + +gs_error_t gs_console_start(const char * prompt, uint32_t flags) +{ + if (console_thread) { + return GS_ERROR_EXIST; + } + + gs_console_init2(flags); + gs_console_set_prompt(prompt); + + return _console_create_thread(GS_THREAD_PRIORITY_LOW, &console_thread, GS_THREAD_CREATE_JOINABLE); +} + +gs_error_t gs_console_stop(void) +{ + if (console_thread == 0) { + return GS_ERROR_HANDLE; + } +#if (__linux__) + if (pthread_cancel(console_thread) != 0) { + return GS_ERROR_IO; + } + gs_error_t error = gs_thread_join(console_thread, NULL); + if (error == GS_OK) { + console_thread = 0; + } + return error; +#else + return GS_ERROR_NOT_SUPPORTED; +#endif +} diff --git a/gomspace/libutil/src/gosh/console_local.h b/gomspace/libutil/src/gosh/console_local.h new file mode 100644 index 00000000..1332e732 --- /dev/null +++ b/gomspace/libutil/src/gosh/console_local.h @@ -0,0 +1,10 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +/** + Change console mode. + @param[in] mode console mode, 'rgosh', 'normal' + @return_gs_error_t +*/ +int gs_console_change_mode(const char * mode); diff --git a/gomspace/libutil/src/gosh/default_commands.c b/gomspace/libutil/src/gosh/default_commands.c new file mode 100644 index 00000000..fb535318 --- /dev/null +++ b/gomspace/libutil/src/gosh/default_commands.c @@ -0,0 +1,277 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include "command_local.h" +#include "console_local.h" + +#include + +#if defined(__linux__) +#include +#include +#endif + +#include +#include +#include +#include +#include + +static int cmd_help(gs_command_context_t * context) +{ + return gs_command_show_help(gs_command_args(context), context->out); +} + +static int cmd_sleep(gs_command_context_t * context) +{ + uint32_t sleep_ms; + gs_error_t error = gs_string_to_uint32(context->argv[1], &sleep_ms); + if (error) { + return error; + } + + gs_time_sleep_ms(sleep_ms); + + return GS_OK; +} + +static int cmd_watch(gs_command_context_t * context, bool check_error) +{ + uint32_t sleep_ms; + gs_error_t error = gs_string_to_uint32(context->argv[1], &sleep_ms); + if (error) { + return error; + } + + fprintf(context->out, "Execution delay: %" PRIu32 "\r\n", sleep_ms); + + char * new_command = strstr(gs_command_args(context), " "); + if (new_command == NULL) { + return GS_ERROR_ARG; + } else { + new_command = new_command + 1; + } + + fprintf(context->out, "Command: %s\r\n", new_command); + + while(1) { + + gs_error_t cmd_result; + error = gs_command_execute(new_command, &cmd_result, context->out, context->io_functions, context->io_ctx); + if (error) { + return error; + } + if (check_error && cmd_result) { + return cmd_result; + } + + if (gs_stdio_getchar_timed(sleep_ms, NULL) != GS_ERROR_TIMEOUT) { + break; + } + } + + return GS_OK; +} + +static int cmd_watch_nocheck(gs_command_context_t * context) +{ + return cmd_watch(context, false); +} + +static int cmd_watch_check(gs_command_context_t * context) +{ + return cmd_watch(context, true); +} + +#define CONTROL(X) ((X) - '@') + +static int cmd_batch(gs_command_context_t * ctx) +{ + char c; + int quit = 0, execute = 0; + unsigned int batch_size = 100; + unsigned int batch_input = 0; + unsigned int batch_count = 0; + char * batch[20] = {}; + printf("Type each command followed by enter, hit ctrl+e to end typing, ctrl+x to cancel:\r\n"); + + /* Wait for ^q to quit. */ + while (quit == 0) { + + /* Get character */ + c = getchar(); + + switch (c) { + + /* CTRL + X */ + case 0x18: + quit = 1; + break; + + /* CTRL + E */ + case 0x05: + execute = 1; + quit = 1; + break; + + /* Backspace */ + case CONTROL('H'): + case 0x7f: + if (batch_input > 0) { + putchar('\b'); + putchar(' '); + putchar('\b'); + batch_input--; + } + break; + + case '\r': + putchar('\r'); + putchar('\n'); + if ((batch[batch_count] != NULL) && (batch_input < batch_size)) + batch[batch_count][batch_input++] = '\r'; + if ((batch[batch_count] != NULL) && (batch_input < batch_size)) + batch[batch_count][batch_input++] = '\0'; + batch_count++; + batch_input = 0; + if (batch_count == 20) + quit = 1; + break; + + default: + putchar(c); + if (batch[batch_count] == NULL) { + batch[batch_count] = calloc(GS_CONSOLE_INPUT_LEN+1, 1); + } + + if ((batch[batch_count] != NULL) && (batch_input < batch_size)) + batch[batch_count][batch_input++] = c; + break; + } + } + + if (execute) { + printf("\r\n"); + for (unsigned int i = 0; i <= batch_count; i++) { + if (batch[i]) + printf("[%02u] %s\r\n", i, batch[i]); + } + printf("Press ctrl+e to execute, or any key to abort\r\n"); + c = getchar(); + if (c != 0x05) + execute = 0; + } + + /* Run/Free batch job */ + for (unsigned int i = 0; i <= batch_count; i++) { + if (execute && batch[i]) { + printf("EXEC [%02u] %s\r\n", i, batch[i]); + gs_command_run(batch[i], NULL); + } + free(batch[i]); + } + + return GS_OK; +} + +#if defined(__linux__) +static int cmd_exit(gs_command_context_t * context) +{ + gs_console_exit(); + exit(EXIT_SUCCESS); + return GS_OK; +} +#endif + +static int cmd_clock(gs_command_context_t * ctx) +{ + if (ctx->argc > 1) { + gs_timestamp_t ts; + gs_error_t error = gs_clock_from_string(ctx->argv[1], &ts); + if (error) { + return GS_ERROR_ARG; + } + error = gs_clock_set_time(&ts); + if (error) { + fprintf(ctx->out, "Failed to set time, error=%s\r\n", gs_error_string(error)); + return GS_ERROR_DATA; + } + } + + timestamp_t clock; + gs_clock_get_monotonic(&clock); + fprintf(ctx->out, "monotonic: %10"PRIu32".%09"PRIu32" sec\r\n", clock.tv_sec, clock.tv_nsec); + gs_command_set_output_printf(ctx, "", "monotonic", "%10"PRIu32".%09"PRIu32"", clock.tv_sec, clock.tv_nsec); + + char tbuf[25]; + gs_clock_get_time(&clock); + gs_clock_to_iso8601_string(&clock, tbuf, sizeof(tbuf)); + fprintf(ctx->out, "realtime: %10"PRIu32".%09"PRIu32" sec -> %s\r\n", clock.tv_sec, clock.tv_nsec, tbuf); + gs_command_set_output_printf(ctx, "", "realtime", "%10"PRIu32".%09"PRIu32"", clock.tv_sec, clock.tv_nsec); + + return GS_OK; +} + +static int cmd_console_mode(gs_command_context_t * ctx) +{ + return gs_console_change_mode(ctx->argv[1]); +} + +static const gs_command_t GS_COMMAND_ROOT cmd_default[] = { + { + .name = "help", + .help = "Show help", + .usage = "[command[ subcommand[ arg ...]]]", + .handler = cmd_help, + .optional_args = 100, + },{ + .name = "sleep", + .help = "Sleep X ms", + .usage = "", + .handler = cmd_sleep, + .mandatory_args = 1, + },{ + .name = "watch", + .help = "Run commands at intervals (abort with key)", + .usage = " [arg ...]", + .handler = cmd_watch_nocheck, + .mandatory_args = 2, + .optional_args = 100, + },{ + .name = "watch_check", + .help = "Like 'watch', but abort if command fails", + .usage = " ", + .handler = cmd_watch_check, + .mandatory_args = 2, + .optional_args = 100, + },{ + .name = "batch", + .help = "Run multiple commands", + .handler = cmd_batch, + .mode = GS_COMMAND_FLAG_HIDDEN, + },{ + .name = "clock", + .help = "Get/set system clock", + .usage = "[ | ]", + .handler = cmd_clock, + .optional_args = 1, + },{ + .name = "console_mode", + .help = "Console mode(s): cci", + .usage = "", + .handler = cmd_console_mode, + .mode = GS_COMMAND_FLAG_HIDDEN, + .mandatory_args = 1, + }, +#if defined(__linux__) + { + .name = "exit", + .help = "Exit program", + .handler = cmd_exit, + }, +#endif +}; + +gs_error_t gs_command_register_default_commands(void) +{ + return GS_COMMAND_REGISTER(cmd_default); +} diff --git a/gomspace/libutil/src/gosh/getopt.c b/gomspace/libutil/src/gosh/getopt.c new file mode 100644 index 00000000..81055bef --- /dev/null +++ b/gomspace/libutil/src/gosh/getopt.c @@ -0,0 +1,55 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include + +#include +#include +#include + +int gs_command_getopt(gs_command_context_t *ctx, const char *opts) +{ + int c; + char *cp; + + if (ctx->optsp == 1) { + if (ctx->optind >= ctx->argc || + ctx->argv[ctx->optind][0] != '-' || + ctx->argv[ctx->optind][1] == '\0') { + return EOF; + } else if (!strcmp(ctx->argv[ctx->optind], "--")) { + ctx->optind++; + return EOF; + } + } + + ctx->optopt = c = ctx->argv[ctx->optind][ctx->optsp]; + if (c == ':' || (cp = strchr(opts, c)) == NULL) { + printf("illegal option -- %c\r\n", c); + if (ctx->argv[ctx->optind][++ctx->optsp] == '\0') { + ctx->optind++; + ctx->optsp = 1; + } + return '?'; + } + + if (*++cp == ':') { + if (ctx->argv[ctx->optind][ctx->optsp+1] != '\0') { + ctx->optarg = &ctx->argv[ctx->optind++][ctx->optsp+1]; + } else if(++ctx->optind >= ctx->argc) { + printf("option requires an argument -- %c\r\n", c); + ctx->optsp = 1; + return '?'; + } else { + ctx->optarg = ctx->argv[ctx->optind++]; + } + ctx->optsp = 1; + } else { + if (ctx->argv[ctx->optind][++ctx->optsp] == '\0') { + ctx->optsp = 1; + ctx->optind++; + } + ctx->optarg = NULL; + } + + return c; +} diff --git a/gomspace/libutil/src/hexdump.c b/gomspace/libutil/src/hexdump.c new file mode 100644 index 00000000..7330ef91 --- /dev/null +++ b/gomspace/libutil/src/hexdump.c @@ -0,0 +1,92 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include + +static void print_disp_addr02(FILE * out, uintptr_t disp_addr) +{ + fprintf(out, "0x%02"PRIx32" : ", (uint32_t) disp_addr); +} +static void print_disp_addr04(FILE * out, uintptr_t disp_addr) +{ + fprintf(out, "0x%04"PRIx32" : ", (uint32_t) disp_addr); +} +static void print_disp_addrxx(FILE * out, uintptr_t disp_addr) +{ +#if defined(PRIx64) + fprintf(out, "0x%08"PRIx64" : ", (uint64_t) disp_addr); +#else + fprintf(out, "0x%08"PRIx32" : ", (uint32_t) disp_addr); +#endif +} + +void gs_hexdump_to_stream(const void * in_src, size_t len, const void * in_disp_addr, FILE* out) +{ + volatile const uint8_t * src = in_src; + uintptr_t disp_addr = GS_TYPES_PTR2UINT(in_disp_addr); + const uintptr_t end_disp_addr = disp_addr + len; + + // work-rounds for not printing NIL (if address 0), align addresses, not supporting %zx, %*x or %08p on all platforms + void (*print_addr)(FILE * out, uintptr_t disp_addr); + if (end_disp_addr <= 0xff) { + print_addr = print_disp_addr02; + } else if (end_disp_addr <= 0xffff) { + print_addr = print_disp_addr04; + } else { + print_addr = print_disp_addrxx; + } + + print_addr(out, disp_addr); + + size_t i = 0; + size_t j = 0; + size_t k = 0; + char text[17]; + for(; i < len; ++i) { + const uint8_t ch = *src++; + ++disp_addr; + + // hex + fprintf(out, "%02x ", ch); + ++j; + if (j == 8) { + fprintf(out, " "); + } + + // printable + if ((ch < 32) || (ch > 126)) { + text[k] = '.'; + } else { + text[k] = (char) ch; + } + ++k; + text[k] = 0; + + // newline? + if(j >= 16) { + fprintf(out, "|%-16.16s|\r\n", text); + j = 0; + k = 0; + text[k] = 0; + + if (i < (len - 1)) { + print_addr(out, disp_addr); + } + } + } + if ((i == 0) || (i % 16)) { + if (j) { + // something was printed - show textual + for (; j < 16; j++) { + if (j == 7) { + fprintf(out, " "); + } + fprintf(out, " "); + } + fprintf(out, "|%-16.16s|", text); + } + fprintf(out, "\r\n"); + } +} diff --git a/gomspace/libutil/src/linux/argp.c b/gomspace/libutil/src/linux/argp.c new file mode 100644 index 00000000..e9156595 --- /dev/null +++ b/gomspace/libutil/src/linux/argp.c @@ -0,0 +1,34 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +void gs_argp_parse(const struct argp * argp, + int argc, char ** argv, + unsigned int flags, int * return_arg_index, + const char * revision) +{ + if (gs_string_empty(revision) == false) { + argp_program_version = revision; + } + + int arg_index = 0; + int res = argp_parse(argp, argc, argv, 0, &arg_index, 0); + if (res) { + printf("Failed to parse argument/option (result: %d)\n", res); + exit(GS_EXITCODE_USAGE); + } + + if ((return_arg_index == NULL) && (arg_index < argc)) { + // application doesn't expect unhandled arguments + for (int i = arg_index; i < argc; ++i) { + printf("Unhandled/unknown argument: [%s]\n", argv[i]); + } + exit(GS_EXITCODE_USAGE); + } + + if (return_arg_index) { + *return_arg_index = arg_index; + } +} diff --git a/gomspace/libutil/src/linux/clock.c b/gomspace/libutil/src/linux/clock.c new file mode 100644 index 00000000..191aac25 --- /dev/null +++ b/gomspace/libutil/src/linux/clock.c @@ -0,0 +1,68 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include + +void gs_clock_get_time(gs_timestamp_t * time) +{ + struct timespec now; + clock_gettime(CLOCK_REALTIME, &now); + + time->tv_sec = (uint32_t) now.tv_sec; + time->tv_nsec = (uint32_t) now.tv_nsec; +} + +gs_error_t gs_clock_set_time(const gs_timestamp_t * time) +{ + struct timespec now; + now.tv_sec = time->tv_sec; + now.tv_nsec = time->tv_nsec; + + int res = clock_settime(CLOCK_REALTIME, &now); + if (res != 0) { + return gs_error(errno); + } + + gs_error_t error = GS_OK; + if (gs_rtc_supported() == GS_OK) { + error = gs_rtc_set_time(time); + } + + return error; +} + +void gs_clock_get_monotonic(gs_timestamp_t * time) +{ + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + time->tv_sec = (uint32_t) now.tv_sec; + time->tv_nsec = (uint32_t) now.tv_nsec; +} + +uint64_t gs_clock_get_nsec(void) +{ + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + return (((uint64_t)now.tv_sec) * GS_TIMESTAMP_NSEC_PER_SEC) + ((uint64_t)now.tv_nsec); +} + +/** + Required by libcsp. + Proto-typed in ./libcsp/include/csp/arch/csp_clock.h, but with different argumet! + + __attribute__((weak)) extern void clock_get_time(csp_timestamp_t * time); + __attribute__((weak)) extern void clock_set_time(csp_timestamp_t * time); +*/ +void clock_get_time(gs_timestamp_t * time) +{ + gs_clock_get_time(time); +} + +void clock_set_time(const gs_timestamp_t * time) +{ + gs_clock_set_time(time); +} diff --git a/gomspace/libutil/src/linux/command_line.c b/gomspace/libutil/src/linux/command_line.c new file mode 100644 index 00000000..e95cd602 --- /dev/null +++ b/gomspace/libutil/src/linux/command_line.c @@ -0,0 +1,76 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +#define KEY_IGNORE_CTRLC 200 + +static bool ignore_ctrlc; + +static int parser(int key, char *arg, struct argp_state *state) +{ + switch (key) { + case KEY_IGNORE_CTRLC: + ignore_ctrlc = true; + gs_signal_ignore(SIGINT); + break; + + case 'h': + argp_help(state->root_argp, state->out_stream, ARGP_HELP_STD_HELP, state->name); + exit(0); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static const struct argp_option options[] = { + { + .name = "ignore-ctrlc", + .key = KEY_IGNORE_CTRLC, + .doc = "Ignore/disable CTRL-C" + }, + {0} +}; + +static const struct argp argp_console = {.options = options, .parser = parser}; + +const struct argp_child gs_console_command_line_ignore_ctrlc_argp = {.argp = &argp_console}; + +bool gs_command_line_ignore_ctrlc(void) +{ + return ignore_ctrlc; +} + +static const struct argp_option help_options[] = { + { + .name = "help", + .key = 'h', + .doc = "Give this help list" + }, + {0} +}; + +static const struct argp gs_argp_help = {.options = help_options, .parser = parser}; + +const struct argp_child gs_help_command_line_argp = {.argp = &gs_argp_help}; + +const char * gs_command_line_program_name(const char * argv) +{ + if (gs_string_empty(argv) == false) { + const char * name = strrchr(argv, '/'); + if (name) { + // skip slash + ++name; + if (gs_string_empty(name) == false) { + return name; + } + } else { + return argv; + } + } + return ""; +} diff --git a/gomspace/libutil/src/linux/cwd.c b/gomspace/libutil/src/linux/cwd.c new file mode 100644 index 00000000..1cfe373d --- /dev/null +++ b/gomspace/libutil/src/linux/cwd.c @@ -0,0 +1,28 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +gs_error_t gs_getcwd(char * buf, size_t bufsize) +{ + if (buf && bufsize) { + char * wd = getcwd(buf, bufsize); + if (wd) { + return GS_OK; + } + switch(errno) { + case ENAMETOOLONG: + case ERANGE: + return GS_ERROR_RANGE; + + case EACCES: + case ENOENT: + return GS_ERROR_NOT_FOUND; + + default: + break; + } + } + return GS_ERROR_ARG; +} diff --git a/gomspace/libutil/src/linux/delay.c b/gomspace/libutil/src/linux/delay.c new file mode 100644 index 00000000..f0a39081 --- /dev/null +++ b/gomspace/libutil/src/linux/delay.c @@ -0,0 +1,22 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +void gs_delay_us(uint32_t time_us) +{ + uint64_t ns = time_us; + ns *= 1000LL; + gs_time_sleep_ns(ns); +} + +uint16_t gs_delay_ts_get(void) +{ + return 0; +} + +void gs_delay_from_ts(uint16_t ts, uint16_t delay) +{ + +} diff --git a/gomspace/libutil/src/linux/drivers/can/can.c b/gomspace/libutil/src/linux/drivers/can/can.c new file mode 100644 index 00000000..40a6b8c8 --- /dev/null +++ b/gomspace/libutil/src/linux/drivers/can/can.c @@ -0,0 +1,308 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + // true if handle is in use + bool inuse; + + // opened socket + int can_socket; + + // receiver thread + gs_thread_t rxthread; + + // received data callback + gs_can_rxdata_callback_t rx_callback; + void * user_data; + +} gs_can_handle_t; + +#define MAX_CAN_HANDLES 10 +static gs_can_handle_t can_handles[MAX_CAN_HANDLES]; + +static int gs_can_alloc_handle(void) +{ + int handle_id; + for (handle_id = 0; (handle_id < MAX_CAN_HANDLES) && (can_handles[handle_id].inuse == true); ++handle_id); + + if (handle_id < MAX_CAN_HANDLES) { + gs_can_handle_t * handle = &can_handles[handle_id]; + memset(handle, 0, sizeof(*handle)); + handle->inuse = true; + handle->can_socket = -1; + } + + return handle_id; +} + +static inline gs_can_handle_t * gs_can_handle(uint8_t hdl) +{ + if (hdl >= MAX_CAN_HANDLES) { + return NULL; + } + if (can_handles[hdl].inuse == false) { + return NULL; + } + return &can_handles[hdl]; +} + +static void * gs_can_rx_thread(void * parameter) +{ + int hdl = (int) GS_TYPES_PTR2INT(parameter); + + log_debug("%s: running, hdl: %d", __FUNCTION__, hdl); + + gs_can_handle_t * handle = gs_can_handle(hdl); + if (handle == NULL) { + log_error("%s: CAN handle: %d is invalid or not opened", __FUNCTION__, hdl); + gs_thread_exit(NULL); + } + + while (1) { + /* Read CAN frame */ + struct can_frame frame; + ssize_t nbytes = read(handle->can_socket, &frame, sizeof(frame)); + if (nbytes < 0) { + log_error("%s: read() on socket failed, error: %s", __FUNCTION__, strerror(errno)); + continue; + } + + if (nbytes != sizeof(frame)) { + log_warning("%s: read() returned incomplete CAN frame of %d bytes - ignoring frame", __FUNCTION__, (int) nbytes); + continue; + } + + /* Frame type */ + if (frame.can_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) { + /* Drop error and remote frames */ + log_warning("%s: discarding ERR/RTR frame, can_id: 0x%x", __FUNCTION__, frame.can_id); + continue; + } + + const bool extId = (frame.can_id & CAN_EFF_FLAG) ? true : false; + if (extId) { + frame.can_id &= CAN_EFF_MASK; + } else { + frame.can_id &= CAN_SFF_MASK; + } + handle->rx_callback(hdl, frame.can_id, extId, frame.data, frame.can_dlc, gs_time_rel_ms(), handle->user_data, false); + } + + /* We should never reach this point */ + return NULL; +} + +static gs_error_t gs_can_send(uint8_t hdl, uint32_t canMsgId, bool extended, const void * data, size_t data_size, int timeout_ms) +{ + gs_can_handle_t * handle = gs_can_handle(hdl); + if (handle == NULL) { + return GS_ERROR_HANDLE; + } + + if ((data == NULL) || (data_size > 8)) { + log_error("%s: invalid data: %p, data_size: %u", __FUNCTION__, (void*) data, (unsigned int) data_size); + return GS_ERROR_ARG; + } + + struct can_frame frame; + memset(&frame, 0, sizeof(frame)); + frame.can_id = canMsgId; + if (extended) { + frame.can_id |= CAN_EFF_FLAG; + } + + memcpy(frame.data, data, data_size); + + frame.can_dlc = (uint8_t) data_size; + + const int DELAY_MS = 10; + while (write(handle->can_socket, &frame, sizeof(frame)) != sizeof(frame)) { + if ((timeout_ms > 0) && (errno == ENOBUFS)) { + // Wait a bit and try again + gs_thread_sleep_ms(DELAY_MS); + timeout_ms -= DELAY_MS; + } else { + gs_error_t gserror = gs_error(errno); + log_error("%s: write() failed, error: %s", __FUNCTION__, gs_error_string(gserror)); + return gserror; + } + } + + return GS_OK; +} + +gs_error_t gs_can_send_standard(uint8_t hdl, uint32_t canMsgId, const void * data, size_t data_size, int timeout_ms) +{ + return gs_can_send(hdl, canMsgId, false, data, data_size, timeout_ms); +} + +gs_error_t gs_can_send_extended(uint8_t hdl, uint32_t canExtMsgId, const void * data, size_t data_size, int timeout_ms) +{ + return gs_can_send(hdl, canExtMsgId, true, data, data_size, timeout_ms); +} + +static void gs_can_close(gs_can_handle_t * handle) +{ + if (handle->can_socket >= 0) { + close(handle->can_socket); + } + + // free instance - must be the last thing done, no lock needed + handle->inuse = false; +} + +gs_error_t gs_can_open(const char * ifname, int * return_handle) +{ + if ((ifname == NULL) || (ifname[0] == 0) || (return_handle == NULL)) { + log_error("%s: invalid CAN interface name", __FUNCTION__); + return GS_ERROR_ARG; + } + + int handle_id = gs_can_alloc_handle(); + if (handle_id >= MAX_CAN_HANDLES) { + log_error("%s: no free handles", __FUNCTION__); + return GS_ERROR_FULL; + } + gs_can_handle_t * handle = &can_handles[handle_id]; + + /* Create socket */ + if ((handle->can_socket = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { + gs_error_t gserror = gs_error(errno); + log_error("%s: socket() failed, error: %s", __FUNCTION__, gs_error_string(gserror)); + gs_can_close(handle); + return gserror; + } + + /* Locate interface */ + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1); + if (ioctl(handle->can_socket, SIOCGIFINDEX, &ifr) < 0) { + gs_error_t gserror = gs_error(errno); + log_error("%s: ioctl(ifname: [%s]) failed, error: %s", __FUNCTION__, ifr.ifr_name, gs_error_string(gserror)); + gs_can_close(handle); + return gserror; + } + + /* Bind the socket to CAN interface */ + struct sockaddr_can addr; + memset(&addr, 0, sizeof(addr)); + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + if (bind(handle->can_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + gs_error_t gserror = gs_error(errno); + log_error("%s: bind() failed, error: %s", __FUNCTION__, gs_error_string(gserror)); + gs_can_close(handle); + return gserror; + } + + *return_handle = handle_id; + + return GS_OK; +} + +static gs_error_t gs_can_set_filter_mask(uint8_t hdl, bool extended, uint32_t canMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * user_data) +{ + gs_can_handle_t * handle = gs_can_handle(hdl); + if (handle == NULL) { + return GS_ERROR_HANDLE; + } + + if (extended) { + if ((canMsgId > CAN_EFF_MASK) || (mask > CAN_EFF_MASK)) { + return GS_ERROR_ARG; + } + } else { + if ((canMsgId > CAN_SFF_MASK) || (mask > CAN_SFF_MASK)) { + return GS_ERROR_ARG; + } + } + + handle->rx_callback = rx_callback; + handle->user_data = user_data; + + struct can_filter filter; + filter.can_id = canMsgId; + filter.can_mask = mask; + if (extended == false) { + filter.can_mask |= (CAN_EFF_MASK & ~CAN_SFF_MASK); + } + + if (setsockopt(handle->can_socket, SOL_CAN_RAW, CAN_RAW_FILTER, &filter, sizeof(filter)) < 0) { + gs_error_t gserror = gs_error(errno); + log_error("%s: setsockopt(id: 0x%x, mask: 0x%x) failed, error: %s", __FUNCTION__, canMsgId, mask, gs_error_string(gserror)); + return gserror; + } + + return GS_OK; +} + +gs_error_t gs_can_set_standard_filter_mask(uint8_t hdl, uint32_t canMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * user_data) +{ + return gs_can_set_filter_mask(hdl, false, canMsgId, mask, rx_callback, user_data); +} + +gs_error_t gs_can_set_extended_filter_mask(uint8_t hdl, uint32_t canExtMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * user_data) +{ + return gs_can_set_filter_mask(hdl, true, canExtMsgId, mask, rx_callback, user_data); +} + +gs_error_t gs_can_start(uint8_t hdl) +{ + gs_can_handle_t * handle = gs_can_handle(hdl); + if (handle == NULL) { + return GS_ERROR_HANDLE; + } + + if (handle->rxthread) { + return GS_OK; + } + + /* Create receiver thread */ + gs_error_t gserror = gs_thread_create("rxcan", gs_can_rx_thread, GS_TYPES_INT2PTR(hdl), 0, GS_THREAD_PRIORITY_HIGH, 0, &handle->rxthread); + if (gserror) { + log_error("s: gs_thread_create() failed, error: %s", gs_error_string(gserror)); + return gserror; + } + + return GS_OK; +} + +gs_error_t gs_can_stop(uint8_t hdl) +{ + gs_can_handle_t * handle = gs_can_handle(hdl); + if (handle == NULL) { + return GS_ERROR_HANDLE; + } + + return GS_ERROR_NOT_IMPLEMENTED; +} + +gs_error_t gs_can_error_state(uint8_t hdl, bool * restart_required) +{ + gs_can_handle_t * handle = gs_can_handle(hdl); + if (handle == NULL) { + return GS_ERROR_HANDLE; + } + + if (restart_required) { + *restart_required = false; + } + + // missing error state check on CAN layer + + return GS_OK; +} diff --git a/gomspace/libutil/src/linux/drivers/gpio/gpio.c b/gomspace/libutil/src/linux/drivers/gpio/gpio.c new file mode 100644 index 00000000..484c6a58 --- /dev/null +++ b/gomspace/libutil/src/linux/drivers/gpio/gpio.c @@ -0,0 +1,102 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +#define MAX_DRIVERS 20 + +typedef struct { + gs_gpio_driver_entry_t entry; + bool in_use; +} gs_gpio_driver_handle_t; + +static gs_gpio_driver_handle_t gpio_drivers[MAX_DRIVERS]; +static uint8_t max_index_in_use = 0; + + +static inline gs_gpio_driver_entry_t * gs_find_driver_entry(gs_gpio_t * gpio) +{ + gs_gpio_driver_handle_t * handle; + for (int i = max_index_in_use; i >= 0; i--) { + handle = &gpio_drivers[i]; + if (((gpio->pin == handle->entry.pin) || (handle->entry.pin == GS_GPIO_ALL_PINS)) && + ((gpio->port == handle->entry.port) || (handle->entry.port == GS_GPIO_ALL_PORTS)) && + (handle->in_use == true)) { + return &handle->entry; + } + } + return NULL; +} + +gs_error_t gs_gpio_get(gs_gpio_t gpio, bool *value) +{ + gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); + if (driver_entry) { + if (driver_entry->driver->get_handler) { + return driver_entry->driver->get_handler(gpio, value, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +bool gs_gpio_get_nc(gs_gpio_t gpio) +{ + gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); + if (driver_entry) { + if (driver_entry->driver->get_nc_handler) { + return driver_entry->driver->get_nc_handler(gpio, driver_entry->driver_data); + } + } + return false; +} + +gs_error_t gs_gpio_set(gs_gpio_t gpio, bool value) +{ + gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); + if (driver_entry) { + if (driver_entry->driver->set_handler) { + return driver_entry->driver->set_handler(gpio, value, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +void gs_gpio_set_nc(gs_gpio_t gpio, bool value) +{ + gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); + if (driver_entry) { + if (driver_entry->driver->set_nc_handler) { + driver_entry->driver->set_nc_handler(gpio, value, driver_entry->driver_data); + } + } +} + +gs_error_t gs_gpio_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf) +{ + gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); + if (driver_entry) { + if (driver_entry->driver->init_as_interrupt_handler) { + return driver_entry->driver->init_as_interrupt_handler(gpio, conf, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_gpio_register_driver(const gs_gpio_driver_entry_t * driver_entry) +{ + GS_CHECK_ARG(driver_entry != NULL); + GS_CHECK_ARG(driver_entry->driver != NULL); + + gs_gpio_driver_handle_t * handle; + for (uint8_t i = 0; i < MAX_DRIVERS; i++) { + handle = &gpio_drivers[i]; + if (handle->in_use == false) { + handle->entry = *driver_entry; + handle->in_use = true; + max_index_in_use = i; + return GS_OK; + } + } + /* Not enough space in buffer */ + return GS_ERROR_FULL; +} diff --git a/gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c b/gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c new file mode 100644 index 00000000..57efd042 --- /dev/null +++ b/gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c @@ -0,0 +1,145 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + @brief GPIO Implementation for Linux of the GPIO API in libutil. + + The GPIO driver provides a simple interface toward driving HW GPIO's. +*/ + +#include + +#include +#include +#include +#include + +#include + +#include + +gs_error_t gs_gpio_sysfs_initialize(gs_gpio_t gpio, bool output,bool init_value, bool active_low) +{ + char gpio_pin_str[6]; + snprintf(gpio_pin_str, sizeof(gpio_pin_str), "%d", gpio.pin); + + /* Try to unexport first */ + gs_sysfs_write_file("/sys/class/gpio/unexport", gpio_pin_str); + + if (gs_sysfs_write_file("/sys/class/gpio/export", gpio_pin_str) != GS_OK) + { + log_warning("failed to export GPIO %s: %s", gpio_pin_str, strerror(errno)); + return GS_ERROR_NOT_SUPPORTED; + } + + char gpio_sys_fname[128]; + snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/active_low", gpio.pin); + const char * active_low_str = active_low ? "1" : "0"; + + if (gs_sysfs_write_file(gpio_sys_fname, active_low_str) != GS_OK) + { + log_warning("failed to set GPIO %d active_low: %s", gpio.pin, strerror(errno)); + return GS_ERROR_NOT_SUPPORTED; + } + + snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/direction", gpio.pin); + + /* Glitch-free output set (high/low makes pin an output and sets value to 1/0 respectively)*/ + const char * dir = output ? (init_value ? "high" : "low") : "in"; + + if (gs_sysfs_write_file(gpio_sys_fname, dir) != GS_OK) + { + log_warning("failed to set GPIO %d direction: %s", gpio.pin, strerror(errno)); + return GS_ERROR_NOT_SUPPORTED; + } + + return GS_OK; +} + +gs_error_t gs_gpio_sysfs_get(gs_gpio_t gpio, bool *value, void * driver_data) +{ + char gpio_sys_fname[128]; + snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); + + if (access(gpio_sys_fname, R_OK) != 0) + { + log_error("GPIO %d not initialized - Can't read the input.", gpio.pin); + return GS_ERROR_ACCESS; + } + + char value_str[10]; + gs_error_t ret = gs_sysfs_read_file(gpio_sys_fname, value_str, sizeof(value_str)); + if (ret == GS_OK) + { + if (strcmp(value_str, "1") == 0) + *value = true; + else + *value = false; + } + + return ret; +} + +bool gs_gpio_sysfs_get_nc(gs_gpio_t gpio, void * driver_data) +{ + char gpio_sys_fname[128]; + snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); + + if (access(gpio_sys_fname, R_OK) != 0) + { + log_error("GPIO %d not initialized - Can't read the input.", gpio.pin); + return 0; + } + + char value_str[10]; + gs_sysfs_read_file(gpio_sys_fname, value_str, sizeof(value_str)); + + if (strncmp(value_str, "1", 10) == 0) { + return true; + } else { + return false; + } +} + +gs_error_t gs_gpio_sysfs_set(gs_gpio_t gpio, bool value, void * driver_data) +{ + const char *value_str = value ? "1" : "0"; + + char gpio_sys_fname[128]; + snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); + if (access(gpio_sys_fname, W_OK) == 0) + { + return gs_sysfs_write_file(gpio_sys_fname, value_str); + } + + log_error("GPIO %d not initialized - Can't set the output.", gpio.pin); + return GS_ERROR_ACCESS; +} + +void gs_gpio_sysfs_set_nc(gs_gpio_t gpio, bool value, void * driver_data) +{ + const char *value_str = value ? "1" : "0"; + + char gpio_sys_fname[128]; + snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); + if (access(gpio_sys_fname, W_OK) == 0) + { + gs_sysfs_write_file(gpio_sys_fname, value_str); + return; + } + log_error("GPIO %d not initialized - Can't set the output.", gpio.pin); +} + +gs_error_t gs_gpio_sysfs_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data) +{ + return GS_ERROR_NOT_IMPLEMENTED; +} + +const gs_gpio_driver_t gs_gpio_sysfs_driver = { + .get_handler = gs_gpio_sysfs_get, + .get_nc_handler = gs_gpio_sysfs_get_nc, + .set_handler = gs_gpio_sysfs_set, + .set_nc_handler = gs_gpio_sysfs_set_nc, + .init_as_interrupt_handler = gs_gpio_sysfs_init_as_interrupt, +}; + diff --git a/gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c b/gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c new file mode 100644 index 00000000..ce20c885 --- /dev/null +++ b/gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c @@ -0,0 +1,171 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +#define MAX_VPINS 500 + +#define FALLING_EDGE_FLAG 0x1 +#define RISING_EDGE_FLAG 0x2 + +typedef struct { + gs_gpio_t gpio; + bool output; + bool value; + bool in_use; + gs_gpio_isr_t isr; + uint8_t edge_flags; + uint32_t transistions; +} gs_gpio_virtual_t; + +static gs_gpio_virtual_t vpins[MAX_VPINS]; + +gs_error_t gs_gpio_virtual_initialize(gs_gpio_t gpio, bool output, bool value) +{ + gs_gpio_virtual_t * pin; + for (uint16_t i = 0; i < MAX_VPINS; i++) { + pin = &vpins[i]; + if ((!pin->in_use) || ((pin->gpio.pin == gpio.pin) && (pin->gpio.port == gpio.port))) { + pin->gpio = gpio; + pin->output = output; + pin->value = value; + pin->in_use = true; + return GS_OK; + } + } + return GS_ERROR_FULL; +} + +static gs_gpio_virtual_t * find_vpin(gs_gpio_t * gpio) +{ + gs_gpio_virtual_t * pin; + for (uint16_t i = 0; i < MAX_VPINS; i++) { + pin = &vpins[i]; + if (pin->gpio.pin == gpio->pin) { + if (pin->gpio.port == gpio->port) { + if (pin->in_use) { + return pin; + } + } + } + } + return NULL; +} + +gs_error_t gs_gpio_virtual_get(gs_gpio_t gpio, bool *value, void * driver_data) +{ + gs_gpio_virtual_t * pin = find_vpin(&gpio); + if (pin) { + *value = pin->value; + return GS_OK; + } + return GS_ERROR_NOT_FOUND; +} + +bool gs_gpio_virtual_get_nc(gs_gpio_t gpio, void * driver_data) +{ + gs_gpio_virtual_t * pin = find_vpin(&gpio); + if (pin) { + return pin->value; + } + return false; +} + +gs_error_t gs_gpio_virtual_set(gs_gpio_t gpio, bool value, void * driver_data) +{ + gs_gpio_virtual_t * pin = find_vpin(&gpio); + if (pin) { + if (pin->output) { + if (pin->value != value) { + pin->value = value; + pin->transistions++; + } + return GS_OK; + } + return GS_ERROR_PERM; + } + return GS_ERROR_NOT_FOUND; +} + +void gs_gpio_virtual_set_nc(gs_gpio_t gpio, bool value, void * driver_data) +{ + gs_gpio_virtual_t * pin = find_vpin(&gpio); + if (pin) { + if (pin->output) { + if (pin->value != value) { + pin->value = value; + pin->transistions++; + } + } + } +} + +gs_error_t gs_gpio_virtual_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data) +{ + gs_gpio_virtual_t * pin; + for (uint16_t i = 0; i < MAX_VPINS; i++) { + pin = &vpins[i]; + if ((!pin->in_use) || ((pin->gpio.pin == gpio.pin) && (pin->gpio.port == gpio.port))) { + pin->gpio = gpio; + pin->output = false; + pin->value = 0; + pin->in_use = true; + pin->isr = conf->isr; + if (conf->falling_edge) { + pin->edge_flags |= FALLING_EDGE_FLAG; + } + if (conf->rising_edge) { + pin->edge_flags |= RISING_EDGE_FLAG; + } + return GS_OK; + } + } + return GS_ERROR_FULL; +} + +gs_error_t gs_gpio_virtual_force_set(gs_gpio_t gpio, bool value) +{ + gs_gpio_virtual_t * pin = find_vpin(&gpio); + if (pin) { + bool old_value = pin->value; + if (old_value != value) { + pin->value = value; + pin->transistions++; + if (pin->isr) { + if ((old_value == false) && (pin->edge_flags & RISING_EDGE_FLAG)) { + pin->isr(NULL); + } else if ((old_value == true) && (pin->edge_flags & FALLING_EDGE_FLAG)) { + pin->isr(NULL); + } + } + } + return GS_OK; + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_gpio_virtual_get_transistions(gs_gpio_t gpio, uint32_t * transitions) +{ + gs_gpio_virtual_t * pin = find_vpin(&gpio); + if (pin) { + *transitions = pin->transistions; + pin->transistions = 0; + return GS_OK; + } + return GS_ERROR_NOT_FOUND; +} + +const gs_gpio_driver_t gs_gpio_virtual_driver = { + .get_handler = gs_gpio_virtual_get, + .get_nc_handler = gs_gpio_virtual_get_nc, + .set_handler = gs_gpio_virtual_set, + .set_nc_handler = gs_gpio_virtual_set_nc, + .init_as_interrupt_handler = gs_gpio_virtual_init_as_interrupt, +}; + + +const gs_gpio_driver_entry_t gs_gpio_virtual_driver_entry_all = { + .port = GS_GPIO_ALL_PORTS, + .pin = GS_GPIO_ALL_PINS, + .driver = &gs_gpio_virtual_driver, + .driver_data = NULL, +}; diff --git a/gomspace/libutil/src/linux/drivers/i2c/i2c.c b/gomspace/libutil/src/linux/drivers/i2c/i2c.c new file mode 100644 index 00000000..679ae3f7 --- /dev/null +++ b/gomspace/libutil/src/linux/drivers/i2c/i2c.c @@ -0,0 +1,144 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +#define MAX_DRIVERS 20 +#define HIGHEST_I2C_ADDR 127 + +typedef struct { + gs_i2c_master_driver_entry_t entry; + bool in_use; +} gs_i2c_master_driver_handle_t; + +typedef struct { + gs_i2c_slave_driver_entry_t entry; + bool in_use; +} gs_i2c_slave_driver_handle_t; + +static gs_i2c_master_driver_handle_t master_drivers[MAX_DRIVERS]; +static gs_i2c_slave_driver_handle_t slave_drivers[MAX_DRIVERS]; + +static uint8_t max_index_master_in_use = 0; +static uint8_t max_index_slave_in_use = 0; + +gs_error_t gs_i2c_master_transaction(uint8_t device, uint8_t addr, const void * tx, + size_t txlen, + void * rx, + size_t rxlen, + int timeout_ms) +{ + GS_CHECK_RANGE(addr <= HIGHEST_I2C_ADDR); + gs_i2c_master_driver_handle_t * handle; + for (int i = max_index_master_in_use; i >= 0; i--) { + handle = &master_drivers[i]; + if (((device == handle->entry.device) || (handle->entry.device == GS_I2C_ALL_DEVICES)) + && ((addr == handle->entry.addr) || (handle->entry.addr == GS_I2C_ALL_ADDR)) + && (handle->in_use == true)) { + if (handle->entry.driver->master_transaction_handler) { + return handle->entry.driver->master_transaction_handler(device, addr, tx, txlen, rx, rxlen, timeout_ms, handle->entry.driver_data); + } + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_i2c_master_register_driver(const gs_i2c_master_driver_entry_t * driver_entry) +{ + GS_CHECK_ARG(driver_entry != NULL); + GS_CHECK_ARG(driver_entry->driver != NULL); + + GS_CHECK_RANGE((driver_entry->addr == GS_I2C_ALL_ADDR) || (driver_entry->addr <= HIGHEST_I2C_ADDR)); + + gs_i2c_master_driver_handle_t * handle; + for (uint8_t i = 0; i < MAX_DRIVERS; i++) { + handle = &master_drivers[i]; + if (handle->in_use == false) { + handle->entry = *driver_entry; + handle->in_use = true; + max_index_master_in_use = i; + return GS_OK; + } + } + + /* Not enough space in buffer */ + return GS_ERROR_FULL; +} + +static inline gs_i2c_slave_driver_entry_t * gs_slave_find_driver_entry(uint8_t device) +{ + gs_i2c_slave_driver_handle_t * handle; + for (int i = max_index_slave_in_use; i >= 0; i--) { + handle = &slave_drivers[i]; + if (((device == handle->entry.device) || (handle->entry.device == GS_I2C_ALL_DEVICES)) + && (handle->in_use == true)) { + return &handle->entry; + } + } + return NULL; +} + +gs_error_t gs_i2c_slave_start(uint8_t device) +{ + gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); + if (driver_entry) { + if (driver_entry->driver->start_handler) { + return driver_entry->driver->start_handler(device, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_i2c_slave_set_rx(uint8_t device, gs_i2c_slave_receive_t rx) +{ + gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); + if (driver_entry) { + if (driver_entry->driver->set_rx_handler) { + return driver_entry->driver->set_rx_handler(device, rx, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_i2c_slave_set_get_rx_buf(uint8_t device, gs_i2c_slave_get_rx_buf_t get_rx_buf, size_t buf_length) +{ + gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); + if (driver_entry) { + if (driver_entry->driver->set_get_rx_buf_handler) { + return driver_entry->driver->set_get_rx_buf_handler(device, get_rx_buf, buf_length, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_i2c_slave_set_response(uint8_t device, const uint8_t * tx, size_t tx_length) +{ + gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); + if (driver_entry) { + if (driver_entry->driver->set_response_handler) { + return driver_entry->driver->set_response_handler(device, tx, tx_length, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_i2c_slave_register_driver(const gs_i2c_slave_driver_entry_t * driver_entry) +{ + GS_CHECK_ARG(driver_entry != NULL); + GS_CHECK_ARG(driver_entry->driver != NULL); + + gs_i2c_slave_driver_handle_t * handle; + for (uint8_t i = 0; i < MAX_DRIVERS; i++) { + handle = &slave_drivers[i]; + if (handle->in_use == false) { + handle->entry = *driver_entry; + handle->in_use = true; + max_index_slave_in_use = i; + return GS_OK; + } + } + + /* Not enough space in buffer */ + return GS_ERROR_FULL; +} diff --git a/gomspace/libutil/src/linux/drivers/spi/spi.c b/gomspace/libutil/src/linux/drivers/spi/spi.c new file mode 100644 index 00000000..6756482c --- /dev/null +++ b/gomspace/libutil/src/linux/drivers/spi/spi.c @@ -0,0 +1,137 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +#define MAX_DRIVERS 20 + +typedef struct { + gs_spi_master_driver_entry_t entry; + bool in_use; +} gs_spi_master_driver_handle_t; + +typedef struct { + gs_spi_slave_driver_entry_t entry; + bool in_use; +} gs_spi_slave_driver_handle_t; + +static gs_spi_master_driver_handle_t master_drivers[MAX_DRIVERS]; +static gs_spi_slave_driver_handle_t slave_drivers[MAX_DRIVERS]; + +static uint8_t max_index_master_in_use = 0; +static uint8_t max_index_slave_in_use = 0; + +static inline gs_spi_master_driver_entry_t * gs_master_find_driver_entry(uint8_t slave) +{ + gs_spi_master_driver_handle_t * handle; + for (int i = max_index_master_in_use; i >= 0; i--) { + handle = &master_drivers[i]; + if (((slave == handle->entry.slave) || (handle->entry.slave == GS_SPI_ALL_SLAVES)) && (handle->in_use == true)) { + return &handle->entry; + } + } + return NULL; +} + +gs_error_t gs_spi_master_transaction(uint8_t slave, const void * tx, void * rx, size_t size, int timeout_ms) +{ + gs_spi_master_trans_t trans = {.tx = tx, .rx = rx, .size = size}; + return gs_spi_master_transactions(slave, &trans, 1, timeout_ms); +} + +gs_error_t gs_spi_master_transactions(uint8_t slave, gs_spi_master_trans_t *trans, size_t count, int timeout_ms) +{ + gs_spi_master_driver_entry_t * driver_entry = gs_master_find_driver_entry(slave); + if (driver_entry) { + if (driver_entry->driver->master_transactions_handler) { + return driver_entry->driver->master_transactions_handler(slave, trans, count, timeout_ms, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_spi_master_register_driver(const gs_spi_master_driver_entry_t * driver_entry) +{ + GS_CHECK_ARG(driver_entry != NULL); + GS_CHECK_ARG(driver_entry->driver != NULL); + + gs_spi_master_driver_handle_t * handle; + for (uint8_t i = 0; i < MAX_DRIVERS; i++) { + handle = &master_drivers[i]; + if (handle->in_use == false) { + handle->entry = *driver_entry; + handle->in_use = true; + max_index_master_in_use = i; + return GS_OK; + } + } + + /* Not enough space in buffer */ + return GS_ERROR_FULL; +} + +static inline gs_spi_slave_driver_entry_t * gs_slave_find_driver_entry(uint8_t device) +{ + gs_spi_slave_driver_handle_t * handle; + for (int i = max_index_slave_in_use; i >= 0; i--) { + handle = &slave_drivers[i]; + if (((device == handle->entry.device) || (handle->entry.device == GS_SPI_ALL_DEVICES)) + && (handle->in_use == true)) { + return &handle->entry; + } + } + return NULL; +} + +gs_error_t gs_spi_slave_start(uint8_t device) +{ + gs_spi_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); + if (driver_entry) { + if (driver_entry->driver->start_handler) { + return driver_entry->driver->start_handler(device, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_spi_slave_set_rx(uint8_t device, gs_spi_slave_receive_t rx) +{ + gs_spi_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); + if (driver_entry) { + if (driver_entry->driver->set_rx_handler) { + return driver_entry->driver->set_rx_handler(device, rx, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_spi_slave_set_response(uint8_t device, size_t offset, const uint8_t * tx, size_t size) +{ + gs_spi_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); + if (driver_entry) { + if (driver_entry->driver->set_response_handler) { + return driver_entry->driver->set_response_handler(device, offset, tx, size, driver_entry->driver_data); + } + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_spi_slave_register_driver(const gs_spi_slave_driver_entry_t * driver_entry) +{ + GS_CHECK_ARG(driver_entry != NULL); + GS_CHECK_ARG(driver_entry->driver != NULL); + + gs_spi_slave_driver_handle_t * handle; + for (uint8_t i = 0; i < MAX_DRIVERS; i++) { + handle = &slave_drivers[i]; + if (handle->in_use == false) { + handle->entry = *driver_entry; + handle->in_use = true; + max_index_slave_in_use = i; + return GS_OK; + } + } + /* Not enough space in buffer */ + return GS_ERROR_FULL; +} diff --git a/gomspace/libutil/src/linux/drivers/sys/memory.c b/gomspace/libutil/src/linux/drivers/sys/memory.c new file mode 100644 index 00000000..8def9988 --- /dev/null +++ b/gomspace/libutil/src/linux/drivers/sys/memory.c @@ -0,0 +1,30 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +gs_error_t gs_mem_get_int_ram_stat(gs_mem_ram_stat_t * ram_stat) +{ + return GS_ERROR_NOT_SUPPORTED; +} + +gs_error_t gs_mem_get_ext_ram_stat(gs_mem_ram_stat_t * ram_stat) +{ + struct sysinfo info; + int res = sysinfo(&info); + if (res != GS_OK) { + return res; + } + + ram_stat->total = info.totalram; + ram_stat->max_available = -1; + ram_stat->min_available = -1; + ram_stat->available = info.freeram; + + return GS_OK; +} + +gs_mem_ram_type_t gs_mem_get_ram_default() +{ + return GS_MEM_RAM_TYPE_EXTERNAL; +} diff --git a/gomspace/libutil/src/linux/function.c b/gomspace/libutil/src/linux/function.c new file mode 100644 index 00000000..9e0f7c0f --- /dev/null +++ b/gomspace/libutil/src/linux/function.c @@ -0,0 +1,41 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +typedef struct { + const char * short_name; + const char * long_name; + gs_function_t function; +} gs_function_register_t; + +static gs_function_register_t registry[10]; + +gs_error_t gs_function_register(const char * short_name, const char * long_name, gs_function_t function) +{ + for (unsigned int i = 0; i < GS_ARRAY_SIZE(registry); ++i) { + gs_function_register_t * cb = ®istry[i]; + if ((cb->short_name == NULL) && (cb->long_name == NULL)) { + cb->short_name = short_name; + cb->long_name = long_name; + cb->function = function; + return GS_OK; + } + } + return GS_ERROR_FULL; +} + +gs_error_t gs_function_invoke(const char * name, void * arg) +{ + for (unsigned int i = 0; i < GS_ARRAY_SIZE(registry); ++i) { + gs_function_register_t * cb = ®istry[i]; + if ((gs_string_empty(cb->short_name) == false) && (strcasecmp(cb->short_name, name) == 0)) { + return (cb->function)(arg); + } + if ((gs_string_empty(cb->long_name) == false) && (strcasecmp(cb->long_name, name) == 0)) { + return (cb->function)(arg); + } + } + + return GS_ERROR_NOT_IMPLEMENTED; +} diff --git a/gomspace/libutil/src/linux/mutex.c b/gomspace/libutil/src/linux/mutex.c new file mode 100644 index 00000000..00336510 --- /dev/null +++ b/gomspace/libutil/src/linux/mutex.c @@ -0,0 +1,59 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +gs_error_t gs_mutex_create(gs_mutex_t * mutex) +{ + if (mutex == NULL) { + return GS_ERROR_ARG; + } + + *mutex = malloc(sizeof(pthread_mutex_t)); + if (*mutex == NULL) { + return GS_ERROR_ALLOC; + } + + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + int res = pthread_mutex_init(*mutex, &attr); + if (res < 0) { + res = gs_error(errno); + free(*mutex); + } + + return res; +} + +gs_error_t gs_mutex_destroy(gs_mutex_t mutex) +{ + int res = GS_OK; + if (mutex) { + res = pthread_mutex_destroy(mutex); + if (res < 0) { + res = gs_error(errno); + } + free(mutex); + } + return res; +} + +gs_error_t gs_mutex_lock(gs_mutex_t mutex) +{ + int res = pthread_mutex_lock(mutex); + if (res < 0) { + res = gs_error(errno); + } + return res; +} + +gs_error_t gs_mutex_unlock(gs_mutex_t mutex) +{ + int res = pthread_mutex_unlock(mutex); + if (res < 0) { + res = gs_error(errno); + } + return res; +} diff --git a/gomspace/libutil/src/linux/queue.c b/gomspace/libutil/src/linux/queue.c new file mode 100644 index 00000000..cb477f70 --- /dev/null +++ b/gomspace/libutil/src/linux/queue.c @@ -0,0 +1,217 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + * Inspired by c-pthread-queue by Matthew Dickinson + * http://code.google.com/p/c-pthread-queue/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PTHREAD_QUEUE_ARG GS_ERROR_ARG +#define PTHREAD_QUEUE_EMPTY GS_ERROR_NOT_FOUND +#define PTHREAD_QUEUE_FULL GS_ERROR_FULL +#define PTHREAD_QUEUE_TIMEOUT GS_ERROR_TIMEOUT +#define PTHREAD_QUEUE_OK GS_OK + +typedef struct gs_pthread_queue { + uint8_t * buffer; + size_t size; + size_t item_size; + size_t items; + size_t in; + size_t out; + pthread_mutex_t mutex; + pthread_cond_t cond_full; + pthread_cond_t cond_empty; +} pthread_queue_t; + +static pthread_queue_t * pthread_queue_create(size_t length, size_t item_size) +{ + pthread_queue_t * q = malloc(sizeof(pthread_queue_t)); + + if (q != NULL) { + q->buffer = malloc(length*item_size); + if (q->buffer != NULL) { + q->size = length; + q->item_size = item_size; + q->items = 0; + q->in = 0; + q->out = 0; + if (pthread_mutex_init(&(q->mutex), NULL) || pthread_cond_init(&(q->cond_full), NULL) || pthread_cond_init(&(q->cond_empty), NULL)) { + free(q->buffer); + free(q); + q = NULL; + } + } else { + free(q); + q = NULL; + } + } + + return q; +} + +static void pthread_queue_delete(pthread_queue_t * q) +{ + if (q) { + free(q->buffer); + free(q); + } +} + +static int pthread_queue_enqueue(pthread_queue_t * queue, const void * value, uint32_t timeout) +{ + /* Calculate timeout */ + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts)) { + return PTHREAD_QUEUE_ARG; + } + + uint32_t sec = timeout / 1000; + uint32_t nsec = (timeout - 1000 * sec) * 1000000; + + ts.tv_sec += sec; + + if (ts.tv_nsec + nsec > 1000000000) + ts.tv_sec++; + + ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; + + /* Get queue lock */ + pthread_mutex_lock(&(queue->mutex)); + + while (queue->items == queue->size) { + int ret = -1; + if (timeout) { + ret = pthread_cond_timedwait(&(queue->cond_full), &(queue->mutex), &ts); + } + if (ret) { + pthread_mutex_unlock(&(queue->mutex)); + return PTHREAD_QUEUE_TIMEOUT; + } + } + + /* Coby object from input buffer */ + memcpy(queue->buffer+(queue->in * queue->item_size), value, queue->item_size); + queue->items++; + queue->in = (queue->in + 1) % queue->size; + pthread_mutex_unlock(&(queue->mutex)); + + /* Nofify blocked threads */ + pthread_cond_broadcast(&(queue->cond_empty)); + + return PTHREAD_QUEUE_OK; +} + +static int pthread_queue_dequeue(pthread_queue_t * queue, void * buf, uint32_t timeout) +{ + /* Calculate timeout */ + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts)) { + return PTHREAD_QUEUE_ARG; + } + + uint32_t sec = timeout / 1000; + uint32_t nsec = (timeout - 1000 * sec) * 1000000; + + ts.tv_sec += sec; + + if (ts.tv_nsec + nsec > 1000000000) + ts.tv_sec++; + + ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; + + /* Get queue lock */ + pthread_mutex_lock(&(queue->mutex)); + while (queue->items == 0) { + int ret = -1; + if (timeout) { + ret = pthread_cond_timedwait(&(queue->cond_empty), &(queue->mutex), &ts); + } + if (ret) { + pthread_mutex_unlock(&(queue->mutex)); + return PTHREAD_QUEUE_TIMEOUT; + } + } + + /* Coby object to output buffer */ + memcpy(buf, queue->buffer+(queue->out * queue->item_size), queue->item_size); + queue->items--; + queue->out = (queue->out + 1) % queue->size; + pthread_mutex_unlock(&(queue->mutex)); + + /* Nofify blocked threads */ + pthread_cond_broadcast(&(queue->cond_full)); + + return PTHREAD_QUEUE_OK; +} + +static size_t pthread_queue_items(pthread_queue_t * queue) +{ + pthread_mutex_lock(&(queue->mutex)); + size_t items = queue->items; + pthread_mutex_unlock(&(queue->mutex)); + return items; +} + +gs_error_t gs_queue_create(size_t items, size_t item_size, gs_queue_t * queue) +{ + if (queue == NULL) { + return GS_ERROR_ARG; + } + pthread_queue_t * q = pthread_queue_create(items, item_size); + if (q == NULL) { + return GS_ERROR_ALLOC; + } + *queue = q; + return GS_OK; +} + +gs_error_t gs_queue_destroy(gs_queue_t queue) +{ + pthread_queue_delete(queue); + return GS_OK; +} + +gs_error_t gs_queue_enqueue(gs_queue_t queue, const void *value, int timeout_ms) +{ + return pthread_queue_enqueue(queue, value, (timeout_ms >= 0) ? timeout_ms : INT_MAX); +} + +gs_error_t gs_queue_enqueue_isr(gs_queue_t queue, const void * value, gs_context_switch_t * cswitch) +{ + (void) cswitch; + gs_error_t error = gs_queue_enqueue(queue, value, 0); + return (error != GS_ERROR_TIMEOUT) ? error : GS_ERROR_FULL; +} + +gs_error_t gs_queue_dequeue(gs_queue_t queue, int timeout_ms, void *buf) +{ + return pthread_queue_dequeue(queue, buf, (timeout_ms >= 0) ? timeout_ms : INT_MAX); +} + +gs_error_t gs_queue_dequeue_isr(gs_queue_t queue, gs_context_switch_t * cswitch, void *buf) +{ + (void) cswitch; + gs_error_t error = gs_queue_dequeue(queue, 0, buf); + return (error != GS_ERROR_TIMEOUT) ? error : GS_ERROR_NOT_FOUND; +} + +unsigned int gs_queue_size(gs_queue_t queue) +{ + if (queue) { + return pthread_queue_items(queue); + } + return 0; +} + +unsigned int gs_queue_size_isr(gs_queue_t queue) +{ + return gs_queue_size(queue); +} diff --git a/gomspace/libutil/src/linux/rtc.c b/gomspace/libutil/src/linux/rtc.c new file mode 100644 index 00000000..ff241d58 --- /dev/null +++ b/gomspace/libutil/src/linux/rtc.c @@ -0,0 +1,78 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +static gs_error_t gs_rtc_get(void * driver_data, gs_timestamp_t * return_time) +{ + if (return_time == NULL) { + return GS_ERROR_ARG; + } + + return_time->tv_sec = 0; + return_time->tv_nsec = 0; + + int fd = open("/dev/rtc", O_RDONLY | O_CLOEXEC); + if (fd < 0) { + return gs_error(errno); + } + + struct tm tm; + memset(&tm, 0, sizeof(tm)); + int res = ioctl(fd, RTC_RD_TIME, &tm); + close(fd); + if (res < 0) { + return gs_error(errno); + } + + time_t time = mktime(&tm); + if (time < 0) { + return GS_ERROR_DATA; + } + + return_time->tv_sec = (uint32_t) time; + + return GS_OK; +} + +static gs_error_t gs_rtc_set(void * driver_data, const gs_timestamp_t * set_time) +{ + if (set_time == NULL) { + return GS_ERROR_ARG; + } + + int fd = open("/dev/rtc", O_RDONLY | O_CLOEXEC); + if (fd < 0) { + return gs_error(errno); + } + + const time_t now = set_time->tv_sec; + struct tm tm; + gmtime_r(&now, &tm); + int res = ioctl(fd, RTC_SET_TIME, &tm); + close(fd); + if (res < 0) { + return gs_error(errno); + } + + return GS_OK; +} + +gs_error_t gs_rtc_register_linux(bool get, bool set) +{ + static gs_rtc_driver_t rtc_driver; + if (get) { + rtc_driver.get_time = gs_rtc_get; + } + if (set) { + rtc_driver.set_time = gs_rtc_set; + } + return gs_rtc_register(&rtc_driver, NULL); +} diff --git a/gomspace/libutil/src/linux/sem.c b/gomspace/libutil/src/linux/sem.c new file mode 100644 index 00000000..b4d2c09d --- /dev/null +++ b/gomspace/libutil/src/linux/sem.c @@ -0,0 +1,89 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include + +gs_error_t gs_sem_create(unsigned int initialValue, gs_sem_t * sem) +{ + if (sem == NULL) { + return GS_ERROR_ARG; + } + + *sem = malloc(sizeof(sem_t)); + if (*sem == NULL) { + return GS_ERROR_ALLOC; + } + + int res = sem_init(*sem, 0, initialValue); + if (res < 0) { + res = gs_error(errno); + free(*sem); + } + + return res; +} + +gs_error_t gs_sem_destroy(gs_sem_t sem) +{ + int res = GS_OK; + if (sem) { + res = sem_destroy(sem); + if (res < 0) { + res = gs_error(errno); + } + free(sem); + } + return res; +} + +gs_error_t gs_sem_wait(gs_sem_t sem, int timeout_ms) +{ + int res; + + if (timeout_ms < 0) { + res = sem_wait(sem); + } else { + struct timespec ts; + res = clock_gettime(CLOCK_REALTIME, &ts); + if (res == 0) { + const uint32_t ms = (uint32_t)timeout_ms; + uint32_t sec = ms / 1000; + uint32_t nsec = (ms - (1000 * sec)) * 1000000; + + ts.tv_sec += sec; + + if (ts.tv_nsec + nsec >= 1000000000) { + ts.tv_sec++; + } + + ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; + + res = sem_timedwait(sem, &ts); + } + } + if (res < 0) { + res = gs_error(errno); + } + return res; +} + +gs_error_t gs_sem_post(gs_sem_t sem) +{ + int res = sem_post(sem); + if (res < 0) { + res = gs_error(errno); + } + return res; +} + +gs_error_t gs_sem_post_isr(gs_sem_t sem, gs_context_switch_t * cswitch) +{ + (void) cswitch; + int res = sem_post(sem); + if (res < 0) { + res = gs_error(errno); + } + return res; +} diff --git a/gomspace/libutil/src/linux/signal.c b/gomspace/libutil/src/linux/signal.c new file mode 100644 index 00000000..826bc325 --- /dev/null +++ b/gomspace/libutil/src/linux/signal.c @@ -0,0 +1,38 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +static void gs_signal_default_handler(int signo, siginfo_t *si, void *context) +{ + exit(GS_EXITCODE_SIGNAL(signo)); // ensure atexit are invoked +} + +gs_error_t gs_signal_catch(int signal, gs_signal_handler handler) +{ + if (handler == NULL) { + handler = gs_signal_default_handler; + } + struct sigaction sa = { .sa_flags = SA_SIGINFO, + .sa_sigaction = handler}; + if (sigemptyset(&sa.sa_mask)) { + return GS_ERROR_UNKNOWN; + } + if (sigaction(signal, &sa, NULL)) { + return GS_ERROR_UNKNOWN; + } + return GS_OK; +} + +gs_error_t gs_signal_ignore(int signal) +{ + struct sigaction sa = { .sa_flags = 0, + .sa_handler = SIG_IGN}; // handle signal by ignoring + if (sigemptyset(&sa.sa_mask)) { + return GS_ERROR_UNKNOWN; + } + if (sigaction(signal, &sa, NULL)) { + return GS_ERROR_UNKNOWN; + } + return GS_OK; +} diff --git a/gomspace/libutil/src/linux/stdio.c b/gomspace/libutil/src/linux/stdio.c new file mode 100644 index 00000000..0fa052b7 --- /dev/null +++ b/gomspace/libutil/src/linux/stdio.c @@ -0,0 +1,36 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +gs_error_t gs_stdio_putchar(int ch) +{ + const int res = putchar(ch); + if (res < 0) { + return GS_ERROR_IO; + } + return GS_OK; +} + +gs_error_t gs_stdio_getchar_timed(int timeout_ms, int * ch) +{ + struct pollfd fds = {STDIN_FILENO, POLLIN, 0}; + const int res = poll(&fds, 1, timeout_ms); + + if (res == 0) { + return GS_ERROR_TIMEOUT; + } + + if ((res > 0) && (fds.revents & POLLIN)) { + int tmp = getchar(); + if (tmp >= 0) { + if (ch) { + *ch = tmp; + } + return GS_OK; + } + } + + return GS_ERROR_IO; +} diff --git a/gomspace/libutil/src/linux/sysfs_helper.c b/gomspace/libutil/src/linux/sysfs_helper.c new file mode 100644 index 00000000..2cdb390a --- /dev/null +++ b/gomspace/libutil/src/linux/sysfs_helper.c @@ -0,0 +1,48 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +gs_error_t gs_sysfs_write_file(const char *path, const char *value) +{ + log_trace("sysfs: write %s to %s", value, path); + + int fd = open(path, O_WRONLY); + if (fd < 0) { + return GS_ERROR_HANDLE; + } + + size_t len = strlen(value); + ssize_t bytes = write(fd, value, len); + close(fd); + if (bytes < 0) { + return GS_ERROR_NO_DATA; + } + + return (len == (size_t)bytes) ? GS_OK : GS_ERROR_NO_DATA; +} + +gs_error_t gs_sysfs_read_file(const char *path, char *value, size_t len) +{ + log_trace("sysfs: read %s", path); + + int fd = open(path, O_RDONLY); + if (fd < 0) { + return GS_ERROR_HANDLE; + } + + ssize_t bytes = read(fd, value, len); + close(fd); + if (bytes < 0) { + return GS_ERROR_DATA; + } + + return GS_OK; +} diff --git a/gomspace/libutil/src/linux/thread.c b/gomspace/libutil/src/linux/thread.c new file mode 100644 index 00000000..43de1815 --- /dev/null +++ b/gomspace/libutil/src/linux/thread.c @@ -0,0 +1,89 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +gs_error_t gs_thread_create(const char * const name, + gs_thread_func_t func, + void * parameter, + size_t stack_size, + gs_thread_priority_t priority, + uint32_t flags, + gs_thread_t * return_handle) +{ + gs_time_uptime(); // force initialize of static offset + + pthread_attr_t attr; + int res = pthread_attr_init(&attr); + if (res) { + return GS_ERROR_ALLOC; + } + + if (flags & GS_THREAD_CREATE_JOINABLE) { + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + } else { + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + } + + gs_thread_t handle; + res = pthread_create(&handle, &attr, func, parameter); + pthread_attr_destroy(&attr); + if (res) { + return GS_ERROR_ALLOC; + } + + if (return_handle) { + *return_handle = handle; + } + + return GS_OK; +} + +gs_error_t gs_thread_create_with_stack(const char * const name, + gs_thread_func_t func, + void * parameter, + size_t stack_size, + gs_stack_type_t *stack, + gs_thread_priority_t priority, + uint32_t flags, + gs_thread_t * return_handle) +{ + return gs_thread_create(name, func, parameter, stack_size, priority, flags, return_handle); +} + +void gs_thread_exit(void * exitValue) +{ + pthread_exit(exitValue); +} + +void gs_thread_sleep_ms(uint32_t time_ms) +{ + gs_time_sleep_ms(time_ms); +} + +gs_error_t gs_thread_join(gs_thread_t thread, void ** return_retval) +{ + gs_error_t error = GS_ERROR_ARG; + void * retval = 0; + if (thread) { + int res = pthread_join(thread, &retval); + if (res == 0) { + error = GS_OK; + } else { + retval = 0; + } + } + if (return_retval) { + *return_retval = retval; + } + return error; +} + +void gs_thread_block(void) +{ + /* Wait here forever */ + for (;;) { + gs_time_sleep_ms(10000); + } +} diff --git a/gomspace/libutil/src/linux/time.c b/gomspace/libutil/src/linux/time.c new file mode 100644 index 00000000..46377feb --- /dev/null +++ b/gomspace/libutil/src/linux/time.c @@ -0,0 +1,53 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +uint32_t gs_time_rel_ms(void) +{ + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { + return 0; + } + + return (uint32_t)((ts.tv_sec * 1000) + (ts.tv_nsec/1000000)); +} + +uint32_t gs_time_rel_ms_isr(void) +{ + return gs_time_rel_ms(); +} + +static uint32_t uptime_offset = 0; +uint32_t gs_time_uptime(void) +{ + uint32_t seconds; + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { + seconds = 0; + } else { + seconds = (uint32_t) ts.tv_sec; + } + if (uptime_offset == 0) { + uptime_offset = seconds; + } + return (seconds - uptime_offset); +} + +void gs_time_sleep_ns(uint64_t time_ns) +{ + struct timespec ts; + ts.tv_sec = (time_ns / GS_TIMESTAMP_NSEC_PER_SEC); + ts.tv_nsec = (time_ns % GS_TIMESTAMP_NSEC_PER_SEC); + + // improvement: check return code (INTR) and use remaining. + nanosleep(&ts, NULL); +} + +void gs_time_sleep_ms(uint32_t time_ms) +{ + uint64_t ns = time_ms; + ns *= 1000000LL; + gs_time_sleep_ns( ns); +} diff --git a/gomspace/libutil/src/lock.c b/gomspace/libutil/src/lock.c new file mode 100644 index 00000000..76be91bd --- /dev/null +++ b/gomspace/libutil/src/lock.c @@ -0,0 +1,30 @@ +/* Copyright (c) 2013-2019 GomSpace A/S. All rights reserved. */ + +#include "lock.h" +#include + +static gs_mutex_t gs_lock; + +gs_error_t gs_lock_init(void) +{ + if (gs_lock == NULL) { + return gs_mutex_create(&gs_lock); + } + return GS_OK; +} + +gs_error_t gs_lock_lock(void) +{ + if (gs_lock == NULL) { + gs_error_t error = gs_lock_init(); + if (error) { + return error; + } + } + return gs_mutex_lock(gs_lock); +} + +gs_error_t gs_lock_unlock(void) +{ + return gs_mutex_unlock(gs_lock); +} diff --git a/gomspace/libutil/src/lock.h b/gomspace/libutil/src/lock.h new file mode 100644 index 00000000..b22841e8 --- /dev/null +++ b/gomspace/libutil/src/lock.h @@ -0,0 +1,14 @@ +/* Copyright (c) 2013-2019 GomSpace A/S. All rights reserved. */ +/** + @file + + Basic/core locking. + + Use for rare read/write locking, e.g. protecting register/de-regsiter functions. +*/ + +#include + +gs_error_t gs_lock_init(void); +gs_error_t gs_lock_lock(void); +gs_error_t gs_lock_unlock(void); diff --git a/gomspace/libutil/src/log/appender/console.c b/gomspace/libutil/src/log/appender/console.c new file mode 100644 index 00000000..818248b3 --- /dev/null +++ b/gomspace/libutil/src/log/appender/console.c @@ -0,0 +1,88 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +// generated by waf configure -> GS_LOG_ENABLE_ISR_LOGS +#include + +static gs_log_appender_console_cb_t g_console_log_cb = NULL; +static gs_mutex_t g_log_console_mutex = NULL; + +gs_error_t gs_log_console_append_init(gs_log_appender_t *appender) +{ + gs_error_t ret = GS_OK; + if (g_log_console_mutex == NULL) { + ret = gs_mutex_create(&g_log_console_mutex); + if (ret != GS_OK) { + g_log_console_mutex = NULL; + } + } + return ret; +} + +static void gs_log_console_append_isr(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) +{ + va_list my_va; + va_copy(my_va, va); + + const char * color = gs_log_level_to_color_begin(level); + const char * end_color = gs_log_level_to_color_end(); + const char clevel = gs_log_level_to_char(level); + + // print log + printf("%s%04"PRIu32".%06"PRIu32" %c %s: ", color, ts->tv_sec, ts->tv_nsec / 1000, clevel, group->name); + GS_PGM_VPRINTF(format, my_va); + printf("%s\r\n", end_color); + + va_end(my_va); +} + +static void gs_log_console_append(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) +{ + if (g_console_log_cb) + return g_console_log_cb(appender, level, group, ts, format, va); + + if (g_log_console_mutex) { + gs_mutex_lock(g_log_console_mutex); + } + + gs_log_console_append_isr(appender, level, group, ts, format, va); + + if (g_log_console_mutex) { + gs_mutex_unlock(g_log_console_mutex); + } +} + +static void gs_log_console_append_get_info(gs_log_appender_t *appender, char *info_str, uint8_t str_size) +{ + if (!info_str) { + return; + } + + snprintf(info_str, str_size, "Prints on stdout"); +} + +gs_error_t gs_log_appender_console_set_cb(gs_log_appender_console_cb_t cb) +{ + g_console_log_cb = cb; + return GS_OK; +} + +static const gs_log_appender_driver_t console_appender_driver = { + .init = gs_log_console_append_init, + .append = gs_log_console_append, +#ifdef GS_LOG_ENABLE_ISR_LOGS + .append_isr = gs_log_console_append_isr, +#else + .append_isr = 0, +#endif + .info = gs_log_console_append_get_info, +}; + +gs_log_appender_t gs_log_appender_console = { + .name = "console", + .drv = &console_appender_driver, + .drv_config = 0, + .mask = LOG_ALL_MASK, +}; diff --git a/gomspace/libutil/src/log/appender/simple_file.c b/gomspace/libutil/src/log/appender/simple_file.c new file mode 100644 index 00000000..f74a19e7 --- /dev/null +++ b/gomspace/libutil/src/log/appender/simple_file.c @@ -0,0 +1,117 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#ifndef __AVR__ +#include +#include +#include + +#include +#include + +typedef struct simple_file_drv_data { + FILE *fp; + gs_mutex_t mutex; +} simple_file_drv_data_t; + +static gs_error_t gs_log_simple_file_init(gs_log_appender_t *appender) +{ + const gs_log_appender_simple_file_config_t *config = appender->drv_config; + + if (config == NULL || gs_string_empty(config->filename)) { + return GS_ERROR_ARG; + } + + simple_file_drv_data_t *drv_data = appender->drv_data; + if (drv_data == NULL) { + drv_data = calloc(1, sizeof(*drv_data)); + if (drv_data == NULL) { + return GS_ERROR_ALLOC; + } + } + + /* If file is already open - Close it first */ + if (drv_data->fp) { + gs_mutex_lock(drv_data->mutex); + fclose(drv_data->fp); + drv_data->fp = NULL; + gs_mutex_unlock(drv_data->mutex); + gs_mutex_destroy(drv_data->mutex); + } + + const char * mode = config->truncate ? "w" : "a"; + + drv_data->fp = fopen(config->filename, mode); + if (drv_data->fp == NULL) { + log_error("%s: failed to open log-file: [%s], mode: %s", __FUNCTION__, config->filename, mode); + free(drv_data); + drv_data = 0; + return GS_ERROR_IO; + } + + gs_mutex_create(&drv_data->mutex); + appender->drv_data = drv_data; /* Set driver data on appender */ + return GS_OK; +} + +static void gs_log_simple_file_append(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) +{ + va_list my_va; + va_copy(my_va, va); + + const gs_log_appender_simple_file_config_t *config = appender->drv_config; + simple_file_drv_data_t *drv_data = appender->drv_data; + if (drv_data == 0) { + va_end(my_va); + return; + } + + const char clevel = gs_log_level_to_char(level); + + const time_t t = ts->tv_sec; + struct tm result; + const char * tzone; + if (config->use_local_time) { + localtime_r(&t, &result); + tzone = ""; + } else { + gmtime_r(&t, &result); + tzone = "Z"; + } + + if (drv_data->mutex) { + gs_mutex_lock(drv_data->mutex); + } + { + fprintf(drv_data->fp, "%04d-%02d-%02d %02d:%02d:%02d.%06"PRIu32"%s %c %s: ", + result.tm_year + 1900, result.tm_mon + 1, result.tm_mday, + result.tm_hour, result.tm_min, result.tm_sec, + ts->tv_nsec / 1000, tzone, clevel, group->name); + vfprintf(drv_data->fp, format, my_va); + fprintf(drv_data->fp, "\r\n"); + fflush(drv_data->fp); + } + if (drv_data->mutex) { + gs_mutex_unlock(drv_data->mutex); + } + + va_end(my_va); +} + +static void gs_log_simple_file_append_info(gs_log_appender_t *appender, char *info_str, uint8_t str_size) +{ + if (!info_str) { + return; + } + + const gs_log_appender_simple_file_config_t *config = appender->drv_config; + snprintf(info_str, str_size, "Writes to file \"%s\"", config->filename); +} + +const gs_log_appender_driver_t gs_log_appender_simple_file_driver = { + .init = gs_log_simple_file_init, + .append = gs_log_simple_file_append, + .append_isr = 0, + .info = gs_log_simple_file_append_info, +}; + +#endif diff --git a/gomspace/libutil/src/log/commands.c b/gomspace/libutil/src/log/commands.c new file mode 100644 index 00000000..85ac7ae5 --- /dev/null +++ b/gomspace/libutil/src/log/commands.c @@ -0,0 +1,392 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include "local.h" +#include + + +// iterator context +typedef struct { + gs_command_context_t * ctx; + gs_log_group_t * first; + gs_log_appender_t * first_appender; + bool completer; + bool detailed; +} iter_group_t; + +#define FORMAT_BUF_SIZE 10 +static const char * format_mask(uint8_t mask, char * buf) +{ + snprintf(buf, FORMAT_BUF_SIZE, "%c%c%c%c%c%c", + (mask & LOG_ERROR_MASK) ? 'E' : '.', + (mask & LOG_WARNING_MASK) ? 'W' : '.', + (mask & LOG_NOTICE_MASK) ? 'N' : '.', + (mask & LOG_INFO_MASK) ? 'I' : '.', + (mask & LOG_DEBUG_MASK) ? 'D' : '.', + (mask & LOG_TRACE_MASK) ? 'T' : '.'); + return buf; +} + +static bool iter_print_group_appenders(void * ctx_in, gs_log_appender_t * appender) +{ + gs_bytebuffer_t *bb = ctx_in; + gs_bytebuffer_printf(bb, "%s,", appender->name); + return true; +} + +static bool iter_print_group(void * ctx_in, gs_log_group_t * group) +{ + iter_group_t * ctx = ctx_in; + char level_mask[FORMAT_BUF_SIZE]; + if (!ctx->completer) { + char appender_str[128] = "\0"; + gs_bytebuffer_t bb; + gs_bytebuffer_init(&bb, appender_str, sizeof(appender_str)); + gs_log_group_appender_iterate(group, &bb, iter_print_group_appenders); + if (ctx->detailed) { + gs_command_set_output_printf(ctx->ctx, group->name, "category", "0x%08x", group->category); + gs_command_set_output_printf(ctx->ctx, group->name, "mask", "%-6s (0x%02x)", format_mask(group->mask, level_mask), group->mask); + gs_command_set_output_printf(ctx->ctx, group->name, "appenders", appender_str); + } else { + gs_command_set_output_printf(ctx->ctx, NULL, NULL, "%-15s %-6s %s", group->name, format_mask(group->mask, level_mask), appender_str); + } + } else { + fprintf(ctx->ctx->out, " %-15s %-6s\r\n", + group->name, + format_mask(group->mask, level_mask)); + } + return true; +} + +static int cmd_log_group_list(gs_command_context_t * ctx) +{ + iter_group_t iter = {.ctx = ctx, .completer = false}; + + if (ctx->argc > 1) { + iter.detailed = true; + gs_log_group_iterate(ctx->argv[1], &iter, iter_print_group); + } else { + fprintf(ctx->out, "Group Mask Appenders\r\n"); + gs_log_group_iterate("*", &iter, iter_print_group); + } + return GS_OK; +} + +static bool iter_print_appender(void * ctx_in, gs_log_appender_t * appender) +{ + iter_group_t * ctx = ctx_in; + char level_mask[FORMAT_BUF_SIZE]; + if (!ctx->completer) { + if (ctx->detailed) { + gs_command_set_output_printf(ctx->ctx, appender->name, "mask", "%-6s (0x%02x)", format_mask(appender->mask, level_mask), appender->mask); + + if (appender->drv->info) { + char info_str[100]; + appender->drv->info(appender, info_str, sizeof(info_str)); + gs_command_set_output(ctx->ctx, appender->name, "info", info_str); + } + } else { + gs_command_set_output_printf(ctx->ctx, NULL, NULL, "%-15s %-6s", appender->name, format_mask(appender->mask, level_mask)); + } + } else { + fprintf(ctx->ctx->out, " %-15s %-6s\r\n", + appender->name, + format_mask(appender->mask, level_mask)); + } + return true; +} + +static int cmd_log_appender_list(gs_command_context_t * ctx) +{ + iter_group_t iter = {.ctx = ctx, .completer = false}; + + if (ctx->argc > 1) { + iter.detailed = true; + gs_log_appender_iterate(ctx->argv[1], &iter, iter_print_appender); + } else { + fprintf(ctx->out, "Appender Mask\r\n"); + gs_log_appender_iterate("*", &iter, iter_print_appender); + } + return GS_OK; +} + +typedef gs_error_t (*log_get_mask_t)(const char *name, uint8_t* mask); +typedef gs_error_t (*log_set_mask_t)(const char *name, uint8_t mask); + +static int cmd_log_mask_handler(gs_command_context_t * ctx, log_get_mask_t get_mask, log_set_mask_t set_mask) +{ + /* strtok writes to the string, so we need to duplicate it to avoid writing to read-only memory */ + char strbuf[100]; + GS_STRNCPY(strbuf, ctx->argv[1]); + + char * saveptr = NULL; + char * token = strtok_r(strbuf, ",", &saveptr); + gs_error_t error = GS_OK; + while (token && (error == GS_OK)) { + + uint8_t old_mask = 0; + if (gs_log_is_group_all(token) == false) { + error = get_mask(token, &old_mask); + } + if (error == GS_OK) { + uint8_t new_mask = 0; + error = gs_log_string_to_mask(ctx->argv[2], old_mask, &new_mask); + if (error == GS_OK) { + error = set_mask(token, new_mask); + } + } + + token = strtok_r(NULL, ",", &saveptr); + } + + return error; +} + +static int cmd_log_group_mask(gs_command_context_t * ctx) +{ + return cmd_log_mask_handler(ctx, gs_log_group_get_level_mask, gs_log_group_set_level_mask); +} + +static int cmd_log_appender_mask(gs_command_context_t * ctx) +{ + return cmd_log_mask_handler(ctx, gs_log_appender_get_level_mask, gs_log_appender_set_level_mask); +} + + +#ifndef __AVR__ +static bool iter_log_completer(void *ctx_in, gs_log_group_t * group) +{ + iter_group_t * ctx = ctx_in; + unsigned int hits = gs_command_completer_add_token(ctx->ctx, group->name, false); + if (hits == 1) { + ctx->first = group; + } else { + if (hits == 2) { + fprintf(ctx->ctx->out, "\r\n"); + iter_print_group(ctx, ctx->first); + } + iter_print_group(ctx, group); + } + return true; +} + +static gs_error_t cmd_log_group_completer(gs_command_context_t * ctx, int arg_to_complete) +{ + if (arg_to_complete == 1) { + iter_group_t iter = {.ctx = ctx, .completer = true}; + char name[50]; + snprintf(name, sizeof(name), "%s*", (ctx->argc > 1) ? ctx->argv[1] : ""); + gs_log_group_iterate(name, &iter, iter_log_completer); + return GS_OK; + } + return GS_ERROR_AMBIGUOUS; +} + +static bool iter_log_appender_completer(void *ctx_in, gs_log_appender_t * appender) +{ + iter_group_t * ctx = ctx_in; + unsigned int hits = gs_command_completer_add_token(ctx->ctx, appender->name, false); + if (hits == 1) { + ctx->first_appender = appender; + } else { + if (hits == 2) { + fprintf(ctx->ctx->out, "\r\n"); + iter_print_appender(ctx, ctx->first_appender); + } + iter_print_appender(ctx, appender); + } + return true; +} + +static gs_error_t cmd_log_appender_completer(gs_command_context_t * ctx, int arg_to_complete) +{ + if (arg_to_complete == 1) { + iter_group_t iter = {.ctx = ctx, .completer = true}; + char name[50]; + snprintf(name, sizeof(name), "%s*", (ctx->argc > 1) ? ctx->argv[1] : ""); + gs_log_appender_iterate(name, &iter, iter_log_appender_completer); + return GS_OK; + } + return GS_ERROR_AMBIGUOUS; +} +#endif + +typedef struct { + gs_command_context_t *cmd_ctx; + unsigned int count; +} hist_ctx_t; + +static bool appender_history_iter(void *ctx, gs_log_level_t level, const gs_timestamp_t *ts, const char *group, const char *msg) +{ + hist_ctx_t * hist_ctx = ctx; + + /* Break iteration if history record count is reached. */ + if (hist_ctx->count-- == 0) { + return false; + } + + gs_command_set_output_printf(hist_ctx->cmd_ctx, NULL, NULL, + "%s%04"PRIu32".%06"PRIu32" %c %s: %s%s", + gs_log_level_to_color_begin(level), + ts->tv_sec, ts->tv_nsec/1000, + gs_log_level_to_char(level), + group, + msg, + gs_log_level_to_color_end()); + + return true; +} + +static int cmd_log_appender_hist(gs_command_context_t * ctx) +{ + hist_ctx_t hist_ctx = {.cmd_ctx = ctx, .count = 20}; + if (ctx->argc == 3) { + hist_ctx.count = atoi(ctx->argv[2]); + } + + return gs_log_appender_history_iterate(ctx->argv[1], &hist_ctx, appender_history_iter); +} + + +static bool iter_log_group_find(void* ctx_in, gs_log_group_t *group) +{ + gs_log_group_t **grp = ctx_in; + *grp = group; + return false; +} + +static int cmd_log_insert(gs_command_context_t * ctx) +{ + gs_log_group_t *log_group = NULL; + gs_error_t error = gs_log_group_iterate(ctx->argv[1], &log_group, iter_log_group_find); + if (error != GS_OK) { + return error; + } + + gs_log_level_t level; + error = gs_log_string_to_level(ctx->argv[2], &level); + if (error == GS_OK) { + gs_log(level, log_group, GS_PGM_STR("%s"), ctx->argv[3]); + } + + return error; +} + +static int cmd_log_color(gs_command_context_t * ctx) +{ + bool color; + gs_error_t error = gs_string_to_bool(ctx->argv[1], &color); + if (error == GS_OK) { + gs_log_set_print_color(color); + } + + return error; +} + +static const gs_command_t GS_COMMAND_SUB cmd_log_group_cmds[] = { + { + .name = "list", + .help = "list log groups", + .usage = "[group]", +#ifndef __AVR__ + .completer = cmd_log_group_completer, +#endif + .handler = cmd_log_group_list, + .mandatory_args = GS_COMMAND_NO_ARGS, + .optional_args = 1, + },{ + .name = "mask", + .help = "Set log group mask(s): e|w|i|d|t|stand|all|non", + .usage = "[,group] <[+-]level>[,level]", +#ifndef __AVR__ + .completer = cmd_log_group_completer, +#endif + .handler = cmd_log_group_mask, + .mandatory_args = 2, + },{ + .name = "insert", + .help = "Log message", + .usage = " ", +#ifndef __AVR__ + .completer = cmd_log_group_completer, +#endif + .handler = cmd_log_insert, + .mandatory_args = 3, + },{ + .name = "color", + .help = "Enable/disable color logs (stdout)", + .usage = "", + .handler = cmd_log_color, + .mandatory_args = 1, + } +}; + +static const gs_command_t GS_COMMAND_SUB cmd_log_appender_cmds[] = { + { + .name = "list", + .help = "list log appenders", + .usage = "[appender]", +#ifndef __AVR__ + .completer = cmd_log_appender_completer, +#endif + .handler = cmd_log_appender_list, + .mandatory_args = GS_COMMAND_NO_ARGS, + .optional_args = 1, + }, { + .name = "mask", + .help = "Set log appender mask(s): e|w|i|d|t|stand|all|non", + .usage = "[,appender] <[+-]level>[,level]", +#ifndef __AVR__ + .completer = cmd_log_appender_completer, +#endif + .handler = cmd_log_appender_mask, + .mandatory_args = 2, + }, { + .name = "hist", + .help = "Show log appender history", + .usage = " [cnt]", +#ifndef __AVR__ + .completer = cmd_log_appender_completer, +#endif + .handler = cmd_log_appender_hist, + .mandatory_args = 1, + .optional_args = 1, + } +}; + +static const gs_command_t GS_COMMAND_SUB cmd_log_cmds[] = { + { + .name = "group", + .help = "log group commands", + .chain = GS_COMMAND_INIT_CHAIN(cmd_log_group_cmds), + }, { + .name = "appender", + .help = "log appender commands", + .chain = GS_COMMAND_INIT_CHAIN(cmd_log_appender_cmds), + } +}; + +static const gs_command_t GS_COMMAND_ROOT cmd_log[] = { + { + .name = "log", + .help = "log: Log system", + .chain = GS_COMMAND_INIT_CHAIN(cmd_log_cmds) + },{ + .name = "debug", + .help = "Set Log group mask(s): e|w|n|i|d|t|stand|all|off", + .usage = "[,group] <[+-]level>[,level]", +#ifndef __AVR__ + .completer = cmd_log_group_completer, +#endif + .handler = cmd_log_group_mask, + .mandatory_args = 2, + }, +}; + +gs_error_t gs_log_register_commands(void) +{ + return GS_COMMAND_REGISTER(cmd_log); +} diff --git a/gomspace/libutil/src/log/local.h b/gomspace/libutil/src/log/local.h new file mode 100644 index 00000000..654577c8 --- /dev/null +++ b/gomspace/libutil/src/log/local.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +struct gs_log_list { + union { + gs_log_group_t * group; + gs_log_appender_t *appender; + } data; + struct gs_log_list * next; +}; + +/** + De-register appender for the given log group. + + @note The de-register function is not safe when logging is active, this function + is mostly for test and should only be used in product code with extreme caution. + If logging is still not active, this function can be used safely. + + @param[in] group_name Name of the group. + @param[in] appender_name Name of appender to de-register for this group. + @return gs_error_t +*/ +gs_error_t gs_log_group_deregister_appender(const char * group_name, const char * appender_name); + +bool gs_log_is_group_all(const char * name); diff --git a/gomspace/libutil/src/log/log.c b/gomspace/libutil/src/log/log.c new file mode 100644 index 00000000..16865900 --- /dev/null +++ b/gomspace/libutil/src/log/log.c @@ -0,0 +1,705 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include "local.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "../lock.h" +#include + +#define MASK_SET 0 +#define MASK_AND 1 +#define MASK_OR 2 + +// use color in log print +static bool g_print_no_color; + +// Log Group list +GS_STATIC gs_log_list_t g_log_groups = { .data = { .group = 0} }; + +// Log Appender list +GS_STATIC gs_log_list_t g_log_appenders = { .data = { .appender = 0} }; + +// Root Log Appenders - used for holding a appender list +GS_STATIC gs_log_group_t g_log_group_root = {.name = GS_LOG_GROUP_ROOT}; + +// Default log group - always present. +GS_LOG_GROUP(LOG_DEFAULT, "default", GS_LOG_CAT_DEFAULT, LOG_ERROR_MASK | LOG_WARNING_MASK | LOG_NOTICE_MASK | LOG_INFO_MASK); + +bool gs_log_is_group_all(const char * name) +{ + return (name && ((strcasecmp(name, "*") == 0) || (strcasecmp(name, "all") == 0))); +} + +static bool iter_set_level_mask(void * ctx_in, gs_log_group_t * group) +{ + uint8_t * level_mask = ctx_in; + group->mask = *level_mask; + return true; +} + +gs_error_t gs_log_group_set_level_mask(const char * group_name, uint8_t mask) +{ + if (gs_string_empty(group_name)) { + return GS_ERROR_HANDLE; + } + + return gs_log_group_iterate(group_name, &mask, iter_set_level_mask); +} + +static bool iter_get_level_mask(void * ctx_in, gs_log_group_t * group) +{ + uint8_t * level_mask = ctx_in; + *level_mask = group->mask; + return true; +} + +gs_error_t gs_log_group_get_level_mask(const char * group_name, uint8_t *mask) +{ + if (gs_string_empty(group_name)) { + return GS_ERROR_HANDLE; + } + + gs_error_t error = gs_log_group_iterate(group_name, mask, iter_get_level_mask); + return error; +} + +gs_error_t gs_log_string_to_level(const char * str, gs_log_level_t * return_level) +{ + if (gs_string_empty(str)) { + return GS_ERROR_ARG; + } + + const size_t len = strlen(str); + gs_log_level_t level; + + if (strncasecmp(str, "trace", len) == 0) { + level = LOG_TRACE; + } else if (strncasecmp(str, "debug", len) == 0) { + level = LOG_DEBUG; + } else if (strncasecmp(str, "informational", len) == 0) { + level = LOG_INFO; + } else if (strncasecmp(str, "notice", len) == 0) { + level = LOG_NOTICE; + } else if (strncasecmp(str, "warning", len) == 0) { + level = LOG_WARNING; + } else if (strncasecmp(str, "error", len) == 0) { + level = LOG_ERROR; + } else { + return GS_ERROR_DATA; + } + + if (return_level) { + *return_level = level; + } + + return GS_OK; +} + +char gs_log_level_to_char(gs_log_level_t level) +{ + switch (level) { + case LOG_TRACE: return 'T'; + case LOG_DEBUG: return 'D'; + case LOG_INFO: return 'I'; + case LOG_NOTICE: return 'N'; + case LOG_WARNING: return 'W'; + case LOG_ERROR: return 'E'; + default: return '?'; + } +} + +gs_error_t gs_log_string_to_mask(const char *str, uint8_t old, uint8_t * return_mask) +{ + GS_CHECK_ARG(gs_string_empty(str) == false); + + char strbuf[50]; // copy buf, coz strtok will mess it up + GS_STRNCPY(strbuf, str); + + char *saveptr = NULL; + char *token = strtok_r(strbuf, ",", &saveptr); + while (token) { + // check for +xxx (add), -xxxx (remove), xxxx (set) + int op = MASK_SET; + if (*token == '+') { + op = MASK_OR; + token++; + } else if (*token == '-') { + op = MASK_AND; + token++; + } + + const unsigned int token_length = strlen(token); + if (token_length < 1) { + return GS_ERROR_DATA; + } + + /* Check mask */ + uint8_t mask; + gs_log_level_t level; + if (gs_log_string_to_level(token, &level) == GS_OK) { + // actual level + if (op == MASK_SET) { + // set all level bits equal or lover + mask = LOG_ALL_MASK & ~((1 << level) - 1); + } else { + mask = (1 << level); + } + } else if (!strncasecmp(token, "default", token_length)) { // legacy - conflicts with 'de(bug)' + mask = LOG_DEFAULT_MASK; + op = MASK_SET; + } else if (!strncasecmp(token, "standard", token_length)) { + mask = LOG_DEFAULT_MASK; + op = MASK_SET; + } else if (!strncasecmp(token, "all", token_length)) { + mask = LOG_ALL_MASK; + op = MASK_SET; + } else if (!strncasecmp(token, "off", token_length)) { + mask = 0; + op = MASK_SET; + } else if (!strncasecmp(token, "none", token_length)) { // legacy - conflicts with 'no(tice)' + mask = 0; + op = MASK_SET; + } else if (gs_string_to_uint8(token, &mask) == GS_OK) { + op = MASK_SET; + } else { + return GS_ERROR_DATA; + } + + /* Apply operation */ + if (op == MASK_OR) { + old |= mask; + } else if (op == MASK_AND) { + old &= ~mask; + } else if (op == MASK_SET) { + old = mask; + } + + token = strtok_r(NULL, ",", &saveptr); + } + + if (return_mask) { + *return_mask = old; + } + + return GS_OK; +} + +/** + All functions must call this initialization function, to ensure log is initialized. +*/ +static gs_error_t gs_log_init_internal(void) +{ + if (g_log_groups.data.group == NULL) { + return gs_log_init(true); + } + return GS_OK; +} + +gs_error_t gs_log_group_iterate(const char * group_name, void * ctx, gs_log_group_iterator_t iter) +{ + const bool all = (gs_string_empty(group_name) || gs_log_is_group_all(group_name)); + bool found = false; + + for (gs_log_list_t *node = &g_log_groups; node; node = node->next) { + if (node->data.group) { + if (all || gs_string_match(group_name, node->data.group->name)) { + found = true; + bool cont = iter(ctx, node->data.group); + if (cont == false) { + return GS_OK; + } + } + } + } + + return found ? GS_OK : GS_ERROR_NOT_FOUND; +} + +static gs_error_t gs_log_group_register_internal(gs_log_group_t *group) +{ + // check if appender is already in the list and find last node + gs_log_list_t * parent = &g_log_groups; // there will always be at least 1 group -> default + for (; parent; parent = parent->next) { + if ((parent->data.group == group) || (strcasecmp(group->name, parent->data.group->name) == 0)) { + return GS_ERROR_EXIST; + } + if (parent->next == NULL) { + break; + } + } + + gs_log_list_t * new_group_node = calloc(1, sizeof(*new_group_node)); + if (new_group_node == NULL) { + return GS_ERROR_ALLOC; + } + + new_group_node->data.group = group; + + // add to list - must be done last, iterating list can be done without locking + parent->next = new_group_node; + + return GS_OK; +} + +gs_error_t gs_log_group_register(gs_log_group_t *group) +{ + GS_CHECK_ARG(group != NULL); + GS_CHECK_ARG(gs_string_empty(group->name) == false); + + gs_log_init_internal(); + + gs_lock_lock(); + gs_error_t error = gs_log_group_register_internal(group); + gs_lock_unlock(); + + return error; +} + + +bool gs_log_group_is_level_enabled(gs_log_group_t *group, gs_log_level_t level) +{ + return ((group->mask & level) > 0); +} + +gs_error_t gs_log_appender_iterate(const char * name, void * ctx, gs_log_appender_iterator_t iter) +{ + const bool all = (gs_string_empty(name) || gs_log_is_group_all(name)); + bool found = false; + + /* Iterate the dynamically registered log appenders: */ + for (gs_log_list_t *node = &g_log_appenders; node; node = node->next) { + if (node->data.appender) { + if (all || gs_string_match(name, node->data.appender->name)) { + found = true; + bool cont = iter(ctx, node->data.appender); + if (cont == false) { + return GS_OK; + } + } + } + } + + return found ? GS_OK : GS_ERROR_NOT_FOUND; +} + +struct gs_log_history_ctx { + gs_log_record_iterator_t iter; + void *ctx; +}; + +static bool gs_log_history_iterator(void* ctx, gs_log_appender_t *appender) +{ + struct gs_log_history_ctx *hist_ctx = ctx; + if (appender->drv->hist) { + appender->drv->hist(appender, hist_ctx->ctx, hist_ctx->iter); + } + return true; +} + +gs_error_t gs_log_appender_history_iterate(const char * name, void * ctx, gs_log_record_iterator_t iter) +{ + struct gs_log_history_ctx hist_ctx = {.iter=iter, .ctx = ctx}; + + return gs_log_appender_iterate(name, &hist_ctx, gs_log_history_iterator); +} + +static gs_error_t gs_log_appender_register_internal(gs_log_appender_t *appender) +{ + if (g_log_appenders.data.appender == NULL) { + // first appender + g_log_appenders.data.appender = appender; + + if (appender->drv->init) { + gs_error_t error = appender->drv->init(appender); + if (error) { + g_log_appenders.data.appender = NULL; + return error; + } + } + + return GS_OK; + } + + // check if appender is already in the list and find last node + gs_log_list_t * parent = &g_log_appenders; + for (; parent; parent = parent->next) { + if ((parent->data.appender == appender) || (strcasecmp(parent->data.appender->name, appender->name) == 0)) { + return GS_ERROR_EXIST; + } + if (parent->next == NULL) { + break; + } + } + + gs_log_list_t *new_appender = calloc(1, sizeof(*new_appender)); + if (new_appender == NULL) { + return GS_ERROR_ALLOC; + } + + new_appender->data.appender = appender; + + if (appender->drv->init) { + gs_error_t error = appender->drv->init(appender); + if (error) { + free(new_appender); + return error; + } + } + + // add to list - must be done last, iterating list can be done without locking + parent->next = new_appender; + + return GS_OK; +} + +gs_error_t gs_log_appender_register(gs_log_appender_t *appender) +{ + GS_CHECK_ARG(appender != NULL); + GS_CHECK_ARG(gs_string_empty(appender->name) == false); + GS_CHECK_ARG(appender->drv != NULL); + GS_CHECK_ARG(appender->drv->append != NULL); + + gs_log_init_internal(); + + gs_lock_lock(); + gs_error_t error = gs_log_appender_register_internal(appender); + gs_lock_unlock(); + + return error; +} + +gs_error_t gs_log_appender_add(gs_log_appender_t *appender, uint16_t count) +{ + GS_CHECK_ARG(appender != NULL); + GS_CHECK_ARG(count != 0); + + gs_error_t error = GS_OK; + for (uint16_t i = 0; i < count; i++) { + gs_error_t tmp_error = gs_log_appender_register(&appender[i]); + if ((error == GS_OK) && tmp_error) { + error = tmp_error; + } + } + + return error; +} + +static bool iter_set_appender_level_mask(void * ctx_in, gs_log_appender_t * appender) +{ + uint8_t * level_mask = ctx_in; + appender->mask = *level_mask; + return true; +} + +gs_error_t gs_log_appender_set_level_mask(const char * appender_name, uint8_t mask) +{ + if (gs_string_empty(appender_name)) { + return GS_ERROR_HANDLE; + } + + return gs_log_appender_iterate(appender_name, &mask, iter_set_appender_level_mask); +} + +static bool iter_get_appender_level_mask(void * ctx_in, gs_log_appender_t * appender) +{ + uint8_t * level_mask = ctx_in; + *level_mask = appender->mask; + return true; +} + +gs_error_t gs_log_appender_get_level_mask(const char * appender_name, uint8_t *mask) +{ + if (gs_string_empty(appender_name)) { + return GS_ERROR_HANDLE; + } + + return gs_log_appender_iterate(appender_name, mask, iter_get_appender_level_mask); +} + +// Appender register/de-register iterator context +typedef struct { + gs_log_appender_t *appender; + gs_error_t ret; +} iter_group_appender_t; + +static bool iter_log_appender_add(void *ctx, gs_log_group_t *group) +{ + iter_group_appender_t* in = ctx; + + gs_log_list_t * last_elem = group->appenders; + for (gs_log_list_t *elem = group->appenders; elem; elem = elem->next) { + last_elem = elem; + if (elem->data.appender == in->appender) { + in->ret = GS_ERROR_EXIST; + return true; + } + } + + in->ret = GS_ERROR_ALLOC; + gs_log_list_t *new_appender = calloc(1, sizeof(*new_appender)); + if (new_appender) { + new_appender->data.appender = in->appender; + new_appender->next = 0; + if (last_elem != NULL) { + last_elem->next = new_appender; + } else { + group->appenders = new_appender; + } + in->ret = GS_OK; + } + + return true; +} + +gs_error_t gs_log_group_register_appender(const char * group_name, const char * appender_name) +{ + gs_log_appender_t *appender = NULL; + for (gs_log_list_t *elem = &g_log_appenders; elem; elem = elem->next) { + if (elem->data.appender) { + if (strcasecmp(elem->data.appender->name, appender_name) == 0) { + appender = elem->data.appender; + break; + } + } + } + if (NULL == appender) { + return GS_ERROR_NOT_FOUND; + } + + iter_group_appender_t ctx = {.appender = appender, .ret = GS_OK}; + + gs_error_t ret = GS_OK; + if (strcasecmp(group_name, GS_LOG_GROUP_ROOT) == 0) { + iter_log_appender_add(&ctx, &g_log_group_root); + } else { + ret = gs_log_group_iterate(group_name, &ctx, iter_log_appender_add); + } + + if (ret == GS_OK) { + ret = ctx.ret; + } + + return ret; +} + +static bool iter_log_appender_remove(void *ctx, gs_log_group_t *group) +{ + iter_group_appender_t* in = ctx; + in->ret = GS_ERROR_NOT_FOUND; + + gs_log_list_t * last_elem = group->appenders; + for (gs_log_list_t *elem = group->appenders; elem; elem = elem->next) { + if (elem->data.appender == in->appender) { + if (elem == group->appenders) { + group->appenders = elem->next; + } + last_elem->next = elem->next; + free(elem); + in->ret = GS_OK; + break; + } + last_elem = elem; + } + + return true; +} + +gs_error_t gs_log_group_deregister_appender(const char * group_name, const char * appender_name) +{ + gs_log_appender_t *appender = NULL; + for (gs_log_list_t *elem = &g_log_appenders; elem; elem = elem->next) { + if (elem->data.appender) { + if (strcasecmp(elem->data.appender->name, appender_name) == 0) { + appender = elem->data.appender; + break; + } + } + } + if (NULL == appender) { + return GS_ERROR_NOT_FOUND; + } + + iter_group_appender_t ctx = {.appender = appender, .ret = GS_OK}; + + gs_error_t ret; + if (strcasecmp(group_name, GS_LOG_GROUP_ROOT) == 0) { + ret = iter_log_appender_remove(&ctx, &g_log_group_root); + } else { + ret = gs_log_group_iterate(group_name, &ctx, iter_log_appender_remove); + } + + if (ret == GS_OK) { + ret = ctx.ret; + } + + return ret; +} + +gs_error_t gs_log_group_appender_iterate(gs_log_group_t * group, void * ctx, gs_log_appender_iterator_t iter) +{ + GS_CHECK_ARG(group != NULL); + + bool found = false; + for (gs_log_list_t *elem = group->appenders; elem; elem = elem->next) { + found = true; + iter(ctx, elem->data.appender); + } + + /* Iterate root appenders */ + for (gs_log_list_t *elem = g_log_group_root.appenders; elem; elem = elem->next) { + found = true; + iter(ctx, elem->data.appender); + } + + return found ? GS_OK : GS_ERROR_NOT_FOUND; +} + +static inline void gs_log_process_appenders(const gs_log_list_t * it, gs_log_level_t level, + const gs_log_group_t * group, gs_timestamp_t* ts, bool from_isr, const char * format, va_list va) +{ + for (; it; it = it->next) { + gs_log_appender_t* appender = it->data.appender; + + if ((appender->mask & (1 << level)) == 0) { + continue; + } + + if (from_isr == false) { + // log from none ISR context + appender->drv->append(appender, level, group, ts, format, va); + + } else if (appender->drv->append_isr) { + // log from ISR (Interrupt Service Routine) context + appender->drv->append_isr(appender, level, group, ts, format, va); + } + } +} + +static inline void gs_log_common_va(gs_log_level_t level, gs_log_group_t * group, bool from_isr, const char * format, va_list va) +{ + // get time as soon as possible + gs_timestamp_t ts; + gs_clock_get_time(&ts); + + // only needed if someone call function directly - otherwise the log macro has set it to a valid group + if (group == NULL) { + group = LOG_DEFAULT; + } + + // check level mask for current group (this will nearly always be true, because the log macro has done the checking + if (group->mask & (1 << level)) { + + // legacy - if log hasn't been initialized, this will initialize with console output enabled. + gs_log_init_internal(); + + if (group->appenders) { + gs_log_process_appenders(group->appenders, level, group, &ts, from_isr, format, va); + } + + if (group->additivity) { + /* Call root appenders */ + gs_log_process_appenders(g_log_group_root.appenders, level, group, &ts, from_isr, format, va); + } + } +} + +void gs_log(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) +{ + va_list va_args; + va_start(va_args, format); + gs_log_common_va(level, group, false, format, va_args); + va_end(va_args); +} + +void gs_log_isr(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) +{ + va_list va_args; + va_start(va_args, format); + gs_log_common_va(level, group, true, format, va_args); + va_end(va_args); +} + +void gs_log_va(gs_log_level_t level, gs_log_group_t * group, const char * format, va_list args) +{ + gs_log_common_va(level, group, false, format, args); +} + +void gs_log_set_print_color(bool color) +{ + g_print_no_color = (color == false); +} + +const char * gs_log_level_to_color_begin(gs_log_level_t level) +{ + if (g_print_no_color) { + return ""; + } + + switch (level) { + case LOG_ERROR: return "\E[1;31m"; // Red + case LOG_WARNING: return "\E[0;33m"; // Yellow + case LOG_NOTICE: + case LOG_INFO: return "\E[0;32m"; // Green + case LOG_DEBUG: return "\E[0;34m"; // Blue + default: + case LOG_TRACE: return "\E[0;35m"; // Magenta + } +} + +const char * gs_log_level_to_color_end(void) +{ + if (g_print_no_color) { + return ""; + } + + return "\E[0m"; +} + +uint8_t gs_log_level_to_mask(gs_log_level_t level) +{ + /* Enable all levels with priority above the set level */ + uint8_t level_mask = (0xFF << level) & LOG_ALL_MASK; + return level_mask; +} + +static bool iter_flush_appender(void * ctx_in, gs_log_appender_t * appender) +{ + if (appender->drv->flush) { + appender->drv->flush(appender); + } + return true; +} + +gs_error_t gs_log_appender_flush_all() +{ + return gs_log_appender_iterate("", NULL, iter_flush_appender); +} + +gs_error_t gs_log_init(bool with_console_appender) +{ + gs_error_t error = GS_OK; + + gs_lock_init(); // ignore result, this is the log system + + if (g_log_groups.data.group == NULL) { + + // default log group -> mark log as initialized + g_log_groups.data.group = LOG_DEFAULT; + + // register console log appender + if (with_console_appender) { + error = gs_log_appender_register(&gs_log_appender_console); + if (error == GS_OK) { + error = gs_log_group_register_appender(GS_LOG_GROUP_ROOT, gs_log_appender_console.name); + } + } + } + + return error; +} diff --git a/gomspace/libutil/src/rtc.c b/gomspace/libutil/src/rtc.c new file mode 100644 index 00000000..160df778 --- /dev/null +++ b/gomspace/libutil/src/rtc.c @@ -0,0 +1,42 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include + +static const gs_rtc_driver_t * rtc_driver; +static void * rtc_driver_data; + +gs_error_t gs_rtc_register(const gs_rtc_driver_t * driver, void * driver_data) +{ + rtc_driver = driver; + rtc_driver_data = driver_data; + return GS_OK; +} + +gs_error_t gs_rtc_supported(void) +{ + return rtc_driver ? GS_OK : GS_ERROR_NOT_SUPPORTED; +} + +gs_error_t gs_rtc_get_time(gs_timestamp_t * time) +{ + if (time == NULL) { + return GS_ERROR_ARG; + } + + if (rtc_driver && rtc_driver->get_time) { + return rtc_driver->get_time(rtc_driver_data, time); + } + return GS_ERROR_NOT_SUPPORTED; +} + +gs_error_t gs_rtc_set_time(const gs_timestamp_t * time) +{ + if (time == NULL) { + return GS_ERROR_ARG; + } + + if (rtc_driver && rtc_driver->set_time) { + return rtc_driver->set_time(rtc_driver_data, time); + } + return GS_ERROR_NOT_SUPPORTED; +} diff --git a/gomspace/libutil/src/stdio.c b/gomspace/libutil/src/stdio.c new file mode 100644 index 00000000..c723f8fe --- /dev/null +++ b/gomspace/libutil/src/stdio.c @@ -0,0 +1,81 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include + +gs_error_t gs_stdio_get(char * buf, size_t len) +{ + while (len > 0) { + int ch; + gs_error_t error = gs_stdio_getchar(&ch); + if (error) { + return error; + } + *buf++ = ch; + --len; + } + + return GS_OK; +} + +gs_error_t gs_stdio_put(const char * buf, size_t len, bool text) +{ + while (len > 0) { + if ((*buf == '\n') && text) { + gs_stdio_putchar('\r'); + } + gs_stdio_putchar(*buf++); + --len; + } + + return GS_OK; +} + +void gs_color_printf(gs_color_printf_t color_arg, const char * format, ...) +{ + va_list args; + va_start(args, format); + + if ((color_arg & GS_COLOR_ATTRS) == GS_COLOR_BOLD) { + printf("\033[1;"); + } else { + printf("\033[0;"); + } + + switch(color_arg & GS_COLOR_COLORS) { + case GS_COLOR_NONE: + printf("0m"); + break; + case GS_COLOR_BLACK: + printf("30m"); + break; + case GS_COLOR_RED: + printf("31m"); + break; + case GS_COLOR_GREEN: + printf("32m"); + break; + case GS_COLOR_YELLOW: + printf("33m"); + break; + case GS_COLOR_BLUE: + printf("34m"); + break; + case GS_COLOR_MAGENTA: + printf("35m"); + break; + case GS_COLOR_CYAN: + printf("36m"); + break; + case GS_COLOR_WHITE: + printf("37m"); + break; + default: + break; + } + + vprintf(format, args); + printf("\033[0m"); + + va_end(args); +} diff --git a/gomspace/libutil/src/string.c b/gomspace/libutil/src/string.c new file mode 100644 index 00000000..31419fd0 --- /dev/null +++ b/gomspace/libutil/src/string.c @@ -0,0 +1,746 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#if (__AVR__ == 0) +#include +#endif + +#ifndef GS_STRING_GET_SUBOPTION_UNIT_TEST +#define GS_STRING_GET_SUBOPTION_UNIT_TEST 0 +#endif + +const char * gs_string_skip_leading_spaces(const char * string) +{ + if (string) { + for (; *string == ' '; ++string); + } + return string; +} + +gs_error_t gs_string_to_int32(const char * string, int32_t * return_value) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (!(isdigit((int)string[0]) || (string[0] == '-'))) { + return GS_ERROR_DATA; + } + + int32_t tmp; + uint8_t base = 10; + + // check for hexadecimal notation + if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) + { + base = 16; + } + + const char *desired_end = string + strlen(string); + // The desired end should point to that last non-space char in the string + while ((isspace((int)desired_end[0]) || (desired_end[0] == '\0')) && (desired_end > string)) + { + desired_end--; + } + char *end; + gs_error_t err = GS_OK; + tmp = gs_string_strto32int(string, &end, base, &err); + if (err != GS_OK) + { + return err; + } + if (desired_end != end-1) + { + return GS_ERROR_DATA; + } + + if (return_value) + { + *return_value = tmp; + } + + return GS_OK; +} + +gs_error_t gs_string_to_int8(const char * string, int8_t * return_value) +{ + int32_t value; + gs_error_t error = gs_string_to_int32(string, &value); + if (error == GS_OK) { + if ((value >= INT8_MIN) && (value <= INT8_MAX)) { + if (return_value) { + *return_value = (int8_t) value; + } + } else { + error = GS_ERROR_OVERFLOW; + } + } + return error; +} + +gs_error_t gs_string_to_uint8(const char * string, uint8_t * return_value) +{ + uint32_t value; + gs_error_t error = gs_string_to_uint32(string, &value); + if (error == GS_OK) { + if (value <= UINT8_MAX) { + if (return_value) { + *return_value = (uint8_t) value; + } + } else { + error = GS_ERROR_OVERFLOW; + } + } + return error; +} + +gs_error_t gs_string_to_int16(const char * string, int16_t * return_value) +{ + int32_t value; + gs_error_t error = gs_string_to_int32(string, &value); + if (error == GS_OK) { + if ((value >= INT16_MIN) && (value <= INT16_MAX)) { + if (return_value) { + *return_value = (int16_t) value; + } + } else { + error = GS_ERROR_OVERFLOW; + } + } + return error; +} + +gs_error_t gs_string_to_uint16(const char * string, uint16_t * return_value) +{ + uint32_t value; + gs_error_t error = gs_string_to_uint32(string, &value); + if (error == GS_OK) { + if (value <= UINT16_MAX) { + if (return_value) { + *return_value = (uint16_t) value; + } + } else { + error = GS_ERROR_OVERFLOW; + } + } + return error; +} + +gs_error_t gs_string_to_uint32(const char * string, uint32_t * return_value) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (!isdigit((int)string[0])) { + return GS_ERROR_DATA; + } + + uint32_t tmp; + uint8_t base = 10; + + // check for hexadecimal notation + if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) + { + base = 16; + } + const char *desired_end = string + strlen(string); + // The desired end should point to that last non-space char in the string + while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) + { + desired_end--; + } + char *end; + gs_error_t err = GS_OK; + tmp = gs_string_strto32uint(string, &end, base, &err); + + if (err != GS_OK) + { + return err; + } + if (desired_end != end-1) + { + return GS_ERROR_DATA; + } + + + if (return_value) { + *return_value = tmp; + } + + return GS_OK; +} + +gs_error_t gs_string_to_uint64(const char * string, uint64_t * return_value) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (!isdigit((int)string[0])) + { + return GS_ERROR_DATA; + } + + uint64_t tmp; + uint8_t base = 10; + + // check for hexadecimal notation + if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) { + base = 16; + } + const char *desired_end = string + strlen(string); + // The desired end should point to that last non-space char in the string + while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) + { + desired_end--; + } + char *end; + gs_error_t err = GS_OK; + tmp = gs_string_strto64uint(string, &end, base, &err); + if (err != GS_OK) + { + return err; + } + + if (desired_end != end-1) + { + return GS_ERROR_DATA; + } + + + if (return_value) { + *return_value = tmp; + } + + return GS_OK; +} + +gs_error_t gs_string_to_int64(const char * string, int64_t * return_value) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (!(isdigit((int)string[0]) || (string[0] == '-'))) + { + return GS_ERROR_DATA; + } + + int64_t tmp; + uint8_t base = 10; + + // check for hexadecimal notation + if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) { + base = 16; + } + const char *desired_end = string + strlen(string); + // The desired end should point to that last non-space char in the string + while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) + { + desired_end--; + } + char *end; + gs_error_t err = GS_OK; + tmp = gs_string_strto64int(string, &end, base, &err); + if (err != GS_OK) + { + return err; + } + + if (desired_end != end-1) + { + return GS_ERROR_DATA; + } + + + if (return_value) { + *return_value = tmp; + } + + return GS_OK; +} + +gs_error_t gs_string_hex_to_uint32(const char * string, uint32_t * return_value) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (!isxdigit((int)string[0])) { + return GS_ERROR_DATA; + } + + const char *desired_end = string + strlen(string); + // The desired end should point to that last non-space char in the string + while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) + { + desired_end--; + } + char *end; + gs_error_t err = GS_OK; + uint32_t tmp = gs_string_strto32uint(string, &end, 16, &err); + + if (err != GS_OK) + { + return err; + } + if (desired_end != end-1) + { + return GS_ERROR_DATA; + } + + if (return_value) { + *return_value = tmp; + } + + return GS_OK; +} + +gs_error_t gs_string_hex_to_uint64(const char * string, uint64_t * return_value) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (!isxdigit((int)string[0])) + { + return GS_ERROR_DATA; + } + + const char *desired_end = string + strlen(string); + // The desired end should point to that last non-space char in the string + while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) + { + desired_end--; + } + char *end; + gs_error_t err = GS_OK; + uint64_t tmp = gs_string_strto64uint(string, &end, 16, &err); + if (err != GS_OK) + { + return err; + } + + if (desired_end != end-1) + { + return GS_ERROR_DATA; + } + + if (return_value) { + *return_value = tmp; + } + + return GS_OK; +} + +#if (__AVR__ == 0) +gs_error_t gs_string_to_float(const char * string, float * pvalue) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (gs_string_empty(string)) { + return GS_ERROR_DATA; + } + + // float strtof(const char *nptr, char **endptr); + char * endp = NULL; + float tmp = strtof(string, &endp); + //if ((endp == NULL) || (gs_string_empty(gs_string_skip_leading_spaces(endp)) == false) || (string == endp)) { + if ((endp == NULL) || (gs_string_empty(gs_string_skip_leading_spaces(endp)) == false) || (string == endp) || isinf(tmp)) { + return GS_ERROR_DATA; + } + + if (pvalue) { + *pvalue = tmp; + } + + return GS_OK; +} + +gs_error_t gs_string_to_double(const char * string, double * pvalue) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + + if (gs_string_empty(string)) { + return GS_ERROR_DATA; + } + + // double strtod(const char *nptr, char **endptr); + char * endp = NULL; + double tmp = strtod(string, &endp); + if ((endp == NULL) || (gs_string_empty(gs_string_skip_leading_spaces(endp)) == false) || isinf(tmp)) { + return GS_ERROR_DATA; + } + + if (pvalue) { + *pvalue = tmp; + } + + return GS_OK; +} +#endif + +#define GS_STRING_BOOL_TRUE "true" +#define GS_STRING_BOOL_FALSE "false" + +const char * gs_string_from_bool(bool value) +{ + if (value) { + return GS_STRING_BOOL_TRUE; + } else { + return GS_STRING_BOOL_FALSE; + } +} + +gs_error_t gs_string_to_bool(const char * string, bool * return_value) +{ + string = gs_string_skip_leading_spaces(string); + if (string == NULL) { + return GS_ERROR_ARG; + } + if (string[0] == 0) { + return GS_ERROR_DATA; + } + + bool value = false; + if (strcasecmp(string, GS_STRING_BOOL_TRUE) == 0) { + value = true; + } else if (strcasecmp(string, GS_STRING_BOOL_FALSE) == 0) { + value = false; + } else if (strcasecmp(string, "on") == 0) { + value = true; + } else if (strcasecmp(string, "off") == 0) { + value = false; + } else if (strcasecmp(string, "1") == 0) { + value = true; + } else if (strcasecmp(string, "0") == 0) { + value = false; + } else if (strcasecmp(string, "yes") == 0) { + value = true; + } else if (strcasecmp(string, "no") == 0) { + value = false; + } else { + return GS_ERROR_DATA; + } + + if (return_value) { + *return_value = value; + } + + return GS_OK; +} + +char * gs_string_bytesize(long n, char *buf, size_t buf_size) +{ + char postfix = 'B'; + double size = (double) n; + if (n >= 1048576) { + size /= 1048576.0; + postfix = 'M'; + } else if (n >= 1024) { + size /= 1024.0; + postfix = 'K'; + } + snprintf(buf, buf_size, "%.1f%c", size, postfix); + return buf; +} + +gs_error_t gs_string_to_pointer(const char * string, void ** value) +{ +#if __LP64__ + uint64_t tmp; + gs_error_t error = gs_string_to_uint64(string, &tmp); + if ((error == GS_OK) && value) { + *value = GS_TYPES_UINT2PTR(tmp); + } + return error; +#else + uint32_t tmp; + gs_error_t error = gs_string_to_uint32(string, &tmp); + if ((error == GS_OK) && value) { + *value = GS_TYPES_UINT2PTR(tmp); + } + return error; +#endif +} + +bool gs_string_empty(const char * string) +{ + if ((string == NULL) || (string[0] == 0)) { + return true; + } + return false; +} + +bool gs_string_match(const char * pattern, const char * string) +{ + if (string && pattern) { + while (*string || *pattern) { + int p = tolower((int)*pattern); + int s = tolower((int)*string); + + if (*pattern == '*') { + ++pattern; + p = tolower((int)*pattern); + for (; *string && (tolower((int)*string) != p); ++string); + s = tolower((int)*string); + } + + if (s != p) { + return false; + } + + if (s) { + ++string; + } + if (p) { + ++pattern; + } + } + if ((*string == 0) && (*pattern == 0)) { + return true; + } + } + return false; +} + +bool gs_string_has_wildcards(const char * string) +{ + if (strchr(string, '*')) { + return true; + } + // future wildcard + //if (strchr(str, '?')) { + // return true; + //} + return false; +} + +void gs_string_trim(char * buffer, size_t buffer_size) +{ + // remove trailing stuff + int len = strnlen(buffer, buffer_size); + if (len) { + for (int i = (len - 1); i >= 0; --i) { + if (isspace((int)buffer[i])) { + buffer[i] = 0; + } else { + break; + } + } + } + + char * start; + for (start = buffer; *start && isspace((int)*start); ++start); + if (*start && (start != buffer)) { + // move chars up + for (; *start; ++start) { + *buffer++ = *start; + } + *buffer = 0; + } +} + +bool gs_string_endswith(const char * string, const char * endswith) +{ + if (string == NULL || endswith == NULL) { + return false; + } + + int str_len = strlen(string); + int endswith_len = strlen(endswith); + + return (str_len >= endswith_len) && + (0 == strcmp(string + (str_len-endswith_len), endswith)); +} + +static size_t suboption_len(const char * ref, const char * end) +{ + if (ref) { + size_t len = (end) ? ((size_t)(end - ref)) : strlen(ref); + for (; len && (ref[len - 1] == ' '); --len); + return len; + } + return 0; +} + +static gs_error_t suboption_copy(const char * data, size_t len, char * buf, size_t buf_size, gs_error_t error) +{ + if (len >= buf_size) { + error = GS_ERROR_OVERFLOW; + len = (buf_size - 1); + } + + if (data == NULL) { + len = 0; + } else { + strncpy(buf, data, len); + } + + buf[len] = 0; + + return error; +} + +gs_error_t gs_string_get_suboption(const char * options, const char * suboption, char * buf, size_t buf_size) +{ + GS_CHECK_ARG(options != NULL); + GS_CHECK_ARG((buf != NULL) && (buf_size > 0)); + + const char * next = options; + for (;next;) { + const char * key = next; + if (*key == ',') { + key = NULL; // no key-value + } + next = strchr(next, ','); + + const char * value = NULL; + if (key) { + for (; *key == ' '; ++key); + + value = strchr(key, '='); + if (value == NULL) { + // no value + } else if (next && (value >= next)) { + // no value + value = NULL; + } + } + + const unsigned int key_len = suboption_len(key, value ? value : next); + + if (value) { + if (*value == '=') { + ++value; + } + for (; *value == ' '; ++value); + } + + const unsigned int value_len = suboption_len(value, next); + + if (GS_STRING_GET_SUBOPTION_UNIT_TEST) { // -> #define + printf(" key=[%.*s], len=%u, value=[%.*s], len=%u, next=[%s]\n", + key_len, key ? key : "", key_len, + value_len, value ? value : "", value_len, + next ? next : ""); + } + + // if suboption is empty, it means get value of first element - ignoring any key + if (gs_string_empty(suboption)) { + if (value) { + return suboption_copy(value, value_len, buf, buf_size, GS_OK); + } + if (key) { + return suboption_copy(key, key_len, buf, buf_size, GS_OK); + } + return suboption_copy(NULL, 0, buf, buf_size, GS_OK); // empty + } + + if ((key_len == strlen(suboption)) && (strncasecmp(key, suboption, key_len) == 0)) { + return suboption_copy(value, value_len, buf, buf_size, GS_OK); + } + + if (next) { + ++next; + if (next[0] == 0) { + next = NULL; + } + } + } + + // not found - return default + return suboption_copy(NULL, 0, buf, buf_size, GS_ERROR_NOT_FOUND); +} + +static const char * _suboption_name(const char * suboption) +{ + if (gs_string_empty(suboption)) { + return "first suboption"; + } + return suboption; +} + +#define _get_suboption(_type) \ + char buf[20]; \ + gs_error_t error = gs_string_get_suboption(options, suboption, buf, sizeof(buf)); \ + if (error == GS_OK) { \ + error = gs_string_to_##_type(buf, value); \ + } \ + if (error) { \ + if (error == GS_ERROR_NOT_FOUND) { \ + error = GS_OK; \ + } else { \ + log_error("Failed to extract suboption [%s] from [%s], error: %d", _suboption_name(suboption), options, error); \ + } \ + *value = def; \ + } \ + return error; \ + +gs_error_t gs_string_get_suboption_uint8(const char * options, const char * suboption, uint8_t def, uint8_t * value) +{ + _get_suboption(uint8) +} + +gs_error_t gs_string_get_suboption_uint16(const char * options, const char * suboption, uint16_t def, uint16_t * value) +{ + _get_suboption(uint16) +} + +gs_error_t gs_string_get_suboption_uint32(const char * options, const char * suboption, uint32_t def, uint32_t * value) +{ + _get_suboption(uint32) +} + +gs_error_t gs_string_get_suboption_string(const char * options, const char * suboption, const char * def, char * buf, size_t buf_size) +{ + gs_error_t error = gs_string_get_suboption(options, suboption, buf, buf_size); + if (error) { + if (error == GS_ERROR_NOT_FOUND) { + error = GS_OK; + } + error = suboption_copy(def, def ? strlen(def) : 0, buf, buf_size, error); + } + return error; +} + +gs_error_t gs_string_get_suboption_bool(const char * options, const char * suboption, bool def, bool * value) +{ + char buf[20]; + gs_error_t error = gs_string_get_suboption(options, suboption, buf, sizeof(buf)); + if (error == GS_OK) { + if (gs_string_empty(buf) || (suboption && (strcasecmp(suboption, buf) == 0))) { + // this means 'true', a=21,active,a=22 + *value = true; + } else { + error = gs_string_to_bool(buf, value); + } + } + if (error) { + if (error == GS_ERROR_NOT_FOUND) { + error = GS_OK; + } else { + log_error("Failed to extract suboption [%s] from [%s], error: %d", _suboption_name(suboption), options, error); + } + *value = def; + } + return error; +} diff --git a/gomspace/libutil/src/strtoint.c b/gomspace/libutil/src/strtoint.c new file mode 100644 index 00000000..152eff39 --- /dev/null +++ b/gomspace/libutil/src/strtoint.c @@ -0,0 +1,399 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * 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. [rescinded 22 July 1999] + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + +@deftypefn Supplemental {long int} strtol (const char *@var{string}, @ + char **@var{endptr}, int @var{base}) +@deftypefnx Supplemental {unsigned long int} strtoul (const char *@var{string}, @ + char **@var{endptr}, int @var{base}) + +The @code{strtol} function converts the string in @var{string} to a +long integer value according to the given @var{base}, which must be +between 2 and 36 inclusive, or be the special value 0. If @var{base} +is 0, @code{strtol} will look for the prefixes @code{0} and @code{0x} +to indicate bases 8 and 16, respectively, else default to base 10. +When the base is 16 (either explicitly or implicitly), a prefix of +@code{0x} is allowed. The handling of @var{endptr} is as that of +@code{strtod} above. The @code{strtoul} function is the same, except +that the converted value is unsigned. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#include +#include +#include + +/* + * Convert a string to a long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +int32_t gs_string_strto32int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) +{ + register const char *s = nptr; + register uint32_t acc; + register int c; + register uint32_t cutoff; + register int neg = 0, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + do + { + c = *s++; + } while (isspace(c)); + if (c == '-') + { + neg = 1; + c = *s++; + } else if (c == '+') + { + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) + { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + { + base = c == '0' ? 8 : 10; + } + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? -(uint32_t)INT32_MIN : INT32_MAX; + cutlim = cutoff % (uint32_t)base; + cutoff /= (uint32_t)base; + for (acc = 0, any = 0;; c = *s++) + { + if (isdigit(c)) + { + c -= '0'; + } + else if (isalpha(c)) + { + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + } + else + { + break; + } + if (c >= base) + { + break; + } + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + { + any = -1; + } + else + { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) + { + acc = neg ? INT32_MIN : INT32_MAX; + *err = GS_ERROR_OVERFLOW; + } else if (neg) + { + acc = -acc; + } + if (endptr != 0) + { + *endptr = (char *) (any ? s - 1 : nptr); + } + return (acc); +} + + +/* + * Convert a string to an unsigned long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +uint32_t gs_string_strto32uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) +{ + register const char *s = nptr; + register uint32_t acc; + register int32_t c; + register uint32_t cutoff; + register int32_t neg = 0, any, cutlim; + + /* + * See strtol for comments as to the logic used. + */ + do + { + c = *s++; + } while (isspace(c)); + if (c == '-') + { + neg = 1; + c = *s++; + } else if (c == '+') + { + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) + { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + { + base = c == '0' ? 8 : 10; + } + cutoff = (uint32_t)UINT32_MAX / (uint32_t)base; + cutlim = (uint32_t)UINT32_MAX % (uint32_t)base; + for (acc = 0, any = 0;; c = *s++) + { + if (isdigit(c)) + { + c -= '0'; + } + else if (isalpha(c)) + { + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + } + else + { + break; + } + if (c >= base) + { + break; + } + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + { + any = -1; + } + else + { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) + { + acc = UINT32_MAX; + *err = GS_ERROR_OVERFLOW; + } else if (neg) + { + acc = -acc; + } + if (endptr != 0) + { + *endptr = (char *) (any ? s - 1 : nptr); + } + return (acc); +} + + +int64_t gs_string_strto64int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) +{ + register const char *s = nptr; + register uint64_t acc; + register int32_t c; + register uint64_t cutoff; + register int32_t neg = 0, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? -(uint64_t)INT64_MIN : INT64_MAX; + cutlim = cutoff % (uint64_t)base; + cutoff /= (uint64_t)base; + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? INT64_MIN : INT64_MAX; + *err = GS_ERROR_OVERFLOW; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} + + +/* + * Convert a string to an unsigned long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ + +uint64_t gs_string_strto64uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) +{ + register const char *s = nptr; + register uint64_t acc; + register int32_t c; + register uint64_t cutoff; + register int32_t neg = 0, any, cutlim; + + /* + * See strtol for comments as to the logic used. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + cutoff = (uint64_t)UINT64_MAX / (uint64_t)base; + cutlim = (uint64_t)UINT64_MAX % (uint64_t)base; + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = UINT64_MAX; + *err = GS_ERROR_OVERFLOW; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} diff --git a/gomspace/libutil/src/test/cmocka.c b/gomspace/libutil/src/test/cmocka.c new file mode 100644 index 00000000..c3c5d171 --- /dev/null +++ b/gomspace/libutil/src/test/cmocka.c @@ -0,0 +1,63 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +void cm_print_error(const char * const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); + +#define EQUAL_TO_STRING(equal) (equal ? "!=" : "==") + +void _gs_assert_int_equal(const intptr_t left, const intptr_t right, bool equal, const char * const file, const int line) +{ + const bool cmp_equal = left == right; + if (cmp_equal != equal) { + cm_print_error("%ld %s %ld\n", left, EQUAL_TO_STRING(equal), right); + + _fail(file, line); + } +} + +void _gs_assert_uint_equal(const uintptr_t left, const uintptr_t right, bool equal, bool hex, const char * const file, const int line) +{ + const bool cmp_equal = left == right; + if (cmp_equal != equal) { + if(hex) { + cm_print_error("0x%lx %s 0x%lx\n", left, EQUAL_TO_STRING(equal), right); + } else { + cm_print_error("%lu %s %lu\n", left, EQUAL_TO_STRING(equal), right); + } + + _fail(file, line); + } +} + +void _gs_assert_error_equal(const int left, const int right, bool equal, const char * const file, const int line) +{ + const bool cmp_equal = left == right; + if (cmp_equal != equal) { + cm_print_error("%d(%s) %s %d(%s)\n", left, gs_error_string(left), EQUAL_TO_STRING(equal), right, gs_error_string(right)); + + _fail(file, line); + } +} + +void _gs_assert_float_equal(const float left, const float right, const float diff, bool equal, const char * const file, const int line) +{ + const bool cmp_equal = (fabsf(left - right) < diff); + if (cmp_equal != equal) { + cm_print_error("%e %s %e\n", left, EQUAL_TO_STRING(equal), right); + + _fail(file, line); + } +} + +void _gs_assert_double_equal(const double left, const double right, const double diff, bool equal, const char * const file, const int line) +{ + const bool cmp_equal = (fabsf(left - right) < diff); + if (cmp_equal != equal) { + cm_print_error("%e %s %e\n", left, EQUAL_TO_STRING(equal), right); + + _fail(file, line); + } +} diff --git a/gomspace/libutil/src/test/command.c b/gomspace/libutil/src/test/command.c new file mode 100644 index 00000000..e9678523 --- /dev/null +++ b/gomspace/libutil/src/test/command.c @@ -0,0 +1,176 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include +#include + +void cm_print_error(const char * const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); + +struct results { + char group[32]; + char key[32]; + char value[128]; +}; + +static FILE* g_output_file = 0; +static char g_stdout_buf[10000]; +static char g_stdin_buf[1000]; +static uint16_t g_stdin_idx; + +static struct results g_results[100]; +static uint32_t g_results_count = 0; + + +static gs_error_t test_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value) +{ + if (g_results_count >= GS_ARRAY_SIZE(g_results)) { + return GS_ERROR_ALLOC; + } + + if (group) { + strncpy(g_results[g_results_count].group, group, sizeof(g_results[0].group)); + } + if (key) { + strncpy(g_results[g_results_count].key, key, sizeof(g_results[0].key)); + } + if (value) { + strncpy(g_results[g_results_count].value, value, sizeof(g_results[0].value)); + } + g_results_count++; + return GS_OK; +} + +static gs_error_t test_flush(gs_command_context_t *ctx) +{ + fflush(ctx->out); + return GS_OK; +} + +static gs_error_t test_wait_for_key(gs_command_context_t *ctx, int *ch, int timeout_ms) +{ + if (g_stdin_buf[g_stdin_idx] == 0) { + gs_time_sleep_ms(timeout_ms); + return GS_ERROR_TIMEOUT; + } + + *ch = g_stdin_buf[g_stdin_idx]; + g_stdin_idx++; + return GS_OK; +} + +static gs_command_io_functions_t g_test_io_functions = { + .set_result = test_set_result, + .flush = test_flush, + .wait_for_key = test_wait_for_key, +}; + + +static gs_error_t prepare_validation(const char *input) +{ + g_results_count = 0; + memset(g_stdout_buf, 0, sizeof(g_stdout_buf)); + memset(g_stdin_buf, 0, sizeof(g_stdin_buf)); + g_stdin_idx = 0; + + if (input != NULL) { + memcpy(g_stdin_buf, input, strlen(input)); + } + + g_output_file = fmemopen(g_stdout_buf, sizeof(g_stdout_buf) - 1, "w"); + if (!g_output_file) { + return GS_ERROR_ALLOC; + } + + return GS_OK; +} + +static bool match(const char *first, const char * second) +{ + return (fnmatch(first, second, 0) == 0); +} + +static gs_error_t do_validation(const char *expected) +{ + fclose(g_output_file); + + if (expected == NULL) + return GS_OK; + + if (!match(expected, g_stdout_buf)) + { + return GS_ERROR_DATA; + } + return GS_OK; +} + + +void _gs_assert_command_validate(const char *cmd, gs_error_t ret, gs_error_t cmd_ret, const char *std_in, const char *std_out, + const char * const file, const int line) +{ + if (prepare_validation(std_in) != GS_OK) + { + cm_print_error("Validation function failed to allocate it's resources\n"); + _fail(file, line); + } + + gs_error_t _ret; + gs_error_t _command_ret = GS_OK; + _ret = gs_command_execute(cmd, &_command_ret, g_output_file, &g_test_io_functions, NULL); + + if (_ret != ret) { + cm_print_error("Return: %d(%s) != %d(%s)\n", _ret, gs_error_string(_ret), ret, gs_error_string(ret)); + _fail(file, line); + } + + if (_ret == GS_OK) /* Only check CMD return if command execution succeeded */ + { + if (_command_ret != cmd_ret) { + cm_print_error("Command return: %d(%s) != %d(%s)\n", _command_ret, gs_error_string(_command_ret), + cmd_ret, gs_error_string(cmd_ret)); + _fail(file, line); + } + } + + if (do_validation(std_out) != GS_OK) + { + //cm_print_error("Stdout != : \n%s\n!=\n%s\n", g_stdout_buf, std_out); + printf("Stdout != : \n%s\n!=\n%s\n", g_stdout_buf, std_out); + _fail(file, line); + } + + return; +} + +void _gs_assert_command_validate_last_result(unsigned int no, const char *group, const char *key, const char *value, + const char * const file, const int line) +{ + if (no >= g_results_count) + { + cm_print_error("Result no: %d not available. Only %d results returned from command\n", no, g_results_count); + _fail(file, line); + } + + if (group) { + if (!match(group, g_results[no].group)) { + cm_print_error("group: %s != %s\n", group, g_results[no].group); + _fail(file, line); + } + } + if (key) { + if (!match(key, g_results[no].key)) { + cm_print_error("key: %s != %s\n", key, g_results[no].key); + _fail(file, line); + } + } + if (value) { + if (!match(value, g_results[no].value)) { + cm_print_error("value: %s != %s\n", value, g_results[no].value); + _fail(file, line); + } + } + + return; +} diff --git a/gomspace/libutil/src/test/log.c b/gomspace/libutil/src/test/log.c new file mode 100644 index 00000000..ba7671e1 --- /dev/null +++ b/gomspace/libutil/src/test/log.c @@ -0,0 +1,165 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// cmocka +void cm_print_error(const char * const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); + +static gs_mutex_t g_lock; + +#define GS_TEST_LOG_MAX_LEVELS 6 +#define GS_TEST_LOG_MAX_LOG_MESSAGES 200 + +typedef struct { + // Overall count per log level. + unsigned int count[GS_TEST_LOG_MAX_LEVELS]; + // Log messages. + struct { + // Level. + gs_log_level_t level; + // Format log message. + char msg[150]; + } logs[GS_TEST_LOG_MAX_LOG_MESSAGES]; + // Index of next entry in \a logs. + unsigned int next_log; +} gs_test_log_stats_t; + +static gs_test_log_stats_t gs_test_log_stats; + +static void log_callback(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t * group, const gs_timestamp_t * ts, const char * format, va_list va) +{ + gs_mutex_lock(g_lock); + gs_test_log_stats.count[level]++; + + { + gs_bytebuffer_t bb; + gs_bytebuffer_init(&bb, + gs_test_log_stats.logs[gs_test_log_stats.next_log].msg, + sizeof(gs_test_log_stats.logs[gs_test_log_stats.next_log].msg)); + + va_list my_va; + va_copy(my_va, va); + gs_bytebuffer_printf(&bb, "%s: ", group->name); + gs_bytebuffer_vprintf(&bb, format, my_va); + va_end(my_va); + gs_bytebuffer_get_as_string(&bb, NULL); // ensure NUL termination + gs_test_log_stats.logs[gs_test_log_stats.next_log].level = level; + + ++gs_test_log_stats.next_log; + if (gs_test_log_stats.next_log >= GS_TEST_LOG_MAX_LOG_MESSAGES) { + gs_test_log_stats.next_log = 0; + } + gs_test_log_stats.logs[gs_test_log_stats.next_log].msg[0] = 0; // clear next entry + gs_test_log_stats.logs[gs_test_log_stats.next_log].level = GS_TEST_LOG_MAX_LEVELS; + } + + gs_mutex_unlock(g_lock); +} + +static gs_log_appender_driver_t g_log_test_appender_driver = { + .init = 0, + .append = log_callback, + .append_isr = log_callback, +}; + +static gs_log_appender_t g_log_test_appender = { + .name = "test_appender", + .drv = &g_log_test_appender_driver, + .drv_config = NULL, + .drv_data = NULL, + .mask = LOG_ALL_MASK, +}; + +void gs_test_log_init(bool verbose) +{ + gs_log_init(true); + + if (g_lock == NULL) { + GS_ASSERT_ERROR_EQUAL(gs_mutex_create(&g_lock), GS_OK); + + /* Add/Register appender - Only first time that init is called. */ + gs_log_appender_add(&g_log_test_appender, 1); + gs_log_group_register_appender("root", "test_appender"); + } + if (verbose) { + gs_log_appender_set_level_mask("console", LOG_ALL_MASK); + } else { + gs_log_appender_set_level_mask("console", 0); + } + + gs_test_log_clear(); +} + +void gs_test_log_clear(void) +{ + gs_mutex_lock(g_lock); + memset(&gs_test_log_stats, 0, sizeof(gs_test_log_stats)); + gs_mutex_unlock(g_lock); +} + +void gs_assert_log_count(int level, unsigned int count, const char * file, int line) +{ + if (level < 0) { + unsigned int tot = 0; + for (int i = 0; i < GS_TEST_LOG_MAX_LEVELS; ++i) { + tot += gs_test_log_stats.count[i]; + } + if (tot != count) { + cm_print_error("Unexpected total log count: %u != %u\n", tot, count); + _fail(file, line); + } + } else if (level >= GS_TEST_LOG_MAX_LEVELS) { + cm_print_error("Unknown log level: %d - valid levels 0 - %d\n", level, GS_TEST_LOG_MAX_LEVELS - 1); + _fail(file, line); + } else if (gs_test_log_stats.count[level] != count) { + cm_print_error("Unexpected log count: %u != %u\n", gs_test_log_stats.count[level], count); + _fail(file, line); + } +} + +void gs_assert_log(unsigned int stack_index, unsigned int count, gs_log_level_t level, const char * pattern, const char * file, int line) +{ + if (stack_index == UINT32_MAX) { + // loop through all logs + unsigned int next = gs_test_log_stats.next_log; + unsigned int hits = 0; + for (unsigned int i = next - 1; i != next; --i) { + if (i >= GS_TEST_LOG_MAX_LOG_MESSAGES) { + i = (GS_TEST_LOG_MAX_LOG_MESSAGES - 1); + } + if ((gs_test_log_stats.logs[i].level == level) && (gs_test_log_stats.logs[i].msg[0])) { + if (fnmatch(pattern, gs_test_log_stats.logs[i].msg, 0) == 0) { + ++hits; + } + } + } + if (hits != count) { + cm_print_error("Unexpected log count: %u != %u\n", hits, count); + _fail(file, line); + } + } else if (stack_index >= GS_TEST_LOG_MAX_LOG_MESSAGES) { + cm_print_error("Invalid stack_index: %u - valid 0 - %d\n", stack_index, GS_TEST_LOG_MAX_LOG_MESSAGES - 1); + _fail(file, line); + } else { + unsigned int i = (((gs_test_log_stats.next_log + GS_TEST_LOG_MAX_LOG_MESSAGES) - 1 - stack_index) % GS_TEST_LOG_MAX_LOG_MESSAGES); + if ((gs_test_log_stats.logs[i].level == level) && + (gs_test_log_stats.logs[i].msg[0]) && + (fnmatch(pattern, gs_test_log_stats.logs[i].msg, 0) == 0)) { + // match + } else { + cm_print_error("[%c][%s] != [%c][%s]\n", + gs_log_level_to_char(gs_test_log_stats.logs[i].level), gs_test_log_stats.logs[i].msg, + gs_log_level_to_char(level), pattern); + _fail(file, line); + } + } +} diff --git a/gomspace/libutil/src/time.c b/gomspace/libutil/src/time.c new file mode 100644 index 00000000..123f5994 --- /dev/null +++ b/gomspace/libutil/src/time.c @@ -0,0 +1,28 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include + +uint32_t gs_time_diff_ms(uint32_t ref_ms, uint32_t now_ms) +{ + if (now_ms >= ref_ms) { + return (now_ms - ref_ms); + } + + // assuming time wrapped at max uint32_t + return ((UINT32_MAX - ref_ms) + now_ms); +} + +bool gs_time_sleep_until_ms(uint32_t * ref_ms, uint32_t sleep_ms) +{ + const uint32_t now = gs_time_rel_ms(); + *ref_ms += sleep_ms; // this is expected to be in the future + uint32_t ms = gs_time_diff_ms(now, *ref_ms); + if (ms > sleep_ms) { + // we are behind - catch up, could be bad seed or too long processing + *ref_ms = now; + gs_time_sleep_ms(0); // yield - let others have a go + return true; + } + gs_time_sleep_ms(ms); + return false; +} diff --git a/gomspace/libutil/src/timestamp.c b/gomspace/libutil/src/timestamp.c new file mode 100644 index 00000000..2f7ee913 --- /dev/null +++ b/gomspace/libutil/src/timestamp.c @@ -0,0 +1,61 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include + +int timestamp_add(gs_timestamp_t * base, const gs_timestamp_t * add) +{ + if (!base || !add) + return -1; + + base->tv_sec += add->tv_sec; + if (base->tv_nsec + add->tv_nsec >= GS_TIMESTAMP_NSEC_PER_SEC) { + base->tv_sec++; + base->tv_nsec = (base->tv_nsec + add->tv_nsec) % GS_TIMESTAMP_NSEC_PER_SEC; + } else { + base->tv_nsec += add->tv_nsec; + } + + return 0; +} + +int timestamp_diff(gs_timestamp_t * base, const gs_timestamp_t * diff) +{ + if (!base || !diff) + return -1; + + base->tv_sec -= diff->tv_sec; + if (base->tv_nsec >= diff->tv_nsec) { + base->tv_nsec -= diff->tv_nsec; + } else { + base->tv_sec--; + base->tv_nsec = (base->tv_nsec + GS_TIMESTAMP_NSEC_PER_SEC) - diff->tv_nsec; + } + + return 0; +} + +/* Test is timestamp is greater or equal */ +int timestamp_ge(const gs_timestamp_t * base, const gs_timestamp_t * test) +{ + if (!base || !test) + return -1; + + if (test->tv_sec > base->tv_sec || + (test->tv_sec == base->tv_sec && + test->tv_nsec > base->tv_nsec)) { + return 1; + } + + return 0; +} + +int timestamp_copy(const gs_timestamp_t * from, gs_timestamp_t * to) +{ + if (!from || !to) + return -1; + + to->tv_sec = from->tv_sec; + to->tv_nsec = from->tv_nsec; + + return 0; +} diff --git a/gomspace/libutil/src/vmem/commands.c b/gomspace/libutil/src/vmem/commands.c new file mode 100644 index 00000000..06a37af4 --- /dev/null +++ b/gomspace/libutil/src/vmem/commands.c @@ -0,0 +1,123 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +static int cmd_vmem_read(gs_command_context_t * ctx) +{ + if (gs_vmem_get_map() == NULL) { + return GS_ERROR_NOT_FOUND; + } + + void * addr; + if (gs_string_to_pointer(ctx->argv[1], &addr)) { + return GS_ERROR_ARG; + } + + uint32_t length; + if (gs_string_to_uint32(ctx->argv[2], &length)) { + return GS_ERROR_ARG; + } + + char data[length]; + void* to = gs_vmem_cpy(data, addr, length); + if (to == NULL) { + return GS_ERROR_ARG; + } + + gs_hexdump_to_stream(data, length, addr, ctx->out); + + return GS_OK; +} + +static unsigned int to_int(char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'A' && c <= 'F') return 10 + c - 'A'; + if (c >= 'a' && c <= 'f') return 10 + c - 'a'; + return -1; +} + +static int cmd_vmem_write(gs_command_context_t * ctx) +{ + if (gs_vmem_get_map() == NULL) { + return GS_ERROR_NOT_FOUND; + } + + void * addr; + if (gs_string_to_pointer(ctx->argv[1], &addr)) { + return GS_ERROR_ARG; + } + + int len = strlen(ctx->argv[2]) / 2; + char data[len]; + + for (int i = 0; (i < len); ++i) { + data[i] = 16 * to_int(ctx->argv[2][2*i]) + to_int(ctx->argv[2][2*i+1]); + } + + gs_vmem_cpy(addr, data, len); + return GS_OK; +} + +static int cmd_vmem_list(gs_command_context_t * ctx) +{ + return gs_vmem_list(ctx->out); +} + +static int cmd_vmem_lock(gs_command_context_t * context) +{ + return gs_vmem_lock_by_name(context->argv[1], true); +} + +static int cmd_vmem_unlock(gs_command_context_t * context) +{ + return gs_vmem_lock_by_name(context->argv[1], false); +} + +static const gs_command_t GS_COMMAND_SUB cmd_vmem_sub[] = { + { + .name = "read", + .help = "Read from virtual memory", + .usage = " ", + .handler = cmd_vmem_read, + .mandatory_args = 2, + },{ + .name = "write", + .help = "Write to virtual memory", + .usage = " ", + .handler = cmd_vmem_write, + .mandatory_args = 2, + },{ + .name = "lock", + .help = "Lock the virtual memory", + .usage = "", + .handler = cmd_vmem_lock, + .mandatory_args = 1, + },{ + .name = "unlock", + .help = "Unlock the virtual memory", + .usage = "", + .handler = cmd_vmem_unlock, + .mandatory_args = 1, + },{ + .name = "list", + .help = "Show virtual memory mappings", + .handler = cmd_vmem_list, + .mandatory_args = GS_COMMAND_NO_ARGS, + } +}; + +static const gs_command_t GS_COMMAND_ROOT cmd_vmem[] = { + { + .name = "vmem", + .help = "Virtual memory", + .chain = GS_COMMAND_INIT_CHAIN(cmd_vmem_sub), + }, +}; + +gs_error_t gs_vmem_register_commands(void) +{ + return GS_COMMAND_REGISTER(cmd_vmem); +} diff --git a/gomspace/libutil/src/vmem/vmem.c b/gomspace/libutil/src/vmem/vmem.c new file mode 100644 index 00000000..30068a01 --- /dev/null +++ b/gomspace/libutil/src/vmem/vmem.c @@ -0,0 +1,143 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include + +static const gs_vmem_t * g_vmem_map; + +gs_error_t gs_vmem_set_map(const gs_vmem_t * map) +{ + g_vmem_map = map; + return GS_OK; +} + +const gs_vmem_t * gs_vmem_get_map(void) +{ + return g_vmem_map; +} + +gs_error_t gs_vmem_list(FILE * out) +{ + const gs_vmem_t * mem = g_vmem_map; + if (mem) { + unsigned int found = 0; + for (; mem->name; ++mem) { + if (found == 0) { + fprintf(out, "%-20s %-10s %-6s %-6s %s\r\n", "name", "virt.", "phys.", "size", "size"); + } + fprintf(out, "%-20s %p 0x%04x 0x%04x %5u\r\n", mem->name, mem->virtmem.p, (unsigned int) mem->physmem.u, (unsigned int) mem->size, (unsigned int) mem->size); + ++found; + } + if (found) { + return GS_OK; + } + } + return GS_ERROR_NOT_FOUND; +} + +const gs_vmem_t * gs_vmem_get_by_name(const char * name) +{ + if (name) { + const gs_vmem_t * mem = g_vmem_map; + if (mem) { + for (; mem->name; ++mem) { + if (strcasecmp(name, mem->name) == 0) { + return mem; + } + } + } + } + return NULL; +} + +gs_error_t gs_vmem_lock_by_name(const char * name, bool on) +{ + const gs_vmem_t * mem = gs_vmem_get_by_name(name); + if (mem) { + if (mem->drv && mem->drv->lock) { + return (mem->drv->lock)(mem, on); + } + return GS_ERROR_NOT_SUPPORTED; + } + return GS_ERROR_NOT_FOUND; +} + +gs_error_t gs_vmem_lock_all(bool on) +{ + const gs_vmem_t * mem = g_vmem_map; + if (mem) { + unsigned int locked = 0; + for (; mem->name; ++mem) { + if (mem->drv && mem->drv->lock) { + (mem->drv->lock)(mem, on); + ++locked; + } + } + if (locked) { + return GS_OK; + } + } + return GS_ERROR_NOT_FOUND; +} + +/** + @note NO LOGGING - currently the log system uses this interface, and logging can therefor create circular/forever loops. +*/ +void * gs_vmem_cpy(void* to, const void* from, size_t size) +{ + /* Search memories */ + const gs_vmem_t *vmem_from = NULL; + const gs_vmem_t *vmem_to = NULL; + const gs_vmem_t *mem = g_vmem_map; + const gs_address_t _to = {.p = to}; + const gs_address_t _from = {.p = (void*) from}; + + if (mem) { + while(mem->size != 0) { + //printf("0x%lx 0x%lx %"PRIu32" %lu %lu\r\n", mem->start, mem->physmem_start, mem->size, to, from); + if ((_to.u >= mem->virtmem.u) && (_to.u < mem->virtmem.u + mem->size)) { + vmem_to = mem; + } + if ((_from.u >= mem->virtmem.u) && (_from.u < mem->virtmem.u + mem->size)) { + vmem_from = mem; + } + mem++; + } + } + + // VMEM -> VMEM + if (vmem_to && vmem_from) { + printf("%s: VMEM to VMEM is not supported\r\n", __FUNCTION__); + return NULL; + } + + // RAM -> VMEM + if (vmem_to) { + if ((vmem_to->drv == NULL) || (vmem_to->drv->write == NULL)) { + printf("%s: Writting to VMEM %p is not supported\r\n", __FUNCTION__, to); + return NULL; + } + gs_address_t physaddr = {.u = (_to.u - vmem_to->virtmem.u) + vmem_to->physmem.u}; + //printf("Copying from ram 0x%lx to physaddr 0x%lx %u\r\n", from, physaddr, (unsigned int) size); + vmem_to->drv->write(vmem_to, physaddr.p, from, size); + return to; + } + + // VMEM -> RAM + if (vmem_from) { + if (vmem_from->drv == NULL || (vmem_from->drv->read == NULL)) { + printf("%s: Reading from VMEM %p is not supported\r\n", __FUNCTION__, from); + return NULL; + } + gs_address_t physaddr = {.u = (_from.u - vmem_from->virtmem.u) + vmem_from->physmem.u}; + //printf("Copying from mem physaddr 0x%lx to 0x%lx %u\r\n", physaddr, to, (unsigned int) size); + vmem_from->drv->read(vmem_from, to, physaddr.p, size); + return to; + } + + // RAM -> RAM (no VMEM mapping found) + return memcpy(to, from, size); +} diff --git a/gomspace/libutil/src/watchdog/local.h b/gomspace/libutil/src/watchdog/local.h new file mode 100644 index 00000000..1dc2e0de --- /dev/null +++ b/gomspace/libutil/src/watchdog/local.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include + +typedef struct { + gs_thread_t task; + bool is_running; + bool do_stop; +} gs_swwd_monitor_task_t; + +// Return monitor task instance +gs_swwd_monitor_task_t * gs_swwd_get_monitor_task(void); + +GS_LOG_GROUP_EXTERN(gs_swwd_log); +#define LOG_DEFAULT gs_swwd_log diff --git a/gomspace/libutil/src/watchdog/monitor_task.c b/gomspace/libutil/src/watchdog/monitor_task.c new file mode 100644 index 00000000..54d7e668 --- /dev/null +++ b/gomspace/libutil/src/watchdog/monitor_task.c @@ -0,0 +1,68 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include "local.h" +#include +#include +#include + +#define GS_SWWD_CHECK_INTERVAL_MS 1000 /* Check every 1 sec. */ + +static void * gs_swwd_monitor_task(void* parameter) +{ + gs_swwd_monitor_task_t * monitor = parameter; + + log_info("monitor task started"); + + monitor->is_running = true; + + while(!monitor->do_stop) { + + gs_time_sleep_ms(GS_SWWD_CHECK_INTERVAL_MS); + + gs_swwd_check_expired_clients(NULL); + } + + monitor->is_running = false; + + log_info("monitor task exiting"); + + return NULL; +} + +gs_error_t gs_swwd_monitor_task_start(void) +{ + gs_swwd_monitor_task_t * monitor = gs_swwd_get_monitor_task(); + GS_CHECK_SUPPORTED(monitor != NULL); /* SWWD must be initialized */ + GS_CHECK_SUPPORTED(monitor->is_running == false); /* SWWD task must not already be running */ + + /* Start the monitor task */ + gs_error_t error = gs_thread_create("SWWD", gs_swwd_monitor_task, monitor, 4000, GS_THREAD_PRIORITY_HIGH, 0, &monitor->task); + if (error) { + log_error("%s: gs_thread_create() failed, error: %s", __FUNCTION__, gs_error_string(error)); + } + return error; +} + +gs_error_t gs_swwd_monitor_task_stop(uint32_t timeout_s) +{ + gs_swwd_monitor_task_t * monitor = gs_swwd_get_monitor_task(); + GS_CHECK_SUPPORTED(monitor != NULL); /* SWWD must be initialized */ + + /* Signal the task to stop */ + monitor->do_stop = true; + + /* Wait for the task to stop */ + const uint32_t timeout = GS_SWWD_CHECK_INTERVAL_MS + (timeout_s * 1000); + uint32_t tm = 0; + while(monitor->is_running && (tm < timeout)) { + gs_thread_sleep_ms(100); + tm += 100; + } + + if (monitor->is_running) { + return GS_ERROR_BUSY; + } + + return GS_OK; +} + diff --git a/gomspace/libutil/src/watchdog/watchdog.c b/gomspace/libutil/src/watchdog/watchdog.c new file mode 100644 index 00000000..867601b1 --- /dev/null +++ b/gomspace/libutil/src/watchdog/watchdog.c @@ -0,0 +1,292 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include "local.h" +#include +#include +#include +#include +#include + +#define GS_SWWD_DEFAULT_TIMEOUT 30 /* 30 second timeout */ + +// define log group and make it default +GS_LOG_GROUP(gs_swwd_log, "swwd", GS_LOG_CAT_DEFAULT, GS_LOG_DEFAULT_MASK); + +// watchdog state +typedef enum { + GS_SWWD_STATE_FREE = 0, + GS_SWWD_STATE_ACTIVE = 1, + GS_SWWD_STATE_EXPIRED = 2, +} gs_swwd_state_t; + +// watchdog client instance +struct gs_swwd_hdl { + // State + gs_swwd_state_t state; + // Last 'user' touch value - used for detecting if watchdog has been touched (avoid race condition) + uint32_t last_touch; + // Last detected touch time + uint32_t last_touch_ms; + + // User 'set' attributes + struct { + // Name + const char* name; + // Timeout - converted from seconds (given to API) to mS + uint32_t timeout_ms; + // Action when/if timeout occurs + gs_swwd_timeout_action_t action; + // callback + gs_swwd_callback_function_t cb; + // user data (for callback) + void * cb_userdata; + // Touch - incremented on each touch + uint32_t touch; + } user; +}; + +typedef struct gs_swwd { + gs_watchdog_device_t *wdev; + gs_mutex_t lock; + gs_swwd_monitor_task_t monitor; + uint32_t num_clients; + gs_swwd_hdl_t clients[0]; +} gs_swwd_t; + +static gs_swwd_t* g_swwd = NULL; + +gs_swwd_monitor_task_t * gs_swwd_get_monitor_task(void) +{ + if (g_swwd) { + return &g_swwd->monitor; + } + return NULL; +} + +gs_error_t gs_swwd_create(uint32_t max_clients, gs_watchdog_device_t * wdev) +{ + GS_CHECK_SUPPORTED(g_swwd == NULL); /* SWWD must not be initialized more than once */ + GS_CHECK_ARG(max_clients > 0); + if (wdev) { + // ping is the only mandatory + GS_CHECK_ARG((wdev->ops != NULL) && (wdev->ops->ping != NULL)); + } + + gs_log_group_register(LOG_DEFAULT); + + gs_swwd_t *swwd_obj = calloc(1, sizeof(*swwd_obj) + (sizeof(swwd_obj->clients[0]) * max_clients)); + if (swwd_obj == NULL) { + return GS_ERROR_ALLOC; + } + + if (gs_mutex_create(&(swwd_obj->lock))) { + free(swwd_obj); + return GS_ERROR_ALLOC; + } + + swwd_obj->num_clients = max_clients; + swwd_obj->wdev = wdev; + + if (wdev) { + if (wdev->ops->set_timeout) { + wdev->ops->set_timeout(wdev, (wdev->timeout > 0) ? wdev->timeout : GS_SWWD_DEFAULT_TIMEOUT); + } + if (wdev->ops->set_pretimeout) { + wdev->ops->set_pretimeout(wdev, (wdev->pretimeout > 0) ? wdev->pretimeout : (GS_SWWD_DEFAULT_TIMEOUT - (GS_SWWD_DEFAULT_TIMEOUT/10))); + } + if (wdev->ops->start) { + wdev->ops->start(wdev); + } + wdev->ops->ping(wdev); + + } else { + log_warning("%s: no watchdog device specifed - cannot reset system!", __FUNCTION__); + } + + g_swwd = swwd_obj; /* Set the task handle as the last operation */ + return GS_OK; +} + +gs_error_t gs_swwd_destroy(uint32_t timeout_s) +{ + GS_CHECK_SUPPORTED(g_swwd != NULL); + + if (gs_swwd_monitor_task_stop(timeout_s) != GS_OK) { + return GS_ERROR_BUSY; + } + + if (g_swwd->wdev && g_swwd->wdev->ops->stop) { + g_swwd->wdev->ops->stop(g_swwd->wdev); + } + + gs_mutex_destroy(g_swwd->lock); + free(g_swwd); + g_swwd = NULL; + + return GS_OK; +} + +static const char * get_action(gs_swwd_timeout_action_t action) +{ + switch (action) { + case GS_SWWD_TIMEOUT_ACTION_RESET: + return "reset"; + case GS_SWWD_TIMEOUT_ACTION_LOG: + return "log"; + } + return "unknown"; +} + +gs_error_t gs_swwd_check_expired_clients(uint32_t *num_expired) +{ + GS_CHECK_SUPPORTED(g_swwd != NULL); /* SWWD must be initialized */ + + uint32_t expired_clients_reset = 0; + uint32_t expired_clients_log = 0; + + gs_mutex_lock(g_swwd->lock); + for (uint32_t idx = 0; idx < g_swwd->num_clients; idx++) { + gs_swwd_hdl_t * wd = &g_swwd->clients[idx]; + + uint32_t now_ms = gs_time_rel_ms(); + if (wd->state == GS_SWWD_STATE_ACTIVE) { + if (wd->last_touch != wd->user.touch) { + // watchdog has been touched since last we checked - update touch time + wd->last_touch = wd->user.touch; + wd->last_touch_ms = now_ms; + } else { + const uint32_t elapsed_ms = gs_time_diff_ms(wd->last_touch_ms, now_ms); + if (elapsed_ms >= wd->user.timeout_ms) { + wd->state = GS_SWWD_STATE_EXPIRED; + + char logbuf[100]; + snprintf(logbuf, sizeof(logbuf), + "[%s] expired -> %s (elapsed %"PRIu32" mS, timeout %"PRIu32" mS)", + wd->user.name, + get_action(wd->user.action), + elapsed_ms, + wd->user.timeout_ms); + + gs_swwd_callback_function_t cb = wd->user.cb; + void * cb_userdata = wd->user.cb_userdata; + + // Unlock while doing log and callback + // - we accept the tiny risk, that client has deregistered and will be called with invalid data + gs_mutex_unlock(g_swwd->lock); + { + log_error("%s", logbuf); + if (cb) { + (cb)(cb_userdata); + } + } + gs_mutex_lock(g_swwd->lock); + } + } + } + if (wd->state == GS_SWWD_STATE_EXPIRED) { + switch (wd->user.action) { + case GS_SWWD_TIMEOUT_ACTION_RESET: + ++expired_clients_reset; + break; + case GS_SWWD_TIMEOUT_ACTION_LOG: + if (wd->last_touch != wd->user.touch) { + // its alive - reactive watchdog + wd->state = GS_SWWD_STATE_ACTIVE; + wd->last_touch = wd->user.touch; + wd->last_touch_ms = now_ms; + } else { + ++expired_clients_log; + } + break; + } + } + } + gs_mutex_unlock(g_swwd->lock); + + if ((expired_clients_reset == 0) && g_swwd->wdev) { + g_swwd->wdev->ops->ping(g_swwd->wdev); + } + + if (num_expired) { + *num_expired = (expired_clients_reset + expired_clients_log); + } + + return GS_OK; +} + +gs_error_t gs_swwd_register_with_action(gs_swwd_hdl_t ** user_wd, + uint32_t timeout_seconds, + gs_swwd_callback_function_t callback, void * userdata, + const char * name, + gs_swwd_timeout_action_t action) +{ + GS_CHECK_ARG(gs_string_empty(name) == false); + GS_CHECK_ARG(timeout_seconds > 0); + GS_CHECK_ARG(user_wd != NULL); + GS_CHECK_SUPPORTED(g_swwd != NULL); /* SWWD must be initialized */ + + gs_swwd_hdl_t * wd = NULL; + gs_mutex_lock(g_swwd->lock); + { + for (unsigned int idx = 0; idx < g_swwd->num_clients; idx++) { + if (g_swwd->clients[idx].state == GS_SWWD_STATE_FREE) { + wd = &g_swwd->clients[idx]; + memset(wd, 0, sizeof(*wd)); + + // set user stuff + wd->user.name = name; + wd->user.timeout_ms = (timeout_seconds * 1000); + wd->user.cb = callback; + wd->user.cb_userdata = userdata; + wd->user.action = action; + + // set internal stuff + wd->state = GS_SWWD_STATE_ACTIVE; + wd->last_touch_ms = gs_time_rel_ms(); + break; + } + } + } + gs_mutex_unlock(g_swwd->lock); + + *user_wd = wd; + + if (wd == NULL) { + log_error("[%s] cannot create instance due to no available handles", name); + return GS_ERROR_FULL; + } + + return GS_OK; +} + +gs_error_t gs_swwd_deregister(gs_swwd_hdl_t ** wd) +{ + GS_CHECK_SUPPORTED(g_swwd != NULL); /* SWWD must be initialized */ + GS_CHECK_ARG(wd != NULL); + GS_CHECK_HANDLE(*wd != NULL); + + gs_mutex_lock(g_swwd->lock); + memset((*wd), 0, sizeof(**wd)); + gs_mutex_unlock(g_swwd->lock); + *wd = NULL; + + return GS_OK; +} + +gs_error_t gs_swwd_touch(gs_swwd_hdl_t * wd) +{ + GS_CHECK_HANDLE(wd != NULL); + + ++wd->user.touch; + return GS_OK; +} + +gs_error_t gs_swwd_set_timeout(gs_swwd_hdl_t * wd, uint32_t timeout_seconds) +{ + GS_CHECK_ARG(timeout_seconds > 0); + GS_CHECK_HANDLE(wd != NULL); + + ++wd->user.touch; + wd->user.timeout_ms = (timeout_seconds * 1000); + return GS_OK; +} diff --git a/gomspace/libutil/src/zip/cppcheck-suppress.txt b/gomspace/libutil/src/zip/cppcheck-suppress.txt new file mode 100644 index 00000000..b23b687d --- /dev/null +++ b/gomspace/libutil/src/zip/cppcheck-suppress.txt @@ -0,0 +1,5 @@ +// we don't wanna change 3rd part code for none-critical issue +localtimeCalled:src/zip/miniz/miniz.c +utimeCalled:src/zip/miniz/miniz.c +assignIfError:src/zip/miniz/miniz.c +unreadVariable:src/zip/miniz/miniz.c diff --git a/gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES b/gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES new file mode 100644 index 00000000..cb7adb22 --- /dev/null +++ b/gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES @@ -0,0 +1,9429 @@ +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +diff --git a/src/zip/miniz/miniz.h b/src/zip/miniz/miniz.h +index 86fac4c..f92f14e 100644 +--- a/src/zip/miniz/miniz.h ++++ b/src/zip/miniz/miniz.h +@@ -447,7 +447,7 @@ typedef void *const voidpc; + #define inflate mz_inflate + #define inflateEnd mz_inflateEnd + #define uncompress mz_uncompress +-#define crc32 mz_crc32 ++// #define crc32 mz_crc32 + #define adler32 mz_adler32 + #define MAX_WBITS 15 + #define MAX_MEM_LEVEL 9 + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + +diff --git a/src/zip/miniz/miniz.c b/src/zip/miniz/miniz.c +index 67318cc..960f07c 100644 +--- a/src/zip/miniz/miniz.c ++++ b/src/zip/miniz/miniz.c +@@ -1936,6 +1936,7 @@ tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_fun + d->m_pSrc = NULL; + d->m_src_buf_left = 0; + d->m_out_buf_ofs = 0; ++ memset(d->m_dict, 0, sizeof(d->m_dict)); // Initialize array to 0's + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +@@ -2464,7 +2465,7 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_nex + } + r->m_table_sizes[2] = 19; + } +- for (; (int)r->m_type >= 0; r->m_type--) ++ for (; ((int)r->m_type) >= 0; r->m_type--) + { + int tree_next, tree_cur; + tinfl_huff_table *pTable; +@@ -3025,7 +3026,7 @@ static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) + #define MZ_DELETE_FILE remove + + #else +-#pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") ++// #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") + #ifndef MINIZ_NO_TIME + #include + #endif +@@ -3267,12 +3268,12 @@ static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) + } + + #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +-static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) ++static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) + { + #ifdef _MSC_VER + struct tm tm_struct; + struct tm *tm = &tm_struct; +- errno_t err = localtime_s(tm, &time); ++ errno_t err = localtime_s(tm, &time_); + if (err) + { + *pDOS_date = 0; +@@ -3280,7 +3281,7 @@ static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_u + return; + } + #else +- struct tm *tm = localtime(&time); ++ struct tm *tm = localtime(&time_); + #endif /* #ifdef _MSC_VER */ + + *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); +@@ -3874,7 +3875,10 @@ mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, + /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ + + if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) ++ { ++ MZ_FCLOSE(pFile); + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); ++ } + + if (!mz_zip_reader_init_internal(pZip, flags)) + { +@@ -4134,7 +4138,7 @@ static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_inde + + pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); + pField_data += sizeof(mz_uint64); +- field_data_remaining -= sizeof(mz_uint64); ++ // field_data_remaining -= sizeof(mz_uint64); + } + + break; +@@ -4219,11 +4223,11 @@ static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) + { +- mz_uint32 index; +- if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index)) ++ mz_uint32 index_; ++ if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) + return -1; + else +- return (int)index; ++ return (int)index_; + } + + mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) +@@ -5332,12 +5336,12 @@ mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) + if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) + { + mz_uint32 found_index; +- mz_zip_archive_file_stat stat; ++ mz_zip_archive_file_stat stat_; + +- if (!mz_zip_reader_file_stat(pZip, i, &stat)) ++ if (!mz_zip_reader_file_stat(pZip, i, &stat_)) + return MZ_FALSE; + +- if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index)) ++ if (!mz_zip_reader_locate_file_v2(pZip, stat_.m_filename, NULL, 0, &found_index)) + return MZ_FALSE; + + /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ +@@ -6011,6 +6015,11 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n + mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, + const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) + { ++ if(!pZip) ++ { ++ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++ } ++ + mz_uint16 method = 0, dos_time = 0, dos_date = 0; + mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; +@@ -6035,7 +6044,7 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n + level = level_and_flags & 0xF; + store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + +- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) ++ if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; +@@ -6296,6 +6305,11 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n + mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) + { ++ if(!pZip) ++ { ++ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++ } ++ + mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; + mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; + mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; +@@ -6315,7 +6329,7 @@ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, + level = level_and_flags & 0xF; + + /* Sanity checks */ +- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) ++ if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; +@@ -6828,7 +6842,7 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { +- const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); ++ // const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); + + if (field_data_size < sizeof(mz_uint64) * 2) + { +@@ -6836,8 +6850,8 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + +- local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); +- local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ ++ // local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); ++ // local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ + + found_zip64_ext_data_in_ldir = MZ_TRUE; + break; +@@ -6966,7 +6980,7 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + +- cur_src_file_ofs += n; ++ // cur_src_file_ofs += n; + cur_dst_file_ofs += n; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + +diff --git a/src/zip/miniz/miniz.h b/src/zip/miniz/miniz.h +index 68f903c..e517263 100644 +--- a/src/zip/miniz/miniz.h ++++ b/src/zip/miniz/miniz.h +@@ -203,7 +203,7 @@ mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + + #define MZ_CRC32_INIT (0) + /* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ +-mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); ++// mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + + /* Compression strategies. */ + enum +@@ -301,7 +301,7 @@ typedef struct mz_stream_s + typedef mz_stream *mz_streamp; + + /* Returns the version string of miniz.c. */ +-const char *mz_version(void); ++// const char *mz_version(void); + + /* mz_deflateInit() initializes a compressor with default options: */ + /* Parameters: */ +@@ -324,7 +324,7 @@ int mz_deflateInit(mz_streamp pStream, int level); + int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); + + /* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ +-int mz_deflateReset(mz_streamp pStream); ++// int mz_deflateReset(mz_streamp pStream); + + /* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */ + /* Parameters: */ +@@ -345,7 +345,7 @@ int mz_deflate(mz_streamp pStream, int flush); + int mz_deflateEnd(mz_streamp pStream); + + /* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ +-mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); ++// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + + /* Single-call compression functions mz_compress() and mz_compress2(): */ + /* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ +@@ -353,7 +353,7 @@ int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char * + int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); + + /* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */ +-mz_ulong mz_compressBound(mz_ulong source_len); ++// mz_ulong mz_compressBound(mz_ulong source_len); + + /* Initializes a decompressor. */ + int mz_inflateInit(mz_streamp pStream); +@@ -386,7 +386,7 @@ int mz_inflateEnd(mz_streamp pStream); + int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); + + /* Returns a string description of the specified error code, or NULL if the error code is invalid. */ +-const char *mz_error(int err); ++// const char *mz_error(int err); + + /* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */ + /* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ +@@ -436,13 +436,13 @@ typedef void *const voidpc; + #define z_stream mz_stream + #define deflateInit mz_deflateInit + #define deflateInit2 mz_deflateInit2 +-#define deflateReset mz_deflateReset ++// #define deflateReset mz_deflateReset + #define deflate mz_deflate + #define deflateEnd mz_deflateEnd +-#define deflateBound mz_deflateBound ++// #define deflateBound mz_deflateBound + #define compress mz_compress + #define compress2 mz_compress2 +-#define compressBound mz_compressBound ++// #define compressBound mz_compressBound + #define inflateInit mz_inflateInit + #define inflateInit2 mz_inflateInit2 + #define inflate mz_inflate +@@ -452,15 +452,15 @@ typedef void *const voidpc; + #define adler32 mz_adler32 + #define MAX_WBITS 15 + #define MAX_MEM_LEVEL 9 +-#define zError mz_error ++// #define zError mz_error + #define ZLIB_VERSION MZ_VERSION + #define ZLIB_VERNUM MZ_VERNUM + #define ZLIB_VER_MAJOR MZ_VER_MAJOR + #define ZLIB_VER_MINOR MZ_VER_MINOR + #define ZLIB_VER_REVISION MZ_VER_REVISION + #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION +-#define zlibVersion mz_version +-#define zlib_version mz_version() ++// #define zlibVersion mz_version ++// #define zlib_version mz_version() + #endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ + + #endif /* MINIZ_NO_ZLIB_APIS */ +@@ -501,15 +501,15 @@ typedef int mz_bool; + #define MZ_FILE FILE + #endif /* #ifdef MINIZ_NO_STDIO */ + +-#ifdef MINIZ_NO_TIME +-typedef struct mz_dummy_time_t_tag +-{ +- int m_dummy; +-} mz_dummy_time_t; +-#define MZ_TIME_T mz_dummy_time_t +-#else +-#define MZ_TIME_T time_t +-#endif ++// #ifdef MINIZ_NO_TIME ++// typedef struct mz_dummy_time_t_tag ++// { ++// int m_dummy; ++// } mz_dummy_time_t; ++// #define MZ_TIME_T mz_dummy_time_t ++// #else ++// #define MZ_TIME_T time_t ++// #endif + + #define MZ_ASSERT(x) assert(x) + +@@ -551,7 +551,7 @@ extern "C" { + + extern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); + extern void miniz_def_free_func(void *opaque, void *address); +-extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); ++// extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); + + #define MZ_UINT16_MAX (0xFFFFU) + #define MZ_UINT32_MAX (0xFFFFFFFFU) +@@ -609,11 +609,11 @@ enum + /* Function returns a pointer to the compressed data, or NULL on failure. */ + /* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */ + /* The caller must free() the returned block when it's no longer needed. */ +-void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); ++// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + + /* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ + /* Returns 0 on failure. */ +-size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); ++// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + + /* Compresses an image to a compressed PNG file in memory. */ + /* On entry: */ +@@ -625,14 +625,14 @@ size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void + /* Function returns a pointer to the compressed data, or NULL on failure. */ + /* *pLen_out will be set to the size of the PNG image file. */ + /* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */ +-void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); +-void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); ++// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); ++// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); + + /* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ + typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); + + /* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */ +-mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); ++// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + + enum + { +@@ -727,9 +727,9 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI + + /* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ + /* tdefl_compress_buffer() always consumes the entire input buffer. */ +-tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); ++// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); + +-tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); ++// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); + mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + + /* Create tdefl_compress() flags given zlib-style compression parameters. */ +@@ -741,8 +741,8 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int + /* Allocate the tdefl_compressor structure in C so that */ + /* non-C language bindings to tdefl_ API don't need to worry about */ + /* structure size and allocation mechanism. */ +-tdefl_compressor *tdefl_compressor_alloc(); +-void tdefl_compressor_free(tdefl_compressor *pComp); ++// tdefl_compressor *tdefl_compressor_alloc(); ++// void tdefl_compressor_free(tdefl_compressor *pComp); + + #ifdef __cplusplus + } +@@ -775,17 +775,17 @@ enum + /* Function returns a pointer to the decompressed data, or NULL on failure. */ + /* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */ + /* The caller must call mz_free() on the returned block when it's no longer needed. */ +-void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); ++// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + + /* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ + /* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ + #define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +-size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); ++// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + + /* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */ + /* Returns 1 on success or 0 on failure. */ + typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); +-int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); ++// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + + struct tinfl_decompressor_tag; + typedef struct tinfl_decompressor_tag tinfl_decompressor; +@@ -794,8 +794,8 @@ typedef struct tinfl_decompressor_tag tinfl_decompressor; + /* non-C language bindings to tinfl_ API don't need to worry about */ + /* structure size and allocation mechanism. */ + +-tinfl_decompressor *tinfl_decompressor_alloc(); +-void tinfl_decompressor_free(tinfl_decompressor *pDecomp); ++// tinfl_decompressor *tinfl_decompressor_alloc(); ++// void tinfl_decompressor_free(tinfl_decompressor *pDecomp); + + /* Max size of LZ dictionary. */ + #define TINFL_LZ_DICT_SIZE 32768 +@@ -896,319 +896,319 @@ struct tinfl_decompressor_tag + + /* ------------------- ZIP archive reading/writing */ + +-#ifndef MINIZ_NO_ARCHIVE_APIS ++// #ifndef MINIZ_NO_ARCHIVE_APIS + +-#ifdef __cplusplus +-extern "C" { +-#endif ++// #ifdef __cplusplus ++// extern "C" { ++// #endif + +-enum +-{ ++// enum ++// { + /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ +- MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, +- MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, +- MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 +-}; +- +-typedef struct +-{ +- /* Central directory file index. */ +- mz_uint32 m_file_index; ++// MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, ++// MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, ++// MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 ++// }; ++ ++// typedef struct ++// { ++// /* Central directory file index. */ ++// mz_uint32 m_file_index; ++ ++// /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ ++// mz_uint64 m_central_dir_ofs; ++ ++// /* These fields are copied directly from the zip's central dir. */ ++// mz_uint16 m_version_made_by; ++// mz_uint16 m_version_needed; ++// mz_uint16 m_bit_flag; ++// mz_uint16 m_method; ++ ++// #ifndef MINIZ_NO_TIME ++// MZ_TIME_T m_time; ++// #endif + +- /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ +- mz_uint64 m_central_dir_ofs; ++// /* CRC-32 of uncompressed data. */ ++// mz_uint32 m_crc32; + +- /* These fields are copied directly from the zip's central dir. */ +- mz_uint16 m_version_made_by; +- mz_uint16 m_version_needed; +- mz_uint16 m_bit_flag; +- mz_uint16 m_method; ++// /* File's compressed size. */ ++// mz_uint64 m_comp_size; + +-#ifndef MINIZ_NO_TIME +- MZ_TIME_T m_time; +-#endif ++// /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ ++// mz_uint64 m_uncomp_size; + +- /* CRC-32 of uncompressed data. */ +- mz_uint32 m_crc32; ++// /* Zip internal and external file attributes. */ ++// mz_uint16 m_internal_attr; ++// mz_uint32 m_external_attr; + +- /* File's compressed size. */ +- mz_uint64 m_comp_size; ++// /* Entry's local header file offset in bytes. */ ++// mz_uint64 m_local_header_ofs; + +- /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ +- mz_uint64 m_uncomp_size; ++// /* Size of comment in bytes. */ ++// mz_uint32 m_comment_size; + +- /* Zip internal and external file attributes. */ +- mz_uint16 m_internal_attr; +- mz_uint32 m_external_attr; ++// /* MZ_TRUE if the entry appears to be a directory. */ ++// mz_bool m_is_directory; + +- /* Entry's local header file offset in bytes. */ +- mz_uint64 m_local_header_ofs; ++// /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ ++// mz_bool m_is_encrypted; + +- /* Size of comment in bytes. */ +- mz_uint32 m_comment_size; ++// /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ ++// mz_bool m_is_supported; + +- /* MZ_TRUE if the entry appears to be a directory. */ +- mz_bool m_is_directory; ++// /* Filename. If string ends in '/' it's a subdirectory entry. */ ++// /* Guaranteed to be zero terminated, may be truncated to fit. */ ++// char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + +- /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ +- mz_bool m_is_encrypted; ++// /* Comment field. */ ++// /* Guaranteed to be zero terminated, may be truncated to fit. */ ++// char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; + +- /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ +- mz_bool m_is_supported; ++// } mz_zip_archive_file_stat; + +- /* Filename. If string ends in '/' it's a subdirectory entry. */ +- /* Guaranteed to be zero terminated, may be truncated to fit. */ +- char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; ++// typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); ++// typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); ++// typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); + +- /* Comment field. */ +- /* Guaranteed to be zero terminated, may be truncated to fit. */ +- char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; ++// struct mz_zip_internal_state_tag; ++// typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + +-} mz_zip_archive_file_stat; ++// typedef enum { ++// MZ_ZIP_MODE_INVALID = 0, ++// MZ_ZIP_MODE_READING = 1, ++// MZ_ZIP_MODE_WRITING = 2, ++// MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 ++// } mz_zip_mode; + +-typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); +-typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); +-typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); ++// typedef enum { ++// MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, ++// MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, ++// MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, ++// MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, ++ // MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ ++ // MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ ++ // MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ ++// MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, ++// MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 ++// } mz_zip_flags; + +-struct mz_zip_internal_state_tag; +-typedef struct mz_zip_internal_state_tag mz_zip_internal_state; +- +-typedef enum { +- MZ_ZIP_MODE_INVALID = 0, +- MZ_ZIP_MODE_READING = 1, +- MZ_ZIP_MODE_WRITING = 2, +- MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 +-} mz_zip_mode; +- +-typedef enum { +- MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, +- MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, +- MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, +- MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, +- MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ +- MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ +- MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ +- MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, +- MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 +-} mz_zip_flags; +- +-typedef enum { +- MZ_ZIP_TYPE_INVALID = 0, +- MZ_ZIP_TYPE_USER, +- MZ_ZIP_TYPE_MEMORY, +- MZ_ZIP_TYPE_HEAP, +- MZ_ZIP_TYPE_FILE, +- MZ_ZIP_TYPE_CFILE, +- MZ_ZIP_TOTAL_TYPES +-} mz_zip_type; ++// typedef enum { ++// MZ_ZIP_TYPE_INVALID = 0, ++// MZ_ZIP_TYPE_USER, ++// MZ_ZIP_TYPE_MEMORY, ++// MZ_ZIP_TYPE_HEAP, ++// MZ_ZIP_TYPE_FILE, ++// MZ_ZIP_TYPE_CFILE, ++// MZ_ZIP_TOTAL_TYPES ++// } mz_zip_type; + + /* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ +-typedef enum { +- MZ_ZIP_NO_ERROR = 0, +- MZ_ZIP_UNDEFINED_ERROR, +- MZ_ZIP_TOO_MANY_FILES, +- MZ_ZIP_FILE_TOO_LARGE, +- MZ_ZIP_UNSUPPORTED_METHOD, +- MZ_ZIP_UNSUPPORTED_ENCRYPTION, +- MZ_ZIP_UNSUPPORTED_FEATURE, +- MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, +- MZ_ZIP_NOT_AN_ARCHIVE, +- MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, +- MZ_ZIP_UNSUPPORTED_MULTIDISK, +- MZ_ZIP_DECOMPRESSION_FAILED, +- MZ_ZIP_COMPRESSION_FAILED, +- MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, +- MZ_ZIP_CRC_CHECK_FAILED, +- MZ_ZIP_UNSUPPORTED_CDIR_SIZE, +- MZ_ZIP_ALLOC_FAILED, +- MZ_ZIP_FILE_OPEN_FAILED, +- MZ_ZIP_FILE_CREATE_FAILED, +- MZ_ZIP_FILE_WRITE_FAILED, +- MZ_ZIP_FILE_READ_FAILED, +- MZ_ZIP_FILE_CLOSE_FAILED, +- MZ_ZIP_FILE_SEEK_FAILED, +- MZ_ZIP_FILE_STAT_FAILED, +- MZ_ZIP_INVALID_PARAMETER, +- MZ_ZIP_INVALID_FILENAME, +- MZ_ZIP_BUF_TOO_SMALL, +- MZ_ZIP_INTERNAL_ERROR, +- MZ_ZIP_FILE_NOT_FOUND, +- MZ_ZIP_ARCHIVE_TOO_LARGE, +- MZ_ZIP_VALIDATION_FAILED, +- MZ_ZIP_WRITE_CALLBACK_FAILED, +- MZ_ZIP_TOTAL_ERRORS +-} mz_zip_error; +- +-typedef struct +-{ +- mz_uint64 m_archive_size; +- mz_uint64 m_central_directory_file_ofs; +- +- /* We only support up to UINT32_MAX files in zip64 mode. */ +- mz_uint32 m_total_files; +- mz_zip_mode m_zip_mode; +- mz_zip_type m_zip_type; +- mz_zip_error m_last_error; +- +- mz_uint64 m_file_offset_alignment; +- +- mz_alloc_func m_pAlloc; +- mz_free_func m_pFree; +- mz_realloc_func m_pRealloc; +- void *m_pAlloc_opaque; +- +- mz_file_read_func m_pRead; +- mz_file_write_func m_pWrite; +- mz_file_needs_keepalive m_pNeeds_keepalive; +- void *m_pIO_opaque; +- +- mz_zip_internal_state *m_pState; +- +-} mz_zip_archive; +- +-typedef struct +-{ +- mz_zip_archive *pZip; +- mz_uint flags; +- +- int status; +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- mz_uint file_crc32; +-#endif +- mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; +- mz_zip_archive_file_stat file_stat; +- void *pRead_buf; +- void *pWrite_buf; ++// typedef enum { ++// MZ_ZIP_NO_ERROR = 0, ++// MZ_ZIP_UNDEFINED_ERROR, ++// MZ_ZIP_TOO_MANY_FILES, ++// MZ_ZIP_FILE_TOO_LARGE, ++// MZ_ZIP_UNSUPPORTED_METHOD, ++// MZ_ZIP_UNSUPPORTED_ENCRYPTION, ++// MZ_ZIP_UNSUPPORTED_FEATURE, ++// MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, ++// MZ_ZIP_NOT_AN_ARCHIVE, ++// MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, ++// MZ_ZIP_UNSUPPORTED_MULTIDISK, ++// MZ_ZIP_DECOMPRESSION_FAILED, ++// MZ_ZIP_COMPRESSION_FAILED, ++// MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, ++// MZ_ZIP_CRC_CHECK_FAILED, ++// MZ_ZIP_UNSUPPORTED_CDIR_SIZE, ++// MZ_ZIP_ALLOC_FAILED, ++// MZ_ZIP_FILE_OPEN_FAILED, ++// MZ_ZIP_FILE_CREATE_FAILED, ++// MZ_ZIP_FILE_WRITE_FAILED, ++// MZ_ZIP_FILE_READ_FAILED, ++// MZ_ZIP_FILE_CLOSE_FAILED, ++// MZ_ZIP_FILE_SEEK_FAILED, ++// MZ_ZIP_FILE_STAT_FAILED, ++// MZ_ZIP_INVALID_PARAMETER, ++// MZ_ZIP_INVALID_FILENAME, ++// MZ_ZIP_BUF_TOO_SMALL, ++// MZ_ZIP_INTERNAL_ERROR, ++// MZ_ZIP_FILE_NOT_FOUND, ++// MZ_ZIP_ARCHIVE_TOO_LARGE, ++// MZ_ZIP_VALIDATION_FAILED, ++// MZ_ZIP_WRITE_CALLBACK_FAILED, ++// MZ_ZIP_TOTAL_ERRORS ++// } mz_zip_error; ++ ++// typedef struct ++// { ++// mz_uint64 m_archive_size; ++// mz_uint64 m_central_directory_file_ofs; ++ ++// /* We only support up to UINT32_MAX files in zip64 mode. */ ++// mz_uint32 m_total_files; ++// mz_zip_mode m_zip_mode; ++// mz_zip_type m_zip_type; ++// mz_zip_error m_last_error; ++ ++// mz_uint64 m_file_offset_alignment; ++ ++// mz_alloc_func m_pAlloc; ++// mz_free_func m_pFree; ++// mz_realloc_func m_pRealloc; ++// void *m_pAlloc_opaque; ++ ++// mz_file_read_func m_pRead; ++// mz_file_write_func m_pWrite; ++// mz_file_needs_keepalive m_pNeeds_keepalive; ++// void *m_pIO_opaque; ++ ++// mz_zip_internal_state *m_pState; ++ ++// } mz_zip_archive; ++ ++// typedef struct ++// { ++// mz_zip_archive *pZip; ++// mz_uint flags; ++ ++// int status; ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// mz_uint file_crc32; ++// #endif ++// mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; ++// mz_zip_archive_file_stat file_stat; ++// void *pRead_buf; ++// void *pWrite_buf; + +- size_t out_blk_remain; ++// size_t out_blk_remain; + +- tinfl_decompressor inflator; ++// tinfl_decompressor inflator; + +-} mz_zip_reader_extract_iter_state; ++// } mz_zip_reader_extract_iter_state; + + /* -------- ZIP reading */ + + /* Inits a ZIP archive reader. */ + /* These functions read and validate the archive's central directory. */ +-mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); ++// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); + +-mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); ++// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); + +-#ifndef MINIZ_NO_STDIO ++// #ifndef MINIZ_NO_STDIO + /* Read a archive from a disk file. */ + /* file_start_ofs is the file offset where the archive actually begins, or 0. */ + /* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */ +-mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); +-mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); ++// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); ++// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); + + /* Read an archive from an already opened FILE, beginning at the current file position. */ + /* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */ + /* The FILE will NOT be closed when mz_zip_reader_end() is called. */ +-mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); +-#endif ++// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); ++// #endif + + /* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */ +-mz_bool mz_zip_reader_end(mz_zip_archive *pZip); ++// mz_bool mz_zip_reader_end(mz_zip_archive *pZip); + + /* -------- ZIP reading or writing */ + + /* Clears a mz_zip_archive struct to all zeros. */ + /* Important: This must be done before passing the struct to any mz_zip functions. */ +-void mz_zip_zero_struct(mz_zip_archive *pZip); ++// void mz_zip_zero_struct(mz_zip_archive *pZip); + +-mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); +-mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); ++// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); ++// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); + + /* Returns the total number of files in the archive. */ +-mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); ++// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); + +-mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); +-mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); +-MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); ++// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); ++// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); ++// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); + + /* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ +-size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); ++// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); + + /* Attempts to locates a file in the archive's central directory. */ + /* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ + /* Returns -1 if the file cannot be found. */ +-int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); ++// int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + /* Returns MZ_FALSE if the file cannot be found. */ +-mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex); ++// mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex); + + /* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */ + /* Note that the m_last_error functionality is not thread safe. */ +-mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); +-mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); +-mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); +-mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); +-const char *mz_zip_get_error_string(mz_zip_error mz_err); ++// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); ++// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); ++// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); ++// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); ++// const char *mz_zip_get_error_string(mz_zip_error mz_err); + + /* MZ_TRUE if the archive file entry is a directory entry. */ +-mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); ++// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); + + /* MZ_TRUE if the file is encrypted/strong encrypted. */ +-mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); ++// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); + + /* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */ +-mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); ++// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); + + /* Retrieves the filename of an archive file entry. */ + /* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */ +-mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); ++// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); + + /* Attempts to locates a file in the archive's central directory. */ + /* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ + /* Returns -1 if the file cannot be found. */ +-int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); +-int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); ++// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); ++// int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); + + /* Returns detailed information about an archive file entry. */ +-mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); ++// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); + + /* MZ_TRUE if the file is in zip64 format. */ + /* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */ +-mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); ++// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); + + /* Returns the total central directory size in bytes. */ + /* The current max supported size is <= MZ_UINT32_MAX. */ +-size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); ++// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); + + /* Extracts a archive file to a memory buffer using no memory allocation. */ + /* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ +-mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); +-mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); ++// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); ++// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + + /* Extracts a archive file to a memory buffer. */ +-mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); +-mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); ++// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); ++// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); + + /* Extracts a archive file to a dynamically allocated heap buffer. */ + /* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ + /* Returns NULL and sets the last error on failure. */ +-void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); +-void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); ++// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); ++// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); + + /* Extracts a archive file using a callback function to output the file's data. */ +-mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); +-mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); ++// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); ++// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); + + /* Extract a file iteratively */ +-mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); +-mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); +-size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); +-mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); ++// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); ++// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); ++// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); ++// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); + +-#ifndef MINIZ_NO_STDIO ++// #ifndef MINIZ_NO_STDIO + /* Extracts a archive file to a disk file and sets its last accessed and modified times. */ + /* This function only extracts files, not archive directory records. */ +-mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); +-mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); ++// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); ++// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); + + /* Extracts a archive file starting at the current position in the destination FILE stream. */ +-mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); +-mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); +-#endif ++// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); ++// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); ++// #endif + + #if 0 + /* TODO */ +@@ -1233,26 +1233,26 @@ mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pA + // mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); + + /* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ +-mz_bool mz_zip_end(mz_zip_archive *pZip); ++// mz_bool mz_zip_end(mz_zip_archive *pZip); + + /* -------- ZIP writing */ + +-#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS ++// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + + /* Inits a ZIP archive writer. */ + /*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ + /*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ +-mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); +-mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); ++// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); ++// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); + +-mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); +-mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); ++// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); ++// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); + +-#ifndef MINIZ_NO_STDIO +-mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); +-mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); +-mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); +-#endif ++// #ifndef MINIZ_NO_STDIO ++// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); ++// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); ++// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); ++// #endif + + /* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */ + /* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ +@@ -1260,33 +1260,33 @@ mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint f + /* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */ + /* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */ + /* the archive is finalized the file's central directory will be hosed. */ +-mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); +-mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); ++// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); ++// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); + + /* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */ + /* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ + /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +-mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); ++// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); + + /* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */ + /* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ +-mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +- mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); ++// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, ++// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); + +-mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +- mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, +- const char *user_extra_data_central, mz_uint user_extra_data_central_len); ++// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, ++// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, ++// const char *user_extra_data_central, mz_uint user_extra_data_central_len); + +-#ifndef MINIZ_NO_STDIO ++// #ifndef MINIZ_NO_STDIO + /* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */ + /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +-mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); ++// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + + /* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ +-mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, +- const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, +- const char *user_extra_data_central, mz_uint user_extra_data_central_len); +-#endif ++// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, ++// const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, ++// const char *user_extra_data_central, mz_uint user_extra_data_central_len); ++// #endif + + /* Adds a file to an archive by fully cloning the data from another archive. */ + /* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */ +@@ -1295,15 +1295,15 @@ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, + /* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ + /* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ + /* An archive must be manually finalized by calling this function for it to be valid. */ +-mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); ++// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); + + /* Finalizes a heap archive, returning a poiner to the heap block and its size. */ + /* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ +-mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); ++// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); + + /* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ + /* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */ +-mz_bool mz_zip_writer_end(mz_zip_archive *pZip); ++// mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + + /* -------- Misc. high-level helper functions: */ + +@@ -1311,19 +1311,19 @@ mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + /* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */ + /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ + /* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */ +-mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +-mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); ++// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); ++// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); + + /* Reads a single file from an archive into a heap block. */ + /* If pComment is not NULL, only the file with the specified comment will be extracted. */ + /* Returns NULL on failure. */ +-void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); +-void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); ++// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); ++// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); + +-#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ ++// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + +-#ifdef __cplusplus +-} +-#endif ++// #ifdef __cplusplus ++// } ++// #endif + +-#endif /* MINIZ_NO_ARCHIVE_APIS */ ++// #endif /* MINIZ_NO_ARCHIVE_APIS */ + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + +diff --git a/src/zip/miniz/miniz.c b/src/zip/miniz/miniz.c +index 9ee7635..910d4b1 100644 +--- a/src/zip/miniz/miniz.c ++++ b/src/zip/miniz/miniz.c +@@ -65,92 +65,92 @@ mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) + } + + /* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */ +-#if 0 +- mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +- { +- static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, +- 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; +- mz_uint32 crcu32 = (mz_uint32)crc; +- if (!ptr) +- return MZ_CRC32_INIT; +- crcu32 = ~crcu32; +- while (buf_len--) +- { +- mz_uint8 b = *ptr++; +- crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; +- crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; +- } +- return ~crcu32; +- } +-#else ++// #if 0 ++// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) ++// { ++// static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, ++// 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; ++// mz_uint32 crcu32 = (mz_uint32)crc; ++// if (!ptr) ++// return MZ_CRC32_INIT; ++// crcu32 = ~crcu32; ++// while (buf_len--) ++// { ++// mz_uint8 b = *ptr++; ++// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; ++// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; ++// } ++// return ~crcu32; ++// } ++// #else + /* Faster, but larger CPU cache footprint. + */ +-mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +-{ +- static const mz_uint32 s_crc_table[256] = +- { +- 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, +- 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, +- 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, +- 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, +- 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, +- 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, +- 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, +- 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, +- 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, +- 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, +- 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, +- 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, +- 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, +- 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, +- 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, +- 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, +- 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, +- 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, +- 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, +- 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, +- 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, +- 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, +- 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, +- 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, +- 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, +- 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, +- 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, +- 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, +- 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, +- 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, +- 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, +- 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, +- 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, +- 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, +- 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, +- 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, +- 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +- }; +- +- mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; +- const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; +- +- while (buf_len >= 4) +- { +- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; +- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; +- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; +- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; +- pByte_buf += 4; +- buf_len -= 4; +- } ++// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) ++// { ++// static const mz_uint32 s_crc_table[256] = ++// { ++// 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, ++// 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, ++// 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, ++// 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, ++// 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, ++// 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, ++// 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, ++// 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, ++// 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, ++// 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, ++// 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, ++// 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, ++// 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, ++// 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, ++// 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, ++// 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, ++// 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, ++// 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, ++// 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, ++// 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, ++// 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, ++// 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, ++// 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, ++// 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, ++// 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, ++// 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, ++// 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, ++// 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, ++// 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, ++// 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, ++// 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, ++// 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, ++// 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, ++// 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, ++// 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, ++// 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, ++// 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D ++// }; ++ ++// mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; ++// const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; ++ ++// while (buf_len >= 4) ++// { ++// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; ++// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; ++// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; ++// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; ++// pByte_buf += 4; ++// buf_len -= 4; ++// } + +- while (buf_len) +- { +- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; +- ++pByte_buf; +- --buf_len; +- } ++// while (buf_len) ++// { ++// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; ++// ++pByte_buf; ++// --buf_len; ++// } + +- return ~crc32; +-} +-#endif ++// return ~crc32; ++// } ++// #endif + + void mz_free(void *p) + { +@@ -167,16 +167,16 @@ void miniz_def_free_func(void *opaque, void *address) + (void)opaque, (void)address; + MZ_FREE(address); + } +-void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) +-{ +- (void)opaque, (void)address, (void)items, (void)size; +- return MZ_REALLOC(address, items * size); +-} ++// void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) ++// { ++// (void)opaque, (void)address, (void)items, (void)size; ++// return MZ_REALLOC(address, items * size); ++// } + +-const char *mz_version(void) +-{ +- return MZ_VERSION; +-} ++// const char *mz_version(void) ++// { ++// return MZ_VERSION; ++// } + + #ifndef MINIZ_NO_ZLIB_APIS + +@@ -221,14 +221,14 @@ int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, + return MZ_OK; + } + +-int mz_deflateReset(mz_streamp pStream) +-{ +- if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) +- return MZ_STREAM_ERROR; +- pStream->total_in = pStream->total_out = 0; +- tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); +- return MZ_OK; +-} ++// int mz_deflateReset(mz_streamp pStream) ++// { ++// if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) ++// return MZ_STREAM_ERROR; ++// pStream->total_in = pStream->total_out = 0; ++// tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); ++// return MZ_OK; ++// } + + int mz_deflate(mz_streamp pStream, int flush) + { +@@ -300,12 +300,12 @@ int mz_deflateEnd(mz_streamp pStream) + return MZ_OK; + } + +-mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) +-{ +- (void)pStream; +- /* This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) */ +- return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); +-} ++// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) ++// { ++// (void)pStream; ++// This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) ++// return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); ++// } + + int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) + { +@@ -342,10 +342,10 @@ int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char * + return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); + } + +-mz_ulong mz_compressBound(mz_ulong source_len) +-{ +- return mz_deflateBound(NULL, source_len); +-} ++// mz_ulong mz_compressBound(mz_ulong source_len) ++// { ++// return mz_deflateBound(NULL, source_len); ++// } + + typedef struct + { +@@ -551,22 +551,22 @@ int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char + return mz_inflateEnd(&stream); + } + +-const char *mz_error(int err) +-{ +- static struct +- { +- int m_err; +- const char *m_pDesc; +- } s_error_descs[] = +- { +- { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } +- }; +- mz_uint i; +- for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) +- if (s_error_descs[i].m_err == err) +- return s_error_descs[i].m_pDesc; +- return NULL; +-} ++// const char *mz_error(int err) ++// { ++// static struct ++// { ++// int m_err; ++// const char *m_pDesc; ++// } s_error_descs[] = ++// { ++// { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } ++// }; ++// mz_uint i; ++// for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) ++// if (s_error_descs[i].m_err == err) ++// return s_error_descs[i].m_pDesc; ++// return NULL; ++// } + + #endif /*MINIZ_NO_ZLIB_APIS */ + +@@ -1049,7 +1049,7 @@ static void tdefl_start_static_block(tdefl_compressor *d) + TDEFL_PUT_BITS(1, 2); + } + +-static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; ++static const mz_uint16 mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + + #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS + static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +@@ -1358,7 +1358,6 @@ static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p) + #endif + static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) + { +- printf("\n--------------------------------------------------- DEBUG ---------------------------------------\n"); + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; +@@ -1456,176 +1455,176 @@ static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahe + } + #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ + +-#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +-static mz_bool tdefl_compress_fast(tdefl_compressor *d) +-{ +- /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ +- mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; +- mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; +- mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; ++// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN ++// static mz_bool tdefl_compress_fast(tdefl_compressor *d) ++// { ++// /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ ++// mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; ++// mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; ++// mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + +- while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) +- { +- const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; +- mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; +- mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); +- d->m_src_buf_left -= num_bytes_to_process; +- lookahead_size += num_bytes_to_process; ++// while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) ++// { ++// const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; ++// mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; ++// mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); ++// d->m_src_buf_left -= num_bytes_to_process; ++// lookahead_size += num_bytes_to_process; + +- while (num_bytes_to_process) +- { +- mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); +- memcpy(d->m_dict + dst_pos, d->m_pSrc, n); +- if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) +- memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); +- d->m_pSrc += n; +- dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; +- num_bytes_to_process -= n; +- } ++// while (num_bytes_to_process) ++// { ++// mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); ++// memcpy(d->m_dict + dst_pos, d->m_pSrc, n); ++// if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) ++// memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); ++// d->m_pSrc += n; ++// dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; ++// num_bytes_to_process -= n; ++// } + +- dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); +- if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) +- break; ++// dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); ++// if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) ++// break; + +- while (lookahead_size >= 4) +- { +- mz_uint cur_match_dist, cur_match_len = 1; +- mz_uint8 *pCur_dict = d->m_dict + cur_pos; +- mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; +- mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; +- mz_uint probe_pos = d->m_hash[hash]; +- d->m_hash[hash] = (mz_uint16)lookahead_pos; +- +- if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) +- { +- const mz_uint16 *p = (const mz_uint16 *)pCur_dict; +- const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); +- mz_uint32 probe_len = 32; +- do +- { +- } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && +- (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); +- cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); +- if (!probe_len) +- cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; ++// while (lookahead_size >= 4) ++// { ++// mz_uint cur_match_dist, cur_match_len = 1; ++// mz_uint8 *pCur_dict = d->m_dict + cur_pos; ++// mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; ++// mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; ++// mz_uint probe_pos = d->m_hash[hash]; ++// d->m_hash[hash] = (mz_uint16)lookahead_pos; ++ ++// if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) ++// { ++// const mz_uint16 *p = (const mz_uint16 *)pCur_dict; ++// const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); ++// mz_uint32 probe_len = 32; ++// do ++// { ++// } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && ++// (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); ++// cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); ++// if (!probe_len) ++// cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + +- if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) +- { +- cur_match_len = 1; +- *pLZ_code_buf++ = (mz_uint8)first_trigram; +- *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); +- d->m_huff_count[0][(mz_uint8)first_trigram]++; +- } +- else +- { +- mz_uint32 s0, s1; +- cur_match_len = MZ_MIN(cur_match_len, lookahead_size); ++// if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) ++// { ++// cur_match_len = 1; ++// *pLZ_code_buf++ = (mz_uint8)first_trigram; ++// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); ++// d->m_huff_count[0][(mz_uint8)first_trigram]++; ++// } ++// else ++// { ++// mz_uint32 s0, s1; ++// cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + +- MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); ++// MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + +- cur_match_dist--; ++// cur_match_dist--; + +- pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); +- *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; +- pLZ_code_buf += 3; +- *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); ++// pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); ++// *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; ++// pLZ_code_buf += 3; ++// *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + +- s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; +- s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; +- d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; ++// s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; ++// s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; ++// d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + +- d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; +- } +- } +- else +- { +- *pLZ_code_buf++ = (mz_uint8)first_trigram; +- *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); +- d->m_huff_count[0][(mz_uint8)first_trigram]++; +- } ++// d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; ++// } ++// } ++// else ++// { ++// *pLZ_code_buf++ = (mz_uint8)first_trigram; ++// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); ++// d->m_huff_count[0][(mz_uint8)first_trigram]++; ++// } + +- if (--num_flags_left == 0) +- { +- num_flags_left = 8; +- pLZ_flags = pLZ_code_buf++; +- } ++// if (--num_flags_left == 0) ++// { ++// num_flags_left = 8; ++// pLZ_flags = pLZ_code_buf++; ++// } + +- total_lz_bytes += cur_match_len; +- lookahead_pos += cur_match_len; +- dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); +- cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; +- MZ_ASSERT(lookahead_size >= cur_match_len); +- lookahead_size -= cur_match_len; ++// total_lz_bytes += cur_match_len; ++// lookahead_pos += cur_match_len; ++// dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); ++// cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; ++// MZ_ASSERT(lookahead_size >= cur_match_len); ++// lookahead_size -= cur_match_len; + +- if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) +- { +- int n; +- d->m_lookahead_pos = lookahead_pos; +- d->m_lookahead_size = lookahead_size; +- d->m_dict_size = dict_size; +- d->m_total_lz_bytes = total_lz_bytes; +- d->m_pLZ_code_buf = pLZ_code_buf; +- d->m_pLZ_flags = pLZ_flags; +- d->m_num_flags_left = num_flags_left; +- if ((n = tdefl_flush_block(d, 0)) != 0) +- return (n < 0) ? MZ_FALSE : MZ_TRUE; +- total_lz_bytes = d->m_total_lz_bytes; +- pLZ_code_buf = d->m_pLZ_code_buf; +- pLZ_flags = d->m_pLZ_flags; +- num_flags_left = d->m_num_flags_left; +- } +- } ++// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ++// { ++// int n; ++// d->m_lookahead_pos = lookahead_pos; ++// d->m_lookahead_size = lookahead_size; ++// d->m_dict_size = dict_size; ++// d->m_total_lz_bytes = total_lz_bytes; ++// d->m_pLZ_code_buf = pLZ_code_buf; ++// d->m_pLZ_flags = pLZ_flags; ++// d->m_num_flags_left = num_flags_left; ++// if ((n = tdefl_flush_block(d, 0)) != 0) ++// return (n < 0) ? MZ_FALSE : MZ_TRUE; ++// total_lz_bytes = d->m_total_lz_bytes; ++// pLZ_code_buf = d->m_pLZ_code_buf; ++// pLZ_flags = d->m_pLZ_flags; ++// num_flags_left = d->m_num_flags_left; ++// } ++// } + +- while (lookahead_size) +- { +- mz_uint8 lit = d->m_dict[cur_pos]; ++// while (lookahead_size) ++// { ++// mz_uint8 lit = d->m_dict[cur_pos]; + +- total_lz_bytes++; +- *pLZ_code_buf++ = lit; +- *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); +- if (--num_flags_left == 0) +- { +- num_flags_left = 8; +- pLZ_flags = pLZ_code_buf++; +- } ++// total_lz_bytes++; ++// *pLZ_code_buf++ = lit; ++// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); ++// if (--num_flags_left == 0) ++// { ++// num_flags_left = 8; ++// pLZ_flags = pLZ_code_buf++; ++// } + +- d->m_huff_count[0][lit]++; ++// d->m_huff_count[0][lit]++; + +- lookahead_pos++; +- dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); +- cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; +- lookahead_size--; ++// lookahead_pos++; ++// dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); ++// cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ++// lookahead_size--; + +- if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) +- { +- int n; +- d->m_lookahead_pos = lookahead_pos; +- d->m_lookahead_size = lookahead_size; +- d->m_dict_size = dict_size; +- d->m_total_lz_bytes = total_lz_bytes; +- d->m_pLZ_code_buf = pLZ_code_buf; +- d->m_pLZ_flags = pLZ_flags; +- d->m_num_flags_left = num_flags_left; +- if ((n = tdefl_flush_block(d, 0)) != 0) +- return (n < 0) ? MZ_FALSE : MZ_TRUE; +- total_lz_bytes = d->m_total_lz_bytes; +- pLZ_code_buf = d->m_pLZ_code_buf; +- pLZ_flags = d->m_pLZ_flags; +- num_flags_left = d->m_num_flags_left; +- } +- } +- } ++// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ++// { ++// int n; ++// d->m_lookahead_pos = lookahead_pos; ++// d->m_lookahead_size = lookahead_size; ++// d->m_dict_size = dict_size; ++// d->m_total_lz_bytes = total_lz_bytes; ++// d->m_pLZ_code_buf = pLZ_code_buf; ++// d->m_pLZ_flags = pLZ_flags; ++// d->m_num_flags_left = num_flags_left; ++// if ((n = tdefl_flush_block(d, 0)) != 0) ++// return (n < 0) ? MZ_FALSE : MZ_TRUE; ++// total_lz_bytes = d->m_total_lz_bytes; ++// pLZ_code_buf = d->m_pLZ_code_buf; ++// pLZ_flags = d->m_pLZ_flags; ++// num_flags_left = d->m_num_flags_left; ++// } ++// } ++// } + +- d->m_lookahead_pos = lookahead_pos; +- d->m_lookahead_size = lookahead_size; +- d->m_dict_size = dict_size; +- d->m_total_lz_bytes = total_lz_bytes; +- d->m_pLZ_code_buf = pLZ_code_buf; +- d->m_pLZ_flags = pLZ_flags; +- d->m_num_flags_left = num_flags_left; +- return MZ_TRUE; +-} +-#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ ++// d->m_lookahead_pos = lookahead_pos; ++// d->m_lookahead_size = lookahead_size; ++// d->m_dict_size = dict_size; ++// d->m_total_lz_bytes = total_lz_bytes; ++// d->m_pLZ_code_buf = pLZ_code_buf; ++// d->m_pLZ_flags = pLZ_flags; ++// d->m_num_flags_left = num_flags_left; ++// return MZ_TRUE; ++// } ++// #endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + + static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) + { +@@ -1870,16 +1869,16 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +-#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +- if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && +- ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && +- ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) +- { +- if (!tdefl_compress_fast(d)) +- return d->m_prev_return_status; +- } +- else +-#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ ++// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN ++// if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && ++// ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && ++// ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) ++// { ++// if (!tdefl_compress_fast(d)) ++// return d->m_prev_return_status; ++// } ++// else ++// #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + { + if (!tdefl_compress_normal(d)) + return d->m_prev_return_status; +@@ -1904,11 +1903,11 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + } + +-tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) +-{ +- MZ_ASSERT(d->m_pPut_buf_func); +- return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +-} ++// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) ++// { ++// MZ_ASSERT(d->m_pPut_buf_func); ++// return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); ++// } + + tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) + { +@@ -1944,92 +1943,92 @@ tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_fun + return TDEFL_STATUS_OKAY; + } + +-tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) +-{ +- return d->m_prev_return_status; +-} ++// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) ++// { ++// return d->m_prev_return_status; ++// } + + mz_uint32 tdefl_get_adler32(tdefl_compressor *d) + { + return d->m_adler32; + } + +-mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +-{ +- tdefl_compressor *pComp; +- mz_bool succeeded; +- if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) +- return MZ_FALSE; +- pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +- if (!pComp) +- return MZ_FALSE; +- succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); +- succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); +- MZ_FREE(pComp); +- return succeeded; +-} ++// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) ++// { ++// tdefl_compressor *pComp; ++// mz_bool succeeded; ++// if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) ++// return MZ_FALSE; ++// pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); ++// if (!pComp) ++// return MZ_FALSE; ++// succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); ++// succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); ++// MZ_FREE(pComp); ++// return succeeded; ++// } + +-typedef struct +-{ +- size_t m_size, m_capacity; +- mz_uint8 *m_pBuf; +- mz_bool m_expandable; +-} tdefl_output_buffer; ++// typedef struct ++// { ++// size_t m_size, m_capacity; ++// mz_uint8 *m_pBuf; ++// mz_bool m_expandable; ++// } tdefl_output_buffer; + +-static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) +-{ +- tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; +- size_t new_size = p->m_size + len; +- if (new_size > p->m_capacity) +- { +- size_t new_capacity = p->m_capacity; +- mz_uint8 *pNew_buf; +- if (!p->m_expandable) +- return MZ_FALSE; +- do +- { +- new_capacity = MZ_MAX(128U, new_capacity << 1U); +- } while (new_size > new_capacity); +- pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); +- if (!pNew_buf) +- return MZ_FALSE; +- p->m_pBuf = pNew_buf; +- p->m_capacity = new_capacity; +- } +- memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); +- p->m_size = new_size; +- return MZ_TRUE; +-} ++// static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) ++// { ++// tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; ++// size_t new_size = p->m_size + len; ++// if (new_size > p->m_capacity) ++// { ++// size_t new_capacity = p->m_capacity; ++// mz_uint8 *pNew_buf; ++// if (!p->m_expandable) ++// return MZ_FALSE; ++// do ++// { ++// new_capacity = MZ_MAX(128U, new_capacity << 1U); ++// } while (new_size > new_capacity); ++// pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); ++// if (!pNew_buf) ++// return MZ_FALSE; ++// p->m_pBuf = pNew_buf; ++// p->m_capacity = new_capacity; ++// } ++// memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); ++// p->m_size = new_size; ++// return MZ_TRUE; ++// } + +-void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +-{ +- tdefl_output_buffer out_buf; +- MZ_CLEAR_OBJ(out_buf); +- if (!pOut_len) +- return MZ_FALSE; +- else +- *pOut_len = 0; +- out_buf.m_expandable = MZ_TRUE; +- if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) +- return NULL; +- *pOut_len = out_buf.m_size; +- return out_buf.m_pBuf; +-} ++// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) ++// { ++// tdefl_output_buffer out_buf; ++// MZ_CLEAR_OBJ(out_buf); ++// if (!pOut_len) ++// return MZ_FALSE; ++// else ++// *pOut_len = 0; ++// out_buf.m_expandable = MZ_TRUE; ++// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) ++// return NULL; ++// *pOut_len = out_buf.m_size; ++// return out_buf.m_pBuf; ++// } + +-size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +-{ +- tdefl_output_buffer out_buf; +- MZ_CLEAR_OBJ(out_buf); +- if (!pOut_buf) +- return 0; +- out_buf.m_pBuf = (mz_uint8 *)pOut_buf; +- out_buf.m_capacity = out_buf_len; +- if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) +- return 0; +- return out_buf.m_size; +-} ++// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) ++// { ++// tdefl_output_buffer out_buf; ++// MZ_CLEAR_OBJ(out_buf); ++// if (!pOut_buf) ++// return 0; ++// out_buf.m_pBuf = (mz_uint8 *)pOut_buf; ++// out_buf.m_capacity = out_buf_len; ++// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) ++// return 0; ++// return out_buf.m_size; ++// } + +-static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; ++static const mz_uint16 s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + + /* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */ + mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) +@@ -2060,102 +2059,102 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int + /* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at + http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. + This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ +-void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) +-{ +- /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ +- static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; +- tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +- tdefl_output_buffer out_buf; +- int i, bpl = w * num_chans, y, z; +- mz_uint32 c; +- *pLen_out = 0; +- if (!pComp) +- return NULL; +- MZ_CLEAR_OBJ(out_buf); +- out_buf.m_expandable = MZ_TRUE; +- out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); +- if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) +- { +- MZ_FREE(pComp); +- return NULL; +- } +- /* write dummy header */ +- for (z = 41; z; --z) +- tdefl_output_buffer_putter(&z, 1, &out_buf); +- /* compress image data */ +- tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); +- for (y = 0; y < h; ++y) +- { +- tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); +- tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); +- } +- if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) +- { +- MZ_FREE(pComp); +- MZ_FREE(out_buf.m_pBuf); +- return NULL; +- } +- /* write real header */ +- *pLen_out = out_buf.m_size - 41; +- { +- static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; +- mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, +- 0x0a, 0x1a, 0x0a, 0x00, 0x00, +- 0x00, 0x0d, 0x49, 0x48, 0x44, +- 0x52, 0x00, 0x00, 0x00, 0x00, +- 0x00, 0x00, 0x00, 0x00, 0x08, +- 0x00, 0x00, 0x00, 0x00, 0x00, +- 0x00, 0x00, 0x00, 0x00, 0x00, +- 0x00, 0x00, 0x49, 0x44, 0x41, +- 0x54 }; +- pnghdr[18] = (mz_uint8)(w >> 8); +- pnghdr[19] = (mz_uint8)w; +- pnghdr[22] = (mz_uint8)(h >> 8); +- pnghdr[23] = (mz_uint8)h; +- pnghdr[25] = chans[num_chans]; +- pnghdr[33] = (mz_uint8)(*pLen_out >> 24); +- pnghdr[34] = (mz_uint8)(*pLen_out >> 16); +- pnghdr[35] = (mz_uint8)(*pLen_out >> 8); +- pnghdr[36] = (mz_uint8)*pLen_out; +- c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); +- for (i = 0; i < 4; ++i, c <<= 8) +- ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); +- memcpy(out_buf.m_pBuf, pnghdr, 41); +- } +- /* write footer (IDAT CRC-32, followed by IEND chunk) */ +- if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) +- { +- *pLen_out = 0; +- MZ_FREE(pComp); +- MZ_FREE(out_buf.m_pBuf); +- return NULL; +- } +- c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); +- for (i = 0; i < 4; ++i, c <<= 8) +- (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); +- /* compute final size of file, grab compressed data buffer and return */ +- *pLen_out += 57; +- MZ_FREE(pComp); +- return out_buf.m_pBuf; +-} +-void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) +-{ ++// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) ++// { ++// /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ ++// static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; ++// tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); ++// tdefl_output_buffer out_buf; ++// int i, bpl = w * num_chans, y, z; ++// mz_uint32 c; ++// *pLen_out = 0; ++// if (!pComp) ++// return NULL; ++// MZ_CLEAR_OBJ(out_buf); ++// out_buf.m_expandable = MZ_TRUE; ++// out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); ++// if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) ++// { ++// MZ_FREE(pComp); ++// return NULL; ++// } ++// /* write dummy header */ ++// for (z = 41; z; --z) ++// tdefl_output_buffer_putter(&z, 1, &out_buf); ++// /* compress image data */ ++// tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); ++// for (y = 0; y < h; ++y) ++// { ++// tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); ++// tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); ++// } ++// if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) ++// { ++// MZ_FREE(pComp); ++// MZ_FREE(out_buf.m_pBuf); ++// return NULL; ++// } ++// /* write real header */ ++// *pLen_out = out_buf.m_size - 41; ++// { ++// static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; ++// mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, ++// 0x0a, 0x1a, 0x0a, 0x00, 0x00, ++// 0x00, 0x0d, 0x49, 0x48, 0x44, ++// 0x52, 0x00, 0x00, 0x00, 0x00, ++// 0x00, 0x00, 0x00, 0x00, 0x08, ++// 0x00, 0x00, 0x00, 0x00, 0x00, ++// 0x00, 0x00, 0x00, 0x00, 0x00, ++// 0x00, 0x00, 0x49, 0x44, 0x41, ++// 0x54 }; ++// pnghdr[18] = (mz_uint8)(w >> 8); ++// pnghdr[19] = (mz_uint8)w; ++// pnghdr[22] = (mz_uint8)(h >> 8); ++// pnghdr[23] = (mz_uint8)h; ++// pnghdr[25] = chans[num_chans]; ++// pnghdr[33] = (mz_uint8)(*pLen_out >> 24); ++// pnghdr[34] = (mz_uint8)(*pLen_out >> 16); ++// pnghdr[35] = (mz_uint8)(*pLen_out >> 8); ++// pnghdr[36] = (mz_uint8)*pLen_out; ++// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); ++// for (i = 0; i < 4; ++i, c <<= 8) ++// ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); ++// memcpy(out_buf.m_pBuf, pnghdr, 41); ++// } ++// /* write footer (IDAT CRC-32, followed by IEND chunk) */ ++// if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) ++// { ++// *pLen_out = 0; ++// MZ_FREE(pComp); ++// MZ_FREE(out_buf.m_pBuf); ++// return NULL; ++// } ++// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); ++// for (i = 0; i < 4; ++i, c <<= 8) ++// (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); ++// /* compute final size of file, grab compressed data buffer and return */ ++// *pLen_out += 57; ++// MZ_FREE(pComp); ++// return out_buf.m_pBuf; ++// } ++// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) ++// { + /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */ +- return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); +-} ++// return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); ++// } + + /* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ + /* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ + /* structure size and allocation mechanism. */ +-tdefl_compressor *tdefl_compressor_alloc() +-{ +- return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +-} ++// tdefl_compressor *tdefl_compressor_alloc() ++// { ++// return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); ++// } + +-void tdefl_compressor_free(tdefl_compressor *pComp) +-{ +- MZ_FREE(pComp); +-} ++// void tdefl_compressor_free(tdefl_compressor *pComp) ++// { ++// MZ_FREE(pComp); ++// } + + #ifdef _MSC_VER + #pragma warning(pop) +@@ -2339,12 +2338,12 @@ extern "C" { + + tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) + { +- static const int s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; +- static const int s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; +- static const int s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; +- static const int s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; ++ static const mz_uint16 s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; ++ static const mz_uint8 s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; ++ static const mz_uint16 s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; ++ static const mz_uint8 s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; + static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; +- static const int s_min_table_sizes[3] = { 257, 1, 4 }; ++ static const mz_uint16 s_min_table_sizes[3] = { 257, 1, 4 }; + + tinfl_status status = TINFL_STATUS_FAILED; + mz_uint32 num_bits, dist, counter, num_extra; +@@ -2805,94 +2804,94 @@ common_exit: + } + + /* Higher level helper functions. */ +-void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +-{ +- tinfl_decompressor decomp; +- void *pBuf = NULL, *pNew_buf; +- size_t src_buf_ofs = 0, out_buf_capacity = 0; +- *pOut_len = 0; +- tinfl_init(&decomp); +- for (;;) +- { +- size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; +- tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, +- (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); +- if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) +- { +- MZ_FREE(pBuf); +- *pOut_len = 0; +- return NULL; +- } +- src_buf_ofs += src_buf_size; +- *pOut_len += dst_buf_size; +- if (status == TINFL_STATUS_DONE) +- break; +- new_out_buf_capacity = out_buf_capacity * 2; +- if (new_out_buf_capacity < 128) +- new_out_buf_capacity = 128; +- pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); +- if (!pNew_buf) +- { +- MZ_FREE(pBuf); +- *pOut_len = 0; +- return NULL; +- } +- pBuf = pNew_buf; +- out_buf_capacity = new_out_buf_capacity; +- } +- return pBuf; +-} ++// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) ++// { ++// tinfl_decompressor decomp; ++// void *pBuf = NULL, *pNew_buf; ++// size_t src_buf_ofs = 0, out_buf_capacity = 0; ++// *pOut_len = 0; ++// tinfl_init(&decomp); ++// for (;;) ++// { ++// size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; ++// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, ++// (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); ++// if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) ++// { ++// MZ_FREE(pBuf); ++// *pOut_len = 0; ++// return NULL; ++// } ++// src_buf_ofs += src_buf_size; ++// *pOut_len += dst_buf_size; ++// if (status == TINFL_STATUS_DONE) ++// break; ++// new_out_buf_capacity = out_buf_capacity * 2; ++// if (new_out_buf_capacity < 128) ++// new_out_buf_capacity = 128; ++// pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); ++// if (!pNew_buf) ++// { ++// MZ_FREE(pBuf); ++// *pOut_len = 0; ++// return NULL; ++// } ++// pBuf = pNew_buf; ++// out_buf_capacity = new_out_buf_capacity; ++// } ++// return pBuf; ++// } + +-size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +-{ +- tinfl_decompressor decomp; +- tinfl_status status; +- tinfl_init(&decomp); +- status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); +- return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; +-} ++// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) ++// { ++// tinfl_decompressor decomp; ++// tinfl_status status; ++// tinfl_init(&decomp); ++// status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); ++// return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; ++// } + +-int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +-{ +- int result = 0; +- tinfl_decompressor decomp; +- mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); +- size_t in_buf_ofs = 0, dict_ofs = 0; +- if (!pDict) +- return TINFL_STATUS_FAILED; +- tinfl_init(&decomp); +- for (;;) +- { +- size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; +- tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, +- (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); +- in_buf_ofs += in_buf_size; +- if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) +- break; +- if (status != TINFL_STATUS_HAS_MORE_OUTPUT) +- { +- result = (status == TINFL_STATUS_DONE); +- break; +- } +- dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); +- } +- MZ_FREE(pDict); +- *pIn_buf_size = in_buf_ofs; +- return result; +-} ++// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) ++// { ++// int result = 0; ++// tinfl_decompressor decomp; ++// mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); ++// size_t in_buf_ofs = 0, dict_ofs = 0; ++// if (!pDict) ++// return TINFL_STATUS_FAILED; ++// tinfl_init(&decomp); ++// for (;;) ++// { ++// size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; ++// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, ++// (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); ++// in_buf_ofs += in_buf_size; ++// if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) ++// break; ++// if (status != TINFL_STATUS_HAS_MORE_OUTPUT) ++// { ++// result = (status == TINFL_STATUS_DONE); ++// break; ++// } ++// dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); ++// } ++// MZ_FREE(pDict); ++// *pIn_buf_size = in_buf_ofs; ++// return result; ++// } + +-tinfl_decompressor *tinfl_decompressor_alloc() +-{ +- tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); +- if (pDecomp) +- tinfl_init(pDecomp); +- return pDecomp; +-} ++// tinfl_decompressor *tinfl_decompressor_alloc() ++// { ++// tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); ++// if (pDecomp) ++// tinfl_init(pDecomp); ++// return pDecomp; ++// } + +-void tinfl_decompressor_free(tinfl_decompressor *pDecomp) +-{ +- MZ_FREE(pDecomp); +-} ++// void tinfl_decompressor_free(tinfl_decompressor *pDecomp) ++// { ++// MZ_FREE(pDecomp); ++// } + + #ifdef __cplusplus + } +@@ -2925,461 +2924,461 @@ void tinfl_decompressor_free(tinfl_decompressor *pDecomp) + **************************************************************************/ + + +-#ifndef MINIZ_NO_ARCHIVE_APIS ++// #ifndef MINIZ_NO_ARCHIVE_APIS + +-#ifdef __cplusplus +-extern "C" { +-#endif ++// #ifdef __cplusplus ++// extern "C" { ++// #endif + + /* ------------------- .ZIP archive reading */ + +-#ifdef MINIZ_NO_STDIO +-#define MZ_FILE void * +-#else +-#include ++// #ifdef MINIZ_NO_STDIO ++// #define MZ_FILE void * ++// #else ++// #include + +-#if defined(_MSC_VER) || defined(__MINGW64__) +-static FILE *mz_fopen(const char *pFilename, const char *pMode) +-{ +- FILE *pFile = NULL; +- fopen_s(&pFile, pFilename, pMode); +- return pFile; +-} +-static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) +-{ +- FILE *pFile = NULL; +- if (freopen_s(&pFile, pPath, pMode, pStream)) +- return NULL; +- return pFile; +-} +-#ifndef MINIZ_NO_TIME +-#include +-#endif +-#define MZ_FOPEN mz_fopen +-#define MZ_FCLOSE fclose +-#define MZ_FREAD fread +-#define MZ_FWRITE fwrite +-#define MZ_FTELL64 _ftelli64 +-#define MZ_FSEEK64 _fseeki64 +-#define MZ_FILE_STAT_STRUCT _stat +-#define MZ_FILE_STAT _stat +-#define MZ_FFLUSH fflush +-#define MZ_FREOPEN mz_freopen +-#define MZ_DELETE_FILE remove +-#elif defined(__MINGW32__) +-#ifndef MINIZ_NO_TIME +-#include +-#endif +-#define MZ_FOPEN(f, m) fopen(f, m) +-#define MZ_FCLOSE fclose +-#define MZ_FREAD fread +-#define MZ_FWRITE fwrite +-#define MZ_FTELL64 ftello64 +-#define MZ_FSEEK64 fseeko64 +-#define MZ_FILE_STAT_STRUCT _stat +-#define MZ_FILE_STAT _stat +-#define MZ_FFLUSH fflush +-#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +-#define MZ_DELETE_FILE remove +-#elif defined(__TINYC__) +-#ifndef MINIZ_NO_TIME +-#include +-#endif +-#define MZ_FOPEN(f, m) fopen(f, m) +-#define MZ_FCLOSE fclose +-#define MZ_FREAD fread +-#define MZ_FWRITE fwrite +-#define MZ_FTELL64 ftell +-#define MZ_FSEEK64 fseek +-#define MZ_FILE_STAT_STRUCT stat +-#define MZ_FILE_STAT stat +-#define MZ_FFLUSH fflush +-#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +-#define MZ_DELETE_FILE remove +-#elif defined(__GNUC__) && _LARGEFILE64_SOURCE +-#ifndef MINIZ_NO_TIME +-#include +-#endif +-#define MZ_FOPEN(f, m) fopen64(f, m) +-#define MZ_FCLOSE fclose +-#define MZ_FREAD fread +-#define MZ_FWRITE fwrite +-#define MZ_FTELL64 ftello64 +-#define MZ_FSEEK64 fseeko64 +-#define MZ_FILE_STAT_STRUCT stat64 +-#define MZ_FILE_STAT stat64 +-#define MZ_FFLUSH fflush +-#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) +-#define MZ_DELETE_FILE remove +-#elif defined(__APPLE__) && _LARGEFILE64_SOURCE +-#ifndef MINIZ_NO_TIME +-#include +-#endif +-#define MZ_FOPEN(f, m) fopen(f, m) +-#define MZ_FCLOSE fclose +-#define MZ_FREAD fread +-#define MZ_FWRITE fwrite +-#define MZ_FTELL64 ftello +-#define MZ_FSEEK64 fseeko +-#define MZ_FILE_STAT_STRUCT stat +-#define MZ_FILE_STAT stat +-#define MZ_FFLUSH fflush +-#define MZ_FREOPEN(p, m, s) freopen(p, m, s) +-#define MZ_DELETE_FILE remove ++// #if defined(_MSC_VER) || defined(__MINGW64__) ++// static FILE *mz_fopen(const char *pFilename, const char *pMode) ++// { ++// FILE *pFile = NULL; ++// fopen_s(&pFile, pFilename, pMode); ++// return pFile; ++// } ++// static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) ++// { ++// FILE *pFile = NULL; ++// if (freopen_s(&pFile, pPath, pMode, pStream)) ++// return NULL; ++// return pFile; ++// } ++// #ifndef MINIZ_NO_TIME ++// #include ++// #endif ++// #define MZ_FOPEN mz_fopen ++// #define MZ_FCLOSE fclose ++// #define MZ_FREAD fread ++// #define MZ_FWRITE fwrite ++// #define MZ_FTELL64 _ftelli64 ++// #define MZ_FSEEK64 _fseeki64 ++// #define MZ_FILE_STAT_STRUCT _stat ++// #define MZ_FILE_STAT _stat ++// #define MZ_FFLUSH fflush ++// #define MZ_FREOPEN mz_freopen ++// #define MZ_DELETE_FILE remove ++// #elif defined(__MINGW32__) ++// #ifndef MINIZ_NO_TIME ++// #include ++// #endif ++// #define MZ_FOPEN(f, m) fopen(f, m) ++// #define MZ_FCLOSE fclose ++// #define MZ_FREAD fread ++// #define MZ_FWRITE fwrite ++// #define MZ_FTELL64 ftello64 ++// #define MZ_FSEEK64 fseeko64 ++// #define MZ_FILE_STAT_STRUCT _stat ++// #define MZ_FILE_STAT _stat ++// #define MZ_FFLUSH fflush ++// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) ++// #define MZ_DELETE_FILE remove ++// #elif defined(__TINYC__) ++// #ifndef MINIZ_NO_TIME ++// #include ++// #endif ++// #define MZ_FOPEN(f, m) fopen(f, m) ++// #define MZ_FCLOSE fclose ++// #define MZ_FREAD fread ++// #define MZ_FWRITE fwrite ++// #define MZ_FTELL64 ftell ++// #define MZ_FSEEK64 fseek ++// #define MZ_FILE_STAT_STRUCT stat ++// #define MZ_FILE_STAT stat ++// #define MZ_FFLUSH fflush ++// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) ++// #define MZ_DELETE_FILE remove ++// #elif defined(__GNUC__) && _LARGEFILE64_SOURCE ++// #ifndef MINIZ_NO_TIME ++// #include ++// #endif ++// #define MZ_FOPEN(f, m) fopen64(f, m) ++// #define MZ_FCLOSE fclose ++// #define MZ_FREAD fread ++// #define MZ_FWRITE fwrite ++// #define MZ_FTELL64 ftello64 ++// #define MZ_FSEEK64 fseeko64 ++// #define MZ_FILE_STAT_STRUCT stat64 ++// #define MZ_FILE_STAT stat64 ++// #define MZ_FFLUSH fflush ++// #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) ++// #define MZ_DELETE_FILE remove ++// #elif defined(__APPLE__) && _LARGEFILE64_SOURCE ++// #ifndef MINIZ_NO_TIME ++// #include ++// #endif ++// #define MZ_FOPEN(f, m) fopen(f, m) ++// #define MZ_FCLOSE fclose ++// #define MZ_FREAD fread ++// #define MZ_FWRITE fwrite ++// #define MZ_FTELL64 ftello ++// #define MZ_FSEEK64 fseeko ++// #define MZ_FILE_STAT_STRUCT stat ++// #define MZ_FILE_STAT stat ++// #define MZ_FFLUSH fflush ++// #define MZ_FREOPEN(p, m, s) freopen(p, m, s) ++// #define MZ_DELETE_FILE remove ++ ++// #else ++// // #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") ++// #ifndef MINIZ_NO_TIME ++// #include ++// #endif ++// #define MZ_FOPEN(f, m) fopen(f, m) ++// #define MZ_FCLOSE fclose ++// #define MZ_FREAD fread ++// #define MZ_FWRITE fwrite ++// #ifdef __STRICT_ANSI__ ++// #define MZ_FTELL64 ftell ++// #define MZ_FSEEK64 fseek ++// #else ++// #define MZ_FTELL64 ftello ++// #define MZ_FSEEK64 fseeko ++// #endif ++// #define MZ_FILE_STAT_STRUCT stat ++// #define MZ_FILE_STAT stat ++// #define MZ_FFLUSH fflush ++// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) ++// #define MZ_DELETE_FILE remove ++// #endif /* #ifdef _MSC_VER */ ++// #endif /* #ifdef MINIZ_NO_STDIO */ ++ ++// #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) + +-#else +-// #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") +-#ifndef MINIZ_NO_TIME +-#include +-#endif +-#define MZ_FOPEN(f, m) fopen(f, m) +-#define MZ_FCLOSE fclose +-#define MZ_FREAD fread +-#define MZ_FWRITE fwrite +-#ifdef __STRICT_ANSI__ +-#define MZ_FTELL64 ftell +-#define MZ_FSEEK64 fseek +-#else +-#define MZ_FTELL64 ftello +-#define MZ_FSEEK64 fseeko +-#endif +-#define MZ_FILE_STAT_STRUCT stat +-#define MZ_FILE_STAT stat +-#define MZ_FFLUSH fflush +-#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +-#define MZ_DELETE_FILE remove +-#endif /* #ifdef _MSC_VER */ +-#endif /* #ifdef MINIZ_NO_STDIO */ ++/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ ++// enum ++// { ++// /* ZIP archive identifiers and record sizes */ ++// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, ++// MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, ++// MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, ++// MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, ++// MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, ++// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, ++ ++// /* ZIP64 archive identifier and record sizes */ ++// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, ++// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, ++// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, ++// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, ++// MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, ++// MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, ++// MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, ++// MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, ++ ++// /* Central directory header record offsets */ ++// MZ_ZIP_CDH_SIG_OFS = 0, ++// MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, ++// MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, ++// MZ_ZIP_CDH_BIT_FLAG_OFS = 8, ++// MZ_ZIP_CDH_METHOD_OFS = 10, ++// MZ_ZIP_CDH_FILE_TIME_OFS = 12, ++// MZ_ZIP_CDH_FILE_DATE_OFS = 14, ++// MZ_ZIP_CDH_CRC32_OFS = 16, ++// MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, ++// MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, ++// MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, ++// MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, ++// MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, ++// MZ_ZIP_CDH_DISK_START_OFS = 34, ++// MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, ++// MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, ++// MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, ++ ++// /* Local directory header offsets */ ++// MZ_ZIP_LDH_SIG_OFS = 0, ++// MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, ++// MZ_ZIP_LDH_BIT_FLAG_OFS = 6, ++// MZ_ZIP_LDH_METHOD_OFS = 8, ++// MZ_ZIP_LDH_FILE_TIME_OFS = 10, ++// MZ_ZIP_LDH_FILE_DATE_OFS = 12, ++// MZ_ZIP_LDH_CRC32_OFS = 14, ++// MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, ++// MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, ++// MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, ++// MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, ++// MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, ++ ++// /* End of central directory offsets */ ++// MZ_ZIP_ECDH_SIG_OFS = 0, ++// MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, ++// MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, ++// MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, ++// MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, ++// MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, ++// MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, ++// MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, ++ ++// /* ZIP64 End of central directory locator offsets */ ++// MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ ++// MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ ++// MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ ++// MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ ++ ++// /* ZIP64 End of central directory header offsets */ ++// MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ ++// MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ ++// MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ ++// MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ ++// MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ ++// MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ ++// MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ ++// MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ ++// MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ ++// MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ ++// MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, ++// MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, ++// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, ++// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, ++// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, ++// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, ++// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 ++// }; ++ ++// typedef struct ++// { ++// void *m_p; ++// size_t m_size, m_capacity; ++// mz_uint m_element_size; ++// } mz_zip_array; + +-#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) ++// struct mz_zip_internal_state_tag ++// { ++// mz_zip_array m_central_dir; ++// mz_zip_array m_central_dir_offsets; ++// mz_zip_array m_sorted_central_dir_offsets; + +-/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ +-enum +-{ +- /* ZIP archive identifiers and record sizes */ +- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, +- MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, +- MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, +- MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, +- MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, +- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, +- +- /* ZIP64 archive identifier and record sizes */ +- MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, +- MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, +- MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, +- MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, +- MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, +- MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, +- MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, +- MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, +- +- /* Central directory header record offsets */ +- MZ_ZIP_CDH_SIG_OFS = 0, +- MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, +- MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, +- MZ_ZIP_CDH_BIT_FLAG_OFS = 8, +- MZ_ZIP_CDH_METHOD_OFS = 10, +- MZ_ZIP_CDH_FILE_TIME_OFS = 12, +- MZ_ZIP_CDH_FILE_DATE_OFS = 14, +- MZ_ZIP_CDH_CRC32_OFS = 16, +- MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, +- MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, +- MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, +- MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, +- MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, +- MZ_ZIP_CDH_DISK_START_OFS = 34, +- MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, +- MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, +- MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, +- +- /* Local directory header offsets */ +- MZ_ZIP_LDH_SIG_OFS = 0, +- MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, +- MZ_ZIP_LDH_BIT_FLAG_OFS = 6, +- MZ_ZIP_LDH_METHOD_OFS = 8, +- MZ_ZIP_LDH_FILE_TIME_OFS = 10, +- MZ_ZIP_LDH_FILE_DATE_OFS = 12, +- MZ_ZIP_LDH_CRC32_OFS = 14, +- MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, +- MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, +- MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, +- MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, +- MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, +- +- /* End of central directory offsets */ +- MZ_ZIP_ECDH_SIG_OFS = 0, +- MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, +- MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, +- MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, +- MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, +- MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, +- MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, +- MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, +- +- /* ZIP64 End of central directory locator offsets */ +- MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ +- MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ +- MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ +- MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ +- +- /* ZIP64 End of central directory header offsets */ +- MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ +- MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ +- MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ +- MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ +- MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ +- MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ +- MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ +- MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ +- MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ +- MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ +- MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, +- MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, +- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, +- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, +- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, +- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, +- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 +-}; ++// /* The flags passed in when the archive is initially opened. */ ++// uint32_t m_init_flags; + +-typedef struct +-{ +- void *m_p; +- size_t m_size, m_capacity; +- mz_uint m_element_size; +-} mz_zip_array; ++// /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ ++// mz_bool m_zip64; + +-struct mz_zip_internal_state_tag +-{ +- mz_zip_array m_central_dir; +- mz_zip_array m_central_dir_offsets; +- mz_zip_array m_sorted_central_dir_offsets; ++// /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ ++// mz_bool m_zip64_has_extended_info_fields; + +- /* The flags passed in when the archive is initially opened. */ +- uint32_t m_init_flags; ++// /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ ++// MZ_FILE *m_pFile; ++// mz_uint64 m_file_archive_start_ofs; + +- /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ +- mz_bool m_zip64; ++// void *m_pMem; ++// size_t m_mem_size; ++// size_t m_mem_capacity; ++// }; + +- /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ +- mz_bool m_zip64_has_extended_info_fields; ++// #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size + +- /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ +- MZ_FILE *m_pFile; +- mz_uint64 m_file_archive_start_ofs; ++// #if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) ++// static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) ++// { ++// MZ_ASSERT(index < pArray->m_size); ++// return index; ++// } ++// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] ++// #else ++// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] ++// #endif + +- void *m_pMem; +- size_t m_mem_size; +- size_t m_mem_capacity; +-}; ++// static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) ++// { ++// memset(pArray, 0, sizeof(mz_zip_array)); ++// pArray->m_element_size = element_size; ++// } + +-#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size ++// static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); ++// memset(pArray, 0, sizeof(mz_zip_array)); ++// } + +-#if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) +-static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) +-{ +- MZ_ASSERT(index < pArray->m_size); +- return index; +-} +-#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] +-#else +-#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] +-#endif ++// static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) ++// { ++// void *pNew_p; ++// size_t new_capacity = min_new_capacity; ++// MZ_ASSERT(pArray->m_element_size); ++// if (pArray->m_capacity >= min_new_capacity) ++// return MZ_TRUE; ++// if (growing) ++// { ++// new_capacity = MZ_MAX(1, pArray->m_capacity); ++// while (new_capacity < min_new_capacity) ++// new_capacity *= 2; ++// } ++// if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) ++// return MZ_FALSE; ++// pArray->m_p = pNew_p; ++// pArray->m_capacity = new_capacity; ++// return MZ_TRUE; ++// } + +-static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) +-{ +- memset(pArray, 0, sizeof(mz_zip_array)); +- pArray->m_element_size = element_size; +-} ++// static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) ++// { ++// if (new_capacity > pArray->m_capacity) ++// { ++// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) ++// return MZ_FALSE; ++// } ++// return MZ_TRUE; ++// } + +-static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) +-{ +- pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); +- memset(pArray, 0, sizeof(mz_zip_array)); +-} ++// static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) ++// { ++// if (new_size > pArray->m_capacity) ++// { ++// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) ++// return MZ_FALSE; ++// } ++// pArray->m_size = new_size; ++// return MZ_TRUE; ++// } + +-static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) +-{ +- void *pNew_p; +- size_t new_capacity = min_new_capacity; +- MZ_ASSERT(pArray->m_element_size); +- if (pArray->m_capacity >= min_new_capacity) +- return MZ_TRUE; +- if (growing) +- { +- new_capacity = MZ_MAX(1, pArray->m_capacity); +- while (new_capacity < min_new_capacity) +- new_capacity *= 2; +- } +- if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) +- return MZ_FALSE; +- pArray->m_p = pNew_p; +- pArray->m_capacity = new_capacity; +- return MZ_TRUE; +-} ++// static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) ++// { ++// return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); ++// } + +-static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) +-{ +- if (new_capacity > pArray->m_capacity) +- { +- if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) +- return MZ_FALSE; +- } +- return MZ_TRUE; +-} ++// static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) ++// { ++// size_t orig_size = pArray->m_size; ++// if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) ++// return MZ_FALSE; ++// memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); ++// return MZ_TRUE; ++// } + +-static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) +-{ +- if (new_size > pArray->m_capacity) +- { +- if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) +- return MZ_FALSE; +- } +- pArray->m_size = new_size; +- return MZ_TRUE; +-} ++// #ifndef MINIZ_NO_TIME ++// static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) ++// { ++// struct tm tm; ++// memset(&tm, 0, sizeof(tm)); ++// tm.tm_isdst = -1; ++// tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; ++// tm.tm_mon = ((dos_date >> 5) & 15) - 1; ++// tm.tm_mday = dos_date & 31; ++// tm.tm_hour = (dos_time >> 11) & 31; ++// tm.tm_min = (dos_time >> 5) & 63; ++// tm.tm_sec = (dos_time << 1) & 62; ++// return mktime(&tm); ++// } + +-static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) +-{ +- return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); +-} ++// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS ++// static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) ++// { ++// #ifdef _MSC_VER ++// struct tm tm_struct; ++// struct tm *tm = &tm_struct; ++// errno_t err = localtime_s(tm, &time_); ++// if (err) ++// { ++// *pDOS_date = 0; ++// *pDOS_time = 0; ++// return; ++// } ++// #else ++// struct tm *tm = localtime(&time_); ++// #endif /* #ifdef _MSC_VER */ + +-static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) +-{ +- size_t orig_size = pArray->m_size; +- if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) +- return MZ_FALSE; +- memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); +- return MZ_TRUE; +-} ++// *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); ++// *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); ++// } ++// #endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ + +-#ifndef MINIZ_NO_TIME +-static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) +-{ +- struct tm tm; +- memset(&tm, 0, sizeof(tm)); +- tm.tm_isdst = -1; +- tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; +- tm.tm_mon = ((dos_date >> 5) & 15) - 1; +- tm.tm_mday = dos_date & 31; +- tm.tm_hour = (dos_time >> 11) & 31; +- tm.tm_min = (dos_time >> 5) & 63; +- tm.tm_sec = (dos_time << 1) & 62; +- return mktime(&tm); +-} ++// #ifndef MINIZ_NO_STDIO ++// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS ++// static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) ++// { ++// struct MZ_FILE_STAT_STRUCT file_stat; + +-#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +-static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +-{ +-#ifdef _MSC_VER +- struct tm tm_struct; +- struct tm *tm = &tm_struct; +- errno_t err = localtime_s(tm, &time_); +- if (err) +- { +- *pDOS_date = 0; +- *pDOS_time = 0; +- return; +- } +-#else +- struct tm *tm = localtime(&time_); +-#endif /* #ifdef _MSC_VER */ ++// /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ ++// if (MZ_FILE_STAT(pFilename, &file_stat) != 0) ++// return MZ_FALSE; + +- *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); +- *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); +-} +-#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ ++// *pTime = file_stat.st_mtime; + +-#ifndef MINIZ_NO_STDIO +-#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +-static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) +-{ +- struct MZ_FILE_STAT_STRUCT file_stat; ++// return MZ_TRUE; ++// } ++// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ + +- /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ +- if (MZ_FILE_STAT(pFilename, &file_stat) != 0) +- return MZ_FALSE; ++// static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) ++// { ++// struct utimbuf t; + +- *pTime = file_stat.st_mtime; ++// memset(&t, 0, sizeof(t)); ++// t.actime = access_time; ++// t.modtime = modified_time; + +- return MZ_TRUE; +-} +-#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ ++// return !utime(pFilename, &t); ++// } ++// #endif /* #ifndef MINIZ_NO_STDIO */ ++// #endif /* #ifndef MINIZ_NO_TIME */ + +-static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) +-{ +- struct utimbuf t; ++// static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) ++// { ++// if (pZip) ++// pZip->m_last_error = err_num; ++// return MZ_FALSE; ++// } + +- memset(&t, 0, sizeof(t)); +- t.actime = access_time; +- t.modtime = modified_time; ++// static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) ++// { ++// (void)flags; ++// if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- return !utime(pFilename, &t); +-} +-#endif /* #ifndef MINIZ_NO_STDIO */ +-#endif /* #ifndef MINIZ_NO_TIME */ ++// if (!pZip->m_pAlloc) ++// pZip->m_pAlloc = miniz_def_alloc_func; ++// if (!pZip->m_pFree) ++// pZip->m_pFree = miniz_def_free_func; ++// if (!pZip->m_pRealloc) ++// pZip->m_pRealloc = miniz_def_realloc_func; + +-static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) +-{ +- if (pZip) +- pZip->m_last_error = err_num; +- return MZ_FALSE; +-} ++// pZip->m_archive_size = 0; ++// pZip->m_central_directory_file_ofs = 0; ++// pZip->m_total_files = 0; ++// pZip->m_last_error = MZ_ZIP_NO_ERROR; + +-static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) +-{ +- (void)flags; +- if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- +- if (!pZip->m_pAlloc) +- pZip->m_pAlloc = miniz_def_alloc_func; +- if (!pZip->m_pFree) +- pZip->m_pFree = miniz_def_free_func; +- if (!pZip->m_pRealloc) +- pZip->m_pRealloc = miniz_def_realloc_func; +- +- pZip->m_archive_size = 0; +- pZip->m_central_directory_file_ofs = 0; +- pZip->m_total_files = 0; +- pZip->m_last_error = MZ_ZIP_NO_ERROR; +- +- if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- +- memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); +- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); +- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); +- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); +- pZip->m_pState->m_init_flags = flags; +- pZip->m_pState->m_zip64 = MZ_FALSE; +- pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; +- +- pZip->m_zip_mode = MZ_ZIP_MODE_READING; ++// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +- return MZ_TRUE; +-} ++// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); ++// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); ++// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); ++// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); ++// pZip->m_pState->m_init_flags = flags; ++// pZip->m_pState->m_zip64 = MZ_FALSE; ++// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; + +-static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) +-{ +- const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; +- const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); +- mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); +- mz_uint8 l = 0, r = 0; +- pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +- pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +- pE = pL + MZ_MIN(l_len, r_len); +- while (pL < pE) +- { +- if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) +- break; +- pL++; +- pR++; +- } +- return (pL == pE) ? (l_len < r_len) : (l < r); +-} ++// pZip->m_zip_mode = MZ_ZIP_MODE_READING; ++ ++// return MZ_TRUE; ++// } + ++// static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) ++// { ++// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; ++// const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); ++// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// mz_uint8 l = 0, r = 0; ++// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; ++// pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; ++// pE = pL + MZ_MIN(l_len, r_len); ++// while (pL < pE) ++// { ++// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) ++// break; ++// pL++; ++// pR++; ++// } ++// return (pL == pE) ? (l_len < r_len) : (l < r); ++// } ++/* + #define MZ_SWAP_UINT32(a, b) \ + do \ + { \ +@@ -3388,1708 +3387,1708 @@ static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pC + b = t; \ + } \ + MZ_MACRO_END +- ++*/ + /* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */ +-static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) +-{ +- mz_zip_internal_state *pState = pZip->m_pState; +- const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; +- const mz_zip_array *pCentral_dir = &pState->m_central_dir; +- mz_uint32 *pIndices; +- mz_uint32 start, end; +- const mz_uint32 size = pZip->m_total_files; +- +- if (size <= 1U) +- return; ++// static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) ++// { ++// mz_zip_internal_state *pState = pZip->m_pState; ++// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; ++// const mz_zip_array *pCentral_dir = &pState->m_central_dir; ++// mz_uint32 *pIndices; ++// mz_uint32 start, end; ++// const mz_uint32 size = pZip->m_total_files; + +- pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); ++// if (size <= 1U) ++// return; + +- start = (size - 2U) >> 1U; +- for (;;) +- { +- mz_uint64 child, root = start; +- for (;;) +- { +- if ((child = (root << 1U) + 1U) >= size) +- break; +- child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); +- if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) +- break; +- MZ_SWAP_UINT32(pIndices[root], pIndices[child]); +- root = child; +- } +- if (!start) +- break; +- start--; +- } ++// pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + +- end = size - 1; +- while (end > 0) +- { +- mz_uint64 child, root = 0; +- MZ_SWAP_UINT32(pIndices[end], pIndices[0]); +- for (;;) +- { +- if ((child = (root << 1U) + 1U) >= end) +- break; +- child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); +- if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) +- break; +- MZ_SWAP_UINT32(pIndices[root], pIndices[child]); +- root = child; +- } +- end--; +- } +-} ++// start = (size - 2U) >> 1U; ++// for (;;) ++// { ++// mz_uint64 child, root = start; ++// for (;;) ++// { ++// if ((child = (root << 1U) + 1U) >= size) ++// break; ++// child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); ++// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) ++// break; ++// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); ++// root = child; ++// } ++// if (!start) ++// break; ++// start--; ++// } + +-static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) +-{ +- mz_int64 cur_file_ofs; +- mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; +- mz_uint8 *pBuf = (mz_uint8 *)buf_u32; ++// end = size - 1; ++// while (end > 0) ++// { ++// mz_uint64 child, root = 0; ++// MZ_SWAP_UINT32(pIndices[end], pIndices[0]); ++// for (;;) ++// { ++// if ((child = (root << 1U) + 1U) >= end) ++// break; ++// child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); ++// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) ++// break; ++// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); ++// root = child; ++// } ++// end--; ++// } ++// } + +- /* Basic sanity checks - reject files which are too small */ +- if (pZip->m_archive_size < record_size) +- return MZ_FALSE; ++// static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) ++// { ++// mz_int64 cur_file_ofs; ++// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; ++// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + +- /* Find the record by scanning the file from the end towards the beginning. */ +- cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); +- for (;;) +- { +- int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); ++// /* Basic sanity checks - reject files which are too small */ ++// if (pZip->m_archive_size < record_size) ++// return MZ_FALSE; + +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) +- return MZ_FALSE; ++// /* Find the record by scanning the file from the end towards the beginning. */ ++// cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); ++// for (;;) ++// { ++// int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + +- for (i = n - 4; i >= 0; --i) +- { +- mz_uint s = MZ_READ_LE32(pBuf + i); +- if (s == record_sig) +- { +- if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) +- break; +- } +- } ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) ++// return MZ_FALSE; + +- if (i >= 0) +- { +- cur_file_ofs += i; +- break; +- } ++// for (i = n - 4; i >= 0; --i) ++// { ++// mz_uint s = MZ_READ_LE32(pBuf + i); ++// if (s == record_sig) ++// { ++// if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) ++// break; ++// } ++// } + +- /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ +- if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) +- return MZ_FALSE; ++// if (i >= 0) ++// { ++// cur_file_ofs += i; ++// break; ++// } + +- cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); +- } ++// /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ ++// if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) ++// return MZ_FALSE; + +- *pOfs = cur_file_ofs; +- return MZ_TRUE; +-} ++// cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); ++// } + +-static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) +-{ +- mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; +- mz_uint64 cdir_ofs = 0; +- mz_int64 cur_file_ofs = 0; +- const mz_uint8 *p; ++// *pOfs = cur_file_ofs; ++// return MZ_TRUE; ++// } + +- mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; +- mz_uint8 *pBuf = (mz_uint8 *)buf_u32; +- mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); +- mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +- mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; ++// static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) ++// { ++// mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; ++// mz_uint64 cdir_ofs = 0; ++// mz_int64 cur_file_ofs = 0; ++// const mz_uint8 *p; + +- mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +- mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; ++// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; ++// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; ++// mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); ++// mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; ++// mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; + +- mz_uint64 zip64_end_of_central_dir_ofs = 0; ++// mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; ++// mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; + +- /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ +- if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); ++// mz_uint64 zip64_end_of_central_dir_ofs = 0; + +- if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) +- return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); ++// /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ ++// if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +- /* Read and verify the end of central directory record. */ +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); + +- if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) +- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); ++// /* Read and verify the end of central directory record. */ ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +- if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) +- { +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) +- { +- if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) +- { +- zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); +- if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) +- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); ++// if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ++// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +- if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) +- { +- if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) +- { +- pZip->m_pState->m_zip64 = MZ_TRUE; +- } +- } +- } +- } +- } ++// if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) ++// { ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) ++// { ++// if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) ++// { ++// zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); ++// if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) ++// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +- pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); +- cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); +- num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); +- cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); +- cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); +- cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); ++// if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// { ++// if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) ++// { ++// pZip->m_pState->m_zip64 = MZ_TRUE; ++// } ++// } ++// } ++// } ++// } + +- if (pZip->m_pState->m_zip64) +- { +- mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); +- mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); +- mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); +- mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); +- mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); ++// pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); ++// cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); ++// num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); ++// cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); ++// cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); ++// cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + +- if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// if (pZip->m_pState->m_zip64) ++// { ++// mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); ++// mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); ++// mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); ++// mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); ++// mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); + +- if (zip64_total_num_of_disks != 1U) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); ++// if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- /* Check for miniz's practical limits */ +- if (zip64_cdir_total_entries > MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// if (zip64_total_num_of_disks != 1U) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +- pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; ++// /* Check for miniz's practical limits */ ++// if (zip64_cdir_total_entries > MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + +- if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; + +- cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; ++// if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + +- /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ +- if (zip64_size_of_central_directory > MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); ++// cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; + +- cdir_size = (mz_uint32)zip64_size_of_central_directory; ++// /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ ++// if (zip64_size_of_central_directory > MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +- num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); ++// cdir_size = (mz_uint32)zip64_size_of_central_directory; + +- cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); ++// num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); + +- cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); +- } ++// cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); + +- if (pZip->m_total_files != cdir_entries_on_this_disk) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); ++// cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); ++// } + +- if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); ++// if (pZip->m_total_files != cdir_entries_on_this_disk) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +- if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +- if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- pZip->m_central_directory_file_ofs = cdir_ofs; ++// if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (pZip->m_total_files) +- { +- mz_uint i, n; +- /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ +- if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || +- (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// pZip->m_central_directory_file_ofs = cdir_ofs; + +- if (sort_central_dir) +- { +- if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- } ++// if (pZip->m_total_files) ++// { ++// mz_uint i, n; ++// /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ ++// if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || ++// (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +- if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// if (sort_central_dir) ++// { ++// if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// } + +- /* Now create an index into the central directory file records, do some basic sanity checking on each record */ +- p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; +- for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) +- { +- mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; +- mz_uint64 comp_size, decomp_size, local_header_ofs; ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +- if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// /* Now create an index into the central directory file records, do some basic sanity checking on each record */ ++// p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; ++// for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) ++// { ++// mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; ++// mz_uint64 comp_size, decomp_size, local_header_ofs; + +- MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); ++// if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (sort_central_dir) +- MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; ++// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + +- comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); +- decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); +- local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); +- filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +- ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); ++// if (sort_central_dir) ++// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; + +- if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && +- (ext_data_size) && +- (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) +- { +- /* Attempt to find zip64 extended information field in the entry's extra data */ +- mz_uint32 extra_size_remaining = ext_data_size; ++// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); ++// decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); ++// local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); ++// filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + +- if (extra_size_remaining) +- { +- const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; ++// if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && ++// (ext_data_size) && ++// (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) ++// { ++// /* Attempt to find zip64 extended information field in the entry's extra data */ ++// mz_uint32 extra_size_remaining = ext_data_size; + +- do +- { +- mz_uint32 field_id; +- mz_uint32 field_data_size; ++// if (extra_size_remaining) ++// { ++// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; + +- if (extra_size_remaining < (sizeof(mz_uint16) * 2)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// do ++// { ++// mz_uint32 field_id; ++// mz_uint32 field_data_size; + +- field_id = MZ_READ_LE16(pExtra_data); +- field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); ++// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// field_id = MZ_READ_LE16(pExtra_data); ++// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + +- if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) +- { +- /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ +- pZip->m_pState->m_zip64 = MZ_TRUE; +- pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; +- break; +- } ++// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; +- extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; +- } while (extra_size_remaining); +- } +- } ++// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) ++// { ++// /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ ++// pZip->m_pState->m_zip64 = MZ_TRUE; ++// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; ++// break; ++// } + +- /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ +- if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) +- { +- if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- } ++// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; ++// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; ++// } while (extra_size_remaining); ++// } ++// } + +- disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); +- if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); ++// /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ ++// if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) ++// { ++// if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// } + +- if (comp_size != MZ_UINT32_MAX) +- { +- if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- } ++// disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); ++// if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +- bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); +- if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); ++// if (comp_size != MZ_UINT32_MAX) ++// { ++// if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// } + +- if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); ++// if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + +- n -= total_header_size; +- p += total_header_size; +- } +- } ++// if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (sort_central_dir) +- mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); ++// n -= total_header_size; ++// p += total_header_size; ++// } ++// } + +- return MZ_TRUE; +-} ++// if (sort_central_dir) ++// mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + +-void mz_zip_zero_struct(mz_zip_archive *pZip) +-{ +- if (pZip) +- MZ_CLEAR_OBJ(*pZip); +-} ++// return MZ_TRUE; ++// } + +-static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +-{ +- mz_bool status = MZ_TRUE; ++// void mz_zip_zero_struct(mz_zip_archive *pZip) ++// { ++// if (pZip) ++// MZ_CLEAR_OBJ(*pZip); ++// } + +- if (!pZip) +- return MZ_FALSE; ++// static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) ++// { ++// mz_bool status = MZ_TRUE; + +- if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) +- { +- if (set_last_error) +- pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; ++// if (!pZip) ++// return MZ_FALSE; + +- return MZ_FALSE; +- } ++// if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) ++// { ++// if (set_last_error) ++// pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; + +- if (pZip->m_pState) +- { +- mz_zip_internal_state *pState = pZip->m_pState; +- pZip->m_pState = NULL; ++// return MZ_FALSE; ++// } + +- mz_zip_array_clear(pZip, &pState->m_central_dir); +- mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); +- mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); ++// if (pZip->m_pState) ++// { ++// mz_zip_internal_state *pState = pZip->m_pState; ++// pZip->m_pState = NULL; + +-#ifndef MINIZ_NO_STDIO +- if (pState->m_pFile) +- { +- if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) +- { +- if (MZ_FCLOSE(pState->m_pFile) == EOF) +- { +- if (set_last_error) +- pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; +- status = MZ_FALSE; +- } +- } +- pState->m_pFile = NULL; +- } +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// mz_zip_array_clear(pZip, &pState->m_central_dir); ++// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); ++// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- } +- pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; ++// #ifndef MINIZ_NO_STDIO ++// if (pState->m_pFile) ++// { ++// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) ++// { ++// if (MZ_FCLOSE(pState->m_pFile) == EOF) ++// { ++// if (set_last_error) ++// pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; ++// status = MZ_FALSE; ++// } ++// } ++// pState->m_pFile = NULL; ++// } ++// #endif /* #ifndef MINIZ_NO_STDIO */ + +- return status; +-} ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// } ++// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + +-mz_bool mz_zip_reader_end(mz_zip_archive *pZip) +-{ +- return mz_zip_reader_end_internal(pZip, MZ_TRUE); +-} +-mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) +-{ +- if ((!pZip) || (!pZip->m_pRead)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return status; ++// } + +- if (!mz_zip_reader_init_internal(pZip, flags)) +- return MZ_FALSE; ++// mz_bool mz_zip_reader_end(mz_zip_archive *pZip) ++// { ++// return mz_zip_reader_end_internal(pZip, MZ_TRUE); ++// } ++// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) ++// { ++// if ((!pZip) || (!pZip->m_pRead)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- pZip->m_zip_type = MZ_ZIP_TYPE_USER; +- pZip->m_archive_size = size; ++// if (!mz_zip_reader_init_internal(pZip, flags)) ++// return MZ_FALSE; + +- if (!mz_zip_reader_read_central_dir(pZip, flags)) +- { +- mz_zip_reader_end_internal(pZip, MZ_FALSE); +- return MZ_FALSE; +- } ++// pZip->m_zip_type = MZ_ZIP_TYPE_USER; ++// pZip->m_archive_size = size; + +- return MZ_TRUE; +-} ++// if (!mz_zip_reader_read_central_dir(pZip, flags)) ++// { ++// mz_zip_reader_end_internal(pZip, MZ_FALSE); ++// return MZ_FALSE; ++// } + +-static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +-{ +- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +- size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); +- memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); +- return s; +-} ++// return MZ_TRUE; ++// } + +-mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) +-{ +- if (!pMem) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) ++// { ++// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; ++// size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); ++// memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); ++// return s; ++// } + +- if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); ++// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) ++// { ++// if (!pMem) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if (!mz_zip_reader_init_internal(pZip, flags)) +- return MZ_FALSE; ++// if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +- pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; +- pZip->m_archive_size = size; +- pZip->m_pRead = mz_zip_mem_read_func; +- pZip->m_pIO_opaque = pZip; +- pZip->m_pNeeds_keepalive = NULL; ++// if (!mz_zip_reader_init_internal(pZip, flags)) ++// return MZ_FALSE; + +-#ifdef __cplusplus +- pZip->m_pState->m_pMem = const_cast(pMem); +-#else +- pZip->m_pState->m_pMem = (void *)pMem; +-#endif ++// pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; ++// pZip->m_archive_size = size; ++// pZip->m_pRead = mz_zip_mem_read_func; ++// pZip->m_pIO_opaque = pZip; ++// pZip->m_pNeeds_keepalive = NULL; + +- pZip->m_pState->m_mem_size = size; ++// #ifdef __cplusplus ++// pZip->m_pState->m_pMem = const_cast(pMem); ++// #else ++// pZip->m_pState->m_pMem = (void *)pMem; ++// #endif + +- if (!mz_zip_reader_read_central_dir(pZip, flags)) +- { +- mz_zip_reader_end_internal(pZip, MZ_FALSE); +- return MZ_FALSE; +- } ++// pZip->m_pState->m_mem_size = size; + +- return MZ_TRUE; +-} ++// if (!mz_zip_reader_read_central_dir(pZip, flags)) ++// { ++// mz_zip_reader_end_internal(pZip, MZ_FALSE); ++// return MZ_FALSE; ++// } + +-#ifndef MINIZ_NO_STDIO +-static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +-{ +- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +- mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); ++// return MZ_TRUE; ++// } + +- file_ofs += pZip->m_pState->m_file_archive_start_ofs; ++// #ifndef MINIZ_NO_STDIO ++// static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) ++// { ++// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; ++// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + +- if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) +- return 0; ++// file_ofs += pZip->m_pState->m_file_archive_start_ofs; + +- return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); +-} ++// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) ++// return 0; + +-mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) +-{ +- return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); +-} ++// return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); ++// } + +-mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) +-{ +- mz_uint64 file_size; +- MZ_FILE *pFile; ++// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) ++// { ++// return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); ++// } + +- if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) ++// { ++// mz_uint64 file_size; ++// MZ_FILE *pFile; + +- pFile = MZ_FOPEN(pFilename, "rb"); +- if (!pFile) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); ++// if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- file_size = archive_size; +- if (!file_size) +- { +- if (MZ_FSEEK64(pFile, 0, SEEK_END)) +- { +- MZ_FCLOSE(pFile); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); +- } ++// pFile = MZ_FOPEN(pFilename, "rb"); ++// if (!pFile) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +- file_size = MZ_FTELL64(pFile); +- } ++// file_size = archive_size; ++// if (!file_size) ++// { ++// if (MZ_FSEEK64(pFile, 0, SEEK_END)) ++// { ++// MZ_FCLOSE(pFile); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); ++// } + +- /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ ++// file_size = MZ_FTELL64(pFile); ++// } + +- if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +- { +- MZ_FCLOSE(pFile); +- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); +- } ++// /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ + +- if (!mz_zip_reader_init_internal(pZip, flags)) +- { +- MZ_FCLOSE(pFile); +- return MZ_FALSE; +- } ++// if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// { ++// MZ_FCLOSE(pFile); ++// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); ++// } + +- pZip->m_zip_type = MZ_ZIP_TYPE_FILE; +- pZip->m_pRead = mz_zip_file_read_func; +- pZip->m_pIO_opaque = pZip; +- pZip->m_pState->m_pFile = pFile; +- pZip->m_archive_size = file_size; +- pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; ++// if (!mz_zip_reader_init_internal(pZip, flags)) ++// { ++// MZ_FCLOSE(pFile); ++// return MZ_FALSE; ++// } + +- if (!mz_zip_reader_read_central_dir(pZip, flags)) +- { +- mz_zip_reader_end_internal(pZip, MZ_FALSE); +- return MZ_FALSE; +- } ++// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; ++// pZip->m_pRead = mz_zip_file_read_func; ++// pZip->m_pIO_opaque = pZip; ++// pZip->m_pState->m_pFile = pFile; ++// pZip->m_archive_size = file_size; ++// pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; + +- return MZ_TRUE; +-} ++// if (!mz_zip_reader_read_central_dir(pZip, flags)) ++// { ++// mz_zip_reader_end_internal(pZip, MZ_FALSE); ++// return MZ_FALSE; ++// } + +-mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) +-{ +- mz_uint64 cur_file_ofs; ++// return MZ_TRUE; ++// } + +- if ((!pZip) || (!pFile)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); ++// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) ++// { ++// mz_uint64 cur_file_ofs; + +- cur_file_ofs = MZ_FTELL64(pFile); ++// if ((!pZip) || (!pFile)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +- if (!archive_size) +- { +- if (MZ_FSEEK64(pFile, 0, SEEK_END)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); ++// cur_file_ofs = MZ_FTELL64(pFile); + +- archive_size = MZ_FTELL64(pFile) - cur_file_ofs; ++// if (!archive_size) ++// { ++// if (MZ_FSEEK64(pFile, 0, SEEK_END)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + +- if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); +- } ++// archive_size = MZ_FTELL64(pFile) - cur_file_ofs; + +- if (!mz_zip_reader_init_internal(pZip, flags)) +- return MZ_FALSE; ++// if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); ++// } + +- pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; +- pZip->m_pRead = mz_zip_file_read_func; ++// if (!mz_zip_reader_init_internal(pZip, flags)) ++// return MZ_FALSE; + +- pZip->m_pIO_opaque = pZip; +- pZip->m_pState->m_pFile = pFile; +- pZip->m_archive_size = archive_size; +- pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; ++// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; ++// pZip->m_pRead = mz_zip_file_read_func; + +- if (!mz_zip_reader_read_central_dir(pZip, flags)) +- { +- mz_zip_reader_end_internal(pZip, MZ_FALSE); +- return MZ_FALSE; +- } ++// pZip->m_pIO_opaque = pZip; ++// pZip->m_pState->m_pFile = pFile; ++// pZip->m_archive_size = archive_size; ++// pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; + +- return MZ_TRUE; +-} ++// if (!mz_zip_reader_read_central_dir(pZip, flags)) ++// { ++// mz_zip_reader_end_internal(pZip, MZ_FALSE); ++// return MZ_FALSE; ++// } + +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// return MZ_TRUE; ++// } + +-static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) +-{ +- if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) +- return NULL; +- return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); +-} ++// #endif /* #ifndef MINIZ_NO_STDIO */ + +-mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) +-{ +- mz_uint m_bit_flag; +- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +- if (!p) +- { +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- return MZ_FALSE; +- } ++// static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) ++// { ++// if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) ++// return NULL; ++// return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); ++// } + +- m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); +- return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; +-} ++// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) ++// { ++// mz_uint m_bit_flag; ++// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); ++// if (!p) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return MZ_FALSE; ++// } + +-mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) +-{ +- mz_uint bit_flag; +- mz_uint method; ++// m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); ++// return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; ++// } + +- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +- if (!p) +- { +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- return MZ_FALSE; +- } ++// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) ++// { ++// mz_uint bit_flag; ++// mz_uint method; + +- method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +- bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); ++// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); ++// if (!p) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return MZ_FALSE; ++// } + +- if ((method != 0) && (method != MZ_DEFLATED)) +- { +- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); +- return MZ_FALSE; +- } ++// method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); ++// bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + +- if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) +- { +- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); +- return MZ_FALSE; +- } ++// if ((method != 0) && (method != MZ_DEFLATED)) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); ++// return MZ_FALSE; ++// } + +- if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) +- { +- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); +- return MZ_FALSE; +- } ++// if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); ++// return MZ_FALSE; ++// } + +- return MZ_TRUE; +-} ++// if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); ++// return MZ_FALSE; ++// } + +-mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) +-{ +- mz_uint filename_len, attribute_mapping_id, external_attr; +- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +- if (!p) +- { +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- return MZ_FALSE; +- } ++// return MZ_TRUE; ++// } + +- filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +- if (filename_len) +- { +- if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') +- return MZ_TRUE; +- } ++// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) ++// { ++// mz_uint filename_len, attribute_mapping_id, external_attr; ++// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); ++// if (!p) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return MZ_FALSE; ++// } ++ ++// filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// if (filename_len) ++// { ++// if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') ++// return MZ_TRUE; ++// } + + /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */ + /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */ + /* FIXME: Remove this check? Is it necessary - we already check the filename. */ +- attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; +- (void)attribute_mapping_id; ++// attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; ++// (void)attribute_mapping_id; + +- external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); +- if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) +- { +- return MZ_TRUE; +- } ++// external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); ++// if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) ++// { ++// return MZ_TRUE; ++// } + +- return MZ_FALSE; +-} ++// return MZ_FALSE; ++// } + +-static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) +-{ +- mz_uint n; +- const mz_uint8 *p = pCentral_dir_header; +- +- if (pFound_zip64_extra_data) +- *pFound_zip64_extra_data = MZ_FALSE; +- +- if ((!p) || (!pStat)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- +- /* Extract fields from the central directory record. */ +- pStat->m_file_index = file_index; +- pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); +- pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); +- pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); +- pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); +- pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +-#ifndef MINIZ_NO_TIME +- pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); +-#endif +- pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); +- pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); +- pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); +- pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); +- pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); +- pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); +- +- /* Copy as much of the filename and comment as possible. */ +- n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +- n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); +- memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); +- pStat->m_filename[n] = '\0'; +- +- n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); +- n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); +- pStat->m_comment_size = n; +- memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); +- pStat->m_comment[n] = '\0'; +- +- /* Set some flags for convienance */ +- pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); +- pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); +- pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); +- +- /* See if we need to read any zip64 extended information fields. */ +- /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ +- if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) +- { +- /* Attempt to find zip64 extended information field in the entry's extra data */ +- mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); ++// static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) ++// { ++// mz_uint n; ++// const mz_uint8 *p = pCentral_dir_header; + +- if (extra_size_remaining) +- { +- const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// if (pFound_zip64_extra_data) ++// *pFound_zip64_extra_data = MZ_FALSE; + +- do +- { +- mz_uint32 field_id; +- mz_uint32 field_data_size; ++// if ((!p) || (!pStat)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if (extra_size_remaining < (sizeof(mz_uint16) * 2)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// /* Extract fields from the central directory record. */ ++// pStat->m_file_index = file_index; ++// pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); ++// pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); ++// pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); ++// pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); ++// pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); ++// #ifndef MINIZ_NO_TIME ++// pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); ++// #endif ++// pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); ++// pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); ++// pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); ++// pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); ++// pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); ++// pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); ++ ++// /* Copy as much of the filename and comment as possible. */ ++// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); ++// memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); ++// pStat->m_filename[n] = '\0'; ++ ++// n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); ++// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); ++// pStat->m_comment_size = n; ++// memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); ++// pStat->m_comment[n] = '\0'; ++ ++// /* Set some flags for convienance */ ++// pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); ++// pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); ++// pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); ++ ++// /* See if we need to read any zip64 extended information fields. */ ++// /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ ++// if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) ++// { ++// /* Attempt to find zip64 extended information field in the entry's extra data */ ++// mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + +- field_id = MZ_READ_LE16(pExtra_data); +- field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); ++// if (extra_size_remaining) ++// { ++// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + +- if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// do ++// { ++// mz_uint32 field_id; ++// mz_uint32 field_data_size; + +- if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) +- { +- const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; +- mz_uint32 field_data_remaining = field_data_size; ++// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (pFound_zip64_extra_data) +- *pFound_zip64_extra_data = MZ_TRUE; ++// field_id = MZ_READ_LE16(pExtra_data); ++// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + +- if (pStat->m_uncomp_size == MZ_UINT32_MAX) +- { +- if (field_data_remaining < sizeof(mz_uint64)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- pStat->m_uncomp_size = MZ_READ_LE64(pField_data); +- pField_data += sizeof(mz_uint64); +- field_data_remaining -= sizeof(mz_uint64); +- } ++// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) ++// { ++// const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; ++// mz_uint32 field_data_remaining = field_data_size; ++ ++// if (pFound_zip64_extra_data) ++// *pFound_zip64_extra_data = MZ_TRUE; ++ ++// if (pStat->m_uncomp_size == MZ_UINT32_MAX) ++// { ++// if (field_data_remaining < sizeof(mz_uint64)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++ ++// pStat->m_uncomp_size = MZ_READ_LE64(pField_data); ++// pField_data += sizeof(mz_uint64); ++// field_data_remaining -= sizeof(mz_uint64); ++// } ++ ++// if (pStat->m_comp_size == MZ_UINT32_MAX) ++// { ++// if (field_data_remaining < sizeof(mz_uint64)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++ ++// pStat->m_comp_size = MZ_READ_LE64(pField_data); ++// pField_data += sizeof(mz_uint64); ++// field_data_remaining -= sizeof(mz_uint64); ++// } ++ ++// if (pStat->m_local_header_ofs == MZ_UINT32_MAX) ++// { ++// if (field_data_remaining < sizeof(mz_uint64)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++ ++// pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); ++// pField_data += sizeof(mz_uint64); ++// // field_data_remaining -= sizeof(mz_uint64); ++// } ++ ++// break; ++// } + +- if (pStat->m_comp_size == MZ_UINT32_MAX) +- { +- if (field_data_remaining < sizeof(mz_uint64)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; ++// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; ++// } while (extra_size_remaining); ++// } ++// } + +- pStat->m_comp_size = MZ_READ_LE64(pField_data); +- pField_data += sizeof(mz_uint64); +- field_data_remaining -= sizeof(mz_uint64); +- } ++// return MZ_TRUE; ++// } + +- if (pStat->m_local_header_ofs == MZ_UINT32_MAX) +- { +- if (field_data_remaining < sizeof(mz_uint64)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) ++// { ++// mz_uint i; ++// if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) ++// return 0 == memcmp(pA, pB, len); ++// for (i = 0; i < len; ++i) ++// if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) ++// return MZ_FALSE; ++// return MZ_TRUE; ++// } + +- pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); +- pField_data += sizeof(mz_uint64); +- // field_data_remaining -= sizeof(mz_uint64); +- } ++// static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) ++// { ++// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; ++// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// mz_uint8 l = 0, r = 0; ++// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; ++// pE = pL + MZ_MIN(l_len, r_len); ++// while (pL < pE) ++// { ++// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) ++// break; ++// pL++; ++// pR++; ++// } ++// return (pL == pE) ? (int)(l_len - r_len) : (l - r); ++// } + +- break; +- } ++// static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) ++// { ++// mz_zip_internal_state *pState = pZip->m_pState; ++// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; ++// const mz_zip_array *pCentral_dir = &pState->m_central_dir; ++// mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); ++// const uint32_t size = pZip->m_total_files; ++// const mz_uint filename_len = (mz_uint)strlen(pFilename); + +- pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; +- extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; +- } while (extra_size_remaining); +- } +- } ++// if (pIndex) ++// *pIndex = 0; + +- return MZ_TRUE; +-} ++// if (size) ++// { ++// /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ ++// /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ ++// mz_int64 l = 0, h = (mz_int64)size - 1; + +-static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) +-{ +- mz_uint i; +- if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) +- return 0 == memcmp(pA, pB, len); +- for (i = 0; i < len; ++i) +- if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) +- return MZ_FALSE; +- return MZ_TRUE; +-} ++// while (l <= h) ++// { ++// mz_int64 m = l + ((h - l) >> 1); ++// uint32_t file_index = pIndices[(uint32_t)m]; + +-static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) +-{ +- const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; +- mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); +- mz_uint8 l = 0, r = 0; +- pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +- pE = pL + MZ_MIN(l_len, r_len); +- while (pL < pE) +- { +- if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) +- break; +- pL++; +- pR++; +- } +- return (pL == pE) ? (int)(l_len - r_len) : (l - r); +-} ++// int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); ++// if (!comp) ++// { ++// if (pIndex) ++// *pIndex = file_index; ++// return MZ_TRUE; ++// } ++// else if (comp < 0) ++// l = m + 1; ++// else ++// h = m - 1; ++// } ++// } + +-static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) +-{ +- mz_zip_internal_state *pState = pZip->m_pState; +- const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; +- const mz_zip_array *pCentral_dir = &pState->m_central_dir; +- mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); +- const uint32_t size = pZip->m_total_files; +- const mz_uint filename_len = (mz_uint)strlen(pFilename); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); ++// } + +- if (pIndex) +- *pIndex = 0; ++// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) ++// { ++// mz_uint32 index_; ++// if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) ++// return -1; ++// else ++// return (int)index_; ++// } + +- if (size) +- { +- /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ +- /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ +- mz_int64 l = 0, h = (mz_int64)size - 1; ++// mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) ++// { ++// mz_uint file_index; ++// size_t name_len, comment_len; + +- while (l <= h) +- { +- mz_int64 m = l + ((h - l) >> 1); +- uint32_t file_index = pIndices[(uint32_t)m]; ++// if (pIndex) ++// *pIndex = 0; + +- int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); +- if (!comp) +- { +- if (pIndex) +- *pIndex = file_index; +- return MZ_TRUE; +- } +- else if (comp < 0) +- l = m + 1; +- else +- h = m - 1; +- } +- } ++// if ((!pZip) || (!pZip->m_pState) || (!pName)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +-} ++// /* See if we can use a binary search */ ++// if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && ++// (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && ++// ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) ++// { ++// return mz_zip_locate_file_binary_search(pZip, pName, pIndex); ++// } + +-int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) +-{ +- mz_uint32 index_; +- if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) +- return -1; +- else +- return (int)index_; +-} ++// /* Locate the entry by scanning the entire central directory */ ++// name_len = strlen(pName); ++// if (name_len > MZ_UINT16_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +-mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) +-{ +- mz_uint file_index; +- size_t name_len, comment_len; ++// comment_len = pComment ? strlen(pComment) : 0; ++// if (comment_len > MZ_UINT16_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if (pIndex) +- *pIndex = 0; ++// for (file_index = 0; file_index < pZip->m_total_files; file_index++) ++// { ++// const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); ++// mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; ++// if (filename_len < name_len) ++// continue; ++// if (comment_len) ++// { ++// mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); ++// const char *pFile_comment = pFilename + filename_len + file_extra_len; ++// if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) ++// continue; ++// } ++// if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) ++// { ++// int ofs = filename_len - 1; ++// do ++// { ++// if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) ++// break; ++// } while (--ofs >= 0); ++// ofs++; ++// pFilename += ofs; ++// filename_len -= ofs; ++// } ++// if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) ++// { ++// if (pIndex) ++// *pIndex = file_index; ++// return MZ_TRUE; ++// } ++// } + +- if ((!pZip) || (!pZip->m_pState) || (!pName)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); ++// } + +- /* See if we can use a binary search */ +- if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && +- (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && +- ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) +- { +- return mz_zip_locate_file_binary_search(pZip, pName, pIndex); +- } ++// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) ++// { ++// int status = TINFL_STATUS_DONE; ++// mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; ++// mz_zip_archive_file_stat file_stat; ++// void *pRead_buf; ++// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; ++// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; ++// tinfl_decompressor inflator; + +- /* Locate the entry by scanning the entire central directory */ +- name_len = strlen(pName); +- if (name_len > MZ_UINT16_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- comment_len = pComment ? strlen(pComment) : 0; +- if (comment_len > MZ_UINT16_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) ++// return MZ_FALSE; + +- for (file_index = 0; file_index < pZip->m_total_files; file_index++) +- { +- const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); +- mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); +- const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +- if (filename_len < name_len) +- continue; +- if (comment_len) +- { +- mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); +- const char *pFile_comment = pFilename + filename_len + file_extra_len; +- if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) +- continue; +- } +- if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) +- { +- int ofs = filename_len - 1; +- do +- { +- if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) +- break; +- } while (--ofs >= 0); +- ofs++; +- pFilename += ofs; +- filename_len -= ofs; +- } +- if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) +- { +- if (pIndex) +- *pIndex = file_index; +- return MZ_TRUE; +- } +- } ++// /* A directory or zero length file */ ++// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) ++// return MZ_TRUE; + +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +-} ++// /* Encryption and patch files are not supported. */ ++// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + +-mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +-{ +- int status = TINFL_STATUS_DONE; +- mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; +- mz_zip_archive_file_stat file_stat; +- void *pRead_buf; +- mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +- mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; +- tinfl_decompressor inflator; +- +- if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- +- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +- return MZ_FALSE; +- +- /* A directory or zero length file */ +- if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) +- return MZ_TRUE; +- +- /* Encryption and patch files are not supported. */ +- if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); +- +- /* This function only supports decompressing stored and deflate. */ +- if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); +- +- /* Ensure supplied output buffer is large enough. */ +- needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; +- if (buf_size < needed_size) +- return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); +- +- /* Read and parse the local directory entry. */ +- cur_file_ofs = file_stat.m_local_header_ofs; +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +- +- if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- +- cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +- if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- +- if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) +- { +- /* The file is stored or the caller has requested the compressed data. */ +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// /* This function only supports decompressing stored and deflate. */ ++// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) +- { +- if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) +- return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); +- } +-#endif ++// /* Ensure supplied output buffer is large enough. */ ++// needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; ++// if (buf_size < needed_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); + +- return MZ_TRUE; +- } ++// /* Read and parse the local directory entry. */ ++// cur_file_ofs = file_stat.m_local_header_ofs; ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +- /* Decompress the file either directly from memory or from a file input buffer. */ +- tinfl_init(&inflator); ++// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (pZip->m_pState->m_pMem) +- { +- /* Read directly from the archive in memory. */ +- pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; +- read_buf_size = read_buf_avail = file_stat.m_comp_size; +- comp_remaining = 0; +- } +- else if (pUser_read_buf) +- { +- /* Use a user provided read buffer. */ +- if (!user_read_buf_size) +- return MZ_FALSE; +- pRead_buf = (mz_uint8 *)pUser_read_buf; +- read_buf_size = user_read_buf_size; +- read_buf_avail = 0; +- comp_remaining = file_stat.m_comp_size; +- } +- else +- { +- /* Temporarily allocate a read buffer. */ +- read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); +- if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); ++// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) ++// { ++// /* The file is stored or the caller has requested the compressed data. */ ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +- read_buf_avail = 0; +- comp_remaining = file_stat.m_comp_size; +- } ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) ++// { ++// if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) ++// return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); ++// } ++// #endif + +- do +- { +- /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ +- size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); +- if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) +- { +- read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +- { +- status = TINFL_STATUS_FAILED; +- mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); +- break; +- } +- cur_file_ofs += read_buf_avail; +- comp_remaining -= read_buf_avail; +- read_buf_ofs = 0; +- } +- in_buf_size = (size_t)read_buf_avail; +- status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); +- read_buf_avail -= in_buf_size; +- read_buf_ofs += in_buf_size; +- out_buf_ofs += out_buf_size; +- } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); +- +- if (status == TINFL_STATUS_DONE) +- { +- /* Make sure the entire file was decompressed, and check its CRC. */ +- if (out_buf_ofs != file_stat.m_uncomp_size) +- { +- mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); +- status = TINFL_STATUS_FAILED; +- } +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) +- { +- mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); +- status = TINFL_STATUS_FAILED; +- } +-#endif +- } ++// return MZ_TRUE; ++// } + +- if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) +- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); ++// /* Decompress the file either directly from memory or from a file input buffer. */ ++// tinfl_init(&inflator); + +- return status == TINFL_STATUS_DONE; +-} ++// if (pZip->m_pState->m_pMem) ++// { ++// /* Read directly from the archive in memory. */ ++// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; ++// read_buf_size = read_buf_avail = file_stat.m_comp_size; ++// comp_remaining = 0; ++// } ++// else if (pUser_read_buf) ++// { ++// /* Use a user provided read buffer. */ ++// if (!user_read_buf_size) ++// return MZ_FALSE; ++// pRead_buf = (mz_uint8 *)pUser_read_buf; ++// read_buf_size = user_read_buf_size; ++// read_buf_avail = 0; ++// comp_remaining = file_stat.m_comp_size; ++// } ++// else ++// { ++// /* Temporarily allocate a read buffer. */ ++// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); ++// if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +-mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +-{ +- mz_uint32 file_index; +- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +- return MZ_FALSE; +- return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); +-} ++// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +-mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) +-{ +- return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); +-} ++// read_buf_avail = 0; ++// comp_remaining = file_stat.m_comp_size; ++// } + +-mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) +-{ +- return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); +-} ++// do ++// { ++// /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ ++// size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); ++// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) ++// { ++// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) ++// { ++// status = TINFL_STATUS_FAILED; ++// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); ++// break; ++// } ++// cur_file_ofs += read_buf_avail; ++// comp_remaining -= read_buf_avail; ++// read_buf_ofs = 0; ++// } ++// in_buf_size = (size_t)read_buf_avail; ++// status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); ++// read_buf_avail -= in_buf_size; ++// read_buf_ofs += in_buf_size; ++// out_buf_ofs += out_buf_size; ++// } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); ++ ++// if (status == TINFL_STATUS_DONE) ++// { ++// /* Make sure the entire file was decompressed, and check its CRC. */ ++// if (out_buf_ofs != file_stat.m_uncomp_size) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); ++// status = TINFL_STATUS_FAILED; ++// } ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); ++// status = TINFL_STATUS_FAILED; ++// } ++// #endif ++// } + +-void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) +-{ +- mz_uint64 comp_size, uncomp_size, alloc_size; +- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +- void *pBuf; ++// if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + +- if (pSize) +- *pSize = 0; ++// return status == TINFL_STATUS_DONE; ++// } + +- if (!p) +- { +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- return NULL; +- } ++// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) ++// { ++// mz_uint32 file_index; ++// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) ++// return MZ_FALSE; ++// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); ++// } + +- comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); +- uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); ++// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) ++// { ++// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); ++// } + +- alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; +- if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +- { +- mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); +- return NULL; +- } ++// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) ++// { ++// return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); ++// } + +- if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) +- { +- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- return NULL; +- } ++// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) ++// { ++// mz_uint64 comp_size, uncomp_size, alloc_size; ++// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); ++// void *pBuf; + +- if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); +- return NULL; +- } ++// if (pSize) ++// *pSize = 0; + +- if (pSize) +- *pSize = (size_t)alloc_size; +- return pBuf; +-} ++// if (!p) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return NULL; ++// } + +-void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) +-{ +- mz_uint32 file_index; +- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +- { +- if (pSize) +- *pSize = 0; +- return MZ_FALSE; +- } +- return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); +-} ++// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); ++// uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + +-mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +-{ +- int status = TINFL_STATUS_DONE; +- mz_uint file_crc32 = MZ_CRC32_INIT; +- mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; +- mz_zip_archive_file_stat file_stat; +- void *pRead_buf = NULL; +- void *pWrite_buf = NULL; +- mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +- mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; +- +- if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- +- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +- return MZ_FALSE; +- +- /* A directory or zero length file */ +- if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) +- return MZ_TRUE; +- +- /* Encryption and patch files are not supported. */ +- if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); +- +- /* This function only supports decompressing stored and deflate. */ +- if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); +- +- /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ +- cur_file_ofs = file_stat.m_local_header_ofs; +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +- +- if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- +- cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +- if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- +- /* Decompress the file either directly from memory or from a file input buffer. */ +- if (pZip->m_pState->m_pMem) +- { +- pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; +- read_buf_size = read_buf_avail = file_stat.m_comp_size; +- comp_remaining = 0; +- } +- else +- { +- read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); +- if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; ++// if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// return NULL; ++// } + +- read_buf_avail = 0; +- comp_remaining = file_stat.m_comp_size; +- } ++// if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// return NULL; ++// } + +- if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) +- { +- /* The file is stored or the caller has requested the compressed data. */ +- if (pZip->m_pState->m_pMem) +- { +- if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); ++// return NULL; ++// } + +- if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) +- { +- mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); +- status = TINFL_STATUS_FAILED; +- } +- else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +- { +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); +-#endif +- } ++// if (pSize) ++// *pSize = (size_t)alloc_size; ++// return pBuf; ++// } + +- cur_file_ofs += file_stat.m_comp_size; +- out_buf_ofs += file_stat.m_comp_size; +- comp_remaining = 0; +- } +- else +- { +- while (comp_remaining) +- { +- read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +- { +- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +- status = TINFL_STATUS_FAILED; +- break; +- } ++// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) ++// { ++// mz_uint32 file_index; ++// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) ++// { ++// if (pSize) ++// *pSize = 0; ++// return MZ_FALSE; ++// } ++// return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); ++// } + +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +- { +- file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); +- } +-#endif ++// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) ++// { ++// int status = TINFL_STATUS_DONE; ++// mz_uint file_crc32 = MZ_CRC32_INIT; ++// mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; ++// mz_zip_archive_file_stat file_stat; ++// void *pRead_buf = NULL; ++// void *pWrite_buf = NULL; ++// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; ++// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + +- if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +- { +- mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); +- status = TINFL_STATUS_FAILED; +- break; +- } ++// if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- cur_file_ofs += read_buf_avail; +- out_buf_ofs += read_buf_avail; +- comp_remaining -= read_buf_avail; +- } +- } +- } +- else +- { +- tinfl_decompressor inflator; +- tinfl_init(&inflator); ++// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) ++// return MZ_FALSE; + +- if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) +- { +- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- status = TINFL_STATUS_FAILED; +- } +- else +- { +- do +- { +- mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); +- size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); +- if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) +- { +- read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +- { +- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +- status = TINFL_STATUS_FAILED; +- break; +- } +- cur_file_ofs += read_buf_avail; +- comp_remaining -= read_buf_avail; +- read_buf_ofs = 0; +- } ++// /* A directory or zero length file */ ++// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) ++// return MZ_TRUE; + +- in_buf_size = (size_t)read_buf_avail; +- status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); +- read_buf_avail -= in_buf_size; +- read_buf_ofs += in_buf_size; ++// /* Encryption and patch files are not supported. */ ++// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + +- if (out_buf_size) +- { +- if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) +- { +- mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); +- status = TINFL_STATUS_FAILED; +- break; +- } ++// /* This function only supports decompressing stored and deflate. */ ++// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); +-#endif +- if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) +- { +- mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); +- status = TINFL_STATUS_FAILED; +- break; +- } +- } +- } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); +- } +- } ++// /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ ++// cur_file_ofs = file_stat.m_local_header_ofs; ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +- if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) +- { +- /* Make sure the entire file was decompressed, and check its CRC. */ +- if (out_buf_ofs != file_stat.m_uncomp_size) +- { +- mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); +- status = TINFL_STATUS_FAILED; +- } +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- else if (file_crc32 != file_stat.m_crc32) +- { +- mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); +- status = TINFL_STATUS_FAILED; +- } +-#endif +- } ++// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (!pZip->m_pState->m_pMem) +- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); ++// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); ++// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +- if (pWrite_buf) +- pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); ++// /* Decompress the file either directly from memory or from a file input buffer. */ ++// if (pZip->m_pState->m_pMem) ++// { ++// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; ++// read_buf_size = read_buf_avail = file_stat.m_comp_size; ++// comp_remaining = 0; ++// } ++// else ++// { ++// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); ++// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +- return status == TINFL_STATUS_DONE; +-} ++// read_buf_avail = 0; ++// comp_remaining = file_stat.m_comp_size; ++// } + +-mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +-{ +- mz_uint32 file_index; +- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +- return MZ_FALSE; ++// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) ++// { ++// /* The file is stored or the caller has requested the compressed data. */ ++// if (pZip->m_pState->m_pMem) ++// { ++// if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +- return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); +-} ++// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); ++// status = TINFL_STATUS_FAILED; ++// } ++// else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) ++// { ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); ++// #endif ++// } + +-mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) +-{ +- mz_zip_reader_extract_iter_state *pState; +- mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +- mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; ++// cur_file_ofs += file_stat.m_comp_size; ++// out_buf_ofs += file_stat.m_comp_size; ++// comp_remaining = 0; ++// } ++// else ++// { ++// while (comp_remaining) ++// { ++// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// status = TINFL_STATUS_FAILED; ++// break; ++// } + +- /* Argument sanity check */ +- if ((!pZip) || (!pZip->m_pState)) +- return NULL; ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) ++// { ++// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); ++// } ++// #endif + +- /* Allocate an iterator status structure */ +- pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); +- if (!pState) +- { +- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- return NULL; +- } ++// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); ++// status = TINFL_STATUS_FAILED; ++// break; ++// } + +- /* Fetch file details */ +- if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } ++// cur_file_ofs += read_buf_avail; ++// out_buf_ofs += read_buf_avail; ++// comp_remaining -= read_buf_avail; ++// } ++// } ++// } ++// else ++// { ++// tinfl_decompressor inflator; ++// tinfl_init(&inflator); + +- /* Encryption and patch files are not supported. */ +- if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) +- { +- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } ++// if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// status = TINFL_STATUS_FAILED; ++// } ++// else ++// { ++// do ++// { ++// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); ++// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); ++// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) ++// { ++// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); ++// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// status = TINFL_STATUS_FAILED; ++// break; ++// } ++// cur_file_ofs += read_buf_avail; ++// comp_remaining -= read_buf_avail; ++// read_buf_ofs = 0; ++// } + +- /* This function only supports decompressing stored and deflate. */ +- if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) +- { +- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } ++// in_buf_size = (size_t)read_buf_avail; ++// status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); ++// read_buf_avail -= in_buf_size; ++// read_buf_ofs += in_buf_size; + +- /* Init state - save args */ +- pState->pZip = pZip; +- pState->flags = flags; ++// if (out_buf_size) ++// { ++// if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); ++// status = TINFL_STATUS_FAILED; ++// break; ++// } ++ ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); ++// #endif ++// if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); ++// status = TINFL_STATUS_FAILED; ++// break; ++// } ++// } ++// } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); ++// } ++// } + +- /* Init state - reset variables to defaults */ +- pState->status = TINFL_STATUS_DONE; +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- pState->file_crc32 = MZ_CRC32_INIT; +-#endif +- pState->read_buf_ofs = 0; +- pState->out_buf_ofs = 0; +- pState->pRead_buf = NULL; +- pState->pWrite_buf = NULL; +- pState->out_blk_remain = 0; +- +- /* Read and parse the local directory entry. */ +- pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; +- if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +- { +- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } ++// if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) ++// { ++// /* Make sure the entire file was decompressed, and check its CRC. */ ++// if (out_buf_ofs != file_stat.m_uncomp_size) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); ++// status = TINFL_STATUS_FAILED; ++// } ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// else if (file_crc32 != file_stat.m_crc32) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); ++// status = TINFL_STATUS_FAILED; ++// } ++// #endif ++// } + +- if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +- { +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } ++// if (!pZip->m_pState->m_pMem) ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + +- pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +- if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) +- { +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } ++// if (pWrite_buf) ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + +- /* Decompress the file either directly from memory or from a file input buffer. */ +- if (pZip->m_pState->m_pMem) +- { +- pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; +- pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; +- pState->comp_remaining = pState->file_stat.m_comp_size; +- } +- else +- { +- if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) +- { +- /* Decompression required, therefore intermediate read buffer required */ +- pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); +- if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) +- { +- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } +- } +- else +- { +- /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ +- pState->read_buf_size = 0; +- } +- pState->read_buf_avail = 0; +- pState->comp_remaining = pState->file_stat.m_comp_size; +- } ++// return status == TINFL_STATUS_DONE; ++// } ++ ++// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) ++// { ++// mz_uint32 file_index; ++// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) ++// return MZ_FALSE; ++ ++// return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); ++// } ++ ++// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) ++// { ++// mz_zip_reader_extract_iter_state *pState; ++// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; ++// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; ++ ++// /* Argument sanity check */ ++// if ((!pZip) || (!pZip->m_pState)) ++// return NULL; ++ ++// /* Allocate an iterator status structure */ ++// pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); ++// if (!pState) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// return NULL; ++// } ++ ++// /* Fetch file details */ ++// if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } ++ ++// /* Encryption and patch files are not supported. */ ++// if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } ++ ++// /* This function only supports decompressing stored and deflate. */ ++// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } ++ ++// /* Init state - save args */ ++// pState->pZip = pZip; ++// pState->flags = flags; ++ ++// /* Init state - reset variables to defaults */ ++// pState->status = TINFL_STATUS_DONE; ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// pState->file_crc32 = MZ_CRC32_INIT; ++// #endif ++// pState->read_buf_ofs = 0; ++// pState->out_buf_ofs = 0; ++// pState->pRead_buf = NULL; ++// pState->pWrite_buf = NULL; ++// pState->out_blk_remain = 0; ++ ++// /* Read and parse the local directory entry. */ ++// pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; ++// if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } ++ ++// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } ++ ++// pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); ++// if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } + +- if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) +- { +- /* Decompression required, init decompressor */ +- tinfl_init( &pState->inflator ); ++// /* Decompress the file either directly from memory or from a file input buffer. */ ++// if (pZip->m_pState->m_pMem) ++// { ++// pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; ++// pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; ++// pState->comp_remaining = pState->file_stat.m_comp_size; ++// } ++// else ++// { ++// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) ++// { ++// /* Decompression required, therefore intermediate read buffer required */ ++// pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); ++// if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } ++// } ++// else ++// { ++// /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ ++// pState->read_buf_size = 0; ++// } ++// pState->read_buf_avail = 0; ++// pState->comp_remaining = pState->file_stat.m_comp_size; ++// } + +- /* Allocate write buffer */ +- if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) +- { +- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- if (pState->pRead_buf) +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- return NULL; +- } +- } ++// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) ++// { ++// /* Decompression required, init decompressor */ ++// tinfl_init( &pState->inflator ); + +- return pState; +-} ++// /* Allocate write buffer */ ++// if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// if (pState->pRead_buf) ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// return NULL; ++// } ++// } + +-mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +-{ +- mz_uint32 file_index; ++// return pState; ++// } + +- /* Locate file index by name */ +- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +- return NULL; ++// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) ++// { ++// mz_uint32 file_index; + +- /* Construct iterator */ +- return mz_zip_reader_extract_iter_new(pZip, file_index, flags); +-} ++// /* Locate file index by name */ ++// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) ++// return NULL; + +-size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) +-{ +- size_t copied_to_caller = 0; ++// /* Construct iterator */ ++// return mz_zip_reader_extract_iter_new(pZip, file_index, flags); ++// } + +- /* Argument sanity check */ +- if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) +- return 0; ++// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) ++// { ++// size_t copied_to_caller = 0; + +- if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) +- { +- /* The file is stored or the caller has requested the compressed data, calc amount to return. */ +- copied_to_caller = MZ_MIN( buf_size, pState->comp_remaining ); ++// /* Argument sanity check */ ++// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) ++// return 0; + +- /* Zip is in memory....or requires reading from a file? */ +- if (pState->pZip->m_pState->m_pMem) +- { +- /* Copy data to caller's buffer */ +- memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); +- pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; +- } +- else +- { +- /* Read directly into caller's buffer */ +- if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) +- { +- /* Failed to read all that was asked for, flag failure and alert user */ +- mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); +- pState->status = TINFL_STATUS_FAILED; +- copied_to_caller = 0; +- } +- } ++// if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) ++// { ++// /* The file is stored or the caller has requested the compressed data, calc amount to return. */ ++// copied_to_caller = MZ_MIN( buf_size, pState->comp_remaining ); + +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- /* Compute CRC if not returning compressed data only */ +- if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +- pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); +-#endif ++// /* Zip is in memory....or requires reading from a file? */ ++// if (pState->pZip->m_pState->m_pMem) ++// { ++// /* Copy data to caller's buffer */ ++// memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); ++// pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; ++// } ++// else ++// { ++// /* Read directly into caller's buffer */ ++// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) ++// { ++// /* Failed to read all that was asked for, flag failure and alert user */ ++// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); ++// pState->status = TINFL_STATUS_FAILED; ++// copied_to_caller = 0; ++// } ++// } + +- /* Advance offsets, dec counters */ +- pState->cur_file_ofs += copied_to_caller; +- pState->out_buf_ofs += copied_to_caller; +- pState->comp_remaining -= copied_to_caller; +- } +- else +- { +- do +- { +- /* Calc ptr to write buffer - given current output pos and block size */ +- mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// /* Compute CRC if not returning compressed data only */ ++// if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) ++// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); ++// #endif + +- /* Calc max output size - given current output pos and block size */ +- size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); ++// /* Advance offsets, dec counters */ ++// pState->cur_file_ofs += copied_to_caller; ++// pState->out_buf_ofs += copied_to_caller; ++// pState->comp_remaining -= copied_to_caller; ++// } ++// else ++// { ++// do ++// { ++// /* Calc ptr to write buffer - given current output pos and block size */ ++// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + +- if (!pState->out_blk_remain) +- { +- /* Read more data from file if none available (and reading from file) */ +- if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) +- { +- /* Calc read size */ +- pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); +- if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) +- { +- mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); +- pState->status = TINFL_STATUS_FAILED; +- break; +- } ++// /* Calc max output size - given current output pos and block size */ ++// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + +- /* Advance offsets, dec counters */ +- pState->cur_file_ofs += pState->read_buf_avail; +- pState->comp_remaining -= pState->read_buf_avail; +- pState->read_buf_ofs = 0; +- } ++// if (!pState->out_blk_remain) ++// { ++// /* Read more data from file if none available (and reading from file) */ ++// if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) ++// { ++// /* Calc read size */ ++// pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); ++// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) ++// { ++// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); ++// pState->status = TINFL_STATUS_FAILED; ++// break; ++// } ++ ++// /* Advance offsets, dec counters */ ++// pState->cur_file_ofs += pState->read_buf_avail; ++// pState->comp_remaining -= pState->read_buf_avail; ++// pState->read_buf_ofs = 0; ++// } + +- /* Perform decompression */ +- in_buf_size = (size_t)pState->read_buf_avail; +- pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); +- pState->read_buf_avail -= in_buf_size; +- pState->read_buf_ofs += in_buf_size; ++// /* Perform decompression */ ++// in_buf_size = (size_t)pState->read_buf_avail; ++// pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); ++// pState->read_buf_avail -= in_buf_size; ++// pState->read_buf_ofs += in_buf_size; + +- /* Update current output block size remaining */ +- pState->out_blk_remain = out_buf_size; +- } ++// /* Update current output block size remaining */ ++// pState->out_blk_remain = out_buf_size; ++// } + +- if (pState->out_blk_remain) +- { +- /* Calc amount to return. */ +- size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); ++// if (pState->out_blk_remain) ++// { ++// /* Calc amount to return. */ ++// size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); + +- /* Copy data to caller's buffer */ +- memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); ++// /* Copy data to caller's buffer */ ++// memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); + +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- /* Perform CRC */ +- pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); +-#endif ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// /* Perform CRC */ ++// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); ++// #endif + +- /* Decrement data consumed from block */ +- pState->out_blk_remain -= to_copy; ++// /* Decrement data consumed from block */ ++// pState->out_blk_remain -= to_copy; + +- /* Inc output offset, while performing sanity check */ +- if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) +- { +- mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); +- pState->status = TINFL_STATUS_FAILED; +- break; +- } ++// /* Inc output offset, while performing sanity check */ ++// if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) ++// { ++// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); ++// pState->status = TINFL_STATUS_FAILED; ++// break; ++// } + +- /* Increment counter of data copied to caller */ +- copied_to_caller += to_copy; +- } +- } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); +- } ++// /* Increment counter of data copied to caller */ ++// copied_to_caller += to_copy; ++// } ++// } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); ++// } + +- /* Return how many bytes were copied into user buffer */ +- return copied_to_caller; +-} ++// /* Return how many bytes were copied into user buffer */ ++// return copied_to_caller; ++// } + +-mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) +-{ +- int status; ++// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) ++// { ++// int status; + +- /* Argument sanity check */ +- if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) +- return MZ_FALSE; ++// /* Argument sanity check */ ++// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) ++// return MZ_FALSE; + +- /* Was decompression completed and requested? */ +- if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) +- { +- /* Make sure the entire file was decompressed, and check its CRC. */ +- if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) +- { +- mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); +- pState->status = TINFL_STATUS_FAILED; +- } +-#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +- else if (pState->file_crc32 != pState->file_stat.m_crc32) +- { +- mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); +- pState->status = TINFL_STATUS_FAILED; +- } +-#endif +- } ++// /* Was decompression completed and requested? */ ++// if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) ++// { ++// /* Make sure the entire file was decompressed, and check its CRC. */ ++// if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) ++// { ++// mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); ++// pState->status = TINFL_STATUS_FAILED; ++// } ++// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS ++// else if (pState->file_crc32 != pState->file_stat.m_crc32) ++// { ++// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); ++// pState->status = TINFL_STATUS_FAILED; ++// } ++// #endif ++// } + +- /* Free buffers */ +- if (!pState->pZip->m_pState->m_pMem) +- pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); +- if (pState->pWrite_buf) +- pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); ++// /* Free buffers */ ++// if (!pState->pZip->m_pState->m_pMem) ++// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); ++// if (pState->pWrite_buf) ++// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); + +- /* Save status */ +- status = pState->status; ++// /* Save status */ ++// status = pState->status; + +- /* Free context */ +- pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); ++// /* Free context */ ++// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); + +- return status == TINFL_STATUS_DONE; +-} ++// return status == TINFL_STATUS_DONE; ++// } + +-#ifndef MINIZ_NO_STDIO +-static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) +-{ +- (void)ofs; ++// #ifndef MINIZ_NO_STDIO ++// static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) ++// { ++// (void)ofs; + +- return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); +-} ++// return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); ++// } + +-mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) +-{ +- mz_bool status; +- mz_zip_archive_file_stat file_stat; +- MZ_FILE *pFile; ++// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) ++// { ++// mz_bool status; ++// mz_zip_archive_file_stat file_stat; ++// MZ_FILE *pFile; + +- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +- return MZ_FALSE; ++// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) ++// return MZ_FALSE; + +- if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); ++// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + +- pFile = MZ_FOPEN(pDst_filename, "wb"); +- if (!pFile) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); ++// pFile = MZ_FOPEN(pDst_filename, "wb"); ++// if (!pFile) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +- status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); ++// status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); + +- if (MZ_FCLOSE(pFile) == EOF) +- { +- if (status) +- mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); ++// if (MZ_FCLOSE(pFile) == EOF) ++// { ++// if (status) ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); + +- status = MZ_FALSE; +- } ++// status = MZ_FALSE; ++// } + +-#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) +- if (status) +- mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); +-#endif ++// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) ++// if (status) ++// mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); ++// #endif + +- return status; +-} ++// return status; ++// } + +-mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) +-{ +- mz_uint32 file_index; +- if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) +- return MZ_FALSE; ++// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) ++// { ++// mz_uint32 file_index; ++// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) ++// return MZ_FALSE; + +- return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); +-} ++// return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); ++// } + +-mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) +-{ +- mz_zip_archive_file_stat file_stat; ++// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) ++// { ++// mz_zip_archive_file_stat file_stat; + +- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +- return MZ_FALSE; ++// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) ++// return MZ_FALSE; + +- if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); ++// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + +- return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); +-} ++// return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); ++// } + +-mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) +-{ +- mz_uint32 file_index; +- if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) +- return MZ_FALSE; ++// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) ++// { ++// mz_uint32 file_index; ++// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) ++// return MZ_FALSE; + +- return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); +-} +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); ++// } ++// #endif /* #ifndef MINIZ_NO_STDIO */ + + // static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) + // { +@@ -5444,1202 +5443,1202 @@ mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pA + + /* ------------------- .ZIP archive writing */ + +-#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS ++// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +-static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) +-{ +- p[0] = (mz_uint8)v; +- p[1] = (mz_uint8)(v >> 8); +-} +-static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) +-{ +- p[0] = (mz_uint8)v; +- p[1] = (mz_uint8)(v >> 8); +- p[2] = (mz_uint8)(v >> 16); +- p[3] = (mz_uint8)(v >> 24); +-} +-static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) +-{ +- mz_write_le32(p, (mz_uint32)v); +- mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); +-} ++// static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) ++// { ++// p[0] = (mz_uint8)v; ++// p[1] = (mz_uint8)(v >> 8); ++// } ++// static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) ++// { ++// p[0] = (mz_uint8)v; ++// p[1] = (mz_uint8)(v >> 8); ++// p[2] = (mz_uint8)(v >> 16); ++// p[3] = (mz_uint8)(v >> 24); ++// } ++// static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) ++// { ++// mz_write_le32(p, (mz_uint32)v); ++// mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); ++// } + +-#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) +-#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) +-#define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) ++// #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) ++// #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) ++// #define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) + +-static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +-{ +- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +- mz_zip_internal_state *pState = pZip->m_pState; +- mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); ++// static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) ++// { ++// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; ++// mz_zip_internal_state *pState = pZip->m_pState; ++// mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); + +- if (!n) +- return 0; ++// if (!n) ++// return 0; + +- /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ +- if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) +- { +- mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); +- return 0; +- } ++// /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ ++// if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); ++// return 0; ++// } + +- if (new_size > pState->m_mem_capacity) +- { +- void *pNew_block; +- size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); ++// if (new_size > pState->m_mem_capacity) ++// { ++// void *pNew_block; ++// size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); + +- while (new_capacity < new_size) +- new_capacity *= 2; ++// while (new_capacity < new_size) ++// new_capacity *= 2; + +- if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) +- { +- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- return 0; +- } ++// if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// return 0; ++// } + +- pState->m_pMem = pNew_block; +- pState->m_mem_capacity = new_capacity; +- } +- memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); +- pState->m_mem_size = (size_t)new_size; +- return n; +-} ++// pState->m_pMem = pNew_block; ++// pState->m_mem_capacity = new_capacity; ++// } ++// memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); ++// pState->m_mem_size = (size_t)new_size; ++// return n; ++// } + +-static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +-{ +- mz_zip_internal_state *pState; +- mz_bool status = MZ_TRUE; ++// static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) ++// { ++// mz_zip_internal_state *pState; ++// mz_bool status = MZ_TRUE; + +- if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) +- { +- if (set_last_error) +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- return MZ_FALSE; +- } ++// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) ++// { ++// if (set_last_error) ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return MZ_FALSE; ++// } + +- pState = pZip->m_pState; +- pZip->m_pState = NULL; +- mz_zip_array_clear(pZip, &pState->m_central_dir); +- mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); +- mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); ++// pState = pZip->m_pState; ++// pZip->m_pState = NULL; ++// mz_zip_array_clear(pZip, &pState->m_central_dir); ++// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); ++// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +-#ifndef MINIZ_NO_STDIO +- if (pState->m_pFile) +- { +- if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) +- { +- if (MZ_FCLOSE(pState->m_pFile) == EOF) +- { +- if (set_last_error) +- mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); +- status = MZ_FALSE; +- } +- } ++// #ifndef MINIZ_NO_STDIO ++// if (pState->m_pFile) ++// { ++// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) ++// { ++// if (MZ_FCLOSE(pState->m_pFile) == EOF) ++// { ++// if (set_last_error) ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); ++// status = MZ_FALSE; ++// } ++// } + +- pState->m_pFile = NULL; +- } +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// pState->m_pFile = NULL; ++// } ++// #endif /* #ifndef MINIZ_NO_STDIO */ + +- if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); +- pState->m_pMem = NULL; +- } ++// if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); ++// pState->m_pMem = NULL; ++// } + +- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +- pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; +- return status; +-} ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); ++// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; ++// return status; ++// } + +-mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) +-{ +- mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; ++// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) ++// { ++// mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; + +- if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +- { +- if (!pZip->m_pRead) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- } ++// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ++// { ++// if (!pZip->m_pRead) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// } + +- if (pZip->m_file_offset_alignment) +- { +- /* Ensure user specified file offset alignment is a power of 2. */ +- if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- } ++// if (pZip->m_file_offset_alignment) ++// { ++// /* Ensure user specified file offset alignment is a power of 2. */ ++// if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// } + +- if (!pZip->m_pAlloc) +- pZip->m_pAlloc = miniz_def_alloc_func; +- if (!pZip->m_pFree) +- pZip->m_pFree = miniz_def_free_func; +- if (!pZip->m_pRealloc) +- pZip->m_pRealloc = miniz_def_realloc_func; ++// if (!pZip->m_pAlloc) ++// pZip->m_pAlloc = miniz_def_alloc_func; ++// if (!pZip->m_pFree) ++// pZip->m_pFree = miniz_def_free_func; ++// if (!pZip->m_pRealloc) ++// pZip->m_pRealloc = miniz_def_realloc_func; + +- pZip->m_archive_size = existing_size; +- pZip->m_central_directory_file_ofs = 0; +- pZip->m_total_files = 0; ++// pZip->m_archive_size = existing_size; ++// pZip->m_central_directory_file_ofs = 0; ++// pZip->m_total_files = 0; + +- if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +- memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); ++// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + +- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); +- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); +- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); ++// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); ++// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); ++// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + +- pZip->m_pState->m_zip64 = zip64; +- pZip->m_pState->m_zip64_has_extended_info_fields = zip64; ++// pZip->m_pState->m_zip64 = zip64; ++// pZip->m_pState->m_zip64_has_extended_info_fields = zip64; + +- pZip->m_zip_type = MZ_ZIP_TYPE_USER; +- pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; ++// pZip->m_zip_type = MZ_ZIP_TYPE_USER; ++// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + +- return MZ_TRUE; +-} ++// return MZ_TRUE; ++// } + +-mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) +-{ +- return mz_zip_writer_init_v2(pZip, existing_size, 0); +-} ++// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) ++// { ++// return mz_zip_writer_init_v2(pZip, existing_size, 0); ++// } + +-mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) +-{ +- pZip->m_pWrite = mz_zip_heap_write_func; +- pZip->m_pNeeds_keepalive = NULL; ++// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) ++// { ++// pZip->m_pWrite = mz_zip_heap_write_func; ++// pZip->m_pNeeds_keepalive = NULL; + +- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +- pZip->m_pRead = mz_zip_mem_read_func; ++// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ++// pZip->m_pRead = mz_zip_mem_read_func; + +- pZip->m_pIO_opaque = pZip; ++// pZip->m_pIO_opaque = pZip; + +- if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) +- return MZ_FALSE; ++// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) ++// return MZ_FALSE; + +- pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; ++// pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; + +- if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) +- { +- if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) +- { +- mz_zip_writer_end_internal(pZip, MZ_FALSE); +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- } +- pZip->m_pState->m_mem_capacity = initial_allocation_size; +- } ++// if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) ++// { ++// if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) ++// { ++// mz_zip_writer_end_internal(pZip, MZ_FALSE); ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// } ++// pZip->m_pState->m_mem_capacity = initial_allocation_size; ++// } + +- return MZ_TRUE; +-} ++// return MZ_TRUE; ++// } + +-mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) +-{ +- return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); +-} ++// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) ++// { ++// return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); ++// } + +-#ifndef MINIZ_NO_STDIO +-static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +-{ +- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +- mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); ++// #ifndef MINIZ_NO_STDIO ++// static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) ++// { ++// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; ++// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + +- file_ofs += pZip->m_pState->m_file_archive_start_ofs; ++// file_ofs += pZip->m_pState->m_file_archive_start_ofs; + +- if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) +- { +- mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); +- return 0; +- } ++// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); ++// return 0; ++// } + +- return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); +-} ++// return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); ++// } + +-mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) +-{ +- return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); +-} ++// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) ++// { ++// return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); ++// } + +-mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) +-{ +- MZ_FILE *pFile; ++// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) ++// { ++// MZ_FILE *pFile; + +- pZip->m_pWrite = mz_zip_file_write_func; +- pZip->m_pNeeds_keepalive = NULL; ++// pZip->m_pWrite = mz_zip_file_write_func; ++// pZip->m_pNeeds_keepalive = NULL; + +- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +- pZip->m_pRead = mz_zip_file_read_func; ++// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ++// pZip->m_pRead = mz_zip_file_read_func; + +- pZip->m_pIO_opaque = pZip; ++// pZip->m_pIO_opaque = pZip; ++ ++// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) ++// return MZ_FALSE; ++ ++// if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) ++// { ++// mz_zip_writer_end(pZip); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); ++// } + +- if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) +- return MZ_FALSE; ++// pZip->m_pState->m_pFile = pFile; ++// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; + +- if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) +- { +- mz_zip_writer_end(pZip); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); +- } ++// if (size_to_reserve_at_beginning) ++// { ++// mz_uint64 cur_ofs = 0; ++// char buf[4096]; + +- pZip->m_pState->m_pFile = pFile; +- pZip->m_zip_type = MZ_ZIP_TYPE_FILE; ++// MZ_CLEAR_OBJ(buf); + +- if (size_to_reserve_at_beginning) +- { +- mz_uint64 cur_ofs = 0; +- char buf[4096]; ++// do ++// { ++// size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) ++// { ++// mz_zip_writer_end(pZip); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// } ++// cur_ofs += n; ++// size_to_reserve_at_beginning -= n; ++// } while (size_to_reserve_at_beginning); ++// } + +- MZ_CLEAR_OBJ(buf); ++// return MZ_TRUE; ++// } + +- do +- { +- size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) +- { +- mz_zip_writer_end(pZip); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- } +- cur_ofs += n; +- size_to_reserve_at_beginning -= n; +- } while (size_to_reserve_at_beginning); +- } ++// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) ++// { ++// pZip->m_pWrite = mz_zip_file_write_func; ++// pZip->m_pNeeds_keepalive = NULL; + +- return MZ_TRUE; +-} ++// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ++// pZip->m_pRead = mz_zip_file_read_func; + +-mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) +-{ +- pZip->m_pWrite = mz_zip_file_write_func; +- pZip->m_pNeeds_keepalive = NULL; ++// pZip->m_pIO_opaque = pZip; + +- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +- pZip->m_pRead = mz_zip_file_read_func; ++// if (!mz_zip_writer_init_v2(pZip, 0, flags)) ++// return MZ_FALSE; + +- pZip->m_pIO_opaque = pZip; ++// pZip->m_pState->m_pFile = pFile; ++// pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); ++// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; + +- if (!mz_zip_writer_init_v2(pZip, 0, flags)) +- return MZ_FALSE; ++// return MZ_TRUE; ++// } ++// #endif /* #ifndef MINIZ_NO_STDIO */ + +- pZip->m_pState->m_pFile = pFile; +- pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); +- pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; ++// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) ++// { ++// mz_zip_internal_state *pState; + +- return MZ_TRUE; +-} +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +-mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +-{ +- mz_zip_internal_state *pState; ++// if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) ++// { ++// /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ ++// if (!pZip->m_pState->m_zip64) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// } + +- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// /* No sense in trying to write to an archive that's already at the support max size */ ++// if (pZip->m_pState->m_zip64) ++// { ++// if (pZip->m_total_files == MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// } ++// else ++// { ++// if (pZip->m_total_files == MZ_UINT16_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + +- if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) +- { +- /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ +- if (!pZip->m_pState->m_zip64) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- } ++// if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); ++// } + +- /* No sense in trying to write to an archive that's already at the support max size */ +- if (pZip->m_pState->m_zip64) +- { +- if (pZip->m_total_files == MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +- } +- else +- { +- if (pZip->m_total_files == MZ_UINT16_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// pState = pZip->m_pState; + +- if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); +- } ++// if (pState->m_pFile) ++// { ++// #ifdef MINIZ_NO_STDIO ++// (void)pFilename; ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// #else ++// if (pZip->m_pIO_opaque != pZip) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- pState = pZip->m_pState; ++// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) ++// { ++// if (!pFilename) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if (pState->m_pFile) +- { +-#ifdef MINIZ_NO_STDIO +- (void)pFilename; +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +-#else +- if (pZip->m_pIO_opaque != pZip) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ ++// if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) ++// { ++// /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ ++// mz_zip_reader_end_internal(pZip, MZ_FALSE); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); ++// } ++// } + +- if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) +- { +- if (!pFilename) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// pZip->m_pWrite = mz_zip_file_write_func; ++// pZip->m_pNeeds_keepalive = NULL; ++// #endif /* #ifdef MINIZ_NO_STDIO */ ++// } ++// else if (pState->m_pMem) ++// { ++// /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ ++// if (pZip->m_pIO_opaque != pZip) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ +- if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) +- { +- /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ +- mz_zip_reader_end_internal(pZip, MZ_FALSE); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); +- } +- } ++// pState->m_mem_capacity = pState->m_mem_size; ++// pZip->m_pWrite = mz_zip_heap_write_func; ++// pZip->m_pNeeds_keepalive = NULL; ++// } ++// /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ ++// else if (!pZip->m_pWrite) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- pZip->m_pWrite = mz_zip_file_write_func; +- pZip->m_pNeeds_keepalive = NULL; +-#endif /* #ifdef MINIZ_NO_STDIO */ +- } +- else if (pState->m_pMem) +- { +- /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ +- if (pZip->m_pIO_opaque != pZip) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// /* Start writing new files at the archive's current central directory location. */ ++// /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ ++// pZip->m_archive_size = pZip->m_central_directory_file_ofs; ++// pZip->m_central_directory_file_ofs = 0; + +- pState->m_mem_capacity = pState->m_mem_size; +- pZip->m_pWrite = mz_zip_heap_write_func; +- pZip->m_pNeeds_keepalive = NULL; +- } +- /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ +- else if (!pZip->m_pWrite) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ ++// /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ ++// /* TODO: We could easily maintain the sorted central directory offsets. */ ++// mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); + +- /* Start writing new files at the archive's current central directory location. */ +- /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ +- pZip->m_archive_size = pZip->m_central_directory_file_ofs; +- pZip->m_central_directory_file_ofs = 0; ++// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + +- /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ +- /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ +- /* TODO: We could easily maintain the sorted central directory offsets. */ +- mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); ++// return MZ_TRUE; ++// } + +- pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; ++// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) ++// { ++// return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); ++// } + +- return MZ_TRUE; +-} ++/* TODO: pArchive_name is a terrible name here! */ ++// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) ++// { ++// return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); ++// } + +-mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) +-{ +- return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); +-} ++// typedef struct ++// { ++// mz_zip_archive *m_pZip; ++// mz_uint64 m_cur_archive_file_ofs; ++// mz_uint64 m_comp_size; ++// } mz_zip_writer_add_state; + +-/* TODO: pArchive_name is a terrible name here! */ +-mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) +-{ +- return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); +-} ++// static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) ++// { ++// mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; ++// if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) ++// return MZ_FALSE; + +-typedef struct +-{ +- mz_zip_archive *m_pZip; +- mz_uint64 m_cur_archive_file_ofs; +- mz_uint64 m_comp_size; +-} mz_zip_writer_add_state; ++// pState->m_cur_archive_file_ofs += len; ++// pState->m_comp_size += len; ++// return MZ_TRUE; ++// } + +-static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) +-{ +- mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; +- if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) +- return MZ_FALSE; ++// #define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) ++// #define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) ++// static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) ++// { ++// mz_uint8 *pDst = pBuf; ++// mz_uint32 field_size = 0; + +- pState->m_cur_archive_file_ofs += len; +- pState->m_comp_size += len; +- return MZ_TRUE; +-} ++// MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); ++// MZ_WRITE_LE16(pDst + 2, 0); ++// pDst += sizeof(mz_uint16) * 2; + +-#define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) +-#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) +-static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) +-{ +- mz_uint8 *pDst = pBuf; +- mz_uint32 field_size = 0; ++// if (pUncomp_size) ++// { ++// MZ_WRITE_LE64(pDst, *pUncomp_size); ++// pDst += sizeof(mz_uint64); ++// field_size += sizeof(mz_uint64); ++// } + +- MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); +- MZ_WRITE_LE16(pDst + 2, 0); +- pDst += sizeof(mz_uint16) * 2; ++// if (pComp_size) ++// { ++// MZ_WRITE_LE64(pDst, *pComp_size); ++// pDst += sizeof(mz_uint64); ++// field_size += sizeof(mz_uint64); ++// } + +- if (pUncomp_size) +- { +- MZ_WRITE_LE64(pDst, *pUncomp_size); +- pDst += sizeof(mz_uint64); +- field_size += sizeof(mz_uint64); +- } ++// if (pLocal_header_ofs) ++// { ++// MZ_WRITE_LE64(pDst, *pLocal_header_ofs); ++// pDst += sizeof(mz_uint64); ++// field_size += sizeof(mz_uint64); ++// } + +- if (pComp_size) +- { +- MZ_WRITE_LE64(pDst, *pComp_size); +- pDst += sizeof(mz_uint64); +- field_size += sizeof(mz_uint64); +- } ++// MZ_WRITE_LE16(pBuf + 2, field_size); + +- if (pLocal_header_ofs) +- { +- MZ_WRITE_LE64(pDst, *pLocal_header_ofs); +- pDst += sizeof(mz_uint64); +- field_size += sizeof(mz_uint64); +- } ++// return (mz_uint32)(pDst - pBuf); ++// } + +- MZ_WRITE_LE16(pBuf + 2, field_size); ++// static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) ++// { ++// (void)pZip; ++// memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); ++// return MZ_TRUE; ++// } + +- return (mz_uint32)(pDst - pBuf); +-} ++// static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, ++// mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, ++// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, ++// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, ++// mz_uint64 local_header_ofs, mz_uint32 ext_attributes) ++// { ++// (void)pZip; ++// memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); ++// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); ++// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); ++// return MZ_TRUE; ++// } + +-static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) +-{ +- (void)pZip; +- memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); +- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); +- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); +- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); +- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); +- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); +- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); +- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); +- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); +- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); +- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); +- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); +- return MZ_TRUE; +-} ++// static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, ++// const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, ++// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, ++// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, ++// mz_uint64 local_header_ofs, mz_uint32 ext_attributes, ++// const char *user_extra_data, mz_uint user_extra_data_len) ++// { ++// mz_zip_internal_state *pState = pZip->m_pState; ++// mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; ++// size_t orig_central_dir_size = pState->m_central_dir.m_size; ++// mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + +-static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, +- mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, +- mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, +- mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, +- mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +-{ +- (void)pZip; +- memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); +- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); +- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); +- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); +- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); +- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); +- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); +- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); +- return MZ_TRUE; +-} ++// if (!pZip->m_pState->m_zip64) ++// { ++// if (local_header_ofs > 0xFFFFFFFF) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); ++// } + +-static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, +- const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, +- mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, +- mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, +- mz_uint64 local_header_ofs, mz_uint32 ext_attributes, +- const char *user_extra_data, mz_uint user_extra_data_len) +-{ +- mz_zip_internal_state *pState = pZip->m_pState; +- mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; +- size_t orig_central_dir_size = pState->m_central_dir.m_size; +- mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; ++// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ ++// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +- if (!pZip->m_pState->m_zip64) +- { +- if (local_header_ofs > 0xFFFFFFFF) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); +- } ++// if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size + user_extra_data_len, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +- /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ +- if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); ++// if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || ++// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || ++// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || ++// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || ++// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || ++// (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) ++// { ++// /* Try to resize the central directory array back into its original state. */ ++// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// } + +- if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size + user_extra_data_len, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// return MZ_TRUE; ++// } + +- if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || +- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || +- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || +- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || +- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || +- (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) +- { +- /* Try to resize the central directory array back into its original state. */ +- mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- } ++// static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) ++// { ++// /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ ++// if (*pArchive_name == '/') ++// return MZ_FALSE; + +- return MZ_TRUE; +-} ++// while (*pArchive_name) ++// { ++// if ((*pArchive_name == '\\') || (*pArchive_name == ':')) ++// return MZ_FALSE; + +-static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) +-{ +- /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ +- if (*pArchive_name == '/') +- return MZ_FALSE; ++// pArchive_name++; ++// } + +- while (*pArchive_name) +- { +- if ((*pArchive_name == '\\') || (*pArchive_name == ':')) +- return MZ_FALSE; ++// return MZ_TRUE; ++// } + +- pArchive_name++; +- } ++// static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) ++// { ++// mz_uint32 n; ++// if (!pZip->m_file_offset_alignment) ++// return 0; ++// n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); ++// return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); ++// } + +- return MZ_TRUE; +-} ++// static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) ++// { ++// char buf[4096]; ++// memset(buf, 0, MZ_MIN(sizeof(buf), n)); ++// while (n) ++// { ++// mz_uint32 s = MZ_MIN(sizeof(buf), n); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +-static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) +-{ +- mz_uint32 n; +- if (!pZip->m_file_offset_alignment) +- return 0; +- n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); +- return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); +-} ++// cur_file_ofs += s; ++// n -= s; ++// } ++// return MZ_TRUE; ++// } + +-static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) +-{ +- char buf[4096]; +- memset(buf, 0, MZ_MIN(sizeof(buf), n)); +- while (n) +- { +- mz_uint32 s = MZ_MIN(sizeof(buf), n); +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, ++// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) ++// { ++// return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); ++// } + +- cur_file_ofs += s; +- n -= s; +- } +- return MZ_TRUE; +-} ++// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, ++// mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, ++// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) ++// { ++// if(!pZip) ++// { ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// } + +-mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +- mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) +-{ +- return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); +-} ++// mz_uint16 method = 0, dos_time = 0, dos_date = 0; ++// mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; ++// mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; ++// size_t archive_name_size; ++// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; ++// tdefl_compressor *pComp = NULL; ++// mz_bool store_data_uncompressed; ++// mz_zip_internal_state *pState; ++// mz_uint8 *pExtra_data = NULL; ++// mz_uint32 extra_size = 0; ++// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; ++// mz_uint16 bit_flags = 0; + +-mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, +- mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, +- const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +-{ +- if(!pZip) +- { +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- } ++// if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) ++// bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; + +- mz_uint16 method = 0, dos_time = 0, dos_date = 0; +- mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; +- mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; +- size_t archive_name_size; +- mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; +- tdefl_compressor *pComp = NULL; +- mz_bool store_data_uncompressed; +- mz_zip_internal_state *pState; +- mz_uint8 *pExtra_data = NULL; +- mz_uint32 extra_size = 0; +- mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; +- mz_uint16 bit_flags = 0; ++// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) ++// bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + +- if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) +- bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; ++// if ((int)level_and_flags < 0) ++// level_and_flags = MZ_DEFAULT_LEVEL; ++// level = level_and_flags & 0xF; ++// store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + +- if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) +- bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; ++// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if ((int)level_and_flags < 0) +- level_and_flags = MZ_DEFAULT_LEVEL; +- level = level_and_flags & 0xF; +- store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); ++// pState = pZip->m_pState; + +- if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if (pState->m_zip64) ++// { ++// if (pZip->m_total_files == MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// } ++// else ++// { ++// if (pZip->m_total_files == MZ_UINT16_MAX) ++// { ++// pState->m_zip64 = MZ_TRUE; ++// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ ++// } ++// if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) ++// { ++// pState->m_zip64 = MZ_TRUE; ++// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ ++// } ++// } + +- pState = pZip->m_pState; ++// if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if (pState->m_zip64) +- { +- if (pZip->m_total_files == MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +- } +- else +- { +- if (pZip->m_total_files == MZ_UINT16_MAX) +- { +- pState->m_zip64 = MZ_TRUE; +- /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ +- } +- if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) +- { +- pState->m_zip64 = MZ_TRUE; +- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +- } +- } ++// if (!mz_zip_writer_validate_archive_name(pArchive_name)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +- if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// #ifndef MINIZ_NO_TIME ++// if (last_modified != NULL) ++// { ++// mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); ++// } ++// else ++// { ++// MZ_TIME_T cur_time; ++// time(&cur_time); ++// mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); ++// } ++// #endif /* #ifndef MINIZ_NO_TIME */ + +- if (!mz_zip_writer_validate_archive_name(pArchive_name)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); ++// archive_name_size = strlen(pArchive_name); ++// if (archive_name_size > MZ_UINT16_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +-#ifndef MINIZ_NO_TIME +- if (last_modified != NULL) +- { +- mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); +- } +- else +- { +- MZ_TIME_T cur_time; +- time(&cur_time); +- mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); +- } +-#endif /* #ifndef MINIZ_NO_TIME */ ++// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + +- archive_name_size = strlen(pArchive_name); +- if (archive_name_size > MZ_UINT16_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); ++// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ ++// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +- num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); ++// if (!pState->m_zip64) ++// { ++// /* Bail early if the archive would obviously become too large */ ++// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size ++// + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + ++// pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len ++// + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) ++// { ++// pState->m_zip64 = MZ_TRUE; ++// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ ++// } ++// } + +- /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ +- if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); ++// if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) ++// { ++// /* Set DOS Subdirectory attribute bit. */ ++// ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; + +- if (!pState->m_zip64) +- { +- /* Bail early if the archive would obviously become too large */ +- if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size +- + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + +- pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len +- + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) +- { +- pState->m_zip64 = MZ_TRUE; +- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +- } +- } ++// /* Subdirectories cannot contain data. */ ++// if ((buf_size) || (uncomp_size)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// } + +- if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) +- { +- /* Set DOS Subdirectory attribute bit. */ +- ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; ++// /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ ++// if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +- /* Subdirectories cannot contain data. */ +- if ((buf_size) || (uncomp_size)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- } ++// if ((!store_data_uncompressed) && (buf_size)) ++// { ++// if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// } + +- /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ +- if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// return MZ_FALSE; ++// } + +- if ((!store_data_uncompressed) && (buf_size)) +- { +- if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- } ++// local_dir_header_ofs += num_alignment_padding_bytes; ++// if (pZip->m_file_offset_alignment) ++// { ++// MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); ++// } ++// cur_archive_file_ofs += num_alignment_padding_bytes; + +- if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +- return MZ_FALSE; +- } ++// MZ_CLEAR_OBJ(local_dir_header); + +- local_dir_header_ofs += num_alignment_padding_bytes; +- if (pZip->m_file_offset_alignment) +- { +- MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); +- } +- cur_archive_file_ofs += num_alignment_padding_bytes; ++// if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) ++// { ++// method = MZ_DEFLATED; ++// } + +- MZ_CLEAR_OBJ(local_dir_header); ++// if (pState->m_zip64) ++// { ++// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) ++// { ++// pExtra_data = extra_data; ++// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, ++// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); ++// } + +- if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +- { +- method = MZ_DEFLATED; +- } ++// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +- if (pState->m_zip64) +- { +- if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) +- { +- pExtra_data = extra_data; +- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +- } ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// cur_archive_file_ofs += sizeof(local_dir_header); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// } ++// cur_archive_file_ofs += archive_name_size; + +- cur_archive_file_ofs += sizeof(local_dir_header); ++// if (pExtra_data != NULL) ++// { ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- } +- cur_archive_file_ofs += archive_name_size; ++// cur_archive_file_ofs += extra_size; ++// } ++// } ++// else ++// { ++// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) ++// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); ++// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +- if (pExtra_data != NULL) +- { +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- cur_archive_file_ofs += extra_size; +- } +- } +- else +- { +- if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) +- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); +- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// cur_archive_file_ofs += sizeof(local_dir_header); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// } ++// cur_archive_file_ofs += archive_name_size; ++// } + +- cur_archive_file_ofs += sizeof(local_dir_header); ++// if (user_extra_data_len > 0) ++// { ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- } +- cur_archive_file_ofs += archive_name_size; +- } ++// cur_archive_file_ofs += user_extra_data_len; ++// } + +- if (user_extra_data_len > 0) +- { +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) ++// { ++// uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); ++// uncomp_size = buf_size; ++// if (uncomp_size <= 3) ++// { ++// level = 0; ++// store_data_uncompressed = MZ_TRUE; ++// } ++// } + +- cur_archive_file_ofs += user_extra_data_len; +- } ++// if (store_data_uncompressed) ++// { ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// } + +- if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +- { +- uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); +- uncomp_size = buf_size; +- if (uncomp_size <= 3) +- { +- level = 0; +- store_data_uncompressed = MZ_TRUE; +- } +- } ++// cur_archive_file_ofs += buf_size; ++// comp_size = buf_size; ++// } ++// else if (buf_size) ++// { ++// mz_zip_writer_add_state state; + +- if (store_data_uncompressed) +- { +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- } ++// state.m_pZip = pZip; ++// state.m_cur_archive_file_ofs = cur_archive_file_ofs; ++// state.m_comp_size = 0; + +- cur_archive_file_ofs += buf_size; +- comp_size = buf_size; +- } +- else if (buf_size) +- { +- mz_zip_writer_add_state state; ++// if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || ++// (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); ++// } + +- state.m_pZip = pZip; +- state.m_cur_archive_file_ofs = cur_archive_file_ofs; +- state.m_comp_size = 0; ++// comp_size = state.m_comp_size; ++// cur_archive_file_ofs = state.m_cur_archive_file_ofs; ++// } + +- if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || +- (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +- return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); +- } ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// pComp = NULL; + +- comp_size = state.m_comp_size; +- cur_archive_file_ofs = state.m_cur_archive_file_ofs; +- } ++// if (uncomp_size) ++// { ++// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; ++// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +- pComp = NULL; ++// MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); + +- if (uncomp_size) +- { +- mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; +- mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; ++// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); ++// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); ++// if (pExtra_data == NULL) ++// { ++// if (comp_size > MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +- MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); ++// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); ++// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); ++// } ++// else ++// { ++// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); ++// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); ++// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; ++// } + +- MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); +- MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); +- if (pExtra_data == NULL) +- { +- if (comp_size > MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) ++// return MZ_FALSE; + +- MZ_WRITE_LE32(local_dir_footer + 8, comp_size); +- MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); +- } +- else +- { +- MZ_WRITE_LE64(local_dir_footer + 8, comp_size); +- MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); +- local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; +- } ++// cur_archive_file_ofs += local_dir_footer_size; ++// } + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) +- return MZ_FALSE; ++// if (pExtra_data != NULL) ++// { ++// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, ++// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); ++// } + +- cur_archive_file_ofs += local_dir_footer_size; +- } ++// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, ++// comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, ++// user_extra_data_central, user_extra_data_central_len)) ++// return MZ_FALSE; + +- if (pExtra_data != NULL) +- { +- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +- } ++// pZip->m_total_files++; ++// pZip->m_archive_size = cur_archive_file_ofs; + +- if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, +- comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, +- user_extra_data_central, user_extra_data_central_len)) +- return MZ_FALSE; ++// return MZ_TRUE; ++// } + +- pZip->m_total_files++; +- pZip->m_archive_size = cur_archive_file_ofs; ++// #ifndef MINIZ_NO_STDIO ++// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, ++// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) ++// { ++// if(!pZip) ++// { ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// } + +- return MZ_TRUE; +-} ++// mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; ++// mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; ++// mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; ++// mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; ++// size_t archive_name_size; ++// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; ++// mz_uint8 *pExtra_data = NULL; ++// mz_uint32 extra_size = 0; ++// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; ++// mz_zip_internal_state *pState; + +-#ifndef MINIZ_NO_STDIO +-mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +- const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +-{ +- if(!pZip) +- { +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- } ++// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) ++// gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + +- mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; +- mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; +- mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; +- mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; +- size_t archive_name_size; +- mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; +- mz_uint8 *pExtra_data = NULL; +- mz_uint32 extra_size = 0; +- mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; +- mz_zip_internal_state *pState; ++// if ((int)level_and_flags < 0) ++// level_and_flags = MZ_DEFAULT_LEVEL; ++// level = level_and_flags & 0xF; + +- if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) +- gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; ++// /* Sanity checks */ ++// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if ((int)level_and_flags < 0) +- level_and_flags = MZ_DEFAULT_LEVEL; +- level = level_and_flags & 0xF; ++// pState = pZip->m_pState; + +- /* Sanity checks */ +- if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) ++// { ++// /* Source file is too large for non-zip64 */ ++// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ ++// pState->m_zip64 = MZ_TRUE; ++// } + +- pState = pZip->m_pState; ++// /* We could support this, but why? */ ++// if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) +- { +- /* Source file is too large for non-zip64 */ +- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +- pState->m_zip64 = MZ_TRUE; +- } ++// if (!mz_zip_writer_validate_archive_name(pArchive_name)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +- /* We could support this, but why? */ +- if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if (pState->m_zip64) ++// { ++// if (pZip->m_total_files == MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// } ++// else ++// { ++// if (pZip->m_total_files == MZ_UINT16_MAX) ++// { ++// pState->m_zip64 = MZ_TRUE; ++// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ ++// } ++// } + +- if (!mz_zip_writer_validate_archive_name(pArchive_name)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); ++// archive_name_size = strlen(pArchive_name); ++// if (archive_name_size > MZ_UINT16_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +- if (pState->m_zip64) +- { +- if (pZip->m_total_files == MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +- } +- else +- { +- if (pZip->m_total_files == MZ_UINT16_MAX) +- { +- pState->m_zip64 = MZ_TRUE; +- /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ +- } +- } ++// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + +- archive_name_size = strlen(pArchive_name); +- if (archive_name_size > MZ_UINT16_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); ++// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ ++// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +- num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); ++// if (!pState->m_zip64) ++// { ++// /* Bail early if the archive would obviously become too large */ ++// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE ++// + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 ++// + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) ++// { ++// pState->m_zip64 = MZ_TRUE; ++// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ ++// } ++// } + +- /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ +- if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); ++// #ifndef MINIZ_NO_TIME ++// if (pFile_time) ++// { ++// mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); ++// } ++// #endif + +- if (!pState->m_zip64) +- { +- /* Bail early if the archive would obviously become too large */ +- if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +- + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 +- + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) +- { +- pState->m_zip64 = MZ_TRUE; +- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +- } +- } ++// if (uncomp_size <= 3) ++// level = 0; + +-#ifndef MINIZ_NO_TIME +- if (pFile_time) +- { +- mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); +- } +-#endif ++// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) ++// { ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// } + +- if (uncomp_size <= 3) +- level = 0; ++// cur_archive_file_ofs += num_alignment_padding_bytes; ++// local_dir_header_ofs = cur_archive_file_ofs; + +- if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) +- { +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- } ++// if (pZip->m_file_offset_alignment) ++// { ++// MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); ++// } + +- cur_archive_file_ofs += num_alignment_padding_bytes; +- local_dir_header_ofs = cur_archive_file_ofs; ++// if (uncomp_size && level) ++// { ++// method = MZ_DEFLATED; ++// } + +- if (pZip->m_file_offset_alignment) +- { +- MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); +- } ++// MZ_CLEAR_OBJ(local_dir_header); ++// if (pState->m_zip64) ++// { ++// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) ++// { ++// pExtra_data = extra_data; ++// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, ++// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); ++// } + +- if (uncomp_size && level) +- { +- method = MZ_DEFLATED; +- } ++// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +- MZ_CLEAR_OBJ(local_dir_header); +- if (pState->m_zip64) +- { +- if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) +- { +- pExtra_data = extra_data; +- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +- } ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// cur_archive_file_ofs += sizeof(local_dir_header); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) ++// { ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// } + +- cur_archive_file_ofs += sizeof(local_dir_header); ++// cur_archive_file_ofs += archive_name_size; + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +- { +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- } ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- cur_archive_file_ofs += archive_name_size; ++// cur_archive_file_ofs += extra_size; ++// } ++// else ++// { ++// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) ++// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); ++// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- cur_archive_file_ofs += extra_size; +- } +- else +- { +- if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) +- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); +- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// cur_archive_file_ofs += sizeof(local_dir_header); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) ++// { ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// } + +- cur_archive_file_ofs += sizeof(local_dir_header); ++// cur_archive_file_ofs += archive_name_size; ++// } + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +- { +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- } ++// if (user_extra_data_len > 0) ++// { ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- cur_archive_file_ofs += archive_name_size; +- } ++// cur_archive_file_ofs += user_extra_data_len; ++// } + +- if (user_extra_data_len > 0) +- { +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// if (uncomp_size) ++// { ++// mz_uint64 uncomp_remaining = uncomp_size; ++// void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); ++// if (!pRead_buf) ++// { ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// } + +- cur_archive_file_ofs += user_extra_data_len; +- } ++// if (!level) ++// { ++// while (uncomp_remaining) ++// { ++// mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); ++// if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// } ++// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); ++// uncomp_remaining -= n; ++// cur_archive_file_ofs += n; ++// } ++// comp_size = uncomp_size; ++// } ++// else ++// { ++// mz_bool result = MZ_FALSE; ++// mz_zip_writer_add_state state; ++// tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); ++// if (!pComp) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); ++// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); ++// } + +- if (uncomp_size) +- { +- mz_uint64 uncomp_remaining = uncomp_size; +- void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); +- if (!pRead_buf) +- { +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- } ++// state.m_pZip = pZip; ++// state.m_cur_archive_file_ofs = cur_archive_file_ofs; ++// state.m_comp_size = 0; + +- if (!level) +- { +- while (uncomp_remaining) +- { +- mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); +- if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +- } +- uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); +- uncomp_remaining -= n; +- cur_archive_file_ofs += n; +- } +- comp_size = uncomp_size; +- } +- else +- { +- mz_bool result = MZ_FALSE; +- mz_zip_writer_add_state state; +- tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); +- if (!pComp) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +- } ++// if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); ++// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); ++// } + +- state.m_pZip = pZip; +- state.m_cur_archive_file_ofs = cur_archive_file_ofs; +- state.m_comp_size = 0; ++// for (;;) ++// { ++// size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); ++// tdefl_status status; ++// tdefl_flush flush = TDEFL_NO_FLUSH; + +- if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); +- } ++// if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); ++// break; ++// } + +- for (;;) +- { +- size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); +- tdefl_status status; +- tdefl_flush flush = TDEFL_NO_FLUSH; ++// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); ++// uncomp_remaining -= in_buf_size; + +- if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) +- { +- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +- break; +- } ++// if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) ++// flush = TDEFL_FULL_FLUSH; + +- uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); +- uncomp_remaining -= in_buf_size; ++// status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); ++// if (status == TDEFL_STATUS_DONE) ++// { ++// result = MZ_TRUE; ++// break; ++// } ++// else if (status != TDEFL_STATUS_OKAY) ++// { ++// mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); ++// break; ++// } ++// } + +- if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) +- flush = TDEFL_FULL_FLUSH; ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + +- status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); +- if (status == TDEFL_STATUS_DONE) +- { +- result = MZ_TRUE; +- break; +- } +- else if (status != TDEFL_STATUS_OKAY) +- { +- mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); +- break; +- } +- } ++// if (!result) ++// { ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); ++// return MZ_FALSE; ++// } + +- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); ++// comp_size = state.m_comp_size; ++// cur_archive_file_ofs = state.m_cur_archive_file_ofs; ++// } + +- if (!result) +- { +- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +- return MZ_FALSE; +- } ++// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); ++// } + +- comp_size = state.m_comp_size; +- cur_archive_file_ofs = state.m_cur_archive_file_ofs; +- } ++// { ++// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; ++// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + +- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +- } ++// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); ++// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); ++// if (pExtra_data == NULL) ++// { ++// if (comp_size > MZ_UINT32_MAX) ++// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +- { +- mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; +- mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; ++// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); ++// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); ++// } ++// else ++// { ++// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); ++// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); ++// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; ++// } + +- MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); +- MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); +- if (pExtra_data == NULL) +- { +- if (comp_size > MZ_UINT32_MAX) +- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) ++// return MZ_FALSE; + +- MZ_WRITE_LE32(local_dir_footer + 8, comp_size); +- MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); +- } +- else +- { +- MZ_WRITE_LE64(local_dir_footer + 8, comp_size); +- MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); +- local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; +- } ++// cur_archive_file_ofs += local_dir_footer_size; ++// } + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) +- return MZ_FALSE; ++// if (pExtra_data != NULL) ++// { ++// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, ++// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); ++// } + +- cur_archive_file_ofs += local_dir_footer_size; +- } ++// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, ++// uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, ++// user_extra_data_central, user_extra_data_central_len)) ++// return MZ_FALSE; + +- if (pExtra_data != NULL) +- { +- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +- } ++// pZip->m_total_files++; ++// pZip->m_archive_size = cur_archive_file_ofs; + +- if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, +- uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, +- user_extra_data_central, user_extra_data_central_len)) +- return MZ_FALSE; ++// return MZ_TRUE; ++// } + +- pZip->m_total_files++; +- pZip->m_archive_size = cur_archive_file_ofs; ++// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) ++// { ++// MZ_FILE *pSrc_file = NULL; ++// mz_uint64 uncomp_size = 0; ++// MZ_TIME_T file_modified_time; ++// MZ_TIME_T *pFile_time = NULL; ++// mz_bool status; + +- return MZ_TRUE; +-} ++// memset(&file_modified_time, 0, sizeof(file_modified_time)); + +-mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +-{ +- MZ_FILE *pSrc_file = NULL; +- mz_uint64 uncomp_size = 0; +- MZ_TIME_T file_modified_time; +- MZ_TIME_T *pFile_time = NULL; +- mz_bool status; +- +- memset(&file_modified_time, 0, sizeof(file_modified_time)); +- +-#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) +- pFile_time = &file_modified_time; +- if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); +-#endif ++// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) ++// pFile_time = &file_modified_time; ++// if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); ++// #endif + +- pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); +- if (!pSrc_file) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); ++// pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); ++// if (!pSrc_file) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +- MZ_FSEEK64(pSrc_file, 0, SEEK_END); +- uncomp_size = MZ_FTELL64(pSrc_file); +- MZ_FSEEK64(pSrc_file, 0, SEEK_SET); ++// MZ_FSEEK64(pSrc_file, 0, SEEK_END); ++// uncomp_size = MZ_FTELL64(pSrc_file); ++// MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + +- status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); ++// status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); + +- MZ_FCLOSE(pSrc_file); ++// MZ_FCLOSE(pSrc_file); + +- return status; +-} +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// return status; ++// } ++// #endif /* #ifndef MINIZ_NO_STDIO */ + + // static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) + // { +@@ -7083,491 +7082,491 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, + // return MZ_TRUE; + // } + +-mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) +-{ +- mz_zip_internal_state *pState; +- mz_uint64 central_dir_ofs, central_dir_size; +- mz_uint8 hdr[256]; ++// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) ++// { ++// mz_zip_internal_state *pState; ++// mz_uint64 central_dir_ofs, central_dir_size; ++// mz_uint8 hdr[256]; + +- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- pState = pZip->m_pState; ++// pState = pZip->m_pState; + +- if (pState->m_zip64) +- { +- if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +- } +- else +- { +- if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) +- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +- } ++// if (pState->m_zip64) ++// { ++// if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// } ++// else ++// { ++// if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) ++// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); ++// } + +- central_dir_ofs = 0; +- central_dir_size = 0; +- if (pZip->m_total_files) +- { +- /* Write central directory */ +- central_dir_ofs = pZip->m_archive_size; +- central_dir_size = pState->m_central_dir.m_size; +- pZip->m_central_directory_file_ofs = central_dir_ofs; +- if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- +- pZip->m_archive_size += central_dir_size; +- } ++// central_dir_ofs = 0; ++// central_dir_size = 0; ++// if (pZip->m_total_files) ++// { ++// /* Write central directory */ ++// central_dir_ofs = pZip->m_archive_size; ++// central_dir_size = pState->m_central_dir.m_size; ++// pZip->m_central_directory_file_ofs = central_dir_ofs; ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- if (pState->m_zip64) +- { +- /* Write zip64 end of central directory header */ +- mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; +- +- MZ_CLEAR_OBJ(hdr); +- MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); +- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); +- MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ +- MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); +- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); +- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); +- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); +- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); +- if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- +- pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; +- +- /* Write zip64 end of central directory locator */ +- MZ_CLEAR_OBJ(hdr); +- MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); +- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); +- MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); +- if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +- +- pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; +- } ++// pZip->m_archive_size += central_dir_size; ++// } + +- /* Write end of central directory record */ +- MZ_CLEAR_OBJ(hdr); +- MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); +- MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); +- MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); +- MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); +- MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); ++// if (pState->m_zip64) ++// { ++// /* Write zip64 end of central directory header */ ++// mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; ++ ++// MZ_CLEAR_OBJ(hdr); ++// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); ++// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); ++// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ ++// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); ++// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); ++// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); ++// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); ++// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); ++// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; + +-#ifndef MINIZ_NO_STDIO +- if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) +- return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// /* Write zip64 end of central directory locator */ ++// MZ_CLEAR_OBJ(hdr); ++// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); ++// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); ++// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; ++// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; ++// } + +- pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; +- return MZ_TRUE; +-} ++// /* Write end of central directory record */ ++// MZ_CLEAR_OBJ(hdr); ++// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); ++// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); ++// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); ++// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); ++// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); + +-mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) +-{ +- if ((!ppBuf) || (!pSize)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +- *ppBuf = NULL; +- *pSize = 0; ++// #ifndef MINIZ_NO_STDIO ++// if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) ++// return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); ++// #endif /* #ifndef MINIZ_NO_STDIO */ + +- if ((!pZip) || (!pZip->m_pState)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; + +- if (pZip->m_pWrite != mz_zip_heap_write_func) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; ++// return MZ_TRUE; ++// } + +- if (!mz_zip_writer_finalize_archive(pZip)) +- return MZ_FALSE; ++// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) ++// { ++// if ((!ppBuf) || (!pSize)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- *ppBuf = pZip->m_pState->m_pMem; +- *pSize = pZip->m_pState->m_mem_size; +- pZip->m_pState->m_pMem = NULL; +- pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; ++// *ppBuf = NULL; ++// *pSize = 0; + +- return MZ_TRUE; +-} ++// if ((!pZip) || (!pZip->m_pState)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +-mz_bool mz_zip_writer_end(mz_zip_archive *pZip) +-{ +- return mz_zip_writer_end_internal(pZip, MZ_TRUE); +-} ++// if (pZip->m_pWrite != mz_zip_heap_write_func) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +-#ifndef MINIZ_NO_STDIO +-mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +-{ +- return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); +-} ++// if (!mz_zip_writer_finalize_archive(pZip)) ++// return MZ_FALSE; + +-mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) +-{ +- mz_bool status, created_new_archive = MZ_FALSE; +- mz_zip_archive zip_archive; +- struct MZ_FILE_STAT_STRUCT file_stat; +- mz_zip_error actual_err = MZ_ZIP_NO_ERROR; ++// *ppBuf = pZip->m_pState->m_pMem; ++// *pSize = pZip->m_pState->m_mem_size; ++// pZip->m_pState->m_pMem = NULL; ++// pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + +- mz_zip_zero_struct(&zip_archive); +- if ((int)level_and_flags < 0) +- level_and_flags = MZ_DEFAULT_LEVEL; ++// return MZ_TRUE; ++// } + +- if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) +- { +- if (pErr) +- *pErr = MZ_ZIP_INVALID_PARAMETER; +- return MZ_FALSE; +- } ++// mz_bool mz_zip_writer_end(mz_zip_archive *pZip) ++// { ++// return mz_zip_writer_end_internal(pZip, MZ_TRUE); ++// } + +- if (!mz_zip_writer_validate_archive_name(pArchive_name)) +- { +- if (pErr) +- *pErr = MZ_ZIP_INVALID_FILENAME; +- return MZ_FALSE; +- } ++// #ifndef MINIZ_NO_STDIO ++// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) ++// { ++// return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); ++// } + +- /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ +- /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ +- if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) +- { +- /* Create a new archive. */ +- if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) +- { +- if (pErr) +- *pErr = zip_archive.m_last_error; +- return MZ_FALSE; +- } ++// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) ++// { ++// mz_bool status, created_new_archive = MZ_FALSE; ++// mz_zip_archive zip_archive; ++// struct MZ_FILE_STAT_STRUCT file_stat; ++// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + +- created_new_archive = MZ_TRUE; +- } +- else +- { +- /* Append to an existing archive. */ +- if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) +- { +- if (pErr) +- *pErr = zip_archive.m_last_error; +- return MZ_FALSE; +- } ++// mz_zip_zero_struct(&zip_archive); ++// if ((int)level_and_flags < 0) ++// level_and_flags = MZ_DEFAULT_LEVEL; + +- if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) +- { +- if (pErr) +- *pErr = zip_archive.m_last_error; ++// if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) ++// { ++// if (pErr) ++// *pErr = MZ_ZIP_INVALID_PARAMETER; ++// return MZ_FALSE; ++// } + +- mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); ++// if (!mz_zip_writer_validate_archive_name(pArchive_name)) ++// { ++// if (pErr) ++// *pErr = MZ_ZIP_INVALID_FILENAME; ++// return MZ_FALSE; ++// } + +- return MZ_FALSE; +- } +- } ++// /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ ++// /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ ++// if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) ++// { ++// /* Create a new archive. */ ++// if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) ++// { ++// if (pErr) ++// *pErr = zip_archive.m_last_error; ++// return MZ_FALSE; ++// } + +- status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); +- actual_err = zip_archive.m_last_error; ++// created_new_archive = MZ_TRUE; ++// } ++// else ++// { ++// /* Append to an existing archive. */ ++// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) ++// { ++// if (pErr) ++// *pErr = zip_archive.m_last_error; ++// return MZ_FALSE; ++// } + +- /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ +- if (!mz_zip_writer_finalize_archive(&zip_archive)) +- { +- if (!actual_err) +- actual_err = zip_archive.m_last_error; ++// if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) ++// { ++// if (pErr) ++// *pErr = zip_archive.m_last_error; + +- status = MZ_FALSE; +- } ++// mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); + +- if (!mz_zip_writer_end_internal(&zip_archive, status)) +- { +- if (!actual_err) +- actual_err = zip_archive.m_last_error; ++// return MZ_FALSE; ++// } ++// } + +- status = MZ_FALSE; +- } ++// status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); ++// actual_err = zip_archive.m_last_error; + +- if ((!status) && (created_new_archive)) +- { +- /* It's a new archive and something went wrong, so just delete it. */ +- int ignoredStatus = MZ_DELETE_FILE(pZip_filename); +- (void)ignoredStatus; +- } ++// /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ ++// if (!mz_zip_writer_finalize_archive(&zip_archive)) ++// { ++// if (!actual_err) ++// actual_err = zip_archive.m_last_error; + +- if (pErr) +- *pErr = actual_err; ++// status = MZ_FALSE; ++// } + +- return status; +-} ++// if (!mz_zip_writer_end_internal(&zip_archive, status)) ++// { ++// if (!actual_err) ++// actual_err = zip_archive.m_last_error; + +-void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) +-{ +- mz_uint32 file_index; +- mz_zip_archive zip_archive; +- void *p = NULL; ++// status = MZ_FALSE; ++// } + +- if (pSize) +- *pSize = 0; ++// if ((!status) && (created_new_archive)) ++// { ++// /* It's a new archive and something went wrong, so just delete it. */ ++// int ignoredStatus = MZ_DELETE_FILE(pZip_filename); ++// (void)ignoredStatus; ++// } + +- if ((!pZip_filename) || (!pArchive_name)) +- { +- if (pErr) +- *pErr = MZ_ZIP_INVALID_PARAMETER; ++// if (pErr) ++// *pErr = actual_err; + +- return NULL; +- } ++// return status; ++// } + +- mz_zip_zero_struct(&zip_archive); +- if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) +- { +- if (pErr) +- *pErr = zip_archive.m_last_error; ++// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) ++// { ++// mz_uint32 file_index; ++// mz_zip_archive zip_archive; ++// void *p = NULL; + +- return NULL; +- } ++// if (pSize) ++// *pSize = 0; + +- if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) +- { +- p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); +- } ++// if ((!pZip_filename) || (!pArchive_name)) ++// { ++// if (pErr) ++// *pErr = MZ_ZIP_INVALID_PARAMETER; + +- mz_zip_reader_end_internal(&zip_archive, p != NULL); ++// return NULL; ++// } + +- if (pErr) +- *pErr = zip_archive.m_last_error; ++// mz_zip_zero_struct(&zip_archive); ++// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) ++// { ++// if (pErr) ++// *pErr = zip_archive.m_last_error; + +- return p; +-} ++// return NULL; ++// } + +-void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) +-{ +- return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); +-} ++// if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) ++// { ++// p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); ++// } ++ ++// mz_zip_reader_end_internal(&zip_archive, p != NULL); ++ ++// if (pErr) ++// *pErr = zip_archive.m_last_error; ++ ++// return p; ++// } ++ ++// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) ++// { ++// return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); ++// } + +-#endif /* #ifndef MINIZ_NO_STDIO */ ++// #endif /* #ifndef MINIZ_NO_STDIO */ + +-#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ ++// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + + /* ------------------- Misc utils */ + +-mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) +-{ +- return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; +-} ++// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) ++// { ++// return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; ++// } + +-mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) +-{ +- return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; +-} ++// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) ++// { ++// return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; ++// } + +-mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) +-{ +- mz_zip_error prev_err; ++// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) ++// { ++// mz_zip_error prev_err; + +- if (!pZip) +- return MZ_ZIP_INVALID_PARAMETER; ++// if (!pZip) ++// return MZ_ZIP_INVALID_PARAMETER; + +- prev_err = pZip->m_last_error; ++// prev_err = pZip->m_last_error; + +- pZip->m_last_error = err_num; +- return prev_err; +-} ++// pZip->m_last_error = err_num; ++// return prev_err; ++// } + +-mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) +-{ +- if (!pZip) +- return MZ_ZIP_INVALID_PARAMETER; ++// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) ++// { ++// if (!pZip) ++// return MZ_ZIP_INVALID_PARAMETER; + +- return pZip->m_last_error; +-} ++// return pZip->m_last_error; ++// } + +-mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) +-{ +- return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); +-} ++// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) ++// { ++// return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); ++// } + +-mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) +-{ +- mz_zip_error prev_err; ++// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) ++// { ++// mz_zip_error prev_err; + +- if (!pZip) +- return MZ_ZIP_INVALID_PARAMETER; ++// if (!pZip) ++// return MZ_ZIP_INVALID_PARAMETER; + +- prev_err = pZip->m_last_error; ++// prev_err = pZip->m_last_error; + +- pZip->m_last_error = MZ_ZIP_NO_ERROR; +- return prev_err; +-} ++// pZip->m_last_error = MZ_ZIP_NO_ERROR; ++// return prev_err; ++// } + +-const char *mz_zip_get_error_string(mz_zip_error mz_err) +-{ +- switch (mz_err) +- { +- case MZ_ZIP_NO_ERROR: +- return "no error"; +- case MZ_ZIP_UNDEFINED_ERROR: +- return "undefined error"; +- case MZ_ZIP_TOO_MANY_FILES: +- return "too many files"; +- case MZ_ZIP_FILE_TOO_LARGE: +- return "file too large"; +- case MZ_ZIP_UNSUPPORTED_METHOD: +- return "unsupported method"; +- case MZ_ZIP_UNSUPPORTED_ENCRYPTION: +- return "unsupported encryption"; +- case MZ_ZIP_UNSUPPORTED_FEATURE: +- return "unsupported feature"; +- case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: +- return "failed finding central directory"; +- case MZ_ZIP_NOT_AN_ARCHIVE: +- return "not a ZIP archive"; +- case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: +- return "invalid header or archive is corrupted"; +- case MZ_ZIP_UNSUPPORTED_MULTIDISK: +- return "unsupported multidisk archive"; +- case MZ_ZIP_DECOMPRESSION_FAILED: +- return "decompression failed or archive is corrupted"; +- case MZ_ZIP_COMPRESSION_FAILED: +- return "compression failed"; +- case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: +- return "unexpected decompressed size"; +- case MZ_ZIP_CRC_CHECK_FAILED: +- return "CRC-32 check failed"; +- case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: +- return "unsupported central directory size"; +- case MZ_ZIP_ALLOC_FAILED: +- return "allocation failed"; +- case MZ_ZIP_FILE_OPEN_FAILED: +- return "file open failed"; +- case MZ_ZIP_FILE_CREATE_FAILED: +- return "file create failed"; +- case MZ_ZIP_FILE_WRITE_FAILED: +- return "file write failed"; +- case MZ_ZIP_FILE_READ_FAILED: +- return "file read failed"; +- case MZ_ZIP_FILE_CLOSE_FAILED: +- return "file close failed"; +- case MZ_ZIP_FILE_SEEK_FAILED: +- return "file seek failed"; +- case MZ_ZIP_FILE_STAT_FAILED: +- return "file stat failed"; +- case MZ_ZIP_INVALID_PARAMETER: +- return "invalid parameter"; +- case MZ_ZIP_INVALID_FILENAME: +- return "invalid filename"; +- case MZ_ZIP_BUF_TOO_SMALL: +- return "buffer too small"; +- case MZ_ZIP_INTERNAL_ERROR: +- return "internal error"; +- case MZ_ZIP_FILE_NOT_FOUND: +- return "file not found"; +- case MZ_ZIP_ARCHIVE_TOO_LARGE: +- return "archive is too large"; +- case MZ_ZIP_VALIDATION_FAILED: +- return "validation failed"; +- case MZ_ZIP_WRITE_CALLBACK_FAILED: +- return "write calledback failed"; +- default: +- break; +- } ++// const char *mz_zip_get_error_string(mz_zip_error mz_err) ++// { ++// switch (mz_err) ++// { ++// case MZ_ZIP_NO_ERROR: ++// return "no error"; ++// case MZ_ZIP_UNDEFINED_ERROR: ++// return "undefined error"; ++// case MZ_ZIP_TOO_MANY_FILES: ++// return "too many files"; ++// case MZ_ZIP_FILE_TOO_LARGE: ++// return "file too large"; ++// case MZ_ZIP_UNSUPPORTED_METHOD: ++// return "unsupported method"; ++// case MZ_ZIP_UNSUPPORTED_ENCRYPTION: ++// return "unsupported encryption"; ++// case MZ_ZIP_UNSUPPORTED_FEATURE: ++// return "unsupported feature"; ++// case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: ++// return "failed finding central directory"; ++// case MZ_ZIP_NOT_AN_ARCHIVE: ++// return "not a ZIP archive"; ++// case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: ++// return "invalid header or archive is corrupted"; ++// case MZ_ZIP_UNSUPPORTED_MULTIDISK: ++// return "unsupported multidisk archive"; ++// case MZ_ZIP_DECOMPRESSION_FAILED: ++// return "decompression failed or archive is corrupted"; ++// case MZ_ZIP_COMPRESSION_FAILED: ++// return "compression failed"; ++// case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: ++// return "unexpected decompressed size"; ++// case MZ_ZIP_CRC_CHECK_FAILED: ++// return "CRC-32 check failed"; ++// case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: ++// return "unsupported central directory size"; ++// case MZ_ZIP_ALLOC_FAILED: ++// return "allocation failed"; ++// case MZ_ZIP_FILE_OPEN_FAILED: ++// return "file open failed"; ++// case MZ_ZIP_FILE_CREATE_FAILED: ++// return "file create failed"; ++// case MZ_ZIP_FILE_WRITE_FAILED: ++// return "file write failed"; ++// case MZ_ZIP_FILE_READ_FAILED: ++// return "file read failed"; ++// case MZ_ZIP_FILE_CLOSE_FAILED: ++// return "file close failed"; ++// case MZ_ZIP_FILE_SEEK_FAILED: ++// return "file seek failed"; ++// case MZ_ZIP_FILE_STAT_FAILED: ++// return "file stat failed"; ++// case MZ_ZIP_INVALID_PARAMETER: ++// return "invalid parameter"; ++// case MZ_ZIP_INVALID_FILENAME: ++// return "invalid filename"; ++// case MZ_ZIP_BUF_TOO_SMALL: ++// return "buffer too small"; ++// case MZ_ZIP_INTERNAL_ERROR: ++// return "internal error"; ++// case MZ_ZIP_FILE_NOT_FOUND: ++// return "file not found"; ++// case MZ_ZIP_ARCHIVE_TOO_LARGE: ++// return "archive is too large"; ++// case MZ_ZIP_VALIDATION_FAILED: ++// return "validation failed"; ++// case MZ_ZIP_WRITE_CALLBACK_FAILED: ++// return "write calledback failed"; ++// default: ++// break; ++// } + +- return "unknown error"; +-} ++// return "unknown error"; ++// } + + /* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */ +-mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) +-{ +- if ((!pZip) || (!pZip->m_pState)) +- return MZ_FALSE; ++// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) ++// { ++// if ((!pZip) || (!pZip->m_pState)) ++// return MZ_FALSE; + +- return pZip->m_pState->m_zip64; +-} ++// return pZip->m_pState->m_zip64; ++// } + +-size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) +-{ +- if ((!pZip) || (!pZip->m_pState)) +- return 0; ++// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) ++// { ++// if ((!pZip) || (!pZip->m_pState)) ++// return 0; + +- return pZip->m_pState->m_central_dir.m_size; +-} ++// return pZip->m_pState->m_central_dir.m_size; ++// } + +-mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) +-{ +- return pZip ? pZip->m_total_files : 0; +-} ++// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) ++// { ++// return pZip ? pZip->m_total_files : 0; ++// } + +-mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) +-{ +- if (!pZip) +- return 0; +- return pZip->m_archive_size; +-} ++// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) ++// { ++// if (!pZip) ++// return 0; ++// return pZip->m_archive_size; ++// } + +-mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) +-{ +- if ((!pZip) || (!pZip->m_pState)) +- return 0; +- return pZip->m_pState->m_file_archive_start_ofs; +-} ++// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) ++// { ++// if ((!pZip) || (!pZip->m_pState)) ++// return 0; ++// return pZip->m_pState->m_file_archive_start_ofs; ++// } + +-MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) +-{ +- if ((!pZip) || (!pZip->m_pState)) +- return 0; +- return pZip->m_pState->m_pFile; +-} ++// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) ++// { ++// if ((!pZip) || (!pZip->m_pState)) ++// return 0; ++// return pZip->m_pState->m_pFile; ++// } + +-size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) +-{ +- if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) +- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) ++// { ++// if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) ++// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +- return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); +-} ++// return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); ++// } + +-mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) +-{ +- mz_uint n; +- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +- if (!p) +- { +- if (filename_buf_size) +- pFilename[0] = '\0'; +- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +- return 0; +- } +- n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +- if (filename_buf_size) +- { +- n = MZ_MIN(n, filename_buf_size - 1); +- memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); +- pFilename[n] = '\0'; +- } +- return n + 1; +-} ++// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) ++// { ++// mz_uint n; ++// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); ++// if (!p) ++// { ++// if (filename_buf_size) ++// pFilename[0] = '\0'; ++// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); ++// return 0; ++// } ++// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); ++// if (filename_buf_size) ++// { ++// n = MZ_MIN(n, filename_buf_size - 1); ++// memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); ++// pFilename[n] = '\0'; ++// } ++// return n + 1; ++// } + +-mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) +-{ +- return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); +-} ++// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) ++// { ++// return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); ++// } + +-mz_bool mz_zip_end(mz_zip_archive *pZip) +-{ +- if (!pZip) +- return MZ_FALSE; +- +- if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) +- return mz_zip_reader_end(pZip); +-#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +- else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) +- return mz_zip_writer_end(pZip); +-#endif ++// mz_bool mz_zip_end(mz_zip_archive *pZip) ++// { ++// if (!pZip) ++// return MZ_FALSE; + +- return MZ_FALSE; +-} ++// if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) ++// return mz_zip_reader_end(pZip); ++// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS ++// else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) ++// return mz_zip_writer_end(pZip); ++// #endif + +-#ifdef __cplusplus +-} +-#endif ++// return MZ_FALSE; ++// } ++ ++// #ifdef __cplusplus ++// } ++// #endif + +-#endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ ++// #endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ diff --git a/gomspace/libutil/src/zip/miniz/miniz.c b/gomspace/libutil/src/zip/miniz/miniz.c new file mode 100644 index 00000000..910d4b1f --- /dev/null +++ b/gomspace/libutil/src/zip/miniz/miniz.c @@ -0,0 +1,7572 @@ +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +#include "miniz.h" + +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- zlib-style API's */ + +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) +{ + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); + size_t block_len = buf_len % 5552; + if (!ptr) + return MZ_ADLER32_INIT; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) + s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + return (s2 << 16) + s1; +} + +/* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */ +// #if 0 +// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +// { +// static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, +// 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; +// mz_uint32 crcu32 = (mz_uint32)crc; +// if (!ptr) +// return MZ_CRC32_INIT; +// crcu32 = ~crcu32; +// while (buf_len--) +// { +// mz_uint8 b = *ptr++; +// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; +// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; +// } +// return ~crcu32; +// } +// #else +/* Faster, but larger CPU cache footprint. + */ +// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +// { +// static const mz_uint32 s_crc_table[256] = +// { +// 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, +// 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, +// 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, +// 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, +// 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, +// 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, +// 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, +// 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, +// 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, +// 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, +// 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, +// 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, +// 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, +// 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, +// 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, +// 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, +// 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, +// 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, +// 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, +// 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, +// 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, +// 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, +// 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, +// 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, +// 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, +// 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, +// 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, +// 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, +// 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, +// 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, +// 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, +// 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, +// 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, +// 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, +// 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, +// 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, +// 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +// }; + +// mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; +// const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; + +// while (buf_len >= 4) +// { +// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; +// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; +// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; +// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; +// pByte_buf += 4; +// buf_len -= 4; +// } + +// while (buf_len) +// { +// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; +// ++pByte_buf; +// --buf_len; +// } + +// return ~crc32; +// } +// #endif + +void mz_free(void *p) +{ + MZ_FREE(p); +} + +void *miniz_def_alloc_func(void *opaque, size_t items, size_t size) +{ + (void)opaque, (void)items, (void)size; + return MZ_MALLOC(items * size); +} +void miniz_def_free_func(void *opaque, void *address) +{ + (void)opaque, (void)address; + MZ_FREE(address); +} +// void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) +// { +// (void)opaque, (void)address, (void)items, (void)size; +// return MZ_REALLOC(address, items * size); +// } + +// const char *mz_version(void) +// { +// return MZ_VERSION; +// } + +#ifndef MINIZ_NO_ZLIB_APIS + +int mz_deflateInit(mz_streamp pStream, int level) +{ + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); +} + +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) +{ + tdefl_compressor *pComp; + mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + + if (!pStream) + return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) + pStream->zalloc = miniz_def_alloc_func; + if (!pStream->zfree) + pStream->zfree = miniz_def_free_func; + + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pComp; + + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) + { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } + + return MZ_OK; +} + +// int mz_deflateReset(mz_streamp pStream) +// { +// if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) +// return MZ_STREAM_ERROR; +// pStream->total_in = pStream->total_out = 0; +// tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); +// return MZ_OK; +// } + +int mz_deflate(mz_streamp pStream, int flush) +{ + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; + + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) + return MZ_STREAM_ERROR; + if (!pStream->avail_out) + return MZ_BUF_ERROR; + + if (flush == MZ_PARTIAL_FLUSH) + flush = MZ_SYNC_FLUSH; + + if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + + orig_total_in = pStream->total_in; + orig_total_out = pStream->total_out; + for (;;) + { + tdefl_status defl_status; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + + defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); + + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (defl_status < 0) + { + mz_status = MZ_STREAM_ERROR; + break; + } + else if (defl_status == TDEFL_STATUS_DONE) + { + mz_status = MZ_STREAM_END; + break; + } + else if (!pStream->avail_out) + break; + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) + { + if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) + break; + return MZ_BUF_ERROR; /* Can't make forward progress without some input. + */ + } + } + return mz_status; +} + +int mz_deflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) +// { +// (void)pStream; +// This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) +// return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); +// } + +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) +{ + int status; + mz_stream stream; + memset(&stream, 0, sizeof(stream)); + + /* In case mz_ulong is 64-bits (argh I hate longs). */ + if ((source_len | *pDest_len) > 0xFFFFFFFFU) + return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_deflateInit(&stream, level); + if (status != MZ_OK) + return status; + + status = mz_deflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_deflateEnd(&stream); + return (status == MZ_OK) ? MZ_BUF_ERROR : status; + } + + *pDest_len = stream.total_out; + return mz_deflateEnd(&stream); +} + +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); +} + +// mz_ulong mz_compressBound(mz_ulong source_len) +// { +// return mz_deflateBound(NULL, source_len); +// } + +typedef struct +{ + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; + int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; +} inflate_state; + +int mz_inflateInit2(mz_streamp pStream, int window_bits) +{ + inflate_state *pDecomp; + if (!pStream) + return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) + pStream->zalloc = miniz_def_alloc_func; + if (!pStream->zfree) + pStream->zfree = miniz_def_free_func; + + pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); + if (!pDecomp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pDecomp; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + + return MZ_OK; +} + +int mz_inflateInit(mz_streamp pStream) +{ + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); +} + +int mz_inflate(mz_streamp pStream, int flush) +{ + inflate_state *pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + + if ((!pStream) || (!pStream->state)) + return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) + flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; + + pState = (inflate_state *)pStream->state; + if (pState->m_window_bits > 0) + decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; + + first_call = pState->m_first_call; + pState->m_first_call = 0; + if (pState->m_last_status < 0) + return MZ_DATA_ERROR; + + if (pState->m_has_flushed && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); + + if ((flush == MZ_FINISH) && (first_call)) + { + /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */ + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) + { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + /* flush != MZ_FINISH then we must assume there's more input. */ + if (flush != MZ_FINISH) + decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + + if (pState->m_dict_avail) + { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + } + + for (;;) + { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + + pState->m_dict_avail = (mz_uint)out_bytes; + + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + + if (status < 0) + return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */ + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */ + else if (flush == MZ_FINISH) + { + /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */ + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */ + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } + else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } + + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; +} + +int mz_inflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + mz_stream stream; + int status; + memset(&stream, 0, sizeof(stream)); + + /* In case mz_ulong is 64-bits (argh I hate longs). */ + if ((source_len | *pDest_len) > 0xFFFFFFFFU) + return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_inflateInit(&stream); + if (status != MZ_OK) + return status; + + status = mz_inflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_inflateEnd(&stream); + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; + } + *pDest_len = stream.total_out; + + return mz_inflateEnd(&stream); +} + +// const char *mz_error(int err) +// { +// static struct +// { +// int m_err; +// const char *m_pDesc; +// } s_error_descs[] = +// { +// { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } +// }; +// mz_uint i; +// for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) +// if (s_error_descs[i].m_err == err) +// return s_error_descs[i].m_pDesc; +// return NULL; +// } + +#endif /*MINIZ_NO_ZLIB_APIS */ + +#ifdef __cplusplus +} +#endif + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + + + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- Low-level Compression (independent from all decompression API's) */ + +/* Purposely making these tables static for faster init and thread safety. */ +static const mz_uint16 s_tdefl_len_sym[256] = + { + 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, + 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285 + }; + +static const mz_uint8 s_tdefl_len_extra[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 + }; + +static const mz_uint8 s_tdefl_small_dist_sym[512] = + { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 + }; + +static const mz_uint8 s_tdefl_small_dist_extra[512] = + { + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7 + }; + +static const mz_uint8 s_tdefl_large_dist_sym[128] = + { + 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 + }; + +static const mz_uint8 s_tdefl_large_dist_extra[128] = + { + 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 + }; + +/* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. */ +typedef struct +{ + mz_uint16 m_key, m_sym_index; +} tdefl_sym_freq; +static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) +{ + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; + tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; + MZ_CLEAR_OBJ(hist); + for (i = 0; i < num_syms; i++) + { + mz_uint freq = pSyms0[i].m_key; + hist[freq & 0xFF]++; + hist[256 + ((freq >> 8) & 0xFF)]++; + } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) + total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) + { + const mz_uint32 *pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) + { + offsets[i] = cur_ofs; + cur_ofs += pHist[i]; + } + for (i = 0; i < num_syms; i++) + pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; + { + tdefl_sym_freq *t = pCur_syms; + pCur_syms = pNew_syms; + pNew_syms = t; + } + } + return pCur_syms; +} + +/* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */ +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) +{ + int root, leaf, next, avbl, used, dpth; + if (n == 0) + return; + else if (n == 1) + { + A[0].m_key = 1; + return; + } + A[0].m_key += A[1].m_key; + root = 0; + leaf = 2; + for (next = 1; next < n - 1; next++) + { + if (leaf >= n || A[root].m_key < A[leaf].m_key) + { + A[next].m_key = A[root].m_key; + A[root++].m_key = (mz_uint16)next; + } + else + A[next].m_key = A[leaf++].m_key; + if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) + { + A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); + A[root++].m_key = (mz_uint16)next; + } + else + A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); + } + A[n - 2].m_key = 0; + for (next = n - 3; next >= 0; next--) + A[next].m_key = A[A[next].m_key].m_key + 1; + avbl = 1; + used = dpth = 0; + root = n - 2; + next = n - 1; + while (avbl > 0) + { + while (root >= 0 && (int)A[root].m_key == dpth) + { + used++; + root--; + } + while (avbl > used) + { + A[next--].m_key = (mz_uint16)(dpth); + avbl--; + } + avbl = 2 * used; + dpth++; + used = 0; + } +} + +/* Limits canonical Huffman code table's max code size. */ +enum +{ + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 +}; +static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) +{ + int i; + mz_uint32 total = 0; + if (code_list_len <= 1) + return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) + pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) + total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) + { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) + if (pNum_codes[i]) + { + pNum_codes[i]--; + pNum_codes[i + 1] += 2; + break; + } + total--; + } +} + +static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) +{ + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; + mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; + MZ_CLEAR_OBJ(num_codes); + if (static_table) + { + for (i = 0; i < table_len; i++) + num_codes[d->m_huff_code_sizes[table_num][i]]++; + } + else + { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; + int num_used_syms = 0; + const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) + if (pSym_count[i]) + { + syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; + syms0[num_used_syms++].m_sym_index = (mz_uint16)i; + } + + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); + tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + + for (i = 0; i < num_used_syms; i++) + num_codes[pSyms[i].m_key]++; + + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); + + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); + MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) + d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } + + next_code[1] = 0; + for (j = 0, i = 2; i <= code_size_limit; i++) + next_code[i] = j = ((j + num_codes[i - 1]) << 1); + + for (i = 0; i < table_len; i++) + { + mz_uint rev_code = 0, code, code_size; + if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) + continue; + code = next_code[code_size]++; + for (l = code_size; l > 0; l--, code >>= 1) + rev_code = (rev_code << 1) | (code & 1); + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } +} + +#define TDEFL_PUT_BITS(b, l) \ + do \ + { \ + mz_uint bits = b; \ + mz_uint len = l; \ + MZ_ASSERT(bits <= ((1U << len) - 1U)); \ + d->m_bit_buffer |= (bits << d->m_bits_in); \ + d->m_bits_in += len; \ + while (d->m_bits_in >= 8) \ + { \ + if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ + *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ + d->m_bit_buffer >>= 8; \ + d->m_bits_in -= 8; \ + } \ + } \ + MZ_MACRO_END + +#define TDEFL_RLE_PREV_CODE_SIZE() \ + { \ + if (rle_repeat_count) \ + { \ + if (rle_repeat_count < 3) \ + { \ + d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + while (rle_repeat_count--) \ + packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ + } \ + else \ + { \ + d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 16; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ + } \ + rle_repeat_count = 0; \ + } \ + } + +#define TDEFL_RLE_ZERO_CODE_SIZE() \ + { \ + if (rle_z_count) \ + { \ + if (rle_z_count < 3) \ + { \ + d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ + while (rle_z_count--) \ + packed_code_sizes[num_packed_code_sizes++] = 0; \ + } \ + else if (rle_z_count <= 10) \ + { \ + d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 17; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ + } \ + else \ + { \ + d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 18; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ + } \ + rle_z_count = 0; \ + } \ + } + +static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + +static void tdefl_start_dynamic_block(tdefl_compressor *d) +{ + int num_lit_codes, num_dist_codes, num_bit_lengths; + mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; + mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; + + d->m_huff_count[0][256] = 1; + + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) + if (d->m_huff_code_sizes[0][num_lit_codes - 1]) + break; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) + if (d->m_huff_code_sizes[1][num_dist_codes - 1]) + break; + + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; + num_packed_code_sizes = 0; + rle_z_count = 0; + rle_repeat_count = 0; + + memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) + { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) + { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); + packed_code_sizes[num_packed_code_sizes++] = code_size; + } + else if (++rle_repeat_count == 6) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + + TDEFL_PUT_BITS(2, 2); + + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); + + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) + if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) + break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); + TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) + TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + + for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;) + { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; + MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) + TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); + } +} + +static void tdefl_start_static_block(tdefl_compressor *d) +{ + mz_uint i; + mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + + for (i = 0; i <= 143; ++i) + *p++ = 8; + for (; i <= 255; ++i) + *p++ = 9; + for (; i <= 279; ++i) + *p++ = 7; + for (; i <= 287; ++i) + *p++ = 8; + + memset(d->m_huff_code_sizes[1], 5, 32); + + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + + TDEFL_PUT_BITS(1, 2); +} + +static const mz_uint16 mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + mz_uint8 *pOutput_buf = d->m_pOutput_buf; + mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; + +#define TDEFL_PUT_BITS_FAST(b, l) \ + { \ + bit_buffer |= (((mz_uint64)(b)) << bits_in); \ + bits_in += (l); \ + } + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + + if (flags & 1) + { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + /* This sequence coaxes MSVC into using cmov's vs. jmp's. */ + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; + + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + } + + if (pOutput_buf >= d->m_pOutput_buf_end) + return MZ_FALSE; + + *(mz_uint64 *)pOutput_buf = bit_buffer; + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } + +#undef TDEFL_PUT_BITS_FAST + + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; + + while (bits_in) + { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#else +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + if (flags & 1) + { + mz_uint sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + if (match_dist < 512) + { + sym = s_tdefl_small_dist_sym[match_dist]; + num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } + else + { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; + num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; + } + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS */ + +static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) +{ + if (static_block) + tdefl_start_static_block(d); + else + tdefl_start_dynamic_block(d); + return tdefl_compress_lz_codes(d); +} + +static int tdefl_flush_block(tdefl_compressor *d, int flush) +{ + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8 *pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; + + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; + + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) + { + TDEFL_PUT_BITS(0x78, 8); + TDEFL_PUT_BITS(0x01, 8); + } + + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + + pSaved_output_buf = d->m_pOutput_buf; + saved_bit_buf = d->m_bit_buffer; + saved_bits_in = d->m_bits_in; + + if (!use_raw_block) + comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); + + /* If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. */ + if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) + { + mz_uint i; + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) + { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) + { + TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); + } + } + /* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. */ + else if (!comp_block_succeeded) + { + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } + + if (flush) + { + if (flush == TDEFL_FINISH) + { + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) + { + mz_uint i, a = d->m_adler32; + for (i = 0; i < 4; i++) + { + TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); + a <<= 8; + } + } + } + else + { + mz_uint i, z = 0; + TDEFL_PUT_BITS(0, 3); + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, z ^= 0xFFFF) + { + TDEFL_PUT_BITS(z & 0xFFFF, 16); + } + } + } + + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; + d->m_total_lz_bytes = 0; + d->m_block_index++; + + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) + { + if (d->m_pPut_buf_func) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } + else if (pOutput_buf_start == d->m_output_buf) + { + int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) + { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } + else + { + d->m_out_buf_ofs += n; + } + } + + return d->m_output_flush_remaining; +} + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES +#ifdef MINIZ_UNALIGNED_USE_MEMCPY +static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8* p) +{ + mz_uint16 ret; + memcpy(&ret, p, sizeof(mz_uint16)); + return ret; +} +static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p) +{ + mz_uint16 ret; + memcpy(&ret, p, sizeof(mz_uint16)); + return ret; +} +#else +#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) +#define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p) +#endif +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + mz_uint16 s01 = TDEFL_READ_UNALIGNED_WORD2(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) + return; + for (;;) + { + for (;;) + { + if (--num_probes_left == 0) + return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) + break; + q = (const mz_uint16 *)(d->m_dict + probe_pos); + if (TDEFL_READ_UNALIGNED_WORD2(q) != s01) + continue; + p = s; + probe_len = 32; + do + { + } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && + (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); + if (!probe_len) + { + *pMatch_dist = dist; + *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN); + break; + } + else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len) + { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) + break; + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } +} +#else +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint8 *s = d->m_dict + pos, *p, *q; + mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) + return; + for (;;) + { + for (;;) + { + if (--num_probes_left == 0) + return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) + break; + p = s; + q = d->m_dict + probe_pos; + for (probe_len = 0; probe_len < max_match_len; probe_len++) + if (*p++ != *q++) + break; + if (probe_len > match_len) + { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = probe_len) == max_match_len) + return; + c0 = d->m_dict[pos + match_len]; + c1 = d->m_dict[pos + match_len - 1]; + } + } +} +#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ + +// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +// static mz_bool tdefl_compress_fast(tdefl_compressor *d) +// { +// /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ +// mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; +// mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; +// mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + +// while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) +// { +// const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; +// mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; +// mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); +// d->m_src_buf_left -= num_bytes_to_process; +// lookahead_size += num_bytes_to_process; + +// while (num_bytes_to_process) +// { +// mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); +// memcpy(d->m_dict + dst_pos, d->m_pSrc, n); +// if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) +// memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); +// d->m_pSrc += n; +// dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; +// num_bytes_to_process -= n; +// } + +// dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); +// if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) +// break; + +// while (lookahead_size >= 4) +// { +// mz_uint cur_match_dist, cur_match_len = 1; +// mz_uint8 *pCur_dict = d->m_dict + cur_pos; +// mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; +// mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; +// mz_uint probe_pos = d->m_hash[hash]; +// d->m_hash[hash] = (mz_uint16)lookahead_pos; + +// if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) +// { +// const mz_uint16 *p = (const mz_uint16 *)pCur_dict; +// const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); +// mz_uint32 probe_len = 32; +// do +// { +// } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && +// (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); +// cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); +// if (!probe_len) +// cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + +// if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) +// { +// cur_match_len = 1; +// *pLZ_code_buf++ = (mz_uint8)first_trigram; +// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); +// d->m_huff_count[0][(mz_uint8)first_trigram]++; +// } +// else +// { +// mz_uint32 s0, s1; +// cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + +// MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + +// cur_match_dist--; + +// pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); +// *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; +// pLZ_code_buf += 3; +// *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + +// s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; +// s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; +// d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + +// d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; +// } +// } +// else +// { +// *pLZ_code_buf++ = (mz_uint8)first_trigram; +// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); +// d->m_huff_count[0][(mz_uint8)first_trigram]++; +// } + +// if (--num_flags_left == 0) +// { +// num_flags_left = 8; +// pLZ_flags = pLZ_code_buf++; +// } + +// total_lz_bytes += cur_match_len; +// lookahead_pos += cur_match_len; +// dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); +// cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; +// MZ_ASSERT(lookahead_size >= cur_match_len); +// lookahead_size -= cur_match_len; + +// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) +// { +// int n; +// d->m_lookahead_pos = lookahead_pos; +// d->m_lookahead_size = lookahead_size; +// d->m_dict_size = dict_size; +// d->m_total_lz_bytes = total_lz_bytes; +// d->m_pLZ_code_buf = pLZ_code_buf; +// d->m_pLZ_flags = pLZ_flags; +// d->m_num_flags_left = num_flags_left; +// if ((n = tdefl_flush_block(d, 0)) != 0) +// return (n < 0) ? MZ_FALSE : MZ_TRUE; +// total_lz_bytes = d->m_total_lz_bytes; +// pLZ_code_buf = d->m_pLZ_code_buf; +// pLZ_flags = d->m_pLZ_flags; +// num_flags_left = d->m_num_flags_left; +// } +// } + +// while (lookahead_size) +// { +// mz_uint8 lit = d->m_dict[cur_pos]; + +// total_lz_bytes++; +// *pLZ_code_buf++ = lit; +// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); +// if (--num_flags_left == 0) +// { +// num_flags_left = 8; +// pLZ_flags = pLZ_code_buf++; +// } + +// d->m_huff_count[0][lit]++; + +// lookahead_pos++; +// dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); +// cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; +// lookahead_size--; + +// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) +// { +// int n; +// d->m_lookahead_pos = lookahead_pos; +// d->m_lookahead_size = lookahead_size; +// d->m_dict_size = dict_size; +// d->m_total_lz_bytes = total_lz_bytes; +// d->m_pLZ_code_buf = pLZ_code_buf; +// d->m_pLZ_flags = pLZ_flags; +// d->m_num_flags_left = num_flags_left; +// if ((n = tdefl_flush_block(d, 0)) != 0) +// return (n < 0) ? MZ_FALSE : MZ_TRUE; +// total_lz_bytes = d->m_total_lz_bytes; +// pLZ_code_buf = d->m_pLZ_code_buf; +// pLZ_flags = d->m_pLZ_flags; +// num_flags_left = d->m_num_flags_left; +// } +// } +// } + +// d->m_lookahead_pos = lookahead_pos; +// d->m_lookahead_size = lookahead_size; +// d->m_dict_size = dict_size; +// d->m_total_lz_bytes = total_lz_bytes; +// d->m_pLZ_code_buf = pLZ_code_buf; +// d->m_pLZ_flags = pLZ_flags; +// d->m_num_flags_left = num_flags_left; +// return MZ_TRUE; +// } +// #endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + +static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) +{ + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); + if (--d->m_num_flags_left == 0) + { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + d->m_huff_count[0][lit]++; +} + +static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) +{ + mz_uint32 s0, s1; + + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); + + d->m_total_lz_bytes += match_len; + + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); + d->m_pLZ_code_buf += 3; + + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); + if (--d->m_num_flags_left == 0) + { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + + if (match_len >= TDEFL_MIN_MATCH_LEN) + d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; +} + +static mz_bool tdefl_compress_normal(tdefl_compressor *d) +{ + const mz_uint8 *pSrc = d->m_pSrc; + size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; + + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) + { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + /* Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. */ + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) + { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) + { + mz_uint8 c = *pSrc++; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + ins_pos++; + } + } + else + { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) + { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + break; + + /* Simple lazy/greedy parsing state machine. */ + len_to_move = 1; + cur_match_dist = 0; + cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); + cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) + { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) + { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; + while (cur_match_len < d->m_lookahead_size) + { + if (d->m_dict[cur_pos + cur_match_len] != c) + break; + cur_match_len++; + } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) + cur_match_len = 0; + else + cur_match_dist = 1; + } + } + else + { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) + { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) + { + if (cur_match_len > d->m_saved_match_len) + { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[cur_pos]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + } + else + { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; + d->m_saved_match_len = 0; + } + } + else if (!cur_match_dist) + tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + /* Move the lookahead forward by len_to_move bytes. */ + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); + /* Check if it's time to flush the current LZ codes to the internal output buffer. */ + if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) + { + int n; + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } + + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + return MZ_TRUE; +} + +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) +{ + if (d->m_pIn_buf_size) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + } + + if (d->m_pOut_buf_size) + { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; + + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } + + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) +{ + if (!d) + { + if (pIn_buf_size) + *pIn_buf_size = 0; + if (pOut_buf_size) + *pOut_buf_size = 0; + return TDEFL_STATUS_BAD_PARAM; + } + + d->m_pIn_buf = pIn_buf; + d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; + d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); + d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; + + if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) + { + if (pIn_buf_size) + *pIn_buf_size = 0; + if (pOut_buf_size) + *pOut_buf_size = 0; + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); + + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +// if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && +// ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && +// ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) +// { +// if (!tdefl_compress_fast(d)) +// return d->m_prev_return_status; +// } +// else +// #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + { + if (!tdefl_compress_normal(d)) + return d->m_prev_return_status; + } + + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) + d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); + + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) + { + if (tdefl_flush_block(d, flush) < 0) + return d->m_prev_return_status; + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) + { + MZ_CLEAR_OBJ(d->m_hash); + MZ_CLEAR_OBJ(d->m_next); + d->m_dict_size = 0; + } + } + + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); +} + +// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) +// { +// MZ_ASSERT(d->m_pPut_buf_func); +// return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +// } + +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + d->m_pPut_buf_func = pPut_buf_func; + d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); + d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; + d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) + MZ_CLEAR_OBJ(d->m_hash); + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; + d->m_pOutput_buf_end = d->m_output_buf; + d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; + d->m_adler32 = 1; + d->m_pIn_buf = NULL; + d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; + d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; + d->m_pSrc = NULL; + d->m_src_buf_left = 0; + d->m_out_buf_ofs = 0; + memset(d->m_dict, 0, sizeof(d->m_dict)); // Initialize array to 0's + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +} + +// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) +// { +// return d->m_prev_return_status; +// } + +mz_uint32 tdefl_get_adler32(tdefl_compressor *d) +{ + return d->m_adler32; +} + +// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +// { +// tdefl_compressor *pComp; +// mz_bool succeeded; +// if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) +// return MZ_FALSE; +// pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +// if (!pComp) +// return MZ_FALSE; +// succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); +// succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); +// MZ_FREE(pComp); +// return succeeded; +// } + +// typedef struct +// { +// size_t m_size, m_capacity; +// mz_uint8 *m_pBuf; +// mz_bool m_expandable; +// } tdefl_output_buffer; + +// static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) +// { +// tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; +// size_t new_size = p->m_size + len; +// if (new_size > p->m_capacity) +// { +// size_t new_capacity = p->m_capacity; +// mz_uint8 *pNew_buf; +// if (!p->m_expandable) +// return MZ_FALSE; +// do +// { +// new_capacity = MZ_MAX(128U, new_capacity << 1U); +// } while (new_size > new_capacity); +// pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); +// if (!pNew_buf) +// return MZ_FALSE; +// p->m_pBuf = pNew_buf; +// p->m_capacity = new_capacity; +// } +// memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); +// p->m_size = new_size; +// return MZ_TRUE; +// } + +// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +// { +// tdefl_output_buffer out_buf; +// MZ_CLEAR_OBJ(out_buf); +// if (!pOut_len) +// return MZ_FALSE; +// else +// *pOut_len = 0; +// out_buf.m_expandable = MZ_TRUE; +// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) +// return NULL; +// *pOut_len = out_buf.m_size; +// return out_buf.m_pBuf; +// } + +// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +// { +// tdefl_output_buffer out_buf; +// MZ_CLEAR_OBJ(out_buf); +// if (!pOut_buf) +// return 0; +// out_buf.m_pBuf = (mz_uint8 *)pOut_buf; +// out_buf.m_capacity = out_buf_len; +// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) +// return 0; +// return out_buf.m_size; +// } + +static const mz_uint16 s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + +/* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */ +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) +{ + mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) + comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + + if (!level) + comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) + comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) + comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) + comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) + comp_flags |= TDEFL_RLE_MATCHES; + + return comp_flags; +} + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) */ +#endif + +/* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at + http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. + This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ +// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) +// { +// /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ +// static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; +// tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +// tdefl_output_buffer out_buf; +// int i, bpl = w * num_chans, y, z; +// mz_uint32 c; +// *pLen_out = 0; +// if (!pComp) +// return NULL; +// MZ_CLEAR_OBJ(out_buf); +// out_buf.m_expandable = MZ_TRUE; +// out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); +// if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) +// { +// MZ_FREE(pComp); +// return NULL; +// } +// /* write dummy header */ +// for (z = 41; z; --z) +// tdefl_output_buffer_putter(&z, 1, &out_buf); +// /* compress image data */ +// tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); +// for (y = 0; y < h; ++y) +// { +// tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); +// tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); +// } +// if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) +// { +// MZ_FREE(pComp); +// MZ_FREE(out_buf.m_pBuf); +// return NULL; +// } +// /* write real header */ +// *pLen_out = out_buf.m_size - 41; +// { +// static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; +// mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, +// 0x0a, 0x1a, 0x0a, 0x00, 0x00, +// 0x00, 0x0d, 0x49, 0x48, 0x44, +// 0x52, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x08, +// 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x49, 0x44, 0x41, +// 0x54 }; +// pnghdr[18] = (mz_uint8)(w >> 8); +// pnghdr[19] = (mz_uint8)w; +// pnghdr[22] = (mz_uint8)(h >> 8); +// pnghdr[23] = (mz_uint8)h; +// pnghdr[25] = chans[num_chans]; +// pnghdr[33] = (mz_uint8)(*pLen_out >> 24); +// pnghdr[34] = (mz_uint8)(*pLen_out >> 16); +// pnghdr[35] = (mz_uint8)(*pLen_out >> 8); +// pnghdr[36] = (mz_uint8)*pLen_out; +// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); +// for (i = 0; i < 4; ++i, c <<= 8) +// ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); +// memcpy(out_buf.m_pBuf, pnghdr, 41); +// } +// /* write footer (IDAT CRC-32, followed by IEND chunk) */ +// if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) +// { +// *pLen_out = 0; +// MZ_FREE(pComp); +// MZ_FREE(out_buf.m_pBuf); +// return NULL; +// } +// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); +// for (i = 0; i < 4; ++i, c <<= 8) +// (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); +// /* compute final size of file, grab compressed data buffer and return */ +// *pLen_out += 57; +// MZ_FREE(pComp); +// return out_buf.m_pBuf; +// } +// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) +// { + /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */ +// return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); +// } + +/* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ +/* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ +// tdefl_compressor *tdefl_compressor_alloc() +// { +// return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +// } + +// void tdefl_compressor_free(tdefl_compressor *pComp) +// { +// MZ_FREE(pComp); +// } + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#ifdef __cplusplus +} +#endif +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- Low-level Decompression (completely independent from all compression API's) */ + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN \ + switch (r->m_state) \ + { \ + case 0: +#define TINFL_CR_RETURN(state_index, result) \ + do \ + { \ + status = result; \ + r->m_state = state_index; \ + goto common_exit; \ + case state_index:; \ + } \ + MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) \ + do \ + { \ + for (;;) \ + { \ + TINFL_CR_RETURN(state_index, result); \ + } \ + } \ + MZ_MACRO_END +#define TINFL_CR_FINISH } + +#define TINFL_GET_BYTE(state_index, c) \ + do \ + { \ + while (pIn_buf_cur >= pIn_buf_end) \ + { \ + TINFL_CR_RETURN(state_index, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \ + } \ + c = *pIn_buf_cur++; \ + } \ + MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) \ + do \ + { \ + mz_uint c; \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) \ + do \ + { \ + if (num_bits < (mz_uint)(n)) \ + { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) \ + do \ + { \ + if (num_bits < (mz_uint)(n)) \ + { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + b = bit_buf & ((1 << (n)) - 1); \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END + +/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */ +/* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */ +/* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */ +/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */ +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do \ + { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) \ + { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) \ + break; \ + } \ + else if (num_bits > TINFL_FAST_LOOKUP_BITS) \ + { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do \ + { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); \ + if (temp >= 0) \ + break; \ + } \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < 15); + +/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */ +/* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */ +/* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */ +/* The slow path is only executed at the very end of the input buffer. */ +/* v1.16: The original macro handled the case at the very end of the passed-in input buffer, but we also need to handle the case where the user passes in 1+zillion bytes */ +/* following the deflate data and our non-conservative read-ahead path won't kick in here on this code. This is much trickier. */ +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \ + do \ + { \ + int temp; \ + mz_uint code_len, c; \ + if (num_bits < 15) \ + { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) \ + { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } \ + else \ + { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ + pIn_buf_cur += 2; \ + num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ + code_len = temp >> 9, temp &= 511; \ + else \ + { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do \ + { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while (temp < 0); \ + } \ + sym = temp; \ + bit_buf >>= code_len; \ + num_bits -= code_len; \ + } \ + MZ_MACRO_END + +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) +{ + static const mz_uint16 s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; + static const mz_uint8 s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; + static const mz_uint16 s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; + static const mz_uint8 s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; + static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + static const mz_uint16 s_min_table_sizes[3] = { 257, 1, 4 }; + + tinfl_status status = TINFL_STATUS_FAILED; + mz_uint32 num_bits, dist, counter, num_extra; + tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + + /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */ + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) + { + *pIn_buf_size = *pOut_buf_size = 0; + return TINFL_STATUS_BAD_PARAM; + } + + num_bits = r->m_num_bits; + bit_buf = r->m_bit_buf; + dist = r->m_dist; + counter = r->m_counter; + num_extra = r->m_num_extra; + dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; + r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_GET_BYTE(1, r->m_zhdr0); + TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); + if (counter) + { + TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); + } + } + + do + { + TINFL_GET_BITS(3, r->m_final, 3); + r->m_type = r->m_final >> 1; + if (r->m_type == 0) + { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) + { + if (num_bits) + TINFL_GET_BITS(6, r->m_raw_header[counter], 8); + else + TINFL_GET_BYTE(7, r->m_raw_header[counter]); + } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) + { + TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); + } + while ((counter) && (num_bits)) + { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) + { + size_t n; + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); + } + while (pIn_buf_cur >= pIn_buf_end) + { + TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); + pIn_buf_cur += n; + pOut_buf_cur += n; + counter -= (mz_uint)n; + } + } + else if (r->m_type == 3) + { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } + else + { + if (r->m_type == 1) + { + mz_uint8 *p = r->m_tables[0].m_code_size; + mz_uint i; + r->m_table_sizes[0] = 288; + r->m_table_sizes[1] = 32; + TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for (i = 0; i <= 143; ++i) + *p++ = 8; + for (; i <= 255; ++i) + *p++ = 9; + for (; i <= 279; ++i) + *p++ = 7; + for (; i <= 287; ++i) + *p++ = 8; + } + else + { + for (counter = 0; counter < 3; counter++) + { + TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); + r->m_table_sizes[counter] += s_min_table_sizes[counter]; + } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); + for (counter = 0; counter < r->m_table_sizes[2]; counter++) + { + mz_uint s; + TINFL_GET_BITS(14, s, 3); + r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; + } + r->m_table_sizes[2] = 19; + } + for (; ((int)r->m_type) >= 0; r->m_type--) + { + int tree_next, tree_cur; + tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; + pTable = &r->m_tables[r->m_type]; + MZ_CLEAR_OBJ(total_syms); + MZ_CLEAR_OBJ(pTable->m_look_up); + MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) + total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; + next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) + { + used_syms += total_syms[i]; + next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); + } + if ((65536 != total) && (used_syms > 1)) + { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) + { + mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; + if (!code_size) + continue; + cur_code = next_code[code_size]++; + for (l = code_size; l > 0; l--, cur_code >>= 1) + rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) + { + mz_int16 k = (mz_int16)((code_size << 9) | sym_index); + while (rev_code < TINFL_FAST_LOOKUP_SIZE) + { + pTable->m_look_up[rev_code] = k; + rev_code += (1 << code_size); + } + continue; + } + if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) + { + pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) + { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) + { + pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + else + tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); + pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) + { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) + { + mz_uint s; + TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); + if (dist < 16) + { + r->m_len_codes[counter++] = (mz_uint8)dist; + continue; + } + if ((dist == 16) && (!counter)) + { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; + TINFL_GET_BITS(18, s, num_extra); + s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); + counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) + { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); + TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for (;;) + { + mz_uint8 *pSrc; + for (;;) + { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) + { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) + break; + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)counter; + } + else + { + int sym2; + mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 4; + num_bits += 32; + } +#else + if (num_bits < 15) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; + do + { + sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + counter = sym2; + bit_buf >>= code_len; + num_bits -= code_len; + if (counter & 256) + break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; + do + { + sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + bit_buf >>= code_len; + num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) + { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) + break; + + num_extra = s_length_extra[counter - 257]; + counter = s_length_base[counter - 257]; + if (num_extra) + { + mz_uint extra_bits; + TINFL_GET_BITS(25, extra_bits, num_extra); + counter += extra_bits; + } + + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; + dist = s_dist_base[dist]; + if (num_extra) + { + mz_uint extra_bits; + TINFL_GET_BITS(27, extra_bits, num_extra); + dist += extra_bits; + } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) + { + while (counter--) + { + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) + { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do + { + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) + { + if (counter) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + do + { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; + pSrc += 3; + } while ((int)(counter -= 3) > 2); + if ((int)counter > 0) + { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + + /* Ensure byte alignment and put back any bytes from the bitbuf if we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ + /* I'm being super conservative here. A number of simplifications can be made to the byte alignment part, and the Adler32 check shouldn't ever need to worry about reading from the bitbuf now. */ + TINFL_SKIP_BITS(32, num_bits & 7); + while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) + { + --pIn_buf_cur; + num_bits -= 8; + } + bit_buf &= (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); + MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */ + + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + for (counter = 0; counter < 4; ++counter) + { + mz_uint s; + if (num_bits) + TINFL_GET_BITS(41, s, 8); + else + TINFL_GET_BYTE(42, s); + r->m_z_adler32 = (r->m_z_adler32 << 8) | s; + } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + + TINFL_CR_FINISH + +common_exit: + /* As long as we aren't telling the caller that we NEED more input to make forward progress: */ + /* Put back any bytes from the bitbuf in case we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ + /* We need to be very careful here to NOT push back any bytes we definitely know we need to make forward progress, though, or we'll lock the caller up into an inf loop. */ + if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) && (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS)) + { + while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) + { + --pIn_buf_cur; + num_bits -= 8; + } + } + r->m_num_bits = num_bits; + r->m_bit_buf = bit_buf & (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); + r->m_dist = dist; + r->m_counter = counter; + r->m_num_extra = num_extra; + r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; + *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) + { + const mz_uint8 *ptr = pOut_buf_next; + size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; + size_t block_len = buf_len % 5552; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) + s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; + if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) + status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +/* Higher level helper functions. */ +// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +// { +// tinfl_decompressor decomp; +// void *pBuf = NULL, *pNew_buf; +// size_t src_buf_ofs = 0, out_buf_capacity = 0; +// *pOut_len = 0; +// tinfl_init(&decomp); +// for (;;) +// { +// size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; +// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, +// (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); +// if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) +// { +// MZ_FREE(pBuf); +// *pOut_len = 0; +// return NULL; +// } +// src_buf_ofs += src_buf_size; +// *pOut_len += dst_buf_size; +// if (status == TINFL_STATUS_DONE) +// break; +// new_out_buf_capacity = out_buf_capacity * 2; +// if (new_out_buf_capacity < 128) +// new_out_buf_capacity = 128; +// pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); +// if (!pNew_buf) +// { +// MZ_FREE(pBuf); +// *pOut_len = 0; +// return NULL; +// } +// pBuf = pNew_buf; +// out_buf_capacity = new_out_buf_capacity; +// } +// return pBuf; +// } + +// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +// { +// tinfl_decompressor decomp; +// tinfl_status status; +// tinfl_init(&decomp); +// status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); +// return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; +// } + +// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +// { +// int result = 0; +// tinfl_decompressor decomp; +// mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); +// size_t in_buf_ofs = 0, dict_ofs = 0; +// if (!pDict) +// return TINFL_STATUS_FAILED; +// tinfl_init(&decomp); +// for (;;) +// { +// size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; +// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, +// (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); +// in_buf_ofs += in_buf_size; +// if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) +// break; +// if (status != TINFL_STATUS_HAS_MORE_OUTPUT) +// { +// result = (status == TINFL_STATUS_DONE); +// break; +// } +// dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); +// } +// MZ_FREE(pDict); +// *pIn_buf_size = in_buf_ofs; +// return result; +// } + +// tinfl_decompressor *tinfl_decompressor_alloc() +// { +// tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); +// if (pDecomp) +// tinfl_init(pDecomp); +// return pDecomp; +// } + +// void tinfl_decompressor_free(tinfl_decompressor *pDecomp) +// { +// MZ_FREE(pDecomp); +// } + +#ifdef __cplusplus +} +#endif +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * Copyright 2016 Martin Raiber + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + +// #ifndef MINIZ_NO_ARCHIVE_APIS + +// #ifdef __cplusplus +// extern "C" { +// #endif + +/* ------------------- .ZIP archive reading */ + +// #ifdef MINIZ_NO_STDIO +// #define MZ_FILE void * +// #else +// #include + +// #if defined(_MSC_VER) || defined(__MINGW64__) +// static FILE *mz_fopen(const char *pFilename, const char *pMode) +// { +// FILE *pFile = NULL; +// fopen_s(&pFile, pFilename, pMode); +// return pFile; +// } +// static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) +// { +// FILE *pFile = NULL; +// if (freopen_s(&pFile, pPath, pMode, pStream)) +// return NULL; +// return pFile; +// } +// #ifndef MINIZ_NO_TIME +// #include +// #endif +// #define MZ_FOPEN mz_fopen +// #define MZ_FCLOSE fclose +// #define MZ_FREAD fread +// #define MZ_FWRITE fwrite +// #define MZ_FTELL64 _ftelli64 +// #define MZ_FSEEK64 _fseeki64 +// #define MZ_FILE_STAT_STRUCT _stat +// #define MZ_FILE_STAT _stat +// #define MZ_FFLUSH fflush +// #define MZ_FREOPEN mz_freopen +// #define MZ_DELETE_FILE remove +// #elif defined(__MINGW32__) +// #ifndef MINIZ_NO_TIME +// #include +// #endif +// #define MZ_FOPEN(f, m) fopen(f, m) +// #define MZ_FCLOSE fclose +// #define MZ_FREAD fread +// #define MZ_FWRITE fwrite +// #define MZ_FTELL64 ftello64 +// #define MZ_FSEEK64 fseeko64 +// #define MZ_FILE_STAT_STRUCT _stat +// #define MZ_FILE_STAT _stat +// #define MZ_FFLUSH fflush +// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) +// #define MZ_DELETE_FILE remove +// #elif defined(__TINYC__) +// #ifndef MINIZ_NO_TIME +// #include +// #endif +// #define MZ_FOPEN(f, m) fopen(f, m) +// #define MZ_FCLOSE fclose +// #define MZ_FREAD fread +// #define MZ_FWRITE fwrite +// #define MZ_FTELL64 ftell +// #define MZ_FSEEK64 fseek +// #define MZ_FILE_STAT_STRUCT stat +// #define MZ_FILE_STAT stat +// #define MZ_FFLUSH fflush +// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) +// #define MZ_DELETE_FILE remove +// #elif defined(__GNUC__) && _LARGEFILE64_SOURCE +// #ifndef MINIZ_NO_TIME +// #include +// #endif +// #define MZ_FOPEN(f, m) fopen64(f, m) +// #define MZ_FCLOSE fclose +// #define MZ_FREAD fread +// #define MZ_FWRITE fwrite +// #define MZ_FTELL64 ftello64 +// #define MZ_FSEEK64 fseeko64 +// #define MZ_FILE_STAT_STRUCT stat64 +// #define MZ_FILE_STAT stat64 +// #define MZ_FFLUSH fflush +// #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) +// #define MZ_DELETE_FILE remove +// #elif defined(__APPLE__) && _LARGEFILE64_SOURCE +// #ifndef MINIZ_NO_TIME +// #include +// #endif +// #define MZ_FOPEN(f, m) fopen(f, m) +// #define MZ_FCLOSE fclose +// #define MZ_FREAD fread +// #define MZ_FWRITE fwrite +// #define MZ_FTELL64 ftello +// #define MZ_FSEEK64 fseeko +// #define MZ_FILE_STAT_STRUCT stat +// #define MZ_FILE_STAT stat +// #define MZ_FFLUSH fflush +// #define MZ_FREOPEN(p, m, s) freopen(p, m, s) +// #define MZ_DELETE_FILE remove + +// #else +// // #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") +// #ifndef MINIZ_NO_TIME +// #include +// #endif +// #define MZ_FOPEN(f, m) fopen(f, m) +// #define MZ_FCLOSE fclose +// #define MZ_FREAD fread +// #define MZ_FWRITE fwrite +// #ifdef __STRICT_ANSI__ +// #define MZ_FTELL64 ftell +// #define MZ_FSEEK64 fseek +// #else +// #define MZ_FTELL64 ftello +// #define MZ_FSEEK64 fseeko +// #endif +// #define MZ_FILE_STAT_STRUCT stat +// #define MZ_FILE_STAT stat +// #define MZ_FFLUSH fflush +// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) +// #define MZ_DELETE_FILE remove +// #endif /* #ifdef _MSC_VER */ +// #endif /* #ifdef MINIZ_NO_STDIO */ + +// #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) + +/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ +// enum +// { +// /* ZIP archive identifiers and record sizes */ +// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, +// MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, +// MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, +// MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, +// MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, +// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, + +// /* ZIP64 archive identifier and record sizes */ +// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, +// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, +// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, +// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, +// MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, +// MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, +// MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, +// MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, + +// /* Central directory header record offsets */ +// MZ_ZIP_CDH_SIG_OFS = 0, +// MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, +// MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, +// MZ_ZIP_CDH_BIT_FLAG_OFS = 8, +// MZ_ZIP_CDH_METHOD_OFS = 10, +// MZ_ZIP_CDH_FILE_TIME_OFS = 12, +// MZ_ZIP_CDH_FILE_DATE_OFS = 14, +// MZ_ZIP_CDH_CRC32_OFS = 16, +// MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, +// MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, +// MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, +// MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, +// MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, +// MZ_ZIP_CDH_DISK_START_OFS = 34, +// MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, +// MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, +// MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, + +// /* Local directory header offsets */ +// MZ_ZIP_LDH_SIG_OFS = 0, +// MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, +// MZ_ZIP_LDH_BIT_FLAG_OFS = 6, +// MZ_ZIP_LDH_METHOD_OFS = 8, +// MZ_ZIP_LDH_FILE_TIME_OFS = 10, +// MZ_ZIP_LDH_FILE_DATE_OFS = 12, +// MZ_ZIP_LDH_CRC32_OFS = 14, +// MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, +// MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, +// MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, +// MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, +// MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, + +// /* End of central directory offsets */ +// MZ_ZIP_ECDH_SIG_OFS = 0, +// MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, +// MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, +// MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, +// MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, +// MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, +// MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, +// MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, + +// /* ZIP64 End of central directory locator offsets */ +// MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ +// MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ +// MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ +// MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ + +// /* ZIP64 End of central directory header offsets */ +// MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ +// MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ +// MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ +// MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ +// MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ +// MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ +// MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ +// MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ +// MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ +// MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ +// MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, +// MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, +// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, +// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, +// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, +// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, +// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 +// }; + +// typedef struct +// { +// void *m_p; +// size_t m_size, m_capacity; +// mz_uint m_element_size; +// } mz_zip_array; + +// struct mz_zip_internal_state_tag +// { +// mz_zip_array m_central_dir; +// mz_zip_array m_central_dir_offsets; +// mz_zip_array m_sorted_central_dir_offsets; + +// /* The flags passed in when the archive is initially opened. */ +// uint32_t m_init_flags; + +// /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ +// mz_bool m_zip64; + +// /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ +// mz_bool m_zip64_has_extended_info_fields; + +// /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ +// MZ_FILE *m_pFile; +// mz_uint64 m_file_archive_start_ofs; + +// void *m_pMem; +// size_t m_mem_size; +// size_t m_mem_capacity; +// }; + +// #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size + +// #if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) +// static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) +// { +// MZ_ASSERT(index < pArray->m_size); +// return index; +// } +// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] +// #else +// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] +// #endif + +// static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) +// { +// memset(pArray, 0, sizeof(mz_zip_array)); +// pArray->m_element_size = element_size; +// } + +// static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); +// memset(pArray, 0, sizeof(mz_zip_array)); +// } + +// static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) +// { +// void *pNew_p; +// size_t new_capacity = min_new_capacity; +// MZ_ASSERT(pArray->m_element_size); +// if (pArray->m_capacity >= min_new_capacity) +// return MZ_TRUE; +// if (growing) +// { +// new_capacity = MZ_MAX(1, pArray->m_capacity); +// while (new_capacity < min_new_capacity) +// new_capacity *= 2; +// } +// if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) +// return MZ_FALSE; +// pArray->m_p = pNew_p; +// pArray->m_capacity = new_capacity; +// return MZ_TRUE; +// } + +// static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) +// { +// if (new_capacity > pArray->m_capacity) +// { +// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) +// return MZ_FALSE; +// } +// return MZ_TRUE; +// } + +// static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) +// { +// if (new_size > pArray->m_capacity) +// { +// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) +// return MZ_FALSE; +// } +// pArray->m_size = new_size; +// return MZ_TRUE; +// } + +// static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) +// { +// return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); +// } + +// static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) +// { +// size_t orig_size = pArray->m_size; +// if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) +// return MZ_FALSE; +// memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); +// return MZ_TRUE; +// } + +// #ifndef MINIZ_NO_TIME +// static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) +// { +// struct tm tm; +// memset(&tm, 0, sizeof(tm)); +// tm.tm_isdst = -1; +// tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; +// tm.tm_mon = ((dos_date >> 5) & 15) - 1; +// tm.tm_mday = dos_date & 31; +// tm.tm_hour = (dos_time >> 11) & 31; +// tm.tm_min = (dos_time >> 5) & 63; +// tm.tm_sec = (dos_time << 1) & 62; +// return mktime(&tm); +// } + +// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +// static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +// { +// #ifdef _MSC_VER +// struct tm tm_struct; +// struct tm *tm = &tm_struct; +// errno_t err = localtime_s(tm, &time_); +// if (err) +// { +// *pDOS_date = 0; +// *pDOS_time = 0; +// return; +// } +// #else +// struct tm *tm = localtime(&time_); +// #endif /* #ifdef _MSC_VER */ + +// *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); +// *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); +// } +// #endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ + +// #ifndef MINIZ_NO_STDIO +// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +// static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) +// { +// struct MZ_FILE_STAT_STRUCT file_stat; + +// /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ +// if (MZ_FILE_STAT(pFilename, &file_stat) != 0) +// return MZ_FALSE; + +// *pTime = file_stat.st_mtime; + +// return MZ_TRUE; +// } +// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ + +// static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) +// { +// struct utimbuf t; + +// memset(&t, 0, sizeof(t)); +// t.actime = access_time; +// t.modtime = modified_time; + +// return !utime(pFilename, &t); +// } +// #endif /* #ifndef MINIZ_NO_STDIO */ +// #endif /* #ifndef MINIZ_NO_TIME */ + +// static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) +// { +// if (pZip) +// pZip->m_last_error = err_num; +// return MZ_FALSE; +// } + +// static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) +// { +// (void)flags; +// if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (!pZip->m_pAlloc) +// pZip->m_pAlloc = miniz_def_alloc_func; +// if (!pZip->m_pFree) +// pZip->m_pFree = miniz_def_free_func; +// if (!pZip->m_pRealloc) +// pZip->m_pRealloc = miniz_def_realloc_func; + +// pZip->m_archive_size = 0; +// pZip->m_central_directory_file_ofs = 0; +// pZip->m_total_files = 0; +// pZip->m_last_error = MZ_ZIP_NO_ERROR; + +// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); +// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); +// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); +// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); +// pZip->m_pState->m_init_flags = flags; +// pZip->m_pState->m_zip64 = MZ_FALSE; +// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; + +// pZip->m_zip_mode = MZ_ZIP_MODE_READING; + +// return MZ_TRUE; +// } + +// static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) +// { +// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; +// const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); +// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// mz_uint8 l = 0, r = 0; +// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +// pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +// pE = pL + MZ_MIN(l_len, r_len); +// while (pL < pE) +// { +// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) +// break; +// pL++; +// pR++; +// } +// return (pL == pE) ? (l_len < r_len) : (l < r); +// } +/* +#define MZ_SWAP_UINT32(a, b) \ + do \ + { \ + mz_uint32 t = a; \ + a = b; \ + b = t; \ + } \ + MZ_MACRO_END +*/ +/* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */ +// static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) +// { +// mz_zip_internal_state *pState = pZip->m_pState; +// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; +// const mz_zip_array *pCentral_dir = &pState->m_central_dir; +// mz_uint32 *pIndices; +// mz_uint32 start, end; +// const mz_uint32 size = pZip->m_total_files; + +// if (size <= 1U) +// return; + +// pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + +// start = (size - 2U) >> 1U; +// for (;;) +// { +// mz_uint64 child, root = start; +// for (;;) +// { +// if ((child = (root << 1U) + 1U) >= size) +// break; +// child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); +// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) +// break; +// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); +// root = child; +// } +// if (!start) +// break; +// start--; +// } + +// end = size - 1; +// while (end > 0) +// { +// mz_uint64 child, root = 0; +// MZ_SWAP_UINT32(pIndices[end], pIndices[0]); +// for (;;) +// { +// if ((child = (root << 1U) + 1U) >= end) +// break; +// child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); +// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) +// break; +// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); +// root = child; +// } +// end--; +// } +// } + +// static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) +// { +// mz_int64 cur_file_ofs; +// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; +// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + +// /* Basic sanity checks - reject files which are too small */ +// if (pZip->m_archive_size < record_size) +// return MZ_FALSE; + +// /* Find the record by scanning the file from the end towards the beginning. */ +// cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); +// for (;;) +// { +// int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) +// return MZ_FALSE; + +// for (i = n - 4; i >= 0; --i) +// { +// mz_uint s = MZ_READ_LE32(pBuf + i); +// if (s == record_sig) +// { +// if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) +// break; +// } +// } + +// if (i >= 0) +// { +// cur_file_ofs += i; +// break; +// } + +// /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ +// if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) +// return MZ_FALSE; + +// cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); +// } + +// *pOfs = cur_file_ofs; +// return MZ_TRUE; +// } + +// static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) +// { +// mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; +// mz_uint64 cdir_ofs = 0; +// mz_int64 cur_file_ofs = 0; +// const mz_uint8 *p; + +// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; +// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; +// mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); +// mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +// mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; + +// mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +// mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; + +// mz_uint64 zip64_end_of_central_dir_ofs = 0; + +// /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ +// if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +// if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) +// return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); + +// /* Read and verify the end of central directory record. */ +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +// if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) +// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +// if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) +// { +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) +// { +// if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) +// { +// zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); +// if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) +// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +// if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) +// { +// if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) +// { +// pZip->m_pState->m_zip64 = MZ_TRUE; +// } +// } +// } +// } +// } + +// pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); +// cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); +// num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); +// cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); +// cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); +// cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + +// if (pZip->m_pState->m_zip64) +// { +// mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); +// mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); +// mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); +// mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); +// mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); + +// if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if (zip64_total_num_of_disks != 1U) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +// /* Check for miniz's practical limits */ +// if (zip64_cdir_total_entries > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + +// pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; + +// if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + +// cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; + +// /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ +// if (zip64_size_of_central_directory > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +// cdir_size = (mz_uint32)zip64_size_of_central_directory; + +// num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); + +// cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); + +// cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); +// } + +// if (pZip->m_total_files != cdir_entries_on_this_disk) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +// if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +// if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// pZip->m_central_directory_file_ofs = cdir_ofs; + +// if (pZip->m_total_files) +// { +// mz_uint i, n; +// /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ +// if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || +// (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// if (sort_central_dir) +// { +// if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +// /* Now create an index into the central directory file records, do some basic sanity checking on each record */ +// p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; +// for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) +// { +// mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; +// mz_uint64 comp_size, decomp_size, local_header_ofs; + +// if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + +// if (sort_central_dir) +// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; + +// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); +// decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); +// local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); +// filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + +// if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && +// (ext_data_size) && +// (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) +// { +// /* Attempt to find zip64 extended information field in the entry's extra data */ +// mz_uint32 extra_size_remaining = ext_data_size; + +// if (extra_size_remaining) +// { +// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; + +// do +// { +// mz_uint32 field_id; +// mz_uint32 field_data_size; + +// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// field_id = MZ_READ_LE16(pExtra_data); +// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + +// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) +// { +// /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ +// pZip->m_pState->m_zip64 = MZ_TRUE; +// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; +// break; +// } + +// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; +// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; +// } while (extra_size_remaining); +// } +// } + +// /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ +// if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) +// { +// if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// } + +// disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); +// if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + +// if (comp_size != MZ_UINT32_MAX) +// { +// if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// } + +// bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); +// if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + +// if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// n -= total_header_size; +// p += total_header_size; +// } +// } + +// if (sort_central_dir) +// mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + +// return MZ_TRUE; +// } + +// void mz_zip_zero_struct(mz_zip_archive *pZip) +// { +// if (pZip) +// MZ_CLEAR_OBJ(*pZip); +// } + +// static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +// { +// mz_bool status = MZ_TRUE; + +// if (!pZip) +// return MZ_FALSE; + +// if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) +// { +// if (set_last_error) +// pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; + +// return MZ_FALSE; +// } + +// if (pZip->m_pState) +// { +// mz_zip_internal_state *pState = pZip->m_pState; +// pZip->m_pState = NULL; + +// mz_zip_array_clear(pZip, &pState->m_central_dir); +// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); +// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +// #ifndef MINIZ_NO_STDIO +// if (pState->m_pFile) +// { +// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) +// { +// if (MZ_FCLOSE(pState->m_pFile) == EOF) +// { +// if (set_last_error) +// pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; +// status = MZ_FALSE; +// } +// } +// pState->m_pFile = NULL; +// } +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// } +// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + +// return status; +// } + +// mz_bool mz_zip_reader_end(mz_zip_archive *pZip) +// { +// return mz_zip_reader_end_internal(pZip, MZ_TRUE); +// } +// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) +// { +// if ((!pZip) || (!pZip->m_pRead)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (!mz_zip_reader_init_internal(pZip, flags)) +// return MZ_FALSE; + +// pZip->m_zip_type = MZ_ZIP_TYPE_USER; +// pZip->m_archive_size = size; + +// if (!mz_zip_reader_read_central_dir(pZip, flags)) +// { +// mz_zip_reader_end_internal(pZip, MZ_FALSE); +// return MZ_FALSE; +// } + +// return MZ_TRUE; +// } + +// static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +// { +// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +// size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); +// memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); +// return s; +// } + +// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) +// { +// if (!pMem) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + +// if (!mz_zip_reader_init_internal(pZip, flags)) +// return MZ_FALSE; + +// pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; +// pZip->m_archive_size = size; +// pZip->m_pRead = mz_zip_mem_read_func; +// pZip->m_pIO_opaque = pZip; +// pZip->m_pNeeds_keepalive = NULL; + +// #ifdef __cplusplus +// pZip->m_pState->m_pMem = const_cast(pMem); +// #else +// pZip->m_pState->m_pMem = (void *)pMem; +// #endif + +// pZip->m_pState->m_mem_size = size; + +// if (!mz_zip_reader_read_central_dir(pZip, flags)) +// { +// mz_zip_reader_end_internal(pZip, MZ_FALSE); +// return MZ_FALSE; +// } + +// return MZ_TRUE; +// } + +// #ifndef MINIZ_NO_STDIO +// static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +// { +// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + +// file_ofs += pZip->m_pState->m_file_archive_start_ofs; + +// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) +// return 0; + +// return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); +// } + +// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) +// { +// return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); +// } + +// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) +// { +// mz_uint64 file_size; +// MZ_FILE *pFile; + +// if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pFile = MZ_FOPEN(pFilename, "rb"); +// if (!pFile) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +// file_size = archive_size; +// if (!file_size) +// { +// if (MZ_FSEEK64(pFile, 0, SEEK_END)) +// { +// MZ_FCLOSE(pFile); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); +// } + +// file_size = MZ_FTELL64(pFile); +// } + +// /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ + +// if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +// { +// MZ_FCLOSE(pFile); +// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); +// } + +// if (!mz_zip_reader_init_internal(pZip, flags)) +// { +// MZ_FCLOSE(pFile); +// return MZ_FALSE; +// } + +// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; +// pZip->m_pRead = mz_zip_file_read_func; +// pZip->m_pIO_opaque = pZip; +// pZip->m_pState->m_pFile = pFile; +// pZip->m_archive_size = file_size; +// pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; + +// if (!mz_zip_reader_read_central_dir(pZip, flags)) +// { +// mz_zip_reader_end_internal(pZip, MZ_FALSE); +// return MZ_FALSE; +// } + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) +// { +// mz_uint64 cur_file_ofs; + +// if ((!pZip) || (!pFile)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +// cur_file_ofs = MZ_FTELL64(pFile); + +// if (!archive_size) +// { +// if (MZ_FSEEK64(pFile, 0, SEEK_END)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + +// archive_size = MZ_FTELL64(pFile) - cur_file_ofs; + +// if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); +// } + +// if (!mz_zip_reader_init_internal(pZip, flags)) +// return MZ_FALSE; + +// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; +// pZip->m_pRead = mz_zip_file_read_func; + +// pZip->m_pIO_opaque = pZip; +// pZip->m_pState->m_pFile = pFile; +// pZip->m_archive_size = archive_size; +// pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; + +// if (!mz_zip_reader_read_central_dir(pZip, flags)) +// { +// mz_zip_reader_end_internal(pZip, MZ_FALSE); +// return MZ_FALSE; +// } + +// return MZ_TRUE; +// } + +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) +// { +// if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) +// return NULL; +// return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); +// } + +// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) +// { +// mz_uint m_bit_flag; +// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +// if (!p) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// return MZ_FALSE; +// } + +// m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); +// return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; +// } + +// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) +// { +// mz_uint bit_flag; +// mz_uint method; + +// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +// if (!p) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// return MZ_FALSE; +// } + +// method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +// bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + +// if ((method != 0) && (method != MZ_DEFLATED)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); +// return MZ_FALSE; +// } + +// if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); +// return MZ_FALSE; +// } + +// if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) +// { +// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); +// return MZ_FALSE; +// } + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) +// { +// mz_uint filename_len, attribute_mapping_id, external_attr; +// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +// if (!p) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// return MZ_FALSE; +// } + +// filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// if (filename_len) +// { +// if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') +// return MZ_TRUE; +// } + + /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */ + /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */ + /* FIXME: Remove this check? Is it necessary - we already check the filename. */ +// attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; +// (void)attribute_mapping_id; + +// external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); +// if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) +// { +// return MZ_TRUE; +// } + +// return MZ_FALSE; +// } + +// static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) +// { +// mz_uint n; +// const mz_uint8 *p = pCentral_dir_header; + +// if (pFound_zip64_extra_data) +// *pFound_zip64_extra_data = MZ_FALSE; + +// if ((!p) || (!pStat)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// /* Extract fields from the central directory record. */ +// pStat->m_file_index = file_index; +// pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); +// pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); +// pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); +// pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); +// pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +// #ifndef MINIZ_NO_TIME +// pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); +// #endif +// pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); +// pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); +// pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); +// pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); +// pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); +// pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + +// /* Copy as much of the filename and comment as possible. */ +// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); +// memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); +// pStat->m_filename[n] = '\0'; + +// n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); +// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); +// pStat->m_comment_size = n; +// memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); +// pStat->m_comment[n] = '\0'; + +// /* Set some flags for convienance */ +// pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); +// pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); +// pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); + +// /* See if we need to read any zip64 extended information fields. */ +// /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ +// if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) +// { +// /* Attempt to find zip64 extended information field in the entry's extra data */ +// mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + +// if (extra_size_remaining) +// { +// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + +// do +// { +// mz_uint32 field_id; +// mz_uint32 field_data_size; + +// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// field_id = MZ_READ_LE16(pExtra_data); +// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + +// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) +// { +// const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; +// mz_uint32 field_data_remaining = field_data_size; + +// if (pFound_zip64_extra_data) +// *pFound_zip64_extra_data = MZ_TRUE; + +// if (pStat->m_uncomp_size == MZ_UINT32_MAX) +// { +// if (field_data_remaining < sizeof(mz_uint64)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// pStat->m_uncomp_size = MZ_READ_LE64(pField_data); +// pField_data += sizeof(mz_uint64); +// field_data_remaining -= sizeof(mz_uint64); +// } + +// if (pStat->m_comp_size == MZ_UINT32_MAX) +// { +// if (field_data_remaining < sizeof(mz_uint64)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// pStat->m_comp_size = MZ_READ_LE64(pField_data); +// pField_data += sizeof(mz_uint64); +// field_data_remaining -= sizeof(mz_uint64); +// } + +// if (pStat->m_local_header_ofs == MZ_UINT32_MAX) +// { +// if (field_data_remaining < sizeof(mz_uint64)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); +// pField_data += sizeof(mz_uint64); +// // field_data_remaining -= sizeof(mz_uint64); +// } + +// break; +// } + +// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; +// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; +// } while (extra_size_remaining); +// } +// } + +// return MZ_TRUE; +// } + +// static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) +// { +// mz_uint i; +// if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) +// return 0 == memcmp(pA, pB, len); +// for (i = 0; i < len; ++i) +// if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) +// return MZ_FALSE; +// return MZ_TRUE; +// } + +// static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) +// { +// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; +// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// mz_uint8 l = 0, r = 0; +// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +// pE = pL + MZ_MIN(l_len, r_len); +// while (pL < pE) +// { +// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) +// break; +// pL++; +// pR++; +// } +// return (pL == pE) ? (int)(l_len - r_len) : (l - r); +// } + +// static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) +// { +// mz_zip_internal_state *pState = pZip->m_pState; +// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; +// const mz_zip_array *pCentral_dir = &pState->m_central_dir; +// mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); +// const uint32_t size = pZip->m_total_files; +// const mz_uint filename_len = (mz_uint)strlen(pFilename); + +// if (pIndex) +// *pIndex = 0; + +// if (size) +// { +// /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ +// /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ +// mz_int64 l = 0, h = (mz_int64)size - 1; + +// while (l <= h) +// { +// mz_int64 m = l + ((h - l) >> 1); +// uint32_t file_index = pIndices[(uint32_t)m]; + +// int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); +// if (!comp) +// { +// if (pIndex) +// *pIndex = file_index; +// return MZ_TRUE; +// } +// else if (comp < 0) +// l = m + 1; +// else +// h = m - 1; +// } +// } + +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +// } + +// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) +// { +// mz_uint32 index_; +// if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) +// return -1; +// else +// return (int)index_; +// } + +// mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) +// { +// mz_uint file_index; +// size_t name_len, comment_len; + +// if (pIndex) +// *pIndex = 0; + +// if ((!pZip) || (!pZip->m_pState) || (!pName)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// /* See if we can use a binary search */ +// if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && +// (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && +// ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) +// { +// return mz_zip_locate_file_binary_search(pZip, pName, pIndex); +// } + +// /* Locate the entry by scanning the entire central directory */ +// name_len = strlen(pName); +// if (name_len > MZ_UINT16_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// comment_len = pComment ? strlen(pComment) : 0; +// if (comment_len > MZ_UINT16_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// for (file_index = 0; file_index < pZip->m_total_files; file_index++) +// { +// const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); +// mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; +// if (filename_len < name_len) +// continue; +// if (comment_len) +// { +// mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); +// const char *pFile_comment = pFilename + filename_len + file_extra_len; +// if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) +// continue; +// } +// if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) +// { +// int ofs = filename_len - 1; +// do +// { +// if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) +// break; +// } while (--ofs >= 0); +// ofs++; +// pFilename += ofs; +// filename_len -= ofs; +// } +// if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) +// { +// if (pIndex) +// *pIndex = file_index; +// return MZ_TRUE; +// } +// } + +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +// } + +// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +// { +// int status = TINFL_STATUS_DONE; +// mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; +// mz_zip_archive_file_stat file_stat; +// void *pRead_buf; +// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; +// tinfl_decompressor inflator; + +// if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +// return MZ_FALSE; + +// /* A directory or zero length file */ +// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) +// return MZ_TRUE; + +// /* Encryption and patch files are not supported. */ +// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + +// /* This function only supports decompressing stored and deflate. */ +// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + +// /* Ensure supplied output buffer is large enough. */ +// needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; +// if (buf_size < needed_size) +// return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); + +// /* Read and parse the local directory entry. */ +// cur_file_ofs = file_stat.m_local_header_ofs; +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) +// { +// /* The file is stored or the caller has requested the compressed data. */ +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) +// { +// if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) +// return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); +// } +// #endif + +// return MZ_TRUE; +// } + +// /* Decompress the file either directly from memory or from a file input buffer. */ +// tinfl_init(&inflator); + +// if (pZip->m_pState->m_pMem) +// { +// /* Read directly from the archive in memory. */ +// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; +// read_buf_size = read_buf_avail = file_stat.m_comp_size; +// comp_remaining = 0; +// } +// else if (pUser_read_buf) +// { +// /* Use a user provided read buffer. */ +// if (!user_read_buf_size) +// return MZ_FALSE; +// pRead_buf = (mz_uint8 *)pUser_read_buf; +// read_buf_size = user_read_buf_size; +// read_buf_avail = 0; +// comp_remaining = file_stat.m_comp_size; +// } +// else +// { +// /* Temporarily allocate a read buffer. */ +// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); +// if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// read_buf_avail = 0; +// comp_remaining = file_stat.m_comp_size; +// } + +// do +// { +// /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ +// size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); +// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) +// { +// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +// { +// status = TINFL_STATUS_FAILED; +// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); +// break; +// } +// cur_file_ofs += read_buf_avail; +// comp_remaining -= read_buf_avail; +// read_buf_ofs = 0; +// } +// in_buf_size = (size_t)read_buf_avail; +// status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); +// read_buf_avail -= in_buf_size; +// read_buf_ofs += in_buf_size; +// out_buf_ofs += out_buf_size; +// } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); + +// if (status == TINFL_STATUS_DONE) +// { +// /* Make sure the entire file was decompressed, and check its CRC. */ +// if (out_buf_ofs != file_stat.m_uncomp_size) +// { +// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); +// status = TINFL_STATUS_FAILED; +// } +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) +// { +// mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); +// status = TINFL_STATUS_FAILED; +// } +// #endif +// } + +// if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) +// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + +// return status == TINFL_STATUS_DONE; +// } + +// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +// { +// mz_uint32 file_index; +// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +// return MZ_FALSE; +// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); +// } + +// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) +// { +// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); +// } + +// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) +// { +// return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); +// } + +// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) +// { +// mz_uint64 comp_size, uncomp_size, alloc_size; +// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +// void *pBuf; + +// if (pSize) +// *pSize = 0; + +// if (!p) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// return NULL; +// } + +// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); +// uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + +// alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; +// if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); +// return NULL; +// } + +// if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) +// { +// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// return NULL; +// } + +// if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); +// return NULL; +// } + +// if (pSize) +// *pSize = (size_t)alloc_size; +// return pBuf; +// } + +// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) +// { +// mz_uint32 file_index; +// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +// { +// if (pSize) +// *pSize = 0; +// return MZ_FALSE; +// } +// return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); +// } + +// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +// { +// int status = TINFL_STATUS_DONE; +// mz_uint file_crc32 = MZ_CRC32_INIT; +// mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; +// mz_zip_archive_file_stat file_stat; +// void *pRead_buf = NULL; +// void *pWrite_buf = NULL; +// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + +// if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +// return MZ_FALSE; + +// /* A directory or zero length file */ +// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) +// return MZ_TRUE; + +// /* Encryption and patch files are not supported. */ +// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + +// /* This function only supports decompressing stored and deflate. */ +// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + +// /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ +// cur_file_ofs = file_stat.m_local_header_ofs; +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// /* Decompress the file either directly from memory or from a file input buffer. */ +// if (pZip->m_pState->m_pMem) +// { +// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; +// read_buf_size = read_buf_avail = file_stat.m_comp_size; +// comp_remaining = 0; +// } +// else +// { +// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); +// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// read_buf_avail = 0; +// comp_remaining = file_stat.m_comp_size; +// } + +// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) +// { +// /* The file is stored or the caller has requested the compressed data. */ +// if (pZip->m_pState->m_pMem) +// { +// if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) +// { +// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); +// status = TINFL_STATUS_FAILED; +// } +// else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +// { +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); +// #endif +// } + +// cur_file_ofs += file_stat.m_comp_size; +// out_buf_ofs += file_stat.m_comp_size; +// comp_remaining = 0; +// } +// else +// { +// while (comp_remaining) +// { +// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// status = TINFL_STATUS_FAILED; +// break; +// } + +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +// { +// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); +// } +// #endif + +// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +// { +// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); +// status = TINFL_STATUS_FAILED; +// break; +// } + +// cur_file_ofs += read_buf_avail; +// out_buf_ofs += read_buf_avail; +// comp_remaining -= read_buf_avail; +// } +// } +// } +// else +// { +// tinfl_decompressor inflator; +// tinfl_init(&inflator); + +// if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) +// { +// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// status = TINFL_STATUS_FAILED; +// } +// else +// { +// do +// { +// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); +// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); +// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) +// { +// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); +// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// status = TINFL_STATUS_FAILED; +// break; +// } +// cur_file_ofs += read_buf_avail; +// comp_remaining -= read_buf_avail; +// read_buf_ofs = 0; +// } + +// in_buf_size = (size_t)read_buf_avail; +// status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); +// read_buf_avail -= in_buf_size; +// read_buf_ofs += in_buf_size; + +// if (out_buf_size) +// { +// if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) +// { +// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); +// status = TINFL_STATUS_FAILED; +// break; +// } + +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); +// #endif +// if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) +// { +// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); +// status = TINFL_STATUS_FAILED; +// break; +// } +// } +// } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); +// } +// } + +// if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) +// { +// /* Make sure the entire file was decompressed, and check its CRC. */ +// if (out_buf_ofs != file_stat.m_uncomp_size) +// { +// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); +// status = TINFL_STATUS_FAILED; +// } +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// else if (file_crc32 != file_stat.m_crc32) +// { +// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); +// status = TINFL_STATUS_FAILED; +// } +// #endif +// } + +// if (!pZip->m_pState->m_pMem) +// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + +// if (pWrite_buf) +// pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + +// return status == TINFL_STATUS_DONE; +// } + +// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +// { +// mz_uint32 file_index; +// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +// return MZ_FALSE; + +// return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); +// } + +// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) +// { +// mz_zip_reader_extract_iter_state *pState; +// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + +// /* Argument sanity check */ +// if ((!pZip) || (!pZip->m_pState)) +// return NULL; + +// /* Allocate an iterator status structure */ +// pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); +// if (!pState) +// { +// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// return NULL; +// } + +// /* Fetch file details */ +// if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } + +// /* Encryption and patch files are not supported. */ +// if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } + +// /* This function only supports decompressing stored and deflate. */ +// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } + +// /* Init state - save args */ +// pState->pZip = pZip; +// pState->flags = flags; + +// /* Init state - reset variables to defaults */ +// pState->status = TINFL_STATUS_DONE; +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// pState->file_crc32 = MZ_CRC32_INIT; +// #endif +// pState->read_buf_ofs = 0; +// pState->out_buf_ofs = 0; +// pState->pRead_buf = NULL; +// pState->pWrite_buf = NULL; +// pState->out_blk_remain = 0; + +// /* Read and parse the local directory entry. */ +// pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; +// if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } + +// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } + +// pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +// if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } + +// /* Decompress the file either directly from memory or from a file input buffer. */ +// if (pZip->m_pState->m_pMem) +// { +// pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; +// pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; +// pState->comp_remaining = pState->file_stat.m_comp_size; +// } +// else +// { +// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) +// { +// /* Decompression required, therefore intermediate read buffer required */ +// pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); +// if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) +// { +// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } +// } +// else +// { +// /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ +// pState->read_buf_size = 0; +// } +// pState->read_buf_avail = 0; +// pState->comp_remaining = pState->file_stat.m_comp_size; +// } + +// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) +// { +// /* Decompression required, init decompressor */ +// tinfl_init( &pState->inflator ); + +// /* Allocate write buffer */ +// if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) +// { +// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// if (pState->pRead_buf) +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// return NULL; +// } +// } + +// return pState; +// } + +// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +// { +// mz_uint32 file_index; + +// /* Locate file index by name */ +// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) +// return NULL; + +// /* Construct iterator */ +// return mz_zip_reader_extract_iter_new(pZip, file_index, flags); +// } + +// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) +// { +// size_t copied_to_caller = 0; + +// /* Argument sanity check */ +// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) +// return 0; + +// if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) +// { +// /* The file is stored or the caller has requested the compressed data, calc amount to return. */ +// copied_to_caller = MZ_MIN( buf_size, pState->comp_remaining ); + +// /* Zip is in memory....or requires reading from a file? */ +// if (pState->pZip->m_pState->m_pMem) +// { +// /* Copy data to caller's buffer */ +// memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); +// pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; +// } +// else +// { +// /* Read directly into caller's buffer */ +// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) +// { +// /* Failed to read all that was asked for, flag failure and alert user */ +// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); +// pState->status = TINFL_STATUS_FAILED; +// copied_to_caller = 0; +// } +// } + +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// /* Compute CRC if not returning compressed data only */ +// if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); +// #endif + +// /* Advance offsets, dec counters */ +// pState->cur_file_ofs += copied_to_caller; +// pState->out_buf_ofs += copied_to_caller; +// pState->comp_remaining -= copied_to_caller; +// } +// else +// { +// do +// { +// /* Calc ptr to write buffer - given current output pos and block size */ +// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + +// /* Calc max output size - given current output pos and block size */ +// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + +// if (!pState->out_blk_remain) +// { +// /* Read more data from file if none available (and reading from file) */ +// if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) +// { +// /* Calc read size */ +// pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); +// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) +// { +// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); +// pState->status = TINFL_STATUS_FAILED; +// break; +// } + +// /* Advance offsets, dec counters */ +// pState->cur_file_ofs += pState->read_buf_avail; +// pState->comp_remaining -= pState->read_buf_avail; +// pState->read_buf_ofs = 0; +// } + +// /* Perform decompression */ +// in_buf_size = (size_t)pState->read_buf_avail; +// pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); +// pState->read_buf_avail -= in_buf_size; +// pState->read_buf_ofs += in_buf_size; + +// /* Update current output block size remaining */ +// pState->out_blk_remain = out_buf_size; +// } + +// if (pState->out_blk_remain) +// { +// /* Calc amount to return. */ +// size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); + +// /* Copy data to caller's buffer */ +// memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); + +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// /* Perform CRC */ +// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); +// #endif + +// /* Decrement data consumed from block */ +// pState->out_blk_remain -= to_copy; + +// /* Inc output offset, while performing sanity check */ +// if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) +// { +// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); +// pState->status = TINFL_STATUS_FAILED; +// break; +// } + +// /* Increment counter of data copied to caller */ +// copied_to_caller += to_copy; +// } +// } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); +// } + +// /* Return how many bytes were copied into user buffer */ +// return copied_to_caller; +// } + +// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) +// { +// int status; + +// /* Argument sanity check */ +// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) +// return MZ_FALSE; + +// /* Was decompression completed and requested? */ +// if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) +// { +// /* Make sure the entire file was decompressed, and check its CRC. */ +// if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) +// { +// mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); +// pState->status = TINFL_STATUS_FAILED; +// } +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// else if (pState->file_crc32 != pState->file_stat.m_crc32) +// { +// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); +// pState->status = TINFL_STATUS_FAILED; +// } +// #endif +// } + +// /* Free buffers */ +// if (!pState->pZip->m_pState->m_pMem) +// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); +// if (pState->pWrite_buf) +// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); + +// /* Save status */ +// status = pState->status; + +// /* Free context */ +// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); + +// return status == TINFL_STATUS_DONE; +// } + +// #ifndef MINIZ_NO_STDIO +// static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) +// { +// (void)ofs; + +// return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); +// } + +// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) +// { +// mz_bool status; +// mz_zip_archive_file_stat file_stat; +// MZ_FILE *pFile; + +// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +// return MZ_FALSE; + +// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + +// pFile = MZ_FOPEN(pDst_filename, "wb"); +// if (!pFile) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +// status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); + +// if (MZ_FCLOSE(pFile) == EOF) +// { +// if (status) +// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); + +// status = MZ_FALSE; +// } + +// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) +// if (status) +// mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); +// #endif + +// return status; +// } + +// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) +// { +// mz_uint32 file_index; +// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) +// return MZ_FALSE; + +// return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); +// } + +// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) +// { +// mz_zip_archive_file_stat file_stat; + +// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) +// return MZ_FALSE; + +// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + +// return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); +// } + +// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) +// { +// mz_uint32 file_index; +// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) +// return MZ_FALSE; + +// return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); +// } +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +// { +// mz_uint32 *p = (mz_uint32 *)pOpaque; +// (void)file_ofs; +// *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n); +// return n; +// } + +// mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) +// { +// mz_zip_archive_file_stat file_stat; +// mz_zip_internal_state *pState; +// const mz_uint8 *pCentral_dir_header; +// mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE; +// mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; +// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; +// mz_uint64 local_header_ofs = 0; +// mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32; +// mz_uint64 local_header_comp_size, local_header_uncomp_size; +// mz_uint32 uncomp_crc32 = MZ_CRC32_INIT; +// mz_bool has_data_descriptor; +// mz_uint32 local_header_bit_flags; + +// mz_zip_array file_data_array; +// mz_zip_array_init(&file_data_array, 1); + +// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (file_index > pZip->m_total_files) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pState = pZip->m_pState; + +// pCentral_dir_header = mz_zip_get_cdh(pZip, file_index); + +// if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir)) +// return MZ_FALSE; + +// /* A directory or zero length file */ +// if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size)) +// return MZ_TRUE; + +// /* Encryption and patch files are not supported. */ +// if (file_stat.m_is_encrypted) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + +// /* This function only supports stored and deflate. */ +// if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + +// if (!file_stat.m_is_supported) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + +// /* Read and parse the local directory entry. */ +// local_header_ofs = file_stat.m_local_header_ofs; +// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); +// local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +// local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); +// local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); +// local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS); +// local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); +// has_data_descriptor = (local_header_bit_flags & 8) != 0; + +// if (local_header_filename_len != strlen(file_stat.m_filename)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size) > pZip->m_archive_size) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if (!mz_zip_array_resize(pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE)) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// if (local_header_filename_len) +// { +// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE, file_data_array.m_p, local_header_filename_len) != local_header_filename_len) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// goto handle_failure; +// } + +// /* I've seen 1 archive that had the same pathname, but used backslashes in the local dir and forward slashes in the central dir. Do we care about this? For now, this case will fail validation. */ +// if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0) +// { +// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); +// goto handle_failure; +// } +// } + +// if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) +// { +// mz_uint32 extra_size_remaining = local_header_extra_len; +// const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p; + +// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// goto handle_failure; +// } + +// do +// { +// mz_uint32 field_id, field_data_size, field_total_size; + +// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// field_id = MZ_READ_LE16(pExtra_data); +// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); +// field_total_size = field_data_size + sizeof(mz_uint16) * 2; + +// if (field_total_size > extra_size_remaining) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) +// { +// const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); + +// if (field_data_size < sizeof(mz_uint64) * 2) +// { +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// goto handle_failure; +// } + +// local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); +// local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); + +// found_zip64_ext_data_in_ldir = MZ_TRUE; +// break; +// } + +// pExtra_data += field_total_size; +// extra_size_remaining -= field_total_size; +// } while (extra_size_remaining); +// } + +// /* TODO: parse local header extra data when local_header_comp_size is 0xFFFFFFFF! (big_descriptor.zip) */ +// /* I've seen zips in the wild with the data descriptor bit set, but proper local header values and bogus data descriptors */ +// if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32)) +// { +// mz_uint8 descriptor_buf[32]; +// mz_bool has_id; +// const mz_uint8 *pSrc; +// mz_uint32 file_crc32; +// mz_uint64 comp_size = 0, uncomp_size = 0; + +// mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4; + +// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size, descriptor_buf, sizeof(mz_uint32) * num_descriptor_uint32s) != (sizeof(mz_uint32) * num_descriptor_uint32s)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// goto handle_failure; +// } + +// has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID); +// pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf; + +// file_crc32 = MZ_READ_LE32(pSrc); + +// if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) +// { +// comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32)); +// uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64)); +// } +// else +// { +// comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32)); +// uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32)); +// } + +// if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); +// goto handle_failure; +// } +// } +// else +// { +// if ((local_header_crc32 != file_stat.m_crc32) || (local_header_comp_size != file_stat.m_comp_size) || (local_header_uncomp_size != file_stat.m_uncomp_size)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); +// goto handle_failure; +// } +// } + +// mz_zip_array_clear(pZip, &file_data_array); + +// if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0) +// { +// if (!mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0)) +// return MZ_FALSE; + +// /* 1 more check to be sure, although the extract checks too. */ +// if (uncomp_crc32 != file_stat.m_crc32) +// { +// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); +// return MZ_FALSE; +// } +// } + +// return MZ_TRUE; + +// handle_failure: +// mz_zip_array_clear(pZip, &file_data_array); +// return MZ_FALSE; +// } + +// mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) +// { +// mz_zip_internal_state *pState; +// uint32_t i; + +// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pState = pZip->m_pState; + +// /* Basic sanity checks */ +// if (!pState->m_zip64) +// { +// if (pZip->m_total_files > MZ_UINT16_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +// if (pZip->m_archive_size > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); +// } +// else +// { +// if (pZip->m_total_files >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +// if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); +// } + +// for (i = 0; i < pZip->m_total_files; i++) +// { +// if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) +// { +// mz_uint32 found_index; +// mz_zip_archive_file_stat stat_; + +// if (!mz_zip_reader_file_stat(pZip, i, &stat_)) +// return MZ_FALSE; + +// if (!mz_zip_reader_locate_file_v2(pZip, stat_.m_filename, NULL, 0, &found_index)) +// return MZ_FALSE; + +// /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ +// if (found_index != i) +// return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); +// } + +// if (!mz_zip_validate_file(pZip, i, flags)) +// return MZ_FALSE; +// } + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr) +// { +// mz_bool success = MZ_TRUE; +// mz_zip_archive zip; +// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + +// if ((!pMem) || (!size)) +// { +// if (pErr) +// *pErr = MZ_ZIP_INVALID_PARAMETER; +// return MZ_FALSE; +// } + +// mz_zip_zero_struct(&zip); + +// if (!mz_zip_reader_init_mem(&zip, pMem, size, flags)) +// { +// if (pErr) +// *pErr = zip.m_last_error; +// return MZ_FALSE; +// } + +// if (!mz_zip_validate_archive(&zip, flags)) +// { +// actual_err = zip.m_last_error; +// success = MZ_FALSE; +// } + +// if (!mz_zip_reader_end_internal(&zip, success)) +// { +// if (!actual_err) +// actual_err = zip.m_last_error; +// success = MZ_FALSE; +// } + +// if (pErr) +// *pErr = actual_err; + +// return success; +// } + +// #ifndef MINIZ_NO_STDIO +// mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr) +// { +// mz_bool success = MZ_TRUE; +// mz_zip_archive zip; +// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + +// if (!pFilename) +// { +// if (pErr) +// *pErr = MZ_ZIP_INVALID_PARAMETER; +// return MZ_FALSE; +// } + +// mz_zip_zero_struct(&zip); + +// if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0)) +// { +// if (pErr) +// *pErr = zip.m_last_error; +// return MZ_FALSE; +// } + +// if (!mz_zip_validate_archive(&zip, flags)) +// { +// actual_err = zip.m_last_error; +// success = MZ_FALSE; +// } + +// if (!mz_zip_reader_end_internal(&zip, success)) +// { +// if (!actual_err) +// actual_err = zip.m_last_error; +// success = MZ_FALSE; +// } + +// if (pErr) +// *pErr = actual_err; + +// return success; +// } +// #endif /* #ifndef MINIZ_NO_STDIO */ + +/* ------------------- .ZIP archive writing */ + +// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +// static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) +// { +// p[0] = (mz_uint8)v; +// p[1] = (mz_uint8)(v >> 8); +// } +// static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) +// { +// p[0] = (mz_uint8)v; +// p[1] = (mz_uint8)(v >> 8); +// p[2] = (mz_uint8)(v >> 16); +// p[3] = (mz_uint8)(v >> 24); +// } +// static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) +// { +// mz_write_le32(p, (mz_uint32)v); +// mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); +// } + +// #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) +// #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) +// #define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) + +// static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +// { +// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +// mz_zip_internal_state *pState = pZip->m_pState; +// mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); + +// if (!n) +// return 0; + +// /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ +// if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); +// return 0; +// } + +// if (new_size > pState->m_mem_capacity) +// { +// void *pNew_block; +// size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); + +// while (new_capacity < new_size) +// new_capacity *= 2; + +// if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) +// { +// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// return 0; +// } + +// pState->m_pMem = pNew_block; +// pState->m_mem_capacity = new_capacity; +// } +// memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); +// pState->m_mem_size = (size_t)new_size; +// return n; +// } + +// static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +// { +// mz_zip_internal_state *pState; +// mz_bool status = MZ_TRUE; + +// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) +// { +// if (set_last_error) +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// return MZ_FALSE; +// } + +// pState = pZip->m_pState; +// pZip->m_pState = NULL; +// mz_zip_array_clear(pZip, &pState->m_central_dir); +// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); +// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +// #ifndef MINIZ_NO_STDIO +// if (pState->m_pFile) +// { +// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) +// { +// if (MZ_FCLOSE(pState->m_pFile) == EOF) +// { +// if (set_last_error) +// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); +// status = MZ_FALSE; +// } +// } + +// pState->m_pFile = NULL; +// } +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); +// pState->m_pMem = NULL; +// } + +// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); +// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; +// return status; +// } + +// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) +// { +// mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; + +// if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +// { +// if (!pZip->m_pRead) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// } + +// if (pZip->m_file_offset_alignment) +// { +// /* Ensure user specified file offset alignment is a power of 2. */ +// if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// } + +// if (!pZip->m_pAlloc) +// pZip->m_pAlloc = miniz_def_alloc_func; +// if (!pZip->m_pFree) +// pZip->m_pFree = miniz_def_free_func; +// if (!pZip->m_pRealloc) +// pZip->m_pRealloc = miniz_def_realloc_func; + +// pZip->m_archive_size = existing_size; +// pZip->m_central_directory_file_ofs = 0; +// pZip->m_total_files = 0; + +// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + +// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); +// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); +// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + +// pZip->m_pState->m_zip64 = zip64; +// pZip->m_pState->m_zip64_has_extended_info_fields = zip64; + +// pZip->m_zip_type = MZ_ZIP_TYPE_USER; +// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) +// { +// return mz_zip_writer_init_v2(pZip, existing_size, 0); +// } + +// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) +// { +// pZip->m_pWrite = mz_zip_heap_write_func; +// pZip->m_pNeeds_keepalive = NULL; + +// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +// pZip->m_pRead = mz_zip_mem_read_func; + +// pZip->m_pIO_opaque = pZip; + +// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) +// return MZ_FALSE; + +// pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; + +// if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) +// { +// if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) +// { +// mz_zip_writer_end_internal(pZip, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } +// pZip->m_pState->m_mem_capacity = initial_allocation_size; +// } + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) +// { +// return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); +// } + +// #ifndef MINIZ_NO_STDIO +// static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +// { +// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; +// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + +// file_ofs += pZip->m_pState->m_file_archive_start_ofs; + +// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); +// return 0; +// } + +// return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); +// } + +// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) +// { +// return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); +// } + +// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) +// { +// MZ_FILE *pFile; + +// pZip->m_pWrite = mz_zip_file_write_func; +// pZip->m_pNeeds_keepalive = NULL; + +// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +// pZip->m_pRead = mz_zip_file_read_func; + +// pZip->m_pIO_opaque = pZip; + +// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) +// return MZ_FALSE; + +// if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) +// { +// mz_zip_writer_end(pZip); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); +// } + +// pZip->m_pState->m_pFile = pFile; +// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; + +// if (size_to_reserve_at_beginning) +// { +// mz_uint64 cur_ofs = 0; +// char buf[4096]; + +// MZ_CLEAR_OBJ(buf); + +// do +// { +// size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) +// { +// mz_zip_writer_end(pZip); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } +// cur_ofs += n; +// size_to_reserve_at_beginning -= n; +// } while (size_to_reserve_at_beginning); +// } + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) +// { +// pZip->m_pWrite = mz_zip_file_write_func; +// pZip->m_pNeeds_keepalive = NULL; + +// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) +// pZip->m_pRead = mz_zip_file_read_func; + +// pZip->m_pIO_opaque = pZip; + +// if (!mz_zip_writer_init_v2(pZip, 0, flags)) +// return MZ_FALSE; + +// pZip->m_pState->m_pFile = pFile; +// pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); +// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; + +// return MZ_TRUE; +// } +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +// { +// mz_zip_internal_state *pState; + +// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) +// { +// /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ +// if (!pZip->m_pState->m_zip64) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// } + +// /* No sense in trying to write to an archive that's already at the support max size */ +// if (pZip->m_pState->m_zip64) +// { +// if (pZip->m_total_files == MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +// } +// else +// { +// if (pZip->m_total_files == MZ_UINT16_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + +// if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); +// } + +// pState = pZip->m_pState; + +// if (pState->m_pFile) +// { +// #ifdef MINIZ_NO_STDIO +// (void)pFilename; +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// #else +// if (pZip->m_pIO_opaque != pZip) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) +// { +// if (!pFilename) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ +// if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) +// { +// /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ +// mz_zip_reader_end_internal(pZip, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); +// } +// } + +// pZip->m_pWrite = mz_zip_file_write_func; +// pZip->m_pNeeds_keepalive = NULL; +// #endif /* #ifdef MINIZ_NO_STDIO */ +// } +// else if (pState->m_pMem) +// { +// /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ +// if (pZip->m_pIO_opaque != pZip) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pState->m_mem_capacity = pState->m_mem_size; +// pZip->m_pWrite = mz_zip_heap_write_func; +// pZip->m_pNeeds_keepalive = NULL; +// } +// /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ +// else if (!pZip->m_pWrite) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// /* Start writing new files at the archive's current central directory location. */ +// /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ +// pZip->m_archive_size = pZip->m_central_directory_file_ofs; +// pZip->m_central_directory_file_ofs = 0; + +// /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ +// /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ +// /* TODO: We could easily maintain the sorted central directory offsets. */ +// mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); + +// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) +// { +// return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); +// } + +/* TODO: pArchive_name is a terrible name here! */ +// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) +// { +// return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); +// } + +// typedef struct +// { +// mz_zip_archive *m_pZip; +// mz_uint64 m_cur_archive_file_ofs; +// mz_uint64 m_comp_size; +// } mz_zip_writer_add_state; + +// static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) +// { +// mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; +// if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) +// return MZ_FALSE; + +// pState->m_cur_archive_file_ofs += len; +// pState->m_comp_size += len; +// return MZ_TRUE; +// } + +// #define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) +// #define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) +// static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) +// { +// mz_uint8 *pDst = pBuf; +// mz_uint32 field_size = 0; + +// MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); +// MZ_WRITE_LE16(pDst + 2, 0); +// pDst += sizeof(mz_uint16) * 2; + +// if (pUncomp_size) +// { +// MZ_WRITE_LE64(pDst, *pUncomp_size); +// pDst += sizeof(mz_uint64); +// field_size += sizeof(mz_uint64); +// } + +// if (pComp_size) +// { +// MZ_WRITE_LE64(pDst, *pComp_size); +// pDst += sizeof(mz_uint64); +// field_size += sizeof(mz_uint64); +// } + +// if (pLocal_header_ofs) +// { +// MZ_WRITE_LE64(pDst, *pLocal_header_ofs); +// pDst += sizeof(mz_uint64); +// field_size += sizeof(mz_uint64); +// } + +// MZ_WRITE_LE16(pBuf + 2, field_size); + +// return (mz_uint32)(pDst - pBuf); +// } + +// static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) +// { +// (void)pZip; +// memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); +// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); +// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); +// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); +// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); +// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); +// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); +// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); +// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); +// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); +// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); +// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); +// return MZ_TRUE; +// } + +// static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, +// mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, +// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, +// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, +// mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +// { +// (void)pZip; +// memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); +// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); +// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); +// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); +// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); +// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); +// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); +// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); +// return MZ_TRUE; +// } + +// static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, +// const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, +// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, +// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, +// mz_uint64 local_header_ofs, mz_uint32 ext_attributes, +// const char *user_extra_data, mz_uint user_extra_data_len) +// { +// mz_zip_internal_state *pState = pZip->m_pState; +// mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; +// size_t orig_central_dir_size = pState->m_central_dir.m_size; +// mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + +// if (!pZip->m_pState->m_zip64) +// { +// if (local_header_ofs > 0xFFFFFFFF) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); +// } + +// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ +// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +// if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size + user_extra_data_len, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +// if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || +// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || +// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || +// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || +// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || +// (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) +// { +// /* Try to resize the central directory array back into its original state. */ +// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// return MZ_TRUE; +// } + +// static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) +// { +// /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ +// if (*pArchive_name == '/') +// return MZ_FALSE; + +// while (*pArchive_name) +// { +// if ((*pArchive_name == '\\') || (*pArchive_name == ':')) +// return MZ_FALSE; + +// pArchive_name++; +// } + +// return MZ_TRUE; +// } + +// static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) +// { +// mz_uint32 n; +// if (!pZip->m_file_offset_alignment) +// return 0; +// n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); +// return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); +// } + +// static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) +// { +// char buf[4096]; +// memset(buf, 0, MZ_MIN(sizeof(buf), n)); +// while (n) +// { +// mz_uint32 s = MZ_MIN(sizeof(buf), n); +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_file_ofs += s; +// n -= s; +// } +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) +// { +// return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); +// } + +// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, +// mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, +// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +// { +// if(!pZip) +// { +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// } + +// mz_uint16 method = 0, dos_time = 0, dos_date = 0; +// mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; +// mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; +// size_t archive_name_size; +// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; +// tdefl_compressor *pComp = NULL; +// mz_bool store_data_uncompressed; +// mz_zip_internal_state *pState; +// mz_uint8 *pExtra_data = NULL; +// mz_uint32 extra_size = 0; +// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; +// mz_uint16 bit_flags = 0; + +// if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) +// bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; + +// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) +// bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + +// if ((int)level_and_flags < 0) +// level_and_flags = MZ_DEFAULT_LEVEL; +// level = level_and_flags & 0xF; +// store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + +// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pState = pZip->m_pState; + +// if (pState->m_zip64) +// { +// if (pZip->m_total_files == MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +// } +// else +// { +// if (pZip->m_total_files == MZ_UINT16_MAX) +// { +// pState->m_zip64 = MZ_TRUE; +// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ +// } +// if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) +// { +// pState->m_zip64 = MZ_TRUE; +// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +// } +// } + +// if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (!mz_zip_writer_validate_archive_name(pArchive_name)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +// #ifndef MINIZ_NO_TIME +// if (last_modified != NULL) +// { +// mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); +// } +// else +// { +// MZ_TIME_T cur_time; +// time(&cur_time); +// mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); +// } +// #endif /* #ifndef MINIZ_NO_TIME */ + +// archive_name_size = strlen(pArchive_name); +// if (archive_name_size > MZ_UINT16_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + +// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ +// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +// if (!pState->m_zip64) +// { +// /* Bail early if the archive would obviously become too large */ +// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size +// + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + +// pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len +// + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) +// { +// pState->m_zip64 = MZ_TRUE; +// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +// } +// } + +// if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) +// { +// /* Set DOS Subdirectory attribute bit. */ +// ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; + +// /* Subdirectories cannot contain data. */ +// if ((buf_size) || (uncomp_size)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// } + +// /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ +// if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// if ((!store_data_uncompressed) && (buf_size)) +// { +// if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +// return MZ_FALSE; +// } + +// local_dir_header_ofs += num_alignment_padding_bytes; +// if (pZip->m_file_offset_alignment) +// { +// MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); +// } +// cur_archive_file_ofs += num_alignment_padding_bytes; + +// MZ_CLEAR_OBJ(local_dir_header); + +// if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +// { +// method = MZ_DEFLATED; +// } + +// if (pState->m_zip64) +// { +// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) +// { +// pExtra_data = extra_data; +// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +// } + +// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += sizeof(local_dir_header); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } +// cur_archive_file_ofs += archive_name_size; + +// if (pExtra_data != NULL) +// { +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += extra_size; +// } +// } +// else +// { +// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); +// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += sizeof(local_dir_header); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } +// cur_archive_file_ofs += archive_name_size; +// } + +// if (user_extra_data_len > 0) +// { +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += user_extra_data_len; +// } + +// if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) +// { +// uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); +// uncomp_size = buf_size; +// if (uncomp_size <= 3) +// { +// level = 0; +// store_data_uncompressed = MZ_TRUE; +// } +// } + +// if (store_data_uncompressed) +// { +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } + +// cur_archive_file_ofs += buf_size; +// comp_size = buf_size; +// } +// else if (buf_size) +// { +// mz_zip_writer_add_state state; + +// state.m_pZip = pZip; +// state.m_cur_archive_file_ofs = cur_archive_file_ofs; +// state.m_comp_size = 0; + +// if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || +// (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +// return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); +// } + +// comp_size = state.m_comp_size; +// cur_archive_file_ofs = state.m_cur_archive_file_ofs; +// } + +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +// pComp = NULL; + +// if (uncomp_size) +// { +// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; +// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + +// MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); + +// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); +// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); +// if (pExtra_data == NULL) +// { +// if (comp_size > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); +// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); +// } +// else +// { +// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); +// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); +// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; +// } + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) +// return MZ_FALSE; + +// cur_archive_file_ofs += local_dir_footer_size; +// } + +// if (pExtra_data != NULL) +// { +// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +// } + +// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, +// comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, +// user_extra_data_central, user_extra_data_central_len)) +// return MZ_FALSE; + +// pZip->m_total_files++; +// pZip->m_archive_size = cur_archive_file_ofs; + +// return MZ_TRUE; +// } + +// #ifndef MINIZ_NO_STDIO +// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +// { +// if(!pZip) +// { +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// } + +// mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; +// mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; +// mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; +// mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; +// size_t archive_name_size; +// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; +// mz_uint8 *pExtra_data = NULL; +// mz_uint32 extra_size = 0; +// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; +// mz_zip_internal_state *pState; + +// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) +// gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + +// if ((int)level_and_flags < 0) +// level_and_flags = MZ_DEFAULT_LEVEL; +// level = level_and_flags & 0xF; + +// /* Sanity checks */ +// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pState = pZip->m_pState; + +// if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) +// { +// /* Source file is too large for non-zip64 */ +// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +// pState->m_zip64 = MZ_TRUE; +// } + +// /* We could support this, but why? */ +// if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (!mz_zip_writer_validate_archive_name(pArchive_name)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +// if (pState->m_zip64) +// { +// if (pZip->m_total_files == MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +// } +// else +// { +// if (pZip->m_total_files == MZ_UINT16_MAX) +// { +// pState->m_zip64 = MZ_TRUE; +// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ +// } +// } + +// archive_name_size = strlen(pArchive_name); +// if (archive_name_size > MZ_UINT16_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + +// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ +// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +// if (!pState->m_zip64) +// { +// /* Bail early if the archive would obviously become too large */ +// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +// + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 +// + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) +// { +// pState->m_zip64 = MZ_TRUE; +// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ +// } +// } + +// #ifndef MINIZ_NO_TIME +// if (pFile_time) +// { +// mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); +// } +// #endif + +// if (uncomp_size <= 3) +// level = 0; + +// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) +// { +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } + +// cur_archive_file_ofs += num_alignment_padding_bytes; +// local_dir_header_ofs = cur_archive_file_ofs; + +// if (pZip->m_file_offset_alignment) +// { +// MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); +// } + +// if (uncomp_size && level) +// { +// method = MZ_DEFLATED; +// } + +// MZ_CLEAR_OBJ(local_dir_header); +// if (pState->m_zip64) +// { +// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) +// { +// pExtra_data = extra_data; +// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +// } + +// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += sizeof(local_dir_header); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +// { +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } + +// cur_archive_file_ofs += archive_name_size; + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += extra_size; +// } +// else +// { +// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); +// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += sizeof(local_dir_header); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) +// { +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } + +// cur_archive_file_ofs += archive_name_size; +// } + +// if (user_extra_data_len > 0) +// { +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_archive_file_ofs += user_extra_data_len; +// } + +// if (uncomp_size) +// { +// mz_uint64 uncomp_remaining = uncomp_size; +// void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); +// if (!pRead_buf) +// { +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if (!level) +// { +// while (uncomp_remaining) +// { +// mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); +// if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// } +// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); +// uncomp_remaining -= n; +// cur_archive_file_ofs += n; +// } +// comp_size = uncomp_size; +// } +// else +// { +// mz_bool result = MZ_FALSE; +// mz_zip_writer_add_state state; +// tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); +// if (!pComp) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// state.m_pZip = pZip; +// state.m_cur_archive_file_ofs = cur_archive_file_ofs; +// state.m_comp_size = 0; + +// if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); +// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); +// } + +// for (;;) +// { +// size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); +// tdefl_status status; +// tdefl_flush flush = TDEFL_NO_FLUSH; + +// if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) +// { +// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// break; +// } + +// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); +// uncomp_remaining -= in_buf_size; + +// if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) +// flush = TDEFL_FULL_FLUSH; + +// status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); +// if (status == TDEFL_STATUS_DONE) +// { +// result = MZ_TRUE; +// break; +// } +// else if (status != TDEFL_STATUS_OKAY) +// { +// mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); +// break; +// } +// } + +// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + +// if (!result) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +// return MZ_FALSE; +// } + +// comp_size = state.m_comp_size; +// cur_archive_file_ofs = state.m_cur_archive_file_ofs; +// } + +// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); +// } + +// { +// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; +// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + +// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); +// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); +// if (pExtra_data == NULL) +// { +// if (comp_size > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); +// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); +// } +// else +// { +// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); +// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); +// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; +// } + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) +// return MZ_FALSE; + +// cur_archive_file_ofs += local_dir_footer_size; +// } + +// if (pExtra_data != NULL) +// { +// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, +// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); +// } + +// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, +// uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, +// user_extra_data_central, user_extra_data_central_len)) +// return MZ_FALSE; + +// pZip->m_total_files++; +// pZip->m_archive_size = cur_archive_file_ofs; + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +// { +// MZ_FILE *pSrc_file = NULL; +// mz_uint64 uncomp_size = 0; +// MZ_TIME_T file_modified_time; +// MZ_TIME_T *pFile_time = NULL; +// mz_bool status; + +// memset(&file_modified_time, 0, sizeof(file_modified_time)); + +// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) +// pFile_time = &file_modified_time; +// if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); +// #endif + +// pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); +// if (!pSrc_file) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + +// MZ_FSEEK64(pSrc_file, 0, SEEK_END); +// uncomp_size = MZ_FTELL64(pSrc_file); +// MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + +// status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); + +// MZ_FCLOSE(pSrc_file); + +// return status; +// } +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) +// { +// /* + 64 should be enough for any new zip64 data */ +// if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE)) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE); + +// if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start)) +// { +// mz_uint8 new_ext_block[64]; +// mz_uint8 *pDst = new_ext_block; +// mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); +// mz_write_le16(pDst + sizeof(mz_uint16), 0); +// pDst += sizeof(mz_uint16) * 2; + +// if (pUncomp_size) +// { +// mz_write_le64(pDst, *pUncomp_size); +// pDst += sizeof(mz_uint64); +// } + +// if (pComp_size) +// { +// mz_write_le64(pDst, *pComp_size); +// pDst += sizeof(mz_uint64); +// } + +// if (pLocal_header_ofs) +// { +// mz_write_le64(pDst, *pLocal_header_ofs); +// pDst += sizeof(mz_uint64); +// } + +// if (pDisk_start) +// { +// mz_write_le32(pDst, *pDisk_start); +// pDst += sizeof(mz_uint32); +// } + +// mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2)); + +// if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block)) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if ((pExt) && (ext_len)) +// { +// mz_uint32 extra_size_remaining = ext_len; +// const mz_uint8 *pExtra_data = pExt; + +// do +// { +// mz_uint32 field_id, field_data_size, field_total_size; + +// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// field_id = MZ_READ_LE16(pExtra_data); +// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); +// field_total_size = field_data_size + sizeof(mz_uint16) * 2; + +// if (field_total_size > extra_size_remaining) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) +// { +// if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size)) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// pExtra_data += field_total_size; +// extra_size_remaining -= field_total_size; +// } while (extra_size_remaining); +// } + +// return MZ_TRUE; +// } + +/* TODO: This func is now pretty freakin complex due to zip64, split it up? */ +// mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index) +// { +// mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size; +// mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs; +// mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; +// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; +// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; +// mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; +// size_t orig_central_dir_size; +// mz_zip_internal_state *pState; +// void *pBuf; +// const mz_uint8 *pSrc_central_header; +// mz_zip_archive_file_stat src_file_stat; +// mz_uint32 src_filename_len, src_comment_len, src_ext_len; +// mz_uint32 local_header_filename_size, local_header_extra_len; +// mz_uint64 local_header_comp_size, local_header_uncomp_size; +// mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; + +// /* Sanity checks */ +// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pState = pZip->m_pState; + +// /* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */ +// if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// /* Get pointer to the source central dir header and crack it */ +// if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index))) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); +// src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS); +// src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len; + +// /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32 fudge factor in case we need to add more extra data) */ +// if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + +// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + +// if (!pState->m_zip64) +// { +// if (pZip->m_total_files == MZ_UINT16_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +// } +// else +// { +// /* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */ +// if (pZip->m_total_files == MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +// } + +// if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL)) +// return MZ_FALSE; + +// cur_src_file_ofs = src_file_stat.m_local_header_ofs; +// cur_dst_file_ofs = pZip->m_archive_size; + +// /* Read the source archive's local dir header */ +// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + +// cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + +// /* Compute the total size we need to copy (filename+extra data+compressed data) */ +// local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); +// local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); +// local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); +// local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); +// src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size; + +// /* Try to find a zip64 extended information field */ +// if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) +// { +// mz_zip_array file_data_array; +// const mz_uint8 *pExtra_data; +// mz_uint32 extra_size_remaining = local_header_extra_len; + +// mz_zip_array_init(&file_data_array, 1); +// if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE)) +// { +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, src_file_stat.m_local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_size, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) +// { +// mz_zip_array_clear(pZip, &file_data_array); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// } + +// pExtra_data = (const mz_uint8 *)file_data_array.m_p; + +// do +// { +// mz_uint32 field_id, field_data_size, field_total_size; + +// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) +// { +// mz_zip_array_clear(pZip, &file_data_array); +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// } + +// field_id = MZ_READ_LE16(pExtra_data); +// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); +// field_total_size = field_data_size + sizeof(mz_uint16) * 2; + +// if (field_total_size > extra_size_remaining) +// { +// mz_zip_array_clear(pZip, &file_data_array); +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// } + +// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) +// { +// // const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); + +// if (field_data_size < sizeof(mz_uint64) * 2) +// { +// mz_zip_array_clear(pZip, &file_data_array); +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); +// } + +// // local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); +// // local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ + +// found_zip64_ext_data_in_ldir = MZ_TRUE; +// break; +// } + +// pExtra_data += field_total_size; +// extra_size_remaining -= field_total_size; +// } while (extra_size_remaining); + +// mz_zip_array_clear(pZip, &file_data_array); +// } + +// if (!pState->m_zip64) +// { +// /* Try to detect if the new archive will most likely wind up too big and bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which could be present, +64 is a fudge factor). */ +// /* We also check when the archive is finalized so this doesn't need to be perfect. */ +// mz_uint64 approx_new_archive_size = cur_dst_file_ofs + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining + (sizeof(mz_uint32) * 4) + +// pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64; + +// if (approx_new_archive_size >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); +// } + +// /* Write dest archive padding */ +// if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) +// return MZ_FALSE; + +// cur_dst_file_ofs += num_alignment_padding_bytes; + +// local_dir_header_ofs = cur_dst_file_ofs; +// if (pZip->m_file_offset_alignment) +// { +// MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); +// } + +// /* The original zip's local header+ext block doesn't change, even with zip64, so we can just copy it over to the dest zip */ +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + +// /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */ +// if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining))))) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// while (src_archive_bytes_remaining) +// { +// n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining); +// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// } +// cur_src_file_ofs += n; + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } +// cur_dst_file_ofs += n; + +// src_archive_bytes_remaining -= n; +// } + +// /* Now deal with the optional data descriptor */ +// bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); +// if (bit_flags & 8) +// { +// /* Copy data descriptor */ +// if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir)) +// { +// /* src is zip64, dest must be zip64 */ + +// /* name uint32_t's */ +// /* id 1 (optional in zip64?) */ +// /* crc 1 */ +// /* comp_size 2 */ +// /* uncomp_size 2 */ +// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6)) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// } + +// n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5); +// } +// else +// { +// /* src is NOT zip64 */ +// mz_bool has_id; + +// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); +// } + +// has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID); + +// if (pZip->m_pState->m_zip64) +// { +// /* dest is zip64, so upgrade the data descriptor */ +// const mz_uint32 *pSrc_descriptor = (const mz_uint32 *)((const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0)); +// const mz_uint32 src_crc32 = pSrc_descriptor[0]; +// const mz_uint64 src_comp_size = pSrc_descriptor[1]; +// const mz_uint64 src_uncomp_size = pSrc_descriptor[2]; + +// mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID); +// mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32); +// mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size); +// mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size); + +// n = sizeof(mz_uint32) * 6; +// } +// else +// { +// /* dest is NOT zip64, just copy it as-is */ +// n = sizeof(mz_uint32) * (has_id ? 4 : 3); +// } +// } + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) +// { +// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); +// } + +// // cur_src_file_ofs += n; +// cur_dst_file_ofs += n; +// } +// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + +// /* Finally, add the new central dir header */ +// orig_central_dir_size = pState->m_central_dir.m_size; + +// memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + +// if (pState->m_zip64) +// { +// /* This is the painful part: We need to write a new central dir header + ext block with updated zip64 fields, and ensure the old fields (if any) are not included. */ +// const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len; +// mz_zip_array new_ext_block; + +// mz_zip_array_init(&new_ext_block, sizeof(mz_uint8)); + +// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX); +// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX); +// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX); + +// if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL)) +// { +// mz_zip_array_clear(pZip, &new_ext_block); +// return MZ_FALSE; +// } + +// MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size); + +// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) +// { +// mz_zip_array_clear(pZip, &new_ext_block); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len)) +// { +// mz_zip_array_clear(pZip, &new_ext_block); +// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size)) +// { +// mz_zip_array_clear(pZip, &new_ext_block); +// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len + src_ext_len, src_comment_len)) +// { +// mz_zip_array_clear(pZip, &new_ext_block); +// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// mz_zip_array_clear(pZip, &new_ext_block); +// } +// else +// { +// /* sanity checks */ +// if (cur_dst_file_ofs > MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +// if (local_dir_header_ofs >= MZ_UINT32_MAX) +// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + +// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); + +// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + +// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_central_dir_following_data_size)) +// { +// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } +// } + +// /* This shouldn't trigger unless we screwed up during the initial sanity checks */ +// if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) +// { +// /* TODO: Support central dirs >= 32-bits in size */ +// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); +// } + +// n = (mz_uint32)orig_central_dir_size; +// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) +// { +// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); +// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); +// } + +// pZip->m_total_files++; +// pZip->m_archive_size = cur_dst_file_ofs; + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) +// { +// mz_zip_internal_state *pState; +// mz_uint64 central_dir_ofs, central_dir_size; +// mz_uint8 hdr[256]; + +// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// pState = pZip->m_pState; + +// if (pState->m_zip64) +// { +// if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +// } +// else +// { +// if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) +// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); +// } + +// central_dir_ofs = 0; +// central_dir_size = 0; +// if (pZip->m_total_files) +// { +// /* Write central directory */ +// central_dir_ofs = pZip->m_archive_size; +// central_dir_size = pState->m_central_dir.m_size; +// pZip->m_central_directory_file_ofs = central_dir_ofs; +// if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// pZip->m_archive_size += central_dir_size; +// } + +// if (pState->m_zip64) +// { +// /* Write zip64 end of central directory header */ +// mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; + +// MZ_CLEAR_OBJ(hdr); +// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); +// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); +// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ +// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); +// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); +// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); +// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); +// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); +// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; + +// /* Write zip64 end of central directory locator */ +// MZ_CLEAR_OBJ(hdr); +// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); +// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); +// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); +// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; +// } + +// /* Write end of central directory record */ +// MZ_CLEAR_OBJ(hdr); +// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); +// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); +// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); +// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); +// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); + +// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +// #ifndef MINIZ_NO_STDIO +// if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) +// return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; + +// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) +// { +// if ((!ppBuf) || (!pSize)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// *ppBuf = NULL; +// *pSize = 0; + +// if ((!pZip) || (!pZip->m_pState)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (pZip->m_pWrite != mz_zip_heap_write_func) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// if (!mz_zip_writer_finalize_archive(pZip)) +// return MZ_FALSE; + +// *ppBuf = pZip->m_pState->m_pMem; +// *pSize = pZip->m_pState->m_mem_size; +// pZip->m_pState->m_pMem = NULL; +// pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + +// return MZ_TRUE; +// } + +// mz_bool mz_zip_writer_end(mz_zip_archive *pZip) +// { +// return mz_zip_writer_end_internal(pZip, MZ_TRUE); +// } + +// #ifndef MINIZ_NO_STDIO +// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +// { +// return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); +// } + +// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) +// { +// mz_bool status, created_new_archive = MZ_FALSE; +// mz_zip_archive zip_archive; +// struct MZ_FILE_STAT_STRUCT file_stat; +// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + +// mz_zip_zero_struct(&zip_archive); +// if ((int)level_and_flags < 0) +// level_and_flags = MZ_DEFAULT_LEVEL; + +// if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) +// { +// if (pErr) +// *pErr = MZ_ZIP_INVALID_PARAMETER; +// return MZ_FALSE; +// } + +// if (!mz_zip_writer_validate_archive_name(pArchive_name)) +// { +// if (pErr) +// *pErr = MZ_ZIP_INVALID_FILENAME; +// return MZ_FALSE; +// } + +// /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ +// /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ +// if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) +// { +// /* Create a new archive. */ +// if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) +// { +// if (pErr) +// *pErr = zip_archive.m_last_error; +// return MZ_FALSE; +// } + +// created_new_archive = MZ_TRUE; +// } +// else +// { +// /* Append to an existing archive. */ +// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) +// { +// if (pErr) +// *pErr = zip_archive.m_last_error; +// return MZ_FALSE; +// } + +// if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) +// { +// if (pErr) +// *pErr = zip_archive.m_last_error; + +// mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); + +// return MZ_FALSE; +// } +// } + +// status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); +// actual_err = zip_archive.m_last_error; + +// /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ +// if (!mz_zip_writer_finalize_archive(&zip_archive)) +// { +// if (!actual_err) +// actual_err = zip_archive.m_last_error; + +// status = MZ_FALSE; +// } + +// if (!mz_zip_writer_end_internal(&zip_archive, status)) +// { +// if (!actual_err) +// actual_err = zip_archive.m_last_error; + +// status = MZ_FALSE; +// } + +// if ((!status) && (created_new_archive)) +// { +// /* It's a new archive and something went wrong, so just delete it. */ +// int ignoredStatus = MZ_DELETE_FILE(pZip_filename); +// (void)ignoredStatus; +// } + +// if (pErr) +// *pErr = actual_err; + +// return status; +// } + +// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) +// { +// mz_uint32 file_index; +// mz_zip_archive zip_archive; +// void *p = NULL; + +// if (pSize) +// *pSize = 0; + +// if ((!pZip_filename) || (!pArchive_name)) +// { +// if (pErr) +// *pErr = MZ_ZIP_INVALID_PARAMETER; + +// return NULL; +// } + +// mz_zip_zero_struct(&zip_archive); +// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) +// { +// if (pErr) +// *pErr = zip_archive.m_last_error; + +// return NULL; +// } + +// if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) +// { +// p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); +// } + +// mz_zip_reader_end_internal(&zip_archive, p != NULL); + +// if (pErr) +// *pErr = zip_archive.m_last_error; + +// return p; +// } + +// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) +// { +// return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); +// } + +// #endif /* #ifndef MINIZ_NO_STDIO */ + +// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + +/* ------------------- Misc utils */ + +// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) +// { +// return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; +// } + +// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) +// { +// return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; +// } + +// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) +// { +// mz_zip_error prev_err; + +// if (!pZip) +// return MZ_ZIP_INVALID_PARAMETER; + +// prev_err = pZip->m_last_error; + +// pZip->m_last_error = err_num; +// return prev_err; +// } + +// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) +// { +// if (!pZip) +// return MZ_ZIP_INVALID_PARAMETER; + +// return pZip->m_last_error; +// } + +// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) +// { +// return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); +// } + +// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) +// { +// mz_zip_error prev_err; + +// if (!pZip) +// return MZ_ZIP_INVALID_PARAMETER; + +// prev_err = pZip->m_last_error; + +// pZip->m_last_error = MZ_ZIP_NO_ERROR; +// return prev_err; +// } + +// const char *mz_zip_get_error_string(mz_zip_error mz_err) +// { +// switch (mz_err) +// { +// case MZ_ZIP_NO_ERROR: +// return "no error"; +// case MZ_ZIP_UNDEFINED_ERROR: +// return "undefined error"; +// case MZ_ZIP_TOO_MANY_FILES: +// return "too many files"; +// case MZ_ZIP_FILE_TOO_LARGE: +// return "file too large"; +// case MZ_ZIP_UNSUPPORTED_METHOD: +// return "unsupported method"; +// case MZ_ZIP_UNSUPPORTED_ENCRYPTION: +// return "unsupported encryption"; +// case MZ_ZIP_UNSUPPORTED_FEATURE: +// return "unsupported feature"; +// case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: +// return "failed finding central directory"; +// case MZ_ZIP_NOT_AN_ARCHIVE: +// return "not a ZIP archive"; +// case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: +// return "invalid header or archive is corrupted"; +// case MZ_ZIP_UNSUPPORTED_MULTIDISK: +// return "unsupported multidisk archive"; +// case MZ_ZIP_DECOMPRESSION_FAILED: +// return "decompression failed or archive is corrupted"; +// case MZ_ZIP_COMPRESSION_FAILED: +// return "compression failed"; +// case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: +// return "unexpected decompressed size"; +// case MZ_ZIP_CRC_CHECK_FAILED: +// return "CRC-32 check failed"; +// case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: +// return "unsupported central directory size"; +// case MZ_ZIP_ALLOC_FAILED: +// return "allocation failed"; +// case MZ_ZIP_FILE_OPEN_FAILED: +// return "file open failed"; +// case MZ_ZIP_FILE_CREATE_FAILED: +// return "file create failed"; +// case MZ_ZIP_FILE_WRITE_FAILED: +// return "file write failed"; +// case MZ_ZIP_FILE_READ_FAILED: +// return "file read failed"; +// case MZ_ZIP_FILE_CLOSE_FAILED: +// return "file close failed"; +// case MZ_ZIP_FILE_SEEK_FAILED: +// return "file seek failed"; +// case MZ_ZIP_FILE_STAT_FAILED: +// return "file stat failed"; +// case MZ_ZIP_INVALID_PARAMETER: +// return "invalid parameter"; +// case MZ_ZIP_INVALID_FILENAME: +// return "invalid filename"; +// case MZ_ZIP_BUF_TOO_SMALL: +// return "buffer too small"; +// case MZ_ZIP_INTERNAL_ERROR: +// return "internal error"; +// case MZ_ZIP_FILE_NOT_FOUND: +// return "file not found"; +// case MZ_ZIP_ARCHIVE_TOO_LARGE: +// return "archive is too large"; +// case MZ_ZIP_VALIDATION_FAILED: +// return "validation failed"; +// case MZ_ZIP_WRITE_CALLBACK_FAILED: +// return "write calledback failed"; +// default: +// break; +// } + +// return "unknown error"; +// } + +/* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */ +// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) +// { +// if ((!pZip) || (!pZip->m_pState)) +// return MZ_FALSE; + +// return pZip->m_pState->m_zip64; +// } + +// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) +// { +// if ((!pZip) || (!pZip->m_pState)) +// return 0; + +// return pZip->m_pState->m_central_dir.m_size; +// } + +// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) +// { +// return pZip ? pZip->m_total_files : 0; +// } + +// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) +// { +// if (!pZip) +// return 0; +// return pZip->m_archive_size; +// } + +// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) +// { +// if ((!pZip) || (!pZip->m_pState)) +// return 0; +// return pZip->m_pState->m_file_archive_start_ofs; +// } + +// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) +// { +// if ((!pZip) || (!pZip->m_pState)) +// return 0; +// return pZip->m_pState->m_pFile; +// } + +// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) +// { +// if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) +// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + +// return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); +// } + +// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) +// { +// mz_uint n; +// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); +// if (!p) +// { +// if (filename_buf_size) +// pFilename[0] = '\0'; +// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +// return 0; +// } +// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); +// if (filename_buf_size) +// { +// n = MZ_MIN(n, filename_buf_size - 1); +// memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); +// pFilename[n] = '\0'; +// } +// return n + 1; +// } + +// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) +// { +// return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); +// } + +// mz_bool mz_zip_end(mz_zip_archive *pZip) +// { +// if (!pZip) +// return MZ_FALSE; + +// if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) +// return mz_zip_reader_end(pZip); +// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +// else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) +// return mz_zip_writer_end(pZip); +// #endif + +// return MZ_FALSE; +// } + +// #ifdef __cplusplus +// } +// #endif + +// #endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ diff --git a/gomspace/libutil/src/zip/miniz/miniz.h b/gomspace/libutil/src/zip/miniz/miniz.h new file mode 100644 index 00000000..e5172634 --- /dev/null +++ b/gomspace/libutil/src/zip/miniz/miniz.h @@ -0,0 +1,1329 @@ +/* miniz.c 2.0.6 beta - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated Oct. 13, 2013 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + + Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define + MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). + + * Low-level Deflate/Inflate implementation notes: + + Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or + greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses + approximately as well as zlib. + + Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function + coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory + block large enough to hold the entire file. + + The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. + + * zlib-style API notes: + + miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in + zlib replacement in many apps: + The z_stream struct, optional memory allocation callbacks + deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound + inflateInit/inflateInit2/inflate/inflateEnd + compress, compress2, compressBound, uncompress + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. + Supports raw deflate streams or standard zlib streams with adler-32 checking. + + Limitations: + The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. + I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but + there are no guarantees that miniz.c pulls this off perfectly. + + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by + Alex Evans. Supports 1-4 bytes/pixel images. + + * ZIP archive API notes: + + The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to + get the job done with minimal fuss. There are simple API's to retrieve file information, read files from + existing archives, create new archives, append new files to existing archives, or clone archive data from + one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), + or you can specify custom file read/write callbacks. + + - Archive reading: Just call this function to read a single file from a disk archive: + + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + + For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central + directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. + + - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + + The locate operation can optionally check file comments too, which (as one example) can be used to identify + multiple versions of the same file in an archive. This function uses a simple linear search through the central + directory, so it's not very fast. + + Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and + retrieve detailed info on each file by calling mz_zip_reader_file_stat(). + + - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data + to disk and builds an exact image of the central directory in memory. The central directory image is written + all at once at the end of the archive file when the archive is finalized. + + The archive writer can optionally align each file's local header and file data to any power of 2 alignment, + which can be useful when the archive will be read from optical media. Also, the writer supports placing + arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still + readable by any ZIP tool. + + - Archive appending: The simple way to add a single file to an archive is to call this function: + + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, + const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + + The archive will be created if it doesn't already exist, otherwise it'll be appended to. + Note the appending is done in-place and is not an atomic operation, so if something goes wrong + during the operation it's possible the archive could be left without a central directory (although the local + file headers and file data will be fine, so the archive will be recoverable). + + For more complex archive modification scenarios: + 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to + preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the + compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and + you're done. This is safe but requires a bunch of temporary disk space or heap memory. + + 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), + append new files as needed, then finalize the archive which will write an updated central directory to the + original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a + possibility that the archive's central directory could be lost with this method if anything goes wrong, though. + + - ZIP archive support limitations: + No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. + Requires streams capable of seeking. + + * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the + below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. + + * Important: For best perf. be sure to customize the below macros for your target platform: + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 + #define MINIZ_LITTLE_ENDIAN 1 + #define MINIZ_HAS_64BIT_REGISTERS 1 + + * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz + uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files + (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). +*/ +#pragma once + + + + + +/* Defines to completely disable specific portions of miniz.c: + If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. */ + +/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */ +/*#define MINIZ_NO_STDIO */ + +/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */ +/* get/set file times, and the C run-time funcs that get/set times won't be called. */ +/* The current downside is the times written to your archives will be from 1979. */ +#define MINIZ_NO_TIME + +/* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */ +/*#define MINIZ_NO_ARCHIVE_APIS */ + +/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */ +/*#define MINIZ_NO_ARCHIVE_WRITING_APIS */ + +/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */ +/*#define MINIZ_NO_ZLIB_APIS */ + +/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */ +/*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ + +/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. + Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc + callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user + functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */ +/*#define MINIZ_NO_MALLOC */ + +#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) +/* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux */ +#define MINIZ_NO_TIME +#endif + +#include + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) +#include +#endif + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) +/* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */ +#define MINIZ_X86_OR_X64_CPU 1 +#else +#define MINIZ_X86_OR_X64_CPU 0 +#endif + +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ +#define MINIZ_LITTLE_ENDIAN 1 +#else +#define MINIZ_LITTLE_ENDIAN 0 +#endif + +// #if MINIZ_X86_OR_X64_CPU +/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */ +// #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +// #else +// #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 +// #endif +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 + +#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) +/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). */ +#define MINIZ_HAS_64BIT_REGISTERS 1 +#else +#define MINIZ_HAS_64BIT_REGISTERS 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- zlib-style API Definitions. */ + +/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */ +typedef unsigned long mz_ulong; + +/* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. */ +void mz_free(void *p); + +#define MZ_ADLER32_INIT (1) +/* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */ +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + +#define MZ_CRC32_INIT (0) +/* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ +// mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + +/* Compression strategies. */ +enum +{ + MZ_DEFAULT_STRATEGY = 0, + MZ_FILTERED = 1, + MZ_HUFFMAN_ONLY = 2, + MZ_RLE = 3, + MZ_FIXED = 4 +}; + +/* Method */ +#define MZ_DEFLATED 8 + +/* Heap allocation callbacks. +Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. */ +typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void *opaque, void *address); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); + +/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */ +enum +{ + MZ_NO_COMPRESSION = 0, + MZ_BEST_SPEED = 1, + MZ_BEST_COMPRESSION = 9, + MZ_UBER_COMPRESSION = 10, + MZ_DEFAULT_LEVEL = 6, + MZ_DEFAULT_COMPRESSION = -1 +}; + +#define MZ_VERSION "10.0.1" +#define MZ_VERNUM 0xA010 +#define MZ_VER_MAJOR 10 +#define MZ_VER_MINOR 0 +#define MZ_VER_REVISION 1 +#define MZ_VER_SUBREVISION 0 + +#ifndef MINIZ_NO_ZLIB_APIS + +/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). */ +enum +{ + MZ_NO_FLUSH = 0, + MZ_PARTIAL_FLUSH = 1, + MZ_SYNC_FLUSH = 2, + MZ_FULL_FLUSH = 3, + MZ_FINISH = 4, + MZ_BLOCK = 5 +}; + +/* Return status codes. MZ_PARAM_ERROR is non-standard. */ +enum +{ + MZ_OK = 0, + MZ_STREAM_END = 1, + MZ_NEED_DICT = 2, + MZ_ERRNO = -1, + MZ_STREAM_ERROR = -2, + MZ_DATA_ERROR = -3, + MZ_MEM_ERROR = -4, + MZ_BUF_ERROR = -5, + MZ_VERSION_ERROR = -6, + MZ_PARAM_ERROR = -10000 +}; + +/* Window bits */ +#define MZ_DEFAULT_WINDOW_BITS 15 + +struct mz_internal_state; + +/* Compression/decompression stream struct. */ +typedef struct mz_stream_s +{ + const unsigned char *next_in; /* pointer to next byte to read */ + unsigned int avail_in; /* number of bytes available at next_in */ + mz_ulong total_in; /* total number of bytes consumed so far */ + + unsigned char *next_out; /* pointer to next byte to write */ + unsigned int avail_out; /* number of bytes that can be written to next_out */ + mz_ulong total_out; /* total number of bytes produced so far */ + + char *msg; /* error msg (unused) */ + struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */ + + mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */ + mz_free_func zfree; /* optional heap free function (defaults to free) */ + void *opaque; /* heap alloc function user pointer */ + + int data_type; /* data_type (unused) */ + mz_ulong adler; /* adler32 of the source or uncompressed data */ + mz_ulong reserved; /* not used */ +} mz_stream; + +typedef mz_stream *mz_streamp; + +/* Returns the version string of miniz.c. */ +// const char *mz_version(void); + +/* mz_deflateInit() initializes a compressor with default options: */ +/* Parameters: */ +/* pStream must point to an initialized mz_stream struct. */ +/* level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */ +/* level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. */ +/* (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */ +/* Return values: */ +/* MZ_OK on success. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_PARAM_ERROR if the input parameters are bogus. */ +/* MZ_MEM_ERROR on out of memory. */ +int mz_deflateInit(mz_streamp pStream, int level); + +/* mz_deflateInit2() is like mz_deflate(), except with more control: */ +/* Additional parameters: */ +/* method must be MZ_DEFLATED */ +/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */ +/* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */ +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); + +/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ +// int mz_deflateReset(mz_streamp pStream); + +/* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */ +/* Parameters: */ +/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ +/* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */ +/* Return values: */ +/* MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). */ +/* MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_PARAM_ERROR if one of the parameters is invalid. */ +/* MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) */ +int mz_deflate(mz_streamp pStream, int flush); + +/* mz_deflateEnd() deinitializes a compressor: */ +/* Return values: */ +/* MZ_OK on success. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +int mz_deflateEnd(mz_streamp pStream); + +/* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ +// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + +/* Single-call compression functions mz_compress() and mz_compress2(): */ +/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); + +/* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */ +// mz_ulong mz_compressBound(mz_ulong source_len); + +/* Initializes a decompressor. */ +int mz_inflateInit(mz_streamp pStream); + +/* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: */ +/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */ +int mz_inflateInit2(mz_streamp pStream, int window_bits); + +/* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. */ +/* Parameters: */ +/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ +/* flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */ +/* On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). */ +/* MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. */ +/* Return values: */ +/* MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. */ +/* MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_DATA_ERROR if the deflate stream is invalid. */ +/* MZ_PARAM_ERROR if one of the parameters is invalid. */ +/* MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again */ +/* with more input data, or with more room in the output buffer (except when using single call decompression, described above). */ +int mz_inflate(mz_streamp pStream, int flush); + +/* Deinitializes a decompressor. */ +int mz_inflateEnd(mz_streamp pStream); + +/* Single-call decompression. */ +/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */ +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); + +/* Returns a string description of the specified error code, or NULL if the error code is invalid. */ +// const char *mz_error(int err); + +/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */ +/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ +#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES +typedef unsigned char Byte; +typedef unsigned int uInt; +typedef mz_ulong uLong; +typedef Byte Bytef; +typedef uInt uIntf; +typedef char charf; +typedef int intf; +typedef void *voidpf; +typedef uLong uLongf; +typedef void *voidp; +typedef void *const voidpc; +#define Z_NULL 0 +#define Z_NO_FLUSH MZ_NO_FLUSH +#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH +#define Z_SYNC_FLUSH MZ_SYNC_FLUSH +#define Z_FULL_FLUSH MZ_FULL_FLUSH +#define Z_FINISH MZ_FINISH +#define Z_BLOCK MZ_BLOCK +#define Z_OK MZ_OK +#define Z_STREAM_END MZ_STREAM_END +#define Z_NEED_DICT MZ_NEED_DICT +#define Z_ERRNO MZ_ERRNO +#define Z_STREAM_ERROR MZ_STREAM_ERROR +#define Z_DATA_ERROR MZ_DATA_ERROR +#define Z_MEM_ERROR MZ_MEM_ERROR +#define Z_BUF_ERROR MZ_BUF_ERROR +#define Z_VERSION_ERROR MZ_VERSION_ERROR +#define Z_PARAM_ERROR MZ_PARAM_ERROR +#define Z_NO_COMPRESSION MZ_NO_COMPRESSION +#define Z_BEST_SPEED MZ_BEST_SPEED +#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION +#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION +#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY +#define Z_FILTERED MZ_FILTERED +#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY +#define Z_RLE MZ_RLE +#define Z_FIXED MZ_FIXED +#define Z_DEFLATED MZ_DEFLATED +#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS +#define alloc_func mz_alloc_func +#define free_func mz_free_func +#define internal_state mz_internal_state +#define z_stream mz_stream +#define deflateInit mz_deflateInit +#define deflateInit2 mz_deflateInit2 +// #define deflateReset mz_deflateReset +#define deflate mz_deflate +#define deflateEnd mz_deflateEnd +// #define deflateBound mz_deflateBound +#define compress mz_compress +#define compress2 mz_compress2 +// #define compressBound mz_compressBound +#define inflateInit mz_inflateInit +#define inflateInit2 mz_inflateInit2 +#define inflate mz_inflate +#define inflateEnd mz_inflateEnd +#define uncompress mz_uncompress +// #define crc32 mz_crc32 +#define adler32 mz_adler32 +#define MAX_WBITS 15 +#define MAX_MEM_LEVEL 9 +// #define zError mz_error +#define ZLIB_VERSION MZ_VERSION +#define ZLIB_VERNUM MZ_VERNUM +#define ZLIB_VER_MAJOR MZ_VER_MAJOR +#define ZLIB_VER_MINOR MZ_VER_MINOR +#define ZLIB_VER_REVISION MZ_VER_REVISION +#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION +// #define zlibVersion mz_version +// #define zlib_version mz_version() +#endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ + +#endif /* MINIZ_NO_ZLIB_APIS */ + +#ifdef __cplusplus +} +#endif +#pragma once +#include +#include +#include +#include + +/* ------------------- Types and macros */ +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef int64_t mz_int64; +typedef uint64_t mz_uint64; +typedef int mz_bool; + +#define MZ_FALSE (0) +#define MZ_TRUE (1) + +/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */ +#ifdef _MSC_VER +#define MZ_MACRO_END while (0, 0) +#else +#define MZ_MACRO_END while (0) +#endif + +#ifdef MINIZ_NO_STDIO +#define MZ_FILE void * +#else +#include +#define MZ_FILE FILE +#endif /* #ifdef MINIZ_NO_STDIO */ + +// #ifdef MINIZ_NO_TIME +// typedef struct mz_dummy_time_t_tag +// { +// int m_dummy; +// } mz_dummy_time_t; +// #define MZ_TIME_T mz_dummy_time_t +// #else +// #define MZ_TIME_T time_t +// #endif + +#define MZ_ASSERT(x) assert(x) + +#ifdef MINIZ_NO_MALLOC +#define MZ_MALLOC(x) NULL +#define MZ_FREE(x) (void)x, ((void)0) +#define MZ_REALLOC(p, x) NULL +#else +#define MZ_MALLOC(x) malloc(x) +#define MZ_FREE(x) free(x) +#define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) +#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else +#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) +#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#define MZ_READ_LE64(p) (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U)) + +#ifdef _MSC_VER +#define MZ_FORCEINLINE __forceinline +#elif defined(__GNUC__) +#define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__)) +#else +#define MZ_FORCEINLINE inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +extern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); +extern void miniz_def_free_func(void *opaque, void *address); +// extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); + +#define MZ_UINT16_MAX (0xFFFFU) +#define MZ_UINT32_MAX (0xFFFFFFFFU) + +#ifdef __cplusplus +} +#endif +#pragma once + + +#ifdef __cplusplus +extern "C" { +#endif +/* ------------------- Low-level Compression API Definitions */ + +/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). */ +#define TDEFL_LESS_MEMORY 0 + +/* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): */ +/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */ +enum +{ + TDEFL_HUFFMAN_ONLY = 0, + TDEFL_DEFAULT_MAX_PROBES = 128, + TDEFL_MAX_PROBES_MASK = 0xFFF +}; + +/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. */ +/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */ +/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */ +/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). */ +/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */ +/* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */ +/* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */ +/* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */ +/* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). */ +enum +{ + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 +}; + +/* High level compression functions: */ +/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */ +/* On entry: */ +/* pSrc_buf, src_buf_len: Pointer and size of source block to compress. */ +/* flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. */ +/* On return: */ +/* Function returns a pointer to the compressed data, or NULL on failure. */ +/* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */ +/* The caller must free() the returned block when it's no longer needed. */ +// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ +/* Returns 0 on failure. */ +// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +/* Compresses an image to a compressed PNG file in memory. */ +/* On entry: */ +/* pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */ +/* The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. */ +/* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */ +/* If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */ +/* On return: */ +/* Function returns a pointer to the compressed data, or NULL on failure. */ +/* *pLen_out will be set to the size of the PNG image file. */ +/* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */ +// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); +// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); + +/* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); + +/* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */ +// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +enum +{ + TDEFL_MAX_HUFF_TABLES = 3, + TDEFL_MAX_HUFF_SYMBOLS_0 = 288, + TDEFL_MAX_HUFF_SYMBOLS_1 = 32, + TDEFL_MAX_HUFF_SYMBOLS_2 = 19, + TDEFL_LZ_DICT_SIZE = 32768, + TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, + TDEFL_MIN_MATCH_LEN = 3, + TDEFL_MAX_MATCH_LEN = 258 +}; + +/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). */ +#if TDEFL_LESS_MEMORY +enum +{ + TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 12, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#else +enum +{ + TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 15, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#endif + +/* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. */ +typedef enum { + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1 +} tdefl_status; + +/* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */ +typedef enum { + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 +} tdefl_flush; + +/* tdefl's compression state structure. */ +typedef struct +{ + tdefl_put_buf_func_ptr m_pPut_buf_func; + void *m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; + tdefl_status m_prev_return_status; + const void *m_pIn_buf; + void *m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8 *m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; +} tdefl_compressor; + +/* Initializes the compressor. */ +/* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */ +/* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. */ +/* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */ +/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */ +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +/* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. */ +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); + +/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ +/* tdefl_compress_buffer() always consumes the entire input buffer. */ +// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); + +// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); +mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + +/* Create tdefl_compress() flags given zlib-style compression parameters. */ +/* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */ +/* window_bits may be -15 (raw deflate) or 15 (zlib) */ +/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */ +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); + +/* Allocate the tdefl_compressor structure in C so that */ +/* non-C language bindings to tdefl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ +// tdefl_compressor *tdefl_compressor_alloc(); +// void tdefl_compressor_free(tdefl_compressor *pComp); + +#ifdef __cplusplus +} +#endif +#pragma once + +/* ------------------- Low-level Decompression API Definitions */ + +#ifdef __cplusplus +extern "C" { +#endif +/* Decompression flags used by tinfl_decompress(). */ +/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. */ +/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. */ +/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */ +/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */ +enum +{ + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +/* High level decompression functions: */ +/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */ +/* On entry: */ +/* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */ +/* On return: */ +/* Function returns a pointer to the decompressed data, or NULL on failure. */ +/* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */ +/* The caller must call mz_free() on the returned block when it's no longer needed. */ +// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ +/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */ +/* Returns 1 on success or 0 on failure. */ +typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); +// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +struct tinfl_decompressor_tag; +typedef struct tinfl_decompressor_tag tinfl_decompressor; + +/* Allocate the tinfl_decompressor structure in C so that */ +/* non-C language bindings to tinfl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ + +// tinfl_decompressor *tinfl_decompressor_alloc(); +// void tinfl_decompressor_free(tinfl_decompressor *pDecomp); + +/* Max size of LZ dictionary. */ +#define TINFL_LZ_DICT_SIZE 32768 + +/* Return status. */ +typedef enum { + /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is indicating that no more are available. The compressed data */ + /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input but this is a BAD sign (either the data is corrupted or you called it incorrectly). */ + /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */ + TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4, + + /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, but if you get this error the calling code is wrong.) */ + TINFL_STATUS_BAD_PARAM = -3, + + /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you call it again it'll return TINFL_STATUS_DONE. */ + TINFL_STATUS_ADLER32_MISMATCH = -2, + + /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */ + TINFL_STATUS_FAILED = -1, + + /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */ + + /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte that it needed, has successfully reached the end of the deflate stream, and */ + /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If you call it again you'll just get TINFL_STATUS_DONE over and over again. */ + TINFL_STATUS_DONE = 0, + + /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */ + /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also possible (but unlikely) for the inflator to keep on demanding input to */ + /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */ + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + + /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write this data into the output buffer. */ + /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed data to the caller. I've been assuming you know how much uncompressed data to expect */ + /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure streaming scenarios where you have no idea how many bytes to expect this may not be possible */ + /* so I may need to add some code to address this. */ + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +/* Initializes the decompressor to its initial state. */ +#define tinfl_init(r) \ + do \ + { \ + (r)->m_state = 0; \ + } \ + MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */ +/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */ +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); + +/* Internal/private bits follow. */ +enum +{ + TINFL_MAX_HUFF_TABLES = 3, + TINFL_MAX_HUFF_SYMBOLS_0 = 288, + TINFL_MAX_HUFF_SYMBOLS_1 = 32, + TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, + TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +typedef struct +{ + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS +#define TINFL_USE_64BIT_BITBUF 1 +#else +#define TINFL_USE_64BIT_BITBUF 0 +#endif + +#if TINFL_USE_64BIT_BITBUF +typedef mz_uint64 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (64) +#else +typedef mz_uint32 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag +{ + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +#ifdef __cplusplus +} +#endif + +#pragma once + + +/* ------------------- ZIP archive reading/writing */ + +// #ifndef MINIZ_NO_ARCHIVE_APIS + +// #ifdef __cplusplus +// extern "C" { +// #endif + +// enum +// { + /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ +// MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, +// MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, +// MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 +// }; + +// typedef struct +// { +// /* Central directory file index. */ +// mz_uint32 m_file_index; + +// /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ +// mz_uint64 m_central_dir_ofs; + +// /* These fields are copied directly from the zip's central dir. */ +// mz_uint16 m_version_made_by; +// mz_uint16 m_version_needed; +// mz_uint16 m_bit_flag; +// mz_uint16 m_method; + +// #ifndef MINIZ_NO_TIME +// MZ_TIME_T m_time; +// #endif + +// /* CRC-32 of uncompressed data. */ +// mz_uint32 m_crc32; + +// /* File's compressed size. */ +// mz_uint64 m_comp_size; + +// /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ +// mz_uint64 m_uncomp_size; + +// /* Zip internal and external file attributes. */ +// mz_uint16 m_internal_attr; +// mz_uint32 m_external_attr; + +// /* Entry's local header file offset in bytes. */ +// mz_uint64 m_local_header_ofs; + +// /* Size of comment in bytes. */ +// mz_uint32 m_comment_size; + +// /* MZ_TRUE if the entry appears to be a directory. */ +// mz_bool m_is_directory; + +// /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ +// mz_bool m_is_encrypted; + +// /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ +// mz_bool m_is_supported; + +// /* Filename. If string ends in '/' it's a subdirectory entry. */ +// /* Guaranteed to be zero terminated, may be truncated to fit. */ +// char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + +// /* Comment field. */ +// /* Guaranteed to be zero terminated, may be truncated to fit. */ +// char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; + +// } mz_zip_archive_file_stat; + +// typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); +// typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); +// typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); + +// struct mz_zip_internal_state_tag; +// typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + +// typedef enum { +// MZ_ZIP_MODE_INVALID = 0, +// MZ_ZIP_MODE_READING = 1, +// MZ_ZIP_MODE_WRITING = 2, +// MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 +// } mz_zip_mode; + +// typedef enum { +// MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, +// MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, +// MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, +// MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, + // MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ + // MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ + // MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ +// MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, +// MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 +// } mz_zip_flags; + +// typedef enum { +// MZ_ZIP_TYPE_INVALID = 0, +// MZ_ZIP_TYPE_USER, +// MZ_ZIP_TYPE_MEMORY, +// MZ_ZIP_TYPE_HEAP, +// MZ_ZIP_TYPE_FILE, +// MZ_ZIP_TYPE_CFILE, +// MZ_ZIP_TOTAL_TYPES +// } mz_zip_type; + +/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ +// typedef enum { +// MZ_ZIP_NO_ERROR = 0, +// MZ_ZIP_UNDEFINED_ERROR, +// MZ_ZIP_TOO_MANY_FILES, +// MZ_ZIP_FILE_TOO_LARGE, +// MZ_ZIP_UNSUPPORTED_METHOD, +// MZ_ZIP_UNSUPPORTED_ENCRYPTION, +// MZ_ZIP_UNSUPPORTED_FEATURE, +// MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, +// MZ_ZIP_NOT_AN_ARCHIVE, +// MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, +// MZ_ZIP_UNSUPPORTED_MULTIDISK, +// MZ_ZIP_DECOMPRESSION_FAILED, +// MZ_ZIP_COMPRESSION_FAILED, +// MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, +// MZ_ZIP_CRC_CHECK_FAILED, +// MZ_ZIP_UNSUPPORTED_CDIR_SIZE, +// MZ_ZIP_ALLOC_FAILED, +// MZ_ZIP_FILE_OPEN_FAILED, +// MZ_ZIP_FILE_CREATE_FAILED, +// MZ_ZIP_FILE_WRITE_FAILED, +// MZ_ZIP_FILE_READ_FAILED, +// MZ_ZIP_FILE_CLOSE_FAILED, +// MZ_ZIP_FILE_SEEK_FAILED, +// MZ_ZIP_FILE_STAT_FAILED, +// MZ_ZIP_INVALID_PARAMETER, +// MZ_ZIP_INVALID_FILENAME, +// MZ_ZIP_BUF_TOO_SMALL, +// MZ_ZIP_INTERNAL_ERROR, +// MZ_ZIP_FILE_NOT_FOUND, +// MZ_ZIP_ARCHIVE_TOO_LARGE, +// MZ_ZIP_VALIDATION_FAILED, +// MZ_ZIP_WRITE_CALLBACK_FAILED, +// MZ_ZIP_TOTAL_ERRORS +// } mz_zip_error; + +// typedef struct +// { +// mz_uint64 m_archive_size; +// mz_uint64 m_central_directory_file_ofs; + +// /* We only support up to UINT32_MAX files in zip64 mode. */ +// mz_uint32 m_total_files; +// mz_zip_mode m_zip_mode; +// mz_zip_type m_zip_type; +// mz_zip_error m_last_error; + +// mz_uint64 m_file_offset_alignment; + +// mz_alloc_func m_pAlloc; +// mz_free_func m_pFree; +// mz_realloc_func m_pRealloc; +// void *m_pAlloc_opaque; + +// mz_file_read_func m_pRead; +// mz_file_write_func m_pWrite; +// mz_file_needs_keepalive m_pNeeds_keepalive; +// void *m_pIO_opaque; + +// mz_zip_internal_state *m_pState; + +// } mz_zip_archive; + +// typedef struct +// { +// mz_zip_archive *pZip; +// mz_uint flags; + +// int status; +// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS +// mz_uint file_crc32; +// #endif +// mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; +// mz_zip_archive_file_stat file_stat; +// void *pRead_buf; +// void *pWrite_buf; + +// size_t out_blk_remain; + +// tinfl_decompressor inflator; + +// } mz_zip_reader_extract_iter_state; + +/* -------- ZIP reading */ + +/* Inits a ZIP archive reader. */ +/* These functions read and validate the archive's central directory. */ +// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); + +// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); + +// #ifndef MINIZ_NO_STDIO +/* Read a archive from a disk file. */ +/* file_start_ofs is the file offset where the archive actually begins, or 0. */ +/* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */ +// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); +// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); + +/* Read an archive from an already opened FILE, beginning at the current file position. */ +/* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */ +/* The FILE will NOT be closed when mz_zip_reader_end() is called. */ +// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); +// #endif + +/* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */ +// mz_bool mz_zip_reader_end(mz_zip_archive *pZip); + +/* -------- ZIP reading or writing */ + +/* Clears a mz_zip_archive struct to all zeros. */ +/* Important: This must be done before passing the struct to any mz_zip functions. */ +// void mz_zip_zero_struct(mz_zip_archive *pZip); + +// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); +// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); + +/* Returns the total number of files in the archive. */ +// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); + +// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); +// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); +// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); + +/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ +// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); + +/* Attempts to locates a file in the archive's central directory. */ +/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ +/* Returns -1 if the file cannot be found. */ +// int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); +/* Returns MZ_FALSE if the file cannot be found. */ +// mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex); + +/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */ +/* Note that the m_last_error functionality is not thread safe. */ +// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); +// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); +// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); +// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); +// const char *mz_zip_get_error_string(mz_zip_error mz_err); + +/* MZ_TRUE if the archive file entry is a directory entry. */ +// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); + +/* MZ_TRUE if the file is encrypted/strong encrypted. */ +// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); + +/* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */ +// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); + +/* Retrieves the filename of an archive file entry. */ +/* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */ +// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); + +/* Attempts to locates a file in the archive's central directory. */ +/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ +/* Returns -1 if the file cannot be found. */ +// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); +// int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); + +/* Returns detailed information about an archive file entry. */ +// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); + +/* MZ_TRUE if the file is in zip64 format. */ +/* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */ +// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); + +/* Returns the total central directory size in bytes. */ +/* The current max supported size is <= MZ_UINT32_MAX. */ +// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); + +/* Extracts a archive file to a memory buffer using no memory allocation. */ +/* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ +// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); +// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + +/* Extracts a archive file to a memory buffer. */ +// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); +// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); + +/* Extracts a archive file to a dynamically allocated heap buffer. */ +/* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ +/* Returns NULL and sets the last error on failure. */ +// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); +// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); + +/* Extracts a archive file using a callback function to output the file's data. */ +// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); +// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); + +/* Extract a file iteratively */ +// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); +// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); +// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); +// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); + +// #ifndef MINIZ_NO_STDIO +/* Extracts a archive file to a disk file and sets its last accessed and modified times. */ +/* This function only extracts files, not archive directory records. */ +// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); +// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); + +/* Extracts a archive file starting at the current position in the destination FILE stream. */ +// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); +// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); +// #endif + +#if 0 +/* TODO */ + typedef void *mz_zip_streaming_extract_state_ptr; + mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); + uint64_t mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); + uint64_t mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); + mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, uint64_t new_ofs); + size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size); + mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); +#endif + +/* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */ +/* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */ +// mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); + +/* Validates an entire archive by calling mz_zip_validate_file() on each file. */ +// mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags); + +/* Misc utils/helpers, valid for ZIP reading or writing */ +// mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr); +// mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); + +/* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ +// mz_bool mz_zip_end(mz_zip_archive *pZip); + +/* -------- ZIP writing */ + +// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +/* Inits a ZIP archive writer. */ +/*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ +/*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ +// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); +// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); + +// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); +// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); + +// #ifndef MINIZ_NO_STDIO +// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); +// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); +// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); +// #endif + +/* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */ +/* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ +/* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). */ +/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */ +/* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */ +/* the archive is finalized the file's central directory will be hosed. */ +// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); +// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); + +/* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */ +/* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); + +/* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */ +/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ +// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); + +// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, +// const char *user_extra_data_central, mz_uint user_extra_data_central_len); + +// #ifndef MINIZ_NO_STDIO +/* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + +/* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ +// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, +// const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, +// const char *user_extra_data_central, mz_uint user_extra_data_central_len); +// #endif + +/* Adds a file to an archive by fully cloning the data from another archive. */ +/* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */ +// mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index); + +/* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ +/* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ +/* An archive must be manually finalized by calling this function for it to be valid. */ +// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); + +/* Finalizes a heap archive, returning a poiner to the heap block and its size. */ +/* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ +// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); + +/* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ +/* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */ +// mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + +/* -------- Misc. high-level helper functions: */ + +/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */ +/* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +/* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */ +// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); + +/* Reads a single file from an archive into a heap block. */ +/* If pComment is not NULL, only the file with the specified comment will be extracted. */ +/* Returns NULL on failure. */ +// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); +// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); + +// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + +// #ifdef __cplusplus +// } +// #endif + +// #endif /* MINIZ_NO_ARCHIVE_APIS */ diff --git a/gomspace/libutil/src/zip/zip.c b/gomspace/libutil/src/zip/zip.c new file mode 100644 index 00000000..b7fd00fc --- /dev/null +++ b/gomspace/libutil/src/zip/zip.c @@ -0,0 +1,357 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include "gs/util/zip/zip.h" +#include "miniz/miniz.h" + +#include +#include +#include + +#include + +static void cleanup(FILE *pInfile, FILE *pOutfile, uint8_t *stream_inbuf, uint8_t *stream_outbuf) +{ + if(pInfile) + fclose(pInfile); + + if(pOutfile) + fclose(pOutfile); + + if(stream_inbuf) + free(stream_inbuf); + + if(stream_outbuf) + free(stream_outbuf); +} + +int gs_zip_compress_file(const char *src, const char *dest) +{ + FILE *pInfile, *pOutfile; + uint32_t infile_size; + long file_loc; + + // Open input file. + pInfile = fopen(src, "rb"); + if (!pInfile) + { + log_error("Zip compress: Failed opening input file!"); + return GS_ERROR_IO; + } + + // Determine input file's size. + fseek(pInfile, 0, SEEK_END); + file_loc = ftell(pInfile); + fseek(pInfile, 0, SEEK_SET); + + if((file_loc < 0) || ((unsigned long)file_loc > UINT_MAX)) + { + log_error("Zip compress: File is too large to be processed."); + fclose(pInfile); + + return GS_ERROR_IO; + } + + infile_size = (uint32_t)file_loc; + uint32_t buffer_size = infile_size; + + // Allocate input buffer memory + uint8_t *stream_inbuf = malloc(buffer_size); + if (stream_inbuf == NULL) + { + log_error("Zip compress: Failed to allocate input buffer memory"); + fclose(pInfile); + + return GS_ERROR_IO; + } + + // Allocate output buffer memory + uint8_t *stream_outbuf = malloc(buffer_size); + if (stream_outbuf == NULL) + { + log_error("Zip compress: Failed to allocate output buffer memory"); + cleanup(pInfile, NULL, stream_inbuf, NULL); + + return GS_ERROR_IO; + } + + // Open output file. + pOutfile = fopen(dest, "wb"); + if (!pOutfile) + { + log_error("Zip compress: Failed opening output file!"); + cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); + + return GS_ERROR_IO; + } + + // Init the z_stream + z_stream stream; + memset(&stream, 0, sizeof(stream)); + stream.next_in = stream_inbuf; + stream.avail_in = 0; + stream.next_out = stream_outbuf; + stream.avail_out = buffer_size; + + // Compression. + uint32_t infile_remaining = infile_size; + + if(deflateInit(&stream, Z_BEST_COMPRESSION) != Z_OK) + { + log_error("Zip compress: deflateInit() failed!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_DATA; + } + + for( ; ; ) + { + int status; + if(!stream.avail_in) + { + // Input buffer is empty, so read more bytes from input file. + uint32_t n = gs_min((uint32_t)buffer_size, infile_remaining); + + if (fread(stream_inbuf, 1, n, pInfile) != n) + { + log_error("Zip compress: Failed reading from input file!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_IO; + } + + stream.next_in = stream_inbuf; + stream.avail_in = n; + + infile_remaining -= n; + } + + status = deflate(&stream, infile_remaining ? Z_NO_FLUSH : Z_FINISH); + + if((status == Z_STREAM_END) || (!stream.avail_out)) + { + // Output buffer is full, or compression is done, so write buffer to output file. + uint32_t n = buffer_size - stream.avail_out; + if (fwrite(stream_outbuf, 1, n, pOutfile) != n) + { + log_error("Zip compress: Failed writing to output file!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_IO; + } + + stream.next_out = stream_outbuf; + stream.avail_out = buffer_size; + } + + if(status == Z_STREAM_END) + { + break; + } + else if(status != Z_OK) + { + log_error("Zip compress: deflate() failed with status %i!", status); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_DATA; + } + } + + if(deflateEnd(&stream) != Z_OK) + { + log_error("Zip compress: deflateEnd() failed!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_DATA; + } + + + cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); + if(EOF == fclose(pOutfile)) + { + log_error("Zip compress: Failed writing to output file!"); + return GS_ERROR_IO; + } + + log_debug("Total input bytes: %u\n", (mz_uint32)stream.total_in); + log_debug("Total output bytes: %u\n", (mz_uint32)stream.total_out); + log_debug("Success.\n"); + + return GS_OK; +} + +int gs_zip_decompress_file(const char *src, const char *dest) +{ + FILE *pInfile, *pOutfile; + uint32_t infile_size; + long file_loc; + + // Open input file. + pInfile = fopen(src, "rb"); + if (!pInfile) + { + log_error("Zip decompress: Failed opening input file!"); + return GS_ERROR_IO; + } + + // Determine input file's size. + fseek(pInfile, 0, SEEK_END); + file_loc = ftell(pInfile); + fseek(pInfile, 0, SEEK_SET); + + if((file_loc < 0) || ((unsigned long)file_loc > UINT_MAX)) + { + log_error("Zip decompress: File is too large to be processed."); + fclose(pInfile); + + return GS_ERROR_IO; + } + + infile_size = (uint32_t)file_loc; + uint32_t buffer_size = infile_size; + + // Allocate input buffer memory + uint8_t *stream_inbuf = malloc(buffer_size); + if (stream_inbuf == NULL) + { + log_error("Zip decompress: Failed to allocate input buffer memory"); + fclose(pInfile); + + return GS_ERROR_IO; + } + + // Allocate output buffer memory + uint8_t *stream_outbuf = malloc(buffer_size); + if (stream_outbuf == NULL) + { + log_error("Zip decompress: Failed to allocate output buffer memory"); + cleanup(pInfile, NULL, stream_inbuf, NULL); + + return GS_ERROR_IO; + } + + // Open output file. + pOutfile = fopen(dest, "wb"); + if (!pOutfile) + { + log_error("Zip decompress: Failed opening output file!"); + cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); + + return GS_ERROR_IO; + } + + // Init the z_stream + z_stream stream; + memset(&stream, 0, sizeof(stream)); + stream.next_in = stream_inbuf; + stream.avail_in = 0; + stream.next_out = stream_outbuf; + stream.avail_out = buffer_size; + + // Decompression. + uint32_t infile_remaining = infile_size; + + if(inflateInit(&stream)) + { + log_error("Zip decompress: inflateInit() failed!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_DATA; + } + + for( ; ; ) + { + int status; + if(!stream.avail_in) + { + // Input buffer is empty, so read more bytes from input file. + uint32_t n = gs_min((uint32_t)buffer_size, infile_remaining); + + if(fread(stream_inbuf, 1, n, pInfile) != n) + { + log_error("Zip decompress: Failed reading from input file!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_IO; + } + + stream.next_in = stream_inbuf; + stream.avail_in = n; + + infile_remaining -= n; + } + + status = inflate(&stream, Z_SYNC_FLUSH); + + if((status == Z_STREAM_END) || (!stream.avail_out)) + { + // Output buffer is full, or decompression is done, so write buffer to output file. + uint32_t n = buffer_size - stream.avail_out; + if(fwrite(stream_outbuf, 1, n, pOutfile) != n) + { + log_error("Zip decompress: Failed writing to output file!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_IO; + } + stream.next_out = stream_outbuf; + stream.avail_out = buffer_size; + } + + if(status == Z_STREAM_END) + { + break; + } + else if(status != Z_OK) + { + log_error("Zip decompress: inflate() failed with status %i!", status); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_DATA; + } + } + + if(inflateEnd(&stream) != Z_OK) + { + log_error("Zip decompress: inflateEnd() failed!"); + cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); + + return GS_ERROR_DATA; + } + + cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); + if(EOF == fclose(pOutfile)) + { + log_error("Zip decompress: Failed writing to output file!"); + return GS_ERROR_IO; + } + + log_debug("Total input bytes: %u", (mz_uint32)stream.total_in); + log_debug("Total output bytes: %u", (mz_uint32)stream.total_out); + log_debug("Success.\n"); + + return GS_OK; +} + +int gs_zip_compress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t *dest_len) +{ + mz_ulong cmp_len = src_len; + if(compress(dest, &cmp_len, src, (mz_ulong)src_len) != MZ_OK) + { + return GS_ERROR_DATA; + } + + *dest_len = cmp_len; + + return GS_OK; +} + +int gs_zip_decompress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t dest_len, uint32_t *decomp_len) +{ + mz_ulong tmp = dest_len; + if(uncompress(dest, &tmp, src, (mz_ulong)src_len) != MZ_OK) + return GS_ERROR_DATA; + + *decomp_len = tmp; + + return GS_OK; +} diff --git a/gomspace/libutil/wscript b/gomspace/libutil/wscript new file mode 100644 index 00000000..48421e39 --- /dev/null +++ b/gomspace/libutil/wscript @@ -0,0 +1,109 @@ +#!/usr/bin/env python +# encoding: utf-8 +# Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. + +import gs_gcc +import gs_doc +import gs_dist +from waflib.Build import BuildContext + +APPNAME = 'util' + + +def options(ctx): + ctx.load('gs_gcc gs_doc') + gs_gcc.gs_recurse(ctx) + + gr = ctx.add_option_group('libutil options') + gr.add_option('--console-history-len', metavar='LEN', default=10, type=int, help='Command history length, 0=none') + gr.add_option('--console-input-len', metavar='LEN', default=100, type=int, help='Command input length') + gr.add_option('--util-enable-isr-logs', action='store_true', help='Enable ISR logs') + + +def configure(ctx): + ctx.load('gs_gcc gs_doc') + + ctx.env.append_unique('FILES_LIBUTIL', ['src/*.c', + 'src/gosh/**/*.c', + 'src/log/**/*.c', + 'src/vmem/**/*.c', + 'src/watchdog/**/*.c', + 'src/drivers/**/*.c']) + + if ctx.env.GS_ARCH not in ['avr8']: + ctx.env.append_unique('FILES_LIBUTIL', ['src/zip/**/*.c']) + + if ctx.gs_is_linux(): + ctx.env.append_unique('FILES_LIBUTIL', ['src/linux/**/*.c']) + + ctx.env.GS_UTIL_CMOCKA = ctx.check_cfg(package='cmocka', args='--cflags --libs', + atleast_version='1.0.1', mandatory=False) + + # Check compiler endianness - avr32 GCC doesn't support endian defines + endianness = ctx.check_endianness() + ctx.define_cond('UTIL_LITTLE_ENDIAN', endianness == 'little') + ctx.define_cond('UTIL_BIG_ENDIAN', endianness == 'big') + + ctx.define('GS_CONSOLE_HISTORY_LEN', ctx.options.console_history_len) + ctx.define('GS_CONSOLE_INPUT_LEN', ctx.options.console_input_len) + ctx.define_cond('GS_LOG_ENABLE_ISR_LOGS', ctx.options.util_enable_isr_logs) + + ctx.gs_write_config_header('include/conf_util.h', remove=True) + + ctx.gs_add_doxygen(example=['tst'], exclude=['*/include/gs/uthash/*', + '*/include/gs/util/zip/*', + '*/include/deprecated/util/*', + '*/include/deprecated/gs/gosh/*']) + + ctx.gs_register_handler(function='command_gen_4_0', filepath='./tools/waf_command.py') + + gs_gcc.gs_recurse(ctx) + + +def build(ctx): + gs_gcc.gs_recurse(ctx) + + public_include = ctx.gs_include(name=APPNAME, + includes=['include', 'include/gs', + 'include/deprecated', 'include/deprecated/gs/gosh/'], + config_header=['include/conf_util.h']) + + ctx.gs_objects(source=ctx.path.ant_glob(ctx.env.FILES_LIBUTIL), + target=APPNAME, + includes=['src'], + use=ctx.env.USE_LIBUTIL + [public_include]) + + ctx.gs_shlib(source=ctx.path.ant_glob(ctx.env.FILES_LIBUTIL), + target=APPNAME, + includes=['src'], + gs_use_shlib=ctx.env.USE_LIBUTIL, + use=[public_include], + lib=['pthread']) + + ctx.gs_python_bindings(source=ctx.path.ant_glob('src/bindings/python/*.c'), + target=APPNAME, + gs_use_shlib=ctx.env.USE_LIBUTIL + [APPNAME], + use=[public_include], + package='libutil') + + if ctx.env.GS_UTIL_CMOCKA: + ctx.gs_stlib(source=ctx.path.ant_glob('src/test/*.c'), + name=APPNAME + '_cmocka', # overwrite default naming + target=APPNAME + '_cmocka', + includes=['include']) + + +def doc(ctx): + gs_doc.gs_library_doc(ctx, keyvalues={ + 'gs_prod_name': 'lib'+APPNAME, + 'gs_prod_desc': 'Low level APIs and utilities', + 'gs_sphinx_exclude': ['CHANGELOG.rst'], + }) + + +class Doc(BuildContext): + cmd = fun = 'doc' + + +def gs_dist(ctx): + ctx.add_default_files(source_module=True) diff --git a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock.h b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock.h new file mode 100644 index 00000000..0a4477ba --- /dev/null +++ b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock.h @@ -0,0 +1,47 @@ +#ifndef P60DOCK_H_ +#define P60DOCK_H_ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +#include + +#include +#include +#include +#include +#include + +/** FRAM MEMORY MAP */ +#define P60DOCK_FRAM_PARAM 0x0400 +#define P60DOCK_FRAM_CAL 0x0800 +#define P60DOCK_FRAM_HK 0x0C00 + +#define P60DOCK_FRAM_GNDWDT 0x1F00 + +/** FRAM FILENAMES */ +#define P60DOCK_FNO_PARAM 1 +#define P60DOCK_FNO_PARAM_DFL 5 +#define P60DOCK_FNO_CAL 2 +#define P60DOCK_FNO_CAL_DFL 6 + +/** PARAM INDEX MAP */ +/* Index 0 is reserved for board param */ +#define P60DOCK_PARAM 1 +#define P60DOCK_CAL 2 +#define P60DOCK_SCRATCH 3 +#define P60DOCK_HK 4 + +#define P60DOCK_BATT_PACK_OTHER 0 +#define P60DOCK_BATT_PACK_BP2 1 +#define P60DOCK_BATT_PACK_BP4 2 +#define P60DOCK_BATT_PACK_BPX 3 + +int p60dock_get_hk(param_index_t * mem, uint8_t node, uint32_t timeout); +int p60dock_gndwdt_clear(uint8_t node, uint32_t timeout); +int p60dock_output_get(uint8_t node, char * ch_name, uint8_t * mode, uint8_t * ch_no); +int p60dock_output_set(uint8_t node, char * ch_name, uint8_t mode, uint8_t * ch_no); + +void cmd_p60dock_setup(void); + +#endif /* P60DOCK_H_ */ diff --git a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_cal.h b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_cal.h new file mode 100644 index 00000000..905bc3db --- /dev/null +++ b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_cal.h @@ -0,0 +1,35 @@ +#ifndef P60DOCK_CAL_H_ +#define P60DOCK_CAL_H_ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +/** + * Define memory space + */ + +#define P60DOCK_CAL_GAIN_V_OUT(i) (0x00 + (4 * i)) /* 13 * float */ +#define P60DOCK_CAL_GAIN_C_OUT(i) (0x34 + (4 * i)) /* 13 * float */ +#define P60DOCK_CAL_OFFSET_C_OUT(i) (0x68 + (2 * i)) /* 13 * uint16_t */ +#define P60DOCK_CAL_VREF 0x82 +#define P60DOCK_CAL_GAIN_VBAT_V 0x84 +#define P60DOCK_CAL_GAIN_VCC_C 0x88 +#define P60DOCK_CAL_OFFSET_VCC_C 0x8C +#define P60DOCK_CAL_GAIN_AUX1 0x90 +#define P60DOCK_CAL_GAIN_AUX2 0x94 +#define P60DOCK_CAL_OFFSET_AUX1 0x98 +#define P60DOCK_CAL_OFFSET_AUX2 0x9A +#define P60DOCK_CAL_GAIN_BATT_V 0x9C +#define P60DOCK_CAL_GAIN_BATT_CHRG 0xA0 +#define P60DOCK_CAL_OFFS_BATT_CHRG 0xA4 +#define P60DOCK_CAL_GAIN_BATT_DIS 0xA8 +#define P60DOCK_CAL_OFFS_BATT_DIS 0xAC + +/** Define the memory size */ +#define P60DOCK_CAL_SIZE 0xAE + +extern const param_table_t p60dock_calibration[]; +extern const int p60dock_cal_count; + +#endif /* P60DOCK_CAL_H_ */ diff --git a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h new file mode 100644 index 00000000..63797e37 --- /dev/null +++ b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h @@ -0,0 +1,51 @@ +#ifndef P60DOCK_HK_H_ +#define P60DOCK_HK_H_ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +/** + * Define memory space + */ +#define P60DOCK_HK_C_OUT(i) (0x00 + (2 * i)) /* 13 * int16_t */ +#define P60DOCK_HK_V_OUT(i) (0x1A + (2 * i)) /* 13 * uint16_t */ +#define P60DOCK_HK_OUT_EN(i) (0x34 + (i)) /* 13 * uint8_t */ +#define P60DOCK_HK_TEMP(i) (0x44 + (2 * i)) /* 2 * int16_t */ +#define P60DOCK_HK_BOOT_CAUSE 0x48 +#define P60DOCK_HK_BOOT_COUNTER 0x4C +#define P60DOCK_HK_UPTIME 0x50 +#define P60DOCK_HK_RESET_CAUSE 0x54 +#define P60DOCK_HK_BATT_MODE 0x56 +#define P60DOCK_HK_HEATER_ON 0x57 +#define P60DOCK_HK_CONV_5V0_EN 0x58 + +#define P60DOCK_HK_LATCHUP(i) (0x5A + (2 * i)) /* 13 * uint16_t */ +#define P60DOCK_HK_VBAT_V 0x74 +#define P60DOCK_HK_VCC_C 0x76 +#define P60DOCK_HK_BATTERY_C 0x78 +#define P60DOCK_HK_BATTERY_V 0x7A +#define P60DOCK_HK_BP_TEMP(i) (0x7C + (2 * i)) /* 2 * int16_t */ +#define P60DOCK_HK_DEVICE_TYPE(i) (0x80 + (i)) /* 8 * uint8_t */ +#define P60DOCK_HK_DEVICE_STATUS(i) (0x88 + (i)) /* 8 * uint8_t */ +#define P60DOCK_HK_DEARM_STATUS 0x90 +#define P60DOCK_HK_CNT_WDTGND 0x94 +#define P60DOCK_HK_CNT_WDTI2C 0x98 +#define P60DOCK_HK_CNT_WDTCAN 0x9C +#define P60DOCK_HK_CNT_WDTCSP(i) (0xA0 + (4 * i)) /* 2 * uint32_t */ +#define P60DOCK_HK_WDTGND_LEFT 0xA8 +#define P60DOCK_HK_WDTI2C_LEFT 0xAC +#define P60DOCK_HK_WDTCAN_LEFT 0xB0 +#define P60DOCK_HK_WDTCSP_LEFT(i) (0xB4 + (i)) /* 2 * uint8_t */ +#define P60DOCK_HK_BATT_C_CHRG 0xB6 /* int16_t */ +#define P60DOCK_HK_BATT_C_DISCHRG 0xB8 /* int16_t */ +#define P60DOCK_HK_ANT6_DEPL 0xBA /* int8_t */ +#define P60DOCK_HK_AR6_DEPL 0xBB /* int8_t */ + +/** Define the memory size */ +#define P60DOCK_HK_SIZE 0xBC + +extern const param_table_t p60dock_hk[]; +extern const int p60dock_hk_count; + +#endif /* P60DOCK_HK_H_ */ diff --git a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_param.h b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_param.h new file mode 100644 index 00000000..05dac011 --- /dev/null +++ b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_param.h @@ -0,0 +1,69 @@ +#ifndef P60DOCK_PARAM_H_ +#define P60DOCK_PARAM_H_ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include + +/** + * Define memory space + */ +#define P60DOCK_NAME_SIZE 8 + +#define P60DOCK_OUT_NAME(i) (0x00 + (P60DOCK_NAME_SIZE * i)) /* 13 * 8 */ +#define P60DOCK_OUT_EN(i) (0x68 + (i)) /* 13 * uint8_t */ +#define P60DOCK_OUT_ON_CNT(i) (0x76 + (2 * i)) /* 13 * uint16_t */ +#define P60DOCK_OUT_OFF_CNT(i) (0x90 + (2 * i)) /* 13 * uint16_t */ + +#define P60DOCK_INIT_OUT_NORM(i) (0xAA + (i)) /* 13 * uint8_t */ +#define P60DOCK_INIT_OUT_SAFE(i) (0xB7 + (i)) /* 13 * uint8_t */ +#define P60DOCK_INIT_ON_DELAY(i) (0xC4 + (2 * i)) /* 13 * uint16_t */ +#define P60DOCK_INIT_OFF_DELAY(i) (0xDE + (2 * i)) /* 13 * uint16_t */ + +#define P60DOCK_CUR_LU_LIM(i) (0xF8 + (2 * i)) /* 13 * uint16_t */ +#define P60DOCK_CUR_LIM(i) (0x112 + (2 * i)) /* 13 * uint16_t */ +#define P60DOCK_CUR_EMA(i) (0x12C + (2 * i)) /* 13 * uint16_t */ +#define P60DOCK_CUR_EMA_GAIN 0x148 + +#define P60DOCK_VCC_LINK(i) (0x14C + (i)) /* 4 * uint8_t */ +#define P60DOCK_VCC_VBAT_LINK(i) (0x150 + (i)) /* 4 * uint8_t */ + +#define P60DOCK_BATTERY_PACK 0x154 + +#define P60DOCK_BATT_HWMAX 0x156 +#define P60DOCK_BATT_MAX 0x158 +#define P60DOCK_BATT_NORM 0x15A +#define P60DOCK_BATT_SAFE 0x15C +#define P60DOCK_BATT_CRIT 0x15E + +#define P60DOCK_BP_HEATERMODE 0x160 +#define P60DOCK_BP_HEATER_LOW 0x162 +#define P60DOCK_BP_HEATER_HIGH 0x164 + +#define P60DOCK_WDTI2C_RST 0x166 +#define P60DOCK_WDTCAN_RST 0x167 +#define P60DOCK_WDTI2C 0x168 +#define P60DOCK_WDTCAN 0x16C +#define P60DOCK_WDTCSP(i) (0x170 + (4 * i)) /* 2 * uint32_t */ +#define P60DOCK_WDTCSP_PING_FAIL(i) (0x178 + (i)) /* 2 * uint8_t */ +#define P60DOCK_WDTCSP_CHAN(i) (0x17A + (i)) /* 2 * uint8_t */ +#define P60DOCK_WDTCSP_ADDR(i) (0x17C + (i)) /* 2 * uint8_t */ + +#define P60DOCK_P60ACU_CHAN(i) (0x17E + (i)) /* 2 * uint8_t */ +#define P60DOCK_P60ACU_ADDR(i) (0x180 + (i)) /* 2 * uint8_t */ +#define P60DOCK_P60PDU_CHAN(i) (0x182 + (i)) /* 4 * uint8_t */ +#define P60DOCK_P60PDU_ADDR(i) (0x186 + (i)) /* 4 * uint8_t */ + +#define P60DOCK_CONV_5V0_EN 0x18A + +#define P60DOCK_ANT6_ADDR(i) (0x190 + (i)) /* 2 * uint8_t */ +#define P60DOCK_AR6_ADDR(i) (0x194 + (i)) /* 4 * uint8_t */ +#define P60DOCK_DEPL_DELAY 0x198 /* uint32_t*/ + +/** Define the memory size */ +#define P60DOCK_PARAM_SIZE 0x19C + +extern const param_table_t p60dock_config[]; +extern const int p60dock_config_count; + +#endif /* P60DOCK_PARAM_H_ */ diff --git a/gomspace/p60-dock_client/src/p60dock_client.c b/gomspace/p60-dock_client/src/p60dock_client.c new file mode 100644 index 00000000..2fa3232b --- /dev/null +++ b/gomspace/p60-dock_client/src/p60dock_client.c @@ -0,0 +1,147 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include +#include + +/** + * Setup info about config parameters + */ +const param_table_t p60dock_config[] = { + {.name = "out_name", .addr = P60DOCK_OUT_NAME(0), .type = PARAM_STRING, .size = P60DOCK_NAME_SIZE, .count = 13}, + {.name = "out_en", .addr = P60DOCK_OUT_EN(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 13}, + {.name = "out_on_cnt", .addr = P60DOCK_OUT_ON_CNT(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, + {.name = "out_off_cnt", .addr = P60DOCK_OUT_OFF_CNT(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, + + {.name = "init_out_norm", .addr = P60DOCK_INIT_OUT_NORM(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 13}, + {.name = "init_out_safe", .addr = P60DOCK_INIT_OUT_SAFE(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 13}, + {.name = "init_on_dly", .addr = P60DOCK_INIT_ON_DELAY(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, + {.name = "init_off_dly", .addr = P60DOCK_INIT_OFF_DELAY(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, + + {.name = "cur_lu_lim", .addr = P60DOCK_CUR_LU_LIM(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, + {.name = "cur_lim", .addr = P60DOCK_CUR_LIM(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, + {.name = "cur_ema", .addr = P60DOCK_CUR_EMA(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, + {.name = "cur_ema_gain", .addr = P60DOCK_CUR_EMA_GAIN, .type = PARAM_FLOAT, .size = sizeof(float)}, + + {.name = "vcc_vbat_link", .addr = P60DOCK_VCC_VBAT_LINK(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 4}, + {.name = "vcc_link", .addr = P60DOCK_VCC_LINK(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 4}, + + {.name = "batt_pack", .addr = P60DOCK_BATTERY_PACK, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + + {.name = "batt_hwmax", .addr = P60DOCK_BATT_HWMAX, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, + {.name = "batt_max", .addr = P60DOCK_BATT_MAX, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, + {.name = "batt_norm", .addr = P60DOCK_BATT_NORM, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, + {.name = "batt_safe", .addr = P60DOCK_BATT_SAFE, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, + {.name = "batt_crit", .addr = P60DOCK_BATT_CRIT, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, + + {.name = "bp_heat_mode", .addr = P60DOCK_BP_HEATERMODE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "bp_heat_low", .addr = P60DOCK_BP_HEATER_LOW, .type = PARAM_INT16, .size = sizeof(int16_t)}, + {.name = "bp_heat_high", .addr = P60DOCK_BP_HEATER_HIGH, .type = PARAM_INT16, .size = sizeof(int16_t)}, + + {.name = "wdt_i2c_rst", .addr = P60DOCK_WDTI2C_RST, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "wdt_can_rst", .addr = P60DOCK_WDTCAN_RST, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "wdt_i2c", .addr = P60DOCK_WDTI2C, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, + {.name = "wdt_can", .addr = P60DOCK_WDTCAN, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, + {.name = "wdt_csp", .addr = P60DOCK_WDTCSP(0), .type = PARAM_UINT32, .size = sizeof(uint32_t), .count = 2}, + {.name = "wdt_csp_ping", .addr = P60DOCK_WDTCSP_PING_FAIL(0),.type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 2}, + {.name = "wdt_csp_chan", .addr = P60DOCK_WDTCSP_CHAN(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 2}, + {.name = "wdt_csp_addr", .addr = P60DOCK_WDTCSP_ADDR(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 2}, + + {.name = "p60acu_chan", .addr = P60DOCK_P60ACU_CHAN(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 2}, + {.name = "p60acu_addr", .addr = P60DOCK_P60ACU_ADDR(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 2}, + {.name = "p60pdu_chan", .addr = P60DOCK_P60PDU_CHAN(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 4}, + {.name = "p60pdu_addr", .addr = P60DOCK_P60PDU_ADDR(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 4}, + + {.name = "conv_5v_en", .addr = P60DOCK_CONV_5V0_EN, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + + {.name = "ant6_addr", .addr = P60DOCK_ANT6_ADDR(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 2}, + {.name = "ar6_addr", .addr = P60DOCK_AR6_ADDR(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 4}, + + {.name = "depl_delay", .addr = P60DOCK_DEPL_DELAY, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, +}; + +const int p60dock_config_count = sizeof(p60dock_config) / sizeof(p60dock_config[0]); + +/** + * Setup info about calibration parameters + */ +const param_table_t p60dock_calibration[] = { + {.name = "gain_v_out", .addr = P60DOCK_CAL_GAIN_V_OUT(0), .type = PARAM_FLOAT, .size = sizeof(float), .count = 13}, + {.name = "gain_c_out", .addr = P60DOCK_CAL_GAIN_C_OUT(0), .type = PARAM_FLOAT, .size = sizeof(float), .count = 13}, + {.name = "offs_c_out", .addr = P60DOCK_CAL_OFFSET_C_OUT(0),.type = PARAM_INT16, .size = sizeof(int16_t), .count = 13}, + {.name = "vref", .addr = P60DOCK_CAL_VREF, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, + {.name = "gain_vbat_v", .addr = P60DOCK_CAL_GAIN_VBAT_V, .type = PARAM_FLOAT, .size = sizeof(float)}, + {.name = "gain_vcc_c", .addr = P60DOCK_CAL_GAIN_VCC_C, .type = PARAM_FLOAT, .size = sizeof(float)}, + {.name = "offs_vcc_c", .addr = P60DOCK_CAL_OFFSET_VCC_C, .type = PARAM_INT16, .size = sizeof(int16_t)}, + {.name = "gain_aux1", .addr = P60DOCK_CAL_GAIN_AUX1, .type = PARAM_FLOAT, .size = sizeof(float)}, + {.name = "gain_aux2", .addr = P60DOCK_CAL_GAIN_AUX2, .type = PARAM_FLOAT, .size = sizeof(float)}, + {.name = "offs_aux1", .addr = P60DOCK_CAL_OFFSET_AUX1, .type = PARAM_INT16, .size = sizeof(int16_t)}, + {.name = "offs_aux2", .addr = P60DOCK_CAL_OFFSET_AUX2, .type = PARAM_INT16, .size = sizeof(int16_t)}, + {.name = "gain_batt_v", .addr = P60DOCK_CAL_GAIN_BATT_V, .type = PARAM_FLOAT, .size = sizeof(float)}, + {.name = "gain_batt_chg", .addr = P60DOCK_CAL_GAIN_BATT_CHRG, .type = PARAM_FLOAT, .size = sizeof(float)}, + {.name = "offs_batt_chg", .addr = P60DOCK_CAL_OFFS_BATT_CHRG, .type = PARAM_INT16, .size = sizeof(int16_t)}, + {.name = "gain_batt_dis", .addr = P60DOCK_CAL_GAIN_BATT_DIS, .type = PARAM_FLOAT, .size = sizeof(float)}, + {.name = "offs_batt_dis", .addr = P60DOCK_CAL_OFFS_BATT_DIS, .type = PARAM_INT16, .size = sizeof(int16_t)}, +}; + +const int p60dock_cal_count = sizeof(p60dock_calibration) / sizeof(p60dock_calibration[0]); + +/** + * Setup info about hk parameters + */ +const param_table_t p60dock_hk[] = { + {.name = "c_out", .addr = P60DOCK_HK_C_OUT(0), .type = PARAM_INT16, .size = sizeof(int16_t), .count = 13}, + {.name = "v_out", .addr = P60DOCK_HK_V_OUT(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, + {.name = "out_en", .addr = P60DOCK_HK_OUT_EN(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 13}, + {.name = "temp", .addr = P60DOCK_HK_TEMP(0), .type = PARAM_INT16, .size = sizeof(int16_t), .count = 2}, + {.name = "bootcause", .addr = P60DOCK_HK_BOOT_CAUSE, .type = PARAM_UINT32, .size = sizeof(uint32_t), .flags = PARAM_F_READONLY}, + {.name = "bootcnt", .addr = P60DOCK_HK_BOOT_COUNTER, .type = PARAM_UINT32, .size = sizeof(uint32_t), .flags = PARAM_F_PERSIST}, + {.name = "uptime", .addr = P60DOCK_HK_UPTIME, .type = PARAM_UINT32, .size = sizeof(uint32_t), .flags = PARAM_F_READONLY}, + {.name = "resetcause", .addr = P60DOCK_HK_RESET_CAUSE, .type = PARAM_UINT16, .size = sizeof(uint16_t), .flags = PARAM_F_PERSIST}, + {.name = "batt_mode", .addr = P60DOCK_HK_BATT_MODE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "heater_on", .addr = P60DOCK_HK_HEATER_ON, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "conv_5v_en", .addr = P60DOCK_HK_CONV_5V0_EN, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "latchup", .addr = P60DOCK_HK_LATCHUP(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13, .flags = PARAM_F_PERSIST}, + {.name = "vbat_v", .addr = P60DOCK_HK_VBAT_V, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, + {.name = "vcc_c", .addr = P60DOCK_HK_VCC_C, .type = PARAM_INT16, .size = sizeof(int16_t)}, + {.name = "batt_c", .addr = P60DOCK_HK_BATTERY_C, .type = PARAM_INT16, .size = sizeof(int16_t)}, + {.name = "batt_v", .addr = P60DOCK_HK_BATTERY_V, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, + {.name = "batt_temp", .addr = P60DOCK_HK_BP_TEMP(0), .type = PARAM_INT16, .size = sizeof(int16_t), .count = 2}, + {.name = "device_type", .addr = P60DOCK_HK_DEVICE_TYPE(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 8}, + {.name = "device_status", .addr = P60DOCK_HK_DEVICE_STATUS(0),.type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 8}, + {.name = "dearm_status", .addr = P60DOCK_HK_DEARM_STATUS, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, + {.name = "wdt_cnt_gnd", .addr = P60DOCK_HK_CNT_WDTGND, .type = PARAM_UINT32, .size = sizeof(uint32_t), .flags = PARAM_F_PERSIST}, + {.name = "wdt_cnt_i2c", .addr = P60DOCK_HK_CNT_WDTI2C, .type = PARAM_UINT32, .size = sizeof(uint32_t), .flags = PARAM_F_PERSIST}, + {.name = "wdt_cnt_can", .addr = P60DOCK_HK_CNT_WDTCAN, .type = PARAM_UINT32, .size = sizeof(uint32_t), .flags = PARAM_F_PERSIST}, + {.name = "wdt_cnt_csp", .addr = P60DOCK_HK_CNT_WDTCSP(0), .type = PARAM_UINT32, .size = sizeof(uint32_t), .count = 2, .flags = PARAM_F_PERSIST}, + {.name = "wdt_gnd_left", .addr = P60DOCK_HK_WDTGND_LEFT, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, + {.name = "wdt_i2c_left", .addr = P60DOCK_HK_WDTI2C_LEFT, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, + {.name = "wdt_can_left", .addr = P60DOCK_HK_WDTCAN_LEFT, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, + {.name = "wdt_csp_left", .addr = P60DOCK_HK_WDTCSP_LEFT(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 2}, + {.name = "batt_chrg", .addr = P60DOCK_HK_BATT_C_CHRG, .type = PARAM_INT16, .size = sizeof(int16_t)}, + {.name = "batt_dischrg", .addr = P60DOCK_HK_BATT_C_DISCHRG, .type = PARAM_INT16, .size = sizeof(int16_t)}, + {.name = "ant6_depl", .addr = P60DOCK_HK_ANT6_DEPL, .type = PARAM_INT8, .size = sizeof(int8_t)}, + {.name = "ar6_depl", .addr = P60DOCK_HK_AR6_DEPL, .type = PARAM_INT8, .size = sizeof(int8_t)}, +}; + +const int p60dock_hk_count = sizeof(p60dock_hk) / sizeof(p60dock_hk[0]); + +int p60dock_get_hk(param_index_t * mem, uint8_t node, uint32_t timeout) { + + mem->table = p60dock_hk; + mem->mem_id = P60DOCK_HK; + mem->count = p60dock_hk_count; + mem->size = P60DOCK_HK_SIZE; + int result = rparam_get_full_table(mem, node, P60_PORT_RPARAM, mem->mem_id, timeout); + + return (result == 0); + +} + +int p60dock_gndwdt_clear(uint8_t node, uint32_t timeout) { + uint8_t magic = 0x78; + return csp_transaction(CSP_PRIO_HIGH, node, P60_PORT_GNDWDT_RESET, timeout, &magic, 1, NULL, 0); +} diff --git a/gomspace/p60-dock_client/wscript b/gomspace/p60-dock_client/wscript new file mode 100644 index 00000000..8fdf39d6 --- /dev/null +++ b/gomspace/p60-dock_client/wscript @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. +# encoding: utf-8 + +import gs_gcc + +APPNAME = 'p60-dock_client' + + +def options(ctx): + gr = ctx.add_option_group('NanoPower-P60 Dock client options') + gr.add_option('--disable-p60-dock-cmd', action='store_true', help='Disable client cmd code for NanoPower-P60 Dock') + + +def configure(ctx): + ctx.env.append_unique('FILES_P60_DOCK_CLIENT', ['src/p60dock_client.c']) + if not ctx.options.disable_p60_dock_cmd: + ctx.env.append_unique('FILES_P60_DOCK_CLIENT', ['src/p60dock_cmd.c']) + + +def build(ctx): + gs_gcc.gs_call_handler(ctx, handler='param_gen_4_3', name=APPNAME, prefix='p60-dock', + generate_rst=True) + + public_include = APPNAME + '_h' + ctx(export_includes=['include', 'include/gs/p60-dock/param'], name=public_include) + + ctx.objects(source=ctx.path.ant_glob(ctx.env.FILES_P60_DOCK_CLIENT), + target=APPNAME, + use=['csp', 'gosh', 'param', 'param_client', 'p60_client', public_include]) + + +def gs_dist(ctx): + ctx.add_default_files(source_module=True) diff --git a/test/testtasks/P60DockTestTask.cpp b/test/testtasks/P60DockTestTask.cpp index 3db66933..8e929e75 100644 --- a/test/testtasks/P60DockTestTask.cpp +++ b/test/testtasks/P60DockTestTask.cpp @@ -73,6 +73,54 @@ ReturnValue_t P60DockTestTask::sendPacket(void){ } +ReturnValue_t P60DockTestTask::getParameters(void) { + gs_param_table_instance_t node_hk; +// int result = rparam_get_full_table(&node_hk, p60dock_node, P60_PORT_RPARAM, + uint32_t timeout; + int result = p60dock_get_hk(&node_hk, p60dock_node, timeout); + if (result != 0) { + sif::info << "Error retrieving P60 Dock housekeeping\n" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } else { + uint8_t tableOffsetTemperature = 0x44; + uint8_t temperature[2]; + size_t parameterSize = 2; + uint32_t flags = 0; + result = gs_param_get_data((gs_param_table_instance_t*) &node_hk, + tableOffsetTemperature, temperature, parameterSize, flags); + sif::info << "P60 Dock Temperature 1: " << temperature[0] << std::endl; + sif::info << "P60 Dock Temperature 2: " << temperature[1] << std::endl; + +// sif::info << "Retrieved P60 Dock housekeeping\n" << std::endl; +// /* List all out_en[] values, using parameter name */ +// const param_table_t * param = param_find_name(node_hk.table, +// node_hk.count, "out_en"); +// if (param != NULL) { +// for (uint8_t index = 0; index < 13; index++) { +// /* Read parameter using name */ +// uint8_t *out_en = param_read_addr( +// param->addr + param->size * index, &node_hk, +// param->size); +// sif::info << "out_en" << index << ": " << *out_en << std::endl; +// } +// } +// /* List all c_out[] values, using parameter address */ +// param = param_find_addr(node_hk.table, node_hk.count, 0x0000); +// if (param != NULL) { +// for (uint8_t index = 0; index < 13; index++) { +// /* Read parameter using address */ +// int16_t *c_out = param_read_addr( +// param->addr + param->size * index, &node_hk, +// param->size); +// sif::info << "c_out" << index << ": " << *c_out << "mA" +// << std::endl; +// } +// } + } + return HasReturnvaluesIF::RETURN_OK; +} + + ReturnValue_t P60DockTestTask::initializeCSPStack(void){ /* Init CSP and CSP buffer system */ if (csp_init(cspAddress) != CSP_ERR_NONE diff --git a/test/testtasks/P60DockTestTask.h b/test/testtasks/P60DockTestTask.h index bcccb487..90d810bd 100644 --- a/test/testtasks/P60DockTestTask.h +++ b/test/testtasks/P60DockTestTask.h @@ -2,7 +2,7 @@ * P60DockTestTask.h * * Created on: 18.11.2020 - * Author: jakob + * Author: Jakob Meier */ #ifndef TEST_TESTTASKS_P60DOCKTESTTASK_H_ @@ -11,6 +11,7 @@ #include #include #include +#include extern "C" { #include @@ -37,8 +38,12 @@ private: int bitrate = 1000; // bitrate of can int promisc = 0; // set to 0 to enable filter mode + uint8_t hk_mem[P60DOCK_HK_SIZE]; + uint8_t p60dock_node = 4; + ReturnValue_t sendPacket(void); ReturnValue_t initializeCSPStack(void); + ReturnValue_t getParameters(void); }; From 3b992f7651c1e6ee1c1d8b4f4ef8f8d4f9661d80 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Thu, 26 Nov 2020 18:13:20 +0100 Subject: [PATCH 005/360] extended p60 dock test task --- gomspace/include/port.h | 111 +++++++++++++++++++++++ gomspace/include/rparam.h | 141 +++++++++++++++++++++++++++++ test/testtasks/P60DockTestTask.cpp | 69 ++++++++++++++ test/testtasks/P60DockTestTask.h | 1 + 4 files changed, 322 insertions(+) create mode 100644 gomspace/include/port.h create mode 100644 gomspace/include/rparam.h diff --git a/gomspace/include/port.h b/gomspace/include/port.h new file mode 100644 index 00000000..29fa32e4 --- /dev/null +++ b/gomspace/include/port.h @@ -0,0 +1,111 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_PORT_H +#define LIBGSCSP_INCLUDE_GS_CSP_PORT_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Port definitions for standard CSP and GomSpace services. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Port definitions for standard CSP and GomSpace services. +*/ +typedef enum { + /** + CSP Management Protocol - standard CSP service. + */ + GS_CSP_CMP = CSP_CMP, // 0 + /** + Ping - standard CSP service. + */ + GS_CSP_PING = CSP_PING, // 1 + /** + Show process status - standard CSP service. + */ + GS_CSP_PS = CSP_PS, // 2 + /** + Show memory free - standard CSP service. + */ + GS_CSP_MEM_FREE = CSP_MEMFREE, // 3 + GS_CSP_MEMFREE = GS_CSP_MEM_FREE, + /** + Reboot/reset request - standard CSP service. + */ + GS_CSP_REBOOT = CSP_REBOOT, // 4 + /** + Show number of free CSP buffers - standard CSP service. + */ + GS_CSP_BUF_FREE = CSP_BUF_FREE, // 5 + /** + Show uptime (time since last reset) - standard CSP service. + */ + GS_CSP_UPTIME = CSP_UPTIME, // 6 + /** + Parameter service (libparam) + */ + GS_CSP_PORT_RPARAM = 7, + /** + File Transfer Service (libftp) + */ + GS_CSP_PORT_FTP = 9, + /** + Remote log service (liblog) + */ + GS_CSP_PORT_RLOG = 11, + /** + Remote GOSH service (librgosh) + */ + GS_CSP_PORT_RGOSH = 12, + /** + AIS command port (libais). + */ + GS_CSP_PORT_AIS = 13, + /** + ADS-B command port (libadsb). + */ + GS_CSP_PORT_ADSB = 14, + + /** + GomSpace Sensor Bus (libgssb). + */ + GS_CSP_PORT_GSSB = 16, + /** + Flight Planner (libfp). + */ + GS_CSP_PORT_FP = 18, + /** + ADCS (libadcs). + */ + GS_CSP_PORT_ADCS = 20, + /** + House Keeping (libhk). + */ + GS_CSP_PORT_HK = 21, + /** + G(omSpace) script service (libgosh) + */ + GS_CSP_PORT_GSCRIPT = 22, + /** + Remote shell (libgosh). + Executes shell commands (linux server only). + Requires CSP_O_RDP. + */ + GS_CSP_PORT_REMOTE_SHELL = 27, + /** + House keeping beacon port (libhk). + Default port for sending beacons from satellite to ground (configurable). + */ + GS_CSP_PORT_HK_BEACON = 30, + +} gs_csp_port_t; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/include/rparam.h b/gomspace/include/rparam.h new file mode 100644 index 00000000..fb838c73 --- /dev/null +++ b/gomspace/include/rparam.h @@ -0,0 +1,141 @@ +#ifndef GS_PARAM_INTERNAL_RPARAM_H +#define GS_PARAM_INTERNAL_RPARAM_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Max query payload in a single message (bytes). +*/ +#define GS_RPARAM_QUERY_MAX_PAYLOAD 180 + +/** + Macro for calculating total query message size, header + payload. +*/ +#define RPARAM_QUERY_LENGTH(query, payload_size) (sizeof(*query) - sizeof(query->payload) + payload_size) + +/** + R(emote) parameter request codes. +*/ +typedef enum { + /** + Get one or more parameters. + */ + RPARAM_GET = 0x00, + /** + Reply to a request. + */ + RPARAM_REPLY = 0x55, + /** + Set one or more parameters. + */ + RPARAM_SET = 0xFF, + // RPARAM_SET_TO_FILE = 0xEE, + /** + Download table specification. + */ + RPARAM_TABLE = 0x44, + /** + Copy memory slot to memory slot. + @version 4.x: Not supported. + */ + RPARAM_COPY = 0x77, + /** + Load from file (slot) to memory (slot). + @version 4.x: Only load from primary store - file (slot) is ignored. + */ + RPARAM_LOAD = 0x88, + /** + Load from file (slot) to memory (slot). + @version 4.x: load by name(s). + */ + RPARAM_LOAD_FROM_STORE = 0x89, + /** + Save from memory (slot) to file (slot). + @version 4.x: Only save to primary store - file (slot) is ignored. + */ + RPARAM_SAVE = 0x99, + /** + Save from memory (slot) to file (slot). + @version 4.x: save by name(s). + */ + RPARAM_SAVE_TO_STORE = 0x9a, + // RPARAM_CLEAR = 0xAA, - completely removed +} gs_rparam_action_t; + +/** + R(emote) parameter reply/completion codes. +*/ +typedef enum { + RPARAM_SET_OK = 1, + RPARAM_LOAD_OK = 2, + RPARAM_SAVE_OK = 3, + RPARAM_COPY_OK = 4, + // RPARAM_CLEAR_OK = 5, + RPARAM_ERROR = 0xFF, +} gs_rparam_reply_t; + +/** + Payload - save/load to/from stores + @version 4 +*/ +typedef struct __attribute__ ((packed)) { + char table[25 + 1]; + char store[25 + 1]; + char slot[25 + 1]; +} gs_rparam_query_payload_store_t; + +/** + Payload. +*/ +typedef union __attribute__ ((packed)) { + uint16_t addr[0]; //! action = RPARAM_GET + uint8_t packed[0]; //! action = RPARAM_REPLY | RPARAM_SET + struct { //! action = RPARAM_COPY | RPARAM_LOAD | RPARM_SAVE + uint8_t from; + uint8_t to; + } copy; +} gs_rparam_query_payload_t; + +/** + Protocol between client and server. + @version 4.x: layout (size) has not changed - only naming of certain fields. +*/ +typedef struct __attribute__ ((packed)) { + /** + Request (gs_rparam_action_t) or Reply (gs_rparam_reply_t). + */ + uint8_t action; + /** + Table id. + Name changed in 4.0 from \a mem. + */ + uint8_t table_id; + /** + Length/size of \a payload in bytes. + */ + uint16_t length; + /** + Fletcher's checksum. + */ + uint16_t checksum; + /** + Sequence number when split over multiple frames (messages). + */ + uint16_t seq; + /** + Total number of frames. + */ + uint16_t total; + /** + Payload. + */ + gs_rparam_query_payload_t payload; +} gs_rparam_query_t; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/test/testtasks/P60DockTestTask.cpp b/test/testtasks/P60DockTestTask.cpp index 3db66933..41696870 100644 --- a/test/testtasks/P60DockTestTask.cpp +++ b/test/testtasks/P60DockTestTask.cpp @@ -9,6 +9,7 @@ #include #include "P60DockTestTask.h" +#include "gomspace/include/rparam.h" P60DockTestTask::P60DockTestTask(object_id_t objectId_): SystemObject(objectId_){ @@ -73,6 +74,74 @@ ReturnValue_t P60DockTestTask::sendPacket(void){ } +ReturnValue_t P60DockTestTask::getParameterTable(unit8_t tableId){ + + gs_rparam_query_t * query; + csp_packet_t * request = csp_buffer_get(RPARAM_QUERY_LENGTH(query, 0)); + if (request == NULL) { + sif::error << "Failed to get buffer for csp packet" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + csp_conn_t * conn = csp_connect(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, CSP_O_CRC32); + if (!conn) { + csp_buffer_free(request); + sif::error << "CSP connection failure" << sif::error << std::endl; + return HasReturnvaluesIF::RETURN_OK; + } + + query = (gs_rparam_query_t *) request->data; + query->action = RPARAM_GET; + query->table_id = table_id; + query->length = 0; // == get full table + query->checksum = csp_hton16(checksum); + query->seq = 0; + query->total = 0; + + request->length = RPARAM_QUERY_LENGTH(query, 0); + if (!csp_send(conn, request, timeout_ms)) { + csp_buffer_free(request); + csp_close(conn); + sif::error << "CSP failed to send packet" << sif::error; + return HasReturnvaluesIF::RETURN_FAILED; + } + + csp_packet_t * reply; + unsigned int total_bytes = 0; + while ((reply = csp_read(conn, timeout_ms)) != NULL) { + + /* We have a reply */ + query = (void *) reply->data; + const uint16_t qlength = csp_ntoh16(query->length); + total_bytes += qlength; + const uint16_t seq = csp_ntoh16(query->seq); + const uint16_t total = csp_ntoh16(query->total); + + if (query->action == RPARAM_REPLY) { + error = gs_param_deserialize(tinst, query->payload.packed, qlength, F_FROM_BIG_ENDIAN); + } + csp_buffer_free(reply); + + if (error || (seq >= total)) { + break; + } + } + + if (reply == NULL) { + error = GS_ERROR_TIMEOUT; + } + + if ((error == GS_OK) && (expected_bytes != total_bytes)) { + log_warning("%s: expected %u != received %u bytes", __FUNCTION__, expected_bytes, total_bytes); + error = GS_ERROR_DATA; + } + + csp_close(conn); + + return error; +} + + ReturnValue_t P60DockTestTask::initializeCSPStack(void){ /* Init CSP and CSP buffer system */ if (csp_init(cspAddress) != CSP_ERR_NONE diff --git a/test/testtasks/P60DockTestTask.h b/test/testtasks/P60DockTestTask.h index bcccb487..4222c017 100644 --- a/test/testtasks/P60DockTestTask.h +++ b/test/testtasks/P60DockTestTask.h @@ -39,6 +39,7 @@ private: ReturnValue_t sendPacket(void); ReturnValue_t initializeCSPStack(void); + ReturnValue_t getParameterTable(unit8_t tableId); }; From d97d1ce3825c42890d6edad5b434d8c3d8545edf Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Fri, 27 Nov 2020 12:07:33 +0100 Subject: [PATCH 006/360] p60 dock test task get parameters incomplete --- fsfw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsfw b/fsfw index 113397c6..6bedc9b8 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 113397c6c6ae4c46341f4880710e4e4d9b6e7630 +Subproject commit 6bedc9b805d9e51fbca0d4b881fab39f52b59a07 From fa58479b34dc68aeb6bc31098450d42ea4e08690 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Sat, 28 Nov 2020 13:41:30 +0100 Subject: [PATCH 007/360] read temperature test --- README.md | 17 + gomspace/gomspace.mk | 5 +- gomspace/libgscsp/include/gs/csp/address.h | 65 + gomspace/libgscsp/include/gs/csp/command.h | 25 + gomspace/libgscsp/include/gs/csp/conn.h | 26 + gomspace/libgscsp/include/gs/csp/csp.h | 202 +++ .../libgscsp/include/gs/csp/drivers/can/can.h | 54 + .../libgscsp/include/gs/csp/drivers/i2c/i2c.h | 29 + .../include/gs/csp/drivers/kiss/kiss.h | 30 + gomspace/libgscsp/include/gs/csp/error.h | 28 + .../include/gs/csp/linux/command_line.h | 24 + gomspace/libgscsp/include/gs/csp/log.h | 27 + gomspace/libgscsp/include/gs/csp/port.h | 111 ++ gomspace/libgscsp/include/gs/csp/router.h | 36 + gomspace/libgscsp/include/gs/csp/rtable.h | 31 + .../include/gs/csp/service_dispatcher.h | 124 ++ .../libgscsp/include/gs/csp/service_handler.h | 102 ++ gomspace/libgscsp/lib/libcsp/CHANGELOG | 113 ++ gomspace/libgscsp/lib/libcsp/CONTRIBUTORS | 3 + gomspace/libgscsp/lib/libcsp/COPYING | 503 ++++++++ gomspace/libgscsp/lib/libcsp/INSTALL.rst | 30 + gomspace/libgscsp/lib/libcsp/README.rst | 41 + .../libcsp/bindings/python/libcsp/__init__.py | 6 + gomspace/libgscsp/lib/libcsp/doc/example.rst | 123 ++ gomspace/libgscsp/lib/libcsp/doc/history.rst | 17 + .../libgscsp/lib/libcsp/doc/interfaces.rst | 95 ++ gomspace/libgscsp/lib/libcsp/doc/libcsp.rst | 21 + gomspace/libgscsp/lib/libcsp/doc/memory.rst | 28 + gomspace/libgscsp/lib/libcsp/doc/mtu.rst | 19 + .../libgscsp/lib/libcsp/doc/protocolstack.rst | 54 + .../libgscsp/lib/libcsp/doc/structure.rst | 27 + gomspace/libgscsp/lib/libcsp/doc/topology.rst | 26 + .../lib/libcsp/examples/csp_if_fifo.c | 165 +++ .../lib/libcsp/examples/csp_if_fifo_windows.c | 225 ++++ gomspace/libgscsp/lib/libcsp/examples/kiss.c | 151 +++ .../python_bindings_example_client.py | 42 + .../python_bindings_example_client_can.py | 30 + .../python_bindings_example_server.py | 72 ++ .../libgscsp/lib/libcsp/examples/simple.c | 200 +++ .../libgscsp/lib/libcsp/examples/zmqproxy.c | 82 ++ .../lib/libcsp/include/csp/arch/csp_clock.h | 60 + .../lib/libcsp/include/csp/arch/csp_malloc.h | 39 + .../lib/libcsp/include/csp/arch/csp_queue.h | 49 + .../libcsp/include/csp/arch/csp_semaphore.h | 109 ++ .../lib/libcsp/include/csp/arch/csp_system.h | 74 ++ .../lib/libcsp/include/csp/arch/csp_thread.h | 100 ++ .../lib/libcsp/include/csp/arch/csp_time.h | 57 + .../include/csp/arch/posix/pthread_queue.h | 118 ++ .../lib/libcsp/include/csp/crypto/csp_hmac.h | 73 ++ .../lib/libcsp/include/csp/crypto/csp_sha1.h | 81 ++ .../lib/libcsp/include/csp/crypto/csp_xtea.h | 52 + .../libgscsp/lib/libcsp/include/csp/csp.h | 545 ++++++++ .../lib/libcsp/include/csp/csp_buffer.h | 92 ++ .../libgscsp/lib/libcsp/include/csp/csp_cmp.h | 189 +++ .../lib/libcsp/include/csp/csp_crc32.h | 63 + .../lib/libcsp/include/csp/csp_debug.h | 150 +++ .../lib/libcsp/include/csp/csp_endian.h | 170 +++ .../lib/libcsp/include/csp/csp_error.h | 50 + .../lib/libcsp/include/csp/csp_iflist.h | 56 + .../lib/libcsp/include/csp/csp_interface.h | 54 + .../lib/libcsp/include/csp/csp_platform.h | 56 + .../lib/libcsp/include/csp/csp_rtable.h | 149 +++ .../lib/libcsp/include/csp/csp_types.h | 235 ++++ .../include/csp/drivers/can_socketcan.h | 22 + .../lib/libcsp/include/csp/drivers/i2c.h | 120 ++ .../lib/libcsp/include/csp/drivers/usart.h | 107 ++ .../include/csp/interfaces/csp_if_can.h | 76 ++ .../include/csp/interfaces/csp_if_i2c.h | 51 + .../include/csp/interfaces/csp_if_kiss.h | 110 ++ .../libcsp/include/csp/interfaces/csp_if_lo.h | 38 + .../include/csp/interfaces/csp_if_zmqhub.h | 26 + .../lib/libcsp/src/arch/freertos/csp_malloc.c | 33 + .../lib/libcsp/src/arch/freertos/csp_queue.c | 66 + .../libcsp/src/arch/freertos/csp_semaphore.c | 96 ++ .../lib/libcsp/src/arch/freertos/csp_system.c | 139 +++ .../lib/libcsp/src/arch/freertos/csp_thread.c | 38 + .../lib/libcsp/src/arch/freertos/csp_time.c | 46 + .../lib/libcsp/src/arch/macosx/csp_malloc.c | 31 + .../lib/libcsp/src/arch/macosx/csp_queue.c | 64 + .../libcsp/src/arch/macosx/csp_semaphore.c | 105 ++ .../lib/libcsp/src/arch/macosx/csp_system.c | 99 ++ .../lib/libcsp/src/arch/macosx/csp_thread.c | 31 + .../lib/libcsp/src/arch/macosx/csp_time.c | 65 + .../libcsp/src/arch/macosx/pthread_queue.c | 179 +++ .../lib/libcsp/src/arch/posix/csp_malloc.c | 31 + .../lib/libcsp/src/arch/posix/csp_queue.c | 64 + .../lib/libcsp/src/arch/posix/csp_semaphore.c | 164 +++ .../lib/libcsp/src/arch/posix/csp_system.c | 131 ++ .../lib/libcsp/src/arch/posix/csp_thread.c | 55 + .../lib/libcsp/src/arch/posix/csp_time.c | 54 + .../lib/libcsp/src/arch/posix/pthread_queue.c | 243 ++++ .../lib/libcsp/src/arch/windows/README | 18 + .../lib/libcsp/src/arch/windows/csp_malloc.c | 9 + .../lib/libcsp/src/arch/windows/csp_queue.c | 40 + .../libcsp/src/arch/windows/csp_semaphore.c | 74 ++ .../lib/libcsp/src/arch/windows/csp_system.c | 60 + .../lib/libcsp/src/arch/windows/csp_thread.c | 11 + .../lib/libcsp/src/arch/windows/csp_time.c | 20 + .../libcsp/src/arch/windows/windows_glue.h | 23 + .../libcsp/src/arch/windows/windows_queue.c | 91 ++ .../libcsp/src/arch/windows/windows_queue.h | 41 + .../lib/libcsp/src/bindings/python/pycsp.c | 1052 ++++++++++++++++ .../libgscsp/lib/libcsp/src/crypto/csp_hmac.c | 202 +++ .../libgscsp/lib/libcsp/src/crypto/csp_sha1.c | 217 ++++ .../libgscsp/lib/libcsp/src/crypto/csp_xtea.c | 134 ++ gomspace/libgscsp/lib/libcsp/src/csp_bridge.c | 94 ++ gomspace/libgscsp/lib/libcsp/src/csp_buffer.c | 224 ++++ gomspace/libgscsp/lib/libcsp/src/csp_conn.c | 498 ++++++++ gomspace/libgscsp/lib/libcsp/src/csp_conn.h | 112 ++ gomspace/libgscsp/lib/libcsp/src/csp_crc32.c | 140 +++ gomspace/libgscsp/lib/libcsp/src/csp_debug.c | 133 ++ gomspace/libgscsp/lib/libcsp/src/csp_dedup.c | 66 + gomspace/libgscsp/lib/libcsp/src/csp_dedup.h | 31 + gomspace/libgscsp/lib/libcsp/src/csp_endian.c | 204 +++ .../libgscsp/lib/libcsp/src/csp_hex_dump.c | 55 + gomspace/libgscsp/lib/libcsp/src/csp_iflist.c | 100 ++ gomspace/libgscsp/lib/libcsp/src/csp_io.c | 502 ++++++++ gomspace/libgscsp/lib/libcsp/src/csp_io.h | 47 + gomspace/libgscsp/lib/libcsp/src/csp_port.c | 105 ++ gomspace/libgscsp/lib/libcsp/src/csp_port.h | 55 + .../libgscsp/lib/libcsp/src/csp_promisc.c | 82 ++ .../libgscsp/lib/libcsp/src/csp_promisc.h | 30 + gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c | 149 +++ gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h | 54 + gomspace/libgscsp/lib/libcsp/src/csp_route.c | 346 ++++++ gomspace/libgscsp/lib/libcsp/src/csp_route.h | 24 + .../lib/libcsp/src/csp_service_handler.c | 334 +++++ .../libgscsp/lib/libcsp/src/csp_services.c | 233 ++++ gomspace/libgscsp/lib/libcsp/src/csp_sfp.c | 170 +++ .../libcsp/src/drivers/can/can_socketcan.c | 201 +++ .../libcsp/src/drivers/usart/usart_linux.c | 254 ++++ .../libcsp/src/drivers/usart/usart_windows.c | 230 ++++ .../lib/libcsp/src/interfaces/csp_if_can.c | 279 +++++ .../libcsp/src/interfaces/csp_if_can_pbuf.c | 77 ++ .../libcsp/src/interfaces/csp_if_can_pbuf.h | 31 + .../lib/libcsp/src/interfaces/csp_if_i2c.c | 116 ++ .../lib/libcsp/src/interfaces/csp_if_kiss.c | 260 ++++ .../lib/libcsp/src/interfaces/csp_if_lo.c | 61 + .../lib/libcsp/src/interfaces/csp_if_zmqhub.c | 165 +++ .../lib/libcsp/src/rtable/csp_rtable_cidr.c | 233 ++++ .../lib/libcsp/src/rtable/csp_rtable_static.c | 128 ++ .../lib/libcsp/src/transport/csp_rdp.c | 1102 +++++++++++++++++ .../lib/libcsp/src/transport/csp_transport.h | 46 + .../lib/libcsp/src/transport/csp_udp.c | 49 + .../libgscsp/lib/libcsp/utils/cfpsplit.py | 52 + .../libgscsp/lib/libcsp/utils/cspsplit.py | 52 + gomspace/libgscsp/lib/libcsp/waf | 170 +++ gomspace/libgscsp/lib/libcsp/wscript | 346 ++++++ .../libgscsp/src/bindings/python/pygscsp.c | 61 + gomspace/libgscsp/src/clock.c | 23 + gomspace/libgscsp/src/commands.c | 652 ++++++++++ gomspace/libgscsp/src/conn.c | 22 + gomspace/libgscsp/src/csp.c | 91 ++ gomspace/libgscsp/src/drivers/can/can.c | 108 ++ gomspace/libgscsp/src/drivers/i2c/i2c.c | 77 ++ gomspace/libgscsp/src/drivers/kiss/kiss.c | 36 + gomspace/libgscsp/src/error.c | 54 + gomspace/libgscsp/src/freertos/cpu.c | 8 + gomspace/libgscsp/src/linux/command_line.c | 265 ++++ gomspace/libgscsp/src/local.h | 21 + gomspace/libgscsp/src/log.c | 64 + gomspace/libgscsp/src/router.c | 84 ++ gomspace/libgscsp/src/rtable.c | 69 ++ gomspace/libgscsp/src/service_dispatcher.c | 213 ++++ gomspace/libgscsp/src/service_handler.c | 86 ++ gomspace/libgscsp/src/transaction.c | 67 + gomspace/libgscsp/wscript | 104 ++ .../include/gs/param/internal/types.h | 3 - gomspace/libutil/include/gs/util/log/log.h | 2 +- test/testtasks/P60DockTestTask.cpp | 22 +- test/testtasks/P60DockTestTask.h | 6 +- 171 files changed, 19670 insertions(+), 14 deletions(-) create mode 100644 gomspace/libgscsp/include/gs/csp/address.h create mode 100644 gomspace/libgscsp/include/gs/csp/command.h create mode 100644 gomspace/libgscsp/include/gs/csp/conn.h create mode 100644 gomspace/libgscsp/include/gs/csp/csp.h create mode 100644 gomspace/libgscsp/include/gs/csp/drivers/can/can.h create mode 100644 gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h create mode 100644 gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h create mode 100644 gomspace/libgscsp/include/gs/csp/error.h create mode 100644 gomspace/libgscsp/include/gs/csp/linux/command_line.h create mode 100644 gomspace/libgscsp/include/gs/csp/log.h create mode 100644 gomspace/libgscsp/include/gs/csp/port.h create mode 100644 gomspace/libgscsp/include/gs/csp/router.h create mode 100644 gomspace/libgscsp/include/gs/csp/rtable.h create mode 100644 gomspace/libgscsp/include/gs/csp/service_dispatcher.h create mode 100644 gomspace/libgscsp/include/gs/csp/service_handler.h create mode 100644 gomspace/libgscsp/lib/libcsp/CHANGELOG create mode 100644 gomspace/libgscsp/lib/libcsp/CONTRIBUTORS create mode 100644 gomspace/libgscsp/lib/libcsp/COPYING create mode 100644 gomspace/libgscsp/lib/libcsp/INSTALL.rst create mode 100644 gomspace/libgscsp/lib/libcsp/README.rst create mode 100644 gomspace/libgscsp/lib/libcsp/bindings/python/libcsp/__init__.py create mode 100644 gomspace/libgscsp/lib/libcsp/doc/example.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/history.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/interfaces.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/libcsp.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/memory.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/mtu.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/protocolstack.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/structure.rst create mode 100644 gomspace/libgscsp/lib/libcsp/doc/topology.rst create mode 100644 gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo.c create mode 100644 gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo_windows.c create mode 100644 gomspace/libgscsp/lib/libcsp/examples/kiss.c create mode 100644 gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client.py create mode 100644 gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client_can.py create mode 100644 gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_server.py create mode 100644 gomspace/libgscsp/lib/libcsp/examples/simple.c create mode 100644 gomspace/libgscsp/lib/libcsp/examples/zmqproxy.c create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_clock.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_malloc.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_queue.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_semaphore.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_system.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_thread.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_time.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/posix/pthread_queue.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_hmac.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_sha1.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_xtea.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_buffer.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_cmp.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_crc32.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_debug.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_endian.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_error.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_iflist.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_interface.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_platform.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_rtable.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_types.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/drivers/can_socketcan.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/drivers/i2c.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/drivers/usart.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_can.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_i2c.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_kiss.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_lo.h create mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_zmqhub.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_malloc.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_queue.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_semaphore.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_system.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_thread.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_time.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_malloc.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_queue.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_semaphore.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_system.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_thread.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_time.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/pthread_queue.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_malloc.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_queue.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_semaphore.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_system.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_thread.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_time.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/pthread_queue.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/README create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_malloc.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_queue.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_semaphore.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_system.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_thread.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_time.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_glue.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/bindings/python/pycsp.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/crypto/csp_hmac.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/crypto/csp_sha1.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/crypto/csp_xtea.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_bridge.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_buffer.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_conn.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_conn.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_crc32.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_debug.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_dedup.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_dedup.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_endian.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_hex_dump.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_iflist.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_io.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_io.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_port.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_port.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_promisc.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_promisc.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_route.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_route.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_service_handler.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_services.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_sfp.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/drivers/can/can_socketcan.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_linux.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_windows.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_i2c.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_kiss.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_lo.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_cidr.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_static.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/transport/csp_rdp.c create mode 100644 gomspace/libgscsp/lib/libcsp/src/transport/csp_transport.h create mode 100644 gomspace/libgscsp/lib/libcsp/src/transport/csp_udp.c create mode 100644 gomspace/libgscsp/lib/libcsp/utils/cfpsplit.py create mode 100644 gomspace/libgscsp/lib/libcsp/utils/cspsplit.py create mode 100644 gomspace/libgscsp/lib/libcsp/waf create mode 100644 gomspace/libgscsp/lib/libcsp/wscript create mode 100644 gomspace/libgscsp/src/bindings/python/pygscsp.c create mode 100644 gomspace/libgscsp/src/clock.c create mode 100644 gomspace/libgscsp/src/commands.c create mode 100644 gomspace/libgscsp/src/conn.c create mode 100644 gomspace/libgscsp/src/csp.c create mode 100644 gomspace/libgscsp/src/drivers/can/can.c create mode 100644 gomspace/libgscsp/src/drivers/i2c/i2c.c create mode 100644 gomspace/libgscsp/src/drivers/kiss/kiss.c create mode 100644 gomspace/libgscsp/src/error.c create mode 100644 gomspace/libgscsp/src/freertos/cpu.c create mode 100644 gomspace/libgscsp/src/linux/command_line.c create mode 100644 gomspace/libgscsp/src/local.h create mode 100644 gomspace/libgscsp/src/log.c create mode 100644 gomspace/libgscsp/src/router.c create mode 100644 gomspace/libgscsp/src/rtable.c create mode 100644 gomspace/libgscsp/src/service_dispatcher.c create mode 100644 gomspace/libgscsp/src/service_handler.c create mode 100644 gomspace/libgscsp/src/transaction.c create mode 100644 gomspace/libgscsp/wscript diff --git a/README.md b/README.md index 71f7860e..b70e1cd6 100644 --- a/README.md +++ b/README.md @@ -323,3 +323,20 @@ git merge upstream/master Alternatively, changes from other upstreams (forks) and branches can be merged like that in the same way. + +## PCDU +Connect to serial console of P60 Dock +```` +picocom -b 500000 /dev/ttyUSBx +```` +General information +```` +cmp ident +```` +List parameter table: +x values: 1,2 or 4 +```` +param table x +```` +Table 4 lists HK parameters + diff --git a/gomspace/gomspace.mk b/gomspace/gomspace.mk index 57d38da7..8a781ac8 100644 --- a/gomspace/gomspace.mk +++ b/gomspace/gomspace.mk @@ -6,6 +6,8 @@ CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/crypto/*.c) CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/arch/posix/*.c) CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/transport/*.c) CSRC += $(wildcard $(CURRENTPATH)/p60-dock_client/src/*.c) +CSRC += $(wildcard $(CURRENTPATH)/libutil/src/*.c) +CSRC += $(wildcard $(CURRENTPATH)/libutil/src/linux/*.c) CSRC += $(wildcard $(CURRENTPATH)/libparam_client/src/*.c) CSRC += $(wildcard $(CURRENTPATH)/libparam_client/src/rparam/*.c) @@ -16,4 +18,5 @@ INCLUDES += $(CURRENTPATH)/p60-dock_client/include/gs/p60-dock/param INCLUDES += $(CURRENTPATH)/libparam_client/include INCLUDES += $(CURRENTPATH)/libparam_client/include/deprecated INCLUDES += $(CURRENTPATH)/libp60_client/include -INCLUDES += $(CURRENTPATH)/libutil/include \ No newline at end of file +INCLUDES += $(CURRENTPATH)/libutil/include +INCLUDES += $(CURRENTPATH)/libgscsp/include \ No newline at end of file diff --git a/gomspace/libgscsp/include/gs/csp/address.h b/gomspace/libgscsp/include/gs/csp/address.h new file mode 100644 index 00000000..9d6e701c --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/address.h @@ -0,0 +1,65 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_ADDRESS_H +#define LIBGSCSP_INCLUDE_GS_CSP_ADDRESS_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Default CSP addresses for nodes in the satellite - often changed for each project. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Default address for OBC (On Board Computer). + Example: a3200-sdk. +*/ +#define GS_CSP_ADDR_OBC 1 +/** + Power supply. + Example: nano-power. +*/ +#define GS_CSP_ADDR_EPS 2 +/** + Payload address. +*/ +#define GS_CSP_ADDR_PAYLOAD_3 3 +/** + Default address for ADCS. + Example: a3200-adcs. +*/ +#define GS_CSP_ADDR_ADCS 4 +/** + Default address for radio. + Example: nanocom-ax. +*/ +#define GS_CSP_ADDR_NANOCOM 5 +/** + Payload address. +*/ +#define GS_CSP_ADDR_PAYLOAD_6 6 +/** + Battery pack. + Example: nano-power-bpx. +*/ +#define GS_CSP_ADDR_BPX 7 +/** + Payload address. +*/ +#define GS_CSP_ADDR_PAYLOAD_8 8 +/** + Reaction wheels. + Example: gsw-600. +*/ +#define GS_CSP_ADDR_GSW600 9 +/** + Antenna module. + Example: ant2150. +*/ +#define GS_CSP_ADDR_ANT2150 10 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/command.h b/gomspace/libgscsp/include/gs/csp/command.h new file mode 100644 index 00000000..79d518db --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/command.h @@ -0,0 +1,25 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_COMMAND_H +#define LIBGSCSP_INCLUDE_GS_CSP_COMMAND_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + CSP commands. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Register CSP commands. + @return_gs_error_t +*/ +gs_error_t gs_csp_register_commands(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/conn.h b/gomspace/libgscsp/include/gs/csp/conn.h new file mode 100644 index 00000000..c8bd755e --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/conn.h @@ -0,0 +1,26 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_CONN_H +#define LIBGSCSP_INCLUDE_GS_CSP_CONN_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Extensions to standard libcsp connection interface. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Return number of open connections. + + @return number of open connections. +*/ +size_t gs_csp_conn_get_open(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/csp.h b/gomspace/libgscsp/include/gs/csp/csp.h new file mode 100644 index 00000000..6268bced --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/csp.h @@ -0,0 +1,202 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_CSP_H +#define LIBGSCSP_INCLUDE_GS_CSP_CSP_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Extensions to standard libcsp. +*/ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Default CSP timeout (mS). + + Default timeout value for communicating with a satellite, based on round-trip time of approximately 500 mS. +*/ +#define GS_CSP_TIMEOUT 3000 + +/** + Check if address is a valid CSP adddress. + @param[in] address CSP address to verify + @return \a true if address is valid. +*/ +bool gs_csp_is_address_valid(uint8_t address); + +/** + gscsp and csp configuration. +*/ +typedef struct { + /** + Forward CSP logs to GomSpace log (libutil). + */ + bool use_gs_log; + + /** + Use command line options. + Configure interfaces specified on the command line. + @note Only supported on Linux - ignored on platforms without command line options. + */ + bool use_command_line_options; + + /** + Size of a CSP buffer (in bytes). + @see csp_buffer_init(). + */ + size_t csp_buffer_size; + /** + Number of CSP buffers to allocate. + @see csp_buffer_init(). + */ + size_t csp_buffers; + + /** + CSP address of the system + */ + uint8_t address; + /** + Host name, returned by the #CSP_CMP_IDENT request. + @note String must remain valid as long as the application is running. + */ + const char *hostname; + /** + Model, returned by the #CSP_CMP_IDENT request. + @note String must remain valid as long as the application is running. + */ + const char *model; + /** + Revision, returned by the #CSP_CMP_IDENT request + @note String must remain valid as long as the application is running. + */ + const char *revision; + +} gs_csp_conf_t; + +/** + Get default CSP configuration for server systems. + @param[in] conf user supplied configuration struct. +*/ +void gs_csp_conf_get_defaults_server(gs_csp_conf_t * conf); + +/** + Get default CSP configuration for embedded systems. + @param[in] conf user supplied configuration struct. +*/ +void gs_csp_conf_get_defaults_embedded(gs_csp_conf_t * conf); + +/** + Initialize CSP. + + Wraps initialization of libcsp, by calling following functions + - hooks CSP log system into GomSpace log system. + - initializes CSP buffers by calling csp_buffer_init() + - initializes CSP by calling csp_init() + - configure interfaces specificed on command line + - configure routing table specificed on command line, or default if only one interface is present. + + @param[in] conf configuration. + @return_gs_error_t +*/ +gs_error_t gs_csp_init(const gs_csp_conf_t * conf); + +/** + Perform an entire request/reply transaction, + + Copies both input buffer and reply to output buffer. + Also makes the connection and closes it again + Differ from 'csp_transaction()' by limiting input buffer size when input length is unknown + + @param[in] prio CSP Prio + @param[in] dest CSP Dest + @param[in] port CSP Port + @param[in] timeout timeout in ms + @param[in] tx_buf pointer to outgoing data buffer + @param[in] tx_len length of request to send + @param[out] rx_buf pointer to incoming data buffer + @param[in] rx_max_len length of expected reply (input buffer size) + @param[out] rx_len pointer to length of reply + @param[in] opts connection options. + @return GS_ERROR_OVERFLOW when input length larger than buffer - it still updates rx_buf + @return GS_ERROR_IO when 'csp_send()' or 'csp_read()' fails + @return GS_ERROR_ALLOC when 'csp_get_buffer()' fails + @return_gs_error_t + */ +gs_error_t gs_csp_transaction2(uint8_t prio, + uint8_t dest, + uint8_t port, + uint32_t timeout, + const void * tx_buf, + size_t tx_len, + void * rx_buf, + size_t rx_max_len, + size_t * rx_len, + uint32_t opts); + +/** + Perform an entire request/reply transaction, + + @param[in] prio CSP Prio + @param[in] dest CSP Dest + @param[in] port CSP Port + @param[in] timeout timeout in ms + @param[in] tx_buf pointer to outgoing data buffer + @param[in] tx_len length of request to send + @param[out] rx_buf pointer to incoming data buffer + @param[in] rx_max_len length of expected reply (input buffer size) + @param[out] rx_len pointer to length of reply + @return GS_ERROR_OVERFLOW when input length larger than buffer - it still updates rx_buf + @return GS_ERROR_IO when 'csp_send()' or 'csp_read()' fails + @return GS_ERROR_ALLOC when 'csp_get_buffer()' fails + @return_gs_error_t + @see gs_csp_transaction2() +*/ +static inline gs_error_t gs_csp_transaction(uint8_t prio, + uint8_t dest, + uint8_t port, + uint32_t timeout, + const void * tx_buf, + size_t tx_len, + void * rx_buf, + size_t rx_max_len, + size_t * rx_len) +{ + return gs_csp_transaction2(prio, dest, port, timeout, tx_buf, tx_len, rx_buf, rx_max_len, rx_len, 0); +} + +/** + Use an existing connection to perform a transaction. + + This is only possible if the next packet is on the same port and destination! + Differ from 'csp_transaction_persistent()' by limiting input buffer size when input length is unknown + + @param[in] conn pointer to connection structure + @param[in] timeout timeout in ms + @param[in] tx_buf pointer to outgoing data buffer + @param[in] tx_len length of request to send + @param[out] rx_buf pointer to incoming data buffer + @param[in] rx_max_len length of expected reply (input buffer size) + @param[out] rx_len pointer to length of reply + @return GS_ERROR_OVERFLOW when input length larger than buffer - it still updates rx_buf + @return GS_ERROR_IO when 'csp_send()' or 'csp_read()' fails + @return GS_ERROR_ALLOC when 'csp_get_buffer()' fails + @return_gs_error_t + */ +gs_error_t gs_csp_transaction_persistent(csp_conn_t * conn, + uint32_t timeout, + const void * tx_buf, + size_t tx_len, + void * rx_buf, + size_t rx_max_len, + size_t * rx_len); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/drivers/can/can.h b/gomspace/libgscsp/include/gs/csp/drivers/can/can.h new file mode 100644 index 00000000..453dabde --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/drivers/can/can.h @@ -0,0 +1,54 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_CAN_CAN_H +#define LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_CAN_CAN_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + GomSpace CAN API for CSP. +*/ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Default CAN interface name. +*/ +#define GS_CSP_CAN_DEFAULT_IF_NAME "CAN" + +/** + Initialize CSP for CAN device. + + @param[in] device CAN device + @param[in] csp_addr CSP address. + @param[in] mtu MTU, normally CSP_CAN_MTU. + @param[in] name name of CSP interface, if NULL #GS_CSP_CAN_DEFAULT_IF_NAME will be used. + @param[in] set_default_route if \a true, the device will be set as default route. + @param[out] csp_if the added CSP interface. + @return #GS_ERROR_EXIST if device already exists. + @return_gs_error_t +*/ +gs_error_t gs_csp_can_init2(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, bool set_default_route, csp_iface_t ** csp_if); + +/** + Initialize CSP for CAN device. + + @param[in] device CAN device + @param[in] csp_addr CSP address. + @param[in] mtu MTU, normally CSP_CAN_MTU. + @param[in] name name of CSP interface, if NULL #GS_CSP_CAN_DEFAULT_IF_NAME will be used. + @param[out] csp_if the added CSP interface. + @return #GS_ERROR_EXIST if device already exists. + @return_gs_error_t + @see gs_csp_can_init2() +*/ +gs_error_t gs_csp_can_init(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, csp_iface_t ** csp_if); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h b/gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h new file mode 100644 index 00000000..4b6204f1 --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h @@ -0,0 +1,29 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_I2C_I2C_H +#define LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_I2C_I2C_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + GomSpace I2C API for CSP. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Initialize CSP for I2C device. + @note I2C device must be initialized allready with the same I2C address as the CSP address. + + @param[in] device I2C device. + @param[in] csp_addr CSP address. + @return_gs_error_t +*/ +gs_error_t gs_csp_i2c_init(uint8_t device, uint8_t csp_addr); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h b/gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h new file mode 100644 index 00000000..cb098fce --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h @@ -0,0 +1,30 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_KISS_KISS_H +#define LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_KISS_KISS_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +/** + @file + + GomSpace KISS API for CSP. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Initialize CSP for KISS device. + @note KISS/UART device must be initialized all ready. + + @param[in] device KISS/UART device. + @return_gs_error_t +*/ +gs_error_t gs_csp_kiss_init(uint8_t device); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/error.h b/gomspace/libgscsp/include/gs/csp/error.h new file mode 100644 index 00000000..8de40787 --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/error.h @@ -0,0 +1,28 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_ERROR_H +#define LIBGSCSP_INCLUDE_GS_CSP_ERROR_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Converting CSP error codes to #gs_error_t +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Convert CSP error. + + @param[in] csp_error CSP error + @return GS error code representing the CSP error. +*/ +gs_error_t gs_csp_error(int csp_error); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/linux/command_line.h b/gomspace/libgscsp/include/gs/csp/linux/command_line.h new file mode 100644 index 00000000..e416eda5 --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/linux/command_line.h @@ -0,0 +1,24 @@ +#ifndef GS_CSP_LINUX_COMMAND_LINE_H +#define GS_CSP_LINUX_COMMAND_LINE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Command line support. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Command line options. +*/ +extern const struct argp_child gs_csp_command_line_options; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/log.h b/gomspace/libgscsp/include/gs/csp/log.h new file mode 100644 index 00000000..91360cc0 --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/log.h @@ -0,0 +1,27 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_LOG_H +#define LIBGSCSP_INCLUDE_GS_CSP_LOG_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + CSP log hook. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Hook into CSP log system. + All CSP logs will be logged through Log (libutil). + + @return_gs_error_t +*/ +gs_error_t gs_csp_log_init(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/port.h b/gomspace/libgscsp/include/gs/csp/port.h new file mode 100644 index 00000000..29fa32e4 --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/port.h @@ -0,0 +1,111 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_PORT_H +#define LIBGSCSP_INCLUDE_GS_CSP_PORT_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + Port definitions for standard CSP and GomSpace services. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Port definitions for standard CSP and GomSpace services. +*/ +typedef enum { + /** + CSP Management Protocol - standard CSP service. + */ + GS_CSP_CMP = CSP_CMP, // 0 + /** + Ping - standard CSP service. + */ + GS_CSP_PING = CSP_PING, // 1 + /** + Show process status - standard CSP service. + */ + GS_CSP_PS = CSP_PS, // 2 + /** + Show memory free - standard CSP service. + */ + GS_CSP_MEM_FREE = CSP_MEMFREE, // 3 + GS_CSP_MEMFREE = GS_CSP_MEM_FREE, + /** + Reboot/reset request - standard CSP service. + */ + GS_CSP_REBOOT = CSP_REBOOT, // 4 + /** + Show number of free CSP buffers - standard CSP service. + */ + GS_CSP_BUF_FREE = CSP_BUF_FREE, // 5 + /** + Show uptime (time since last reset) - standard CSP service. + */ + GS_CSP_UPTIME = CSP_UPTIME, // 6 + /** + Parameter service (libparam) + */ + GS_CSP_PORT_RPARAM = 7, + /** + File Transfer Service (libftp) + */ + GS_CSP_PORT_FTP = 9, + /** + Remote log service (liblog) + */ + GS_CSP_PORT_RLOG = 11, + /** + Remote GOSH service (librgosh) + */ + GS_CSP_PORT_RGOSH = 12, + /** + AIS command port (libais). + */ + GS_CSP_PORT_AIS = 13, + /** + ADS-B command port (libadsb). + */ + GS_CSP_PORT_ADSB = 14, + + /** + GomSpace Sensor Bus (libgssb). + */ + GS_CSP_PORT_GSSB = 16, + /** + Flight Planner (libfp). + */ + GS_CSP_PORT_FP = 18, + /** + ADCS (libadcs). + */ + GS_CSP_PORT_ADCS = 20, + /** + House Keeping (libhk). + */ + GS_CSP_PORT_HK = 21, + /** + G(omSpace) script service (libgosh) + */ + GS_CSP_PORT_GSCRIPT = 22, + /** + Remote shell (libgosh). + Executes shell commands (linux server only). + Requires CSP_O_RDP. + */ + GS_CSP_PORT_REMOTE_SHELL = 27, + /** + House keeping beacon port (libhk). + Default port for sending beacons from satellite to ground (configurable). + */ + GS_CSP_PORT_HK_BEACON = 30, + +} gs_csp_port_t; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/router.h b/gomspace/libgscsp/include/gs/csp/router.h new file mode 100644 index 00000000..dae8990a --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/router.h @@ -0,0 +1,36 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_ROUTER_H +#define LIBGSCSP_INCLUDE_GS_CSP_ROUTER_H +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ +/** + @file + + CSP router task, with support for stopping/terminating router task. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Start CSP router (task/thread). + @param[in] stack_size stack size in bytes, minimum 300 bytes. + @param[in] priority task priority, normally GS_THREAD_PRIORITY_HIGH. + @return_gs_error_t +*/ +gs_error_t gs_csp_router_task_start(size_t stack_size, gs_thread_priority_t priority); + +/** + Stop CSP router task (for testing). + + Signal stop to the router and waits for it to terminate (join). + @note Join is performed, which may hang forever if the router doesn't respond to the stop request. + @return_gs_error_t +*/ +gs_error_t gs_csp_router_task_stop(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/rtable.h b/gomspace/libgscsp/include/gs/csp/rtable.h new file mode 100644 index 00000000..511b7bc2 --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/rtable.h @@ -0,0 +1,31 @@ +#ifndef GS_CSP_RTABLE_H +#define GS_CSP_RTABLE_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + CSP routing table support. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Load routing table. + Extension to csp_rtable_load(). + + @param[in] rtable string containing the routing table to set/load. + @param[in] set_default_route if \a true, sets a default route if no routing table specified and only one interface configured. + @param[in] use_command_line_option if \a true (and command line supported), use command line options to configure routing. + @return_gs_error_t +*/ +gs_error_t gs_csp_rtable_load(const char * rtable, bool set_default_route, bool use_command_line_option); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/service_dispatcher.h b/gomspace/libgscsp/include/gs/csp/service_dispatcher.h new file mode 100644 index 00000000..e80ef66d --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/service_dispatcher.h @@ -0,0 +1,124 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_SERVICE_DISPATCHER_H +#define LIBGSCSP_INCLUDE_GS_CSP_SERVICE_DISPATCHER_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + CSP Service Dispatcher. + + The dispatcher is a task/thread, listening on a configured number of ports and forwards the the incoming connection + to a configured CSP service handler. + The dispatcher touches a software watchdog for every handled connection. +*/ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + CSP service dispatcher configuration. +*/ +typedef struct { + /** + Name of dispatcher. + */ + const char * name; + /** + Array of service handlers - index'ed by CSP port number. + */ + const gs_csp_service_handler_t * handler_array; + /** + Array size of \a handler_array. + */ + unsigned int handler_array_size; + /** + Bind to any unbound ports (CSP_ANY). + Only one task/dispatcher can bind to any ports. This can be used to log unexpected incoming connections. + */ + bool bind_any; + /** + Disable watchdog. + The watchdog is created with a fixed timeout of 20 seconds. + */ + bool disable_watchdog; + /** + CSP connection backlog. + If 0 (zero), the backlog is set to 10. + */ + size_t listen_backlog; + /** + Callback after timeout or processsed connection. + The return value is the next timeout in milli seconds. + Return UINT32_MAX to use default timeout. + */ + unsigned int (*callback)(void); + /** + Socket options. + */ + uint32_t socket_options; +} gs_csp_service_dispatcher_conf_t; + +/** + Basic CSP service handlers. + + Can be used to configure handlers for all basic CSP services. +*/ +#define GS_CSP_BASIC_SERVICE_HANDLERS \ + [GS_CSP_CMP] = gs_csp_cmp_service_handler, \ + [GS_CSP_PING] = gs_csp_ping_service_handler, \ + [GS_CSP_PS] = gs_csp_ps_service_handler, \ + [GS_CSP_MEMFREE] = gs_csp_mem_free_service_handler, \ + [GS_CSP_REBOOT] = gs_csp_reboot_service_handler, \ + [GS_CSP_BUF_FREE] = gs_csp_buf_free_service_handler, \ + [GS_CSP_UPTIME] = gs_csp_uptime_service_handler + +/** + Service dispatcher handle. + @see gs_csp_service_dispatcher_create(), gs_csp_service_dispatcher_close() +*/ +typedef struct gs_csp_service_dispatcher * gs_csp_service_dispatcher_t; + +/** + Create service dispatcher (task/thread). + + @param[in] conf configuration - must remain valid as long as the dispatcher is running. + @param[in] stack_size thread stack size. + @param[in] priority thread priority. + @param[out] return_handle created dispatcher - use NULL if not used. + @return_gs_error_t +*/ +gs_error_t gs_csp_service_dispatcher_create(const gs_csp_service_dispatcher_conf_t * conf, + size_t stack_size, + gs_thread_priority_t priority, + gs_csp_service_dispatcher_t * return_handle); + +/** + Wake up service dispatcher. + + This will cause the disapther to wake up (from listing for new connections), and invoke the configured \a callback function, + before listing for new connections. + + @param[in] handle dispatcher. + @return_gs_error_t +*/ +gs_error_t gs_csp_service_dispatcher_wake_up(gs_csp_service_dispatcher_t handle); + +/** + Destroy/close service dispatcher (for testing). + + Signal stop to the dispatcher and waits for it to terminate (join). + + @note Join is performed, which may hang forever if the dispatcher doesn't respond to the stop request. + @param[in] handle dispatcher. + @return_gs_error_t +*/ +gs_error_t gs_csp_service_dispatcher_destroy(gs_csp_service_dispatcher_t handle); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/include/gs/csp/service_handler.h b/gomspace/libgscsp/include/gs/csp/service_handler.h new file mode 100644 index 00000000..52479129 --- /dev/null +++ b/gomspace/libgscsp/include/gs/csp/service_handler.h @@ -0,0 +1,102 @@ +#ifndef LIBGSCSP_INCLUDE_GS_CSP_SERVICE_HANDLER_H +#define LIBGSCSP_INCLUDE_GS_CSP_SERVICE_HANDLER_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + CSP Service handler. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + CSP Service handler. + + It is the handler's responsibility to process all pakcets on the connection and close the connection when done - even if a failure + is returned. + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +typedef gs_error_t (*gs_csp_service_handler_t)(csp_conn_t * conn); + +/** + Service handler for CSP Management Protocol. + + Invokes standard libcsp service handler. + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +gs_error_t gs_csp_cmp_service_handler(csp_conn_t * conn); + +/** + Service handler for ping. + + Invokes standard libcsp service handler. + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +gs_error_t gs_csp_ping_service_handler(csp_conn_t * conn); + +/** + Service handler for getting process list. + + Invokes standard libcsp service handler. + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +gs_error_t gs_csp_ps_service_handler(csp_conn_t * conn); + +/** + Service handler for getting memory free. + + Invokes GomSpace handler, which doesn't use malloc() to determine \a free memory. + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +gs_error_t gs_csp_mem_free_service_handler(csp_conn_t * conn); + + +/** + Service handler for reboot (reset) of node. + + Invokes standard libcsp service handler. + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +gs_error_t gs_csp_reboot_service_handler(csp_conn_t * conn); + +/** + Service handler for getting free CSP buffers. + + Invokes standard libcsp service handler. + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +gs_error_t gs_csp_buf_free_service_handler(csp_conn_t * conn); + +/** + Service handler for getting uptime (in seconds). + + Invokes GomSpace handler (works on Linux). + + @param[in] conn incoming connection. + @return_gs_error_t +*/ +gs_error_t gs_csp_uptime_service_handler(csp_conn_t * conn); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/lib/libcsp/CHANGELOG b/gomspace/libgscsp/lib/libcsp/CHANGELOG new file mode 100644 index 00000000..a4945716 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/CHANGELOG @@ -0,0 +1,113 @@ +libcsp 1.4, 07-05-2015 +---------------------- +- new: General rtable interface with support for STATIC or CIDR format +- new: CIDR (classless interdomain routing) route table format with netmasks +- new: Bridge capability +- new: Added routing table (de)serialization functions for load/save +- new: Automatic packet deduplication using CRC32 (compile time option) +- new: Autogenerated python bindings using ctypesgen +- new: Task-less operation with router invocation from external scheduler function +- api: Refactor route_if_add to csp_iflist_add +- api: Refactor route_set and friends to rtable_set +- api: Refactor csp_fifo_qos to csp_qfifo +- api: Added defined to be backwards compatible with 1.x +- interfaces: Drop packets on LOOP interface not for own address (blackhole) +- interfaces: New ZMQHUB interface (using zeroMQ over TCP) +- other: Increase stack size from 250 to 1100 for csp_can_rx_task +- other: Cleanup in csp_route.c +- other: Show incoming interface name in debug message +- other: Remove newlines from debug calls +- improvement: Reduce debug hook function complexity with valist passing +- fix: csp_sleep_ms did not work + +libcsp 1.3, 07-05-2015 +---------------------- +- new: Split long process lists into multiple packets +- new: Added posix csp_clock.h +- new: cmp clock functions (requires that you provide csp_clock.h implementation) +- new: Added SFP (Small fragmentation protocol) for larger data chunks +- fix: csp_if_fifo example +- fix: NULL char at the end of rps +- doc: Updated mtu documentation +- other: Tested with FreeRTOS 8.0 +- other: Added disable-stlib option to build only object files + +libcsp 1.2, 25-10-2013 +---------------------- +- Feature release +- New: CMP service for peek and poke of memory +- New: CMP interface statistics struct is now packed +- New: Faster O(1) buffer system with reference counting and automatic alignment +- New: Thread safe KISS driver with support for multiple interfaces +- New: CSP interface struct now holds an opaque pointer to driver handle +- New: removed TXBUF from KISS driver entirely to minimize stack usage, added TX lock instead +- New: Pre-calculated CRC table .romem or PROGMEM on __avr__ +- New: Added buffer overflow protection to KISS interface +- New: Allow posting null pointers on conn RX queues +- New: Lower memory usage on AVR8 +- New: csp_route_save and csp_route_load functions +- New: option --disable-verbose to disable filenames and linenumber on debug +- Protocol: KISS uses csp_crc32 instead of it own embedded crc32 +- Improvement: Use buffer clone function to copy promisc packets +- Bugfix: Fix pointer size (32/16bit) in cmp_peek/poke +- Bugfix: Issue with double free in KISS fixed +- Bugfix: Change rdp_send timeout from packet to connection timeout to make sending task block longer +- Bugfix: Fix conn pool leak when using security check and discarding new packets +- Bugfix: Add packet too short check for CRC32 +- Bugfix: Accept CRC32 responses from nodes without CRC support +- Bugfix: Ensure csp_ping works for packets > 256 bytes +- Bugfix: Cleanup printf inside ISR functions +- Bugfix: Do not add forwarded packets to promisc queue twice +- Bugfix: Fix return value bug of csp_buffer_get when out of buffers +- Bugfix: Always post null pointer with lowest priority, not highest +- Bugfix: Add check on debug level before calling do_csp_debug, fixes #35 +- Other: Export csp/arch include files +- Other: Remove the use of bool type from csp_debug +- Other: Moved csp debug functions to csp_debug.h instead of csp.h +- Other: Ensure assignment of id happens using the uint32_t .ext value of the union, quenches warning + +libcsp 1.1, 24-08-2012 +---------------------- +- Feature release +- Defacto stable since Feb 2012 +- New: I2C interface +- New: KISS interface +- New: USART drivers for Linux, Mac and Windows +- New: Windows/MinGW support +- New: MacOSX support +- New: Interface register function +- New: Interface search function +- New: CMP service for remote route updating +- New: CMP service for interface statistics +- Improvement: Better QoS support +- Improvement: Send RDP control messages with high priority +- Improvement: WAF distcheck now works +- Improvement: Automatic endian discovery +- Improvement: Accept packets with CRC32 checksum if compiled without CRC32 support +- Improvement: Do not wake the router task if RDP is not enabled +- Improvement: Save 102 bytes of RAM by packing route entries +- Cleanup: Simplify CAN configuration +- Cleanup: Move architecture specific code to src/arch +- Bugfix: CSP_MEMFREE gives wrong answer on freertos AVR due to truncation +- Bugfix: Fixed wrong 64-bit size_t in csp_service_handler +- Bugfix: Fixed problem in csp_if_kiss when out of buffers +- Bigfix: Handle bus-off CAN IRQ for AT90CAN128 + +libcsp 1.0.1, 30-10-2011 +------------------------ +- Hotfix release +- Bugfix: missing extern in csp_if_lo.h + +libcsp 1.0, 24-10-2011 +---------------------- +- First official release +- New: CSP 32-bit header 1.0 +- Features: Network Router with promiscous mode, broadcast and QoS +- Features: Connection-oriented transport protocol w. flow-control +- Features: Connection-less "UDP" like transport +- Features: Encryption, Authentication and message check +- Features: Loopback interface +- Features: Python Bindings +- Features: CAN interface w. drivers for several chips +- Features: CSP-services (ping, reboot, uptime, memfree, buffree, ident) + diff --git a/gomspace/libgscsp/lib/libcsp/CONTRIBUTORS b/gomspace/libgscsp/lib/libcsp/CONTRIBUTORS new file mode 100644 index 00000000..97240f60 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/CONTRIBUTORS @@ -0,0 +1,3 @@ +Jeppe Ledet-Pedersen +Johan De Claville Christiansen +Dan Erik Holmstrøm diff --git a/gomspace/libgscsp/lib/libcsp/COPYING b/gomspace/libgscsp/lib/libcsp/COPYING new file mode 100644 index 00000000..54c619ad --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/COPYING @@ -0,0 +1,503 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/gomspace/libgscsp/lib/libcsp/INSTALL.rst b/gomspace/libgscsp/lib/libcsp/INSTALL.rst new file mode 100644 index 00000000..e68a46ed --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/INSTALL.rst @@ -0,0 +1,30 @@ +How to install LibCSP +===================== + +CSP uses the `waf` build system (http://code.google.com/p/waf/). In order to +compile CSP, you first need to configure the toolchain, what operating system +to compile for, the location of required libraries and whether to enable +certain optional features. + +To configure CSP to build with the AVR32 toolchain for FreeRTOS and output +the compiled libcsp.a and header files to the install directory, issue: + +.. code-block:: bash + + ./waf configure --toolchain=avr32- --with-os=freertos --prefix=install + +When compiling for FreeRTOS, the path to the FreeRTOS header files must be +specified with `--with-freertos=PATH.` + +A number of optional features can be enabled by from the configure script. +Support for XTEA encryption can e.g. be enabled with `--enable-xtea`. Run +`./waf configure --help` to list the available configure options. + +The CAN drivers can be enabled by appending the configure option `--with-driver-can=CHIP`, +where CHIP is one of 'socketcan', 'at91sam7a1', 'at91sam7a3' or 'at90can128'. + +To build and copy the library to the location specified with --prefix, use: + +.. code-block:: bash + + ./waf build install diff --git a/gomspace/libgscsp/lib/libcsp/README.rst b/gomspace/libgscsp/lib/libcsp/README.rst new file mode 100644 index 00000000..c8aff3d8 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/README.rst @@ -0,0 +1,41 @@ +The Cubesat Space Protocol +========================== + +Cubesat Space Protocol (CSP) is a small protocol stack written in C. CSP is designed to ease communication between distributed embedded systems in smaller networks, such as Cubesats. The design follows the TCP/IP model and includes a transport protocol, a routing protocol and several MAC-layer interfaces. The core of libcsp includes a router, a socket buffer pool and a connection oriented socket API. + +The protocol is based on a 32-bit header containing both transport and network-layer information. Its implementation is designed for, but not limited to, embedded systems such as the 8-bit AVR microprocessor and the 32-bit ARM and AVR from Atmel. The implementation is written in GNU C and is currently ported to run on FreeRTOS or POSIX operating systems such as Linux. + +The idea is to give sub-system developers of cubesats the same features of a TCP/IP stack, but without adding the huge overhead of the IP header. The small footprint and simple implementation allows a small 8-bit system with less than 4 kB of RAM to be fully connected on the network. This allows all subsystems to provide their services on the same network level, without any master node required. Using a service oriented architecture has several advantages compared to the traditional mater/slave topology used on many cubesats. + + * Standardised network protocol: All subsystems can communicate with eachother + * Service loose coupling: Services maintain a relationship that minimizes dependencies between subsystems + * Service abstraction: Beyond descriptions in the service contract, services hide logic from the outside world + * Service reusability: Logic is divided into services with the intention of promoting reuse. + * Service autonomy: Services have control over the logic they encapsulate. + * Service Redundancy: Easily add redundant services to the bus + * Reduces single point of failure: The complexity is moved from a single master node to several well defines services on the network + +The implementation of LibCSP is written with simplicity in mind, but it's compile time configuration allows it to have some rather advanced features as well: + +Features +-------- + + * Thread safe Socket API + * Router task with Quality of Services + * Connection-oriented operation (RFC 908 and 1151). + * Connection-less operation (similar to UDP) + * ICMP-like requests such as ping and buffer status. + * Loopback interface + * Very Small Footprint 48 kB code and less that 1kB ram required on ARM + * Zero-copy buffer and queue system + * Modular network interface system + * Modular OS interface, ported to FreeRTOS, windows (cygwin) and Linux + * Broadcast traffic + * Promiscuous mode + * Encrypted packets with XTEA in CTR mode + * Truncated HMAC-SHA1 Authentication (RFC 2104) + +LGPL Software license +--------------------- +The source code is available under an LGPL 2.1 license. See COPYING for the license text. + diff --git a/gomspace/libgscsp/lib/libcsp/bindings/python/libcsp/__init__.py b/gomspace/libgscsp/lib/libcsp/bindings/python/libcsp/__init__.py new file mode 100644 index 00000000..39de36b5 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/bindings/python/libcsp/__init__.py @@ -0,0 +1,6 @@ +import sys + +if sys.version_info >= (3, 0): + from libcsp_py3 import * +else: + from libcsp_py2 import * diff --git a/gomspace/libgscsp/lib/libcsp/doc/example.rst b/gomspace/libgscsp/lib/libcsp/doc/example.rst new file mode 100644 index 00000000..b82a055e --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/example.rst @@ -0,0 +1,123 @@ +Client and server example +========================= + +The following examples show the initialization of the protocol stack and examples of client/server code. + +Initialization Sequence +----------------------- + +This code initializes the CSP buffer system, device drivers and router core. The example uses the CAN interface function csp_can_tx but the initialization is similar for other interfaces. The loopback interface does not require any explicit initialization. + +.. code-block:: c + + #include + #include + + /* CAN configuration struct for SocketCAN interface "can0" */ + struct csp_can_config can_conf = {.ifc = "can0"}; + + /* Init buffer system with 10 packets of maximum 320 bytes each */ + csp_buffer_init(10, 320); + + /* Init CSP with address 1 */ + csp_init(1); + + /* Init the CAN interface with hardware filtering */ + csp_can_init(CSP_CAN_MASKED, &can_conf) + + /* Setup default route to CAN interface */ + csp_route_set(CSP_DEFAULT_ROUTE, &csp_can_tx, CSP_HOST_MAC); + + /* Start router task with 500 word stack, OS task priority 1 */ + csp_route_start_task(500, 1); + +Server +------ + +This example shows how to create a server task that listens for incoming connections. CSP should be initialized before starting this task. Note the use of `csp_service_handler()` as the default branch in the port switch case. The service handler will automatically reply to ICMP-like requests, such as pings and buffer status requests. + +.. code-block:: c + + void csp_task(void *parameters) { + /* Create socket without any socket options */ + csp_socket_t *sock = csp_socket(CSP_SO_NONE); + + /* Bind all ports to socket */ + csp_bind(sock, CSP_ANY); + + /* Create 10 connections backlog queue */ + csp_listen(sock, 10); + + /* Pointer to current connection and packet */ + csp_conn_t *conn; + csp_packet_t *packet; + + /* Process incoming connections */ + while (1) { + /* Wait for connection, 10000 ms timeout */ + if ((conn = csp_accept(sock, 10000)) == NULL) + continue; + + /* Read packets. Timout is 1000 ms */ + while ((packet = csp_read(conn, 1000)) != NULL) { + switch (csp_conn_dport(conn)) { + case MY_PORT: + /* Process packet here */ + default: + /* Let the service handler reply pings, buffer use, etc. */ + csp_service_handler(conn, packet); + break; + } + } + + /* Close current connection, and handle next */ + csp_close(conn); + } + } + +Client +------ + +This example shows how to allocate a packet buffer, connect to another host and send the packet. CSP should be initialized before calling this function. RDP, XTEA, HMAC and CRC checksums can be enabled per connection, by setting the connection option to a bitwise OR of any combination of `CSP_O_RDP`, `CSP_O_XTEA`, `CSP_O_HMAC` and `CSP_O_CRC`. + +.. code-block:: c + + int send_packet(void) { + + /* Get packet buffer for data */ + csp_packet_t *packet = csp_buffer_get(data_size); + if (packet == NULL) { + /* Could not get buffer element */ + printf("Failed to get buffer element\\n"); + return -1; + } + + /* Connect to host HOST, port PORT with regular UDP-like protocol and 1000 ms timeout */ + csp_conn_t *conn = csp_connect(CSP_PRIO_NORM, HOST, PORT, 1000, CSP_O_NONE); + if (conn == NULL) { + /* Connect failed */ + printf("Connection failed\\n"); + /* Remember to free packet buffer */ + csp_buffer_free(packet); + return -1; + } + + /* Copy message to packet */ + char *msg = "HELLO"; + strcpy(packet->data, msg); + + /* Set packet length */ + packet->length = strlen(msg); + + /* Send packet */ + if (!csp_send(conn, packet, 1000)) { + /* Send failed */ + printf("Send failed\\n"); + csp_buffer_free(packet); + } + + /* Close connection */ + csp_close(conn); + + return 0 + } diff --git a/gomspace/libgscsp/lib/libcsp/doc/history.rst b/gomspace/libgscsp/lib/libcsp/doc/history.rst new file mode 100644 index 00000000..ad064873 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/history.rst @@ -0,0 +1,17 @@ +History +======= + +The idea was developed by a group of students from Aalborg University in 2008. In 2009 the main developer started working for GomSpace, and CSP became integrated into the GomSpace products. The protocol is based on a 32-bit header containing both transport, network and MAC-layer information. It's implementation is designed for, but not limited to, embedded systems such as the 8-bit AVR microprocessor and the 32-bit ARM and AVR from Atmel. The implementation is written in C and is currently ported to run on FreeRTOS and POSIX and pthreads based operating systems like Linux and BSD. The three letter acronym CSP was originally an abbreviation for CAN Space Protocol because the first MAC-layer driver was written for CAN-bus. Now the physical layer has extended to include spacelink, I2C and RS232, the name was therefore extended to the more general CubeSat Space Protocol without changing the abbreviation. + +Satellites using CSP +-------------------- + +This is the known list of satellites or organisations that uses CSP. + + * GomSpace GATOSS GOMX-1 + * AAUSAT-3 + * EgyCubeSat + * EuroLuna + * NUTS + * Hawaiian Space Flight Laboratory + * GomSpace GOMX-3 diff --git a/gomspace/libgscsp/lib/libcsp/doc/interfaces.rst b/gomspace/libgscsp/lib/libcsp/doc/interfaces.rst new file mode 100644 index 00000000..5a80325c --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/interfaces.rst @@ -0,0 +1,95 @@ +CSP Interfaces +============== + +This is an example of how to implement a new layer-2 interface in CSP. The example is going to show how to create a `csp_if_fifo`, using a set of [named pipes](http://en.wikipedia.org/wiki/Named_pipe). The complete interface example code can be found in `examples/fifo.c`. For an example of a fragmenting interface, see the CAN interface in `src/interfaces/csp_if_can.c`. + +CSP interfaces are declared in a `csp_iface_t` structure, which sets the interface nexthop function and name. A maximum transmission unit can also be set, which forces CSP to drop outgoing packets above a certain size. The fifo interface is defined as: + +.. code-block:: c + + #include + #include + + csp_iface_t csp_if_fifo = { + .name = "fifo", + .nexthop = csp_fifo_tx, + .mtu = BUF_SIZE, + }; + +Outgoing traffic +---------------- + +The nexthop function takes a pointer to a CSP packet and a timeout as parameters. All outgoing packets that are routed to the interface are passed to this function: + +.. code-block:: c + + int csp_fifo_tx(csp_packet_t *packet, uint32_t timeout) { + write(tx_channel, &packet->length, packet->length + sizeof(uint32_t) + sizeof(uint16_t)); + csp_buffer_free(packet); + return 1; + } + +In the fifo interface, we simply transmit the header, length field and data using a write to the fifo. CSP does not dictate the wire format, so other interfaces may decide to e.g. ignore the length field if the physical layer provides start/stop flags. + +_Important notice: If the transmission succeeds, the interface must free the packet and return 1. If transmission fails, the nexthop function should return 0 and not free the packet, to allow retransmissions by the caller._ + +Incoming traffic +---------------- + +The interface also needs to receive incoming packets and pass it to the CSP protocol stack. In the fifo interface, this is handled by a thread that blocks on the incoming fifo and waits for packets: + +.. code-block:: c + + void * fifo_rx(void * parameters) { + csp_packet_t *buf = csp_buffer_get(BUF_SIZE); + /* Wait for packet on fifo */ + while (read(rx_channel, &buf->length, BUF_SIZE) > 0) { + csp_qfifo_write(buf, &csp_if_fifo, NULL); + buf = csp_buffer_get(BUF_SIZE); + } + } + +A new CSP buffer is preallocated with csp_buffer_get(). When data is received, the packet is passed to CSP using `csp_qfifo_write()` and a new buffer is allocated for the next packet. In addition to the received packet, `csp_qfifo_write()` takes two additional arguments: + +.. code-block:: c + + void csp_qfifo_write(csp_packet_t *packet, csp_iface_t *interface, CSP_BASE_TYPE *pxTaskWoken); + +The calling interface must be passed in `interface` to avoid routing loops. Furthermore, `pxTaskWoken` must be set to a non-NULL value if the packet is received in an interrupt service routine. If the packet is received in task context, NULL must be passed. 'pxTaskWoken' only applies to FreeRTOS systems, and POSIX system should always set the value to NULL. + +`csp_qfifo_write` will either accept the packet or free the packet buffer, so the interface must never free the packet after passing it to CSP. + +Initialization +-------------- + +In order to initialize the interface, and make it available to the router, use the following function found in `csp/csp_interface.h`: + +.. code-block:: c + + csp_route_add_if(&csp_if_fifo); + +This actually happens automatically if you try to call `csp_route_add()` with an interface that is unknown to the router. This may however be removed in the future, in order to ensure that all interfaces are initialised before configuring the routing table. The reason is, that some products released in the future may ship with an empty routing table, which is then configured by a routing protocol rather than a static configuration. + +In order to setup a manual static route, use the following example where the default route is set to the fifo interface: + +.. code-block:: c + + csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_fifo, CSP_NODE_MAC); + +All outgoing traffic except loopback, is now passed to the fifo interface's nexthop function. + +Building the example +-------------------- + +The fifo examples can be compiled with: + +.. code-block:: bash + + % gcc csp_if_fifo.c -o csp_if_fifo -I/include -L/build -lcsp -lpthread -lrt + +The two named pipes are created with: + +.. code-block:: bash + + % mkfifo server_to_client client_to_server + diff --git a/gomspace/libgscsp/lib/libcsp/doc/libcsp.rst b/gomspace/libgscsp/lib/libcsp/doc/libcsp.rst new file mode 100644 index 00000000..f866015f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/libcsp.rst @@ -0,0 +1,21 @@ +.. CSP Documentation master file. + +.. _libcsp: + +********************** +CubeSat Space Protocol +********************** + +.. toctree:: + :maxdepth: 3 + + ../README + history + structure + interfaces + memory + protocolstack + topology + mtu + example + diff --git a/gomspace/libgscsp/lib/libcsp/doc/memory.rst b/gomspace/libgscsp/lib/libcsp/doc/memory.rst new file mode 100644 index 00000000..4e38d711 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/memory.rst @@ -0,0 +1,28 @@ +How CSP uses memory +=================== + +CSP has been written for small microprocessor systems. The way memory is handled is therefore a tradeoff between the amount used and the code efficiency. This section tries to give some answers to what the memory is used for and how it it used. The primary memory blocks in use by CSP is: + + * Routing table + * Ports table + * Connection table + * Buffer pool + * Interface list + +Tables +------ +The reason for using tables for the routes, ports and connections is speed. When a new packet arrives the core of CSP needs to do a quick lookup in the connection so see if it can find an existing connection to which the packet matches. If this is not found, it will take a lookup in the ports table to see if there are any applications listening on the incoming port number. Another argument of using tables are pre-allocation. The linker will reserve an area of the memory for which the routes and connections can be stored. This avoid an expensive `malloc()` call during initialization of CSP, and practically costs zero CPU instructions. The downside of using tables are the wasted memory used by unallocated ports and connections. For the routing table the argumentation is the same, pre-allocation is better than calling `malloc()`. + +Buffer Pool +----------- + +The buffer handling system can be compiled for either static allocation or a one-time dynamic allocation of the main memory block. After this, the buffer system is entirely self-contained. All allocated elements are of the same size, so the buffer size must be chosen to be able to handle the maximum possible packet length. The buffer pool uses a queue to store pointers to free buffer elements. First of all, this gives a very quick method to get the next free element since the dequeue is an O(1) operation. Furthermore, since the queue is a protected operating system primitive, it can be accessed from both task-context and interrupt-context. The `csp_buffer_get` version is for task-context and `csp_buffer_get_isr` is for interrupt-context. Using fixed size buffer elements that are preallocated is again a question of speed and safety. + + +A basic concept of the buffer system is called Zero-Copy. This means that from userspace to the kernel-driver, the buffer is never copied from one buffer to another. This is a big deal for a small microprocessor, where a call to `memcpy()` can be very expensive. In practice when data is inserted into a packet, it is shifted a certain number of bytes in order to allow for a packet header to be prepended at the lower layers. This also means that there is a strict contract between the layers, which data can be modified and where. The buffer object is normally casted to a `csp_packet_t`, but when its given to an interface on the MAC layer it's casted to a `csp_i2c_frame_t` for example. + +Interface list +-------------- + +The interface list is a simple single-ended linked list of references to the interface specification structures. These structures are static const and allocated by the linker. The pointer to this data is inserted into the list one time during setup of the interface. Each entry in the routing table has a direct pointer to the interface element, thereby avoiding list lookup, but the list is needed in order for the dynamic route configuration to know which interfaces are available. + diff --git a/gomspace/libgscsp/lib/libcsp/doc/mtu.rst b/gomspace/libgscsp/lib/libcsp/doc/mtu.rst new file mode 100644 index 00000000..27753300 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/mtu.rst @@ -0,0 +1,19 @@ +Maximum Transfer Unit +===================== + +There are two things limiting the MTU of CSP. + + 1. The pre-allocated buffer pool’s allocation size + 2. The link layer protocol. + +So let’s assume that you have made a protocol called KISS with a MTU of 256. The 256 is the total amount of data that you can put into the CSP-packet. However, you need to take the overhead of the link layer into account. Typically this could consist of a length field and/or a start/stop flag. So the actual frame size on the link layer would for example be 256 bytes of data + 2 bytes sync flag + 2 bytes length field. + +This requires a buffer allocation of at lest 256 + 2 + 2. However, the CSP packet itself has some reserved bytes in the beginning of the packet (which you can see in csp.h) - so the recommended buffer allocation size is MAX MTU + 16 bytes. In this case the max MTU would be 256. + +If you try to pass data which is longer than the MTU, the chance is that you will also make a buffer overflow in the CSP buffer pool. However, lets assume that you have two interfaces one with an MTU of 200 bytes and another with an MTU of 100 bytes. In this case you might successfully transfer 150 bytes over the first interface, but the packet will be rejected once it comes to the second interface. + +If you want to increase your MTU of a specific link layer, it is up to the link layer protocol to implement its own fragmentation protocol. A good example is CAN-bus which only allows a frame size of 8 bytes. libcsp have a small protocol for this called the “CAN fragmentation protocol" or CFP for short. This allows data of much larger size to be transferred over the CAN bus. + +Okay, but what if you want to transfer 1000 bytes, and the network maximum MTU is 256? Well, since CSP does not include streaming sockets, only packet’s. Somebody will have to split that data up into chunks. It might be that you application have special knowledge about the datatype you are transmitting, and that it makes sense to split the 1000 byte content into 10 chunks of 100 byte status messages. This, application layer delimitation might be good if you have a situation with packet loss, because your receiver could still make good usage of the partially delivered chunks. + +But, what if you just want 1000 bytes transmitted, and you don’t care about the fragmentation unit, and also don’t want the hassle of writing the fragmentation code yourself? - In this case, libcsp now features a new (still experimental) feature called SFP (small fragmentation protocol) designed to work on the application layer. For this purpose you will not use csp_send and csp_recv, but csp_sfp_send and csp_sfp_recv. This will split your data into chunks of a certain size, enumerate them and transfer over a given connection. If a chunk is missing the SFP client will abort the reception, because SFP does not provide retransmission. If you wish to also have retransmission and orderly delivery you will have to open an RDP connection and send your SFP message to that connection. diff --git a/gomspace/libgscsp/lib/libcsp/doc/protocolstack.rst b/gomspace/libgscsp/lib/libcsp/doc/protocolstack.rst new file mode 100644 index 00000000..365aabbe --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/protocolstack.rst @@ -0,0 +1,54 @@ +The Protocol Stack +================== + +The CSP protocol stack includes functionality on all layers of the TCP/IP model: + +Layer 1: Drivers +---------------- + +Lib CSP is not designed for any specific processor or hardware peripheral, but yet these drivers are required in order to work. The intention of LibCSP is not to provide CAN, I2C or UART drivers for all platforms, however some drivers has been included for some platforms. If you do not find your platform supported, it is quite simple to add a driver that conforms to the CSP interfaces. For example the I2C driver just requires three functions: `init`, `send` and `recv`. For good stability and performance interrupt driven drivers are preferred in favor of polled drivers. Where applicable also DMA usage is recommended. + +Layer 2: MAC interfaces +----------------------- + +CSP has interfaces for I2C, CAN, RS232 (KISS) and Loopback. The layer 2 protocol software defines a frame-format that is suitable for the media. CSP can be easily extended with implementations for even more links. For example a radio-link and IP-networks. The file `csp_interface.h` declares the rx and tx functions needed in order to define a network interface in CSP. During initialisation of CSP each interface will be inserted into a linked list of interfaces that is available to the router. In cases where link-layer addresses are required, such as I2C, the routing table supports specifying next-hop link-layer address directly. This avoids the need to implement an address resolution protocol to translate CSP addresses to I2C addresses. + +Layer 3: Network Router +----------------------- + +The router core is the backbone of the CSP implementation. The router works by looking at a 32-bit CSP header which contains the delivery and source address together with port numbers for the connection. Each router supports both local delivery and forwarding of frames to another destination. Frames will never exit the router on the same interface that they arrives at, this concept is called split horizon, and helps prevent routing loops. + +The main purpose of the router is to accept incoming packets and deliver them to the right message queue. Therefore, in order to listen on a port-number on the network, a task must create a socket and call the accept() call. This will make the task block and wait for incoming traffic, just like a web-server or similar. When an incoming connection is opened, the task is woken. Depending on the task-priority, the task can even preempt another task and start execution immediately. + +There is no routing protocol for automatic route discovery, all routing tables are pre-programmed into the subsystems. The table itself contains a separate route to each of the possible 32 nodes in the network and the additional default route. This means that the overall topology must be decided before putting sub-systems together, as explained in the `topology.md` file. However CSP has an extension on port zero CMP (CSP management protocol), which allows for over-the-network routing table configuration. This has the advantage that default routes could be changed if for example the primary radio fails, and the secondary should be used instead. + +Layer 4: Transport Layer +------------------------ + +LibCSP implements two different Transport Layer protocols, they are called UDP (unreliable datagram protocol) and RDP (reliable datagram protocol). The name UDP has not been chosen to be an exact replica of the UDP (user datagram protocol) known from the TCP/IP model, but they have certain similarities. + +The most important thing to notice is that CSP is entirely a datagram service. There is no stream based service like TCP. A datagram is defined a block of data with a specified size and structure. This block enters the transport layer as a single datagram and exits the transport layer in the other end as a single datagram. CSP preserves this structure all the way to the physical layer for I2C, KISS and Loopback interfaces are used. The CAN-bus interface has to fragment the datagram into CAN-frames of 8 bytes, however only a fully completed datagram will arrive at the receiver. + +UDP +^^^ + +UDP uses a simple transmission model without implicit hand-shaking dialogues for guaranteeing reliability, ordering, or data integrity. Thus, UDP provides an unreliable service and datagrams may arrive out of order, appear duplicated, or go missing without notice. UDP assumes that error checking and correction is either not necessary or performed in the application, avoiding the overhead of such processing at the network interface level. Time-sensitive applications often use UDP because dropping packets is preferable to waiting for delayed packets, which may not be an option in a real-time system. + +UDP is very practical to implement request/reply based communication where a single packet forms the request and a single packet forms the reply. In this case a typical request and wait protocol is used between the client and server, which will simply return an error if a reply is not received within a specified time limit. An error would normally lead to a retransmission of the request from the user or operator which sent the request. + +While UDP is very simple, it also has some limitations. Normally a human in the loop is a good thing when operating the satellite over UDP. But when it comes to larger file transfers, the human becomes the bottleneck. When a high-speed file transfer is initiated data acknowledgment should be done automatically in order to speed up the transfer. This is where the RDP protocol can help. + +RDP +^^^ +CSP provides a transport layer extension called RDP (reliable datagram protocol) which is an implementation of RFC908 and RFC1151. RDP provides a few additional features: + + * Three-way handshake + * Flow Control + * Data-buffering + * Packet re-ordering + * Retransmission + * Windowing + * Extended Acknowledgment + +For more information on this, please refer to RFC908. + diff --git a/gomspace/libgscsp/lib/libcsp/doc/structure.rst b/gomspace/libgscsp/lib/libcsp/doc/structure.rst new file mode 100644 index 00000000..4c9b515c --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/structure.rst @@ -0,0 +1,27 @@ +Structure +========= +The Cubesat Space Protocol library is structured as shown in the following table: + +============================= ========================================================================= +**Folder** **Description** +============================= ========================================================================= +libcsp/include/csp Main include files +libcsp/include/csp/arch Architecture include files +libcsp/include/csp/interfaces Interface include files +libcsp/include/csp/drivers Drivers include files +libcsp/src Main modules for CSP: io, router, connections, services +libcsp/src/interfaces Interface modules for CAN, I2C, KISS, LOOP and ZMQHUB +libcsp/src/drivers/can Driver for CAN +libcsp/src/drivers/usart Driver for USART +libcsp/src/arch/freertos FreeRTOS architecture module +libcsp/src/arch/macosx Mac OS X architecture module +libcsp/src/arch/posix Posix architecture module +libcsp/src/arch/windows Windows architecture module +libcsp/src/rtable Routing table module +libcsp/transport Transport module, UDP and RDP +libcsp/crypto Crypto module +libcsp/utils Utilities +libcsp/bindings/python Python wrapper for libcsp +libcsp/examples CSP examples (source code) +libasf/doc The doc folder contains the source code for this documentation +============================= ========================================================================= diff --git a/gomspace/libgscsp/lib/libcsp/doc/topology.rst b/gomspace/libgscsp/lib/libcsp/doc/topology.rst new file mode 100644 index 00000000..e629c29e --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/doc/topology.rst @@ -0,0 +1,26 @@ +Network Topology +================ + +CSP uses a network oriented terminology similar to what is known from the Internet and the TCP/IP model. A CSP network can be configured for several different topologies. The most common topology is to create two segments, one for the Satellite and one for the Ground-Station. + +.. code-block:: none + + I2C BUS + _______________________________ + / | | | \ + +---+ +---+ +---+ +---+ +---+ + |OBC| |COM| |EPS| |PL1| |PL2| Nodes 0 - 7 (Space segment) + +---+ +---+ +---+ +---+ +---+ + ^ + | Radio + v + +---+ +----+ + |TNC| ------- | PC | Nodes 8 - 15 (Ground segment) + +---+ USB +----+ + + Node 9 Node 10 + +The address range, from 0 to 15, has been segmented into two equal size segments. This allows for easy routing in the network. All addresses starting with binary 1 is on the ground-segment, and all addresses starting with 0 is on the space segment. From CSP v1.0 the address space has been increased to 32 addresses, 0 to 31. But for legacy purposes, the old 0 to 15 is still used in most products. + +The network is configured using static routes initialised at boot-up of each sub-system. This means that the basic routing table must be assigned compile-time of each subsystem. However each node supports assigning an individual route to every single node in the network and can be changed run-time. This means that the network topology can be easily reconfigured after startup. + diff --git a/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo.c b/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo.c new file mode 100644 index 00000000..136fc3aa --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo.c @@ -0,0 +1,165 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TYPE_SERVER 1 +#define TYPE_CLIENT 2 +#define PORT 10 +#define BUF_SIZE 250 + +pthread_t rx_thread; +int rx_channel, tx_channel; + +int csp_fifo_tx(csp_iface_t *ifc, csp_packet_t *packet, uint32_t timeout); + +csp_iface_t csp_if_fifo = { + .name = "fifo", + .nexthop = csp_fifo_tx, + .mtu = BUF_SIZE, +}; + +int csp_fifo_tx(csp_iface_t *ifc, csp_packet_t *packet, uint32_t timeout) { + /* Write packet to fifo */ + if (write(tx_channel, &packet->length, packet->length + sizeof(uint32_t) + sizeof(uint16_t)) < 0) + printf("Failed to write frame\r\n"); + csp_buffer_free(packet); + return CSP_ERR_NONE; +} + +void * fifo_rx(void * parameters) { + csp_packet_t *buf = csp_buffer_get(BUF_SIZE); + /* Wait for packet on fifo */ + while (read(rx_channel, &buf->length, BUF_SIZE) > 0) { + csp_qfifo_write(buf, &csp_if_fifo, NULL); + buf = csp_buffer_get(BUF_SIZE); + } + + return NULL; +} + +int main(int argc, char **argv) { + + int me, other, type; + const char *message = "Testing CSP"; + const char *rx_channel_name; + const char *tx_channel_name; + csp_socket_t *sock; + csp_conn_t *conn; + csp_packet_t *packet; + + /* Run as either server or client */ + if (argc != 2) { + printf("usage: %s \r\n", argv[0]); + return -1; + } + + /* Set type */ + if (strcmp(argv[1], "server") == 0) { + me = 1; + other = 2; + tx_channel_name = "server_to_client"; + rx_channel_name = "client_to_server"; + type = TYPE_SERVER; + } else if (strcmp(argv[1], "client") == 0) { + me = 2; + other = 1; + tx_channel_name = "client_to_server"; + rx_channel_name = "server_to_client"; + type = TYPE_CLIENT; + } else { + printf("Invalid type. Must be either 'server' or 'client'\r\n"); + return -1; + } + + /* Init CSP and CSP buffer system */ + if (csp_init(me) != CSP_ERR_NONE || csp_buffer_init(10, 300) != CSP_ERR_NONE) { + printf("Failed to init CSP\r\n"); + return -1; + } + + tx_channel = open(tx_channel_name, O_RDWR); + if (tx_channel < 0) { + printf("Failed to open TX channel\r\n"); + return -1; + } + + rx_channel = open(rx_channel_name, O_RDWR); + if (rx_channel < 0) { + printf("Failed to open RX channel\r\n"); + return -1; + } + + /* Start fifo RX task */ + pthread_create(&rx_thread, NULL, fifo_rx, NULL); + + /* Set default route and start router */ + csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_fifo, CSP_NODE_MAC); + csp_route_start_task(0, 0); + + /* Create socket and listen for incoming connections */ + if (type == TYPE_SERVER) { + sock = csp_socket(CSP_SO_NONE); + csp_bind(sock, PORT); + csp_listen(sock, 5); + } + + /* Super loop */ + while (1) { + if (type == TYPE_SERVER) { + /* Process incoming packet */ + conn = csp_accept(sock, 1000); + if (conn) { + packet = csp_read(conn, 0); + if (packet) + printf("Received: %s\r\n", packet->data); + csp_buffer_free(packet); + csp_close(conn); + } + } else { + /* Send a new packet */ + packet = csp_buffer_get(strlen(message)); + if (packet) { + strcpy((char *) packet->data, message); + packet->length = strlen(message); + + conn = csp_connect(CSP_PRIO_NORM, other, PORT, 1000, CSP_O_NONE); + printf("Sending: %s\r\n", message); + if (!conn || !csp_send(conn, packet, 1000)) + return -1; + csp_close(conn); + } + sleep(1); + } + } + + close(rx_channel); + close(tx_channel); + + return 0; +} diff --git a/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo_windows.c b/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo_windows.c new file mode 100644 index 00000000..5b360709 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo_windows.c @@ -0,0 +1,225 @@ +#include +#include +#include +#include +#include +#undef interface + +#include +#include + +#define PIPE_BUFSIZE 1024 + +#define TYPE_SERVER 1 +#define TYPE_CLIENT 2 +#define PORT 10 +#define BUF_SIZE 250 + + +static LPCTSTR pipeName = TEXT("\\\\.\\pipe\\CSP_Pipe"); + +static HANDLE pipe = INVALID_HANDLE_VALUE; + +unsigned WINAPI fifo_rx(void *); +unsigned WINAPI pipe_listener(void *); + +void printError(void); + +int csp_fifo_tx(csp_packet_t *packet, uint32_t timeout); + +csp_iface_t csp_if_fifo = { + .name = "fifo", + .nexthop = csp_fifo_tx, + .mtu = BUF_SIZE, +}; + +int csp_fifo_tx(csp_packet_t *packet, uint32_t timeout) { + printf("csp_fifo_tx tid: %lu\n", GetCurrentThreadId()); + DWORD expectedSent = packet->length + sizeof(uint32_t) + sizeof(uint16_t); + DWORD actualSent; + /* Write packet to fifo */ + if( !WriteFile(pipe, &packet->length, expectedSent, &actualSent, NULL) + || actualSent != expectedSent ) { + printError(); + } + + csp_buffer_free(packet); + return CSP_ERR_NONE; +} + + +int main(int argc, char *argv[]) { + int me, other, type; + char *message = "Testing CSP"; + csp_socket_t *sock = NULL; + csp_conn_t *conn = NULL; + csp_packet_t *packet = NULL; + + /* Run as either server or client */ + if (argc != 2) { + printf("usage: server \r\n"); + return -1; + } + + /* Set type */ + if (strcmp(argv[1], "server") == 0) { + me = 1; + other = 2; + type = TYPE_SERVER; + } else if (strcmp(argv[1], "client") == 0) { + me = 2; + other = 1; + type = TYPE_CLIENT; + } else { + printf("Invalid type. Must be either 'server' or 'client'\r\n"); + return -1; + } + + /* Init CSP and CSP buffer system */ + if (csp_init(me) != CSP_ERR_NONE || csp_buffer_init(10, 300) != CSP_ERR_NONE) { + printf("Failed to init CSP\r\n"); + return -1; + } + + if( type == TYPE_SERVER ) { + _beginthreadex(NULL, 0, pipe_listener, NULL, 0, 0); + } else { + pipe = CreateFile( + pipeName, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + 0, + NULL); + if( pipe == INVALID_HANDLE_VALUE ) { + printError(); + return -1; + } + } + + /* Set default route and start router */ + csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_fifo, CSP_NODE_MAC); + csp_route_start_task(0, 0); + + /* Create socket and listen for incoming connections */ + if (type == TYPE_SERVER) { + sock = csp_socket(CSP_SO_NONE); + csp_bind(sock, PORT); + csp_listen(sock, 5); + } + + /* Super loop */ + while (1) { + if (type == TYPE_SERVER) { + /* Process incoming packet */ + conn = csp_accept(sock, 1000); + if (conn) { + packet = csp_read(conn, 0); + if (packet) + printf("Received: %s\r\n", packet->data); + csp_buffer_free(packet); + csp_close(conn); + } + } else { + /* Send a new packet */ + packet = csp_buffer_get(strlen(message)); + if (packet) { + strcpy((char *) packet->data, message); + packet->length = strlen(message); + + conn = csp_connect(CSP_PRIO_NORM, other, PORT, 1000, CSP_O_NONE); + printf("Sending: %s\r\n", message); + if (!conn || !csp_send(conn, packet, 1000)) + return -1; + csp_close(conn); + Sleep(1000); + } + } + } + + return 0; +} + +void printError(void) { + LPTSTR messageBuffer = NULL; + DWORD errorCode = GetLastError(); + DWORD formatMessageRet; + formatMessageRet = FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + errorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&messageBuffer, + 0, + NULL); + + if( !formatMessageRet ) { + wprintf(L"FormatMessage error, code: %lu\n", GetLastError()); + return; + } + + printf("%s\n", messageBuffer); + LocalFree(messageBuffer); +} + +unsigned WINAPI pipe_listener(void *parameters) { + while(1) { + HANDLE pipe = CreateNamedPipe( + pipeName, + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + PIPE_BUFSIZE, + PIPE_BUFSIZE, + 0, + NULL); + BOOL clientConnected; + if( pipe == INVALID_HANDLE_VALUE ) { + printf("Error creating named pipe. Code %lu\n", GetLastError()); + return -1; + } + + // True if client connects *after* server called ConnectNamedPipe + // or *between* CreateNamedPipe and ConnectNamedPipe + clientConnected = + ConnectNamedPipe(pipe, NULL) ? TRUE : GetLastError()==ERROR_PIPE_CONNECTED; + printf("Client connected!\n"); + + if( !clientConnected ) { + printf("Failure while listening for clients. Code %lu\n", GetLastError()); + CloseHandle(pipe); + return -1; + } + printf("Create client thread\n"); + _beginthreadex(NULL, 0, fifo_rx, (PVOID)pipe, 0, 0); + } + + return 0; +} + +unsigned WINAPI fifo_rx(void *handle) { + printf("fifo_rx tid: %lu\n", GetCurrentThreadId()); + HANDLE pipe = (HANDLE) handle; + csp_packet_t *buf = csp_buffer_get(BUF_SIZE); + DWORD bytesRead; + BOOL readSuccess; + + while(1) { + readSuccess = + ReadFile(pipe, &buf->length, BUF_SIZE, &bytesRead, NULL); + if( !readSuccess || bytesRead == 0 ) { + csp_buffer_free(buf); + printError(); + break; + } + csp_qfifo_write(buf, &csp_if_fifo, NULL); + buf = csp_buffer_get(BUF_SIZE); + } + printf("Closing pipe to client\n"); + CloseHandle(pipe); + + return 0; +} diff --git a/gomspace/libgscsp/lib/libcsp/examples/kiss.c b/gomspace/libgscsp/lib/libcsp/examples/kiss.c new file mode 100644 index 00000000..c95eb2aa --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/kiss.c @@ -0,0 +1,151 @@ +/** + * Build this example on linux with: + * ./waf configure --enable-examples --enable-if-kiss --with-driver-usart=linux --enable-crc32 clean build + */ + +#include +#include +#include + +#include +#include + +#define PORT 10 +#define MY_ADDRESS 1 + +#define SERVER_TIDX 0 +#define CLIENT_TIDX 1 +#define USART_HANDLE 0 + +CSP_DEFINE_TASK(task_server) { + int running = 1; + csp_socket_t *socket = csp_socket(CSP_SO_NONE); + csp_conn_t *conn; + csp_packet_t *packet; + csp_packet_t *response; + + response = csp_buffer_get(sizeof(csp_packet_t) + 2); + if( response == NULL ) { + fprintf(stderr, "Could not allocate memory for response packet!\n"); + return CSP_TASK_RETURN; + } + response->data[0] = 'O'; + response->data[1] = 'K'; + response->length = 2; + + csp_bind(socket, CSP_ANY); + csp_listen(socket, 5); + + printf("Server task started\r\n"); + + while(running) { + if( (conn = csp_accept(socket, 10000)) == NULL ) { + continue; + } + + while( (packet = csp_read(conn, 100)) != NULL ) { + switch( csp_conn_dport(conn) ) { + case PORT: + if( packet->data[0] == 'q' ) + running = 0; + csp_buffer_free(packet); + csp_send(conn, response, 1000); + break; + default: + csp_service_handler(conn, packet); + break; + } + } + + csp_close(conn); + } + + csp_buffer_free(response); + + return CSP_TASK_RETURN; +} + +CSP_DEFINE_TASK(task_client) { + + char outbuf = 'q'; + char inbuf[3] = {0}; + int pingResult; + + for(int i = 50; i <= 200; i+= 50) { + pingResult = csp_ping(MY_ADDRESS, 1000, 100, CSP_O_NONE); + printf("Ping with payload of %d bytes, took %d ms\n", i, pingResult); + csp_sleep_ms(1000); + } + csp_ps(MY_ADDRESS, 1000); + csp_sleep_ms(1000); + csp_memfree(MY_ADDRESS, 1000); + csp_sleep_ms(1000); + csp_buf_free(MY_ADDRESS, 1000); + csp_sleep_ms(1000); + csp_uptime(MY_ADDRESS, 1000); + csp_sleep_ms(1000); + + csp_transaction(0, MY_ADDRESS, PORT, 1000, &outbuf, 1, inbuf, 2); + printf("Quit response from server: %s\n", inbuf); + + return CSP_TASK_RETURN; +} + +int main(int argc, char **argv) { + csp_debug_toggle_level(CSP_PACKET); + csp_debug_toggle_level(CSP_INFO); + + csp_buffer_init(10, 300); + csp_init(MY_ADDRESS); + + struct usart_conf conf; + +#if defined(CSP_WINDOWS) + conf.device = argc != 2 ? "COM4" : argv[1]; + conf.baudrate = CBR_9600; + conf.databits = 8; + conf.paritysetting = NOPARITY; + conf.stopbits = ONESTOPBIT; + conf.checkparity = FALSE; +#elif defined(CSP_POSIX) + conf.device = argc != 2 ? "/dev/ttyUSB0" : argv[1]; + conf.baudrate = 500000; +#elif defined(CSP_MACOSX) + conf.device = argc != 2 ? "/dev/tty.usbserial-FTSM9EGE" : argv[1]; + conf.baudrate = 115200; +#endif + + /* Run USART init */ + usart_init(&conf); + + /* Setup CSP interface */ + static csp_iface_t csp_if_kiss; + static csp_kiss_handle_t csp_kiss_driver; + csp_kiss_init(&csp_if_kiss, &csp_kiss_driver, usart_putc, usart_insert, "KISS"); + + /* Setup callback from USART RX to KISS RS */ + void my_usart_rx(uint8_t * buf, int len, void * pxTaskWoken) { + csp_kiss_rx(&csp_if_kiss, buf, len, pxTaskWoken); + } + usart_set_callback(my_usart_rx); + + csp_route_set(MY_ADDRESS, &csp_if_kiss, CSP_NODE_MAC); + csp_route_start_task(0, 0); + + csp_conn_print_table(); + csp_route_print_table(); + csp_route_print_interfaces(); + + csp_thread_handle_t handle_server; + csp_thread_create(task_server, "SERVER", 1000, NULL, 0, &handle_server); + csp_thread_handle_t handle_client; + csp_thread_create(task_client, "CLIENT", 1000, NULL, 0, &handle_client); + + /* Wait for program to terminate (ctrl + c) */ + while(1) { + csp_sleep_ms(1000000); + } + + return 0; + +} diff --git a/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client.py b/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client.py new file mode 100644 index 00000000..123ce36e --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client.py @@ -0,0 +1,42 @@ +#!/usr/bin/python + +# libcsp must be build with at least these options to run this example client: +# ./waf distclean configure build --enable-bindings --enable-crc32 --enable-rdp --enable-if-zmq --with-driver-usart=linux --enable-if-kiss --enable-xtea --enable-if-can --enable-can-socketcan --enable-hmac --enable-examples + +# Can be run from root of libcsp like this: +# LD_LIBRARY_PATH=build PYTHONPATH=bindings/python:build python examples/python_bindings_example_client.py +# + +import os +import time +import libcsp as csp + + +if __name__ == "__main__": + + csp.buffer_init(10, 300) + csp.init(28) + csp.zmqhub_init(28, "localhost") + csp.rtable_set(27, 5, "ZMQHUB") + csp.route_start_task() + + ## allow router task startup + time.sleep(1) + + ## cmp_ident + (rc, host, model, rev, date, time) = csp.cmp_ident(27) + if rc == csp.CSP_ERR_NONE: + print (host, model, rev, date, time) + else: + print ("error in cmp_ident, rc=%i" % (rc)) + + ## transaction + outbuf = bytearray().fromhex('01') + inbuf = bytearray(1) + print ("using csp_transaction to send a single byte") + if csp.transaction(0, 27, 10, 1000, outbuf, inbuf) < 1: + print ("csp_transaction failed") + else: + print ("got reply, data=" + ''.join('{:02x}'.format(x) for x in inbuf)) + + diff --git a/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client_can.py b/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client_can.py new file mode 100644 index 00000000..ec796572 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client_can.py @@ -0,0 +1,30 @@ +#!/usr/bin/python + +# libcsp must be build with at least these options to run this example client: +# ./waf distclean configure build --enable-bindings --enable-crc32 --enable-rdp --enable-if-zmq --with-driver-usart=linux --enable-if-kiss --enable-xtea --enable-if-can --enable-can-socketcan --enable-hmac --enable-examples + +# Can be run from root of libcsp like this: +# LD_LIBRARY_PATH=build PYTHONPATH=bindings/python:build python examples/python_bindings_example_client.py +# + +import os +import time +import libcsp as csp + + +if __name__ == "__main__": + + csp.buffer_init(10, 300) + csp.init(28) + csp.can_socketcan_init("can0") + csp.rtable_set(4, 5, "CAN") + csp.route_start_task() + + ## allow router task startup + time.sleep(1) + + + node = 4 + if csp.ping(node) < 0: + print ("Unable to ping node %d"%(node)) + diff --git a/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_server.py b/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_server.py new file mode 100644 index 00000000..3cf3f5da --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_server.py @@ -0,0 +1,72 @@ +#!/usr/bin/python + +# libcsp must be build with at least these options to run this example server: +# ./waf distclean configure build --enable-bindings --enable-crc32 --enable-rdp --enable-if-zmq --with-driver-usart=linux --enable-if-kiss --enable-xtea --enable-if-can --enable-can-socketcan --enable-hmac --enable-examples + +# Can be run from root of libcsp like this: +# LD_LIBRARY_PATH=build PYTHONPATH=bindings/python:build python examples/python_bindings_example_server.py +# + +import os +import time +import sys +import libcsp as csp +import subprocess + +if __name__ == "__main__": + + # start a zmqproxy to transport messages to and from the client + zmqp = subprocess.Popen('build/zmqproxy') + + # init csp + csp.buffer_init(10, 300) + csp.init(27) + csp.zmqhub_init(27, "localhost") + csp.rtable_set(28, 5, "ZMQHUB") + csp.route_start_task() + + # set identity + csp.set_hostname("test_service") + csp.set_model("bindings") + csp.set_revision("1.2.3") + + # and read it back + print (csp.get_hostname()) + print (csp.get_model()) + print (csp.get_revision()) + + # start listening for packets... + sock = csp.socket() + csp.bind(sock, csp.CSP_ANY) + csp.listen(sock) + while True: + conn = csp.accept(sock) + if not conn: + continue + + print ("connection: source=%i:%i, dest=%i:%i" % (csp.conn_src(conn), + csp.conn_sport(conn), + csp.conn_dst(conn), + csp.conn_dport(conn))) + + while True: + packet = csp.read(conn) + if not packet: + break + + if csp.conn_dport(conn) == 10: + data = bytearray(csp.packet_get_data(packet)) + length = csp.packet_get_length(packet) + print ("got packet, len=" + str(length) + ", data=" + ''.join('{:02x}'.format(x) for x in data)) + + data[0] = data[0] + 1 + reply_packet = csp.buffer_get(1) + if reply_packet: + csp.packet_set_data(reply_packet, data) + csp.sendto_reply(packet, reply_packet, csp.CSP_O_NONE) + + csp.buffer_free(packet) + else: + csp.service_handler(conn, packet) + csp.close(conn) + diff --git a/gomspace/libgscsp/lib/libcsp/examples/simple.c b/gomspace/libgscsp/lib/libcsp/examples/simple.c new file mode 100644 index 00000000..b996f8c1 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/simple.c @@ -0,0 +1,200 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +#include + +/* Using un-exported header file. + * This is allowed since we are still in libcsp */ +#include + +/** Example defines */ +#define MY_ADDRESS 1 // Address of local CSP node +#define MY_PORT 10 // Port to send test traffic to + +CSP_DEFINE_TASK(task_server) { + + /* Create socket without any socket options */ + csp_socket_t *sock = csp_socket(CSP_SO_NONE); + + /* Bind all ports to socket */ + csp_bind(sock, CSP_ANY); + + /* Create 10 connections backlog queue */ + csp_listen(sock, 10); + + /* Pointer to current connection and packet */ + csp_conn_t *conn; + csp_packet_t *packet; + + /* Process incoming connections */ + while (1) { + + /* Wait for connection, 10000 ms timeout */ + if ((conn = csp_accept(sock, 10000)) == NULL) + continue; + + /* Read packets. Timout is 100 ms */ + while ((packet = csp_read(conn, 100)) != NULL) { + switch (csp_conn_dport(conn)) { + case MY_PORT: + /* Process packet here */ + printf("Packet received on MY_PORT: %s\r\n", (char *) packet->data); + csp_buffer_free(packet); + break; + + default: + /* Let the service handler reply pings, buffer use, etc. */ + csp_service_handler(conn, packet); + break; + } + } + + /* Close current connection, and handle next */ + csp_close(conn); + + } + + return CSP_TASK_RETURN; + +} + +CSP_DEFINE_TASK(task_client) { + + csp_packet_t * packet; + csp_conn_t * conn; + + while (1) { + + /** + * Try ping + */ + + csp_sleep_ms(1000); + + int result = csp_ping(MY_ADDRESS, 100, 100, CSP_O_NONE); + printf("Ping result %d [ms]\r\n", result); + + csp_sleep_ms(1000); + + /** + * Try data packet to server + */ + + /* Get packet buffer for data */ + packet = csp_buffer_get(100); + if (packet == NULL) { + /* Could not get buffer element */ + printf("Failed to get buffer element\n"); + return CSP_TASK_RETURN; + } + + /* Connect to host HOST, port PORT with regular UDP-like protocol and 1000 ms timeout */ + conn = csp_connect(CSP_PRIO_NORM, MY_ADDRESS, MY_PORT, 1000, CSP_O_NONE); + if (conn == NULL) { + /* Connect failed */ + printf("Connection failed\n"); + /* Remember to free packet buffer */ + csp_buffer_free(packet); + return CSP_TASK_RETURN; + } + + /* Copy dummy data to packet */ + const char *msg = "Hello World"; + strcpy((char *) packet->data, msg); + + /* Set packet length */ + packet->length = strlen(msg); + + /* Send packet */ + if (!csp_send(conn, packet, 1000)) { + /* Send failed */ + printf("Send failed\n"); + csp_buffer_free(packet); + } + + /* Close connection */ + csp_close(conn); + + } + + return CSP_TASK_RETURN; +} + +int main(int argc, char * argv[]) { + + /** + * Initialise CSP, + * No physical interfaces are initialised in this example, + * so only the loopback interface is registered. + */ + + /* Init buffer system with 10 packets of maximum 300 bytes each */ + printf("Initialising CSP\r\n"); + csp_buffer_init(5, 300); + + /* Init CSP with address MY_ADDRESS */ + csp_init(MY_ADDRESS); + + /* Start router task with 500 word stack, OS task priority 1 */ + csp_route_start_task(500, 1); + + /* Enable debug output from CSP */ + if ((argc > 1) && (strcmp(argv[1], "-v") == 0)) { + printf("Debug enabed\r\n"); + csp_debug_toggle_level(3); + csp_debug_toggle_level(4); + + printf("Conn table\r\n"); + csp_conn_print_table(); + + printf("Route table\r\n"); + csp_route_print_table(); + + printf("Interfaces\r\n"); + csp_route_print_interfaces(); + + } + + /** + * Initialise example threads, using pthreads. + */ + + /* Server */ + printf("Starting Server task\r\n"); + csp_thread_handle_t handle_server; + csp_thread_create(task_server, "SERVER", 1000, NULL, 0, &handle_server); + + /* Client */ + printf("Starting Client task\r\n"); + csp_thread_handle_t handle_client; + csp_thread_create(task_client, "SERVER", 1000, NULL, 0, &handle_client); + + /* Wait for execution to end (ctrl+c) */ + while(1) { + csp_sleep_ms(100000); + } + + return 0; + +} diff --git a/gomspace/libgscsp/lib/libcsp/examples/zmqproxy.c b/gomspace/libgscsp/lib/libcsp/examples/zmqproxy.c new file mode 100644 index 00000000..5e259579 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/examples/zmqproxy.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include +#include + +static void * task_capture(void *ctx) { + + /* Subscriber (RX) */ + void *subscriber = zmq_socket(ctx, ZMQ_SUB); + assert(zmq_connect(subscriber, "tcp://localhost:7000") == 0); + assert(zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, "", 0) == 0); + + while (1) { + zmq_msg_t msg; + zmq_msg_init_size(&msg, 1024); + + /* Receive data */ + if (zmq_msg_recv(&msg, subscriber, 0) < 0) { + zmq_msg_close(&msg); + csp_log_error("ZMQ: %s\r\n", zmq_strerror(zmq_errno())); + continue; + } + + int datalen = zmq_msg_size(&msg); + if (datalen < 5) { + csp_log_warn("ZMQ: Too short datalen: %u\r\n", datalen); + while(zmq_msg_recv(&msg, subscriber, ZMQ_NOBLOCK) > 0) + zmq_msg_close(&msg); + continue; + } + + /* Create new csp packet */ + csp_packet_t * packet = malloc(1024); + if (packet == NULL) { + zmq_msg_close(&msg); + continue; + } + + /* Copy the data from zmq to csp */ + char * satidptr = ((char *) &packet->id) - 1; + memcpy(satidptr, zmq_msg_data(&msg), datalen); + packet->length = datalen - 4 - 1; + + printf("Input: Src %u, Dst %u, Dport %u, Sport %u, Pri %u, Flags 0x%02X, Size %"PRIu16"\r\n", + packet->id.src, packet->id.dst, packet->id.dport, + packet->id.sport, packet->id.pri, packet->id.flags, packet->length); + + free(packet); + zmq_msg_close(&msg); + } +} + +int main(int argc, char ** argv) { + + /** + * ZMQ PROXY + */ + void * ctx = zmq_ctx_new(); + assert(ctx); + + void *frontend = zmq_socket(ctx, ZMQ_XSUB); + assert(frontend); + assert(zmq_bind (frontend, "tcp://*:6000") == 0); + + void *backend = zmq_socket(ctx, ZMQ_XPUB); + assert(backend); + assert(zmq_bind(backend, "tcp://*:7000") == 0); + + pthread_t capworker; + pthread_create(&capworker, NULL, task_capture, ctx); + + printf("Starting ZMQproxy\r\n"); + zmq_proxy(frontend, backend, NULL); + + printf("Closing ZMQproxy\r\n"); + zmq_ctx_destroy(ctx); + return 0; + +} diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_clock.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_clock.h new file mode 100644 index 00000000..3c19c887 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_clock.h @@ -0,0 +1,60 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_CLOCK_H_ +#define _CSP_CLOCK_H_ + +/** + @file + + Clock API. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + Cross-platform timestamp. +*/ +typedef struct { + //! Seconds + uint32_t tv_sec; + //! Nano-seconds. + uint32_t tv_nsec; +} csp_timestamp_t; + +/** + Get time - must be implemented by the user. +*/ +__attribute__((weak)) extern void clock_get_time(csp_timestamp_t * time); + +/** + Set time - must be implemented by the user. +*/ +__attribute__((weak)) extern void clock_set_time(csp_timestamp_t * time); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_CLOCK_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_malloc.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_malloc.h new file mode 100644 index 00000000..12602d1b --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_malloc.h @@ -0,0 +1,39 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_MALLOC_H_ +#define _CSP_MALLOC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +void * csp_malloc(size_t size); +void csp_free(void * ptr); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_MALLOC_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_queue.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_queue.h new file mode 100644 index 00000000..3156c05e --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_queue.h @@ -0,0 +1,49 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_QUEUE_H_ +#define _CSP_QUEUE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define CSP_QUEUE_FULL 0 +#define CSP_QUEUE_ERROR 0 +#define CSP_QUEUE_OK 1 +typedef void * csp_queue_handle_t; + +#include +#include + +csp_queue_handle_t csp_queue_create(int length, size_t item_size); +void csp_queue_remove(csp_queue_handle_t queue); +int csp_queue_enqueue(csp_queue_handle_t handle, void *value, uint32_t timeout); +int csp_queue_enqueue_isr(csp_queue_handle_t handle, void * value, CSP_BASE_TYPE * task_woken); +int csp_queue_dequeue(csp_queue_handle_t handle, void *buf, uint32_t timeout); +int csp_queue_dequeue_isr(csp_queue_handle_t handle, void * buf, CSP_BASE_TYPE * task_woken); +int csp_queue_size(csp_queue_handle_t handle); +int csp_queue_size_isr(csp_queue_handle_t handle); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_QUEUE_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_semaphore.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_semaphore.h new file mode 100644 index 00000000..c8068da2 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_semaphore.h @@ -0,0 +1,109 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_SEMAPHORE_H_ +#define _CSP_SEMAPHORE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +/* POSIX interface */ +#if defined(CSP_POSIX) + +#include +#include + +#define CSP_SEMAPHORE_OK 1 +#define CSP_SEMAPHORE_ERROR 2 +#define CSP_MUTEX_OK CSP_SEMAPHORE_OK +#define CSP_MUTEX_ERROR CSP_SEMAPHORE_ERROR + +typedef sem_t csp_bin_sem_handle_t; +typedef pthread_mutex_t csp_mutex_t; + +#endif // CSP_POSIX + +/* MAC OS X interface */ +#if defined(CSP_MACOSX) + +#include +#include "posix/pthread_queue.h" + +#define CSP_SEMAPHORE_OK PTHREAD_QUEUE_OK +#define CSP_SEMAPHORE_ERROR PTHREAD_QUEUE_EMPTY +#define CSP_MUTEX_OK CSP_SEMAPHORE_OK +#define CSP_MUTEX_ERROR CSP_SEMAPHORE_ERROR + +typedef pthread_queue_t * csp_bin_sem_handle_t; +typedef pthread_queue_t * csp_mutex_t; + +#endif // CSP_MACOSX + +#if defined(CSP_WINDOWS) + +#include +#undef interface + +#define CSP_SEMAPHORE_OK 1 +#define CSP_SEMAPHORE_ERROR 2 +#define CSP_MUTEX_OK CSP_SEMAPHORE_OK +#define CSP_MUTEX_ERROR CSP_SEMAPHORE_ERROR + +typedef HANDLE csp_bin_sem_handle_t; +typedef HANDLE csp_mutex_t; + +#endif + +/* FreeRTOS interface */ +#if defined(CSP_FREERTOS) + +#include +#include + +#define CSP_SEMAPHORE_OK pdPASS +#define CSP_SEMAPHORE_ERROR pdFAIL +#define CSP_MUTEX_OK CSP_SEMAPHORE_OK +#define CSP_MUTEX_ERROR CSP_SEMAPHORE_ERROR + +typedef xSemaphoreHandle csp_bin_sem_handle_t; +typedef xSemaphoreHandle csp_mutex_t; + +#endif // CSP_FREERTOS + +int csp_mutex_create(csp_mutex_t * mutex); +int csp_mutex_remove(csp_mutex_t * mutex); +int csp_mutex_lock(csp_mutex_t * mutex, uint32_t timeout); +int csp_mutex_unlock(csp_mutex_t * mutex); +int csp_bin_sem_create(csp_bin_sem_handle_t * sem); +int csp_bin_sem_remove(csp_bin_sem_handle_t * sem); +int csp_bin_sem_wait(csp_bin_sem_handle_t * sem, uint32_t timeout); +int csp_bin_sem_post(csp_bin_sem_handle_t * sem); +int csp_bin_sem_post_isr(csp_bin_sem_handle_t * sem, CSP_BASE_TYPE * task_woken); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_SEMAPHORE_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_system.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_system.h new file mode 100644 index 00000000..c6c0e5af --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_system.h @@ -0,0 +1,74 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_SYSTEM_H_ +#define _CSP_SYSTEM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define COLOR_MASK_COLOR 0x0F +#define COLOR_MASK_MODIFIER 0xF0 + +typedef enum { + /* Colors */ + COLOR_RESET = 0xF0, + COLOR_BLACK = 0x01, + COLOR_RED = 0x02, + COLOR_GREEN = 0x03, + COLOR_YELLOW = 0x04, + COLOR_BLUE = 0x05, + COLOR_MAGENTA = 0x06, + COLOR_CYAN = 0x07, + COLOR_WHITE = 0x08, + /* Modifiers */ + COLOR_NORMAL = 0x0F, + COLOR_BOLD = 0x10, + COLOR_UNDERLINE = 0x20, + COLOR_BLINK = 0x30, + COLOR_HIDE = 0x40, +} csp_color_t; + +/** + * Writes out a task list into a pre-allocate buffer, + * use csp_sys_tasklist_size to get sizeof buffer to allocate + * @param out pointer to output buffer + * @return + */ +int csp_sys_tasklist(char * out); + +/** + * @return Size of tasklist buffer to allocate for the csp_sys_tasklist call + */ +int csp_sys_tasklist_size(void); + +uint32_t csp_sys_memfree(void); +int csp_sys_reboot(void); +int csp_sys_shutdown(void); +void csp_sys_set_color(csp_color_t color); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_SYSTEM_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_thread.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_thread.h new file mode 100644 index 00000000..3c6ea171 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_thread.h @@ -0,0 +1,100 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_THREAD_H_ +#define _CSP_THREAD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* POSIX interface */ +#if defined(CSP_POSIX) || defined(CSP_MACOSX) + +#include +#include + +#define csp_thread_exit() pthread_exit(NULL) + +typedef pthread_t csp_thread_handle_t; +typedef void * csp_thread_return_t; + +#define CSP_DEFINE_TASK(task_name) csp_thread_return_t task_name(void * param) +#define CSP_TASK_RETURN NULL + +#define csp_sleep_ms(time_ms) usleep(time_ms * 1000); + +#endif // CSP_POSIX + +/* Windows interface */ +#if defined(CSP_WINDOWS) + +#include +#undef interface +#include + +#define csp_thread_exit() _endthreadex(0) + +typedef HANDLE csp_thread_handle_t; +typedef unsigned int csp_thread_return_t; + +#define CSP_DEFINE_TASK(task_name) csp_thread_return_t __attribute__((stdcall)) task_name(void * param) +#define CSP_TASK_RETURN 0 + +#define csp_sleep_ms(time_ms) Sleep(time_ms); + +#endif // CSP_WINDOWS + +/* FreeRTOS interface */ +#if defined(CSP_FREERTOS) + +#include +#include + +#if INCLUDE_vTaskDelete +#define csp_thread_exit() vTaskDelete(NULL) +#else +#define csp_thread_exit() +#endif + +typedef xTaskHandle csp_thread_handle_t; +typedef void csp_thread_return_t; + +#define CSP_DEFINE_TASK(task_name) csp_thread_return_t task_name(void * param) +#define CSP_TASK_RETURN + +#define csp_sleep_ms(time_ms) vTaskDelay(time_ms / portTICK_RATE_MS); + +#endif // CSP_FREERTOS + +#ifndef CSP_WINDOWS +int csp_thread_create(csp_thread_return_t (* routine)(void *), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle); +#else +int csp_thread_create(csp_thread_return_t (* routine)(void *)__attribute__((stdcall)), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_THREAD_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_time.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_time.h new file mode 100644 index 00000000..aa72ab8f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_time.h @@ -0,0 +1,57 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_TIME_H_ +#define _CSP_TIME_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* Blackfin/x86 on Linux */ +#if defined(CSP_POSIX) + +#include +#include +#include + +#endif // CSP_POSIX + +/* AVR/ARM on FreeRTOS */ +#if defined(CSP_FREERTOS) + +#include +#include + +#endif // CSP_FREERTOS + +uint32_t csp_get_ms(void); +uint32_t csp_get_ms_isr(void); +uint32_t csp_get_s(void); +uint32_t csp_get_s_isr(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_TIME_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/posix/pthread_queue.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/posix/pthread_queue.h new file mode 100644 index 00000000..44ef596e --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/arch/posix/pthread_queue.h @@ -0,0 +1,118 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _PTHREAD_QUEUE_H_ +#define _PTHREAD_QUEUE_H_ + +/** + @file + + Queue implemented using pthread locks and conds. + + Inspired by c-pthread-queue by Matthew Dickinson: http://code.google.com/p/c-pthread-queue/ +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include + +/** + Queue error codes. + @{ +*/ +/** + General error code - something went wrong. +*/ +#define PTHREAD_QUEUE_ERROR CSP_QUEUE_ERROR +/** + Queue is empty - cannot extract element. +*/ +#define PTHREAD_QUEUE_EMPTY CSP_QUEUE_ERROR +/** + Queue is full - cannot insert element. +*/ +#define PTHREAD_QUEUE_FULL CSP_QUEUE_ERROR +/** + Ok - no error. +*/ +#define PTHREAD_QUEUE_OK CSP_QUEUE_OK +/** @{ */ + +/** + Queue handle. +*/ +typedef struct pthread_queue_s { + //! Memory area. + void * buffer; + //! Memory size. + int size; + //! Item/element size. + int item_size; + //! Items/elements in queue. + int items; + //! Insert point. + int in; + //! Extract point. + int out; + //! Lock. + pthread_mutex_t mutex; + //! Wait because queue is full (insert). + pthread_cond_t cond_full; + //! Wait because queue is empty (extract). + pthread_cond_t cond_empty; +} pthread_queue_t; + +/** + Create queue. +*/ +pthread_queue_t * pthread_queue_create(int length, size_t item_size); + +/** + Delete queue. +*/ +void pthread_queue_delete(pthread_queue_t * q); + +/** + Enqueue/insert element. +*/ +int pthread_queue_enqueue(pthread_queue_t * queue, void * value, uint32_t timeout); + +/** + Dequeue/extract element. +*/ +int pthread_queue_dequeue(pthread_queue_t * queue, void * buf, uint32_t timeout); + +/** + Return number of elements in the queue. +*/ +int pthread_queue_items(pthread_queue_t * queue); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _PTHREAD_QUEUE_H_ + diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_hmac.h b/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_hmac.h new file mode 100644 index 00000000..8c3f5d6a --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_hmac.h @@ -0,0 +1,73 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_HMAC_H_ +#define _CSP_HMAC_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CSP_HMAC_LENGTH 4 + +/** + * Append HMAC to packet + * @param packet Pointer to packet + * @param include_header use header in hmac calculation (this will not modify the flags field) + * @return 0 on success, negative on failure + */ +int csp_hmac_append(csp_packet_t * packet, bool include_header); + +/** + * Verify HMAC of packet + * @param packet Pointer to packet + * @param include_header use header in hmac calculation (this will not modify the flags field) + * @return 0 on success, negative on failure + */ +int csp_hmac_verify(csp_packet_t * packet, bool include_header); + +/** + * Calculate HMAC on buffer + * + * This function is used by append/verify but cal also be called separately. + * @param key HMAC key + * @param keylen HMAC key length + * @param data pointer to data + * @param datalen lehgth of data + * @param hmac output HMAC calculation (CSP_HMAC_LENGTH) + * @return 0 on success, negative on failure + */ +int csp_hmac_memory(const uint8_t * key, uint32_t keylen, const uint8_t * data, uint32_t datalen, uint8_t * hmac); + +/** + * Save a copy of the key string for use by the append/verify functions + * @param key HMAC key + * @param keylen HMAC key length + * @return Always returns 0 + */ +int csp_hmac_set_key(char * key, uint32_t keylen); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_HMAC_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_sha1.h b/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_sha1.h new file mode 100644 index 00000000..aa7e7a0d --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_sha1.h @@ -0,0 +1,81 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_SHA1_H_ +#define _CSP_SHA1_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* The SHA1 block and message digest size in bytes */ +#define SHA1_BLOCKSIZE 64 +#define SHA1_DIGESTSIZE 20 + +/** + SHA1 state structure +*/ +typedef struct { + //! Internal SHA1 state. + uint64_t length; + //! Internal SHA1 state. + uint32_t state[5]; + //! Internal SHA1 state. + uint32_t curlen; + //! Internal SHA1 state. + uint8_t buf[SHA1_BLOCKSIZE]; +} csp_sha1_state; + +/** + * Initialize the hash state + * @param sha1 The hash state you wish to initialize + */ +void csp_sha1_init(csp_sha1_state * sha1); + +/** + * Process a block of memory though the hash + * @param sha1 The hash state + * @param in The data to hash + * @param inlen The length of the data (octets) + */ +void csp_sha1_process(csp_sha1_state * sha1, const uint8_t * in, uint32_t inlen); + +/** + * Terminate the hash to get the digest + * @param sha1 The hash state + * @param out [out] The destination of the hash (20 bytes) + */ +void csp_sha1_done(csp_sha1_state * sha1, uint8_t * out); + +/** + * Calculate SHA1 hash of block of memory. + * @param msg Pointer to message buffer + * @param len Length of message + * @param sha1 Pointer to SHA1 output buffer. Must be 20 bytes or more! + */ +void csp_sha1_memory(const uint8_t * msg, uint32_t len, uint8_t * hash); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_SHA1_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_xtea.h b/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_xtea.h new file mode 100644 index 00000000..f740b8d5 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_xtea.h @@ -0,0 +1,52 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_XTEA_H_ +#define _CSP_XTEA_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CSP_XTEA_IV_LENGTH 8 + +/** + * XTEA encrypt byte array + * @param plain Pointer to plain text + * @param len Length of plain text + * @param iv Initialization vector + */ +int csp_xtea_encrypt(uint8_t * plain, const uint32_t len, uint32_t iv[2]); + +/** + * Decrypt XTEA encrypted byte array + * @param cipher Pointer to cipher text + * @param len Length of plain text + * @param iv Initialization vector + */ +int csp_xtea_decrypt(uint8_t * cipher, const uint32_t len, uint32_t iv[2]); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_XTEA_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp.h new file mode 100644 index 00000000..6962195b --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp.h @@ -0,0 +1,545 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_H_ +#define _CSP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes */ +#include + +#include + +/* CSP includes */ +#include "csp_types.h" +#include "csp_platform.h" +#include "csp_error.h" +#include "csp_debug.h" +#include "csp_buffer.h" +#include "csp_rtable.h" +#include "csp_iflist.h" + +/** csp_init + * Start up the can-space protocol + * @param my_node_address The CSP node address + */ +int csp_init(uint8_t my_node_address); + +/** csp_set_address + * Set the systems own address + * @param addr The new address of the system + */ +void csp_set_address(uint8_t addr); + +/** csp_get_address + * Get the systems own address + * @return The current address of the system + */ +uint8_t csp_get_address(void); + +/** csp_set_hostname + * Set subsystem hostname. + * This function takes a pointer to a string, which should remain static + * @param hostname Hostname to set + */ +void csp_set_hostname(const char *hostname); + +/** csp_get_hostname + * Get current subsystem hostname. + * @return Pointer to char array with current hostname. + */ +const char *csp_get_hostname(void); + +/** csp_set_model + * Set subsystem model name. + * This function takes a pointer to a string, which should remain static + * @param model Model name to set + */ +void csp_set_model(const char *model); + +/** csp_get_model + * Get current model name. + * @return Pointer to char array with current model name. + */ +const char *csp_get_model(void); + +/** csp_set_revision + * Set subsystem revision. This can be used to override the CMP revision field. + * This function takes a pointer to a string, which should remain static + * @param revision Revision name to set + */ +void csp_set_revision(const char *revision); + +/** csp_get_revision + * Get subsystem revision. + * @return Pointer to char array with software revision. + */ +const char *csp_get_revision(void); + +/** csp_socket + * Create CSP socket endpoint + * @param opts Socket options + * @return Pointer to socket on success, NULL on failure + */ +csp_socket_t *csp_socket(uint32_t opts); + +/** + * Wait for a new connection on a socket created by csp_socket + * @param socket Socket to accept connections on + * @param timeout use CSP_MAX_DELAY for infinite timeout + * @return Return pointer to csp_conn_t or NULL if timeout was reached + */ +csp_conn_t *csp_accept(csp_socket_t *socket, uint32_t timeout); + +/** + * Read data from a connection + * This fuction uses the RX queue of a connection to receive a packet + * If no packet is available and a timeout has been specified + * The call will block. + * Do NOT call this from ISR + * @param conn pointer to connection + * @param timeout timeout in ms, use CSP_MAX_DELAY for infinite blocking time + * @return Returns pointer to csp_packet_t, which you MUST free yourself, either by calling csp_buffer_free() or reusing the buffer for a new csp_send. + */ +csp_packet_t *csp_read(csp_conn_t *conn, uint32_t timeout); + +/** + * Send a packet on an already established connection + * @param conn pointer to connection + * @param packet pointer to packet, + * @param timeout a timeout to wait for TX to complete. NOTE: not all underlying drivers supports flow-control. + * @return returns 1 if successful and 0 otherwise. you MUST free the frame yourself if the transmission was not successful. + */ +int csp_send(csp_conn_t *conn, csp_packet_t *packet, uint32_t timeout); + +/** + * Send a packet on an already established connection, and change the default priority of the connection + * + * @note When using this function, the priority of the connection will change. If you need to change it back + * use another call to csp_send_prio, or ensure that all packets sent on a given connection is using send_prio call. + * + * @param prio csp priority + * @param conn pointer to connection + * @param packet pointer to packet, + * @param timeout a timeout to wait for TX to complete. NOTE: not all underlying drivers supports flow-control. + * @return returns 1 if successful and 0 otherwise. you MUST free the frame yourself if the transmission was not successful. + */ +int csp_send_prio(uint8_t prio, csp_conn_t *conn, csp_packet_t *packet, uint32_t timeout); + +/** + * Perform an entire request/reply transaction + * Copies both input buffer and reply to output buffeer. + * Also makes the connection and closes it again + * @param prio CSP Prio + * @param dest CSP Dest + * @param port CSP Port + * @param timeout timeout in ms + * @param outbuf pointer to outgoing data buffer + * @param outlen length of request to send + * @param inbuf pointer to incoming data buffer + * @param inlen length of expected reply, -1 for unknown size (note inbuf MUST be large enough) + * @return Return 1 or reply size if successful, 0 if error or incoming length does not match or -1 if timeout was reached + */ +int csp_transaction(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, void *outbuf, int outlen, void *inbuf, int inlen); + +/** + * Perform an entire request/reply transaction + * Copies both input buffer and reply to output buffeer. + * Also makes the connection and closes it again + * @param prio CSP Prio + * @param dest CSP Dest + * @param port CSP Port + * @param timeout timeout in ms + * @param outbuf pointer to outgoing data buffer + * @param outlen length of request to send + * @param inbuf pointer to incoming data buffer + * @param inlen length of expected reply, -1 for unknown size (note inbuf MUST be large enough) + * @param opts Connection options. + * @return Return 1 or reply size if successful, 0 if error or incoming length does not match or -1 if timeout was reached + */ +int csp_transaction2(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, void *outbuf, int outlen, void *inbuf, int inlen, uint32_t opts); + +/** + * Use an existing connection to perform a transaction, + * This is only possible if the next packet is on the same port and destination! + * @param conn pointer to connection structure + * @param timeout timeout in ms + * @param outbuf pointer to outgoing data buffer + * @param outlen length of request to send + * @param inbuf pointer to incoming data buffer + * @param inlen length of expected reply, -1 for unknown size (note inbuf MUST be large enough) + * @return + */ +int csp_transaction_persistent(csp_conn_t *conn, uint32_t timeout, void *outbuf, int outlen, void *inbuf, int inlen); + +/** + * Read data from a connection-less server socket + * This fuction uses the socket directly to receive a frame + * If no packet is available and a timeout has been specified the call will block. + * Do NOT call this from ISR + * @return Returns pointer to csp_packet_t, which you MUST free yourself, either by calling csp_buffer_free() or reusing the buffer for a new csp_send. + */ +csp_packet_t *csp_recvfrom(csp_socket_t *socket, uint32_t timeout); + +/** + * Send a packet without previously opening a connection + * @param prio CSP_PRIO_x + * @param dest destination node + * @param dport destination port + * @param src_port source port + * @param opts CSP_O_x + * @param packet pointer to packet + * @param timeout timeout used by interfaces with blocking send + * @return -1 if error (you must free packet), 0 if OK (you must discard pointer) + */ +int csp_sendto(uint8_t prio, uint8_t dest, uint8_t dport, uint8_t src_port, uint32_t opts, csp_packet_t *packet, uint32_t timeout); + +/** + * Send a packet as a direct reply to the source of an incoming packet, + * but still without holding an entire connection + * @param request_packet pointer to packet to reply to + * @param reply_packet actual reply data + * @param opts CSP_O_x + * @param timeout timeout used by interfaces with blocking send + * @return -1 if error (you must free packet), 0 if OK (you must discard pointer) + */ +int csp_sendto_reply(csp_packet_t * request_packet, csp_packet_t * reply_packet, uint32_t opts, uint32_t timeout); + +/** csp_connect + * Used to establish outgoing connections + * This function searches the port table for free slots and finds an unused + * connection from the connection pool + * There is no handshake in the CSP protocol + * @param prio Connection priority. + * @param dest Destination address. + * @param dport Destination port. + * @param timeout Timeout in ms. + * @param opts Connection options. + * @return a pointer to a new connection or NULL + */ +csp_conn_t *csp_connect(uint8_t prio, uint8_t dest, uint8_t dport, uint32_t timeout, uint32_t opts); + +/** csp_close + * Closes a given connection and frees buffers used. + * @param conn pointer to connection structure + * @return CSP_ERR_NONE if connection was closed. Otherwise, an err code is returned. + */ +int csp_close(csp_conn_t *conn); + +/** + * @param conn pointer to connection structure + * @return destination port of an incoming connection + */ +int csp_conn_dport(csp_conn_t *conn); + +/** + * @param conn pointer to connection structure + * @return source port of an incoming connection + */ +int csp_conn_sport(csp_conn_t *conn); + +/** + * @param conn pointer to connection structure + * @return destination address of an incoming connection + */ +int csp_conn_dst(csp_conn_t *conn); + +/** + * @param conn pointer to connection structure + * @return source address of an incoming connection + */ +int csp_conn_src(csp_conn_t *conn); + +/** + * @param conn pointer to connection structure + * @return flags field of an incoming connection + */ +int csp_conn_flags(csp_conn_t *conn); + +/** + * Set socket to listen for incoming connections + * @param socket Socket to enable listening on + * @param conn_queue_length Lenght of backlog connection queue + * @return 0 on success, -1 on error. + */ +int csp_listen(csp_socket_t *socket, size_t conn_queue_length); + +/** + * Bind port to socket + * @param socket Socket to bind port to + * @param port Port number to bind + * @return 0 on success, -1 on error. + */ +int csp_bind(csp_socket_t *socket, uint8_t port); + +/** + * Start the router task. + * @param task_stack_size The number of portStackType to allocate. This only affects FreeRTOS systems. + * @param priority The OS task priority of the router + */ +int csp_route_start_task(unsigned int task_stack_size, unsigned int priority); + +/** + * Call the router worker function manually (without the router task) + * This must be run inside a loop or called periodically for the csp router to work. + * Use this function instead of calling and starting the router task. + * @param timeout max blocking time + * @return -1 if no packet was processed, 0 otherwise + */ +int csp_route_work(uint32_t timeout); + +/** + * Start the bridge task. + * @param task_stack_size The number of portStackType to allocate. This only affects FreeRTOS systems. + * @param priority The OS task priority of the router + * @param _if_a pointer to first side + * @param _if_b pointer to second side + * @return CSP_ERR type + */ +int csp_bridge_start(unsigned int task_stack_size, unsigned int task_priority, csp_iface_t * _if_a, csp_iface_t * _if_b); + +/** + * Enable promiscuous mode packet queue + * This function is used to enable promiscuous mode for the router. + * If enabled, a copy of all incoming packets are placed in a queue + * that can be read with csp_promisc_get(). Not all interface drivers + * support promiscuous mode. + * + * @param buf_size Size of buffer for incoming packets + */ +int csp_promisc_enable(unsigned int buf_size); + +/** + * Disable promiscuous mode. + * If the queue was initialised prior to this, it can be re-enabled + * by calling promisc_enable(0) + */ +void csp_promisc_disable(void); + +/** + * Get packet from promiscuous mode packet queue + * Returns the first packet from the promiscuous mode packet queue. + * The queue is FIFO, so the returned packet is the oldest one + * in the queue. + * + * @param timeout Timeout in ms to wait for a new packet + */ +csp_packet_t *csp_promisc_read(uint32_t timeout); + +/** + * Send multiple packets using the simple fragmentation protocol + * CSP will add total size and offset to all packets + * This can be read by the client using the csp_sfp_recv, if the CSP_FFRAG flag is set + * @param conn pointer to connection + * @param data pointer to data to send + * @param totalsize size of data to send + * @param mtu maximum transfer unit + * @param timeout timeout in ms to wait for csp_send() + * @return 0 if OK, -1 if ERR + */ +int csp_sfp_send(csp_conn_t * conn, const void * data, int totalsize, int mtu, uint32_t timeout); + +/** + * Same as csp_sfp_send but with option to supply your own memcpy function. + * This is usefull if you wish to send data stored in flash memory or another location + * @param conn pointer to connection + * @param data pointer to data to send + * @param totalsize size of data to send + * @param mtu maximum transfer unit + * @param timeout timeout in ms to wait for csp_send() + * @param memcpyfcn, pointer to memcpy function + * @return 0 if OK, -1 if ERR + */ +int csp_sfp_send_own_memcpy(csp_conn_t * conn, const void * data, int totalsize, int mtu, uint32_t timeout, void * (*memcpyfcn)(void *, const void *, size_t)); + +/** + * This is the counterpart to the csp_sfp_send function + * @param conn pointer to active conn, on which you expect to receive sfp packed data + * @param dataout pointer to NULL pointer, whill be overwritten with malloc pointer + * @param datasize actual size of received data + * @param timeout timeout in ms to wait for csp_recv() + * @return 0 if OK, -1 if ERR + */ +int csp_sfp_recv(csp_conn_t * conn, void ** dataout, int * datasize, uint32_t timeout); + +/** + * This is the counterpart to the csp_sfp_send function + * @param conn pointer to active conn, on which you expect to receive sfp packed data + * @param dataout pointer to NULL pointer, whill be overwritten with malloc pointer + * @param datasize actual size of received data + * @param timeout timeout in ms to wait for csp_recv() + * @param first_packet This is a pointer to the first SFP packet (previously received with csp_read) + * @return 0 if OK, -1 if ERR + */ +int csp_sfp_recv_fp(csp_conn_t * conn, void ** dataout, int * datasize, uint32_t timeout, csp_packet_t * first_packet); + +/** + * If the given packet is a service-request (that is uses one of the csp service ports) + * it will be handled according to the CSP service handler. + * This function will either use the packet buffer or delete it, + * so this function is typically called in the last "default" clause of + * a switch/case statement in a csp_listener task. + * In order to listen to csp service ports, bind your listener to the CSP_ANY port. + * This function may only be called from task context. + * @param conn Pointer to the new connection + * @param packet Pointer to the first packet, obtained by using csp_read() + */ +void csp_service_handler(csp_conn_t *conn, csp_packet_t *packet); + +/** + * Send a single ping/echo packet + * @param node node id + * @param timeout timeout in ms + * @param size size of packet to transmit + * @param conn_options csp connection options + * @return >0 = Echo time in ms, -1 = ERR + */ +int csp_ping(uint8_t node, uint32_t timeout, unsigned int size, uint8_t conn_options); + +/** + * Send a single ping/echo packet without waiting for reply + * @param node node id + */ +void csp_ping_noreply(uint8_t node); + +/** + * Request process list. + * @note This is only available for FreeRTOS systems + * @param node node id + * @param timeout timeout in ms + */ +void csp_ps(uint8_t node, uint32_t timeout); + +/** + * Request amount of free memory + * @param node node id + * @param timeout timeout in ms + */ +void csp_memfree(uint8_t node, uint32_t timeout); + +/** + * Request number of free buffer elements + * @param node node id + * @param timeout timeout in ms + */ +void csp_buf_free(uint8_t node, uint32_t timeout); + +/** + * Reboot subsystem + * @param node node id + */ +void csp_reboot(uint8_t node); + +/** + * Shutdown subsystem + * @param node node id + */ +void csp_shutdown(uint8_t node); + +/** + * Request subsystem uptime + * @param node node id + * @param timeout timeout in ms + */ +void csp_uptime(uint8_t node, uint32_t timeout); + +/** + * Set RDP options + * @param window_size Window size + * @param conn_timeout_ms Connection timeout in ms + * @param packet_timeout_ms Packet timeout in ms + * @param delayed_acks Enable/disable delayed acknowledgements + * @param ack_timeout Acknowledgement timeout when delayed ACKs is enabled + * @param ack_delay_count Send acknowledgement for every ack_delay_count packets + */ +void csp_rdp_set_opt(unsigned int window_size, unsigned int conn_timeout_ms, + unsigned int packet_timeout_ms, unsigned int delayed_acks, + unsigned int ack_timeout, unsigned int ack_delay_count); + +/** + * Get RDP options + * @param window_size Window size + * @param conn_timeout_ms Connection timeout in ms + * @param packet_timeout_ms Packet timeout in ms + * @param delayed_acks Enable/disable delayed acknowledgements + * @param ack_timeout Acknowledgement timeout when delayed ACKs is enabled + * @param ack_delay_count Send acknowledgement for every ack_delay_count packets + */ +void csp_rdp_get_opt(unsigned int *window_size, unsigned int *conn_timeout_ms, + unsigned int *packet_timeout_ms, unsigned int *delayed_acks, + unsigned int *ack_timeout, unsigned int *ack_delay_count); + +/** + * Set XTEA key + * @param key Pointer to key array + * @param keylen Length of key + * @return 0 if key was successfully set, -1 otherwise + */ +int csp_xtea_set_key(char *key, uint32_t keylen); + +/** + * Set HMAC key + * @param key Pointer to key array + * @param keylen Length of key + * @return 0 if key was successfully set, -1 otherwise + */ +int csp_hmac_set_key(char *key, uint32_t keylen); + +/** + * Print connection table + */ +void csp_conn_print_table(void); +int csp_conn_print_table_str(char * str_buf, int str_size); + +/** + * Print buffer usage table + */ +void csp_buffer_print_table(void); + +/** + * Hex dump to stdout + */ +void csp_hex_dump(const char *desc, void *addr, int len); + +#ifdef __AVR__ +typedef uint32_t csp_memptr_t; +#else +typedef void * csp_memptr_t; +#endif + +typedef csp_memptr_t (*csp_memcpy_fnc_t)(csp_memptr_t, const csp_memptr_t, size_t); +void csp_cmp_set_memcpy(csp_memcpy_fnc_t fnc); + +/** + * Set csp_debug hook function + * @param f Hook function + */ +#include +typedef void (*csp_debug_hook_func_t)(csp_debug_level_t level, const char *format, va_list args); +void csp_debug_hook_set(csp_debug_hook_func_t f); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_buffer.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_buffer.h new file mode 100644 index 00000000..9ed6df77 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_buffer.h @@ -0,0 +1,92 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_BUFFER_H_ +#define _CSP_BUFFER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Start the buffer handling system + * You must specify the number for buffers and the size. All buffers are fixed + * size so you must specify the size of your largest buffer. + * + * @param count Number of buffers to allocate + * @param size Buffer size in bytes. + * + * @return CSP_ERR_NONE if malloc() succeeded, CSP_ERR message otherwise. + */ +int csp_buffer_init(int count, int size); + +/** + * Get a reference to a free buffer. This function can only be called + * from task context. + * + * @param size Specify what data-size you will put in the buffer + * @return pointer to a free csp_packet_t or NULL if out of memory + */ +void * csp_buffer_get(size_t size); + +/** + * Get a reference to a free buffer. This function can only be called + * from interrupt context. + * + * @param buf_size Specify what data-size you will put in the buffer + * @return pointer to a free csp_packet_t or NULL if out of memory + */ +void * csp_buffer_get_isr(size_t buf_size); + +/** + * Free a buffer after use. + * @param packet pointer to memory area, must be acquired by csp_buffer_get(). + */ +void csp_buffer_free(void *packet); + +/** + * Free a buffer after use in ISR context. + * @param packet pointer to memory area, must be acquired by csp_buffer_get(). + */ +void csp_buffer_free_isr(void *packet); + +/** + * Clone an existing packet and increase/decrease cloned packet size. + * @param buffer Existing buffer to clone. + */ +void * csp_buffer_clone(void *buffer); + +/** + * Return how many buffers that are currently free. + * @return number of free buffers + */ +int csp_buffer_remaining(void); + +/** + * Return the size of the CSP buffers + * @return size of CSP buffers + */ +int csp_buffer_size(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CSP_BUFFER_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_cmp.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_cmp.h new file mode 100644 index 00000000..114a8eab --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_cmp.h @@ -0,0 +1,189 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_CMP_H_ +#define _CSP_CMP_H_ + +/** + @file + CSP management protocol (CMP). +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/** + CMP type. + @{ +*/ +/** + CMP request. +*/ +#define CSP_CMP_REQUEST 0x00 +/** + CMP reply. +*/ +#define CSP_CMP_REPLY 0xff +/**@}*/ + +/** + CMP requests. + @{ +*/ +/** + CMP request codes. +*/ +/** + Request identification, compile time, revision, name. +*/ +#define CSP_CMP_IDENT 1 +/** + Set/configure routing. +*/ +#define CSP_CMP_ROUTE_SET 2 +/** + Request interface statistics. +*/ +#define CSP_CMP_IF_STATS 3 +/** + Peek/read data from memory. +*/ +#define CSP_CMP_PEEK 4 +/** + Poke/write data from memory. +*/ +#define CSP_CMP_POKE 5 +/** + Get/set clock. +*/ +#define CSP_CMP_CLOCK 6 +/**@}*/ + +/** + CMP identification - max revision length. +*/ +#define CSP_CMP_IDENT_REV_LEN 20 +/** + CMP identification - max date length. +*/ +#define CSP_CMP_IDENT_DATE_LEN 12 +/** + CMP identification - max time length. +*/ +#define CSP_CMP_IDENT_TIME_LEN 9 + +/** + CMP interface statistics - max interface name length. +*/ +#define CSP_CMP_ROUTE_IFACE_LEN 11 + +/** + CMP peek/read memeory - max read length. +*/ +#define CSP_CMP_PEEK_MAX_LEN 200 + +/** + CMP poke/write memeory - max write length. +*/ +#define CSP_CMP_POKE_MAX_LEN 200 + +/** + CSP management protocol description. +*/ +struct csp_cmp_message { + //! CMP request type. + uint8_t type; + //! CMP request code. + uint8_t code; + union { + struct { + char hostname[CSP_HOSTNAME_LEN]; + char model[CSP_MODEL_LEN]; + char revision[CSP_CMP_IDENT_REV_LEN]; + char date[CSP_CMP_IDENT_DATE_LEN]; + char time[CSP_CMP_IDENT_TIME_LEN]; + } ident; + struct { + uint8_t dest_node; + uint8_t next_hop_mac; + char interface[CSP_CMP_ROUTE_IFACE_LEN]; + } route_set; + struct __attribute__((__packed__)) { + char interface[CSP_CMP_ROUTE_IFACE_LEN]; + uint32_t tx; + uint32_t rx; + uint32_t tx_error; + uint32_t rx_error; + uint32_t drop; + uint32_t autherr; + uint32_t frame; + uint32_t txbytes; + uint32_t rxbytes; + uint32_t irq; + } if_stats; + struct { + uint32_t addr; + uint8_t len; + char data[CSP_CMP_PEEK_MAX_LEN]; + } peek; + struct { + uint32_t addr; + uint8_t len; + char data[CSP_CMP_POKE_MAX_LEN]; + } poke; + csp_timestamp_t clock; + }; +} __attribute__ ((packed)); + +/** + Macro for calculating size of management message. +*/ +#define CMP_SIZE(_memb) (sizeof(((struct csp_cmp_message *)0)->_memb) + sizeof(uint8_t) + sizeof(uint8_t)) + +/** + Generic send management message request. +*/ +int csp_cmp(uint8_t node, uint32_t timeout, uint8_t code, int membsize, struct csp_cmp_message *msg); + +/** + Macro for defining management handling function. +*/ +#define CMP_MESSAGE(_code, _memb) \ +static inline int csp_cmp_##_memb(uint8_t node, uint32_t timeout, struct csp_cmp_message *msg) { \ + return csp_cmp(node, timeout, _code, CMP_SIZE(_memb), msg); \ +} + +CMP_MESSAGE(CSP_CMP_IDENT, ident) +CMP_MESSAGE(CSP_CMP_ROUTE_SET, route_set) +CMP_MESSAGE(CSP_CMP_IF_STATS, if_stats) +CMP_MESSAGE(CSP_CMP_PEEK, peek) +CMP_MESSAGE(CSP_CMP_POKE, poke) +CMP_MESSAGE(CSP_CMP_CLOCK, clock) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_CMP_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_crc32.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_crc32.h new file mode 100644 index 00000000..a474eaf8 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_crc32.h @@ -0,0 +1,63 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_CRC32_H_ +#define _CSP_CRC32_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Generate precomputed CRC32 table + */ +void csp_crc32_gentab(void); + +/** + * Append CRC32 checksum to packet + * @param packet Packet to append checksum + * @param include_header use header in calculation (this will not modify the flags field) + * @return 0 on success, -1 on error + */ +int csp_crc32_append(csp_packet_t * packet, bool include_header); + +/** + * Verify CRC32 checksum on packet + * @param packet Packet to verify + * @param include_header use header in calculation (this will not modify the flags field) + * @return 0 if checksum is valid, -1 otherwise + */ +int csp_crc32_verify(csp_packet_t * packet, bool include_header); + +/** + * Calculate checksum for a given memory area + * @param data pointer to memory + * @param length length of memory to do checksum on + * @return return uint32_t checksum + */ +uint32_t csp_crc32_memory(const uint8_t * data, uint32_t length); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CSP_CRC32_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_debug.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_debug.h new file mode 100644 index 00000000..64429d49 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_debug.h @@ -0,0 +1,150 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_DEBUG_H_ +#define _CSP_DEBUG_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Debug levels */ +typedef enum { + CSP_ERROR = 0, + CSP_WARN = 1, + CSP_INFO = 2, + CSP_BUFFER = 3, + CSP_PACKET = 4, + CSP_PROTOCOL = 5, + CSP_LOCK = 6, +} csp_debug_level_t; + +/* Extract filename component from path */ +#define BASENAME(_file) ((strrchr(_file, '/') ? : (strrchr(_file, '\\') ? : _file)) + 1) + +/* Implement csp_assert_fail_action to override default failure action */ +extern void __attribute__((weak)) csp_assert_fail_action(const char *assertion, const char *file, int line); + +#ifndef NDEBUG + #define csp_assert(exp) \ + do { \ + if (!(exp)) { \ + const char *assertion = #exp; \ + const char *file = BASENAME(__FILE__); \ + int line = __LINE__; \ + printf("\E[1;31m[%02" PRIu8 "] Assertion \'%s\' failed in %s:%d\E[0m\r\n", \ + csp_get_address(), assertion, file, line); \ + if (csp_assert_fail_action) \ + csp_assert_fail_action(assertion, file, line); \ + } \ + } while (0) +#else + #define csp_assert(...) do {} while (0) +#endif + +#ifdef __AVR__ + #include + #include + #define CONSTSTR(data) PSTR(data) + #undef printf + #undef sscanf + #undef scanf + #undef sprintf + #undef snprintf + #define printf(s, ...) printf_P(PSTR(s), ## __VA_ARGS__) + #define sscanf(buf, s, ...) sscanf_P(buf, PSTR(s), ## __VA_ARGS__) + #define scanf(s, ...) scanf_P(PSTR(s), ## __VA_ARGS__) + #define sprintf(buf, s, ...) sprintf_P(buf, PSTR(s), ## __VA_ARGS__) + #define snprintf(buf, size, s, ...) snprintf_P(buf, size, PSTR(s), ## __VA_ARGS__) +#else + #define CONSTSTR(data) data +#endif + +#ifdef CSP_DEBUG + #define csp_debug(level, format, ...) do { do_csp_debug(level, CONSTSTR(format), ##__VA_ARGS__); } while(0) +#else + #define csp_debug(...) do {} while (0) +#endif + +#ifdef CSP_LOG_LEVEL_ERROR + #define csp_log_error(format, ...) csp_debug(CSP_ERROR, format, ##__VA_ARGS__) +#else + #define csp_log_error(...) do {} while (0) +#endif + +#ifdef CSP_LOG_LEVEL_WARN + #define csp_log_warn(format, ...) csp_debug(CSP_WARN, format, ##__VA_ARGS__) +#else + #define csp_log_warn(...) do {} while (0) +#endif + +#ifdef CSP_LOG_LEVEL_INFO + #define csp_log_info(format, ...) csp_debug(CSP_INFO, format, ##__VA_ARGS__) +#else + #define csp_log_info(...) do {} while (0) +#endif + +#ifdef CSP_LOG_LEVEL_DEBUG + #define csp_log_buffer(format, ...) csp_debug(CSP_BUFFER, format, ##__VA_ARGS__) + #define csp_log_packet(format, ...) csp_debug(CSP_PACKET, format, ##__VA_ARGS__) + #define csp_log_protocol(format, ...) csp_debug(CSP_PROTOCOL, format, ##__VA_ARGS__) + #define csp_log_lock(format, ...) csp_debug(CSP_LOCK, format, ##__VA_ARGS__) +#else + #define csp_log_buffer(...) do {} while (0) + #define csp_log_packet(...) do {} while (0) + #define csp_log_protocol(...) do {} while (0) + #define csp_log_lock(...) do {} while (0) +#endif + +/** + * This function should not be used directly, use csp_log_() macro instead + * @param level + * @param format + */ +void do_csp_debug(csp_debug_level_t level, const char *format, ...); + +/** + * Toggle debug level on/off + * @param level Level to toggle + */ +void csp_debug_toggle_level(csp_debug_level_t level); + +/** + * Set debug level + * @param level Level to set + * @param value New level value + */ +void csp_debug_set_level(csp_debug_level_t level, bool value); + +/** + * Get current debug level value + * @param level Level value to get + * @return Level value + */ +int csp_debug_get_level(csp_debug_level_t level); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_DEBUG_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_endian.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_endian.h new file mode 100644 index 00000000..e63a73c2 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_endian.h @@ -0,0 +1,170 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_ENDIAN_H_ +#define _CSP_ENDIAN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * Convert 16-bit integer from host byte order to network byte order + * @param h16 Host byte order 16-bit integer + */ +uint16_t csp_hton16(uint16_t h16); + +/** + * Convert 16-bit integer from host byte order to host byte order + * @param n16 Network byte order 16-bit integer + */ +uint16_t csp_ntoh16(uint16_t n16); + +/** + * Convert 32-bit integer from host byte order to network byte order + * @param h32 Host byte order 32-bit integer + */ +uint32_t csp_hton32(uint32_t h32); + +/** + * Convert 32-bit integer from host byte order to host byte order + * @param n32 Network byte order 32-bit integer + */ +uint32_t csp_ntoh32(uint32_t n32); + +/** + * Convert 64-bit integer from host byte order to network byte order + * @param h64 Host byte order 64-bit integer + */ +uint64_t csp_hton64(uint64_t h64); + +/** + * Convert 64-bit integer from host byte order to host byte order + * @param n64 Network byte order 64-bit integer + */ +uint64_t csp_ntoh64(uint64_t n64); + +/** + * Convert 16-bit integer from host byte order to big endian byte order + * @param h16 Host byte order 16-bit integer + */ +uint16_t csp_htobe16(uint16_t h16); + +/** + * Convert 16-bit integer from host byte order to little endian byte order + * @param h16 Host byte order 16-bit integer + */ +uint16_t csp_htole16(uint16_t h16); + +/** + * Convert 16-bit integer from big endian byte order to little endian byte order + * @param be16 Big endian byte order 16-bit integer + */ +uint16_t csp_betoh16(uint16_t be16); + +/** + * Convert 16-bit integer from little endian byte order to host byte order + * @param le16 Little endian byte order 16-bit integer + */ +uint16_t csp_letoh16(uint16_t le16); + +/** + * Convert 32-bit integer from host byte order to big endian byte order + * @param h32 Host byte order 32-bit integer + */ +uint32_t csp_htobe32(uint32_t h32); + +/** + * Convert 32-bit integer from little endian byte order to host byte order + * @param h32 Host byte order 32-bit integer + */ +uint32_t csp_htole32(uint32_t h32); + +/** + * Convert 32-bit integer from big endian byte order to host byte order + * @param be32 Big endian byte order 32-bit integer + */ +uint32_t csp_betoh32(uint32_t be32); + +/** + * Convert 32-bit integer from little endian byte order to host byte order + * @param le32 Little endian byte order 32-bit integer + */ +uint32_t csp_letoh32(uint32_t le32); + +/** + * Convert 64-bit integer from host byte order to big endian byte order + * @param h64 Host byte order 64-bit integer + */ +uint64_t csp_htobe64(uint64_t h64); + +/** + * Convert 64-bit integer from host byte order to little endian byte order + * @param h64 Host byte order 64-bit integer + */ +uint64_t csp_htole64(uint64_t h64); + +/** + * Convert 64-bit integer from big endian byte order to host byte order + * @param be64 Big endian byte order 64-bit integer + */ +uint64_t csp_betoh64(uint64_t be64); + +/** + * Convert 64-bit integer from little endian byte order to host byte order + * @param le64 Little endian byte order 64-bit integer + */ +uint64_t csp_letoh64(uint64_t le64); + +/** + * Convert float from host to network byte order + * @param f Float in host order + * @return Float in network order + */ +float csp_htonflt(float f); + +/** + * Convert float from network to host byte order + * @param f Float in network order + * @return Float in host order + */ +float csp_ntohflt(float f); + +/** + * Convert double from host to network byte order + * @param d Double in host order + * @return Double in network order + */ +double csp_htondbl(double d); + +/** + * Convert double from network to host order + * @param d Double in network order + * @return Double in host order + */ +double csp_ntohdbl(double d); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_ENDIAN_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_error.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_error.h new file mode 100644 index 00000000..31866607 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_error.h @@ -0,0 +1,50 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_ERROR_H_ +#define _CSP_ERROR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define CSP_ERR_NONE 0 /* No error */ +#define CSP_ERR_NOMEM -1 /* Not enough memory */ +#define CSP_ERR_INVAL -2 /* Invalid argument */ +#define CSP_ERR_TIMEDOUT -3 /* Operation timed out */ +#define CSP_ERR_USED -4 /* Resource already in use */ +#define CSP_ERR_NOTSUP -5 /* Operation not supported */ +#define CSP_ERR_BUSY -6 /* Device or resource busy */ +#define CSP_ERR_ALREADY -7 /* Connection already in progress */ +#define CSP_ERR_RESET -8 /* Connection reset */ +#define CSP_ERR_NOBUFS -9 /* No more buffer space available */ +#define CSP_ERR_TX -10 /* Transmission failed */ +#define CSP_ERR_DRIVER -11 /* Error in driver layer */ +#define CSP_ERR_AGAIN -12 /* Resource temporarily unavailable */ + +#define CSP_ERR_HMAC -100 /* HMAC failed */ +#define CSP_ERR_XTEA -101 /* XTEA failed */ +#define CSP_ERR_CRC32 -102 /* CRC32 failed */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_ERROR_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_iflist.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_iflist.h new file mode 100644 index 00000000..55875657 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_iflist.h @@ -0,0 +1,56 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CSP_IFLIST_H_ +#define CSP_IFLIST_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Add interface to list + * @param ifc Pointer to interface to add + */ +void csp_iflist_add(csp_iface_t *ifc); + +/** + * Lookup interface by name + * @param name String with interface name + * @return Pointer to interface or NULL if not found + */ +csp_iface_t * csp_iflist_get_by_name(const char *name); + +/** + * Print list of interfaces to stdout + */ +void csp_iflist_print(void); + +/** + * Return list of registered interfaces. + */ +csp_iface_t * csp_iflist_get(void); + +#ifdef __cplusplus +} +#endif +#endif /* CSP_IFLIST_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_interface.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_interface.h new file mode 100644 index 00000000..8f04bee3 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_interface.h @@ -0,0 +1,54 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_INTERFACE_H_ +#define _CSP_INTERFACE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * Inputs a new packet into the system + * This function is called from interface drivers ISR to route and accept packets. + * But it can also be called from a task, provided that the pxTaskWoken parameter is NULL! + * + * EXTREMELY IMPORTANT: + * pxTaskWoken arg must ALWAYS be NULL if called from task, + * and ALWAYS be NON NULL if called from ISR! + * If this condition is met, this call is completely thread-safe + * + * This function is fire and forget, it returns void, meaning + * that a packet will always be either accepted or dropped + * so the memory will always be freed. + * + * @param packet A pointer to the incoming packet + * @param interface A pointer to the incoming interface TX function. + * @param pxTaskWoken This must be a pointer a valid variable if called from ISR or NULL otherwise! + */ +void csp_qfifo_write(csp_packet_t *packet, csp_iface_t *interface, CSP_BASE_TYPE *pxTaskWoken); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_INTERFACE_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_platform.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_platform.h new file mode 100644 index 00000000..b33292e9 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_platform.h @@ -0,0 +1,56 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_PLATFORM_H_ +#define _CSP_PLATFORM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Set OS */ +#if defined(CSP_POSIX) || defined(CSP_WINDOWS) || defined(CSP_MACOSX) + #define CSP_BASE_TYPE int + #define CSP_MAX_DELAY (UINT32_MAX) + #define CSP_INFINITY (UINT32_MAX) + #define CSP_DEFINE_CRITICAL(lock) static csp_bin_sem_handle_t lock + #define CSP_INIT_CRITICAL(lock) ({(csp_bin_sem_create(&lock) == CSP_SEMAPHORE_OK) ? CSP_ERR_NONE : CSP_ERR_NOMEM;}) + #define CSP_ENTER_CRITICAL(lock) do { csp_bin_sem_wait(&lock, CSP_MAX_DELAY); } while(0) + #define CSP_EXIT_CRITICAL(lock) do { csp_bin_sem_post(&lock); } while(0) +#elif defined(CSP_FREERTOS) + #include "FreeRTOS.h" + #define CSP_BASE_TYPE portBASE_TYPE + #define CSP_MAX_DELAY portMAX_DELAY + #define CSP_INFINITY portMAX_DELAY + #define CSP_DEFINE_CRITICAL(lock) + #define CSP_INIT_CRITICAL(lock) ({CSP_ERR_NONE;}) + #define CSP_ENTER_CRITICAL(lock) do { portENTER_CRITICAL(); } while (0) + #define CSP_EXIT_CRITICAL(lock) do { portEXIT_CRITICAL(); } while (0) +#else + #error "OS must be either CSP_POSIX, CSP_MACOSX, CSP_FREERTOS OR CSP_WINDOWS" +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_PLATFORM_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_rtable.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_rtable.h new file mode 100644 index 00000000..34cd18e2 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_rtable.h @@ -0,0 +1,149 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CSP_RTABLE_H_ +#define CSP_RTABLE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CSP_NODE_MAC 0xFF +#define CSP_ROUTE_COUNT (CSP_ID_HOST_MAX + 2) +#define CSP_ROUTE_TABLE_SIZE 5 * CSP_ROUTE_COUNT + +/** + * Find outgoing interface in routing table + * @param id Destination node + * @return pointer to outgoing interface or NULL + */ +csp_iface_t * csp_rtable_find_iface(uint8_t id); + +/** + * Find MAC address associated with node + * @param id Destination node + * @return MAC address + */ +uint8_t csp_rtable_find_mac(uint8_t id); + +/** + * Setup routing entry + * @param node Host + * @param mask Number of bits in netmask + * @param ifc Interface + * @param mac MAC address + * @return CSP error type + */ +int csp_rtable_set(uint8_t node, uint8_t mask, csp_iface_t *ifc, uint8_t mac); + +/** + * Print routing table to stdout + */ +void csp_rtable_print(void); + + +/** + * Load the routing table from a buffer + * (deprecated, please use new csp_rtable_load) + * + * Warning: + * The table will be RAW from memory and contains direct pointers, not interface names. + * Therefore it's very important that a saved routing table is deleted after a firmware update + * + * @param route_table_in pointer to routing table buffer + */ +void csp_route_table_load(uint8_t route_table_in[CSP_ROUTE_TABLE_SIZE]); + +/** + * Save the routing table to a buffer + * (deprecated, please use new csp_rtable_save) + * + * Warning: + * The table will be RAW from memory and contains direct pointers, not interface names. + * Therefore it's very important that a saved routing table is deleted after a firmware update + * + * @param route_table_out pointer to routing table buffer + */ +void csp_route_table_save(uint8_t route_table_out[CSP_ROUTE_TABLE_SIZE]); + +/** + * Save routing table as a string to a buffer, which can be parsed + * again by csp_rtable_load. + * @param buffer pointer to buffer + * @param maxlen length of buffer + * @return length of saved string + */ +int csp_rtable_save(char * buffer, int maxlen); + +/** + * Load routing table from a string in the format + * %u/%u %s %u + * - Address + * - Netmask + * - Ifname + * - Mac Address (this field is optional) + * An example routing string is "0/0 I2C, 8/2 KISS" + * The string must be \0 null terminated + * @param buffer Pointer to string + */ +void csp_rtable_load(const char * buffer); + +/** + * Check string for valid routing table + * @param buffer Pointer to string + * @return number of valid entries found + */ +int csp_rtable_check(const char * buffer); + +/** + * Clear routing table: + * This could be done before load to ensure an entire clean table is loaded. + */ +void csp_rtable_clear(void); + +/** + * Setup routing entry to single node + * (deprecated, please use csp_rtable_set) + * + * @param node Host + * @param ifc Interface + * @param mac MAC address + * @return CSP error type + */ +#define csp_route_set(node, ifc, mac) csp_rtable_set(node, CSP_ID_HOST_SIZE, ifc, mac) + +/** + * Print routing table + * (deprecated, please use csp_rtable_print) + */ +#define csp_route_print_table() csp_rtable_print(); + +/** + * Print list of interfaces + * (deprecated, please use csp_iflist_print) + */ +#define csp_route_print_interfaces() csp_iflist_print(); + +#ifdef __cplusplus +} +#endif +#endif /* CSP_RTABLE_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_types.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_types.h new file mode 100644 index 00000000..a9cc28cd --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/csp_types.h @@ -0,0 +1,235 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CSP_TYPES_H_ +#define CSP_TYPES_H_ + +#include +#include // -> CSP_HAVE_X defines +#ifdef CSP_HAVE_STDBOOL_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Make bool for compilers without stdbool.h */ +#ifndef CSP_HAVE_STDBOOL_H +#define bool int +#define false 0 +#define true !false +#endif + +/** + * RESERVED PORTS (SERVICES) + */ + +enum csp_reserved_ports_e { + CSP_CMP = 0, + CSP_PING = 1, + CSP_PS = 2, + CSP_MEMFREE = 3, + CSP_REBOOT = 4, + CSP_BUF_FREE = 5, + CSP_UPTIME = 6, + CSP_ANY = (CSP_MAX_BIND_PORT + 1), + CSP_PROMISC = (CSP_MAX_BIND_PORT + 2) +}; + +typedef enum { + CSP_PRIO_CRITICAL = 0, + CSP_PRIO_HIGH = 1, + CSP_PRIO_NORM = 2, + CSP_PRIO_LOW = 3, +} csp_prio_t; + +#define CSP_PRIORITIES (1 << CSP_ID_PRIO_SIZE) + +#ifdef CSP_USE_QOS +#define CSP_RX_QUEUE_LENGTH (CSP_CONN_QUEUE_LENGTH / CSP_PRIORITIES) +#define CSP_ROUTE_FIFOS CSP_PRIORITIES +#define CSP_RX_QUEUES CSP_PRIORITIES +#else +#define CSP_RX_QUEUE_LENGTH CSP_CONN_QUEUE_LENGTH +#define CSP_ROUTE_FIFOS 1 +#define CSP_RX_QUEUES 1 +#endif + +/** Size of bit-fields in CSP header */ +#define CSP_ID_PRIO_SIZE 2 +#define CSP_ID_HOST_SIZE 5 +#define CSP_ID_PORT_SIZE 6 +#define CSP_ID_FLAGS_SIZE 8 + +#define CSP_HEADER_BITS (CSP_ID_PRIO_SIZE + 2 * CSP_ID_HOST_SIZE + 2 * CSP_ID_PORT_SIZE + CSP_ID_FLAGS_SIZE) +#define CSP_HEADER_LENGTH (CSP_HEADER_BITS / 8) + +#if CSP_HEADER_BITS != 32 && __GNUC__ +#error "Header length must be 32 bits" +#endif + +/** Highest number to be entered in field */ +#define CSP_ID_PRIO_MAX ((1 << (CSP_ID_PRIO_SIZE)) - 1) +#define CSP_ID_HOST_MAX ((1 << (CSP_ID_HOST_SIZE)) - 1) +#define CSP_ID_PORT_MAX ((1 << (CSP_ID_PORT_SIZE)) - 1) +#define CSP_ID_FLAGS_MAX ((1 << (CSP_ID_FLAGS_SIZE)) - 1) + +/** Identifier field masks */ +#define CSP_ID_PRIO_MASK ((uint32_t) CSP_ID_PRIO_MAX << (CSP_ID_FLAGS_SIZE + 2 * CSP_ID_PORT_SIZE + 2 * CSP_ID_HOST_SIZE)) +#define CSP_ID_SRC_MASK ((uint32_t) CSP_ID_HOST_MAX << (CSP_ID_FLAGS_SIZE + 2 * CSP_ID_PORT_SIZE + 1 * CSP_ID_HOST_SIZE)) +#define CSP_ID_DST_MASK ((uint32_t) CSP_ID_HOST_MAX << (CSP_ID_FLAGS_SIZE + 2 * CSP_ID_PORT_SIZE)) +#define CSP_ID_DPORT_MASK ((uint32_t) CSP_ID_PORT_MAX << (CSP_ID_FLAGS_SIZE + 1 * CSP_ID_PORT_SIZE)) +#define CSP_ID_SPORT_MASK ((uint32_t) CSP_ID_PORT_MAX << (CSP_ID_FLAGS_SIZE)) +#define CSP_ID_FLAGS_MASK ((uint32_t) CSP_ID_FLAGS_MAX << (0)) + +#define CSP_ID_CONN_MASK (CSP_ID_SRC_MASK | CSP_ID_DST_MASK | CSP_ID_DPORT_MASK | CSP_ID_SPORT_MASK) + +/** + CSP identifier. +*/ +typedef union { + //! Entire identifier. + uint32_t ext; + //! Individual fields. + struct __attribute__((__packed__)) { +#if defined(CSP_BIG_ENDIAN) && !defined(CSP_LITTLE_ENDIAN) + unsigned int pri : CSP_ID_PRIO_SIZE; + unsigned int src : CSP_ID_HOST_SIZE; + unsigned int dst : CSP_ID_HOST_SIZE; + unsigned int dport : CSP_ID_PORT_SIZE; + unsigned int sport : CSP_ID_PORT_SIZE; + unsigned int flags : CSP_ID_FLAGS_SIZE; +#elif defined(CSP_LITTLE_ENDIAN) && !defined(CSP_BIG_ENDIAN) + unsigned int flags : CSP_ID_FLAGS_SIZE; + unsigned int sport : CSP_ID_PORT_SIZE; + unsigned int dport : CSP_ID_PORT_SIZE; + unsigned int dst : CSP_ID_HOST_SIZE; + unsigned int src : CSP_ID_HOST_SIZE; + unsigned int pri : CSP_ID_PRIO_SIZE; +#else +#error "Must define one of CSP_BIG_ENDIAN or CSP_LITTLE_ENDIAN in csp_platform.h" +#endif + }; +} csp_id_t; + +/** Broadcast address */ +#define CSP_BROADCAST_ADDR CSP_ID_HOST_MAX + +/** Default routing address */ +#define CSP_DEFAULT_ROUTE (CSP_ID_HOST_MAX + 1) + +/** CSP Flags */ +#define CSP_FRES1 0x80 // Reserved for future use +#define CSP_FRES2 0x40 // Reserved for future use +#define CSP_FRES3 0x20 // Reserved for future use +#define CSP_FFRAG 0x10 // Use fragmentation +#define CSP_FHMAC 0x08 // Use HMAC verification +#define CSP_FXTEA 0x04 // Use XTEA encryption +#define CSP_FRDP 0x02 // Use RDP protocol +#define CSP_FCRC32 0x01 // Use CRC32 checksum + +/** CSP Socket options */ +#define CSP_SO_NONE 0x0000 // No socket options +#define CSP_SO_RDPREQ 0x0001 // Require RDP +#define CSP_SO_RDPPROHIB 0x0002 // Prohibit RDP +#define CSP_SO_HMACREQ 0x0004 // Require HMAC +#define CSP_SO_HMACPROHIB 0x0008 // Prohibit HMAC +#define CSP_SO_XTEAREQ 0x0010 // Require XTEA +#define CSP_SO_XTEAPROHIB 0x0020 // Prohibit HMAC +#define CSP_SO_CRC32REQ 0x0040 // Require CRC32 +#define CSP_SO_CRC32PROHIB 0x0080 // Prohibit CRC32 +#define CSP_SO_CONN_LESS 0x0100 // Enable Connection Less mode +#define CSP_SO_INTERNAL_LISTEN 0x1000 // Internal flag: listen called on socket + +/** CSP Connect options */ +#define CSP_O_NONE CSP_SO_NONE // No connection options +#define CSP_O_RDP CSP_SO_RDPREQ // Enable RDP +#define CSP_O_NORDP CSP_SO_RDPPROHIB // Disable RDP +#define CSP_O_HMAC CSP_SO_HMACREQ // Enable HMAC +#define CSP_O_NOHMAC CSP_SO_HMACPROHIB // Disable HMAC +#define CSP_O_XTEA CSP_SO_XTEAREQ // Enable XTEA +#define CSP_O_NOXTEA CSP_SO_XTEAPROHIB // Disable XTEA +#define CSP_O_CRC32 CSP_SO_CRC32REQ // Enable CRC32 +#define CSP_O_NOCRC32 CSP_SO_CRC32PROHIB // Disable CRC32 + +/** + * CSP PACKET STRUCTURE + * Note: This structure is constructed to fit + * with all interface frame types in order to + * have buffer reuse + */ +typedef struct __attribute__((__packed__)) { + uint8_t padding[CSP_PADDING_BYTES]; /**< Interface dependent padding */ + uint16_t length; /**< Length field must be just before CSP ID */ + csp_id_t id; /**< CSP id must be just before data */ + union { + uint8_t data[0]; /**< This just points to the rest of the buffer, without a size indication. */ + uint16_t data16[0]; /**< The data 16 and 32 types makes it easy to reference an integer (properly aligned) */ + uint32_t data32[0]; /**< without the compiler warning about strict aliasing rules. */ + }; +} csp_packet_t; + +/** Interface TX function */ +struct csp_iface_s; +typedef int (*nexthop_t)(struct csp_iface_s * interface, csp_packet_t *packet, uint32_t timeout); + +/** Interface struct */ +typedef struct csp_iface_s { + const char *name; /**< Interface name (keep below 10 bytes) */ + void * driver; /**< Pointer to interface handler structure */ + nexthop_t nexthop; /**< Next hop function */ + uint16_t mtu; /**< Maximum Transmission Unit of interface */ + uint8_t split_horizon_off; /**< Disable the route-loop prevention on if */ + uint32_t tx; /**< Successfully transmitted packets */ + uint32_t rx; /**< Successfully received packets */ + uint32_t tx_error; /**< Transmit errors */ + uint32_t rx_error; /**< Receive errors */ + uint32_t drop; /**< Dropped packets */ + uint32_t autherr; /**< Authentication errors */ + uint32_t frame; /**< Frame format errors */ + uint32_t txbytes; /**< Transmitted bytes */ + uint32_t rxbytes; /**< Received bytes */ + uint32_t irq; /**< Interrupts */ + struct csp_iface_s *next; /**< Next interface */ +} csp_iface_t; + +/** + * This define must be equal to the size of the packet overhead in csp_packet_t. + * It is used in csp_buffer_get() to check the allocated buffer size against + * the required buffer size. + */ +#define CSP_BUFFER_PACKET_OVERHEAD (sizeof(csp_packet_t) - sizeof(((csp_packet_t *)0)->data)) + +/** Forward declaration of socket and connection structures */ +typedef struct csp_conn_s csp_socket_t; +typedef struct csp_conn_s csp_conn_t; + +#define CSP_HOSTNAME_LEN 20 +#define CSP_MODEL_LEN 30 + +/* CSP_REBOOT magic values */ +#define CSP_REBOOT_MAGIC 0x80078007 +#define CSP_REBOOT_SHUTDOWN_MAGIC 0xD1E5529A + +#ifdef __cplusplus +} +#endif +#endif /* CSP_TYPES_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/drivers/can_socketcan.h b/gomspace/libgscsp/lib/libcsp/include/csp/drivers/can_socketcan.h new file mode 100644 index 00000000..0963b414 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/drivers/can_socketcan.h @@ -0,0 +1,22 @@ +/* + * can_socketcan.h + * + * Created on: Feb 6, 2017 + * Author: johan + */ + +#ifndef LIB_CSP_INCLUDE_CSP_DRIVERS_CAN_SOCKETCAN_H_ +#define LIB_CSP_INCLUDE_CSP_DRIVERS_CAN_SOCKETCAN_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +csp_iface_t * csp_can_socketcan_init(const char * ifc, int bitrate, int promisc); + +#ifdef __cplusplus +} +#endif +#endif /* LIB_CSP_INCLUDE_CSP_DRIVERS_CAN_SOCKETCAN_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/drivers/i2c.h b/gomspace/libgscsp/lib/libcsp/include/csp/drivers/i2c.h new file mode 100644 index 00000000..3cf605ee --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/drivers/i2c.h @@ -0,0 +1,120 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file + * Common I2C interface, + * This file is derived from the Gomspace I2C driver, + * + */ + +#ifndef I2C_H_ +#define I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The return value of the driver is a bit strange, + * It should return E_NO_ERR if successfull and the value is -1 + */ +#define E_NO_ERR -1 + +/** + * Maximum transfer length on I2C + */ +#define I2C_MTU 256 + +/** + I2C device modes + @{ +*/ +/** + I2C Master mode. +*/ +#define I2C_MASTER 0 +/** + I2C Slave mode. +*/ +#define I2C_SLAVE 1 +/**@}*/ + +/** + Data structure for I2C frames. + This structs fits on top of #csp_packet_t, removing the need for copying data. +*/ +typedef struct __attribute__((packed)) i2c_frame_s { + //! Not used by CSP + uint8_t padding; + //! Not used by CSP - cleared before Tx + uint8_t retries; + //! Not used by CSP + uint32_t reserved; + //! Destination address + uint8_t dest; + //! Not used by CSP - cleared before Tx + uint8_t len_rx; + //! Length of \a data part + uint16_t len; + //! CSP data + uint8_t data[I2C_MTU]; +} i2c_frame_t; + +/** + Callback for receiving data. + + @param[in] frame received I2C frame + @param[out] pxTaskWoken can be set, if context switch is required due to received data. +*/ +typedef void (*i2c_callback_t) (i2c_frame_t * frame, void * pxTaskWoken); + +/** + Initialise the I2C driver + + Functions is called by csp_i2c_init(). + + @param handle Which I2C bus (if more than one exists) + @param mode I2C device mode. Must be either I2C_MASTER or I2C_SLAVE + @param addr Own slave address + @param speed Bus speed in kbps + @param queue_len_tx Length of transmit queue + @param queue_len_rx Length of receive queue + @param callback If this value is set, the driver will call this function instead of using an RX queue + @return Error code +*/ +int i2c_init(int handle, int mode, uint8_t addr, uint16_t speed, int queue_len_tx, int queue_len_rx, i2c_callback_t callback); + +/** + User I2C transmit function. + + Called by CSP, when sending message over I2C. + + @param handle Handle to the device + @param frame Pointer to I2C frame + @param timeout Ticks to wait + @return Error code +*/ +int i2c_send(int handle, i2c_frame_t * frame, uint16_t timeout); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/drivers/usart.h b/gomspace/libgscsp/lib/libcsp/include/csp/drivers/usart.h new file mode 100644 index 00000000..d2da8448 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/drivers/usart.h @@ -0,0 +1,107 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file + * Common USART interface, + * This file is derived from the Gomspace USART driver, + * the main difference is the assumption that only one USART will be present on a PC + */ + +#ifndef USART_H_ +#define USART_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Usart configuration, to be used with the usart_init call. +*/ +struct usart_conf { + //! USART device. + const char *device; + //! bits per second. + uint32_t baudrate; + //! Number of data bits. + uint8_t databits; + //! Number of stop bits. + uint8_t stopbits; + //! Parity setting. + uint8_t paritysetting; + //! Enable parity checking (Windows only). + uint8_t checkparity; +}; + +/** + Initialise UART with the usart_conf data structure + @param[in] conf full configuration structure +*/ +void usart_init(struct usart_conf *conf); + +/** + In order to catch incoming chars use the callback. + Only one callback per interface. + @param[in] handle usart[0,1,2,3] + @param[in] callback function pointer +*/ +typedef void (*usart_callback_t) (uint8_t *buf, int len, void *pxTaskWoken); + +/** + Set callback for receiving data. +*/ +void usart_set_callback(usart_callback_t callback); + +/** + Insert a character to the RX buffer of a usart + + @param[in] c character to insert + @param[out] pxTaskWoken can be set, if context switch is required due to received data. +*/ +void usart_insert(char c, void *pxTaskWoken); + +/** + Polling putchar (stdin). + + @param[in] c Character to transmit +*/ +void usart_putc(char c); + +/** + Send char buffer on UART (stdout). + + @param[in] buf Pointer to data + @param[in] len Length of data +*/ +void usart_putstr(char *buf, int len); + +/** + Buffered getchar (stdin). + + @return Character received +*/ +char usart_getc(void); + +#ifdef __cplusplus +} +#endif +#endif /* USART_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_can.h b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_can.h new file mode 100644 index 00000000..229671f2 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_can.h @@ -0,0 +1,76 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_IF_CAN_H_ +#define _CSP_IF_CAN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include + +/* CAN header macros */ +#define CFP_HOST_SIZE 5 +#define CFP_TYPE_SIZE 1 +#define CFP_REMAIN_SIZE 8 +#define CFP_ID_SIZE 10 + +/* Macros for extracting header fields */ +#define CFP_FIELD(id,rsiz,fsiz) ((uint32_t)((uint32_t)((id) >> (rsiz)) & (uint32_t)((1 << (fsiz)) - 1))) +#define CFP_SRC(id) CFP_FIELD(id, CFP_HOST_SIZE + CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE, CFP_HOST_SIZE) +#define CFP_DST(id) CFP_FIELD(id, CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE, CFP_HOST_SIZE) +#define CFP_TYPE(id) CFP_FIELD(id, CFP_REMAIN_SIZE + CFP_ID_SIZE, CFP_TYPE_SIZE) +#define CFP_REMAIN(id) CFP_FIELD(id, CFP_ID_SIZE, CFP_REMAIN_SIZE) +#define CFP_ID(id) CFP_FIELD(id, 0, CFP_ID_SIZE) + +/* Macros for building CFP headers */ +#define CFP_MAKE_FIELD(id,fsiz,rsiz) ((uint32_t)(((id) & (uint32_t)((uint32_t)(1 << (fsiz)) - 1)) << (rsiz))) +#define CFP_MAKE_SRC(id) CFP_MAKE_FIELD(id, CFP_HOST_SIZE, CFP_HOST_SIZE + CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE) +#define CFP_MAKE_DST(id) CFP_MAKE_FIELD(id, CFP_HOST_SIZE, CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE) +#define CFP_MAKE_TYPE(id) CFP_MAKE_FIELD(id, CFP_TYPE_SIZE, CFP_REMAIN_SIZE + CFP_ID_SIZE) +#define CFP_MAKE_REMAIN(id) CFP_MAKE_FIELD(id, CFP_REMAIN_SIZE, CFP_ID_SIZE) +#define CFP_MAKE_ID(id) CFP_MAKE_FIELD(id, CFP_ID_SIZE, 0) + +/* Mask to uniquely separate connections */ +#define CFP_ID_CONN_MASK (CFP_MAKE_SRC((uint32_t)(1 << CFP_HOST_SIZE) - 1) | \ + CFP_MAKE_DST((uint32_t)(1 << CFP_HOST_SIZE) - 1) | \ + CFP_MAKE_ID((uint32_t)(1 << CFP_ID_SIZE) - 1)) + +/** + Default Maximum Transmission Unit (MTU) for CSP over CAN. + Maximum value is 2042 bytes. +*/ +#define CSP_CAN_MTU 256 + +int csp_can_rx(csp_iface_t *interface, uint32_t id, const uint8_t * data, uint8_t dlc, CSP_BASE_TYPE *task_woken); +int csp_can_tx(csp_iface_t *interface, csp_packet_t *packet, uint32_t timeout); + +/* Must be implemented by the driver */ +int csp_can_tx_frame(csp_iface_t *interface, uint32_t id, const uint8_t * data, uint8_t dlc); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CSP_IF_CAN_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_i2c.h b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_i2c.h new file mode 100644 index 00000000..c2169843 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_i2c.h @@ -0,0 +1,51 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_IF_I2C_H_ +#define _CSP_IF_I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include +#include + +extern csp_iface_t csp_if_i2c; + +/** + * Capture I2C RX events for CSP + * @param opt_addr local i2c address + * @param handle which i2c device to use + * @param speed interface speed in kHz (normally 100 or 400) + * @return csp_error.h code + */ +int csp_i2c_init(uint8_t opt_addr, int handle, int speed); + +void csp_i2c_rx(i2c_frame_t * frame, void * pxTaskWoken); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CSP_IF_I2C_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_kiss.h b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_kiss.h new file mode 100644 index 00000000..f164cad1 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_kiss.h @@ -0,0 +1,110 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_IF_KISS_H_ +#define _CSP_IF_KISS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include + +/** + * The KISS interface relies on the USART callback in order to parse incoming + * messaged from the serial interface. The USART callback however does not + * support passing the handle number of the responding USART, so you need to implement + * a USART callback for each handle and then call kiss_rx subsequently. + * + * In order to initialize the KISS interface. Fist call kiss_init() and then + * setup your usart to call csp_kiss_rx when new data is available. + * + * When a byte is not a part of a kiss packet, it will be returned to your + * usart driver using the usart_insert funtion that you provide. + * + * @param csp_iface pointer to interface + * @param buf pointer to incoming data + * @param len length of incoming data + * @param pxTaskWoken NULL if task context, pointer to variable if ISR + */ +void csp_kiss_rx(csp_iface_t * interface, uint8_t *buf, int len, void *pxTaskWoken); + +/** + * The putc function is used by the kiss interface to send + * a string of data to the serial port. This function must + * be implemented by the user, and passed to the kiss + * interface through the kiss_init function. + * @param buf byte to push + */ +typedef void (*csp_kiss_putc_f)(char buf); + +/** + * The characters not accepted by the kiss interface, are discarded + * using this function, which must be implemented by the user + * and passed through the kiss_init function. + * + * This reject function is typically used to display ASCII strings + * sent over the serial port, which are not in KISS format. Such as + * debugging information. + * + * @param c rejected character + * @param pxTaskWoken NULL if task context, pointer to variable if ISR + */ +typedef void (*csp_kiss_discard_f)(char c, void *pxTaskWoken); + +typedef enum { + KISS_MODE_NOT_STARTED, + KISS_MODE_STARTED, + KISS_MODE_ESCAPED, + KISS_MODE_SKIP_FRAME, +} kiss_mode_e; + +/** + * This structure should be statically allocated by the user + * and passed to the kiss interface during the init function + * no member information should be changed + */ +typedef struct csp_kiss_handle_s { + //! Put character on usart (tx). + csp_kiss_putc_f kiss_putc; + //! Discard - not KISS data (rx). + csp_kiss_discard_f kiss_discard; + //! Internal KISS state. + unsigned int rx_length; + //! Internal KISS state. + kiss_mode_e rx_mode; + //! Internal KISS state. + unsigned int rx_first; + //! Not used. + volatile unsigned char *rx_cbuf; + //! Internal KISS state. + csp_packet_t * rx_packet; +} csp_kiss_handle_t; + +void csp_kiss_init(csp_iface_t * csp_iface, csp_kiss_handle_t * csp_kiss_handle, csp_kiss_putc_f kiss_putc_f, csp_kiss_discard_f kiss_discard_f, const char * name); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CSP_IF_KISS_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_lo.h b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_lo.h new file mode 100644 index 00000000..793c45ac --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_lo.h @@ -0,0 +1,38 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_IF_LO_H_ +#define _CSP_IF_LO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* CSP includes */ +#include +#include + +extern csp_iface_t csp_if_lo; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_IF_LO_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_zmqhub.h b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_zmqhub.h new file mode 100644 index 00000000..f9ab43bf --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_zmqhub.h @@ -0,0 +1,26 @@ +#ifndef CSP_IF_ZMQHUB_H_ +#define CSP_IF_ZMQHUB_H_ + +#include + +extern csp_iface_t csp_if_zmqhub; + +/** + * Setup ZMQ interface + * @param addr only receive messages matching this address (255 means all) + * @param host Pointer to string containing zmqproxy host + * @return CSP_ERR + */ +int csp_zmqhub_init(uint8_t addr, const char * host); + +/** + * Setup ZMQ interface + * @param addr only receive messages matching this address (255 means all) + * @param publisher_endpoint Pointer to string containing zmqproxy publisher endpoint + * @param subscriber_endpoint Pointer to string containing zmqproxy subscriber endpoint + * @return CSP_ERR + */ +int csp_zmqhub_init_w_endpoints(uint8_t addr, const char * publisher_url, + const char * subscriber_url); + +#endif /* CSP_IF_ZMQHUB_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_malloc.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_malloc.c new file mode 100644 index 00000000..97e5c8f4 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_malloc.c @@ -0,0 +1,33 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +/* FreeRTOS includes */ +#include + +void * csp_malloc(size_t size) { + return pvPortMalloc(size); +} + +void csp_free(void *ptr) { + vPortFree(ptr); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_queue.c new file mode 100644 index 00000000..44efd0eb --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_queue.c @@ -0,0 +1,66 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +/* FreeRTOS includes */ +#include +#include + +/* CSP includes */ +#include + +#include + +csp_queue_handle_t csp_queue_create(int length, size_t item_size) { + return xQueueCreate(length, item_size); +} + +void csp_queue_remove(csp_queue_handle_t queue) { + vQueueDelete(queue); +} + +int csp_queue_enqueue(csp_queue_handle_t handle, void * value, uint32_t timeout) { + if (timeout != CSP_MAX_DELAY) + timeout = timeout / portTICK_RATE_MS; + return xQueueSendToBack(handle, value, timeout); +} + +int csp_queue_enqueue_isr(csp_queue_handle_t handle, void * value, CSP_BASE_TYPE * task_woken) { + return xQueueSendToBackFromISR(handle, value, task_woken); +} + +int csp_queue_dequeue(csp_queue_handle_t handle, void * buf, uint32_t timeout) { + if (timeout != CSP_MAX_DELAY) + timeout = timeout / portTICK_RATE_MS; + return xQueueReceive(handle, buf, timeout); +} + +int csp_queue_dequeue_isr(csp_queue_handle_t handle, void * buf, CSP_BASE_TYPE * task_woken) { + return xQueueReceiveFromISR(handle, buf, task_woken); +} + +int csp_queue_size(csp_queue_handle_t handle) { + return uxQueueMessagesWaiting(handle); +} + +int csp_queue_size_isr(csp_queue_handle_t handle) { + return uxQueueMessagesWaitingFromISR(handle); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_semaphore.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_semaphore.c new file mode 100644 index 00000000..b91757e5 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_semaphore.c @@ -0,0 +1,96 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +/* FreeRTOS includes */ +#include +#include + +/* CSP includes */ +#include + +#include +#include +#include + +int csp_mutex_create(csp_mutex_t * mutex) { + *mutex = xSemaphoreCreateMutex(); + if (*mutex) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_mutex_remove(csp_mutex_t * mutex) { + return csp_bin_sem_remove(mutex); +} + +int csp_mutex_lock(csp_mutex_t * mutex, uint32_t timeout) { + return csp_bin_sem_wait(mutex, timeout); +} + +int csp_mutex_unlock(csp_mutex_t * mutex) { + return csp_bin_sem_post(mutex); +} + +int csp_bin_sem_create(csp_bin_sem_handle_t * sem) { + vSemaphoreCreateBinary(*sem); + return CSP_SEMAPHORE_OK; +} + +int csp_bin_sem_remove(csp_bin_sem_handle_t * sem) { + if ((sem != NULL) && (*sem != NULL)) { + csp_queue_remove(*sem); + } + return CSP_SEMAPHORE_OK; +} + +int csp_bin_sem_wait(csp_bin_sem_handle_t * sem, uint32_t timeout) { + csp_log_lock("Wait: %p", sem); + if (timeout != CSP_MAX_DELAY) + timeout = timeout / portTICK_RATE_MS; + if (xSemaphoreTake(*sem, timeout) == pdPASS) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_bin_sem_post(csp_bin_sem_handle_t * sem) { + csp_log_lock("Post: %p", sem); + if (xSemaphoreGive(*sem) == pdPASS) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_bin_sem_post_isr(csp_bin_sem_handle_t * sem, CSP_BASE_TYPE * task_woken) { + csp_log_lock("Post: %p", sem); + if (xSemaphoreGiveFromISR(*sem, task_woken) == pdPASS) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_system.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_system.c new file mode 100644 index 00000000..a81c84b4 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_system.c @@ -0,0 +1,139 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +#include +#include + +#include + +int csp_sys_tasklist(char * out) { +#if (tskKERNEL_VERSION_MAJOR < 8) + vTaskList((signed portCHAR *) out); +#else + vTaskList(out); +#endif + return CSP_ERR_NONE; +} + +int csp_sys_tasklist_size(void) { + return 40 * uxTaskGetNumberOfTasks(); +} + +uint32_t csp_sys_memfree(void) { + + uint32_t total = 0, max = UINT32_MAX, size; + void * pmem; + + /* If size_t is less than 32 bits, start with 10 KiB */ + size = sizeof(uint32_t) > sizeof(size_t) ? 10000 : 1000000; + + while (1) { + pmem = pvPortMalloc(size + total); + if (pmem == NULL) { + max = size + total; + size = size / 2; + } else { + total += size; + if (total + size >= max) + size = size / 2; + vPortFree(pmem); + } + if (size < 32) break; + } + + return total; +} + +int csp_sys_reboot(void) { + + extern void __attribute__((weak)) cpu_set_reset_cause(unsigned int); + if (cpu_set_reset_cause) + cpu_set_reset_cause(1); + + extern void __attribute__((weak)) cpu_reset(void); + if (cpu_reset) { + cpu_reset(); + while (1); + } + + csp_log_error("Failed to reboot"); + + return CSP_ERR_INVAL; +} + +int csp_sys_shutdown(void) { + + extern void __attribute__((weak)) cpu_shutdown(void); + if (cpu_shutdown) { + cpu_shutdown(); + while (1); + } + + csp_log_error("Failed to shutdown"); + + return CSP_ERR_INVAL; +} + +void csp_sys_set_color(csp_color_t color) { + + unsigned int color_code, modifier_code; + switch (color & COLOR_MASK_COLOR) { + case COLOR_BLACK: + color_code = 30; break; + case COLOR_RED: + color_code = 31; break; + case COLOR_GREEN: + color_code = 32; break; + case COLOR_YELLOW: + color_code = 33; break; + case COLOR_BLUE: + color_code = 34; break; + case COLOR_MAGENTA: + color_code = 35; break; + case COLOR_CYAN: + color_code = 36; break; + case COLOR_WHITE: + color_code = 37; break; + case COLOR_RESET: + default: + color_code = 0; break; + } + + switch (color & COLOR_MASK_MODIFIER) { + case COLOR_BOLD: + modifier_code = 1; break; + case COLOR_UNDERLINE: + modifier_code = 2; break; + case COLOR_BLINK: + modifier_code = 3; break; + case COLOR_HIDE: + modifier_code = 4; break; + case COLOR_NORMAL: + default: + modifier_code = 0; break; + } + + printf("\033[%u;%um", modifier_code, color_code); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_thread.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_thread.c new file mode 100644 index 00000000..af8296cd --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_thread.c @@ -0,0 +1,38 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +/* CSP includes */ +#include + +#include + +int csp_thread_create(csp_thread_return_t (* routine)(void *), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle) { +#if (tskKERNEL_VERSION_MAJOR >= 8) + portBASE_TYPE ret = xTaskCreate(routine, thread_name, stack_depth, parameters, priority, handle); +#else + portBASE_TYPE ret = xTaskCreate(routine, (signed char *) thread_name, stack_depth, parameters, priority, handle); +#endif + if (ret != pdTRUE) + return CSP_ERR_NOMEM; + return CSP_ERR_NONE; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_time.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_time.c new file mode 100644 index 00000000..fd54a8cb --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_time.c @@ -0,0 +1,46 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +/* FreeRTOS includes */ +#include +#include + +/* CSP includes */ +#include + +#include + +uint32_t csp_get_ms(void) { + return (uint32_t)(xTaskGetTickCount() * (1000/configTICK_RATE_HZ)); +} + +uint32_t csp_get_ms_isr(void) { + return (uint32_t)(xTaskGetTickCountFromISR() * (1000/configTICK_RATE_HZ)); +} + +uint32_t csp_get_s(void) { + return (uint32_t)(xTaskGetTickCount()/configTICK_RATE_HZ); +} + +uint32_t csp_get_s_isr(void) { + return (uint32_t)(xTaskGetTickCountFromISR()/configTICK_RATE_HZ); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_malloc.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_malloc.c new file mode 100644 index 00000000..95bb8cc7 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_malloc.c @@ -0,0 +1,31 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +void * csp_malloc(size_t size) { + return malloc(size); +} + +void csp_free(void *ptr) { + free(ptr); +} + diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_queue.c new file mode 100644 index 00000000..a2fb1b4f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_queue.c @@ -0,0 +1,64 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +/* CSP includes */ +#include + +#include +#include + + +csp_queue_handle_t csp_queue_create(int length, size_t item_size) { + return pthread_queue_create(length, item_size); +} + +void csp_queue_remove(csp_queue_handle_t queue) { + return pthread_queue_delete(queue); +} + +int csp_queue_enqueue(csp_queue_handle_t handle, void *value, uint32_t timeout) { + return pthread_queue_enqueue(handle, value, timeout); +} + +int csp_queue_enqueue_isr(csp_queue_handle_t handle, void * value, CSP_BASE_TYPE * task_woken) { + if (task_woken != NULL) + *task_woken = 0; + return csp_queue_enqueue(handle, value, 0); +} + +int csp_queue_dequeue(csp_queue_handle_t handle, void *buf, uint32_t timeout) { + return pthread_queue_dequeue(handle, buf, timeout); +} + +int csp_queue_dequeue_isr(csp_queue_handle_t handle, void *buf, CSP_BASE_TYPE * task_woken) { + *task_woken = 0; + return csp_queue_dequeue(handle, buf, 0); +} + +int csp_queue_size(csp_queue_handle_t handle) { + return pthread_queue_items(handle); +} + +int csp_queue_size_isr(csp_queue_handle_t handle) { + return pthread_queue_items(handle); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_semaphore.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_semaphore.c new file mode 100644 index 00000000..915447f3 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_semaphore.c @@ -0,0 +1,105 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* CSP includes */ +#include + +#include + +int csp_mutex_create(csp_mutex_t * mutex) { + csp_log_lock("Mutex init: %p", mutex); + *mutex = pthread_queue_create(1, sizeof(int)); + if (mutex) { + int dummy = 0; + pthread_queue_enqueue(*mutex, &dummy, 0); + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_mutex_remove(csp_mutex_t * mutex) { + pthread_queue_delete(*mutex); + return CSP_SEMAPHORE_OK; +} + +int csp_mutex_lock(csp_mutex_t * mutex, uint32_t timeout) { + + int ret; + csp_log_lock("Wait: %p timeout %"PRIu32, mutex, timeout); + + if (timeout == CSP_INFINITY) { + /* TODO: fix this to be infinite */ + int dummy = 0; + if (pthread_queue_dequeue(*mutex, &dummy, timeout) == PTHREAD_QUEUE_OK) + ret = CSP_MUTEX_OK; + else + ret = CSP_MUTEX_ERROR; + } else { + int dummy = 0; + if (pthread_queue_dequeue(*mutex, &dummy, timeout) == PTHREAD_QUEUE_OK) + ret = CSP_MUTEX_OK; + else + ret = CSP_MUTEX_ERROR; + } + + return ret == CSP_MUTEX_ERROR ? CSP_SEMAPHORE_ERROR : CSP_SEMAPHORE_OK; +} + +int csp_mutex_unlock(csp_mutex_t * mutex) { + int dummy = 0; + if (pthread_queue_enqueue(*mutex, &dummy, 0) == PTHREAD_QUEUE_OK) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_bin_sem_create(csp_bin_sem_handle_t * sem) { + return csp_mutex_create(sem); +} + +int csp_bin_sem_remove(csp_bin_sem_handle_t * sem) { + return csp_mutex_remove(sem); +} + +int csp_bin_sem_wait(csp_bin_sem_handle_t * sem, uint32_t timeout) { + return csp_mutex_lock(sem, timeout); +} + +int csp_bin_sem_post(csp_bin_sem_handle_t * sem) { + return csp_mutex_unlock(sem); +} + +int csp_bin_sem_post_isr(csp_bin_sem_handle_t * sem, CSP_BASE_TYPE * task_woken) { + return csp_mutex_unlock(sem); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_system.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_system.c new file mode 100644 index 00000000..834cb210 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_system.c @@ -0,0 +1,99 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +#include +#include + +#include + +int csp_sys_tasklist(char * out) { + strcpy(out, "Tasklist not available on OSX"); + return CSP_ERR_NONE; +} + +int csp_sys_tasklist_size(void) { + return 100; +} + +uint32_t csp_sys_memfree(void) { + /* TODO: Fix memory free on OSX */ + uint32_t total = 0; + return total; +} + +int csp_sys_reboot(void) { + /* TODO: Fix reboot on OSX */ + csp_log_error("Failed to reboot"); + + return CSP_ERR_INVAL; +} + +int csp_sys_shutdown(void) { + /* TODO: Fix shutdown on OSX */ + csp_log_error("Failed to shutdown"); + + return CSP_ERR_INVAL; +} + +void csp_sys_set_color(csp_color_t color) { + + unsigned int color_code, modifier_code; + switch (color & COLOR_MASK_COLOR) { + case COLOR_BLACK: + color_code = 30; break; + case COLOR_RED: + color_code = 31; break; + case COLOR_GREEN: + color_code = 32; break; + case COLOR_YELLOW: + color_code = 33; break; + case COLOR_BLUE: + color_code = 34; break; + case COLOR_MAGENTA: + color_code = 35; break; + case COLOR_CYAN: + color_code = 36; break; + case COLOR_WHITE: + color_code = 37; break; + case COLOR_RESET: + default: + color_code = 0; break; + } + + switch (color & COLOR_MASK_MODIFIER) { + case COLOR_BOLD: + modifier_code = 1; break; + case COLOR_UNDERLINE: + modifier_code = 2; break; + case COLOR_BLINK: + modifier_code = 3; break; + case COLOR_HIDE: + modifier_code = 4; break; + case COLOR_NORMAL: + default: + modifier_code = 0; break; + } + + printf("\033[%u;%um", modifier_code, color_code); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_thread.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_thread.c new file mode 100644 index 00000000..ed64856a --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_thread.c @@ -0,0 +1,31 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +/* CSP includes */ +#include + +#include + +int csp_thread_create(csp_thread_return_t (* routine)(void *), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle) { + return pthread_create(handle, NULL, routine, parameters); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_time.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_time.c new file mode 100644 index 00000000..a53f27e6 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_time.c @@ -0,0 +1,65 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +/* CSP includes */ +#include + +#include + +uint32_t csp_get_ms(void) { + struct timespec ts; + + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + ts.tv_sec = mts.tv_sec; + ts.tv_nsec = mts.tv_nsec; + + return (uint32_t)(ts.tv_sec*1000+ts.tv_nsec/1000000); +} + +uint32_t csp_get_ms_isr(void) { + return csp_get_ms(); +} + +uint32_t csp_get_s(void) { + struct timespec ts; + + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + ts.tv_sec = mts.tv_sec; + ts.tv_nsec = mts.tv_nsec; + + return (uint32_t)ts.tv_sec; +} + +uint32_t csp_get_s_isr(void) { + return csp_get_s(); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/pthread_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/pthread_queue.c new file mode 100644 index 00000000..c4ac8c1d --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/pthread_queue.c @@ -0,0 +1,179 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Inspired by c-pthread-queue by Matthew Dickinson +http://code.google.com/p/c-pthread-queue/ +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* CSP includes */ +#include + +pthread_queue_t * pthread_queue_create(int length, size_t item_size) { + + pthread_queue_t * q = malloc(sizeof(pthread_queue_t)); + + if (q != NULL) { + q->buffer = malloc(length*item_size); + if (q->buffer != NULL) { + q->size = length; + q->item_size = item_size; + q->items = 0; + q->in = 0; + q->out = 0; + if (pthread_mutex_init(&(q->mutex), NULL) || pthread_cond_init(&(q->cond_full), NULL) || pthread_cond_init(&(q->cond_empty), NULL)) { + free(q->buffer); + free(q); + q = NULL; + } + } else { + free(q); + q = NULL; + } + } + + return q; + +} + +void pthread_queue_delete(pthread_queue_t * q) { + + if (q == NULL) + return; + + free(q->buffer); + free(q); + + return; + +} + +int pthread_queue_enqueue(pthread_queue_t * queue, void * value, uint32_t timeout) { + + int ret; + + /* Calculate timeout */ + struct timespec ts; + + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + ts.tv_sec = mts.tv_sec; + ts.tv_nsec = mts.tv_nsec; + + uint32_t sec = timeout / 1000; + uint32_t nsec = (timeout - 1000 * sec) * 1000000; + + ts.tv_sec += sec; + + if (ts.tv_nsec + nsec > 1000000000) + ts.tv_sec++; + + ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; + + /* Get queue lock */ + pthread_mutex_lock(&(queue->mutex)); + while (queue->items == queue->size) { + ret = pthread_cond_timedwait(&(queue->cond_full), &(queue->mutex), &ts); + if (ret != 0) { + pthread_mutex_unlock(&(queue->mutex)); + return PTHREAD_QUEUE_FULL; + } + } + + /* Coby object from input buffer */ + memcpy(queue->buffer+(queue->in * queue->item_size), value, queue->item_size); + queue->items++; + queue->in = (queue->in + 1) % queue->size; + pthread_mutex_unlock(&(queue->mutex)); + + /* Nofify blocked threads */ + pthread_cond_broadcast(&(queue->cond_empty)); + + return PTHREAD_QUEUE_OK; + +} + +int pthread_queue_dequeue(pthread_queue_t * queue, void * buf, uint32_t timeout) { + + int ret; + + /* Calculate timeout */ + struct timespec ts; + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + ts.tv_sec = mts.tv_sec; + ts.tv_nsec = mts.tv_nsec; + + uint32_t sec = timeout / 1000; + uint32_t nsec = (timeout - 1000 * sec) * 1000000; + + ts.tv_sec += sec; + + if (ts.tv_nsec + nsec > 1000000000) + ts.tv_sec++; + + ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; + + /* Get queue lock */ + pthread_mutex_lock(&(queue->mutex)); + while (queue->items == 0) { + ret = pthread_cond_timedwait(&(queue->cond_empty), &(queue->mutex), &ts); + if (ret != 0) { + pthread_mutex_unlock(&(queue->mutex)); + return PTHREAD_QUEUE_EMPTY; + } + } + + /* Coby object to output buffer */ + memcpy(buf, queue->buffer+(queue->out * queue->item_size), queue->item_size); + queue->items--; + queue->out = (queue->out + 1) % queue->size; + pthread_mutex_unlock(&(queue->mutex)); + + /* Nofify blocked threads */ + pthread_cond_broadcast(&(queue->cond_full)); + + return PTHREAD_QUEUE_OK; + +} + +int pthread_queue_items(pthread_queue_t * queue) { + + pthread_mutex_lock(&(queue->mutex)); + int items = queue->items; + pthread_mutex_unlock(&(queue->mutex)); + + return items; + +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_malloc.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_malloc.c new file mode 100644 index 00000000..95bb8cc7 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_malloc.c @@ -0,0 +1,31 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +void * csp_malloc(size_t size) { + return malloc(size); +} + +void csp_free(void *ptr) { + free(ptr); +} + diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_queue.c new file mode 100644 index 00000000..a2fb1b4f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_queue.c @@ -0,0 +1,64 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +/* CSP includes */ +#include + +#include +#include + + +csp_queue_handle_t csp_queue_create(int length, size_t item_size) { + return pthread_queue_create(length, item_size); +} + +void csp_queue_remove(csp_queue_handle_t queue) { + return pthread_queue_delete(queue); +} + +int csp_queue_enqueue(csp_queue_handle_t handle, void *value, uint32_t timeout) { + return pthread_queue_enqueue(handle, value, timeout); +} + +int csp_queue_enqueue_isr(csp_queue_handle_t handle, void * value, CSP_BASE_TYPE * task_woken) { + if (task_woken != NULL) + *task_woken = 0; + return csp_queue_enqueue(handle, value, 0); +} + +int csp_queue_dequeue(csp_queue_handle_t handle, void *buf, uint32_t timeout) { + return pthread_queue_dequeue(handle, buf, timeout); +} + +int csp_queue_dequeue_isr(csp_queue_handle_t handle, void *buf, CSP_BASE_TYPE * task_woken) { + *task_woken = 0; + return csp_queue_dequeue(handle, buf, 0); +} + +int csp_queue_size(csp_queue_handle_t handle) { + return pthread_queue_items(handle); +} + +int csp_queue_size_isr(csp_queue_handle_t handle) { + return pthread_queue_items(handle); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_semaphore.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_semaphore.c new file mode 100644 index 00000000..6829dec2 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_semaphore.c @@ -0,0 +1,164 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* CSP includes */ +#include + +#include + +int csp_mutex_create(csp_mutex_t * mutex) { + csp_log_lock("Mutex init: %p", mutex); + if (pthread_mutex_init(mutex, NULL) == 0) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_mutex_remove(csp_mutex_t * mutex) { + if (pthread_mutex_destroy(mutex) == 0) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_mutex_lock(csp_mutex_t * mutex, uint32_t timeout) { + + int ret; + struct timespec ts; + uint32_t sec, nsec; + + csp_log_lock("Wait: %p timeout %"PRIu32, mutex, timeout); + + if (timeout == CSP_INFINITY) { + ret = pthread_mutex_lock(mutex); + } else { + if (clock_gettime(CLOCK_REALTIME, &ts)) + return CSP_SEMAPHORE_ERROR; + + sec = timeout / 1000; + nsec = (timeout - 1000 * sec) * 1000000; + + ts.tv_sec += sec; + + if (ts.tv_nsec + nsec >= 1000000000) + ts.tv_sec++; + + ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; + + ret = pthread_mutex_timedlock(mutex, &ts); + } + + if (ret != 0) + return CSP_SEMAPHORE_ERROR; + + return CSP_SEMAPHORE_OK; +} + +int csp_mutex_unlock(csp_mutex_t * mutex) { + if (pthread_mutex_unlock(mutex) == 0) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_bin_sem_create(csp_bin_sem_handle_t * sem) { + csp_log_lock("Semaphore init: %p", sem); + if (sem_init(sem, 0, 1) == 0) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} + +int csp_bin_sem_remove(csp_bin_sem_handle_t * sem) { + if (sem_destroy(sem) == 0) + return CSP_SEMAPHORE_OK; + else + return CSP_SEMAPHORE_ERROR; +} + +int csp_bin_sem_wait(csp_bin_sem_handle_t * sem, uint32_t timeout) { + + int ret; + struct timespec ts; + uint32_t sec, nsec; + + csp_log_lock("Wait: %p timeout %"PRIu32, sem, timeout); + + if (timeout == CSP_INFINITY) { + ret = sem_wait(sem); + } else { + if (clock_gettime(CLOCK_REALTIME, &ts)) + return CSP_SEMAPHORE_ERROR; + + sec = timeout / 1000; + nsec = (timeout - 1000 * sec) * 1000000; + + ts.tv_sec += sec; + + if (ts.tv_nsec + nsec >= 1000000000) + ts.tv_sec++; + + ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; + + ret = sem_timedwait(sem, &ts); + } + + if (ret != 0) + return CSP_SEMAPHORE_ERROR; + + return CSP_SEMAPHORE_OK; +} + +int csp_bin_sem_post(csp_bin_sem_handle_t * sem) { + CSP_BASE_TYPE dummy = 0; + return csp_bin_sem_post_isr(sem, &dummy); +} + +int csp_bin_sem_post_isr(csp_bin_sem_handle_t * sem, CSP_BASE_TYPE * task_woken) { + csp_log_lock("Post: %p", sem); + *task_woken = 0; + + int value; + sem_getvalue(sem, &value); + if (value > 0) + return CSP_SEMAPHORE_OK; + + if (sem_post(sem) == 0) { + return CSP_SEMAPHORE_OK; + } else { + return CSP_SEMAPHORE_ERROR; + } +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_system.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_system.c new file mode 100644 index 00000000..6c882c7c --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_system.c @@ -0,0 +1,131 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +int csp_sys_tasklist(char * out) { + strcpy(out, "Tasklist not available on POSIX"); + return CSP_ERR_NONE; +} + +int csp_sys_tasklist_size(void) { + return 100; +} + +uint32_t csp_sys_memfree(void) { + uint32_t total = 0; + struct sysinfo info; + sysinfo(&info); + total = info.freeram * info.mem_unit; + return total; +} + +int csp_sys_reboot(void) { +#ifdef CSP_USE_INIT_SHUTDOWN + /* Let init(1) handle the reboot */ + int ret = system("reboot"); + (void) ret; /* Silence warning */ +#else + int magic = LINUX_REBOOT_CMD_RESTART; + + /* Sync filesystem before reboot */ + sync(); + reboot(magic); +#endif + + /* If reboot(2) returns, it is an error */ + csp_log_error("Failed to reboot: %s", strerror(errno)); + + return CSP_ERR_INVAL; +} + +int csp_sys_shutdown(void) { +#ifdef CSP_USE_INIT_SHUTDOWN + /* Let init(1) handle the shutdown */ + int ret = system("halt"); + (void) ret; /* Silence warning */ +#else + int magic = LINUX_REBOOT_CMD_HALT; + + /* Sync filesystem before reboot */ + sync(); + reboot(magic); +#endif + + /* If reboot(2) returns, it is an error */ + csp_log_error("Failed to shutdown: %s", strerror(errno)); + + return CSP_ERR_INVAL; +} + +void csp_sys_set_color(csp_color_t color) { + + unsigned int color_code, modifier_code; + switch (color & COLOR_MASK_COLOR) { + case COLOR_BLACK: + color_code = 30; break; + case COLOR_RED: + color_code = 31; break; + case COLOR_GREEN: + color_code = 32; break; + case COLOR_YELLOW: + color_code = 33; break; + case COLOR_BLUE: + color_code = 34; break; + case COLOR_MAGENTA: + color_code = 35; break; + case COLOR_CYAN: + color_code = 36; break; + case COLOR_WHITE: + color_code = 37; break; + case COLOR_RESET: + default: + color_code = 0; break; + } + + switch (color & COLOR_MASK_MODIFIER) { + case COLOR_BOLD: + modifier_code = 1; break; + case COLOR_UNDERLINE: + modifier_code = 2; break; + case COLOR_BLINK: + modifier_code = 3; break; + case COLOR_HIDE: + modifier_code = 4; break; + case COLOR_NORMAL: + default: + modifier_code = 0; break; + } + + printf("\033[%u;%um", modifier_code, color_code); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_thread.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_thread.c new file mode 100644 index 00000000..3277d35d --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_thread.c @@ -0,0 +1,55 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +/* CSP includes */ +#include + +#include + +int csp_thread_create(csp_thread_return_t (* routine)(void *), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle) { + pthread_attr_t attributes, *attr_ref; + int return_code; + + if( pthread_attr_init(&attributes) == 0 ) + { + unsigned int stack_size = PTHREAD_STACK_MIN;// use at least one memory page + + while(stack_size < stack_depth)// must reach at least the provided size + { + stack_size += PTHREAD_STACK_MIN;// keep memory page boundary (some systems may fail otherwise)) + } + attr_ref = &attributes; + + pthread_attr_setdetachstate(attr_ref, PTHREAD_CREATE_DETACHED);// do not waste memory on each call + pthread_attr_setstacksize(attr_ref, stack_size); + } + else + { + attr_ref = NULL; + } + return_code = pthread_create(handle, attr_ref, routine, parameters); + if( attr_ref != NULL ) pthread_attr_destroy(attr_ref); + + return return_code; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_time.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_time.c new file mode 100644 index 00000000..c9677443 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_time.c @@ -0,0 +1,54 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +/* CSP includes */ +#include + +#include + +uint32_t csp_get_ms(void) { + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + return (uint32_t)(ts.tv_sec*1000+ts.tv_nsec/1000000); + else + return 0; +} + +uint32_t csp_get_ms_isr(void) { + return csp_get_ms(); +} + +uint32_t csp_get_s(void) { + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + return (uint32_t)ts.tv_sec; + else + return 0; +} + +uint32_t csp_get_s_isr(void) { + return csp_get_s(); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/pthread_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/pthread_queue.c new file mode 100644 index 00000000..e8b6d4ab --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/posix/pthread_queue.c @@ -0,0 +1,243 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Inspired by c-pthread-queue by Matthew Dickinson +http://code.google.com/p/c-pthread-queue/ +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* CSP includes */ +#include + +static inline int get_deadline(struct timespec *ts, uint32_t timeout_ms) +{ + int ret = clock_gettime(CLOCK_MONOTONIC, ts); + + if (ret < 0) { + return ret; + } + + uint32_t sec = timeout_ms / 1000; + uint32_t nsec = (timeout_ms - 1000 * sec) * 1000000; + + ts->tv_sec += sec; + + if (ts->tv_nsec + nsec >= 1000000000) { + ts->tv_sec++; + } + + ts->tv_nsec = (ts->tv_nsec + nsec) % 1000000000; + + return ret; +} + +static inline int init_cond_clock_monotonic(pthread_cond_t * cond) +{ + + int ret; + pthread_condattr_t attr; + + pthread_condattr_init(&attr); + ret = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + + if (ret == 0) { + ret = pthread_cond_init(cond, &attr); + } + + pthread_condattr_destroy(&attr); + return ret; + +} + +pthread_queue_t * pthread_queue_create(int length, size_t item_size) { + + pthread_queue_t * q = malloc(sizeof(pthread_queue_t)); + + if (q != NULL) { + q->buffer = malloc(length*item_size); + if (q->buffer != NULL) { + q->size = length; + q->item_size = item_size; + q->items = 0; + q->in = 0; + q->out = 0; + if (pthread_mutex_init(&(q->mutex), NULL) || init_cond_clock_monotonic(&(q->cond_full)) || init_cond_clock_monotonic(&(q->cond_empty))) { + free(q->buffer); + free(q); + q = NULL; + } + } else { + free(q); + q = NULL; + } + } + + return q; + +} + +void pthread_queue_delete(pthread_queue_t * q) { + + if (q == NULL) + return; + + free(q->buffer); + free(q); + + return; + +} + + +static inline int wait_slot_available(pthread_queue_t * queue, struct timespec *ts) { + + int ret; + + while (queue->items == queue->size) { + + if (ts != NULL) { + ret = pthread_cond_timedwait(&(queue->cond_full), &(queue->mutex), ts); + } else { + ret = pthread_cond_wait(&(queue->cond_full), &(queue->mutex)); + } + + if (ret != 0 && errno != EINTR) { + return PTHREAD_QUEUE_FULL; //Timeout + } + } + + return PTHREAD_QUEUE_OK; + +} + +int pthread_queue_enqueue(pthread_queue_t * queue, void * value, uint32_t timeout) { + + int ret; + struct timespec ts; + struct timespec *pts = NULL; + + /* Calculate timeout */ + if (timeout != CSP_MAX_DELAY) { + if (get_deadline(&ts, timeout) != 0) { + return PTHREAD_QUEUE_ERROR; + } + pts = &ts; + } else { + pts = NULL; + } + + /* Get queue lock */ + pthread_mutex_lock(&(queue->mutex)); + + ret = wait_slot_available(queue, pts); + if (ret == PTHREAD_QUEUE_OK) { + /* Copy object from input buffer */ + memcpy(queue->buffer+(queue->in * queue->item_size), value, queue->item_size); + queue->items++; + queue->in = (queue->in + 1) % queue->size; + } + + pthread_mutex_unlock(&(queue->mutex)); + + if (ret == PTHREAD_QUEUE_OK) { + /* Nofify blocked threads */ + pthread_cond_broadcast(&(queue->cond_empty)); + } + + return ret; + +} + +static inline int wait_item_available(pthread_queue_t * queue, struct timespec *ts) { + + int ret; + + while (queue->items == 0) { + + if (ts != NULL) { + ret = pthread_cond_timedwait(&(queue->cond_empty), &(queue->mutex), ts); + } else { + ret = pthread_cond_wait(&(queue->cond_empty), &(queue->mutex)); + } + + if (ret != 0 && errno != EINTR) { + return PTHREAD_QUEUE_EMPTY; //Timeout + } + } + + return PTHREAD_QUEUE_OK; + +} + +int pthread_queue_dequeue(pthread_queue_t * queue, void * buf, uint32_t timeout) { + + int ret; + struct timespec ts; + struct timespec *pts; + + /* Calculate timeout */ + if (timeout != CSP_MAX_DELAY) { + if (get_deadline(&ts, timeout) != 0) { + return PTHREAD_QUEUE_ERROR; + } + pts = &ts; + } else { + pts = NULL; + } + + /* Get queue lock */ + pthread_mutex_lock(&(queue->mutex)); + + ret = wait_item_available(queue, pts); + if (ret == PTHREAD_QUEUE_OK) { + /* Coby object to output buffer */ + memcpy(buf, queue->buffer+(queue->out * queue->item_size), queue->item_size); + queue->items--; + queue->out = (queue->out + 1) % queue->size; + } + + pthread_mutex_unlock(&(queue->mutex)); + + if (ret == PTHREAD_QUEUE_OK) { + /* Nofify blocked threads */ + pthread_cond_broadcast(&(queue->cond_full)); + } + + return ret; + +} + +int pthread_queue_items(pthread_queue_t * queue) { + + pthread_mutex_lock(&(queue->mutex)); + int items = queue->items; + pthread_mutex_unlock(&(queue->mutex)); + + return items; + +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/README b/gomspace/libgscsp/lib/libcsp/src/arch/windows/README new file mode 100644 index 00000000..b97ce7f5 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/README @@ -0,0 +1,18 @@ +This directory contains files specific to the windows port of libcsp. + +To compile and create a static library, execute: + + python waf configure --with-os=windows build + +from the root of this project. Note python must be in PATH. + +The build requirements are: + * Windows Vista SP1 + * A recent version of MinGW _or_ MinGW-w64 + * Windows API headers + * cPython 2.5 or newer + +What provides the Windows API headers depends on the development environment: +Using MinGW: Headers provided by w32api package. windows_glue.h header is needed because these headers do not declare condition variables. +Using MinGW-w64: Headers should be available in the default configuration. You may have to compile the distribution from source. windows_glue.h should not be needed. + diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_malloc.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_malloc.c new file mode 100644 index 00000000..4b301e49 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_malloc.c @@ -0,0 +1,9 @@ +#include + +void * csp_malloc(size_t size) { + return malloc(size); +} + +void csp_free(void * ptr) { + free(ptr); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_queue.c new file mode 100644 index 00000000..177f8fa9 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_queue.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include "windows_queue.h" + +csp_queue_handle_t csp_queue_create(int length, size_t item_size) { + return windows_queue_create(length, item_size); +} + +void csp_queue_remove(csp_queue_handle_t queue) { + windows_queue_delete(queue); +} + +int csp_queue_enqueue(csp_queue_handle_t handle, void *value, uint32_t timeout) { + return windows_queue_enqueue(handle, value, timeout); +} + +int csp_queue_enqueue_isr(csp_queue_handle_t handle, void * value, CSP_BASE_TYPE * task_woken) { + if( task_woken != NULL ) + *task_woken = 0; + return windows_queue_enqueue(handle, value, 0); +} + +int csp_queue_dequeue(csp_queue_handle_t handle, void *buf, uint32_t timeout) { + return windows_queue_dequeue(handle, buf, timeout); +} + +int csp_queue_dequeue_isr(csp_queue_handle_t handle, void * buf, CSP_BASE_TYPE * task_woken) { + if( task_woken != NULL ) + *task_woken = 0; + return windows_queue_dequeue(handle, buf, 0); +} + +int csp_queue_size(csp_queue_handle_t handle) { + return windows_queue_items(handle); +} + +int csp_queue_size_isr(csp_queue_handle_t handle) { + return windows_queue_items(handle); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_semaphore.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_semaphore.c new file mode 100644 index 00000000..aa69251e --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_semaphore.c @@ -0,0 +1,74 @@ +#include +#include +#include + +int csp_mutex_create(csp_mutex_t * mutex) { + HANDLE mutexHandle = CreateMutex(NULL, FALSE, FALSE); + if( mutexHandle == NULL ) { + return CSP_MUTEX_ERROR; + } + *mutex = mutexHandle; + return CSP_MUTEX_OK; +} + +int csp_mutex_remove(csp_mutex_t * mutex) { + if( !CloseHandle(*mutex) ) { + return CSP_MUTEX_ERROR; + } + return CSP_MUTEX_OK; +} + +int csp_mutex_lock(csp_mutex_t * mutex, uint32_t timeout) { + if(WaitForSingleObject(*mutex, timeout) == WAIT_OBJECT_0) { + return CSP_MUTEX_OK; + } + return CSP_MUTEX_ERROR; + +} + +int csp_mutex_unlock(csp_mutex_t * mutex) { + if( !ReleaseMutex(*mutex) ) { + return CSP_MUTEX_ERROR; + } + return CSP_MUTEX_OK; +} + +int csp_bin_sem_create(csp_bin_sem_handle_t * sem) { + HANDLE semHandle = CreateSemaphore(NULL, 1, 1, NULL); + if( semHandle == NULL ) { + return CSP_SEMAPHORE_ERROR; + } + *sem = semHandle; + return CSP_SEMAPHORE_OK; +} + +int csp_bin_sem_remove(csp_bin_sem_handle_t * sem) { + if( !CloseHandle(*sem) ) { + return CSP_SEMAPHORE_ERROR; + } + return CSP_SEMAPHORE_OK; +} + +int csp_bin_sem_wait(csp_bin_sem_handle_t * sem, uint32_t timeout) { + if( WaitForSingleObject(*sem, timeout) == WAIT_OBJECT_0 ) { + return CSP_SEMAPHORE_OK; + } + return CSP_SEMAPHORE_ERROR; + +} + +int csp_bin_sem_post(csp_bin_sem_handle_t * sem) { + if( !ReleaseSemaphore(*sem, 1, NULL) ) { + return CSP_SEMAPHORE_ERROR; + } + return CSP_SEMAPHORE_OK; +} + +int csp_bin_sem_post_isr(csp_bin_sem_handle_t * sem, CSP_BASE_TYPE * task_woken) { + if( task_woken != NULL ) { + *task_woken = 0; + } + return csp_bin_sem_post(sem); +} + + diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_system.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_system.c new file mode 100644 index 00000000..262c2052 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_system.c @@ -0,0 +1,60 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +#include +#include + +#include + +int csp_sys_tasklist(char * out) { + strcpy(out, "Tasklist not available on Windows"); + return CSP_ERR_NONE; +} + +uint32_t csp_sys_memfree(void) { + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + GlobalMemoryStatusEx(&statex); + DWORDLONG freePhysicalMem = statex.ullAvailPhys; + size_t total = (size_t) freePhysicalMem; + return (uint32_t)total; +} + +int csp_sys_reboot(void) { + /* TODO: Fix reboot on Windows */ + csp_log_error("Failed to reboot"); + + return CSP_ERR_INVAL; +} + +int csp_sys_shutdown(void) { + /* TODO: Fix shutdown on Windows */ + csp_log_error("Failed to shutdown"); + + return CSP_ERR_INVAL; +} + +void csp_sys_set_color(csp_color_t color) { + /* TODO: Add Windows color output here */ +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_thread.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_thread.c new file mode 100644 index 00000000..ef46a948 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_thread.c @@ -0,0 +1,11 @@ +#include +#include +#include + +int csp_thread_create(csp_thread_return_t (* routine)(void *)__attribute__((stdcall)), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle) { + HANDLE taskHandle = (HANDLE) _beginthreadex(NULL, stack_depth, routine, parameters, 0, 0); + if( taskHandle == 0 ) + return CSP_ERR_NOMEM; // Failure + *handle = taskHandle; + return CSP_ERR_NONE; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_time.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_time.c new file mode 100644 index 00000000..618292ab --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_time.c @@ -0,0 +1,20 @@ +#include +#include +#include + +uint32_t csp_get_ms(void) { + return (uint32_t)GetTickCount(); +} + +uint32_t csp_get_ms_isr(void) { + return csp_get_ms(); +} + +uint32_t csp_get_s(void) { + uint32_t time_ms = csp_get_ms(); + return time_ms/1000; +} + +uint32_t csp_get_s_isr(void) { + return csp_get_s(); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_glue.h b/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_glue.h new file mode 100644 index 00000000..6e0cf6db --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_glue.h @@ -0,0 +1,23 @@ +#ifndef WINDOWS_GLUE_H +#define WINDOWS_GLUE_H + +#include +#undef interface + +#if (_WIN32_WINNT >= 0x0600) + +#define RTL_CONDITION_VARIABLE_INIT 0 +#define RTL_CONDITION_VARIABLE_LOCKMODE_SHARED 1 +#define CONDITION_VARIABLE_INIT RTL_CONDITION_VARIABLE_INIT +#define CONDITION_VARIABLE_LOCKMODE_SHARED RTL_CONDITION_VARIABLE_LOCKMODE_SHARED + +typedef PVOID RTL_CONDITION_VARIABLE; +typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE; + +WINBASEAPI VOID WINAPI InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable); +WINBASEAPI WINBOOL WINAPI SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable, PCRITICAL_SECTION CriticalSection, DWORD dwMilliseconds); +WINBASEAPI VOID WINAPI WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable); +WINBASEAPI VOID WINAPI WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable); + +#endif // _WIN#"_WINNT +#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.c new file mode 100644 index 00000000..aa337dc8 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.c @@ -0,0 +1,91 @@ +#include "windows_queue.h" +#include "windows_glue.h" +#include + +static int queueFull(windows_queue_t * queue) { + return queue->items == queue->size; +} + +static int queueEmpty(windows_queue_t * queue) { + return queue->items == 0; +} + +windows_queue_t * windows_queue_create(int length, size_t item_size) { + windows_queue_t *queue = (windows_queue_t*)malloc(sizeof(windows_queue_t)); + if(queue == NULL) + goto queue_malloc_failed; + + queue->buffer = malloc(length*item_size); + if(queue->buffer == NULL) + goto buffer_malloc_failed; + + queue->size = length; + queue->item_size = item_size; + queue->items = 0; + queue->head_idx = 0; + + InitializeCriticalSection(&(queue->mutex)); + InitializeConditionVariable(&(queue->cond_full)); + InitializeConditionVariable(&(queue->cond_empty)); + goto queue_init_success; + +buffer_malloc_failed: + free(queue); + queue = NULL; +queue_malloc_failed: +queue_init_success: + return queue; +} + +void windows_queue_delete(windows_queue_t * q) { + if(q==NULL) return; + DeleteCriticalSection(&(q->mutex)); + free(q->buffer); + free(q); +} + +int windows_queue_enqueue(windows_queue_t * queue, void * value, int timeout) { + int offset; + EnterCriticalSection(&(queue->mutex)); + while(queueFull(queue)) { + int ret = SleepConditionVariableCS(&(queue->cond_full), &(queue->mutex), timeout); + if( !ret ) { + LeaveCriticalSection(&(queue->mutex)); + return ret == WAIT_TIMEOUT ? WINDOWS_QUEUE_FULL : WINDOWS_QUEUE_ERROR; + } + } + offset = ((queue->head_idx+queue->items) % queue->size) * queue->item_size; + memcpy((unsigned char*)queue->buffer + offset, value, queue->item_size); + queue->items++; + + LeaveCriticalSection(&(queue->mutex)); + WakeAllConditionVariable(&(queue->cond_empty)); + return WINDOWS_QUEUE_OK; +} + +int windows_queue_dequeue(windows_queue_t * queue, void * buf, int timeout) { + EnterCriticalSection(&(queue->mutex)); + while(queueEmpty(queue)) { + int ret = SleepConditionVariableCS(&(queue->cond_empty), &(queue->mutex), timeout); + if( !ret ) { + LeaveCriticalSection(&(queue->mutex)); + return ret == WAIT_TIMEOUT ? WINDOWS_QUEUE_EMPTY : WINDOWS_QUEUE_ERROR; + } + } + memcpy(buf, (unsigned char*)queue->buffer+(queue->head_idx%queue->size*queue->item_size), queue->item_size); + queue->items--; + queue->head_idx = (queue->head_idx + 1) % queue->size; + + LeaveCriticalSection(&(queue->mutex)); + WakeAllConditionVariable(&(queue->cond_full)); + return WINDOWS_QUEUE_OK; +} + +int windows_queue_items(windows_queue_t * queue) { + int items; + EnterCriticalSection(&(queue->mutex)); + items = queue->items; + LeaveCriticalSection(&(queue->mutex)); + + return items; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.h b/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.h new file mode 100644 index 00000000..e6bc5423 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.h @@ -0,0 +1,41 @@ +#ifndef _WINDOWS_QUEUE_H_ +#define _WINDOWS_QUEUE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "windows_glue.h" +#undef interface + +#include + +#define WINDOWS_QUEUE_ERROR CSP_QUEUE_ERROR +#define WINDOWS_QUEUE_EMPTY CSP_QUEUE_ERROR +#define WINDOWS_QUEUE_FULL CSP_QUEUE_ERROR +#define WINDOWS_QUEUE_OK CSP_QUEUE_OK + +typedef struct windows_queue_s { + void * buffer; + int size; + int item_size; + int items; + int head_idx; + CRITICAL_SECTION mutex; + CONDITION_VARIABLE cond_full; + CONDITION_VARIABLE cond_empty; +} windows_queue_t; + +windows_queue_t * windows_queue_create(int length, size_t item_size); +void windows_queue_delete(windows_queue_t * q); +int windows_queue_enqueue(windows_queue_t * queue, void * value, int timeout); +int windows_queue_dequeue(windows_queue_t * queue, void * buf, int timeout); +int windows_queue_items(windows_queue_t * queue); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _WINDOWS_QUEUE_H_ + diff --git a/gomspace/libgscsp/lib/libcsp/src/bindings/python/pycsp.c b/gomspace/libgscsp/lib/libcsp/src/bindings/python/pycsp.c new file mode 100644 index 00000000..f1009d1a --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/bindings/python/pycsp.c @@ -0,0 +1,1052 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if PY_MAJOR_VERSION == 3 +#define IS_PY3 +#endif + +static int is_capsule_of_type(PyObject* capsule, const char* expected_type) { + const char* capsule_name = PyCapsule_GetName(capsule); + if (strcmp(capsule_name, expected_type) != 0) { + PyErr_Format( + PyExc_TypeError, + "capsule contains unexpected type, expected=%s, got=%s", + expected_type, capsule_name); // TypeError is thrown + return 0; + } + return 1; +} + +/** + * csp/csp.h + */ + +/* + * void csp_service_handler(csp_conn_t *conn, csp_packet_t *packet); + */ +static PyObject* pycsp_service_handler(PyObject *self, PyObject *args) { + PyObject* conn_capsule; + PyObject* packet_capsule; + if (!PyArg_ParseTuple(args, "OO", &conn_capsule, &packet_capsule)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(conn_capsule, "csp_conn_t") || + !is_capsule_of_type(packet_capsule, "csp_packet_t")) { + return NULL; // TypeError is thrown + } + + csp_service_handler( + (csp_conn_t*)PyCapsule_GetPointer(conn_capsule, "csp_conn_t"), + (csp_packet_t*)PyCapsule_GetPointer(packet_capsule, "csp_packet_t")); + + Py_RETURN_NONE; +} + +/* + * int csp_init(uint8_t my_node_address); + */ +static PyObject* pycsp_init(PyObject *self, PyObject *args) { + uint8_t my_node_address; + if (!PyArg_ParseTuple(args, "b", &my_node_address)) { + return NULL; // TypeError is thrown + } + + return Py_BuildValue("i", csp_init(my_node_address)); +} + +/* + * void csp_set_hostname(const char *hostname); + */ +static PyObject* pycsp_set_hostname(PyObject *self, PyObject *args) { + char* hostname; + if (!PyArg_ParseTuple(args, "s", &hostname)) { + return NULL; // TypeError is thrown + } + + csp_set_hostname(hostname); + Py_RETURN_NONE; +} + +/* + * const char *csp_get_hostname(void); + */ +static PyObject* pycsp_get_hostname(PyObject *self, PyObject *args) { + return Py_BuildValue("s", csp_get_hostname()); +} + +/* + * void csp_set_model(const char *model); + */ +static PyObject* pycsp_set_model(PyObject *self, PyObject *args) { + char* model; + if (!PyArg_ParseTuple(args, "s", &model)) { + return NULL; // TypeError is thrown + } + + csp_set_model(model); + Py_RETURN_NONE; +} + +/* + * const char *csp_get_model(void); + */ +static PyObject* pycsp_get_model(PyObject *self, PyObject *args) { + return Py_BuildValue("s", csp_get_model()); +} + +/* + * void csp_set_revision(const char *revision); + */ +static PyObject* pycsp_set_revision(PyObject *self, PyObject *args) { + char* revision; + if (!PyArg_ParseTuple(args, "s", &revision)) { + return NULL; // TypeError is thrown + } + + csp_set_revision(revision); + Py_RETURN_NONE; +} + +/* + * const char *csp_get_revision(void); + */ +static PyObject* pycsp_get_revision(PyObject *self, PyObject *args) { + return Py_BuildValue("s", csp_get_revision()); +} + +/* + * csp_socket_t *csp_socket(uint32_t opts); + */ +static PyObject* pycsp_socket(PyObject *self, PyObject *args) { + uint32_t opts = CSP_SO_NONE; + if (!PyArg_ParseTuple(args, "|I", &opts)) { + return NULL; // TypeError is thrown + } + + return PyCapsule_New(csp_socket(opts), "csp_socket_t", NULL); +} + +/* + * csp_conn_t *csp_accept(csp_socket_t *socket, uint32_t timeout); + */ +static PyObject* pycsp_accept(PyObject *self, PyObject *args) { + PyObject* socket_capsule; + uint32_t timeout = 500; + if (!PyArg_ParseTuple(args, "O|I", &socket_capsule, &timeout)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(socket_capsule, "csp_socket_t")) { + return NULL; // TypeError is thrown + } + + void* socket = PyCapsule_GetPointer(socket_capsule, "csp_socket_t"); + csp_conn_t* conn = csp_accept((csp_socket_t*)socket, timeout); + if (conn == NULL) { + Py_RETURN_NONE; // because a capsule cannot contain a NULL-pointer + } + + return PyCapsule_New(conn, "csp_conn_t", NULL); +} + +/* + * csp_packet_t *csp_read(csp_conn_t *conn, uint32_t timeout); + */ +static PyObject* pycsp_read(PyObject *self, PyObject *args) { + PyObject* conn_capsule; + uint32_t timeout = 500; + if (!PyArg_ParseTuple(args, "O|I", &conn_capsule, &timeout)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { + return NULL; // TypeError is thrown + } + + void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); + csp_packet_t* packet = csp_read((csp_conn_t*)conn, timeout); + if (packet == NULL) { + Py_RETURN_NONE; // because capsule cannot contain a NULL-pointer + } + + return PyCapsule_New(packet, "csp_packet_t", NULL); +} + +/* +* int csp_send(csp_conn_t * conn, csp_packet_t * packet, uint32_t timeout) +*/ +static PyObject* pycsp_send(PyObject *self, PyObject *args) { + PyObject* conn_capsule; + PyObject* packet_capsule; + uint32_t timeout = 500; + if (!PyArg_ParseTuple(args, "OO|I", &conn_capsule, &packet_capsule, &timeout)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { + return NULL; // TypeError is thrown + } + + void* packet = PyCapsule_GetPointer(packet_capsule, "csp_packet_t"); + if (packet == NULL) { + Py_RETURN_NONE; + } + + void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); + + int result = csp_send(conn, packet, timeout); + + return Py_BuildValue("i", result); +} + +/* + * int csp_transaction(uint8_t prio, uint8_t dest, uint8_t port, + * uint32_t timeout, void *outbuf, int outlen, + * void *inbuf, int inlen); + */ +static PyObject* pycsp_transaction(PyObject *self, PyObject *args) { + uint8_t prio; + uint8_t dest; + uint8_t port; + uint32_t timeout; + Py_buffer inbuf; + Py_buffer outbuf; + if (!PyArg_ParseTuple(args, "bbbIw*w*", &prio, &dest, &port, &timeout, &outbuf, &inbuf)) { + return NULL; // TypeError is thrown + } + + int result = csp_transaction(prio, dest, port, timeout, + outbuf.buf, outbuf.len, + inbuf.buf, inbuf.len); + + return Py_BuildValue("i", result); +} + +/* int csp_sendto(uint8_t prio, uint8_t dest, uint8_t dport, uint8_t src_port, uint32_t opts, csp_packet_t *packet, uint32_t timeout); */ +static PyObject* pycsp_sendto(PyObject *self, PyObject *args) { + uint8_t prio; + uint8_t dest; + uint8_t dport; + uint8_t src_port; + uint32_t opts; + PyObject* packet_capsule; + uint32_t timeout; + if (!PyArg_ParseTuple(args, "bbbbIOI", &prio, &dest, &dport, &src_port, &opts, &packet_capsule, &timeout)) { + Py_RETURN_NONE; + } + + void* packet = PyCapsule_GetPointer(packet_capsule, "csp_packet_t"); + if (packet == NULL) { + Py_RETURN_NONE; + } + + return Py_BuildValue("i", csp_sendto(prio, + dest, + dport, + src_port, + opts, + (csp_packet_t*)packet, + timeout)); +} + + +/* + * int csp_sendto_reply(csp_packet_t * request_packet, + * csp_packet_t * reply_packet, + * uint32_t opts, uint32_t timeout); + */ +static PyObject* pycsp_sendto_reply(PyObject *self, PyObject *args) { + PyObject* request_packet_capsule; + PyObject* reply_packet_capsule; + uint32_t opts = CSP_O_NONE; + uint32_t timeout = 500; + if (!PyArg_ParseTuple(args, "OO|II", &request_packet_capsule, &reply_packet_capsule, &opts, &timeout)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(request_packet_capsule, "csp_packet_t") || + !is_capsule_of_type(reply_packet_capsule, "csp_packet_t")) { + return NULL; // TypeError is thrown + } + + void* request_packet = PyCapsule_GetPointer(request_packet_capsule, "csp_packet_t"); + void* reply_packet = PyCapsule_GetPointer(reply_packet_capsule, "csp_packet_t"); + + return Py_BuildValue("i", csp_sendto_reply((csp_packet_t*)request_packet, + (csp_packet_t*)reply_packet, + opts, + timeout)); +} + +/* + * csp_conn_t *csp_connect(uint8_t prio, uint8_t dest, uint8_t dport, uint32_t timeout, uint32_t opts); + */ +static PyObject* pycsp_connect(PyObject *self, PyObject *args) { + uint8_t prio; + uint8_t dest; + uint8_t dport; + uint32_t timeout; + uint32_t opts; + if (!PyArg_ParseTuple(args, "bbbII", &prio, &dest, &dport, &timeout, &opts)) { + return NULL; // TypeError is thrown + } + + csp_conn_t *conn = csp_connect(prio, dest, dport, timeout,opts); + + return PyCapsule_New(conn, "csp_conn_t", NULL); +} + +/* + * int csp_close(csp_conn_t *conn); + */ +static PyObject* pycsp_close(PyObject *self, PyObject *conn_capsule) { + if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { + return NULL; // TypeError is thrown + } + + void *conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); + return Py_BuildValue("i", csp_close((csp_conn_t*)conn)); +} + +/* + * int csp_conn_dport(csp_conn_t *conn); + */ +static PyObject* pycsp_conn_dport(PyObject *self, PyObject *conn_capsule) { + if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { + return NULL; // TypeError is thrown + } + + void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); + return Py_BuildValue("i", csp_conn_dport((csp_conn_t*)conn)); +} + +/* + * int csp_conn_sport(csp_conn_t *conn); + */ +static PyObject* pycsp_conn_sport(PyObject *self, PyObject *conn_capsule) { + if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { + return NULL; // TypeError is thrown + } + + void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); + return Py_BuildValue("i", csp_conn_sport((csp_conn_t*)conn)); +} + +/* int csp_conn_dst(csp_conn_t *conn); */ +static PyObject* pycsp_conn_dst(PyObject *self, PyObject *conn_capsule) { + if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { + return NULL; // TypeError is thrown + } + + void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); + return Py_BuildValue("i", csp_conn_dst((csp_conn_t*)conn)); +} + +/* + * int csp_conn_src(csp_conn_t *conn); + */ +static PyObject* pycsp_conn_src(PyObject *self, PyObject *conn_capsule) { + if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { + return NULL; // TypeError is thrown + } + + void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); + return Py_BuildValue("i", csp_conn_src((csp_conn_t*)conn)); +} + +/* int csp_listen(csp_socket_t *socket, size_t conn_queue_length); */ +static PyObject* pycsp_listen(PyObject *self, PyObject *args) { + PyObject* socket_capsule; + size_t conn_queue_len = 10; + if (!PyArg_ParseTuple(args, "O|n", &socket_capsule, &conn_queue_len)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(socket_capsule, "csp_socket_t")) { + return NULL; // TypeError is thrown + } + + void* sock = PyCapsule_GetPointer(socket_capsule, "csp_socket_t"); + return Py_BuildValue("i", csp_listen((csp_socket_t*)sock, conn_queue_len)); +} + +/* int csp_bind(csp_socket_t *socket, uint8_t port); */ +static PyObject* pycsp_bind(PyObject *self, PyObject *args) { + PyObject* socket_capsule; + uint8_t port; + if (!PyArg_ParseTuple(args, "Ob", &socket_capsule, &port)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(socket_capsule, "csp_socket_t")) { + return NULL; // TypeError is thrown + } + + void* sock = PyCapsule_GetPointer(socket_capsule, "csp_socket_t"); + return Py_BuildValue("i", csp_bind((csp_socket_t*)sock, port)); +} + +/* int csp_route_start_task(unsigned int task_stack_size, unsigned int priority); */ +static PyObject* pycsp_route_start_task(PyObject *self, PyObject *args) { + unsigned int priority = CSP_PRIO_NORM; + if (!PyArg_ParseTuple(args, "|I", &priority)) { + return NULL; // TypeError is thrown + } + + return Py_BuildValue("i", csp_route_start_task(0, priority)); +} + +/* + * int csp_ping(uint8_t node, uint32_t timeout, + * unsigned int size, uint8_t conn_options); + */ +static PyObject* pycsp_ping(PyObject *self, PyObject *args) { + uint8_t node; + uint32_t timeout = 500; + unsigned int size = 100; + uint8_t conn_options = CSP_O_NONE; + if (!PyArg_ParseTuple(args, "b|IIb", &node, &timeout, &size, &conn_options)) { + return NULL; // TypeError is thrown + } + + return Py_BuildValue("i", csp_ping(node, timeout, size, conn_options)); +} + +/* + * void csp_reboot(uint8_t node); + */ +static PyObject* pycsp_reboot(PyObject *self, PyObject *args) { + uint8_t node; + if (!PyArg_ParseTuple(args, "b", &node)) { + return NULL; // TypeError is thrown + } + + csp_reboot(node); + Py_RETURN_NONE; +} + +/* + * void csp_shutdown(uint8_t node); + */ +static PyObject* pycsp_shutdown(PyObject *self, PyObject *args) { + uint8_t node; + if (!PyArg_ParseTuple(args, "b", &node)) { + return NULL; // TypeError is thrown + } + + csp_shutdown(node); + Py_RETURN_NONE; +} + +/* + * void csp_rdp_set_opt(unsigned int window_size, + * unsigned int conn_timeout_ms, + * unsigned int packet_timeout_ms, + * unsigned int delayed_acks, + * unsigned int ack_timeout, + * unsigned int ack_delay_count); + */ +static PyObject* pycsp_rdp_set_opt(PyObject *self, PyObject *args) { + unsigned int window_size; + unsigned int conn_timeout_ms; + unsigned int packet_timeout_ms; + unsigned int delayed_acks; + unsigned int ack_timeout; + unsigned int ack_delay_count; + if (!PyArg_ParseTuple(args, "IIIIII", &window_size, &conn_timeout_ms, + &packet_timeout_ms, &delayed_acks, + &ack_timeout, &ack_delay_count)) { + return NULL; // TypeError is thrown + } +#ifdef CSP_USE_RDP + csp_rdp_set_opt(window_size, conn_timeout_ms, packet_timeout_ms, + delayed_acks, ack_timeout, ack_delay_count); +#endif + Py_RETURN_NONE; +} + +/* + * void csp_rdp_get_opt(unsigned int *window_size, + * unsigned int *conn_timeout_ms, + * unsigned int *packet_timeout_ms, + * unsigned int *delayed_acks, + * unsigned int *ack_timeout, + * unsigned int *ack_delay_count); + */ +static PyObject* pycsp_rdp_get_opt(PyObject *self, PyObject *args) { + + unsigned int window_size = 0; + unsigned int conn_timeout_ms = 0; + unsigned int packet_timeout_ms = 0; + unsigned int delayed_acks = 0; + unsigned int ack_timeout = 0; + unsigned int ack_delay_count = 0; +#ifdef CSP_USE_RDP + csp_rdp_get_opt(&window_size, + &conn_timeout_ms, + &packet_timeout_ms, + &delayed_acks, + &ack_timeout, + &ack_delay_count); +#endif + return Py_BuildValue("IIIIII", + window_size, + conn_timeout_ms, + packet_timeout_ms, + delayed_acks, + ack_timeout, + ack_delay_count); +} + + +/* + * + * int csp_xtea_set_key(char *key, uint32_t keylen); + */ +static PyObject* pycsp_xtea_set_key(PyObject *self, PyObject *args) { + char* key; + uint32_t keylen; + if (!PyArg_ParseTuple(args, "si", &key, &keylen)) { + return NULL; // TypeError is thrown + } + return Py_BuildValue("i", csp_xtea_set_key(key, keylen)); +} +/** + * csp/csp_rtable.h + */ + +/* + * int csp_rtable_set(uint8_t node, uint8_t mask, + * csp_iface_t *ifc, uint8_t mac); + */ +static PyObject* pycsp_rtable_set(PyObject *self, PyObject *args) { + uint8_t node; + uint8_t mask; + char* interface_name; + uint8_t mac = CSP_NODE_MAC; + if (!PyArg_ParseTuple(args, "bbs|b", &node, &mask, &interface_name, &mac)) { + return NULL; // TypeError is thrown + } + + return Py_BuildValue("i", csp_rtable_set(node, + mask, + csp_iflist_get_by_name(interface_name), + mac)); +} + +/* + * void csp_rtable_clear(void); + */ +static PyObject* pycsp_rtable_clear(PyObject *self, PyObject *args) { + csp_rtable_clear(); + Py_RETURN_NONE; +} + +/* +* int csp_rtable_check(const char * buffer) +*/ +static PyObject* pycsp_rtable_check(PyObject *self, PyObject *args) { + char* buffer; + if (!PyArg_ParseTuple(args, "s", &buffer)) { + return NULL; // TypeError is thrown + } + + return Py_BuildValue("i", csp_rtable_check(buffer)); +} + +/* +* void csp_rtable_load(const char * buffer) +*/ +static PyObject* pycsp_rtable_load(PyObject *self, PyObject *args) { + char* buffer; + if (!PyArg_ParseTuple(args, "s", &buffer)) { + return NULL; // TypeError is thrown + } + + csp_rtable_load(buffer); + Py_RETURN_NONE; +} + +/** + * csp/csp_buffer.h + */ + +/* + * int csp_buffer_init(int count, int size); + */ +static PyObject* pycsp_buffer_init(PyObject *self, PyObject *args) { + int count; + int size; + if (!PyArg_ParseTuple(args, "ii", &count, &size)) { + return NULL; // TypeError is thrown + } + + return Py_BuildValue("i", csp_buffer_init(count, size)); +} + +/* + * void * csp_buffer_get(size_t size); + */ +static PyObject* pycsp_buffer_get(PyObject *self, PyObject *args) { + size_t size; + if (!PyArg_ParseTuple(args, "n", &size)) { + return NULL; // TypeError is thrown + } + + void* packet = csp_buffer_get(size); + if (packet == NULL) { + Py_RETURN_NONE; + } + + return PyCapsule_New(packet, "csp_packet_t", NULL); +} +/* + * void csp_buffer_free(void *packet); + */ +static PyObject* pycsp_buffer_free(PyObject *self, PyObject *args) { + PyObject* packet_capsule; + if (!PyArg_ParseTuple(args, "O", &packet_capsule)) { + return NULL; // TypeError is thrown + } + + + if (!is_capsule_of_type(packet_capsule, "csp_packet_t")) { + return NULL; // TypeError is thrown + } + + csp_buffer_free(PyCapsule_GetPointer(packet_capsule, "csp_packet_t")); + Py_RETURN_NONE; +} + +/* + * int csp_buffer_remaining(void); + */ +static PyObject* pycsp_buffer_remaining(PyObject *self, PyObject *args) { + return Py_BuildValue("i", csp_buffer_remaining()); +} + +/** + * csp/csp_cmp.h + */ + +/* + * static inline int csp_cmp_ident(uint8_t node, uint32_t timeout, + * struct csp_cmp_message *msg) + */ +static PyObject* pycsp_cmp_ident(PyObject *self, PyObject *args) { + uint8_t node; + uint32_t timeout = 500; + if (!PyArg_ParseTuple(args, "b|i", &node, &timeout)) { + return NULL; // TypeError is thrown + } + + struct csp_cmp_message msg; + int rc = csp_cmp_ident(node, timeout, &msg); + return Py_BuildValue("isssss", + rc, + msg.ident.hostname, + msg.ident.model, + msg.ident.revision, + msg.ident.date, + msg.ident.time); +} + +/* + * static inline int csp_cmp_route_set(uint8_t node, uint32_t timeout, + * struct csp_cmp_message *msg) + */ +static PyObject* pycsp_cmp_route_set(PyObject *self, PyObject *args) { + uint8_t node; + uint32_t timeout = 500; + uint8_t addr; + uint8_t mac; + char* ifstr; + if (!PyArg_ParseTuple(args, "bibbs", &node, &timeout, &addr, &mac, &ifstr)) { + return NULL; // TypeError is thrown + } + + struct csp_cmp_message msg; + msg.route_set.dest_node = addr; + msg.route_set.next_hop_mac = mac; + strncpy(msg.route_set.interface, ifstr, CSP_CMP_ROUTE_IFACE_LEN); + int rc = csp_cmp_route_set(node, timeout, &msg); + return Py_BuildValue("i", + rc); +} + +/* static inline int pycsp_cmp_peek(uint8_t node, uint32_t timeout, struct csp_cmp_message *msg); */ +static PyObject* pycsp_cmp_peek(PyObject *self, PyObject *args) { + uint8_t node; + uint32_t timeout; + uint8_t len; + uint32_t addr; + Py_buffer outbuf; + + if (!PyArg_ParseTuple(args, "biibw*", &node, &timeout, &addr, &len, &outbuf)) { + Py_RETURN_NONE; + } + + if (len > CSP_CMP_PEEK_MAX_LEN) { + len = CSP_CMP_PEEK_MAX_LEN; + } + struct csp_cmp_message msg; + msg.peek.addr = csp_hton32(addr); + msg.peek.len = len; + int rc = csp_cmp_peek(node, timeout, &msg); + if (rc != CSP_ERR_NONE) { + Py_RETURN_NONE; + } + memcpy(outbuf.buf, msg.peek.data, len); + outbuf.len = len; + + return Py_BuildValue("i", rc); +} + +/* static inline int pycsp_cmp_poke(uint8_t node, uint32_t timeout, struct csp_cmp_message *msg); */ +static PyObject* pycsp_cmp_poke(PyObject *self, PyObject *args) { + uint8_t node; + uint32_t timeout; + uint8_t len; + uint32_t addr; + Py_buffer inbuf; + + if (!PyArg_ParseTuple(args, "biibw*", &node, &timeout, &addr, &len, &inbuf)) { + Py_RETURN_NONE; + } + + if (len > CSP_CMP_POKE_MAX_LEN) { + len = CSP_CMP_POKE_MAX_LEN; + } + struct csp_cmp_message msg; + msg.poke.addr = csp_hton32(addr); + msg.poke.len = len; + memcpy(msg.poke.data, inbuf.buf, len); + int rc = csp_cmp_poke(node, timeout, &msg); + if (rc != CSP_ERR_NONE) { + Py_RETURN_NONE; + } + + return Py_BuildValue("i", rc); +} + +/* static inline int csp_cmp_clock(uint8_t node, uint32_t timeout, struct csp_cmp_message *msg); */ +static PyObject* pycsp_cmp_clock(PyObject *self, PyObject *args) { + uint8_t node; + uint32_t timeout; + uint32_t sec; + uint32_t nsec; + if (!PyArg_ParseTuple(args, "bIII", &node, &timeout, &sec, &nsec)) { + Py_RETURN_NONE; + } + + struct csp_cmp_message msg; + msg.clock.tv_sec = csp_hton32(sec); + msg.clock.tv_nsec = csp_hton32(nsec); + return Py_BuildValue("i", csp_cmp_clock(node, timeout, &msg)); +} + +/** + * csp/interfaces/csp_if_zmqhub.h + */ + +/* + * int csp_zmqhub_init(char addr, char * host); + */ +static PyObject* pycsp_zmqhub_init(PyObject *self, PyObject *args) { + char addr; + char* host; + if (!PyArg_ParseTuple(args, "bs", &addr, &host)) { + return NULL; // TypeError is thrown + } + + return Py_BuildValue("i", csp_zmqhub_init(addr, host)); +} + +/** + * csp/drivers/can_socketcan.h + */ + +/* + * csp_iface_t * csp_can_socketcan_init(const char * ifc, int bitrate, int promisc); + */ +static PyObject* pycsp_can_socketcan_init(PyObject *self, PyObject *args) +{ + char* ifc; + int bitrate = 1000000; + int promisc = 0; + + if (!PyArg_ParseTuple(args, "s|ii", &ifc, &bitrate, &promisc)) + { + return NULL; + } + + csp_can_socketcan_init(ifc, bitrate, promisc); + Py_RETURN_NONE; +} + + +/** + * csp/interfaces/csp_if_kiss.h + */ + +/* + * int csp_kiss_init(char addr, char * host); + */ +static PyObject* pycsp_kiss_init(PyObject *self, PyObject *args) { + char* device; + uint32_t baudrate = 500000; + uint32_t mtu = 512; + const char* if_name = "KISS"; + if (!PyArg_ParseTuple(args, "s|IIs", &device, &baudrate, &mtu, &if_name)) { + return NULL; // TypeError is thrown + } + + static csp_iface_t csp_if_kiss; + static csp_kiss_handle_t csp_kiss_driver; + csp_if_kiss.mtu = (uint16_t) mtu; + struct usart_conf conf = {.device = device, .baudrate = baudrate}; + csp_kiss_init(&csp_if_kiss, &csp_kiss_driver, usart_putc, usart_insert, if_name); + usart_init(&conf); + + void my_usart_rx(uint8_t * buf, int len, void * pxTaskWoken) { + csp_kiss_rx(&csp_if_kiss, buf, len, pxTaskWoken); + } + usart_set_callback(my_usart_rx); + + Py_RETURN_NONE; +} + +/** + * Helpers - accessing csp_packet_t members + */ +static PyObject* pycsp_packet_set_data(PyObject *self, PyObject *args) { + PyObject* packet_capsule; + Py_buffer data; + if (!PyArg_ParseTuple(args, "Ow*", &packet_capsule, &data)) { + return NULL; // TypeError is thrown + } + + if (!is_capsule_of_type(packet_capsule, "csp_packet_t")) { + return NULL; // TypeError is thrown + } + + csp_packet_t* packet = PyCapsule_GetPointer(packet_capsule, "csp_packet_t"); + + memcpy((char *)packet->data, data.buf, data.len); + packet->length = data.len; + + Py_RETURN_NONE; +} +static PyObject* pycsp_packet_get_data(PyObject *self, PyObject *packet_capsule) { + if (!is_capsule_of_type(packet_capsule, "csp_packet_t")) { + return NULL; // TypeError is thrown + } + + csp_packet_t* packet = PyCapsule_GetPointer(packet_capsule, "csp_packet_t"); +#ifdef IS_PY3 + return Py_BuildValue("y#", packet->data, packet->length); +#else + return Py_BuildValue("s#", packet->data, packet->length); +#endif +} + +static PyObject* pycsp_packet_get_length(PyObject *self, PyObject *packet_capsule) { + if (!is_capsule_of_type(packet_capsule, "csp_packet_t")) { + return NULL; // TypeError is thrown + } + + csp_packet_t* packet = PyCapsule_GetPointer(packet_capsule, "csp_packet_t"); + return Py_BuildValue("H", packet->length); +} + +static PyMethodDef methods[] = { + + /* csp/csp.h */ + {"service_handler", pycsp_service_handler, METH_VARARGS, ""}, + {"init", pycsp_init, METH_VARARGS, ""}, + {"set_hostname", pycsp_set_hostname, METH_VARARGS, ""}, + {"get_hostname", pycsp_get_hostname, METH_NOARGS, ""}, + {"set_model", pycsp_set_model, METH_VARARGS, ""}, + {"get_model", pycsp_get_model, METH_NOARGS, ""}, + {"set_revision", pycsp_set_revision, METH_VARARGS, ""}, + {"get_revision", pycsp_get_revision, METH_NOARGS, ""}, + {"socket", pycsp_socket, METH_VARARGS, ""}, + {"accept", pycsp_accept, METH_VARARGS, ""}, + {"read", pycsp_read, METH_VARARGS, ""}, + {"send", pycsp_send, METH_VARARGS, ""}, + {"transaction", pycsp_transaction, METH_VARARGS, ""}, + {"sendto_reply", pycsp_sendto_reply, METH_VARARGS, ""}, + {"sendto", pycsp_sendto, METH_VARARGS, ""}, + {"connect", pycsp_connect, METH_VARARGS, ""}, + {"close", pycsp_close, METH_O, ""}, + {"conn_dport", pycsp_conn_dport, METH_O, ""}, + {"conn_sport", pycsp_conn_sport, METH_O, ""}, + {"conn_dst", pycsp_conn_dst, METH_O, ""}, + {"conn_src", pycsp_conn_src, METH_O, ""}, + {"listen", pycsp_listen, METH_VARARGS, ""}, + {"bind", pycsp_bind, METH_VARARGS, ""}, + {"route_start_task", pycsp_route_start_task, METH_VARARGS, ""}, + {"ping", pycsp_ping, METH_VARARGS, ""}, + {"reboot", pycsp_reboot, METH_VARARGS, ""}, + {"shutdown", pycsp_shutdown, METH_VARARGS, ""}, + {"rdp_set_opt", pycsp_rdp_set_opt, METH_VARARGS, ""}, + {"rdp_get_opt", pycsp_rdp_get_opt, METH_NOARGS, ""}, + {"xtea_set_key", pycsp_xtea_set_key, METH_VARARGS, ""}, + + /* csp/csp_rtable.h */ + {"rtable_set", pycsp_rtable_set, METH_VARARGS, ""}, + {"rtable_clear", pycsp_rtable_clear, METH_NOARGS, ""}, + {"rtable_check", pycsp_rtable_check, METH_VARARGS, ""}, + {"rtable_load", pycsp_rtable_load, METH_VARARGS, ""}, + + /* csp/csp_buffer.h */ + {"buffer_init", pycsp_buffer_init, METH_VARARGS, ""}, + {"buffer_free", pycsp_buffer_free, METH_VARARGS, ""}, + {"buffer_get", pycsp_buffer_get, METH_VARARGS, ""}, + {"buffer_remaining", pycsp_buffer_remaining, METH_NOARGS, ""}, + + /* csp/csp_cmp.h */ + {"cmp_ident", pycsp_cmp_ident, METH_VARARGS, ""}, + {"cmp_route_set", pycsp_cmp_route_set, METH_VARARGS, ""}, + {"cmp_peek", pycsp_cmp_peek, METH_VARARGS, ""}, + {"cmp_poke", pycsp_cmp_poke, METH_VARARGS, ""}, + {"cmp_clock", pycsp_cmp_clock, METH_VARARGS, ""}, + + + /* csp/interfaces/csp_if_zmqhub.h */ + {"zmqhub_init", pycsp_zmqhub_init, METH_VARARGS, ""}, + {"kiss_init", pycsp_kiss_init, METH_VARARGS, ""}, + + /* csp/drivers/can_socketcan.h */ + {"can_socketcan_init", pycsp_can_socketcan_init, METH_VARARGS, ""}, + + /* helpers */ + {"packet_get_length", pycsp_packet_get_length, METH_O, ""}, + {"packet_get_data", pycsp_packet_get_data, METH_O, ""}, + {"packet_set_data", pycsp_packet_set_data, METH_VARARGS, ""}, + + /* sentinel */ + {NULL, NULL, 0, NULL} +}; + +#ifdef IS_PY3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "libcsp_py3", + NULL, + -1, + methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +#ifdef IS_PY3 +PyMODINIT_FUNC PyInit_libcsp_py3(void) { +#else + PyMODINIT_FUNC initlibcsp_py2(void) { +#endif + + PyObject* m; + +#ifdef IS_PY3 + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule("libcsp_py2", methods); +#endif + /** + * csp/csp_types.h + */ + + /* RESERVED PORTS */ + PyModule_AddIntConstant(m, "CSP_CMP", CSP_CMP); + PyModule_AddIntConstant(m, "CSP_PING", CSP_PING); + PyModule_AddIntConstant(m, "CSP_PS", CSP_PS); + PyModule_AddIntConstant(m, "CSP_MEMFREE", CSP_MEMFREE); + PyModule_AddIntConstant(m, "CSP_REBOOT", CSP_REBOOT); + PyModule_AddIntConstant(m, "CSP_BUF_FREE", CSP_BUF_FREE); + PyModule_AddIntConstant(m, "CSP_UPTIME", CSP_UPTIME); + PyModule_AddIntConstant(m, "CSP_ANY", CSP_MAX_BIND_PORT + 1); + PyModule_AddIntConstant(m, "CSP_PROMISC", CSP_MAX_BIND_PORT + 2); + + /* PRIORITIES */ + PyModule_AddIntConstant(m, "CSP_PRIO_CRITICAL", CSP_PRIO_CRITICAL); + PyModule_AddIntConstant(m, "CSP_PRIO_HIGH", CSP_PRIO_HIGH); + PyModule_AddIntConstant(m, "CSP_PRIO_NORM", CSP_PRIO_NORM); + PyModule_AddIntConstant(m, "CSP_PRIO_LOW", CSP_PRIO_LOW); + + /* FLAGS */ + PyModule_AddIntConstant(m, "CSP_FFRAG", CSP_FFRAG); + PyModule_AddIntConstant(m, "CSP_FHMAC", CSP_FHMAC); + PyModule_AddIntConstant(m, "CSP_FXTEA", CSP_FXTEA); + PyModule_AddIntConstant(m, "CSP_FRDP", CSP_FRDP); + PyModule_AddIntConstant(m, "CSP_FCRC32", CSP_FCRC32); + + /* SOCKET OPTIONS */ + PyModule_AddIntConstant(m, "CSP_SO_NONE", CSP_SO_NONE); + PyModule_AddIntConstant(m, "CSP_SO_RDPREQ", CSP_SO_RDPREQ); + PyModule_AddIntConstant(m, "CSP_SO_RDPPROHIB", CSP_SO_RDPPROHIB); + PyModule_AddIntConstant(m, "CSP_SO_HMACREQ", CSP_SO_HMACREQ); + PyModule_AddIntConstant(m, "CSP_SO_HMACPROHIB", CSP_SO_HMACPROHIB); + PyModule_AddIntConstant(m, "CSP_SO_XTEAREQ", CSP_SO_XTEAREQ); + PyModule_AddIntConstant(m, "CSP_SO_XTEAPROHIB", CSP_SO_XTEAPROHIB); + PyModule_AddIntConstant(m, "CSP_SO_CRC32REQ", CSP_SO_CRC32REQ); + PyModule_AddIntConstant(m, "CSP_SO_CRC32PROHIB", CSP_SO_CRC32PROHIB); + PyModule_AddIntConstant(m, "CSP_SO_CONN_LESS", CSP_SO_CONN_LESS); + + /* CONNECT OPTIONS */ + PyModule_AddIntConstant(m, "CSP_O_NONE", CSP_O_NONE); + PyModule_AddIntConstant(m, "CSP_O_RDP", CSP_O_RDP); + PyModule_AddIntConstant(m, "CSP_O_NORDP", CSP_O_NORDP); + PyModule_AddIntConstant(m, "CSP_O_HMAC", CSP_O_HMAC); + PyModule_AddIntConstant(m, "CSP_O_NOHMAC", CSP_O_NOHMAC); + PyModule_AddIntConstant(m, "CSP_O_XTEA", CSP_O_XTEA); + PyModule_AddIntConstant(m, "CSP_O_NOXTEA", CSP_O_NOXTEA); + PyModule_AddIntConstant(m, "CSP_O_CRC32", CSP_O_CRC32); + PyModule_AddIntConstant(m, "CSP_O_NOCRC32", CSP_O_NOCRC32); + + + /** + * csp/csp_error.h + */ + + PyModule_AddIntConstant(m, "CSP_ERR_NONE", CSP_ERR_NONE); + PyModule_AddIntConstant(m, "CSP_ERR_NOMEM", CSP_ERR_NOMEM); + PyModule_AddIntConstant(m, "CSP_ERR_INVAL", CSP_ERR_INVAL); + PyModule_AddIntConstant(m, "CSP_ERR_TIMEDOUT", CSP_ERR_TIMEDOUT); + PyModule_AddIntConstant(m, "CSP_ERR_USED", CSP_ERR_USED); + PyModule_AddIntConstant(m, "CSP_ERR_NOTSUP", CSP_ERR_NOTSUP); + PyModule_AddIntConstant(m, "CSP_ERR_BUSY", CSP_ERR_BUSY); + PyModule_AddIntConstant(m, "CSP_ERR_ALREADY", CSP_ERR_ALREADY); + PyModule_AddIntConstant(m, "CSP_ERR_RESET", CSP_ERR_RESET); + PyModule_AddIntConstant(m, "CSP_ERR_NOBUFS", CSP_ERR_NOBUFS); + PyModule_AddIntConstant(m, "CSP_ERR_TX", CSP_ERR_TX); + PyModule_AddIntConstant(m, "CSP_ERR_DRIVER", CSP_ERR_DRIVER); + PyModule_AddIntConstant(m, "CSP_ERR_AGAIN", CSP_ERR_AGAIN); + PyModule_AddIntConstant(m, "CSP_ERR_HMAC", CSP_ERR_HMAC); + PyModule_AddIntConstant(m, "CSP_ERR_XTEA", CSP_ERR_XTEA); + PyModule_AddIntConstant(m, "CSP_ERR_CRC32", CSP_ERR_CRC32); + + /** + * csp/rtable.h + */ + PyModule_AddIntConstant(m, "CSP_NODE_MAC", CSP_NODE_MAC); + +#ifdef IS_PY3 + return m; +#endif + } + diff --git a/gomspace/libgscsp/lib/libcsp/src/crypto/csp_hmac.c b/gomspace/libgscsp/lib/libcsp/src/crypto/csp_hmac.c new file mode 100644 index 00000000..ae7fbb00 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/crypto/csp_hmac.c @@ -0,0 +1,202 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* Hash-based Message Authentication Code - based on code from libtom.org */ + +#include +#include +#include + +/* CSP includes */ +#include + +#include +#include + +#ifdef CSP_USE_HMAC + +#define HMAC_KEY_LENGTH 16 + +/* HMAC key */ +static uint8_t csp_hmac_key[HMAC_KEY_LENGTH]; + +/* HMAC state structure */ +typedef struct { + csp_sha1_state md; + uint8_t key[SHA1_BLOCKSIZE]; +} hmac_state; + +static int csp_hmac_init(hmac_state * hmac, const uint8_t * key, uint32_t keylen) { + uint32_t i; + uint8_t buf[SHA1_BLOCKSIZE]; + + /* NULL pointer and key check */ + if (!hmac || !key || keylen < 1) + return CSP_ERR_INVAL; + + /* Make sure we have a large enough key */ + if(keylen > SHA1_BLOCKSIZE) { + csp_sha1_memory(key, keylen, hmac->key); + if(SHA1_DIGESTSIZE < SHA1_BLOCKSIZE) + memset((hmac->key) + SHA1_DIGESTSIZE, 0, (size_t)(SHA1_BLOCKSIZE - SHA1_DIGESTSIZE)); + } else { + memcpy(hmac->key, key, (size_t)keylen); + if(keylen < SHA1_BLOCKSIZE) + memset((hmac->key) + keylen, 0, (size_t)(SHA1_BLOCKSIZE - keylen)); + } + + /* Create the initial vector */ + for(i = 0; i < SHA1_BLOCKSIZE; i++) + buf[i] = hmac->key[i] ^ 0x36; + + /* Prepend to the hash data */ + csp_sha1_init(&hmac->md); + csp_sha1_process(&hmac->md, buf, SHA1_BLOCKSIZE); + + return CSP_ERR_NONE; +} + +static int csp_hmac_process(hmac_state * hmac, const uint8_t * in, uint32_t inlen) { + + /* NULL pointer check */ + if (!hmac || !in) + return CSP_ERR_INVAL; + + /* Process data */ + csp_sha1_process(&hmac->md, in, inlen); + + return CSP_ERR_NONE; +} + +static int csp_hmac_done(hmac_state * hmac, uint8_t * out) { + + uint32_t i; + uint8_t buf[SHA1_BLOCKSIZE]; + uint8_t isha[SHA1_DIGESTSIZE]; + + if (!hmac || !out) + return CSP_ERR_INVAL; + + /* Get the hash of the first HMAC vector plus the data */ + csp_sha1_done(&hmac->md, isha); + + /* Create the second HMAC vector vector */ + for(i = 0; i < SHA1_BLOCKSIZE; i++) + buf[i] = hmac->key[i] ^ 0x5C; + + /* Now calculate the outer hash */ + csp_sha1_init(&hmac->md); + csp_sha1_process(&hmac->md, buf, SHA1_BLOCKSIZE); + csp_sha1_process(&hmac->md, isha, SHA1_DIGESTSIZE); + csp_sha1_done(&hmac->md, buf); + + /* Copy to output */ + for (i = 0; i < SHA1_DIGESTSIZE; i++) + out[i] = buf[i]; + + return CSP_ERR_NONE; +} + +int csp_hmac_memory(const uint8_t * key, uint32_t keylen, const uint8_t * data, uint32_t datalen, uint8_t * hmac) { + hmac_state state; + + /* NULL pointer check */ + if (!key || !data || !hmac) + return CSP_ERR_INVAL; + + /* Init HMAC state */ + if (csp_hmac_init(&state, key, keylen) != 0) + return CSP_ERR_INVAL; + + /* Process data */ + if (csp_hmac_process(&state, data, datalen) != 0) + return CSP_ERR_INVAL; + + /* Output HMAC */ + if (csp_hmac_done(&state, hmac) != 0) + return CSP_ERR_INVAL; + + return CSP_ERR_NONE; +} + +int csp_hmac_set_key(char * key, uint32_t keylen) { + + /* Use SHA1 as KDF */ + uint8_t hash[SHA1_DIGESTSIZE]; + csp_sha1_memory((uint8_t *)key, keylen, hash); + + /* Copy key */ + memcpy(csp_hmac_key, hash, HMAC_KEY_LENGTH); + + return CSP_ERR_NONE; + +} + +int csp_hmac_append(csp_packet_t * packet, bool include_header) { + + /* NULL pointer check */ + if (packet == NULL) + return CSP_ERR_INVAL; + + uint8_t hmac[SHA1_DIGESTSIZE]; + + /* Calculate HMAC */ + if (include_header) { + csp_hmac_memory(csp_hmac_key, HMAC_KEY_LENGTH, (uint8_t *) &packet->id, packet->length + sizeof(packet->id), hmac); + } else { + csp_hmac_memory(csp_hmac_key, HMAC_KEY_LENGTH, packet->data, packet->length, hmac); + } + + /* Truncate hash and copy to packet */ + memcpy(&packet->data[packet->length], hmac, CSP_HMAC_LENGTH); + packet->length += CSP_HMAC_LENGTH; + + return CSP_ERR_NONE; + +} + +int csp_hmac_verify(csp_packet_t * packet, bool include_header) { + + /* NULL pointer check */ + if (packet == NULL) + return CSP_ERR_INVAL; + + uint8_t hmac[SHA1_DIGESTSIZE]; + + /* Calculate HMAC */ + if (include_header) { + csp_hmac_memory(csp_hmac_key, HMAC_KEY_LENGTH, (uint8_t *) &packet->id, packet->length + sizeof(packet->id) - CSP_HMAC_LENGTH, hmac); + } else { + csp_hmac_memory(csp_hmac_key, HMAC_KEY_LENGTH, packet->data, packet->length - CSP_HMAC_LENGTH, hmac); + } + + /* Compare calculated HMAC with packet header */ + if (memcmp(&packet->data[packet->length] - CSP_HMAC_LENGTH, hmac, CSP_HMAC_LENGTH) != 0) { + /* HMAC failed */ + return CSP_ERR_HMAC; + } else { + /* Strip HMAC */ + packet->length -= CSP_HMAC_LENGTH; + return CSP_ERR_NONE; + } + +} + +#endif // CSP_USE_HMAC diff --git a/gomspace/libgscsp/lib/libcsp/src/crypto/csp_sha1.c b/gomspace/libgscsp/lib/libcsp/src/crypto/csp_sha1.c new file mode 100644 index 00000000..6c3920e9 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/crypto/csp_sha1.c @@ -0,0 +1,217 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* Code originally from Python's SHA1 Module, who based it on libtom.org */ + +#include +#include + +/* CSP includes */ +#include + +#include + +#if defined(CSP_USE_HMAC) || defined(CSP_USE_XTEA) + +/* Rotate left macro */ +#define ROL(x,y) (((x) << (y)) | ((x) >> (32-y))) + +/* Endian Neutral macros that work on all platforms */ +#define STORE32H(x, y) do { (y)[0] = (uint8_t)(((x) >> 24) & 0xff); \ + (y)[1] = (uint8_t)(((x) >> 16) & 0xff); \ + (y)[2] = (uint8_t)(((x) >> 8) & 0xff); \ + (y)[3] = (uint8_t)(((x) >> 0) & 0xff); } while (0) + +#define LOAD32H(x, y) do { (x) = ((uint32_t)((y)[0] & 0xff) << 24) | \ + ((uint32_t)((y)[1] & 0xff) << 16) | \ + ((uint32_t)((y)[2] & 0xff) << 8) | \ + ((uint32_t)((y)[3] & 0xff) << 0); } while (0) + +#define STORE64H(x, y) do { (y)[0] = (uint8_t)(((x) >> 56) & 0xff); \ + (y)[1] = (uint8_t)(((x) >> 48) & 0xff); \ + (y)[2] = (uint8_t)(((x) >> 40) & 0xff); \ + (y)[3] = (uint8_t)(((x) >> 32) & 0xff); \ + (y)[4] = (uint8_t)(((x) >> 24) & 0xff); \ + (y)[5] = (uint8_t)(((x) >> 16) & 0xff); \ + (y)[6] = (uint8_t)(((x) >> 8) & 0xff); \ + (y)[7] = (uint8_t)(((x) >> 0) & 0xff); } while (0) + +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) + +/* SHA1 macros */ +#define F0(x,y,z) (z ^ (x & (y ^ z))) +#define F1(x,y,z) (x ^ y ^ z) +#define F2(x,y,z) ((x & y) | (z & (x | y))) +#define F3(x,y,z) (x ^ y ^ z) + +#define FF_0(a, b, c, d, e, i) do {e = (ROL(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROL(b, 30);} while (0) +#define FF_1(a, b, c, d, e, i) do {e = (ROL(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROL(b, 30);} while (0) +#define FF_2(a, b, c, d, e, i) do {e = (ROL(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROL(b, 30);} while (0) +#define FF_3(a, b, c, d, e, i) do {e = (ROL(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROL(b, 30);} while (0) + +static void csp_sha1_compress(csp_sha1_state * sha1, const uint8_t * buf) { + + uint32_t a, b, c, d, e, W[80], i; + + /* Copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) + LOAD32H(W[i], buf + (4*i)); + + /* Copy state */ + a = sha1->state[0]; + b = sha1->state[1]; + c = sha1->state[2]; + d = sha1->state[3]; + e = sha1->state[4]; + + /* Expand it */ + for (i = 16; i < 80; i++) + W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1); + + /* Compress */ + i = 0; + + /* Round one */ + for (; i < 20;) { + FF_0(a, b, c, d, e, i++); + FF_0(e, a, b, c, d, i++); + FF_0(d, e, a, b, c, i++); + FF_0(c, d, e, a, b, i++); + FF_0(b, c, d, e, a, i++); + } + + /* Round two */ + for (; i < 40;) { + FF_1(a, b, c, d, e, i++); + FF_1(e, a, b, c, d, i++); + FF_1(d, e, a, b, c, i++); + FF_1(c, d, e, a, b, i++); + FF_1(b, c, d, e, a, i++); + } + + /* Round three */ + for (; i < 60;) { + FF_2(a, b, c, d, e, i++); + FF_2(e, a, b, c, d, i++); + FF_2(d, e, a, b, c, i++); + FF_2(c, d, e, a, b, i++); + FF_2(b, c, d, e, a, i++); + } + + /* Round four */ + for (; i < 80;) { + FF_3(a, b, c, d, e, i++); + FF_3(e, a, b, c, d, i++); + FF_3(d, e, a, b, c, i++); + FF_3(c, d, e, a, b, i++); + FF_3(b, c, d, e, a, i++); + } + + /* Store */ + sha1->state[0] += a; + sha1->state[1] += b; + sha1->state[2] += c; + sha1->state[3] += d; + sha1->state[4] += e; + +} + +void csp_sha1_init(csp_sha1_state * sha1) { + + sha1->state[0] = 0x67452301UL; + sha1->state[1] = 0xefcdab89UL; + sha1->state[2] = 0x98badcfeUL; + sha1->state[3] = 0x10325476UL; + sha1->state[4] = 0xc3d2e1f0UL; + sha1->curlen = 0; + sha1->length = 0; + +} + +void csp_sha1_process(csp_sha1_state * sha1, const uint8_t * in, uint32_t inlen) { + + uint32_t n; + while (inlen > 0) { + if (sha1->curlen == 0 && inlen >= SHA1_BLOCKSIZE) { + csp_sha1_compress(sha1, in); + sha1->length += SHA1_BLOCKSIZE * 8; + in += SHA1_BLOCKSIZE; + inlen -= SHA1_BLOCKSIZE; + } else { + n = MIN(inlen, (SHA1_BLOCKSIZE - sha1->curlen)); + memcpy(sha1->buf + sha1->curlen, in, (size_t)n); + sha1->curlen += n; + in += n; + inlen -= n; + if (sha1->curlen == SHA1_BLOCKSIZE) { + csp_sha1_compress(sha1, sha1->buf); + sha1->length += 8*SHA1_BLOCKSIZE; + sha1->curlen = 0; + } + } + } + +} + +void csp_sha1_done(csp_sha1_state * sha1, uint8_t * out) { + + uint32_t i; + + /* Increase the length of the message */ + sha1->length += sha1->curlen * 8; + + /* Append the '1' bit */ + sha1->buf[sha1->curlen++] = 0x80; + + /* If the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (sha1->curlen > 56) { + while (sha1->curlen < 64) + sha1->buf[sha1->curlen++] = 0; + csp_sha1_compress(sha1, sha1->buf); + sha1->curlen = 0; + } + + /* Pad up to 56 bytes of zeroes */ + while (sha1->curlen < 56) + sha1->buf[sha1->curlen++] = 0; + + /* Store length */ + STORE64H(sha1->length, sha1->buf + 56); + csp_sha1_compress(sha1, sha1->buf); + + /* Copy output */ + for (i = 0; i < 5; i++) + STORE32H(sha1->state[i], out + (4 * i)); + +} + +void csp_sha1_memory(const uint8_t * msg, uint32_t len, uint8_t * hash) { + + csp_sha1_state md; + csp_sha1_init(&md); + csp_sha1_process(&md, msg, len); + csp_sha1_done(&md, hash); + +} + +#endif // CSP_USE_HMAC diff --git a/gomspace/libgscsp/lib/libcsp/src/crypto/csp_xtea.c b/gomspace/libgscsp/lib/libcsp/src/crypto/csp_xtea.c new file mode 100644 index 00000000..718824d1 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/crypto/csp_xtea.c @@ -0,0 +1,134 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* Simple implementation of XTEA in CTR mode */ + +#include +#include + +/* CSP includes */ +#include +#include +#include +#include + +#ifdef CSP_USE_XTEA + +#define XTEA_BLOCKSIZE 8 +#define XTEA_ROUNDS 32 +#define XTEA_KEY_LENGTH 16 + +/* XTEA key */ +static uint32_t csp_xtea_key[XTEA_KEY_LENGTH/sizeof(uint32_t)] __attribute__ ((aligned(sizeof(uint32_t)))); + +#define STORE32L(x, y) do { (y)[3] = (uint8_t)(((x) >> 24) & 0xff); \ + (y)[2] = (uint8_t)(((x) >> 16) & 0xff); \ + (y)[1] = (uint8_t)(((x) >> 8) & 0xff); \ + (y)[0] = (uint8_t)(((x) >> 0) & 0xff); } while (0) + +#define LOAD32L(x, y) do { (x) = ((uint32_t)((y)[3] & 0xff) << 24) | \ + ((uint32_t)((y)[2] & 0xff) << 16) | \ + ((uint32_t)((y)[1] & 0xff) << 8) | \ + ((uint32_t)((y)[0] & 0xff) << 0); } while (0) + +/* This function takes 64 bits of data in block and the 128 bits key in key */ +static inline void csp_xtea_encrypt_block(uint8_t *block, uint8_t const *key) { + + uint32_t i, v0, v1, delta = 0x9E3779B9, sum = 0, k[4]; + + LOAD32L(k[0], &key[0]); + LOAD32L(k[1], &key[4]); + LOAD32L(k[2], &key[8]); + LOAD32L(k[3], &key[12]); + + LOAD32L(v0, &block[0]); + LOAD32L(v1, &block[4]); + + for (i = 0; i < XTEA_ROUNDS; i++) { + v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]); + sum += delta; + v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum >> 11) & 3]); + } + + STORE32L(v0, &block[0]); + STORE32L(v1, &block[4]); + +} + +static inline void csp_xtea_xor_byte(uint8_t * dst, uint8_t * src, uint32_t len) { + + unsigned int i; + for (i = 0; i < len; i++) + dst[i] ^= src[i]; + +} + +int csp_xtea_set_key(char * key, uint32_t keylen) { + + /* Use SHA1 as KDF */ + uint8_t hash[SHA1_DIGESTSIZE]; + csp_sha1_memory((uint8_t *)key, keylen, hash); + + /* Copy key */ + memcpy(csp_xtea_key, hash, XTEA_KEY_LENGTH); + + return CSP_ERR_NONE; + +} + +int csp_xtea_encrypt(uint8_t * plain, const uint32_t len, uint32_t iv[2]) { + + unsigned int i; + uint32_t stream[2]; + + uint32_t blocks = (len + XTEA_BLOCKSIZE - 1)/ XTEA_BLOCKSIZE; + uint32_t remain; + + /* Initialize stream */ + stream[0] = csp_htobe32(iv[0]); + stream[1] = csp_htobe32(iv[1]); + + for (i = 0; i < blocks; i++) { + /* Create stream */ + csp_xtea_encrypt_block((uint8_t *)stream, (uint8_t *)csp_xtea_key); + + /* Calculate remaining bytes */ + remain = len - i * XTEA_BLOCKSIZE; + + /* XOR plain text with stream to generate cipher text */ + csp_xtea_xor_byte(&plain[len - remain], (uint8_t *)stream, remain < XTEA_BLOCKSIZE ? remain : XTEA_BLOCKSIZE); + + /* Increment counter */ + stream[0] = csp_htobe32(iv[0]); + stream[1] = csp_htobe32(iv[1]++); + } + + return CSP_ERR_NONE; + +} + +int csp_xtea_decrypt(uint8_t * cipher, const uint32_t len, uint32_t iv[2]) { + + /* Since we use counter mode, we can reuse the encryption function */ + return csp_xtea_encrypt(cipher, len, iv); + +} + +#endif // CSP_USE_XTEA diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_bridge.c b/gomspace/libgscsp/lib/libcsp/src/csp_bridge.c new file mode 100644 index 00000000..1c579a9f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_bridge.c @@ -0,0 +1,94 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include "csp_route.h" +#include "csp_qfifo.h" +#include "csp_io.h" +#include "csp_promisc.h" + +static csp_iface_t* if_a = NULL; +static csp_iface_t* if_b = NULL; + +static CSP_DEFINE_TASK(csp_bridge) { + + csp_qfifo_t input; + csp_packet_t * packet; + + /* Here there be bridging */ + while (1) { + + /* Get next packet to route */ + if (csp_qfifo_read(&input) != CSP_ERR_NONE) + continue; + + packet = input.packet; + + csp_log_packet("Input: Src %u, Dst %u, Dport %u, Sport %u, Pri %u, Flags 0x%02X, Size %"PRIu16, + packet->id.src, packet->id.dst, packet->id.dport, + packet->id.sport, packet->id.pri, packet->id.flags, packet->length); + + /* Here there be promiscuous mode */ +#ifdef CSP_USE_PROMISC + csp_promisc_add(packet); +#endif + + /* Find the opposing interface */ + csp_iface_t * ifout; + if (input.interface == if_a) { + ifout = if_b; + } else { + ifout = if_a; + } + + /* Send to the interface directly, no hassle */ + if (csp_send_direct(packet->id, packet, ifout, 0) != CSP_ERR_NONE) { + csp_log_warn("Router failed to send"); + csp_buffer_free(packet); + } + + /* Next message, please */ + continue; + + } + + return CSP_TASK_RETURN; + +} + +int csp_bridge_start(unsigned int task_stack_size, unsigned int task_priority, csp_iface_t * _if_a, csp_iface_t * _if_b) { + + /* Set static references to A/B side of bridge */ + if_a = _if_a; + if_b = _if_b; + + static csp_thread_handle_t handle; + int ret = csp_thread_create(csp_bridge, "BRIDGE", task_stack_size, NULL, task_priority, &handle); + + if (ret != 0) { + csp_log_error("Failed to start task"); + return CSP_ERR_NOMEM; + } + + return CSP_ERR_NONE; + +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_buffer.c b/gomspace/libgscsp/lib/libcsp/src/csp_buffer.c new file mode 100644 index 00000000..8947f337 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_buffer.c @@ -0,0 +1,224 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +/* CSP includes */ +#include +#include +#include +#include +#include + +#ifndef CSP_BUFFER_ALIGN +#define CSP_BUFFER_ALIGN (sizeof(int *)) +#endif + +typedef struct csp_skbf_s { + unsigned int refcount; + void * skbf_addr; + char skbf_data[]; +} csp_skbf_t; + +static csp_queue_handle_t csp_buffers; +static char * csp_buffer_pool; +static unsigned int count, size; + +CSP_DEFINE_CRITICAL(csp_critical_lock); + +int csp_buffer_init(int buf_count, int buf_size) { + + unsigned int i; + csp_skbf_t * buf; + + count = buf_count; + size = buf_size + CSP_BUFFER_PACKET_OVERHEAD; + unsigned int skbfsize = (sizeof(csp_skbf_t) + size); + skbfsize = CSP_BUFFER_ALIGN * ((skbfsize + CSP_BUFFER_ALIGN - 1) / CSP_BUFFER_ALIGN); + unsigned int poolsize = count * skbfsize; + + csp_buffer_pool = csp_malloc(poolsize); + if (csp_buffer_pool == NULL) + goto fail_malloc; + + csp_buffers = csp_queue_create(count, sizeof(void *)); + if (!csp_buffers) + goto fail_queue; + + if (CSP_INIT_CRITICAL(csp_critical_lock) != CSP_ERR_NONE) + goto fail_critical; + + memset(csp_buffer_pool, 0, poolsize); + + for (i = 0; i < count; i++) { + + /* We have already taken care of pointer alignment since + * skbfsize is an integer multiple of sizeof(int *) + * but the explicit cast to a void * is still necessary + * to tell the compiler so. + */ + buf = (void *) &csp_buffer_pool[i * skbfsize]; + buf->refcount = 0; + buf->skbf_addr = buf; + + csp_queue_enqueue(csp_buffers, &buf, 0); + + } + + return CSP_ERR_NONE; + +fail_critical: + csp_queue_remove(csp_buffers); +fail_queue: + csp_free(csp_buffer_pool); +fail_malloc: + return CSP_ERR_NOMEM; + +} + +void *csp_buffer_get_isr(size_t buf_size) { + + csp_skbf_t * buffer = NULL; + CSP_BASE_TYPE task_woken = 0; + + if (buf_size + CSP_BUFFER_PACKET_OVERHEAD > size) + return NULL; + + csp_queue_dequeue_isr(csp_buffers, &buffer, &task_woken); + if (buffer == NULL) + return NULL; + + if (buffer != buffer->skbf_addr) + return NULL; + + buffer->refcount++; + return buffer->skbf_data; + +} + +void *csp_buffer_get(size_t buf_size) { + + csp_skbf_t * buffer = NULL; + + if (buf_size + CSP_BUFFER_PACKET_OVERHEAD > size) { + csp_log_error("Attempt to allocate too large block %u", buf_size); + return NULL; + } + + csp_queue_dequeue(csp_buffers, &buffer, 0); + if (buffer == NULL) { + csp_log_error("Out of buffers"); + return NULL; + } + + csp_log_buffer("GET: %p %p", buffer, buffer->skbf_addr); + + if (buffer != buffer->skbf_addr) { + csp_log_error("Corrupt CSP buffer"); + return NULL; + } + + buffer->refcount++; + return buffer->skbf_data; +} + +void csp_buffer_free_isr(void *packet) { + CSP_BASE_TYPE task_woken = 0; + if (!packet) + return; + + csp_skbf_t * buf = packet - sizeof(csp_skbf_t); + + if (((uintptr_t) buf % CSP_BUFFER_ALIGN) > 0) + return; + + if (buf->skbf_addr != buf) + return; + + if (buf->refcount == 0) { + return; + } else if (buf->refcount > 1) { + buf->refcount--; + return; + } else { + buf->refcount = 0; + csp_queue_enqueue_isr(csp_buffers, &buf, &task_woken); + } + +} + +void csp_buffer_free(void *packet) { + if (!packet) { + csp_log_error("Attempt to free null pointer"); + return; + } + + csp_skbf_t * buf = packet - sizeof(csp_skbf_t); + + if (((uintptr_t) buf % CSP_BUFFER_ALIGN) > 0) { + csp_log_error("FREE: Unaligned CSP buffer pointer %p", packet); + return; + } + + if (buf->skbf_addr != buf) { + csp_log_error("FREE: Invalid CSP buffer pointer %p", packet); + return; + } + + if (buf->refcount == 0) { + csp_log_error("FREE: Buffer already free %p", buf); + return; + } else if (buf->refcount > 1) { + buf->refcount--; + csp_log_error("FREE: Buffer %p in use by %u users", buf, buf->refcount); + return; + } else { + buf->refcount = 0; + csp_log_buffer("FREE: %p", buf); + csp_queue_enqueue(csp_buffers, &buf, 0); + } + +} + +void *csp_buffer_clone(void *buffer) { + + csp_packet_t *packet = (csp_packet_t *) buffer; + + if (!packet) + return NULL; + + csp_packet_t *clone = csp_buffer_get(packet->length); + + if (clone) + memcpy(clone, packet, size); + + return clone; + +} + +int csp_buffer_remaining(void) { + return csp_queue_size(csp_buffers); +} + +int csp_buffer_size(void) { + return size; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_conn.c b/gomspace/libgscsp/lib/libcsp/src/csp_conn.c new file mode 100644 index 00000000..7daa569d --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_conn.c @@ -0,0 +1,498 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +/* CSP includes */ +#include +#include + +#include +#include +#include +#include +#include + +#include "csp_conn.h" +#include "transport/csp_transport.h" + +/* Static connection pool */ +static csp_conn_t arr_conn[CSP_CONN_MAX]; + +/* Connection pool lock */ +static csp_bin_sem_handle_t conn_lock; + +/* Source port */ +static uint8_t sport; + +/* Source port lock */ +static csp_bin_sem_handle_t sport_lock; + +void csp_conn_check_timeouts(void) { +#ifdef CSP_USE_RDP + int i; + for (i = 0; i < CSP_CONN_MAX; i++) + if (arr_conn[i].state == CONN_OPEN) + if (arr_conn[i].idin.flags & CSP_FRDP) + csp_rdp_check_timeouts(&arr_conn[i]); +#endif +} + +int csp_conn_get_rxq(int prio) { + +#ifdef CSP_USE_QOS + return prio; +#else + return 0; +#endif + +} + +int csp_conn_lock(csp_conn_t * conn, uint32_t timeout) { + + if (csp_mutex_lock(&conn->lock, timeout) != CSP_MUTEX_OK) + return CSP_ERR_TIMEDOUT; + + return CSP_ERR_NONE; + +} + +int csp_conn_unlock(csp_conn_t * conn) { + + csp_mutex_unlock(&conn->lock); + + return CSP_ERR_NONE; + +} + +int csp_conn_enqueue_packet(csp_conn_t * conn, csp_packet_t * packet) { + + if (!conn) + return CSP_ERR_INVAL; + + int rxq; + if (packet != NULL) { + rxq = csp_conn_get_rxq(packet->id.pri); + } else { + rxq = CSP_RX_QUEUES - 1; + } + + if (csp_queue_enqueue(conn->rx_queue[rxq], &packet, 0) != CSP_QUEUE_OK) { + csp_log_error("RX queue %p full with %u items", conn->rx_queue[rxq], csp_queue_size(conn->rx_queue[rxq])); + return CSP_ERR_NOMEM; + } + +#ifdef CSP_USE_QOS + int event = 0; + if (csp_queue_enqueue(conn->rx_event, &event, 0) != CSP_QUEUE_OK) { + csp_log_error("QOS event queue full"); + return CSP_ERR_NOMEM; + } +#endif + + return CSP_ERR_NONE; +} + +int csp_conn_init(void) { + + /* Initialize source port */ + srand(csp_get_ms()); + sport = (rand() % (CSP_ID_PORT_MAX - CSP_MAX_BIND_PORT)) + (CSP_MAX_BIND_PORT + 1); + + if (csp_bin_sem_create(&sport_lock) != CSP_SEMAPHORE_OK) { + csp_log_error("No more memory for sport semaphore"); + return CSP_ERR_NOMEM; + } + + int i, prio; + for (i = 0; i < CSP_CONN_MAX; i++) { + for (prio = 0; prio < CSP_RX_QUEUES; prio++) + arr_conn[i].rx_queue[prio] = csp_queue_create(CSP_RX_QUEUE_LENGTH, sizeof(csp_packet_t *)); + +#ifdef CSP_USE_QOS + arr_conn[i].rx_event = csp_queue_create(CSP_CONN_QUEUE_LENGTH, sizeof(int)); +#endif + arr_conn[i].state = CONN_CLOSED; + + if (csp_mutex_create(&arr_conn[i].lock) != CSP_MUTEX_OK) { + csp_log_error("Failed to create connection lock"); + return CSP_ERR_NOMEM; + } + +#ifdef CSP_USE_RDP + if (csp_rdp_allocate(&arr_conn[i]) != CSP_ERR_NONE) { + csp_log_error("Failed to create queues for RDP in csp_conn_init"); + return CSP_ERR_NOMEM; + } +#endif + } + + if (csp_bin_sem_create(&conn_lock) != CSP_SEMAPHORE_OK) { + csp_log_error("No more memory for conn semaphore"); + return CSP_ERR_NOMEM; + } + + return CSP_ERR_NONE; + +} + +csp_conn_t * csp_conn_find(uint32_t id, uint32_t mask) { + + /* Search for matching connection */ + int i; + csp_conn_t * conn; + id = (id & mask); + for (i = 0; i < CSP_CONN_MAX; i++) { + conn = &arr_conn[i]; + if ((conn->state != CONN_CLOSED) && (conn->type == CONN_CLIENT) && ((conn->idin.ext & mask) == id)) + return conn; + } + + return NULL; + +} + +static int csp_conn_flush_rx_queue(csp_conn_t * conn) { + + csp_packet_t * packet; + + int prio; + + /* Flush packet queues */ + for (prio = 0; prio < CSP_RX_QUEUES; prio++) { + while (csp_queue_dequeue(conn->rx_queue[prio], &packet, 0) == CSP_QUEUE_OK) + if (packet != NULL) + csp_buffer_free(packet); + } + + /* Flush event queue */ +#ifdef CSP_USE_QOS + int event; + while (csp_queue_dequeue(conn->rx_event, &event, 0) == CSP_QUEUE_OK); +#endif + + return CSP_ERR_NONE; + +} + +csp_conn_t * csp_conn_allocate(csp_conn_type_t type) { + + int i, j; + static uint8_t csp_conn_last_given = 0; + csp_conn_t * conn; + + if (csp_bin_sem_wait(&conn_lock, 100) != CSP_SEMAPHORE_OK) { + csp_log_error("Failed to lock conn array"); + return NULL; + } + + /* Search for free connection */ + i = csp_conn_last_given; + i = (i + 1) % CSP_CONN_MAX; + + for (j = 0; j < CSP_CONN_MAX; j++) { + conn = &arr_conn[i]; + if (conn->state == CONN_CLOSED) + break; + i = (i + 1) % CSP_CONN_MAX; + } + + if (conn->state == CONN_OPEN) { + csp_log_error("No more free connections"); + csp_bin_sem_post(&conn_lock); + return NULL; + } + + conn->idin.ext = 0; + conn->idout.ext = 0; + conn->socket = NULL; + conn->timestamp = 0; + conn->type = type; + conn->state = CONN_OPEN; + + csp_conn_last_given = i; + csp_bin_sem_post(&conn_lock); + + return conn; + +} + +csp_conn_t * csp_conn_new(csp_id_t idin, csp_id_t idout) { + + /* Allocate connection structure */ + csp_conn_t * conn = csp_conn_allocate(CONN_CLIENT); + + if (conn) { + /* No lock is needed here, because nobody else * + * has a reference to this connection yet. */ + conn->idin.ext = idin.ext; + conn->idout.ext = idout.ext; + conn->timestamp = csp_get_ms(); + + /* Ensure connection queue is empty */ + csp_conn_flush_rx_queue(conn); + } + + return conn; + +} + +int csp_close(csp_conn_t * conn) { + + if (conn == NULL) { + csp_log_error("NULL Pointer given to csp_close"); + return CSP_ERR_INVAL; + } + + if (conn->state == CONN_CLOSED) { + csp_log_protocol("Conn already closed"); + return CSP_ERR_NONE; + } + +#ifdef CSP_USE_RDP + /* Ensure RDP knows this connection is closing */ + if (conn->idin.flags & CSP_FRDP || conn->idout.flags & CSP_FRDP) + if (csp_rdp_close(conn) == CSP_ERR_AGAIN) + return CSP_ERR_NONE; +#endif + + /* Lock connection array while closing connection */ + if (csp_bin_sem_wait(&conn_lock, 100) != CSP_SEMAPHORE_OK) { + csp_log_error("Failed to lock conn array"); + return CSP_ERR_TIMEDOUT; + } + + /* Set to closed */ + conn->state = CONN_CLOSED; + + /* Ensure connection queue is empty */ + csp_conn_flush_rx_queue(conn); + + if (conn->socket && (conn->type == CONN_SERVER) && (conn->opts & (CSP_SO_CONN_LESS | CSP_SO_INTERNAL_LISTEN))) { + csp_queue_remove(conn->socket); + conn->socket = NULL; + } + + /* Reset RDP state */ +#ifdef CSP_USE_RDP + if (conn->idin.flags & CSP_FRDP) + csp_rdp_flush_all(conn); +#endif + + /* Unlock connection array */ + csp_bin_sem_post(&conn_lock); + + return CSP_ERR_NONE; +} + +csp_conn_t * csp_connect(uint8_t prio, uint8_t dest, uint8_t dport, uint32_t timeout, uint32_t opts) { + + /* Force options on all connections */ + opts |= CSP_CONNECTION_SO; + + /* Generate identifier */ + csp_id_t incoming_id, outgoing_id; + incoming_id.pri = prio; + incoming_id.dst = csp_get_address(); + incoming_id.src = dest; + incoming_id.sport = dport; + incoming_id.flags = 0; + outgoing_id.pri = prio; + outgoing_id.dst = dest; + outgoing_id.src = csp_get_address(); + outgoing_id.dport = dport; + outgoing_id.flags = 0; + + /* Set connection options */ + if (opts & CSP_O_NOCRC32) { + opts &= ~CSP_O_CRC32; + } + + if (opts & CSP_O_RDP) { +#ifdef CSP_USE_RDP + incoming_id.flags |= CSP_FRDP; + outgoing_id.flags |= CSP_FRDP; +#else + csp_log_error("Attempt to create RDP connection, but CSP was compiled without RDP support"); + return NULL; +#endif + } + + if (opts & CSP_O_HMAC) { +#ifdef CSP_USE_HMAC + outgoing_id.flags |= CSP_FHMAC; + incoming_id.flags |= CSP_FHMAC; +#else + csp_log_error("Attempt to create HMAC authenticated connection, but CSP was compiled without HMAC support"); + return NULL; +#endif + } + + if (opts & CSP_O_XTEA) { +#ifdef CSP_USE_XTEA + outgoing_id.flags |= CSP_FXTEA; + incoming_id.flags |= CSP_FXTEA; +#else + csp_log_error("Attempt to create XTEA encrypted connection, but CSP was compiled without XTEA support"); + return NULL; +#endif + } + + if (opts & CSP_O_CRC32) { +#ifdef CSP_USE_CRC32 + outgoing_id.flags |= CSP_FCRC32; + incoming_id.flags |= CSP_FCRC32; +#else + csp_log_error("Attempt to create CRC32 validated connection, but CSP was compiled without CRC32 support"); + return NULL; +#endif + } + + /* Find an unused ephemeral port */ + csp_conn_t * conn = NULL; + + /* Wait for sport lock - note that csp_conn_new(..) is called inside the lock! */ + if (csp_bin_sem_wait(&sport_lock, 1000) != CSP_SEMAPHORE_OK) + return NULL; + + const uint8_t start = sport; + while (++sport != start) { + if (sport > CSP_ID_PORT_MAX) + sport = CSP_MAX_BIND_PORT + 1; + + outgoing_id.sport = sport; + incoming_id.dport = sport; + + /* Match on destination port of _incoming_ identifier */ + if (csp_conn_find(incoming_id.ext, CSP_ID_DPORT_MASK) == NULL) { + /* Break - we found an unused ephemeral port + allocate connection while locked to mark port in use */ + conn = csp_conn_new(incoming_id, outgoing_id); + break; + } + } + + /* Post sport lock */ + csp_bin_sem_post(&sport_lock); + + if (conn == NULL) + return NULL; + + /* Set connection options */ + conn->opts = opts; + +#ifdef CSP_USE_RDP + /* Call Transport Layer connect */ + if (outgoing_id.flags & CSP_FRDP) { + /* If the transport layer has failed to connect + * deallocate connection structure again and return NULL */ + if (csp_rdp_connect(conn, timeout) != CSP_ERR_NONE) { + csp_close(conn); + return NULL; + } + } +#endif + + /* We have a successful connection */ + return conn; + +} + +inline int csp_conn_dport(csp_conn_t * conn) { + + return conn->idin.dport; + +} + +inline int csp_conn_sport(csp_conn_t * conn) { + + return conn->idin.sport; + +} + +inline int csp_conn_dst(csp_conn_t * conn) { + + return conn->idin.dst; + +} + +inline int csp_conn_src(csp_conn_t * conn) { + + return conn->idin.src; + +} + +inline int csp_conn_flags(csp_conn_t * conn) { + + return conn->idin.flags; + +} + +#ifdef CSP_DEBUG +void csp_conn_print_table(void) { + + int i; + csp_conn_t * conn; + + for (i = 0; i < CSP_CONN_MAX; i++) { + conn = &arr_conn[i]; + printf("[%02u %p] S:%u, %u -> %u, %u -> %u, sock: %p\r\n", + i, conn, conn->state, conn->idin.src, conn->idin.dst, + conn->idin.dport, conn->idin.sport, conn->socket); +#ifdef CSP_USE_RDP + if (conn->idin.flags & CSP_FRDP) + csp_rdp_conn_print(conn); +#endif + } +} + +int csp_conn_print_table_str(char * str_buf, int str_size) { + + int i, start = 0; + csp_conn_t * conn; + char buf[100]; + + /* Display up to 10 connections */ + if (CSP_CONN_MAX - 10 > 0) + start = CSP_CONN_MAX - 10; + + for (i = start; i < CSP_CONN_MAX; i++) { + conn = &arr_conn[i]; + snprintf(buf, sizeof(buf), "[%02u %p] S:%u, %u -> %u, %u -> %u, sock: %p\n", + i, conn, conn->state, conn->idin.src, conn->idin.dst, + conn->idin.dport, conn->idin.sport, conn->socket); + + strncat(str_buf, buf, str_size); + if ((str_size -= strlen(buf)) <= 0) + break; + } + + return CSP_ERR_NONE; +} +#endif + +const csp_conn_t * csp_conn_get_array(size_t * size) +{ + *size = CSP_CONN_MAX; + return arr_conn; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_conn.h b/gomspace/libgscsp/lib/libcsp/src/csp_conn.h new file mode 100644 index 00000000..3fa0ff52 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_conn.h @@ -0,0 +1,112 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_CONN_H_ +#define _CSP_CONN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +#include +#include + +/** @brief Connection states */ +typedef enum { + CONN_CLOSED = 0, + CONN_OPEN = 1, +} csp_conn_state_t; + +/** @brief Connection types */ +typedef enum { + CONN_CLIENT = 0, + CONN_SERVER = 1, +} csp_conn_type_t; + +typedef enum { + RDP_CLOSED = 0, + RDP_SYN_SENT, + RDP_SYN_RCVD, + RDP_OPEN, + RDP_CLOSE_WAIT, +} csp_rdp_state_t; + +/** @brief RDP Connection header + * @note Do not try to pack this struct, the posix sem handle will stop working */ +typedef struct { + csp_rdp_state_t state; /**< Connection state */ + uint16_t snd_nxt; /**< The sequence number of the next segment that is to be sent */ + uint16_t snd_una; /**< The sequence number of the oldest unacknowledged segment */ + uint16_t snd_iss; /**< The initial send sequence number */ + uint16_t rcv_cur; /**< The sequence number of the last segment received correctly and in sequence */ + uint16_t rcv_irs; /**< The initial receive sequence number */ + uint16_t rcv_lsa; /**< The last sequence number acknowledged by the receiver */ + uint32_t window_size; + uint32_t conn_timeout; + uint32_t packet_timeout; + uint32_t delayed_acks; + uint32_t ack_timeout; + uint32_t ack_delay_count; + uint32_t ack_timestamp; + csp_bin_sem_handle_t tx_wait; + csp_queue_handle_t tx_queue; + csp_queue_handle_t rx_queue; +} csp_rdp_t; + +/** @brief Connection struct */ +struct csp_conn_s { + csp_conn_type_t type; /* Connection type (CONN_CLIENT or CONN_SERVER) */ + csp_conn_state_t state; /* Connection state (CONN_OPEN or CONN_CLOSED) */ + csp_mutex_t lock; /* Connection structure lock */ + csp_id_t idin; /* Identifier received */ + csp_id_t idout; /* Identifier transmitted */ +#ifdef CSP_USE_QOS + csp_queue_handle_t rx_event; /* Event queue for RX packets */ +#endif + csp_queue_handle_t rx_queue[CSP_RX_QUEUES]; /* Queue for RX packets */ + csp_queue_handle_t socket; /* Socket to be "woken" when first packet is ready */ + uint32_t timestamp; /* Time the connection was opened */ + uint32_t opts; /* Connection or socket options */ +#ifdef CSP_USE_RDP + csp_rdp_t rdp; /* RDP state */ +#endif +}; + +int csp_conn_lock(csp_conn_t * conn, uint32_t timeout); +int csp_conn_unlock(csp_conn_t * conn); +int csp_conn_enqueue_packet(csp_conn_t * conn, csp_packet_t * packet); +int csp_conn_init(void); +csp_conn_t * csp_conn_allocate(csp_conn_type_t type); +csp_conn_t * csp_conn_find(uint32_t id, uint32_t mask); +csp_conn_t * csp_conn_new(csp_id_t idin, csp_id_t idout); +void csp_conn_check_timeouts(void); +int csp_conn_get_rxq(int prio); + +const csp_conn_t * csp_conn_get_array(size_t * size); // for test purposes only! + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_CONN_H_ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_crc32.c b/gomspace/libgscsp/lib/libcsp/src/csp_crc32.c new file mode 100644 index 00000000..8bf2145f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_crc32.c @@ -0,0 +1,140 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +#include +#include + +#include + +#ifdef CSP_USE_CRC32 + +#ifdef __AVR__ +#include +static const uint32_t crc_tab[256] PROGMEM = { +#else +static const uint32_t crc_tab[256] = { +#endif + 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, + 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, + 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, + 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, + 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, + 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, + 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, + 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, + 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, + 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, + 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, + 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, + 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, + 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, + 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, + 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, + 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, + 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, + 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, + 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, + 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, + 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, + 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, + 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, + 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, + 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, + 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, + 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, + 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, + 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, + 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, + 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 }; + +uint32_t csp_crc32_memory(const uint8_t * data, uint32_t length) { + uint32_t crc; + + crc = 0xFFFFFFFF; + while (length--) +#ifdef __AVR__ + crc = pgm_read_dword(&crc_tab[(crc ^ *data++) & 0xFFL]) ^ (crc >> 8); +#else + crc = crc_tab[(crc ^ *data++) & 0xFFL] ^ (crc >> 8); +#endif + + return (crc ^ 0xFFFFFFFF); +} + +int csp_crc32_append(csp_packet_t * packet, bool include_header) { + + uint32_t crc; + + /* NULL pointer check */ + if (packet == NULL) + return CSP_ERR_INVAL; + + /* Calculate CRC32, convert to network byte order */ + if (include_header) { + crc = csp_crc32_memory((uint8_t *) &packet->id, packet->length + sizeof(packet->id)); + } else { + crc = csp_crc32_memory(packet->data, packet->length); + } + crc = csp_hton32(crc); + + /* Copy checksum to packet */ + memcpy(&packet->data[packet->length], &crc, sizeof(uint32_t)); + packet->length += sizeof(uint32_t); + + return CSP_ERR_NONE; + +} + +int csp_crc32_verify(csp_packet_t * packet, bool include_header) { + + uint32_t crc; + + /* NULL pointer check */ + if (packet == NULL) + return CSP_ERR_INVAL; + + if (packet->length < sizeof(uint32_t)) + return CSP_ERR_INVAL; + + /* Calculate CRC32, convert to network byte order */ + if (include_header) { + crc = csp_crc32_memory((uint8_t *) &packet->id, packet->length + sizeof(packet->id) - sizeof(uint32_t)); + } else { + crc = csp_crc32_memory(packet->data, packet->length - sizeof(uint32_t)); + } + crc = csp_hton32(crc); + + /* Compare calculated checksum with packet header */ + if (memcmp(&packet->data[packet->length] - sizeof(uint32_t), &crc, sizeof(uint32_t)) != 0) { + /* CRC32 failed */ + return CSP_ERR_INVAL; + } else { + /* Strip CRC32 */ + packet->length -= sizeof(uint32_t); + return CSP_ERR_NONE; + } + +} + +#endif // CSP_USE_CRC32 diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_debug.c b/gomspace/libgscsp/lib/libcsp/src/csp_debug.c new file mode 100644 index 00000000..2e710cb3 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_debug.c @@ -0,0 +1,133 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +#ifdef __AVR__ +#include +#endif + +/* CSP includes */ +#include + +#include + +/* Custom debug function */ +csp_debug_hook_func_t csp_debug_hook_func = NULL; + +/* Debug levels */ +static bool csp_debug_level_enabled[] = { + [CSP_ERROR] = true, + [CSP_WARN] = true, + [CSP_INFO] = false, + [CSP_BUFFER] = false, + [CSP_PACKET] = false, + [CSP_PROTOCOL] = false, + [CSP_LOCK] = false, +}; + +/* Some compilers do not support weak symbols, so this function + * can be used instead to set a custom debug hook */ +void csp_debug_hook_set(csp_debug_hook_func_t f) +{ + csp_debug_hook_func = f; +} + +void do_csp_debug(csp_debug_level_t level, const char *format, ...) +{ + int color = COLOR_RESET; + va_list args; + + /* Don't print anything if log level is disabled */ + if (level > CSP_LOCK || !csp_debug_level_enabled[level]) + return; + + switch(level) { + case CSP_INFO: + color = COLOR_GREEN | COLOR_BOLD; + break; + case CSP_ERROR: + color = COLOR_RED | COLOR_BOLD; + break; + case CSP_WARN: + color = COLOR_YELLOW | COLOR_BOLD; + break; + case CSP_BUFFER: + color = COLOR_MAGENTA; + break; + case CSP_PACKET: + color = COLOR_GREEN; + break; + case CSP_PROTOCOL: + color = COLOR_BLUE; + break; + case CSP_LOCK: + color = COLOR_CYAN; + break; + default: + return; + } + + va_start(args, format); + + /* If csp_debug_hook symbol is defined, pass on the message. + * Otherwise, just print with pretty colors ... */ + if (csp_debug_hook_func) { + csp_debug_hook_func(level, format, args); + } else { + csp_sys_set_color(color); +#ifdef __AVR__ + vfprintf_P(stdout, format, args); +#else + vprintf(format, args); +#endif + printf("\r\n"); + csp_sys_set_color(COLOR_RESET); + } + + va_end(args); +} + +void csp_debug_set_level(csp_debug_level_t level, bool value) +{ + if (level > CSP_LOCK) + return; + csp_debug_level_enabled[level] = value; +} + +int csp_debug_get_level(csp_debug_level_t level) +{ + if (level > CSP_LOCK) + return 0; + return csp_debug_level_enabled[level]; +} + +void csp_debug_toggle_level(csp_debug_level_t level) +{ + if (level > CSP_LOCK) { + printf("Max level is 6\r\n"); + return; + } + csp_debug_level_enabled[level] = (csp_debug_level_enabled[level]) ? false : true; + printf("Level %u: value %u\r\n", level, csp_debug_level_enabled[level]); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_dedup.c b/gomspace/libgscsp/lib/libcsp/src/csp_dedup.c new file mode 100644 index 00000000..d263c7a4 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_dedup.c @@ -0,0 +1,66 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +#include +#include +#include + +#include "csp_dedup.h" + +/* Check the last CSP_DEDUP_COUNT packets for duplicates */ +#define CSP_DEDUP_COUNT 16 + +/* Only consider packet a duplicate if received under CSP_DEDUP_WINDOW_MS ago */ +#define CSP_DEDUP_WINDOW_MS 1000 + +/* Store packet CRC's in a ringbuffer */ +static uint32_t csp_dedup_array[CSP_DEDUP_COUNT] = {}; +static uint32_t csp_dedup_timestamp[CSP_DEDUP_COUNT] = {}; +static int csp_dedup_in = 0; + +bool csp_dedup_is_duplicate(csp_packet_t *packet) +{ + /* Calculate CRC32 for packet */ + uint32_t crc = csp_crc32_memory((const uint8_t *) &packet->id, packet->length + sizeof(packet->id)); + + /* Check if we have received this packet before */ + for (int i = 0; i < CSP_DEDUP_COUNT; i++) { + + /* Check for match */ + if (crc == csp_dedup_array[i]) { + + /* Check the timestamp */ + if (csp_get_ms() < csp_dedup_timestamp[i] + CSP_DEDUP_WINDOW_MS) + return true; + } + } + + /* If not, insert packet into duplicate list */ + csp_dedup_array[csp_dedup_in] = crc; + csp_dedup_timestamp[csp_dedup_in] = csp_get_ms(); + csp_dedup_in = (csp_dedup_in + 1) % CSP_DEDUP_COUNT; + + return false; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_dedup.h b/gomspace/libgscsp/lib/libcsp/src/csp_dedup.h new file mode 100644 index 00000000..75a3f124 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_dedup.h @@ -0,0 +1,31 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CSP_DEDUP_H_ +#define CSP_DEDUP_H_ + +/** + * Check for a duplicate packet + * @param packet pointer to packet + * @return false if not a duplicate, true if duplicate + */ +bool csp_dedup_is_duplicate(csp_packet_t *packet); + +#endif /* CSP_DEDUP_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_endian.c b/gomspace/libgscsp/lib/libcsp/src/csp_endian.c new file mode 100644 index 00000000..6d0ef226 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_endian.c @@ -0,0 +1,204 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +/* CSP includes */ +#include +#include + +/* Convert 16-bit number from host byte order to network byte order */ +inline uint16_t __attribute__ ((__const__)) csp_hton16(uint16_t h16) { +#ifdef CSP_BIG_ENDIAN + return h16; +#else + return (((h16 & 0xff00) >> 8) | + ((h16 & 0x00ff) << 8)); +#endif +} + +/* Convert 16-bit number from network byte order to host byte order */ +inline uint16_t __attribute__ ((__const__)) csp_ntoh16(uint16_t n16) { + return csp_hton16(n16); +} + +/* Convert 32-bit number from host byte order to network byte order */ +inline uint32_t __attribute__ ((__const__)) csp_hton32(uint32_t h32) { +#ifdef CSP_BIG_ENDIAN + return h32; +#else + return (((h32 & 0xff000000) >> 24) | + ((h32 & 0x000000ff) << 24) | + ((h32 & 0x0000ff00) << 8) | + ((h32 & 0x00ff0000) >> 8)); +#endif +} + +/* Convert 32-bit number from network byte order to host byte order */ +inline uint32_t __attribute__ ((__const__)) csp_ntoh32(uint32_t n32) { + return csp_hton32(n32); +} + +/* Convert 64-bit number from host byte order to network byte order */ +inline uint64_t __attribute__ ((__const__)) csp_hton64(uint64_t h64) { +#ifdef CSP_BIG_ENDIAN + return h64; +#else + return (((h64 & 0xff00000000000000LL) >> 56) | + ((h64 & 0x00000000000000ffLL) << 56) | + ((h64 & 0x00ff000000000000LL) >> 40) | + ((h64 & 0x000000000000ff00LL) << 40) | + ((h64 & 0x0000ff0000000000LL) >> 24) | + ((h64 & 0x0000000000ff0000LL) << 24) | + ((h64 & 0x000000ff00000000LL) >> 8) | + ((h64 & 0x00000000ff000000LL) << 8)); +#endif +} + +/* Convert 64-bit number from host byte order to network byte order */ +inline uint64_t __attribute__ ((__const__)) csp_ntoh64(uint64_t n64) { + return csp_hton64(n64); +} + +/* Convert 16-bit number from host byte order to big endian byte order */ +inline uint16_t __attribute__ ((__const__)) csp_htobe16(uint16_t h16) { + return csp_hton16(h16); +} + +/* Convert 16-bit number from host byte order to little endian byte order */ +inline uint16_t __attribute__ ((__const__)) csp_htole16(uint16_t h16) { +#ifdef CSP_LITTLE_ENDIAN + return h16; +#else + return (((h16 & 0xff00) >> 8) | + ((h16 & 0x00ff) << 8)); +#endif +} + +/* Convert 16-bit number from big endian byte order to little endian byte order */ +inline uint16_t __attribute__ ((__const__)) csp_betoh16(uint16_t be16) { + return csp_ntoh16(be16); +} + +/* Convert 16-bit number from little endian byte order to host byte order */ +inline uint16_t __attribute__ ((__const__)) csp_letoh16(uint16_t le16) { + return csp_htole16(le16); +} + +/* Convert 32-bit number from host byte order to big endian byte order */ +inline uint32_t __attribute__ ((__const__)) csp_htobe32(uint32_t h32) { + return csp_hton32(h32); +} + +/* Convert 32-bit number from little endian byte order to host byte order */ +inline uint32_t __attribute__ ((__const__)) csp_htole32(uint32_t h32) { +#ifdef CSP_LITTLE_ENDIAN + return h32; +#else + return (((h32 & 0xff000000) >> 24) | + ((h32 & 0x000000ff) << 24) | + ((h32 & 0x0000ff00) << 8) | + ((h32 & 0x00ff0000) >> 8)); +#endif +} + +/* Convert 32-bit number from big endian byte order to host byte order */ +inline uint32_t __attribute__ ((__const__)) csp_betoh32(uint32_t be32) { + return csp_ntoh32(be32); +} + +/* Convert 32-bit number from little endian byte order to host byte order */ +inline uint32_t __attribute__ ((__const__)) csp_letoh32(uint32_t le32) { + return csp_htole32(le32); +} + +/* Convert 64-bit number from host byte order to big endian byte order */ +inline uint64_t __attribute__ ((__const__)) csp_htobe64(uint64_t h64) { + return csp_hton64(h64); +} + +/* Convert 64-bit number from host byte order to little endian byte order */ +inline uint64_t __attribute__ ((__const__)) csp_htole64(uint64_t h64) { +#ifdef CSP_LITTLE_ENDIAN + return h64; +#else + return (((h64 & 0xff00000000000000LL) >> 56) | + ((h64 & 0x00000000000000ffLL) << 56) | + ((h64 & 0x00ff000000000000LL) >> 40) | + ((h64 & 0x000000000000ff00LL) << 40) | + ((h64 & 0x0000ff0000000000LL) >> 24) | + ((h64 & 0x0000000000ff0000LL) << 24) | + ((h64 & 0x000000ff00000000LL) >> 8) | + ((h64 & 0x00000000ff000000LL) << 8)); +#endif +} + +/* Convert 64-bit number from big endian byte order to host byte order */ +inline uint64_t __attribute__ ((__const__)) csp_betoh64(uint64_t be64) { + return csp_ntoh64(be64); +} + +/* Convert 64-bit number from little endian byte order to host byte order */ +inline uint64_t __attribute__ ((__const__)) csp_letoh64(uint64_t le64) { + return csp_htole64(le64); +} + + +/* Convert float from host byte order to network byte order */ +inline float __attribute__ ((__const__)) csp_htonflt(float f) { +#ifdef CSP_BIG_ENDIAN + return f; +#else + union v { + float f; + uint32_t i; + }; + union v val; + val.f = f; + val.i = csp_hton32(val.i); + return val.f; +#endif +} + +/* Convert float from host byte order to network byte order */ +inline float __attribute__ ((__const__)) csp_ntohflt(float f) { + return csp_htonflt(f); +} + +/* Convert double from host byte order to network byte order */ +inline double __attribute__ ((__const__)) csp_htondbl(double d) { +#ifdef CSP_BIG_ENDIAN + return d; +#else + union v { + double d; + uint64_t i; + }; + union v val; + val.d = d; + val.i = csp_hton64(val.i); + return val.d; +#endif +} + +/* Convert float from host byte order to network byte order */ +inline double __attribute__ ((__const__)) csp_ntohdbl(double d) { + return csp_htondbl(d); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_hex_dump.c b/gomspace/libgscsp/lib/libcsp/src/csp_hex_dump.c new file mode 100644 index 00000000..af0a2660 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_hex_dump.c @@ -0,0 +1,55 @@ +#include +#include + +void csp_hex_dump (const char *desc, void *addr, int len) +{ + int i; + unsigned char buff[17]; + unsigned char *pc = (unsigned char*)addr; + + // Output description if given. + if (desc != NULL) + printf ("%s:\r\n", desc); + + if (len == 0) { + printf(" ZERO LENGTH\r\n"); + return; + } + if (len < 0) { + printf(" NEGATIVE LENGTH: %i\r\n",len); + return; + } + + // Process every byte in the data. + for (i = 0; i < len; i++) { + // Multiple of 16 means new line (with line offset). + + if ((i % 16) == 0) { + // Just don't print ASCII for the zeroth line. + if (i != 0) + printf (" %s\r\n", buff); + + // Output the offset. + printf (" %p ", addr + i); + } + + // Now the hex code for the specific character. + printf (" %02x", pc[i]); + + // And store a printable ASCII character for later. + if ((pc[i] < 0x20) || (pc[i] > 0x7e)) + buff[i % 16] = '.'; + else + buff[i % 16] = pc[i]; + buff[(i % 16) + 1] = '\0'; + } + + // Pad out last line if not exactly 16 characters. + while ((i % 16) != 0) { + printf (" "); + i++; + } + + // And print the final ASCII bit. + printf (" %s\r\n", buff); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_iflist.c b/gomspace/libgscsp/lib/libcsp/src/csp_iflist.c new file mode 100644 index 00000000..2bfef422 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_iflist.c @@ -0,0 +1,100 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +/* Interfaces are stored in a linked list*/ +static csp_iface_t * interfaces = NULL; + +csp_iface_t * csp_iflist_get_by_name(const char *name) { + csp_iface_t *ifc = interfaces; + while(ifc) { + if (strncmp(ifc->name, name, 10) == 0) + break; + ifc = ifc->next; + } + return ifc; +} + +void csp_iflist_add(csp_iface_t *ifc) { + + /* Add interface to pool */ + if (interfaces == NULL) { + /* This is the first interface to be added */ + interfaces = ifc; + ifc->next = NULL; + } else { + /* One or more interfaces were already added */ + csp_iface_t * i = interfaces; + while (i != ifc && i->next) + i = i->next; + + /* Insert interface last if not already in pool */ + if (i != ifc && i->next == NULL) { + i->next = ifc; + ifc->next = NULL; + } + } + +} + +csp_iface_t * csp_iflist_get(void) +{ + return interfaces; +} + +#ifdef CSP_DEBUG +static int csp_bytesize(char *buf, int len, unsigned long int n) { + char postfix; + double size; + + if (n >= 1048576) { + size = n/1048576.0; + postfix = 'M'; + } else if (n >= 1024) { + size = n/1024.; + postfix = 'K'; + } else { + size = n; + postfix = 'B'; + } + + return snprintf(buf, len, "%.1f%c", size, postfix); +} + +void csp_iflist_print(void) { + csp_iface_t * i = interfaces; + char txbuf[25], rxbuf[25]; + + while (i) { + csp_bytesize(txbuf, 25, i->txbytes); + csp_bytesize(rxbuf, 25, i->rxbytes); + printf("%-5s tx: %05"PRIu32" rx: %05"PRIu32" txe: %05"PRIu32" rxe: %05"PRIu32"\r\n" + " drop: %05"PRIu32" autherr: %05"PRIu32 " frame: %05"PRIu32"\r\n" + " txb: %"PRIu32" (%s) rxb: %"PRIu32" (%s)\r\n\r\n", + i->name, i->tx, i->rx, i->tx_error, i->rx_error, i->drop, + i->autherr, i->frame, i->txbytes, txbuf, i->rxbytes, rxbuf); + i = i->next; + } + +} +#endif + diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_io.c b/gomspace/libgscsp/lib/libcsp/src/csp_io.c new file mode 100644 index 00000000..3d7f614a --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_io.c @@ -0,0 +1,502 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +/* CSP includes */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "csp_io.h" +#include "csp_port.h" +#include "csp_conn.h" +#include "csp_route.h" +#include "csp_promisc.h" +#include "csp_qfifo.h" +#include "transport/csp_transport.h" + +/** CSP address of this node */ +static uint8_t csp_my_address; + +/* Hostname, model and build revision */ +static const char *csp_hostname = NULL; +static const char *csp_model = NULL; +static const char *csp_revision = GIT_REV; + +#ifdef CSP_USE_PROMISC +extern csp_queue_handle_t csp_promisc_queue; +#endif + +void csp_set_address(uint8_t addr) +{ + csp_my_address = addr; +} + +uint8_t csp_get_address(void) +{ + return csp_my_address; +} + +void csp_set_hostname(const char *hostname) +{ + csp_hostname = hostname; +} + +const char *csp_get_hostname(void) +{ + return csp_hostname; +} + +void csp_set_model(const char *model) +{ + csp_model = model; +} + +const char *csp_get_model(void) +{ + return csp_model; +} + +void csp_set_revision(const char *revision) +{ + csp_revision = revision; +} + +const char *csp_get_revision(void) +{ + return csp_revision; +} + +int csp_init(unsigned char address) { + + int ret; + + /* Initialize CSP */ + csp_set_address(address); + + ret = csp_conn_init(); + if (ret != CSP_ERR_NONE) + return ret; + + ret = csp_port_init(); + if (ret != CSP_ERR_NONE) + return ret; + + ret = csp_qfifo_init(); + if (ret != CSP_ERR_NONE) + return ret; + + /* Loopback */ + csp_iflist_add(&csp_if_lo); + + /* Register loopback route */ + csp_route_set(csp_get_address(), &csp_if_lo, CSP_NODE_MAC); + + /* Also register loopback as default, until user redefines default route */ + csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_lo, CSP_NODE_MAC); + + return CSP_ERR_NONE; + +} + +csp_socket_t * csp_socket(uint32_t opts) { + + /* Validate socket options */ +#ifndef CSP_USE_RDP + if (opts & CSP_SO_RDPREQ) { + csp_log_error("Attempt to create socket that requires RDP, but CSP was compiled without RDP support"); + return NULL; + } +#endif + +#ifndef CSP_USE_XTEA + if (opts & CSP_SO_XTEAREQ) { + csp_log_error("Attempt to create socket that requires XTEA, but CSP was compiled without XTEA support"); + return NULL; + } +#endif + +#ifndef CSP_USE_HMAC + if (opts & CSP_SO_HMACREQ) { + csp_log_error("Attempt to create socket that requires HMAC, but CSP was compiled without HMAC support"); + return NULL; + } +#endif + +#ifndef CSP_USE_CRC32 + if (opts & CSP_SO_CRC32REQ) { + csp_log_error("Attempt to create socket that requires CRC32, but CSP was compiled without CRC32 support"); + return NULL; + } +#endif + + /* Drop packet if reserved flags are set */ + if (opts & ~(CSP_SO_RDPREQ | CSP_SO_XTEAREQ | CSP_SO_HMACREQ | CSP_SO_CRC32REQ | CSP_SO_CONN_LESS)) { + csp_log_error("Invalid socket option"); + return NULL; + } + + /* Use CSP buffers instead? */ + csp_socket_t * sock = csp_conn_allocate(CONN_SERVER); + if (sock == NULL) + return NULL; + + /* If connectionless, init the queue to a pre-defined size + * if not, the user must init the queue using csp_listen */ + if (opts & CSP_SO_CONN_LESS) { + sock->socket = csp_queue_create(CSP_CONN_QUEUE_LENGTH, sizeof(csp_packet_t *)); + if (sock->socket == NULL) { + csp_close(sock); + return NULL; + } + } else { + sock->socket = NULL; + } + sock->opts = opts; + + return sock; + +} + +csp_conn_t * csp_accept(csp_socket_t * sock, uint32_t timeout) { + + if (sock == NULL) + return NULL; + + if (sock->socket == NULL) + return NULL; + + csp_conn_t * conn; + if (csp_queue_dequeue(sock->socket, &conn, timeout) == CSP_QUEUE_OK) + return conn; + + return NULL; + +} + +csp_packet_t * csp_read(csp_conn_t * conn, uint32_t timeout) { + + csp_packet_t * packet = NULL; + + if (conn == NULL || conn->state != CONN_OPEN) + return NULL; + +#ifdef CSP_USE_QOS + int prio, event; + if (csp_queue_dequeue(conn->rx_event, &event, timeout) != CSP_QUEUE_OK) + return NULL; + + for (prio = 0; prio < CSP_RX_QUEUES; prio++) + if (csp_queue_dequeue(conn->rx_queue[prio], &packet, 0) == CSP_QUEUE_OK) + break; +#else + if (csp_queue_dequeue(conn->rx_queue[0], &packet, timeout) != CSP_QUEUE_OK) + return NULL; +#endif + +#ifdef CSP_USE_RDP + /* Packet read could trigger ACK transmission */ + if (conn->idin.flags & CSP_FRDP && conn->rdp.delayed_acks) + csp_rdp_check_ack(conn); + +#endif + + return packet; + +} + +int csp_send_direct(csp_id_t idout, csp_packet_t * packet, csp_iface_t * ifout, uint32_t timeout) { + + if (packet == NULL) { + csp_log_error("csp_send_direct called with NULL packet"); + goto err; + } + + if ((ifout == NULL) || (ifout->nexthop == NULL)) { + csp_log_error("No route to host: %#08x", idout.ext); + goto err; + } + + csp_log_packet("OUT: S %u, D %u, Dp %u, Sp %u, Pr %u, Fl 0x%02X, Sz %u VIA: %s", + idout.src, idout.dst, idout.dport, idout.sport, idout.pri, idout.flags, packet->length, ifout->name); + + /* Copy identifier to packet (before crc, xtea and hmac) */ + packet->id.ext = idout.ext; + +#ifdef CSP_USE_PROMISC + /* Loopback traffic is added to promisc queue by the router */ + if (idout.dst != csp_get_address() && idout.src == csp_get_address()) { + packet->id.ext = idout.ext; + csp_promisc_add(packet); + } +#endif + + /* Only encrypt packets from the current node */ + if (idout.src == csp_get_address()) { + /* Append HMAC */ + if (idout.flags & CSP_FHMAC) { +#ifdef CSP_USE_HMAC + /* Calculate and add HMAC (does not include header for backwards compatability with csp1.x) */ + if (csp_hmac_append(packet, false) != 0) { + /* HMAC append failed */ + csp_log_warn("HMAC append failed!"); + goto tx_err; + } +#else + csp_log_warn("Attempt to send packet with HMAC, but CSP was compiled without HMAC support. Discarding packet"); + goto tx_err; +#endif + } + + /* Append CRC32 */ + if (idout.flags & CSP_FCRC32) { +#ifdef CSP_USE_CRC32 + /* Calculate and add CRC32 (does not include header for backwards compatability with csp1.x) */ + if (csp_crc32_append(packet, false) != 0) { + /* CRC32 append failed */ + csp_log_warn("CRC32 append failed!"); + goto tx_err; + } +#else + csp_log_warn("Attempt to send packet with CRC32, but CSP was compiled without CRC32 support. Sending without CRC32r"); + idout.flags &= ~(CSP_FCRC32); +#endif + } + + if (idout.flags & CSP_FXTEA) { +#ifdef CSP_USE_XTEA + /* Create nonce */ + uint32_t nonce, nonce_n; + nonce = (uint32_t)rand(); + nonce_n = csp_hton32(nonce); + memcpy(&packet->data[packet->length], &nonce_n, sizeof(nonce_n)); + + /* Create initialization vector */ + uint32_t iv[2] = {nonce, 1}; + + /* Encrypt data */ + if (csp_xtea_encrypt(packet->data, packet->length, iv) != 0) { + /* Encryption failed */ + csp_log_warn("Encryption failed! Discarding packet"); + goto tx_err; + } + + packet->length += sizeof(nonce_n); +#else + csp_log_warn("Attempt to send XTEA encrypted packet, but CSP was compiled without XTEA support. Discarding packet"); + goto tx_err; +#endif + } + } + + /* Store length before passing to interface */ + uint16_t bytes = packet->length; + uint16_t mtu = ifout->mtu; + + if (mtu > 0 && bytes > mtu) + goto tx_err; + + if ((*ifout->nexthop)(ifout, packet, timeout) != CSP_ERR_NONE) + goto tx_err; + + ifout->tx++; + ifout->txbytes += bytes; + return CSP_ERR_NONE; + +tx_err: + ifout->tx_error++; +err: + return CSP_ERR_TX; + +} + +int csp_send(csp_conn_t * conn, csp_packet_t * packet, uint32_t timeout) { + + int ret; + + if ((conn == NULL) || (packet == NULL) || (conn->state != CONN_OPEN)) { + csp_log_error("Invalid call to csp_send"); + return 0; + } + +#ifdef CSP_USE_RDP + if (conn->idout.flags & CSP_FRDP) { + if (csp_rdp_send(conn, packet, timeout) != CSP_ERR_NONE) { + csp_iface_t * ifout = csp_rtable_find_iface(conn->idout.dst); + if (ifout != NULL) + ifout->tx_error++; + csp_log_warn("RDP send failed!"); + return 0; + } + } +#endif + + csp_iface_t * ifout = csp_rtable_find_iface(conn->idout.dst); + ret = csp_send_direct(conn->idout, packet, ifout, timeout); + + return (ret == CSP_ERR_NONE) ? 1 : 0; + +} + +int csp_send_prio(uint8_t prio, csp_conn_t * conn, csp_packet_t * packet, uint32_t timeout) { + conn->idout.pri = prio; + return csp_send(conn, packet, timeout); +} + +int csp_transaction_persistent(csp_conn_t * conn, uint32_t timeout, void * outbuf, int outlen, void * inbuf, int inlen) { + + int size = (inlen > outlen) ? inlen : outlen; + csp_packet_t * packet = csp_buffer_get(size); + if (packet == NULL) + return 0; + + /* Copy the request */ + if (outlen > 0 && outbuf != NULL) + memcpy(packet->data, outbuf, outlen); + packet->length = outlen; + + if (!csp_send(conn, packet, timeout)) { + csp_buffer_free(packet); + return 0; + } + + /* If no reply is expected, return now */ + if (inlen == 0) + return 1; + + packet = csp_read(conn, timeout); + if (packet == NULL) + return 0; + + if ((inlen != -1) && ((int)packet->length != inlen)) { + csp_log_error("Reply length %u expected %u", packet->length, inlen); + csp_buffer_free(packet); + return 0; + } + + memcpy(inbuf, packet->data, packet->length); + int length = packet->length; + csp_buffer_free(packet); + return length; + +} + +int csp_transaction(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, void * outbuf, int outlen, void * inbuf, int inlen) { + return csp_transaction2(prio, dest, port, timeout, outbuf, outlen, inbuf, inlen, 0); +} + +int csp_transaction2(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, void * outbuf, int outlen, void * inbuf, int inlen, uint32_t opts) { + + csp_conn_t * conn = csp_connect(prio, dest, port, 0, opts); + if (conn == NULL) + return 0; + + int status = csp_transaction_persistent(conn, timeout, outbuf, outlen, inbuf, inlen); + + csp_close(conn); + + return status; + +} + +csp_packet_t * csp_recvfrom(csp_socket_t * socket, uint32_t timeout) { + + if ((socket == NULL) || (!(socket->opts & CSP_SO_CONN_LESS))) + return NULL; + + csp_packet_t * packet = NULL; + csp_queue_dequeue(socket->socket, &packet, timeout); + + return packet; + +} + +int csp_sendto(uint8_t prio, uint8_t dest, uint8_t dport, uint8_t src_port, uint32_t opts, csp_packet_t * packet, uint32_t timeout) { + + packet->id.flags = 0; + + if (opts & CSP_O_RDP) { + csp_log_error("Attempt to create RDP packet on connection-less socket"); + return CSP_ERR_INVAL; + } + + if (opts & CSP_O_HMAC) { +#ifdef CSP_USE_HMAC + packet->id.flags |= CSP_FHMAC; +#else + csp_log_error("Attempt to create HMAC authenticated packet, but CSP was compiled without HMAC support"); + return CSP_ERR_NOTSUP; +#endif + } + + if (opts & CSP_O_XTEA) { +#ifdef CSP_USE_XTEA + packet->id.flags |= CSP_FXTEA; +#else + csp_log_error("Attempt to create XTEA encrypted packet, but CSP was compiled without XTEA support"); + return CSP_ERR_NOTSUP; +#endif + } + + if (opts & CSP_O_CRC32) { +#ifdef CSP_USE_CRC32 + packet->id.flags |= CSP_FCRC32; +#else + csp_log_error("Attempt to create CRC32 validated packet, but CSP was compiled without CRC32 support"); + return CSP_ERR_NOTSUP; +#endif + } + + packet->id.dst = dest; + packet->id.dport = dport; + packet->id.src = csp_get_address(); + packet->id.sport = src_port; + packet->id.pri = prio; + + csp_iface_t * ifout = csp_rtable_find_iface(dest); + if (csp_send_direct(packet->id, packet, ifout, timeout) != CSP_ERR_NONE) + return CSP_ERR_NOTSUP; + + return CSP_ERR_NONE; + +} + +int csp_sendto_reply(csp_packet_t * request_packet, csp_packet_t * reply_packet, uint32_t opts, uint32_t timeout) { + if (request_packet == NULL) + return CSP_ERR_INVAL; + + return csp_sendto(request_packet->id.pri, request_packet->id.src, request_packet->id.sport, request_packet->id.dport, opts, reply_packet, timeout); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_io.h b/gomspace/libgscsp/lib/libcsp/src/csp_io.h new file mode 100644 index 00000000..6ea8dfec --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_io.h @@ -0,0 +1,47 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_IO_H_ +#define _CSP_IO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +/** + * Function to transmit a frame without an existing connection structure. + * This function is used for stateless transmissions + * @param idout 32bit CSP identifier + * @param packet pointer to packet, + * @param ifout pointer to output interface + * @param timeout a timeout to wait for TX to complete. NOTE: not all underlying drivers supports flow-control. + * @return returns 1 if successful and 0 otherwise. you MUST free the frame yourself if the transmission was not successful. + */ +int csp_send_direct(csp_id_t idout, csp_packet_t * packet, csp_iface_t * ifout, uint32_t timeout); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_IO_H_ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_port.c b/gomspace/libgscsp/lib/libcsp/src/csp_port.c new file mode 100644 index 00000000..2a4ac2a9 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_port.c @@ -0,0 +1,105 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +/* CSP includes */ +#include +#include + +#include +#include +#include + +#include "csp_port.h" +#include "csp_conn.h" + +/* Allocation of ports */ +static csp_port_t ports[CSP_MAX_BIND_PORT + 2]; + +csp_socket_t * csp_port_get_socket(unsigned int port) { + + csp_socket_t * ret = NULL; + + if (port >= CSP_ANY) + return NULL; + + /* Match dport to socket or local "catch all" port number */ + if (ports[port].state == PORT_OPEN) + ret = ports[port].socket; + else if (ports[CSP_ANY].state == PORT_OPEN) + ret = ports[CSP_ANY].socket; + + return ret; + +} + +int csp_port_init(void) { + + memset(ports, PORT_CLOSED, sizeof(csp_port_t) * (CSP_MAX_BIND_PORT + 2)); + + return CSP_ERR_NONE; + +} + +int csp_listen(csp_socket_t * socket, size_t conn_queue_length) { + + if (socket == NULL) + return CSP_ERR_INVAL; + + socket->socket = csp_queue_create(conn_queue_length, sizeof(csp_conn_t *)); + if (socket->socket == NULL) + return CSP_ERR_NOMEM; + + socket->opts |= CSP_SO_INTERNAL_LISTEN; + + return CSP_ERR_NONE; + +} + +int csp_bind(csp_socket_t * socket, uint8_t port) { + + if (socket == NULL) + return CSP_ERR_INVAL; + + if (port > CSP_ANY) { + csp_log_error("Only ports from 0-%u (and CSP_ANY for default) are available for incoming ports", CSP_ANY); + return CSP_ERR_INVAL; + } + + /* Check if port number is valid */ + if (ports[port].state != PORT_CLOSED) { + csp_log_error("Port %d is already in use", port); + return CSP_ERR_USED; + } + + csp_log_info("Binding socket %p to port %u", socket, port); + + /* Save listener */ + ports[port].socket = socket; + ports[port].state = PORT_OPEN; + + return CSP_ERR_NONE; + +} + + diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_port.h b/gomspace/libgscsp/lib/libcsp/src/csp_port.h new file mode 100644 index 00000000..d2ec06e9 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_port.h @@ -0,0 +1,55 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_PORT_H_ +#define _CSP_PORT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +/** @brief Port states */ +typedef enum { + PORT_CLOSED = 0, + PORT_OPEN = 1, +} csp_port_state_t; + +/** @brief Port struct */ +typedef struct { + csp_port_state_t state; // Port state + csp_socket_t * socket; // New connections are added to this socket's conn queue +} csp_port_t; + +/** + * Init ports array + */ +int csp_port_init(void); + +csp_socket_t * csp_port_get_socket(unsigned int dport); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // _CSP_PORT_H_ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_promisc.c b/gomspace/libgscsp/lib/libcsp/src/csp_promisc.c new file mode 100644 index 00000000..5f156c33 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_promisc.c @@ -0,0 +1,82 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +#ifdef CSP_USE_PROMISC + +static csp_queue_handle_t csp_promisc_queue = NULL; +static int csp_promisc_enabled = 0; + +int csp_promisc_enable(unsigned int buf_size) { + + /* If queue already initialised */ + if (csp_promisc_queue != NULL) { + csp_promisc_enabled = 1; + return CSP_ERR_NONE; + } + + /* Create packet queue */ + csp_promisc_queue = csp_queue_create(buf_size, sizeof(csp_packet_t *)); + + if (csp_promisc_queue == NULL) + return CSP_ERR_INVAL; + + csp_promisc_enabled = 1; + return CSP_ERR_NONE; + +} + +void csp_promisc_disable(void) { + csp_promisc_enabled = 0; +} + +csp_packet_t * csp_promisc_read(uint32_t timeout) { + + if (csp_promisc_queue == NULL) + return NULL; + + csp_packet_t * packet = NULL; + csp_queue_dequeue(csp_promisc_queue, &packet, timeout); + + return packet; + +} + +void csp_promisc_add(csp_packet_t * packet) { + + if (csp_promisc_enabled == 0) + return; + + if (csp_promisc_queue != NULL) { + /* Make a copy of the message and queue it to the promiscuous task */ + csp_packet_t *packet_copy = csp_buffer_clone(packet); + if (packet_copy != NULL) { + if (csp_queue_enqueue(csp_promisc_queue, &packet_copy, 0) != CSP_QUEUE_OK) { + csp_log_error("Promiscuous mode input queue full"); + csp_buffer_free(packet_copy); + } + } + } + +} + +#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_promisc.h b/gomspace/libgscsp/lib/libcsp/src/csp_promisc.h new file mode 100644 index 00000000..be62edda --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_promisc.h @@ -0,0 +1,30 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CSP_PROMISC_H_ +#define CSP_PROMISC_H_ + +/** + * Add packet to promiscuous mode packet queue + * @param packet Packet to add to the queue + */ +void csp_promisc_add(csp_packet_t * packet); + +#endif /* CSP_PROMISC_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c b/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c new file mode 100644 index 00000000..9329b2ca --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c @@ -0,0 +1,149 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include "csp_qfifo.h" + +static csp_queue_handle_t qfifo[CSP_ROUTE_FIFOS]; +#ifdef CSP_USE_QOS +static csp_queue_handle_t qfifo_events; +#endif + +int csp_qfifo_init(void) { + int prio; + + /* Create router fifos for each priority */ + for (prio = 0; prio < CSP_ROUTE_FIFOS; prio++) { + if (qfifo[prio] == NULL) { + qfifo[prio] = csp_queue_create(CSP_FIFO_INPUT, sizeof(csp_qfifo_t)); + if (!qfifo[prio]) + return CSP_ERR_NOMEM; + } + } + +#ifdef CSP_USE_QOS + /* Create QoS fifo notification queue */ + qfifo_events = csp_queue_create(CSP_FIFO_INPUT, sizeof(int)); + if (!qfifo_events) + return CSP_ERR_NOMEM; +#endif + + return CSP_ERR_NONE; + +} + +int csp_qfifo_read(csp_qfifo_t * input) { + +#ifdef CSP_USE_QOS + int prio, found, event; + + /* Wait for packet in any queue */ + if (csp_queue_dequeue(qfifo_events, &event, FIFO_TIMEOUT) != CSP_QUEUE_OK) + return CSP_ERR_TIMEDOUT; + + /* Find packet with highest priority */ + found = 0; + for (prio = 0; prio < CSP_ROUTE_FIFOS; prio++) { + if (csp_queue_dequeue(qfifo[prio], input, 0) == CSP_QUEUE_OK) { + found = 1; + break; + } + } + + if (!found) { + csp_log_warn("Spurious wakeup: No packet found"); + return CSP_ERR_TIMEDOUT; + } +#else + if (csp_queue_dequeue(qfifo[0], input, FIFO_TIMEOUT) != CSP_QUEUE_OK) + return CSP_ERR_TIMEDOUT; +#endif + + return CSP_ERR_NONE; + +} + +void csp_qfifo_write(csp_packet_t * packet, csp_iface_t * interface, CSP_BASE_TYPE * pxTaskWoken) { + + int result; + + if (packet == NULL) { + if (pxTaskWoken == NULL) { // Only do logging in non-ISR context + csp_log_warn("csp_new packet called with NULL packet"); + } + return; + } else if (interface == NULL) { + if (pxTaskWoken == NULL) { // Only do logging in non-ISR context + csp_log_warn("csp_new packet called with NULL interface"); + } + if (pxTaskWoken == NULL) + csp_buffer_free(packet); + else + csp_buffer_free_isr(packet); + return; + } + + csp_qfifo_t queue_element; + queue_element.interface = interface; + queue_element.packet = packet; + +#ifdef CSP_USE_QOS + int fifo = packet->id.pri; +#else + int fifo = 0; +#endif + + if (pxTaskWoken == NULL) + result = csp_queue_enqueue(qfifo[fifo], &queue_element, 0); + else + result = csp_queue_enqueue_isr(qfifo[fifo], &queue_element, pxTaskWoken); + +#ifdef CSP_USE_QOS + static int event = 0; + + if (result == CSP_QUEUE_OK) { + if (pxTaskWoken == NULL) + csp_queue_enqueue(qfifo_events, &event, 0); + else + csp_queue_enqueue_isr(qfifo_events, &event, pxTaskWoken); + } +#endif + + if (result != CSP_QUEUE_OK) { + if (pxTaskWoken == NULL) { // Only do logging in non-ISR context + csp_log_warn("ERROR: Routing input FIFO is FULL. Dropping packet."); + } + interface->drop++; + if (pxTaskWoken == NULL) + csp_buffer_free(packet); + else + csp_buffer_free_isr(packet); + } + +} + +void csp_qfifo_wake_up(void) { + csp_qfifo_t queue_element; + queue_element.interface = NULL; + queue_element.packet = NULL; + csp_queue_enqueue(qfifo[0], &queue_element, 0); +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h b/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h new file mode 100644 index 00000000..2910c48d --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h @@ -0,0 +1,54 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CSP_QFIFO_H_ +#define CSP_QFIFO_H_ + +#ifdef CSP_USE_RDP +#define FIFO_TIMEOUT 100 //! If RDP is enabled, the router needs to awake some times to check timeouts +#else +#define FIFO_TIMEOUT CSP_MAX_DELAY //! If no RDP, the router can sleep untill data arrives +#endif + +/** + * Init FIFO/QOS queues + * @return CSP_ERR type + */ +int csp_qfifo_init(void); + +typedef struct { + csp_iface_t * interface; + csp_packet_t * packet; +} csp_qfifo_t; + +/** + * Read next packet from router input queue + * @param input pointer to router queue item element + * @return CSP_ERR type + */ +int csp_qfifo_read(csp_qfifo_t * input); + +/** + * Wake up any task (e.g. router) waiting on messages. + * For testing. + */ +void csp_qfifo_wake_up(void); + +#endif /* CSP_QFIFO_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_route.c b/gomspace/libgscsp/lib/libcsp/src/csp_route.c new file mode 100644 index 00000000..bc843577 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_route.c @@ -0,0 +1,346 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +/* CSP includes */ +#include +#include +#include + +#include +#include + +#include +#include + +#include "csp_port.h" +#include "csp_conn.h" +#include "csp_io.h" +#include "csp_promisc.h" +#include "csp_qfifo.h" +#include "csp_dedup.h" +#include "transport/csp_transport.h" + +/** + * Check supported packet options + * @param interface pointer to incoming interface + * @param packet pointer to packet + * @return CSP_ERR_NONE is all options are supported, CSP_ERR_NOTSUP if not + */ +static int csp_route_check_options(csp_iface_t *interface, csp_packet_t *packet) +{ +#ifndef CSP_USE_XTEA + /* Drop XTEA packets */ + if (packet->id.flags & CSP_FXTEA) { + csp_log_error("Received XTEA encrypted packet, but CSP was compiled without XTEA support. Discarding packet"); + interface->autherr++; + return CSP_ERR_NOTSUP; + } +#endif + +#ifndef CSP_USE_HMAC + /* Drop HMAC packets */ + if (packet->id.flags & CSP_FHMAC) { + csp_log_error("Received packet with HMAC, but CSP was compiled without HMAC support. Discarding packet"); + interface->autherr++; + return CSP_ERR_NOTSUP; + } +#endif + +#ifndef CSP_USE_RDP + /* Drop RDP packets */ + if (packet->id.flags & CSP_FRDP) { + csp_log_error("Received RDP packet, but CSP was compiled without RDP support. Discarding packet"); + interface->rx_error++; + return CSP_ERR_NOTSUP; + } +#endif + return CSP_ERR_NONE; +} + +/** + * Helper function to decrypt, check auth and CRC32 + * @param security_opts either socket_opts or conn_opts + * @param interface pointer to incoming interface + * @param packet pointer to packet + * @return -1 Missing feature, -2 XTEA error, -3 CRC error, -4 HMAC error, 0 = OK. + */ +static int csp_route_security_check(uint32_t security_opts, csp_iface_t * interface, csp_packet_t * packet) { + +#ifdef CSP_USE_XTEA + /* XTEA encrypted packet */ + if (packet->id.flags & CSP_FXTEA) { + /* Read nonce */ + uint32_t nonce; + memcpy(&nonce, &packet->data[packet->length - sizeof(nonce)], sizeof(nonce)); + nonce = csp_ntoh32(nonce); + packet->length -= sizeof(nonce); + + /* Create initialization vector */ + uint32_t iv[2] = {nonce, 1}; + + /* Decrypt data */ + if (csp_xtea_decrypt(packet->data, packet->length, iv) != 0) { + /* Decryption failed */ + csp_log_error("Decryption failed! Discarding packet"); + interface->autherr++; + return CSP_ERR_XTEA; + } + } else if (security_opts & CSP_SO_XTEAREQ) { + csp_log_warn("Received packet without XTEA encryption. Discarding packet"); + interface->autherr++; + return CSP_ERR_XTEA; + } +#endif + + /* CRC32 verified packet */ + if (packet->id.flags & CSP_FCRC32) { +#ifdef CSP_USE_CRC32 + if (packet->length < 4) + csp_log_error("Too short packet for CRC32, %u", packet->length); + /* Verify CRC32 (does not include header for backwards compatability with csp1.x) */ + if (csp_crc32_verify(packet, false) != 0) { + /* Checksum failed */ + csp_log_error("CRC32 verification error! Discarding packet"); + interface->rx_error++; + return CSP_ERR_CRC32; + } + } else if (security_opts & CSP_SO_CRC32REQ) { + csp_log_warn("Received packet without CRC32. Accepting packet"); +#else + /* Strip CRC32 field and accept the packet */ + csp_log_warn("Received packet with CRC32, but CSP was compiled without CRC32 support. Accepting packet"); + packet->length -= sizeof(uint32_t); +#endif + } + +#ifdef CSP_USE_HMAC + /* HMAC authenticated packet */ + if (packet->id.flags & CSP_FHMAC) { + /* Verify HMAC (does not include header for backwards compatability with csp1.x) */ + if (csp_hmac_verify(packet, false) != 0) { + /* HMAC failed */ + csp_log_error("HMAC verification error! Discarding packet"); + interface->autherr++; + return CSP_ERR_HMAC; + } + } else if (security_opts & CSP_SO_HMACREQ) { + csp_log_warn("Received packet without HMAC. Discarding packet"); + interface->autherr++; + return CSP_ERR_HMAC; + } +#endif + +#ifdef CSP_USE_RDP + /* RDP packet */ + if (!(packet->id.flags & CSP_FRDP)) { + if (security_opts & CSP_SO_RDPREQ) { + csp_log_warn("Received packet without RDP header. Discarding packet"); + interface->rx_error++; + return CSP_ERR_INVAL; + } + } +#endif + + return CSP_ERR_NONE; + +} + +int csp_route_work(uint32_t timeout) { + + csp_qfifo_t input; + csp_packet_t * packet; + csp_conn_t * conn; + csp_socket_t * socket; + +#ifdef CSP_USE_RDP + /* Check connection timeouts (currently only for RDP) */ + csp_conn_check_timeouts(); +#endif + + /* Get next packet to route */ + if (csp_qfifo_read(&input) != CSP_ERR_NONE) + return -1; + + packet = input.packet; + if (!packet) + return -1; + + csp_log_packet("INP: S %u, D %u, Dp %u, Sp %u, Pr %u, Fl 0x%02X, Sz %"PRIu16" VIA: %s", + packet->id.src, packet->id.dst, packet->id.dport, + packet->id.sport, packet->id.pri, packet->id.flags, packet->length, input.interface->name); + + /* Here there be promiscuous mode */ +#ifdef CSP_USE_PROMISC + csp_promisc_add(packet); +#endif + +#ifdef CSP_USE_DEDUP + /* Check for duplicates */ + if (csp_dedup_is_duplicate(packet)) { + /* Discard packet */ + csp_log_packet("Duplicate packet discarded"); + input.interface->drop++; + csp_buffer_free(packet); + return 0; + } +#endif + + /* Now we count the message (since its deduplicated) */ + input.interface->rx++; + input.interface->rxbytes += packet->length; + + /* If the message is not to me, route the message to the correct interface */ + if ((packet->id.dst != csp_get_address()) && (packet->id.dst != CSP_BROADCAST_ADDR)) { + + /* Find the destination interface */ + csp_iface_t * dstif = csp_rtable_find_iface(packet->id.dst); + + /* If the message resolves to the input interface, don't loop it back out */ + if ((dstif == NULL) || ((dstif == input.interface) && (input.interface->split_horizon_off == 0))) { + csp_buffer_free(packet); + return 0; + } + + /* Otherwise, actually send the message */ + if (csp_send_direct(packet->id, packet, dstif, 0) != CSP_ERR_NONE) { + csp_log_warn("Router failed to send"); + csp_buffer_free(packet); + } + + /* Next message, please */ + return 0; + } + + /* Discard packets with unsupported options */ + if (csp_route_check_options(input.interface, packet) != CSP_ERR_NONE) { + csp_buffer_free(packet); + return 0; + } + + /* The message is to me, search for incoming socket */ + socket = csp_port_get_socket(packet->id.dport); + + /* If the socket is connection-less, deliver now */ + if (socket && (socket->opts & CSP_SO_CONN_LESS)) { + if (csp_route_security_check(socket->opts, input.interface, packet) < 0) { + csp_buffer_free(packet); + return 0; + } + if (csp_queue_enqueue(socket->socket, &packet, 0) != CSP_QUEUE_OK) { + csp_log_error("Conn-less socket queue full"); + csp_buffer_free(packet); + return 0; + } + return 0; + } + + /* Search for an existing connection */ + conn = csp_conn_find(packet->id.ext, CSP_ID_CONN_MASK); + + /* If this is an incoming packet on a new connection */ + if (conn == NULL) { + + /* Reject packet if no matching socket is found */ + if (!socket) { + csp_buffer_free(packet); + return 0; + } + + /* Run security check on incoming packet */ + if (csp_route_security_check(socket->opts, input.interface, packet) < 0) { + csp_buffer_free(packet); + return 0; + } + + /* New incoming connection accepted */ + csp_id_t idout; + idout.pri = packet->id.pri; + idout.src = csp_get_address(); + + idout.dst = packet->id.src; + idout.dport = packet->id.sport; + idout.sport = packet->id.dport; + idout.flags = packet->id.flags; + + /* Create connection */ + conn = csp_conn_new(packet->id, idout); + + if (!conn) { + csp_log_error("No more connections available"); + csp_buffer_free(packet); + return 0; + } + + /* Store the socket queue and options */ + conn->socket = socket->socket; + conn->opts = socket->opts; + + /* Packet to existing connection */ + } else { + + /* Run security check on incoming packet */ + if (csp_route_security_check(conn->opts, input.interface, packet) < 0) { + csp_buffer_free(packet); + return 0; + } + + } + +#ifdef CSP_USE_RDP + /* Pass packet to RDP module */ + if (packet->id.flags & CSP_FRDP) { + csp_rdp_new_packet(conn, packet); + return 0; + } +#endif + + /* Pass packet to UDP module */ + csp_udp_new_packet(conn, packet); + return 0; +} + +static CSP_DEFINE_TASK(csp_task_router) { + + /* Here there be routing */ + while (1) { + csp_route_work(FIFO_TIMEOUT); + } + + return CSP_TASK_RETURN; + +} + +int csp_route_start_task(unsigned int task_stack_size, unsigned int priority) { + + static csp_thread_handle_t handle_router; + int ret = csp_thread_create(csp_task_router, "RTE", task_stack_size, NULL, priority, &handle_router); + + if (ret != 0) { + csp_log_error("Failed to start router task"); + return CSP_ERR_NOMEM; + } + + return CSP_ERR_NONE; + +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_route.h b/gomspace/libgscsp/lib/libcsp/src/csp_route.h new file mode 100644 index 00000000..2a20f49f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_route.h @@ -0,0 +1,24 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_ROUTE_H_ +#define _CSP_ROUTE_H_ + +#endif // _CSP_ROUTE_H_ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_service_handler.c b/gomspace/libgscsp/lib/libcsp/src/csp_service_handler.c new file mode 100644 index 00000000..0090afc1 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_service_handler.c @@ -0,0 +1,334 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +/* CSP includes */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "csp_route.h" + +#define CSP_RPS_MTU 196 + +/** + * The CSP CMP mempy function is used to, override the function used to + * read/write memory by peek and poke. + */ +#ifdef __AVR__ +static uint32_t wrap_32bit_memcpy(uint32_t to, const uint32_t from, size_t size) { + return (uint32_t) (uintptr_t) memcpy((void *) (uintptr_t) to, (const void *) (uintptr_t) from, size); +} +static csp_memcpy_fnc_t csp_cmp_memcpy_fnc = wrap_32bit_memcpy; +#else +static csp_memcpy_fnc_t csp_cmp_memcpy_fnc = (csp_memcpy_fnc_t) memcpy; +#endif + + +void csp_cmp_set_memcpy(csp_memcpy_fnc_t fnc) { + csp_cmp_memcpy_fnc = fnc; +} + +static int do_cmp_ident(struct csp_cmp_message *cmp) { + + /* Copy revision */ + strncpy(cmp->ident.revision, csp_get_revision(), CSP_CMP_IDENT_REV_LEN); + cmp->ident.revision[CSP_CMP_IDENT_REV_LEN - 1] = '\0'; + + /* Copy compilation date */ + strncpy(cmp->ident.date, __DATE__, CSP_CMP_IDENT_DATE_LEN); + cmp->ident.date[CSP_CMP_IDENT_DATE_LEN - 1] = '\0'; + + /* Copy compilation time */ + strncpy(cmp->ident.time, __TIME__, CSP_CMP_IDENT_TIME_LEN); + cmp->ident.time[CSP_CMP_IDENT_TIME_LEN - 1] = '\0'; + + /* Copy hostname */ + strncpy(cmp->ident.hostname, csp_get_hostname(), CSP_HOSTNAME_LEN); + cmp->ident.hostname[CSP_HOSTNAME_LEN - 1] = '\0'; + + /* Copy model name */ + strncpy(cmp->ident.model, csp_get_model(), CSP_MODEL_LEN); + cmp->ident.model[CSP_MODEL_LEN - 1] = '\0'; + + return CSP_ERR_NONE; + +} + +static int do_cmp_route_set(struct csp_cmp_message *cmp) { + + csp_iface_t *ifc = csp_iflist_get_by_name(cmp->route_set.interface); + if (ifc == NULL) + return CSP_ERR_INVAL; + + if (csp_route_set(cmp->route_set.dest_node, ifc, cmp->route_set.next_hop_mac) != CSP_ERR_NONE) + return CSP_ERR_INVAL; + + return CSP_ERR_NONE; + +} + +static int do_cmp_if_stats(struct csp_cmp_message *cmp) { + + csp_iface_t *ifc = csp_iflist_get_by_name(cmp->if_stats.interface); + if (ifc == NULL) + return CSP_ERR_INVAL; + + cmp->if_stats.tx = csp_hton32(ifc->tx); + cmp->if_stats.rx = csp_hton32(ifc->rx); + cmp->if_stats.tx_error = csp_hton32(ifc->tx_error); + cmp->if_stats.rx_error = csp_hton32(ifc->rx_error); + cmp->if_stats.drop = csp_hton32(ifc->drop); + cmp->if_stats.autherr = csp_hton32(ifc->autherr); + cmp->if_stats.frame = csp_hton32(ifc->frame); + cmp->if_stats.txbytes = csp_hton32(ifc->txbytes); + cmp->if_stats.rxbytes = csp_hton32(ifc->rxbytes); + cmp->if_stats.irq = csp_hton32(ifc->irq); + + return CSP_ERR_NONE; +} + +static int do_cmp_peek(struct csp_cmp_message *cmp) { + + cmp->peek.addr = csp_hton32(cmp->peek.addr); + if (cmp->peek.len > CSP_CMP_PEEK_MAX_LEN) + return CSP_ERR_INVAL; + + /* Dangerous, you better know what you are doing */ + csp_cmp_memcpy_fnc((csp_memptr_t) (uintptr_t) cmp->peek.data, (csp_memptr_t) (unsigned long) cmp->peek.addr, cmp->peek.len); + + return CSP_ERR_NONE; + +} + +static int do_cmp_poke(struct csp_cmp_message *cmp) { + + cmp->poke.addr = csp_hton32(cmp->poke.addr); + if (cmp->poke.len > CSP_CMP_POKE_MAX_LEN) + return CSP_ERR_INVAL; + + /* Extremely dangerous, you better know what you are doing */ + csp_cmp_memcpy_fnc((csp_memptr_t) (unsigned long) cmp->poke.addr, (csp_memptr_t) (uintptr_t) cmp->poke.data, cmp->poke.len); + + return CSP_ERR_NONE; + +} + +static int do_cmp_clock(struct csp_cmp_message *cmp) { + + cmp->clock.tv_sec = csp_ntoh32(cmp->clock.tv_sec); + cmp->clock.tv_nsec = csp_ntoh32(cmp->clock.tv_nsec); + + if ((cmp->clock.tv_sec != 0) && (clock_set_time != NULL)) { + clock_set_time(&cmp->clock); + } + + if (clock_get_time != NULL) { + clock_get_time(&cmp->clock); + } + + cmp->clock.tv_sec = csp_hton32(cmp->clock.tv_sec); + cmp->clock.tv_nsec = csp_hton32(cmp->clock.tv_nsec); + return CSP_ERR_NONE; + +} + +/* CSP Management Protocol handler */ +static int csp_cmp_handler(csp_conn_t * conn, csp_packet_t * packet) { + + int ret = CSP_ERR_INVAL; + struct csp_cmp_message * cmp = (struct csp_cmp_message *) packet->data; + + /* Ignore everything but requests */ + if (cmp->type != CSP_CMP_REQUEST) + return ret; + + switch (cmp->code) { + case CSP_CMP_IDENT: + ret = do_cmp_ident(cmp); + packet->length = CMP_SIZE(ident); + break; + + case CSP_CMP_ROUTE_SET: + ret = do_cmp_route_set(cmp); + packet->length = CMP_SIZE(route_set); + break; + + case CSP_CMP_IF_STATS: + ret = do_cmp_if_stats(cmp); + packet->length = CMP_SIZE(if_stats); + break; + + case CSP_CMP_PEEK: + ret = do_cmp_peek(cmp); + break; + + case CSP_CMP_POKE: + ret = do_cmp_poke(cmp); + break; + + case CSP_CMP_CLOCK: + ret = do_cmp_clock(cmp); + break; + + default: + ret = CSP_ERR_INVAL; + break; + } + + cmp->type = CSP_CMP_REPLY; + + return ret; +} + +void csp_service_handler(csp_conn_t * conn, csp_packet_t * packet) { + + switch (csp_conn_dport(conn)) { + + case CSP_CMP: + /* Pass to CMP handler */ + if (csp_cmp_handler(conn, packet) != CSP_ERR_NONE) { + csp_buffer_free(packet); + return; + } + break; + + case CSP_PING: + /* A ping means, just echo the packet, so no changes */ + csp_log_info("SERVICE: Ping received"); + break; + + case CSP_PS: { + /* Sanity check on request */ + if ((packet->length != 1) || (packet->data[0] != 0x55)) { + /* Sanity check failed */ + csp_buffer_free(packet); + /* Clear the packet, it has been freed */ + packet = NULL; + break; + } + /* Start by allocating just the right amount of memory */ + int task_list_size = csp_sys_tasklist_size(); + char * pslist = csp_malloc(task_list_size); + /* Check for malloc fail */ + if (pslist == NULL) { + /* Send out the data */ + strcpy((char *)packet->data, "Not enough memory"); + packet->length = strlen((char *)packet->data); + /* Break and let the default handling send packet */ + break; + } + + /* Retrieve the tasklist */ + csp_sys_tasklist(pslist); + int pslen = strnlen(pslist, task_list_size); + + /* Split the potentially very long string into packets */ + int i = 0; + while(i < pslen) { + + /* Allocate packet buffer, if need be */ + if (packet == NULL) + packet = csp_buffer_get(CSP_RPS_MTU); + if (packet == NULL) + break; + + /* Calculate length, either full MTU or the remainder */ + packet->length = (pslen - i > CSP_RPS_MTU) ? CSP_RPS_MTU : (pslen - i); + + /* Send out the data */ + memcpy(packet->data, &pslist[i], packet->length); + i += packet->length; + if (!csp_send(conn, packet, 0)) + csp_buffer_free(packet); + + /* Clear the packet reference when sent */ + packet = NULL; + + } + csp_free(pslist); + break; + } + + case CSP_MEMFREE: { + uint32_t total = csp_sys_memfree(); + + total = csp_hton32(total); + memcpy(packet->data, &total, sizeof(total)); + packet->length = sizeof(total); + + break; + } + + case CSP_REBOOT: { + uint32_t magic_word; + memcpy(&magic_word, packet->data, sizeof(magic_word)); + + magic_word = csp_ntoh32(magic_word); + + /* If the magic word is valid, reboot */ + if (magic_word == CSP_REBOOT_MAGIC) { + csp_sys_reboot(); + } else if (magic_word == CSP_REBOOT_SHUTDOWN_MAGIC) { + csp_sys_shutdown(); + } + + + + csp_buffer_free(packet); + return; + } + + case CSP_BUF_FREE: { + uint32_t size = csp_buffer_remaining(); + size = csp_hton32(size); + memcpy(packet->data, &size, sizeof(size)); + packet->length = sizeof(size); + break; + } + + case CSP_UPTIME: { + uint32_t time = csp_get_s(); + time = csp_hton32(time); + memcpy(packet->data, &time, sizeof(time)); + packet->length = sizeof(time); + break; + } + + default: + csp_buffer_free(packet); + return; + } + + if (packet != NULL) { + if (!csp_send(conn, packet, 0)) + csp_buffer_free(packet); + } + +} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_services.c b/gomspace/libgscsp/lib/libcsp/src/csp_services.c new file mode 100644 index 00000000..5392cb82 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_services.c @@ -0,0 +1,233 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +/* CSP includes */ +#include +#include +#include + +#include + +int csp_ping(uint8_t node, uint32_t timeout, unsigned int size, uint8_t conn_options) { + + unsigned int i; + uint32_t start, time, status = 0; + + /* Counter */ + start = csp_get_ms(); + + /* Open connection */ + csp_conn_t * conn = csp_connect(CSP_PRIO_NORM, node, CSP_PING, timeout, conn_options); + if (conn == NULL) + return -1; + + /* Prepare data */ + csp_packet_t * packet; + packet = csp_buffer_get(size); + if (packet == NULL) + goto out; + + /* Set data to increasing numbers */ + packet->length = size; + for (i = 0; i < size; i++) + packet->data[i] = i; + + /* Try to send frame */ + if (!csp_send(conn, packet, 0)) + goto out; + + /* Read incoming frame */ + packet = csp_read(conn, timeout); + if (packet == NULL) + goto out; + + /* Ensure that the data was actually echoed */ + for (i = 0; i < size; i++) + if (packet->data[i] != i % (0xff + 1)) + goto out; + + status = 1; + +out: + /* Clean up */ + if (packet != NULL) + csp_buffer_free(packet); + csp_close(conn); + + /* We have a reply */ + time = (csp_get_ms() - start); + + if (status) { + return time; + } else { + return -1; + } + +} + +void csp_ping_noreply(uint8_t node) { + + /* Prepare data */ + csp_packet_t * packet; + packet = csp_buffer_get(1); + + /* Check malloc */ + if (packet == NULL) + return; + + /* Open connection */ + csp_conn_t * conn = csp_connect(CSP_PRIO_NORM, node, CSP_PING, 0, 0); + if (conn == NULL) { + csp_buffer_free(packet); + return; + } + + packet->data[0] = 0x55; + packet->length = 1; + + printf("Ping ignore reply node %u.\r\n", (unsigned int) node); + + /* Try to send frame */ + if (!csp_send(conn, packet, 0)) + csp_buffer_free(packet); + + csp_close(conn); + +} + +void csp_reboot(uint8_t node) { + uint32_t magic_word = csp_hton32(CSP_REBOOT_MAGIC); + csp_transaction(CSP_PRIO_NORM, node, CSP_REBOOT, 0, &magic_word, sizeof(magic_word), NULL, 0); +} + +void csp_shutdown(uint8_t node) { + uint32_t magic_word = csp_hton32(CSP_REBOOT_SHUTDOWN_MAGIC); + csp_transaction(CSP_PRIO_NORM, node, CSP_REBOOT, 0, &magic_word, sizeof(magic_word), NULL, 0); +} + +void csp_ps(uint8_t node, uint32_t timeout) { + + /* Open connection */ + csp_conn_t * conn = csp_connect(CSP_PRIO_NORM, node, CSP_PS, 0, 0); + if (conn == NULL) + return; + + /* Prepare data */ + csp_packet_t * packet; + packet = csp_buffer_get(95); + + /* Check malloc */ + if (packet == NULL) + goto out; + + packet->data[0] = 0x55; + packet->length = 1; + + printf("PS node %u: \r\n", (unsigned int) node); + + /* Try to send frame */ + if (!csp_send(conn, packet, 0)) + goto out; + + while(1) { + + /* Read incoming frame */ + packet = csp_read(conn, timeout); + if (packet == NULL) + break; + + /* We have a reply, add our own NULL char */ + packet->data[packet->length] = 0; + printf("%s", packet->data); + + /* Each packet from csp_read must to be freed by user */ + csp_buffer_free(packet); + } + + printf("\r\n"); + + /* Clean up */ +out: + if (packet != NULL) + csp_buffer_free(packet); + csp_close(conn); + +} + +void csp_memfree(uint8_t node, uint32_t timeout) { + + uint32_t memfree; + + int status = csp_transaction(CSP_PRIO_NORM, node, CSP_MEMFREE, timeout, NULL, 0, &memfree, sizeof(memfree)); + if (status == 0) { + printf("Network error\r\n"); + return; + } + + /* Convert from network to host order */ + memfree = csp_ntoh32(memfree); + + printf("Free Memory at node %u is %"PRIu32" bytes\r\n", (unsigned int) node, memfree); + +} + +void csp_buf_free(uint8_t node, uint32_t timeout) { + + uint32_t size = 0; + + int status = csp_transaction(CSP_PRIO_NORM, node, CSP_BUF_FREE, timeout, NULL, 0, &size, sizeof(size)); + if (status == 0) { + printf("Network error\r\n"); + return; + } + size = csp_ntoh32(size); + printf("Free buffers at node %u is %"PRIu32"\r\n", (unsigned int) node, size); + +} + +void csp_uptime(uint8_t node, uint32_t timeout) { + + uint32_t uptime = 0; + + int status = csp_transaction(CSP_PRIO_NORM, node, CSP_UPTIME, timeout, NULL, 0, &uptime, sizeof(uptime)); + if (status == 0) { + printf("Network error\r\n"); + return; + } + uptime = csp_ntoh32(uptime); + printf("Uptime of node %u is %"PRIu32" s\r\n", (unsigned int) node, uptime); + +} + +int csp_cmp(uint8_t node, uint32_t timeout, uint8_t code, int membsize, struct csp_cmp_message * msg) { + msg->type = CSP_CMP_REQUEST; + msg->code = code; + int status = csp_transaction(CSP_PRIO_NORM, node, CSP_CMP, timeout, msg, membsize, msg, membsize); + if (status == 0) + return CSP_ERR_TIMEDOUT; + + return CSP_ERR_NONE; +} + diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_sfp.c b/gomspace/libgscsp/lib/libcsp/src/csp_sfp.c new file mode 100644 index 00000000..96ef36e1 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/csp_sfp.c @@ -0,0 +1,170 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include "csp_conn.h" + +typedef struct __attribute__((__packed__)) { + uint32_t offset; + uint32_t totalsize; +} sfp_header_t; + +/** + * SFP Headers: + * The following functions are helper functions that handles the extra SFP + * information that needs to be appended to all data packets. + */ +static sfp_header_t * csp_sfp_header_add(csp_packet_t * packet) { + sfp_header_t * header = (sfp_header_t *) &packet->data[packet->length]; + packet->length += sizeof(sfp_header_t); + memset(header, 0, sizeof(sfp_header_t)); + return header; +} + +static sfp_header_t * csp_sfp_header_remove(csp_packet_t * packet) { + sfp_header_t * header = (sfp_header_t *) &packet->data[packet->length-sizeof(sfp_header_t)]; + packet->length -= sizeof(sfp_header_t); + return header; +} + +int csp_sfp_send_own_memcpy(csp_conn_t * conn, const void * data, int totalsize, int mtu, uint32_t timeout, void * (*memcpyfcn)(void *, const void *, size_t)) { + + int count = 0; + while(count < totalsize) { + + /* Allocate packet */ + csp_packet_t * packet = csp_buffer_get(mtu); + if (packet == NULL) + return -1; + + /* Calculate sending size */ + int size = totalsize - count; + if (size > mtu) + size = mtu; + + /* Print debug */ + csp_debug(CSP_PROTOCOL, "Sending SFP at %x size %u", data + count, size); + + /* Copy data */ + (*memcpyfcn)(packet->data, data + count, size); + packet->length = size; + + /* Set fragment flag */ + conn->idout.flags |= CSP_FFRAG; + + /* Add SFP header */ + sfp_header_t * sfp_header = csp_sfp_header_add(packet); + sfp_header->totalsize = csp_hton32(totalsize); + sfp_header->offset = csp_hton32(count); + + /* Send data */ + if (!csp_send(conn, packet, timeout)) { + csp_buffer_free(packet); + return -1; + } + + /* Increment count */ + count += size; + + } + + return 0; + +} + +int csp_sfp_send(csp_conn_t * conn, const void * data, int totalsize, int mtu, uint32_t timeout) { + return csp_sfp_send_own_memcpy(conn, data, totalsize, mtu, timeout, &memcpy); +} + +int csp_sfp_recv_fp(csp_conn_t * conn, void ** dataout, int * datasize, uint32_t timeout, csp_packet_t * first_packet) { + + unsigned int last_byte = 0; + + *dataout = NULL; /* Allow caller to assume csp_free() can always be called when dataout is non-NULL */ + + /* Get first packet from user, or from connection */ + csp_packet_t * packet = NULL; + if (first_packet == NULL) { + packet = csp_read(conn, timeout); + if (packet == NULL) + return -1; + } else { + packet = first_packet; + } + + do { + + /* Check that SFP header is present */ + if ((packet->id.flags & CSP_FFRAG) == 0) { + csp_debug(CSP_ERROR, "Missing SFP header"); + csp_buffer_free(packet); + return -1; + } + + /* Read SFP header */ + sfp_header_t * sfp_header = csp_sfp_header_remove(packet); + sfp_header->offset = csp_ntoh32(sfp_header->offset); + sfp_header->totalsize = csp_ntoh32(sfp_header->totalsize); + + csp_debug(CSP_PROTOCOL, "SFP fragment %u/%u", sfp_header->offset + packet->length, sfp_header->totalsize); + + if (sfp_header->offset > last_byte + 1) { + csp_debug(CSP_ERROR, "SFP missing %u bytes", sfp_header->offset - last_byte); + csp_buffer_free(packet); + return -1; + } else { + last_byte = sfp_header->offset + packet->length; + } + + /* Allocate memory */ + if (*dataout == NULL) + *dataout = csp_malloc(sfp_header->totalsize); + if (*dataout == NULL) { + csp_debug(CSP_ERROR, "No dyn-memory for SFP fragment"); + csp_buffer_free(packet); + return -1; + } + + /* Copy data to output */ + *datasize = sfp_header->totalsize; + memcpy(*dataout + sfp_header->offset, packet->data, packet->length); + + if (sfp_header->offset + packet->length >= sfp_header->totalsize) { + csp_debug(CSP_PROTOCOL, "SFP complete"); + csp_buffer_free(packet); + return 0; + } else { + csp_buffer_free(packet); + } + + } while((packet = csp_read(conn, timeout)) != NULL); + + return -1; + +} + +int csp_sfp_recv(csp_conn_t * conn, void ** dataout, int * datasize, uint32_t timeout) { + return csp_sfp_recv_fp(conn, dataout, datasize, timeout, NULL); +} + diff --git a/gomspace/libgscsp/lib/libcsp/src/drivers/can/can_socketcan.c b/gomspace/libgscsp/lib/libcsp/src/drivers/can/can_socketcan.c new file mode 100644 index 00000000..7d12f184 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/drivers/can/can_socketcan.c @@ -0,0 +1,201 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* SocketCAN driver */ +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#ifdef CSP_HAVE_LIBSOCKETCAN +#include +#endif + +static struct can_socketcan_s { + int socket; + csp_iface_t interface; +} socketcan[1] = { + { + .interface = { + .name = "CAN", + .nexthop = csp_can_tx, + .mtu = CSP_CAN_MTU, + .driver = &socketcan[0], + }, + }, +}; + +static void * socketcan_rx_thread(void * parameters) +{ + struct can_frame frame; + int nbytes; + + while (1) { + /* Read CAN frame */ + nbytes = read(socketcan[0].socket, &frame, sizeof(frame)); + if (nbytes < 0) { + csp_log_error("read: %s", strerror(errno)); + continue; + } + + if (nbytes != sizeof(frame)) { + csp_log_warn("Read incomplete CAN frame"); + continue; + } + + /* Frame type */ + if (frame.can_id & (CAN_ERR_FLAG | CAN_RTR_FLAG) || !(frame.can_id & CAN_EFF_FLAG)) { + /* Drop error and remote frames */ + csp_log_warn("Discarding ERR/RTR/SFF frame"); + continue; + } + + /* Strip flags */ + frame.can_id &= CAN_EFF_MASK; + + /* Call RX callbacsp_can_rx_frameck */ + csp_can_rx(&socketcan[0].interface, frame.can_id, frame.data, frame.can_dlc, NULL); + } + + /* We should never reach this point */ + pthread_exit(NULL); +} + + +int csp_can_tx_frame(csp_iface_t *interface, uint32_t id, const uint8_t * data, uint8_t dlc) +{ + struct can_frame frame; + int i, tries = 0; + memset(&frame, 0, sizeof(frame)); + if (dlc > 8) + return -1; + + /* Copy identifier */ + frame.can_id = id | CAN_EFF_FLAG; + + /* Copy data to frame */ + for (i = 0; i < dlc; i++) + frame.data[i] = data[i]; + + /* Set DLC */ + frame.can_dlc = dlc; + + /* Send frame */ + while (write(socketcan[0].socket, &frame, sizeof(frame)) != sizeof(frame)) { + if (++tries < 1000 && errno == ENOBUFS) { + /* Wait 10 ms and try again */ + usleep(10000); + } else { + csp_log_error("write: %s", strerror(errno)); + break; + } + } + + return 0; +} + +csp_iface_t * csp_can_socketcan_init(const char * ifc, int bitrate, int promisc) +{ + struct ifreq ifr; + struct sockaddr_can addr; + pthread_t rx_thread; + + printf("Init can interface %s\n", ifc); + +#ifdef CSP_HAVE_LIBSOCKETCAN + /* Set interface up */ + if (bitrate > 0) { + can_do_stop(ifc); + can_set_bitrate(ifc, bitrate); + can_set_restart_ms(ifc, 100); + can_do_start(ifc); + } +#endif + + /* Create socket */ + if ((socketcan[0].socket = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { + csp_log_error("socket: %s", strerror(errno)); + return NULL; + } + + /* Locate interface */ + strncpy(ifr.ifr_name, ifc, IFNAMSIZ - 1); + if (ioctl(socketcan[0].socket, SIOCGIFINDEX, &ifr) < 0) { + csp_log_error("ioctl: %s", strerror(errno)); + return NULL; + } + memset(&addr, 0, sizeof(addr)); + /* Bind the socket to CAN interface */ + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + if (bind(socketcan[0].socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + csp_log_error("bind: %s", strerror(errno)); + return NULL; + } + + /* Set filter mode */ + if (promisc == 0) { + + struct can_filter filter; + filter.can_id = CFP_MAKE_DST(csp_get_address()); + filter.can_mask = CFP_MAKE_DST((1 << CFP_HOST_SIZE) - 1); + + if (setsockopt(socketcan[0].socket, SOL_CAN_RAW, CAN_RAW_FILTER, &filter, sizeof(filter)) < 0) { + csp_log_error("setsockopt: %s", strerror(errno)); + return NULL; + } + + } + + /* Create receive thread */ + if (pthread_create(&rx_thread, NULL, socketcan_rx_thread, NULL) != 0) { + csp_log_error("pthread_create: %s", strerror(errno)); + return NULL; + } + + csp_iflist_add(&socketcan[0].interface); + + return &socketcan[0].interface; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_linux.c b/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_linux.c new file mode 100644 index 00000000..c4ceeb27 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_linux.c @@ -0,0 +1,254 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +int fd; +usart_callback_t usart_callback = NULL; + +static void *serial_rx_thread(void *vptr_args); + +int getbaud(int ifd) { + struct termios termAttr; + int inputSpeed = -1; + speed_t baudRate; + tcgetattr(ifd, &termAttr); + /* Get the input speed. */ + baudRate = cfgetispeed(&termAttr); + switch (baudRate) { + case B0: + inputSpeed = 0; + break; + case B50: + inputSpeed = 50; + break; + case B110: + inputSpeed = 110; + break; + case B134: + inputSpeed = 134; + break; + case B150: + inputSpeed = 150; + break; + case B200: + inputSpeed = 200; + break; + case B300: + inputSpeed = 300; + break; + case B600: + inputSpeed = 600; + break; + case B1200: + inputSpeed = 1200; + break; + case B1800: + inputSpeed = 1800; + break; + case B2400: + inputSpeed = 2400; + break; + case B4800: + inputSpeed = 4800; + break; + case B9600: + inputSpeed = 9600; + break; + case B19200: + inputSpeed = 19200; + break; + case B38400: + inputSpeed = 38400; + break; + case B57600: + inputSpeed = 57600; + break; + case B115200: + inputSpeed = 115200; + break; + case B230400: + inputSpeed = 230400; + break; +#ifndef CSP_MACOSX + case B460800: + inputSpeed = 460800; + break; + case B500000: + inputSpeed = 500000; + break; + case B576000: + inputSpeed = 576000; + break; + case B921600: + inputSpeed = 921600; + break; + case B1000000: + inputSpeed = 1000000; + break; + case B1152000: + inputSpeed = 1152000; + break; + case B1500000: + inputSpeed = 1500000; + break; + case B2000000: + inputSpeed = 2000000; + break; + case B2500000: + inputSpeed = 2500000; + break; + case B3000000: + inputSpeed = 3000000; + break; + case B3500000: + inputSpeed = 3500000; + break; + case B4000000: + inputSpeed = 4000000; + break; +#endif + } + + return inputSpeed; + +} + +void usart_init(struct usart_conf * conf) { + + struct termios options; + pthread_t rx_thread; + + fd = open(conf->device, O_RDWR | O_NOCTTY | O_NONBLOCK); + + if (fd < 0) { + printf("Failed to open %s: %s\r\n", conf->device, strerror(errno)); + return; + } + + int brate = 0; + switch(conf->baudrate) { + case 4800: brate=B4800; break; + case 9600: brate=B9600; break; + case 19200: brate=B19200; break; + case 38400: brate=B38400; break; + case 57600: brate=B57600; break; + case 115200: brate=B115200; break; + case 230400: brate=B230400; break; +#ifndef CSP_MACOSX + case 460800: brate=B460800; break; + case 500000: brate=B500000; break; + case 576000: brate=B576000; break; + case 921600: brate=B921600; break; + case 1000000: brate=B1000000; break; + case 1152000: brate=B1152000; break; + case 1500000: brate=B1500000; break; + case 2000000: brate=B2000000; break; + case 2500000: brate=B2500000; break; + case 3000000: brate=B3000000; break; + case 3500000: brate=B3500000; break; + case 4000000: brate=B4000000; break; +#endif + default: + printf("Unsupported baudrate requested, defaulting to 500000, requested baudrate=%u\n", conf->baudrate); + brate=B500000; + break; + } + + tcgetattr(fd, &options); + cfsetispeed(&options, brate); + cfsetospeed(&options, brate); + options.c_cflag |= (CLOCAL | CREAD); + options.c_cflag &= ~PARENB; + options.c_cflag &= ~CSTOPB; + options.c_cflag &= ~CSIZE; + options.c_cflag |= CS8; + options.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); + options.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | PARMRK | INPCK | ISTRIP | IXON); + options.c_oflag &= ~(OCRNL | ONLCR | ONLRET | ONOCR | OFILL | OPOST); + options.c_cc[VTIME] = 0; + options.c_cc[VMIN] = 1; + tcsetattr(fd, TCSANOW, &options); + if (tcgetattr(fd, &options) == -1) + perror("error setting options"); + fcntl(fd, F_SETFL, 0); + + /* Flush old transmissions */ + if (tcflush(fd, TCIOFLUSH) == -1) + printf("Error flushing serial port - %s(%d).\n", strerror(errno), errno); + + if (pthread_create(&rx_thread, NULL, serial_rx_thread, NULL) != 0) + return; + +} + +void usart_set_callback(usart_callback_t callback) { + usart_callback = callback; +} + +void usart_insert(char c, void * pxTaskWoken) { + printf("%c", c); +} + +void usart_putstr(char * buf, int len) { + if (write(fd, buf, len) != len) + return; +} + +void usart_putc(char c) { + if (write(fd, &c, 1) != 1) + return; +} + +char usart_getc(void) { + char c; + if (read(fd, &c, 1) != 1) return 0; + return c; +} + +static void *serial_rx_thread(void *vptr_args) { + unsigned int length; + uint8_t * cbuf = malloc(100000); + + // Receive loop + while (1) { + length = read(fd, cbuf, 300); + if (length <= 0) { + perror("Error: "); + exit(1); + } + if (usart_callback) + usart_callback(cbuf, length, NULL); + } + return NULL; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_windows.c b/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_windows.c new file mode 100644 index 00000000..91ffe87d --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_windows.c @@ -0,0 +1,230 @@ +#include +#include +#include + +#include +#include + +static HANDLE portHandle = INVALID_HANDLE_VALUE; +static HANDLE rxThread = INVALID_HANDLE_VALUE; +static CRITICAL_SECTION txSection; +static LONG isListening = 0; +static usart_callback_t usart_callback = NULL; + +static void prvSendData(char *buf, int bufsz); +static int prvTryOpenPort(const char* intf); +static int prvTryConfigurePort(const struct usart_conf*); +static int prvTrySetPortTimeouts(void); +static const char* prvParityToStr(BYTE paritySetting); + +#ifdef CSP_DEBUG +static void prvPrintError(void) { + char *messageBuffer = NULL; + DWORD errorCode = GetLastError(); + DWORD formatMessageRet; + formatMessageRet = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + errorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (char*)&messageBuffer, + 0, + NULL); + + if( !formatMessageRet ) { + csp_log_error("FormatMessage error, code: %lu", GetLastError()); + return; + } + csp_log_error("%s", messageBuffer); + LocalFree(messageBuffer); +} +#endif + +#ifdef CSP_DEBUG +#define printError() prvPrintError() +#else +#define printError() do {} while(0) +#endif + +static int prvTryOpenPort(const char *intf) { + portHandle = CreateFileA( + intf, + GENERIC_READ|GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + 0, + NULL); + + if( portHandle == INVALID_HANDLE_VALUE ) { + DWORD errorCode = GetLastError(); + if( errorCode == ERROR_FILE_NOT_FOUND ) { + csp_log_error("Could not open serial port, because it didn't exist!"); + } + else + csp_log_error("Failure opening serial port! Code: %lu", errorCode); + return 1; + } + return 0; +} + +static int prvTryConfigurePort(const struct usart_conf * conf) { + DCB portSettings = {0}; + portSettings.DCBlength = sizeof(DCB); + if(!GetCommState(portHandle, &portSettings) ) { + csp_log_error("Could not get default settings for open COM port! Code: %lu", GetLastError()); + return -1; + } + portSettings.BaudRate = conf->baudrate; + portSettings.Parity = conf->paritysetting; + portSettings.StopBits = conf->stopbits; + portSettings.fParity = conf->checkparity; + portSettings.fBinary = TRUE; + portSettings.ByteSize = conf->databits; + if( !SetCommState(portHandle, &portSettings) ) { + csp_log_error("Error when setting COM port settings! Code:%lu", GetLastError()); + return 1; + } + + GetCommState(portHandle, &portSettings); + + csp_log_info("Port: %s, Baudrate: %lu, Data bits: %d, Stop bits: %d, Parity: %s", + conf->device, conf->baudrate, conf->databits, conf->stopbits, prvParityToStr(conf->paritysetting)); + return 0; +} + +static const char* prvParityToStr(BYTE paritySetting) { + static const char *parityStr[] = { + "None", + "Odd", + "Even", + "N/A" + }; + char const *resultStr = NULL; + + switch(paritySetting) { + case NOPARITY: + resultStr = parityStr[0]; + break; + case ODDPARITY: + resultStr = parityStr[1]; + break; + case EVENPARITY: + resultStr = parityStr[2]; + break; + default: + resultStr = parityStr[3]; + }; + return resultStr; +} + +static int prvTrySetPortTimeouts(void) { + COMMTIMEOUTS timeouts = {0}; + + if( !GetCommTimeouts(portHandle, &timeouts) ) { + csp_log_error("Error gettings current timeout settings"); + return 1; + } + + timeouts.ReadIntervalTimeout = 5; + timeouts.ReadTotalTimeoutMultiplier = 1; + timeouts.ReadTotalTimeoutConstant = 5; + timeouts.WriteTotalTimeoutMultiplier = 1; + timeouts.WriteTotalTimeoutConstant = 5; + + if(!SetCommTimeouts(portHandle, &timeouts)) { + csp_log_error("Error setting timeouts!"); + return 1; + } + + return 0; +} + +unsigned WINAPI prvRxTask(void* params) { + DWORD bytesRead; + DWORD eventStatus; + uint8_t recvBuffer[24]; + SetCommMask(portHandle, EV_RXCHAR); + + while(isListening) { + WaitCommEvent(portHandle, &eventStatus, NULL); + if( !(eventStatus & EV_RXCHAR) ) { + continue; + } + if( !ReadFile(portHandle, recvBuffer, 24, &bytesRead, NULL)) { + csp_log_warn("Error receiving data! Code: %lu", GetLastError()); + continue; + } + if( usart_callback != NULL ) + usart_callback(recvBuffer, (size_t)bytesRead, NULL); + } + return 0; +} + +static void prvSendData(char *buf, int bufsz) { + DWORD bytesTotal = 0; + DWORD bytesActual; + if( !WriteFile(portHandle, buf, bufsz-bytesTotal, &bytesActual, NULL) ) { + csp_log_error("Could not write data. Code: %lu", GetLastError()); + return; + } + if( !FlushFileBuffers(portHandle) ) { + csp_log_warn("Could not flush write buffer. Code: %lu", GetLastError()); + } +} + +void usart_shutdown(void) { + InterlockedExchange(&isListening, 0); + CloseHandle(portHandle); + portHandle = INVALID_HANDLE_VALUE; + if( rxThread != INVALID_HANDLE_VALUE ) { + WaitForSingleObject(rxThread, INFINITE); + rxThread = INVALID_HANDLE_VALUE; + } + DeleteCriticalSection(&txSection); +} + +void usart_listen(void) { + InterlockedExchange(&isListening, 1); + rxThread = (HANDLE)_beginthreadex(NULL, 0, &prvRxTask, NULL, 0, NULL); +} + +void usart_putstr(char* buf, int bufsz) { + EnterCriticalSection(&txSection); + prvSendData(buf, bufsz); + LeaveCriticalSection(&txSection); +} + +void usart_insert(char c, void *pxTaskWoken) { + /* redirect debug output to stdout */ + printf("%c", c); +} + +void usart_set_callback(usart_callback_t callback) { + usart_callback = callback; +} + +void usart_init(struct usart_conf * conf) { + if( prvTryOpenPort(conf->device) ) { + printError(); + return; + } + + if( prvTryConfigurePort(conf) ) { + printError(); + return; + } + + if( prvTrySetPortTimeouts() ) { + printError(); + return; + } + + InitializeCriticalSection(&txSection); + + /* Start receiver thread */ + usart_listen(); +} + + diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can.c new file mode 100644 index 00000000..5add8334 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can.c @@ -0,0 +1,279 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* CAN frames contains at most 8 bytes of data, so in order to transmit CSP + * packets larger than this, a fragmentation protocol is required. The CAN + * Fragmentation Protocol (CFP) header is designed to match the 29 bit CAN + * identifier. + * + * The CAN identifier is divided in these fields: + * src: 5 bits + * dst: 5 bits + * type: 1 bit + * remain: 8 bits + * identifier: 10 bits + * + * Source and Destination addresses must match the CSP packet. The type field + * is used to distinguish the first and subsequent frames in a fragmented CSP + * packet. Type is BEGIN (0) for the first fragment and MORE (1) for all other + * fragments. Remain indicates number of remaining fragments, and must be + * decremented by one for each fragment sent. The identifier field serves the + * same purpose as in the Internet Protocol, and should be an auto incrementing + * integer to uniquely separate sessions. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "csp_if_can_pbuf.h" + +/* CFP Frame Types */ +enum cfp_frame_t { + CFP_BEGIN = 0, + CFP_MORE = 1 +}; + +int csp_can_rx(csp_iface_t *interface, uint32_t id, const uint8_t *data, uint8_t dlc, CSP_BASE_TYPE *task_woken) +{ + csp_can_pbuf_element_t *buf; + uint8_t offset; + + /* Random packet loss */ +#if 0 + int random = rand(); + if (random < RAND_MAX * 0.00005) { + csp_log_warn("Dropping frame"); + return; + } +#endif + + /* Bind incoming frame to a packet buffer */ + buf = csp_can_pbuf_find(id, CFP_ID_CONN_MASK); + + /* Check returned buffer */ + if (buf == NULL) { + if (CFP_TYPE(id) == CFP_BEGIN) { + buf = csp_can_pbuf_new(id, task_woken); + if (buf == NULL) { + //csp_log_warn("No available packet buffer for CAN"); + interface->rx_error++; + return CSP_ERR_NOMEM; + } + } else { + //csp_log_warn("Out of order id 0x%X remain %u", CFP_ID(id), CFP_REMAIN(id)); + interface->frame++; + return CSP_ERR_INVAL; + } + } + + /* Reset frame data offset */ + offset = 0; + + switch (CFP_TYPE(id)) { + + case CFP_BEGIN: + + /* Discard packet if DLC is less than CSP id + CSP length fields */ + if (dlc < sizeof(csp_id_t) + sizeof(uint16_t)) { + //csp_log_warn("Short BEGIN frame received"); + interface->frame++; + csp_can_pbuf_free(buf, task_woken); + break; + } + + /* Check for incomplete frame */ + if (buf->packet != NULL) { + /* Reuse the buffer */ + //csp_log_warn("Incomplete frame"); + interface->frame++; + } else { + /* Allocate memory for frame */ + if (task_woken == NULL) { + buf->packet = csp_buffer_get(interface->mtu); + } else { + buf->packet = csp_buffer_get_isr(interface->mtu); + } + if (buf->packet == NULL) { + //csp_log_error("Failed to get buffer for CSP_BEGIN packet"); + interface->frame++; + csp_can_pbuf_free(buf, task_woken); + break; + } + } + + /* Copy CSP identifier and length*/ + memcpy(&(buf->packet->id), data, sizeof(csp_id_t)); + buf->packet->id.ext = csp_ntoh32(buf->packet->id.ext); + memcpy(&(buf->packet->length), data + sizeof(csp_id_t), sizeof(uint16_t)); + buf->packet->length = csp_ntoh16(buf->packet->length); + + /* Reset RX count */ + buf->rx_count = 0; + + /* Set offset to prevent CSP header from being copied to CSP data */ + offset = sizeof(csp_id_t) + sizeof(uint16_t); + + /* Set remain field - increment to include begin packet */ + buf->remain = CFP_REMAIN(id) + 1; + + /* FALLTHROUGH */ + + case CFP_MORE: + + /* Check 'remain' field match */ + if (CFP_REMAIN(id) != buf->remain - 1) { + //csp_log_error("CAN frame lost in CSP packet"); + csp_can_pbuf_free(buf, task_woken); + interface->frame++; + break; + } + + /* Decrement remaining frames */ + buf->remain--; + + /* Check for overflow */ + if ((buf->rx_count + dlc - offset) > buf->packet->length) { + //csp_log_error("RX buffer overflow"); + interface->frame++; + csp_can_pbuf_free(buf, task_woken); + break; + } + + /* Copy dlc bytes into buffer */ + memcpy(&buf->packet->data[buf->rx_count], data + offset, dlc - offset); + buf->rx_count += dlc - offset; + + /* Check if more data is expected */ + if (buf->rx_count != buf->packet->length) + break; + + /* Data is available */ + csp_qfifo_write(buf->packet, interface, task_woken); + + /* Drop packet buffer reference */ + buf->packet = NULL; + + /* Free packet buffer */ + csp_can_pbuf_free(buf, task_woken); + + break; + + default: + //csp_log_warn("Received unknown CFP message type"); + csp_can_pbuf_free(buf, task_woken); + break; + + } + + return CSP_ERR_NONE; +} + +int csp_can_tx(csp_iface_t *interface, csp_packet_t *packet, uint32_t timeout) +{ + + /* CFP Identification number */ + static volatile int csp_can_frame_id = 0; + + /* Get local copy of the static frameid */ + int ident = csp_can_frame_id++; + + uint16_t tx_count; + uint8_t bytes, overhead, avail, dest; + uint8_t frame_buf[8]; + + /* Calculate overhead */ + overhead = sizeof(csp_id_t) + sizeof(uint16_t); + + /* Insert destination node mac address into the CFP destination field */ + dest = csp_rtable_find_mac(packet->id.dst); + if (dest == CSP_NODE_MAC) + dest = packet->id.dst; + + /* Create CAN identifier */ + uint32_t id = 0; + id |= CFP_MAKE_SRC(packet->id.src); + id |= CFP_MAKE_DST(dest); + id |= CFP_MAKE_ID(ident); + id |= CFP_MAKE_TYPE(CFP_BEGIN); + id |= CFP_MAKE_REMAIN((packet->length + overhead - 1) / 8); + + /* Calculate first frame data bytes */ + avail = 8 - overhead; + bytes = (packet->length <= avail) ? packet->length : avail; + + /* Copy CSP headers and data */ + uint32_t csp_id_be = csp_hton32(packet->id.ext); + uint16_t csp_length_be = csp_hton16(packet->length); + + memcpy(frame_buf, &csp_id_be, sizeof(csp_id_be)); + memcpy(frame_buf + sizeof(csp_id_be), &csp_length_be, sizeof(csp_length_be)); + memcpy(frame_buf + overhead, packet->data, bytes); + + /* Increment tx counter */ + tx_count = bytes; + + /* Send first frame */ + if (csp_can_tx_frame(interface, id, frame_buf, overhead + bytes)) { + //csp_log_warn("Failed to send CAN frame in csp_tx_can"); + interface->tx_error++; + return CSP_ERR_DRIVER; + } + + /* Send next frames if not complete */ + while (tx_count < packet->length) { + /* Calculate frame data bytes */ + bytes = (packet->length - tx_count >= 8) ? 8 : packet->length - tx_count; + + /* Prepare identifier */ + id = 0; + id |= CFP_MAKE_SRC(packet->id.src); + id |= CFP_MAKE_DST(dest); + id |= CFP_MAKE_ID(ident); + id |= CFP_MAKE_TYPE(CFP_MORE); + id |= CFP_MAKE_REMAIN((packet->length - tx_count - bytes + 7) / 8); + + /* Increment tx counter */ + tx_count += bytes; + + /* Send frame */ + if (csp_can_tx_frame(interface, id, packet->data + tx_count - bytes, bytes)) { + //csp_log_warn("Failed to send CAN frame in Tx callback"); + interface->tx_error++; + return CSP_ERR_DRIVER; + } + } + + csp_buffer_free(packet); + + return CSP_ERR_NONE; +} diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.c new file mode 100644 index 00000000..65f18de9 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.c @@ -0,0 +1,77 @@ +/* + * csp_if_can_pbuf.c + * + * Created on: Feb 3, 2017 + * Author: johan + */ + +#include +#include "csp_if_can_pbuf.h" + +/* Number of packet buffer elements */ +#define PBUF_ELEMENTS CSP_CONN_MAX + +/* Buffer element timeout in ms */ +#define PBUF_TIMEOUT_MS 1000 + +static csp_can_pbuf_element_t csp_can_pbuf[PBUF_ELEMENTS] = {}; + +int csp_can_pbuf_free(csp_can_pbuf_element_t *buf, CSP_BASE_TYPE *task_woken) +{ + /* Free CSP packet */ + if (buf->packet != NULL) { + if (task_woken == NULL) { + csp_buffer_free(buf->packet); + } else { + csp_buffer_free_isr(buf->packet); + } + } + + /* Mark buffer element free */ + buf->packet = NULL; + buf->rx_count = 0; + buf->cfpid = 0; + buf->last_used = 0; + buf->remain = 0; + buf->state = BUF_FREE; + + return CSP_ERR_NONE; +} + +csp_can_pbuf_element_t *csp_can_pbuf_new(uint32_t id, CSP_BASE_TYPE *task_woken) +{ + uint32_t now = csp_get_ms(); + + for (int i = 0; i < PBUF_ELEMENTS; i++) { + + /* Perform cleanup in used pbufs */ + if (csp_can_pbuf[i].state == BUF_USED) { + if (now - csp_can_pbuf[i].last_used > PBUF_TIMEOUT_MS) + csp_can_pbuf_free(&csp_can_pbuf[i], task_woken); + } + + if (csp_can_pbuf[i].state == BUF_FREE) { + csp_can_pbuf[i].state = BUF_USED; + csp_can_pbuf[i].cfpid = id; + csp_can_pbuf[i].remain = 0; + csp_can_pbuf[i].last_used = now; + return &csp_can_pbuf[i]; + } + + } + + return NULL; + +} + +csp_can_pbuf_element_t *csp_can_pbuf_find(uint32_t id, uint32_t mask) +{ + for (int i = 0; i < PBUF_ELEMENTS; i++) { + if ((csp_can_pbuf[i].state == BUF_USED) && ((csp_can_pbuf[i].cfpid & mask) == (id & mask))) { + csp_can_pbuf[i].last_used = csp_get_ms(); + return &csp_can_pbuf[i]; + } + } + return NULL; +} + diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.h b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.h new file mode 100644 index 00000000..3e71c26c --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.h @@ -0,0 +1,31 @@ +/* + * csp_if_can_pbuf.h + * + * Created on: Feb 3, 2017 + * Author: johan + */ + +#ifndef LIB_CSP_SRC_INTERFACES_CSP_IF_CAN_PBUF_H_ +#define LIB_CSP_SRC_INTERFACES_CSP_IF_CAN_PBUF_H_ + +/* Packet buffers */ +typedef enum { + BUF_FREE = 0, /* Buffer element free */ + BUF_USED = 1, /* Buffer element used */ +} csp_can_pbuf_state_t; + +typedef struct { + uint16_t rx_count; /* Received bytes */ + uint32_t remain; /* Remaining packets */ + uint32_t cfpid; /* Connection CFP identification number */ + csp_packet_t *packet; /* Pointer to packet buffer */ + csp_can_pbuf_state_t state; /* Element state */ + uint32_t last_used; /* Timestamp in ms for last use of buffer */ +} csp_can_pbuf_element_t; + +int csp_can_pbuf_free(csp_can_pbuf_element_t *buf, CSP_BASE_TYPE *task_woken); +csp_can_pbuf_element_t *csp_can_pbuf_new(uint32_t id, CSP_BASE_TYPE *task_woken); +csp_can_pbuf_element_t *csp_can_pbuf_find(uint32_t id, uint32_t mask); +void csp_can_pbuf_cleanup(CSP_BASE_TYPE *task_woken); + +#endif /* LIB_CSP_SRC_INTERFACES_CSP_IF_CAN_PBUF_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_i2c.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_i2c.c new file mode 100644 index 00000000..c5d105df --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_i2c.c @@ -0,0 +1,116 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include + +static int csp_i2c_handle = 0; + +int csp_i2c_tx(csp_iface_t * interface, csp_packet_t * packet, uint32_t timeout) { + + /* Cast the CSP packet buffer into an i2c frame */ + i2c_frame_t * frame = (i2c_frame_t *) packet; + + /* Insert destination node into the i2c destination field */ + if (csp_rtable_find_mac(packet->id.dst) == CSP_NODE_MAC) { + frame->dest = packet->id.dst; + } else { + frame->dest = csp_rtable_find_mac(packet->id.dst); + } + + /* Save the outgoing id in the buffer */ + packet->id.ext = csp_hton32(packet->id.ext); + + /* Add the CSP header to the I2C length field */ + frame->len += sizeof(packet->id); + frame->len_rx = 0; + + /* Some I2C drivers support X number of retries + * CSP don't care about this. If it doesn't work the first + * time, don'y use time on it. + */ + frame->retries = 0; + + /* enqueue the frame */ + if (i2c_send(csp_i2c_handle, frame, timeout) != E_NO_ERR) + return CSP_ERR_DRIVER; + + return CSP_ERR_NONE; + +} + +/** + * When a frame is received, cast it to a csp_packet + * and send it directly to the CSP new packet function. + * Context: ISR only + * @param frame + */ +void csp_i2c_rx(i2c_frame_t * frame, void * pxTaskWoken) { + + static csp_packet_t * packet; + + /* Validate input */ + if (frame == NULL) + return; + + if ((frame->len < 4) || (frame->len > I2C_MTU)) { + csp_if_i2c.frame++; + csp_buffer_free_isr(frame); + return; + } + + /* Strip the CSP header off the length field before converting to CSP packet */ + frame->len -= sizeof(csp_id_t); + + /* Convert the packet from network to host order */ + packet = (csp_packet_t *) frame; + packet->id.ext = csp_ntoh32(packet->id.ext); + + /* Receive the packet in CSP */ + csp_qfifo_write(packet, &csp_if_i2c, pxTaskWoken); + +} + +int csp_i2c_init(uint8_t addr, int handle, int speed) { + + /* Create i2c_handle */ + csp_i2c_handle = handle; + if (i2c_init(csp_i2c_handle, I2C_MASTER, addr, speed, 10, 10, csp_i2c_rx) != E_NO_ERR) + return CSP_ERR_DRIVER; + + /* Register interface */ + csp_iflist_add(&csp_if_i2c); + + return CSP_ERR_NONE; + +} + +/** Interface definition */ +csp_iface_t csp_if_i2c = { + .name = "I2C", + .nexthop = csp_i2c_tx, +}; diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_kiss.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_kiss.c new file mode 100644 index 00000000..fe5707f6 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_kiss.c @@ -0,0 +1,260 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define KISS_MTU 256 + +#define FEND 0xC0 +#define FESC 0xDB +#define TFEND 0xDC +#define TFESC 0xDD + +#define TNC_DATA 0x00 +#define TNC_SET_HARDWARE 0x06 +#define TNC_RETURN 0xFF + +static int kiss_lock_init = 0; +static csp_bin_sem_handle_t kiss_lock; + +/* Send a CSP packet over the KISS RS232 protocol */ +static int csp_kiss_tx(csp_iface_t * interface, csp_packet_t * packet, uint32_t timeout) { + + if (interface == NULL || interface->driver == NULL) + return CSP_ERR_DRIVER; + + /* Add CRC32 checksum */ + csp_crc32_append(packet, false); + + /* Save the outgoing id in the buffer */ + packet->id.ext = csp_hton32(packet->id.ext); + packet->length += sizeof(packet->id.ext); + + /* Lock */ + csp_bin_sem_wait(&kiss_lock, 1000); + + /* Transmit data */ + csp_kiss_handle_t * driver = interface->driver; + driver->kiss_putc(FEND); + driver->kiss_putc(TNC_DATA); + for (unsigned int i = 0; i < packet->length; i++) { + if (((unsigned char *) &packet->id.ext)[i] == FEND) { + ((unsigned char *) &packet->id.ext)[i] = TFEND; + driver->kiss_putc(FESC); + } else if (((unsigned char *) &packet->id.ext)[i] == FESC) { + ((unsigned char *) &packet->id.ext)[i] = TFESC; + driver->kiss_putc(FESC); + } + driver->kiss_putc(((unsigned char *) &packet->id.ext)[i]); + } + driver->kiss_putc(FEND); + + /* Free data */ + csp_buffer_free(packet); + + /* Unlock */ + csp_bin_sem_post(&kiss_lock); + + return CSP_ERR_NONE; +} + +/** + * When a frame is received, decode the kiss-stuff + * and eventually send it directly to the CSP new packet function. + */ +void csp_kiss_rx(csp_iface_t * interface, uint8_t * buf, int len, void * pxTaskWoken) { + + /* Driver handle */ + csp_kiss_handle_t * driver = interface->driver; + + while (len--) { + + /* Input */ + unsigned char inputbyte = *buf++; + + /* If packet was too long */ + if (driver->rx_length > interface->mtu) { + //csp_log_warn("KISS RX overflow"); + interface->rx_error++; + driver->rx_mode = KISS_MODE_NOT_STARTED; + driver->rx_length = 0; + } + + switch (driver->rx_mode) { + + case KISS_MODE_NOT_STARTED: + + /* Send normal chars back to usart driver */ + if (inputbyte != FEND) { + if (driver->kiss_discard != NULL) + driver->kiss_discard(inputbyte, pxTaskWoken); + break; + } + + /* Try to allocate new buffer */ + if (driver->rx_packet == NULL) { + if (pxTaskWoken == NULL) { + driver->rx_packet = csp_buffer_get(interface->mtu); + } else { + driver->rx_packet = csp_buffer_get_isr(interface->mtu); + } + } + + /* If no more memory, skip frame */ + if (driver->rx_packet == NULL) { + driver->rx_mode = KISS_MODE_SKIP_FRAME; + break; + } + + /* Start transfer */ + driver->rx_length = 0; + driver->rx_mode = KISS_MODE_STARTED; + driver->rx_first = 1; + break; + + case KISS_MODE_STARTED: + + /* Escape char */ + if (inputbyte == FESC) { + driver->rx_mode = KISS_MODE_ESCAPED; + break; + } + + /* End Char */ + if (inputbyte == FEND) { + + /* Accept message */ + if (driver->rx_length > 0) { + + /* Check for valid length */ + if (driver->rx_length < CSP_HEADER_LENGTH + sizeof(uint32_t)) { + //csp_log_warn("KISS short frame skipped, len: %u", driver->rx_length); + interface->rx_error++; + driver->rx_mode = KISS_MODE_NOT_STARTED; + break; + } + + /* Count received frame */ + interface->frame++; + + /* The CSP packet length is without the header */ + driver->rx_packet->length = driver->rx_length - CSP_HEADER_LENGTH; + + /* Convert the packet from network to host order */ + driver->rx_packet->id.ext = csp_ntoh32(driver->rx_packet->id.ext); + + /* Validate CRC */ + if (csp_crc32_verify(driver->rx_packet, false) != CSP_ERR_NONE) { + //csp_log_warn("KISS invalid crc frame skipped, len: %u", driver->rx_packet->length); + interface->rx_error++; + driver->rx_mode = KISS_MODE_NOT_STARTED; + break; + } + + /* Send back into CSP, notice calling from task so last argument must be NULL! */ + csp_qfifo_write(driver->rx_packet, interface, pxTaskWoken); + driver->rx_packet = NULL; + driver->rx_mode = KISS_MODE_NOT_STARTED; + break; + + } + + /* Break after the end char */ + break; + } + + /* Skip the first char after FEND which is TNC_DATA (0x00) */ + if (driver->rx_first) { + driver->rx_first = 0; + break; + } + + /* Valid data char */ + ((char *) &driver->rx_packet->id.ext)[driver->rx_length++] = inputbyte; + + break; + + case KISS_MODE_ESCAPED: + + /* Escaped escape char */ + if (inputbyte == TFESC) + ((char *) &driver->rx_packet->id.ext)[driver->rx_length++] = FESC; + + /* Escaped fend char */ + if (inputbyte == TFEND) + ((char *) &driver->rx_packet->id.ext)[driver->rx_length++] = FEND; + + /* Go back to started mode */ + driver->rx_mode = KISS_MODE_STARTED; + break; + + case KISS_MODE_SKIP_FRAME: + + /* Just wait for end char */ + if (inputbyte == FEND) + driver->rx_mode = KISS_MODE_NOT_STARTED; + + break; + + } + + } + +} + +void csp_kiss_init(csp_iface_t * csp_iface, csp_kiss_handle_t * csp_kiss_handle, csp_kiss_putc_f kiss_putc_f, csp_kiss_discard_f kiss_discard_f, const char * name) { + + /* Init lock only once */ + if (kiss_lock_init == 0) { + csp_bin_sem_create(&kiss_lock); + kiss_lock_init = 1; + } + + /* Register device handle as member of interface */ + csp_iface->driver = csp_kiss_handle; + csp_kiss_handle->kiss_discard = kiss_discard_f; + csp_kiss_handle->kiss_putc = kiss_putc_f; + csp_kiss_handle->rx_packet = NULL; + csp_kiss_handle->rx_mode = KISS_MODE_NOT_STARTED; + + /* Set default MTU if not given */ + if (csp_iface->mtu == 0) { + csp_iface->mtu = KISS_MTU; + } + + /* Setup other mandatories */ + csp_iface->nexthop = csp_kiss_tx; + csp_iface->name = name; + + /* Regsiter interface */ + csp_iflist_add(csp_iface); + +} diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_lo.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_lo.c new file mode 100644 index 00000000..f3e81b15 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_lo.c @@ -0,0 +1,61 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* CSP includes */ +#include +#include +#include +#include + +#include +#include + +#include "../csp_route.h" + +/** + * Loopback interface transmit function + * @param packet Packet to transmit + * @param timeout Timout in ms + * @return 1 if packet was successfully transmitted, 0 on error + */ +static int csp_lo_tx(csp_iface_t * interface, csp_packet_t * packet, uint32_t timeout) { + + /* Drop packet silently if not destined for us. This allows + * blackhole routing addresses by setting their nexthop to + * the loopback interface. + */ + if (packet->id.dst != csp_get_address()) { + /* Consume and drop packet */ + csp_buffer_free(packet); + return CSP_ERR_NONE; + } + + /* Send back into CSP, notice calling from task so last argument must be NULL! */ + csp_qfifo_write(packet, &csp_if_lo, NULL); + + return CSP_ERR_NONE; + +} + +/* Interface definition */ +csp_iface_t csp_if_lo = { + .name = "LOOP", + .nexthop = csp_lo_tx, +}; diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c new file mode 100644 index 00000000..5292663b --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c @@ -0,0 +1,165 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +/* CSP includes */ +#include +#include +#include +#include +#include +#include + +/* ZMQ */ +#include + +static void * context; +static void * publisher; +static void * subscriber; +static csp_bin_sem_handle_t tx_wait; + +/** + * Interface transmit function + * @param packet Packet to transmit + * @param timeout Timeout in ms + * @return 1 if packet was successfully transmitted, 0 on error + */ +int csp_zmqhub_tx(csp_iface_t * interface, csp_packet_t * packet, uint32_t timeout) { + + /* Send envelope */ + uint8_t dest = csp_rtable_find_mac(packet->id.dst); + if (dest == CSP_NODE_MAC) + dest = packet->id.dst; + + uint16_t length = packet->length; + uint8_t * destptr = ((uint8_t *) &packet->id) - sizeof(dest); + memcpy(destptr, &dest, sizeof(dest)); + csp_bin_sem_wait(&tx_wait, CSP_INFINITY); /* Using ZMQ in thread safe manner*/ + int result = zmq_send(publisher, destptr, length + sizeof(packet->id) + sizeof(dest), 0); + csp_bin_sem_post(&tx_wait); /* Release tx semaphore */ + if (result < 0) + csp_log_error("ZMQ send error: %u %s\r\n", result, strerror(result)); + + csp_buffer_free(packet); + + return CSP_ERR_NONE; + +} + +CSP_DEFINE_TASK(csp_zmqhub_task) { + + while(1) { + zmq_msg_t msg; + assert(zmq_msg_init_size(&msg, 1024) == 0); + + /* Receive data */ + if (zmq_msg_recv(&msg, subscriber, 0) < 0) { + zmq_msg_close(&msg); + csp_log_error("ZMQ: %s", zmq_strerror(zmq_errno())); + continue; + } + + int datalen = zmq_msg_size(&msg); + if (datalen < 5) { + csp_log_warn("ZMQ: Too short datalen: %u", datalen); + while(zmq_msg_recv(&msg, subscriber, ZMQ_NOBLOCK) > 0) + zmq_msg_close(&msg); + continue; + } + + /* Create new csp packet */ + csp_packet_t * packet = csp_buffer_get(256); + if (packet == NULL) { + zmq_msg_close(&msg); + continue; + } + + /* Copy the data from zmq to csp */ + uint8_t * destptr = ((uint8_t *) &packet->id) - sizeof(*destptr); + memcpy(destptr, zmq_msg_data(&msg), datalen); + packet->length = datalen - sizeof(packet->id) - sizeof(*destptr); + + /* Queue up packet to router */ + csp_qfifo_write(packet, &csp_if_zmqhub, NULL); + + zmq_msg_close(&msg); + } + + return CSP_TASK_RETURN; + +} + +int csp_zmqhub_init(uint8_t addr, const char * host) { + char url_pub[100]; + char url_sub[100]; + + sprintf(url_pub, "tcp://%s:6000", host); + sprintf(url_sub, "tcp://%s:7000", host); + + return csp_zmqhub_init_w_endpoints(addr, url_pub, url_sub); +} + +int csp_zmqhub_init_w_endpoints(uint8_t addr, const char * publisher_endpoint, + const char * subscriber_endpoint) { + + context = zmq_ctx_new(); + assert(context); + + csp_log_info("INIT ZMQ with addr %u to servers %s / %s\r\n", + addr, publisher_endpoint, subscriber_endpoint); + + /* Publisher (TX) */ + publisher = zmq_socket(context, ZMQ_PUB); + assert(publisher); + assert(zmq_connect(publisher, publisher_endpoint) == 0); + + /* Subscriber (RX) */ + subscriber = zmq_socket(context, ZMQ_SUB); + assert(subscriber); + assert(zmq_connect(subscriber, subscriber_endpoint) == 0); + + if (addr == CSP_NODE_MAC) { // == 255 + assert(zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, NULL, 0) == 0); + } else { + assert(zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, &addr, 1) == 0); + } + /* ZMQ isn't thread safe, so we add a binary semaphore to wait on for tx */ + if (csp_bin_sem_create(&tx_wait) != CSP_SEMAPHORE_OK) { + csp_log_error("Failed to initialize semaphore in csp_zmqhub_init_w_endpoints"); + return CSP_ERR_NOMEM; + } + /* Start RX thread */ + static csp_thread_handle_t handle_subscriber; + int ret = csp_thread_create(csp_zmqhub_task, "ZMQ", 20000, NULL, 0, &handle_subscriber); + csp_log_info("Task start %d\r\n", ret); + + /* Register interface */ + csp_iflist_add(&csp_if_zmqhub); + + return CSP_ERR_NONE; + +} + +/* Interface definition */ +csp_iface_t csp_if_zmqhub = { + .name = "ZMQHUB", + .nexthop = csp_zmqhub_tx, +}; diff --git a/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_cidr.c b/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_cidr.c new file mode 100644 index 00000000..5758dc3c --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_cidr.c @@ -0,0 +1,233 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include + +/* Local typedef for routing table */ +typedef struct __attribute__((__packed__)) csp_rtable_s { + uint8_t address; + uint8_t netmask; + uint8_t mac; + csp_iface_t * interface; + struct csp_rtable_s * next; +} csp_rtable_t; + +/* Routing entries are stored in a linked list*/ +static csp_rtable_t * rtable = NULL; + +static csp_rtable_t * csp_rtable_find(uint8_t addr, uint8_t netmask, uint8_t exact) { + + /* Remember best result */ + csp_rtable_t * best_result = NULL; + uint8_t best_result_mask = 0; + + /* Start search */ + csp_rtable_t * i = rtable; + while(i) { + + /* Look for exact match */ + if (i->address == addr && i->netmask == netmask) { + best_result = i; + break; + } + + /* Try a CIDR netmask match */ + if (!exact) { + uint8_t hostbits = (1 << (CSP_ID_HOST_SIZE - i->netmask)) - 1; + uint8_t netbits = ~hostbits; + //printf("Netbits %x Hostbits %x\r\n", netbits, hostbits); + + /* Match network addresses */ + uint8_t net_a = i->address & netbits; + uint8_t net_b = addr & netbits; + //printf("A: %hhx, B: %hhx\r\n", net_a, net_b); + + /* We have a match */ + if (net_a == net_b) { + if (i->netmask >= best_result_mask) { + //printf("Match best result %u %u\r\n", best_result_mask, i->netmask); + best_result = i; + best_result_mask = i->netmask; + } + } + + } + + i = i->next; + + } + +#if 0 + if (best_result) + csp_debug(CSP_PACKET, "Using routing entry: %u/%u dev %s m:%u\r\n", best_result->address, best_result->netmask, best_result->interface->name, best_result->mac); +#endif + + return best_result; + +} + +void csp_rtable_clear(void) { + for (csp_rtable_t * i = rtable; (i);) { + void * freeme = i; + i = i->next; + csp_free(freeme); + } + rtable = NULL; + + /* Set loopback up again */ + csp_rtable_set(csp_get_address(), CSP_ID_HOST_SIZE, &csp_if_lo, CSP_NODE_MAC); + +} + +static int csp_rtable_parse(const char * buffer, int dry_run) { + + int valid_entries = 0; + + /* Copy string before running strtok */ + char * str = alloca(strlen(buffer) + 1); + memcpy(str, buffer, strlen(buffer) + 1); + + /* Get first token */ + str = strtok(str, ","); + + while ((str) && (strlen(str) > 1)) { + int address = 0, netmask = 0, mac = 255; + char name[10] = {}; + if (sscanf(str, "%u/%u %s %u", &address, &netmask, name, &mac) != 4) { + if (sscanf(str, "%u/%u %s", &address, &netmask, name) != 3) { + csp_log_error("Parse error %s", str); + return -1; + } + } + //printf("Parsed %u/%u %u %s\r\n", address, netmask, mac, name); + csp_iface_t * ifc = csp_iflist_get_by_name(name); + if (ifc) { + if (dry_run == 0) + csp_rtable_set(address, netmask, ifc, mac); + } else { + csp_log_error("Unknown interface %s", name); + return -1; + } + valid_entries++; + str = strtok(NULL, ","); + } + + return valid_entries; +} + +void csp_rtable_load(const char * buffer) { + csp_rtable_parse(buffer, 0); +} + +int csp_rtable_check(const char * buffer) { + return csp_rtable_parse(buffer, 1); +} + +int csp_rtable_save(char * buffer, int maxlen) { + int len = 0; + for (csp_rtable_t * i = rtable; (i); i = i->next) { + if (i->mac != CSP_NODE_MAC) { + len += snprintf(buffer + len, maxlen - len, "%u/%u %s %u, ", i->address, i->netmask, i->interface->name, i->mac); + } else { + len += snprintf(buffer + len, maxlen - len, "%u/%u %s, ", i->address, i->netmask, i->interface->name); + } + } + return len; +} + +csp_iface_t * csp_rtable_find_iface(uint8_t id) { + csp_rtable_t * entry = csp_rtable_find(id, CSP_ID_HOST_SIZE, 0); + if (entry == NULL) + return NULL; + return entry->interface; +} + +uint8_t csp_rtable_find_mac(uint8_t id) { + csp_rtable_t * entry = csp_rtable_find(id, CSP_ID_HOST_SIZE, 0); + if (entry == NULL) + return 255; + return entry->mac; +} + +int csp_rtable_set(uint8_t _address, uint8_t _netmask, csp_iface_t *ifc, uint8_t mac) { + + if (ifc == NULL) + return CSP_ERR_INVAL; + + /* Set default route in the old way */ + int address, netmask; + if (_address == CSP_DEFAULT_ROUTE) { + netmask = 0; + address = 0; + } else { + netmask = _netmask; + address = _address; + } + + /* Fist see if the entry exists */ + csp_rtable_t * entry = csp_rtable_find(address, netmask, 1); + + /* If not, create a new one */ + if (!entry) { + entry = csp_malloc(sizeof(csp_rtable_t)); + if (entry == NULL) + return CSP_ERR_NOMEM; + + entry->next = NULL; + /* Add entry to linked-list */ + if (rtable == NULL) { + /* This is the first interface to be added */ + rtable = entry; + } else { + /* One or more interfaces were already added */ + csp_rtable_t * i = rtable; + while (i->next) + i = i->next; + i->next = entry; + } + } + + /* Fill in the data */ + entry->address = address; + entry->netmask = netmask; + entry->interface = ifc; + entry->mac = mac; + + return CSP_ERR_NONE; +} + +#ifdef CSP_DEBUG +void csp_rtable_print(void) { + + for (csp_rtable_t * i = rtable; (i); i = i->next) { + if (i->mac == 255) { + printf("%u/%u %s\r\n", i->address, i->netmask, i->interface->name); + } else { + printf("%u/%u %s %u\r\n", i->address, i->netmask, i->interface->name, i->mac); + } + } + +} +#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_static.c b/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_static.c new file mode 100644 index 00000000..ea993027 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_static.c @@ -0,0 +1,128 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +/* Local typedef for routing table */ +typedef struct __attribute__((__packed__)) csp_rtable_s { + csp_iface_t * interface; + uint8_t mac; +} csp_rtable_t; + +/* Static storage context for routing table */ +static csp_rtable_t routes[CSP_ROUTE_COUNT] = {}; + +/** + * Find entry in static routing table + * This is done by table lookup with fallback to the default route + * The reason why the csp_rtable_t struct is not returned directly + * is that we wish to hide the storage format, mainly because of + * the alternative routing table storage (cidr). + * @param id Node + * @return pointer to found routing entry + */ +static csp_rtable_t * csp_rtable_find(uint8_t id) { + + if (routes[id].interface != NULL) { + return &routes[id]; + } else if (routes[CSP_DEFAULT_ROUTE].interface != NULL) { + return &routes[CSP_DEFAULT_ROUTE]; + } + return NULL; + +} + +csp_iface_t * csp_rtable_find_iface(uint8_t id) { + csp_rtable_t * route = csp_rtable_find(id); + if (route == NULL) + return NULL; + return route->interface; +} + +uint8_t csp_rtable_find_mac(uint8_t id) { + csp_rtable_t * route = csp_rtable_find(id); + if (route == NULL) + return 255; + return route->mac; +} + +void csp_rtable_clear(void) { + memset(routes, 0, sizeof(routes[0]) * CSP_ROUTE_COUNT); +} + +void csp_route_table_load(uint8_t route_table_in[CSP_ROUTE_TABLE_SIZE]) { + memcpy(routes, route_table_in, sizeof(routes[0]) * CSP_ROUTE_COUNT); +} + +void csp_route_table_save(uint8_t route_table_out[CSP_ROUTE_TABLE_SIZE]) { + memcpy(route_table_out, routes, sizeof(routes[0]) * CSP_ROUTE_COUNT); +} + +int csp_rtable_set(uint8_t node, uint8_t mask, csp_iface_t *ifc, uint8_t mac) { + + /* Don't add nothing */ + if (ifc == NULL) + return CSP_ERR_INVAL; + + /** + * Check if the interface has been added. + * + * NOTE: For future implementations, interfaces should call + * csp_route_add_if in its csp_if__init function, instead + * of registering at first route_set, in order to make the interface + * available to network based (CMP) route configuration. + */ + csp_iflist_add(ifc); + + /* Set route */ + if (node <= CSP_DEFAULT_ROUTE) { + routes[node].interface = ifc; + routes[node].mac = mac; + } else { + csp_log_error("Failed to set route: invalid node id %u", node); + return CSP_ERR_INVAL; + } + + return CSP_ERR_NONE; + +} + +void csp_rtable_load(const char * buffer) { +} + +int csp_rtable_check(const char * buffer) { + return -1; +} + +#ifdef CSP_DEBUG +void csp_rtable_print(void) { + int i; + printf("Node Interface Address\r\n"); + for (i = 0; i < CSP_DEFAULT_ROUTE; i++) + if (routes[i].interface != NULL) + printf("%4u %-9s %u\r\n", i, + routes[i].interface->name, + routes[i].mac == CSP_NODE_MAC ? i : routes[i].mac); + printf(" * %-9s %u\r\n", routes[CSP_DEFAULT_ROUTE].interface->name, routes[CSP_DEFAULT_ROUTE].mac); + +} +#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/transport/csp_rdp.c b/gomspace/libgscsp/lib/libcsp/src/transport/csp_rdp.c new file mode 100644 index 00000000..e19968e2 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/transport/csp_rdp.c @@ -0,0 +1,1102 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + * This is a implementation of the seq/ack handling taken from the Reliable Datagram Protocol (RDP) + * For more information read RFC 908/1151. The implementation has been extended to include support for + * delayed acknowledgments, to improve performance over half-duplex links. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "../csp_port.h" +#include "../csp_conn.h" +#include "../csp_io.h" +#include "csp_transport.h" + +#ifdef CSP_USE_RDP + +#define RDP_SYN 0x01 +#define RDP_ACK 0x02 +#define RDP_EAK 0x04 +#define RDP_RST 0x08 + +static uint32_t csp_rdp_window_size = 4; +static uint32_t csp_rdp_conn_timeout = 10000; +static uint32_t csp_rdp_packet_timeout = 1000; +static uint32_t csp_rdp_delayed_acks = 1; +static uint32_t csp_rdp_ack_timeout = 1000 / 4; +static uint32_t csp_rdp_ack_delay_count = 4 / 2; + +/* Used for queue calls */ +static CSP_BASE_TYPE pdTrue = 1; + +typedef struct __attribute__((__packed__)) { + /* The timestamp is placed in the padding bytes */ + uint8_t padding[CSP_PADDING_BYTES - 2 * sizeof(uint32_t)]; + uint32_t quarantine; // EACK quarantine period + uint32_t timestamp; // Time the message was sent + uint16_t length; // Length field must be just before CSP ID + csp_id_t id; // CSP id must be just before data + uint8_t data[]; // This just points to the rest of the buffer, without a size indication. +} rdp_packet_t; + +typedef struct __attribute__((__packed__)) { + union __attribute__((__packed__)) { + uint8_t flags; + struct __attribute__((__packed__)) { +#if defined(CSP_BIG_ENDIAN) && !defined(CSP_LITTLE_ENDIAN) + unsigned int res : 4; + unsigned int syn : 1; + unsigned int ack : 1; + unsigned int eak : 1; + unsigned int rst : 1; +#elif defined(CSP_LITTLE_ENDIAN) && !defined(CSP_BIG_ENDIAN) + unsigned int rst : 1; + unsigned int eak : 1; + unsigned int ack : 1; + unsigned int syn : 1; + unsigned int res : 4; +#else + #error "Must define one of CSP_BIG_ENDIAN or CSP_LITTLE_ENDIAN in csp_platform.h" +#endif + }; + }; + uint16_t seq_nr; + uint16_t ack_nr; +} rdp_header_t; + +/** + * RDP Headers: + * The following functions are helper functions that handles the extra RDP + * information that needs to be appended to all data packets. + */ +static rdp_header_t * csp_rdp_header_add(csp_packet_t * packet) { + rdp_header_t * header = (rdp_header_t *) &packet->data[packet->length]; + packet->length += sizeof(rdp_header_t); + memset(header, 0, sizeof(rdp_header_t)); + return header; +} + +static rdp_header_t * csp_rdp_header_remove(csp_packet_t * packet) { + rdp_header_t * header = (rdp_header_t *) &packet->data[packet->length-sizeof(rdp_header_t)]; + packet->length -= sizeof(rdp_header_t); + return header; +} + +static rdp_header_t * csp_rdp_header_ref(csp_packet_t * packet) { + rdp_header_t * header = (rdp_header_t *) &packet->data[packet->length-sizeof(rdp_header_t)]; + return header; +} + +/* Functions for comparing wrapping sequence numbers and timestamps */ + +/* Return 1 if seq is between start and end (both inclusive) */ +static inline int csp_rdp_seq_between(uint16_t seq, uint16_t start, uint16_t end) { + return (uint16_t)(end - start) >= (uint16_t)(seq - start); +} + +/* Return 1 if seq is before cmp */ +static inline int csp_rdp_seq_before(uint16_t seq, uint16_t cmp) { + return (int16_t)(seq - cmp) < 0; +} + +/* Return 1 if seq is after cmp */ +static inline int csp_rdp_seq_after(uint16_t seq, uint16_t cmp) { + return csp_rdp_seq_before(cmp, seq); +} + +/* Return 1 if time is between start and end (both inclusive) */ +static inline int csp_rdp_time_between(uint32_t time, uint32_t start, uint32_t end) { + return (uint32_t)(end - start) >= (uint32_t)(time - start); +} + +/* Return 1 if time is before cmp */ +static inline int csp_rdp_time_before(uint32_t time, uint32_t cmp) { + return (int32_t)(time - cmp) < 0; +} + +/* Return 1 if time is after cmp */ +static inline int csp_rdp_time_after(uint32_t time, uint32_t cmp) { + return csp_rdp_time_before(cmp, time); +} + +/** + * CONTROL MESSAGES + * The following function is used to send empty messages, + * with ACK, SYN or RST flag. + */ +static int csp_rdp_send_cmp(csp_conn_t * conn, csp_packet_t * packet, int flags, int seq_nr, int ack_nr) { + + csp_id_t idout; + + /* Generate message */ + if (!packet) { + packet = csp_buffer_get(20); + if (!packet) + return CSP_ERR_NOMEM; + packet->length = 0; + } + + /* Add RDP header */ + rdp_header_t * header = csp_rdp_header_add(packet); + header->seq_nr = csp_hton16(seq_nr); + header->ack_nr = csp_hton16(ack_nr); + header->ack = (flags & RDP_ACK) ? 1 : 0; + header->eak = (flags & RDP_EAK) ? 1 : 0; + header->syn = (flags & RDP_SYN) ? 1 : 0; + header->rst = (flags & RDP_RST) ? 1 : 0; + + /* Send copy to tx_queue, before sending packet to IF */ + if (flags & RDP_SYN) { + rdp_packet_t * rdp_packet = csp_buffer_clone(packet); + if (rdp_packet == NULL) return CSP_ERR_NOMEM; + rdp_packet->timestamp = csp_get_ms(); + if (csp_queue_enqueue(conn->rdp.tx_queue, &rdp_packet, 0) != CSP_QUEUE_OK) + csp_buffer_free(rdp_packet); + } + + /* Send control messages with high priority */ + idout = conn->idout; + idout.pri = conn->idout.pri < CSP_PRIO_HIGH ? conn->idout.pri : CSP_PRIO_HIGH; + + /* Send packet to IF */ + csp_iface_t * ifout = csp_rtable_find_iface(idout.dst); + if (csp_send_direct(idout, packet, ifout, 0) != CSP_ERR_NONE) { + csp_log_error("INTERFACE ERROR: not possible to send"); + csp_buffer_free(packet); + return CSP_ERR_BUSY; + } + + /* Update last ACK time stamp */ + if (flags & RDP_ACK) { + conn->rdp.rcv_lsa = ack_nr; + conn->rdp.ack_timestamp = csp_get_ms(); + } + + return CSP_ERR_NONE; + +} + +/** + * EXTENDED ACKNOWLEDGEMENTS + * The following function sends an extended ACK packet + */ +static int csp_rdp_send_eack(csp_conn_t * conn) { + + /* Allocate message */ + csp_packet_t * packet_eack = csp_buffer_get(100); + if (packet_eack == NULL) return CSP_ERR_NOMEM; + packet_eack->length = 0; + + /* Loop through RX queue */ + int i, count; + csp_packet_t * packet; + count = csp_queue_size(conn->rdp.rx_queue); + for (i = 0; i < count; i++) { + + if (csp_queue_dequeue_isr(conn->rdp.rx_queue, &packet, &pdTrue) != CSP_QUEUE_OK) { + csp_log_error("Cannot dequeue from rx_queue in queue deliver"); + break; + } + + /* Add seq nr to EACK packet */ + rdp_header_t * header = csp_rdp_header_ref(packet); + packet_eack->data16[packet_eack->length/sizeof(uint16_t)] = csp_hton16(header->seq_nr); + packet_eack->length += sizeof(uint16_t); + csp_log_protocol("Added EACK nr %u", header->seq_nr); + + /* Requeue */ + csp_queue_enqueue_isr(conn->rdp.rx_queue, &packet, &pdTrue); + + } + + return csp_rdp_send_cmp(conn, packet_eack, RDP_ACK | RDP_EAK, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + +} + + +/** + * SYN Packet + * The following function sends a SYN packet + */ +static int csp_rdp_send_syn(csp_conn_t * conn) { + + /* Allocate message */ + csp_packet_t * packet = csp_buffer_get(100); + if (packet == NULL) return CSP_ERR_NOMEM; + + /* Generate contents */ + packet->data32[0] = csp_hton32(csp_rdp_window_size); + packet->data32[1] = csp_hton32(csp_rdp_conn_timeout); + packet->data32[2] = csp_hton32(csp_rdp_packet_timeout); + packet->data32[3] = csp_hton32(csp_rdp_delayed_acks); + packet->data32[4] = csp_hton32(csp_rdp_ack_timeout); + packet->data32[5] = csp_hton32(csp_rdp_ack_delay_count); + packet->length = 6 * sizeof(uint32_t); + + return csp_rdp_send_cmp(conn, packet, RDP_SYN, conn->rdp.snd_iss, 0); + +} + +static inline int csp_rdp_receive_data(csp_conn_t * conn, csp_packet_t * packet) { + + /* Remove RDP header before passing to userspace */ + csp_rdp_header_remove(packet); + + /* Enqueue data */ + if (csp_conn_enqueue_packet(conn, packet) < 0) { + csp_log_warn("Conn RX buffer full"); + return CSP_ERR_NOBUFS; + } + + return CSP_ERR_NONE; + +} + +static inline void csp_rdp_rx_queue_flush(csp_conn_t * conn) { + + /* Loop through RX queue */ + int i, count; + csp_packet_t * packet; + +front: + count = csp_queue_size(conn->rdp.rx_queue); + for (i = 0; i < count; i++) { + + if (csp_queue_dequeue_isr(conn->rdp.rx_queue, &packet, &pdTrue) != CSP_QUEUE_OK) { + csp_log_error("Cannot dequeue from rx_queue in queue deliver"); + break; + } + + rdp_header_t * header = csp_rdp_header_ref(packet); + csp_log_protocol("RX Queue deliver matching Element, seq %u", header->seq_nr); + + /* If the matching packet was found: */ + if (header->seq_nr == (uint16_t)(conn->rdp.rcv_cur + 1)) { + csp_log_protocol("Deliver seq %u", header->seq_nr); + csp_rdp_receive_data(conn, packet); + conn->rdp.rcv_cur++; + /* Loop from first element again */ + goto front; + + /* Otherwise, requeue */ + } else { + csp_queue_enqueue_isr(conn->rdp.rx_queue, &packet, &pdTrue); + } + + } + +} + +static inline bool csp_rdp_seq_in_rx_queue(csp_conn_t * conn, uint16_t seq_nr) { + + /* Loop through RX queue */ + int i, count; + rdp_packet_t * packet; + count = csp_queue_size(conn->rdp.rx_queue); + for (i = 0; i < count; i++) { + + if (csp_queue_dequeue_isr(conn->rdp.rx_queue, &packet, &pdTrue) != CSP_QUEUE_OK) { + csp_log_error("Cannot dequeue from rx_queue in queue exists"); + break; + } + + csp_queue_enqueue_isr(conn->rdp.rx_queue, &packet, &pdTrue); + + rdp_header_t * header = csp_rdp_header_ref((csp_packet_t *) packet); + csp_log_protocol("RX Queue exists matching Element, seq %u", header->seq_nr); + + /* If the matching packet was found, deliver */ + if (header->seq_nr == seq_nr) { + csp_log_protocol("We have a match"); + return true; + } + + } + + return false; + +} + +static inline int csp_rdp_rx_queue_add(csp_conn_t * conn, csp_packet_t * packet, uint16_t seq_nr) { + + if (csp_rdp_seq_in_rx_queue(conn, seq_nr)) + return CSP_QUEUE_ERROR; + return csp_queue_enqueue_isr(conn->rdp.rx_queue, &packet, &pdTrue); + +} + +static void csp_rdp_flush_eack(csp_conn_t * conn, csp_packet_t * eack_packet) { + + /* Loop through TX queue */ + int i, j, count; + rdp_packet_t * packet; + count = csp_queue_size(conn->rdp.tx_queue); + for (i = 0; i < count; i++) { + + if (csp_queue_dequeue(conn->rdp.tx_queue, &packet, 0) != CSP_QUEUE_OK) { + csp_log_error("Cannot dequeue from tx_queue in flush EACK"); + break; + } + + rdp_header_t * header = csp_rdp_header_ref((csp_packet_t *) packet); + csp_log_protocol("EACK compare element, time %u, seq %u", packet->timestamp, csp_ntoh16(header->seq_nr)); + + /* Look for this element in EACKs */ + int match = 0; + for (j = 0; j < (int)((eack_packet->length - sizeof(rdp_header_t)) / sizeof(uint16_t)); j++) { + if (csp_ntoh16(eack_packet->data16[j]) == csp_ntoh16(header->seq_nr)) + match = 1; + + /* Enable this if you want EACK's to trigger retransmission */ + if (csp_ntoh16(eack_packet->data16[j]) > csp_ntoh16(header->seq_nr)) { + uint32_t time_now = csp_get_ms(); + if (csp_rdp_time_after(time_now, packet->quarantine)) { + packet->timestamp = time_now - conn->rdp.packet_timeout - 1; + packet->quarantine = time_now + conn->rdp.packet_timeout / 2; + } + } + } + + if (match == 0) { + /* If not found, put back on tx queue */ + csp_queue_enqueue(conn->rdp.tx_queue, &packet, 0); + } else { + /* Found, free */ + csp_log_protocol("TX Element %u freed", csp_ntoh16(header->seq_nr)); + csp_buffer_free(packet); + } + + } + +} + +static inline bool csp_rdp_should_ack(csp_conn_t * conn) { + + /* If delayed ACKs are not used, always ACK */ + if (!conn->rdp.delayed_acks) { + return true; + } + + /* ACK if time since last ACK is greater than ACK timeout */ + uint32_t time_now = csp_get_ms(); + if (csp_rdp_time_after(time_now, conn->rdp.ack_timestamp + conn->rdp.ack_timeout)) + return true; + + /* ACK if number of unacknowledged packets is greater than delay count */ + if (csp_rdp_seq_after(conn->rdp.rcv_cur, conn->rdp.rcv_lsa + conn->rdp.ack_delay_count)) + return true; + + return false; + +} + +void csp_rdp_flush_all(csp_conn_t * conn) { + + if ((conn == NULL) || conn->rdp.tx_queue == NULL) { + csp_log_error("Null pointer passed to rdp flush all"); + return; + } + + rdp_packet_t * packet; + + /* Empty TX queue */ + while (csp_queue_dequeue_isr(conn->rdp.tx_queue, &packet, &pdTrue) == CSP_QUEUE_OK) { + if (packet != NULL) { + csp_log_protocol("RDP %p: Flush TX Element, time %u, seq %u", conn, packet->timestamp, csp_ntoh16(csp_rdp_header_ref((csp_packet_t *) packet)->seq_nr)); + csp_buffer_free(packet); + } + } + + /* Empty RX queue */ + while (csp_queue_dequeue_isr(conn->rdp.rx_queue, &packet, &pdTrue) == CSP_QUEUE_OK) { + if (packet != NULL) { + csp_log_protocol("RDP %p: Flush RX Element, time %u, seq %u", conn, packet->timestamp, csp_ntoh16(csp_rdp_header_ref((csp_packet_t *) packet)->seq_nr)); + csp_buffer_free(packet); + } + } + +} + + +int csp_rdp_check_ack(csp_conn_t * conn) { + + /* Check all RX queues for spare capacity */ + int prio, avail = 1; + for (prio = 0; prio < CSP_RX_QUEUES; prio++) { + if (CSP_RX_QUEUE_LENGTH - csp_queue_size(conn->rx_queue[prio]) <= 2 * (int32_t)conn->rdp.window_size) { + avail = 0; + break; + } + } + + /* If more space available, only send after ack timeout or immediately if delay_acks is zero */ + if (avail && csp_rdp_should_ack(conn)) + csp_rdp_send_cmp(conn, NULL, RDP_ACK, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + + return CSP_ERR_NONE; + +} + +static inline bool csp_rdp_is_conn_ready_for_tx(csp_conn_t * conn) +{ + // Check Tx window (messages waiting for acks) + if (csp_rdp_seq_after(conn->rdp.snd_nxt, conn->rdp.snd_una + conn->rdp.window_size - 1)) { + return false; + } + return true; +} + +/** + * This function must be called with regular intervals for the + * RDP protocol to work as expected. This takes care of closing + * stale connections and retransmitting traffic. A good place to + * call this function is from the CSP router task. + */ +void csp_rdp_check_timeouts(csp_conn_t * conn) { + + rdp_packet_t * packet; + + /** + * CONNECTION TIMEOUT: + * Check that connection has not timed out inside the network stack + * */ + uint32_t time_now = csp_get_ms(); + if (conn->socket != NULL) { + if (csp_rdp_time_after(time_now, conn->timestamp + conn->rdp.conn_timeout)) { + csp_log_warn("RDP %p: Found a lost connection (now: %u, ts: %u, to: %u), closing now", + conn, time_now, conn->timestamp, conn->rdp.conn_timeout); + csp_close(conn); + return; + } + } + + /** + * CLOSE-WAIT TIMEOUT: + * After waiting a while in CLOSE-WAIT, the connection should be closed. + */ + if (conn->rdp.state == RDP_CLOSE_WAIT) { + if (csp_rdp_time_after(time_now, conn->timestamp + conn->rdp.conn_timeout)) { + csp_log_protocol("RDP %p: CLOSE_WAIT timeout", conn); + csp_close(conn); + } + return; + } + + /** + * MESSAGE TIMEOUT: + * Check each outgoing message for TX timeout + */ + int i, count; + count = csp_queue_size(conn->rdp.tx_queue); + for (i = 0; i < count; i++) { + + if ((csp_queue_dequeue_isr(conn->rdp.tx_queue, &packet, &pdTrue) != CSP_QUEUE_OK) || packet == NULL) { + csp_log_warn("Cannot dequeue from tx_queue in check timeout"); + break; + } + + /* Get header */ + rdp_header_t * header = csp_rdp_header_ref((csp_packet_t *) packet); + + /* If acked, do not retransmit */ + if (csp_rdp_seq_before(csp_ntoh16(header->seq_nr), conn->rdp.snd_una)) { + csp_log_protocol("TX Element Free, time %u, seq %u, una %u", packet->timestamp, csp_ntoh16(header->seq_nr), conn->rdp.snd_una); + csp_buffer_free(packet); + continue; + } + + /* Check timestamp and retransmit if needed */ + if (csp_rdp_time_after(time_now, packet->timestamp + conn->rdp.packet_timeout)) { + csp_log_protocol("TX Element timed out, retransmitting seq %u", csp_ntoh16(header->seq_nr)); + + /* Update to latest outgoing ACK */ + header->ack_nr = csp_hton16(conn->rdp.rcv_cur); + + /* Send copy to tx_queue */ + packet->timestamp = csp_get_ms(); + csp_packet_t * new_packet = csp_buffer_clone(packet); + csp_iface_t * ifout = csp_rtable_find_iface(conn->idout.dst); + if (csp_send_direct(conn->idout, new_packet, ifout, 0) != CSP_ERR_NONE) { + csp_log_warn("Retransmission failed"); + csp_buffer_free(new_packet); + } + + } + + /* Requeue the TX element */ + csp_queue_enqueue_isr(conn->rdp.tx_queue, &packet, &pdTrue); + + } + + /** + * ACK TIMEOUT: + * Check ACK timeouts, if we have unacknowledged segments + */ + if (conn->rdp.delayed_acks) { + csp_rdp_check_ack(conn); + } + + /* Wake user task if connection is open and additional Tx can be done */ + if ((conn->rdp.state == RDP_OPEN) && csp_rdp_is_conn_ready_for_tx(conn)) { + csp_log_protocol("RDP %p: Wake Tx task (check timeouts)", conn); + csp_bin_sem_post(&conn->rdp.tx_wait); + } +} + +void csp_rdp_new_packet(csp_conn_t * conn, csp_packet_t * packet) { + + /* Get RX header and convert to host byte-order */ + rdp_header_t * rx_header = csp_rdp_header_ref(packet); + rx_header->ack_nr = csp_ntoh16(rx_header->ack_nr); + rx_header->seq_nr = csp_ntoh16(rx_header->seq_nr); + + csp_log_protocol("RDP %p: Received in S %u: syn %u, ack %u, eack %u, " + "rst %u, seq_nr %5u, ack_nr %5u, packet_len %u (%u)", + conn, conn->rdp.state, rx_header->syn, rx_header->ack, rx_header->eak, + rx_header->rst, rx_header->seq_nr, rx_header->ack_nr, + packet->length, packet->length - sizeof(rdp_header_t)); + + /* If a RESET was received. */ + if (rx_header->rst) { + + if (rx_header->ack) { + /* Store current ack'ed sequence number */ + conn->rdp.snd_una = rx_header->ack_nr + 1; + } + + if (conn->rdp.state == RDP_CLOSE_WAIT || conn->rdp.state == RDP_CLOSED) { + csp_log_protocol("RDP %p: RST received in CLOSE_WAIT or CLOSED. Now closing connection", conn); + goto discard_close; + } else { + csp_log_protocol("RDP %p: Got RESET in state %u", conn, conn->rdp.state); + + if (rx_header->seq_nr == (uint16_t)(conn->rdp.rcv_cur + 1)) { + csp_log_protocol("RDP %p: RESET in sequence, no more data incoming, reply with RESET", conn); + conn->rdp.state = RDP_CLOSE_WAIT; + conn->timestamp = csp_get_ms(); + csp_rdp_send_cmp(conn, NULL, RDP_ACK | RDP_RST, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + goto discard_close; + } else { + csp_log_protocol("RDP %p: RESET out of sequence, keep connection open", conn); + goto discard_open; + } + } + } + + /* The BIG FAT switch (state-machine) */ + switch(conn->rdp.state) { + + /** + * STATE == CLOSED + */ + case RDP_CLOSED: { + + /* No SYN flag set while in closed. Inform by sending back RST */ + if (!rx_header->syn) { + csp_log_protocol("Not SYN received in CLOSED state. Discarding packet"); + csp_rdp_send_cmp(conn, NULL, RDP_RST, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + goto discard_close; + } + + csp_log_protocol("RDP: SYN-Received"); + + /* Setup TX seq. */ + conn->rdp.snd_iss = (uint16_t)rand(); + conn->rdp.snd_nxt = conn->rdp.snd_iss + 1; + conn->rdp.snd_una = conn->rdp.snd_iss; + + /* Store RX seq. */ + conn->rdp.rcv_cur = rx_header->seq_nr; + conn->rdp.rcv_irs = rx_header->seq_nr; + conn->rdp.rcv_lsa = rx_header->seq_nr; + + /* Store RDP options */ + conn->rdp.window_size = csp_ntoh32(packet->data32[0]); + conn->rdp.conn_timeout = csp_ntoh32(packet->data32[1]); + conn->rdp.packet_timeout = csp_ntoh32(packet->data32[2]); + conn->rdp.delayed_acks = csp_ntoh32(packet->data32[3]); + conn->rdp.ack_timeout = csp_ntoh32(packet->data32[4]); + conn->rdp.ack_delay_count = csp_ntoh32(packet->data32[5]); + csp_log_protocol("RDP: Window Size %u, conn timeout %u, packet timeout %u", + conn->rdp.window_size, conn->rdp.conn_timeout, conn->rdp.packet_timeout); + csp_log_protocol("RDP: Delayed acks: %u, ack timeout %u, ack each %u packet", + conn->rdp.delayed_acks, conn->rdp.ack_timeout, conn->rdp.ack_delay_count); + + /* Connection accepted */ + conn->rdp.state = RDP_SYN_RCVD; + + /* Send SYN/ACK */ + csp_rdp_send_cmp(conn, NULL, RDP_ACK | RDP_SYN, conn->rdp.snd_iss, conn->rdp.rcv_irs); + + goto discard_open; + + } + break; + + /** + * STATE == SYN-SENT + */ + case RDP_SYN_SENT: { + + /* First check SYN/ACK */ + if (rx_header->syn && rx_header->ack) { + + conn->rdp.rcv_cur = rx_header->seq_nr; + conn->rdp.rcv_irs = rx_header->seq_nr; + conn->rdp.rcv_lsa = rx_header->seq_nr - 1; + conn->rdp.snd_una = rx_header->ack_nr + 1; + conn->rdp.ack_timestamp = csp_get_ms(); + conn->rdp.state = RDP_OPEN; + + csp_log_protocol("RDP: NP: Connection OPEN"); + + /* Send ACK */ + csp_rdp_send_cmp(conn, NULL, RDP_ACK, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + + /* Wake TX task */ + csp_log_protocol("RDP %p: Wake Tx task (ack)", conn); + csp_bin_sem_post(&conn->rdp.tx_wait); + + goto discard_open; + } + + /* If there was no SYN in the reply, our SYN message hit an already open connection + * This is handled by sending a RST. + * Normally this would be followed up by a new connection attempt, however + * we don't have a method for signaling this to the user space. + */ + if (rx_header->ack) { + csp_log_error("Half-open connection found, sending RST"); + csp_rdp_send_cmp(conn, NULL, RDP_RST, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + csp_log_protocol("RDP %p: Wake Tx task (rst)", conn); + csp_bin_sem_post(&conn->rdp.tx_wait); + + goto discard_open; + } + + /* Otherwise we have an invalid command, such as a SYN reply to a SYN command, + * indicating simultaneous connections, which is not possible in the way CSP + * reserves some ports for server and some for clients. + */ + csp_log_error("Invalid reply to SYN request"); + goto discard_close; + + } + break; + + /** + * STATE == OPEN + */ + case RDP_SYN_RCVD: + case RDP_OPEN: + { + + /* SYN or !ACK is invalid */ + if (rx_header->syn || !rx_header->ack) { + if (rx_header->seq_nr != conn->rdp.rcv_irs) { + csp_log_error("Invalid SYN or no ACK, resetting!"); + goto discard_close; + } else { + csp_log_protocol("Ignoring duplicate SYN packet!"); + goto discard_open; + } + } + + /* Check sequence number */ + if (!csp_rdp_seq_between(rx_header->seq_nr, conn->rdp.rcv_cur + 1, conn->rdp.rcv_cur + conn->rdp.window_size * 2)) { + csp_log_protocol("Invalid sequence number! %"PRIu16" not between %"PRIu16" and %"PRIu16, + rx_header->seq_nr, conn->rdp.rcv_cur + 1, conn->rdp.rcv_cur + 1 + conn->rdp.window_size * 2); + /* If duplicate SYN received, send another SYN/ACK */ + if (conn->rdp.state == RDP_SYN_RCVD) + csp_rdp_send_cmp(conn, NULL, RDP_ACK | RDP_SYN, conn->rdp.snd_iss, conn->rdp.rcv_irs); + /* If duplicate data packet received, send EACK back */ + if (conn->rdp.state == RDP_OPEN) + csp_rdp_send_eack(conn); + + goto discard_open; + } + + /* Check ACK number */ + if (!csp_rdp_seq_between(rx_header->ack_nr, conn->rdp.snd_una - 1 - (conn->rdp.window_size * 2), conn->rdp.snd_nxt - 1)) { + csp_log_error("Invalid ACK number! %u not between %u and %u", + rx_header->ack_nr, conn->rdp.snd_una - 1 - (conn->rdp.window_size * 2), conn->rdp.snd_nxt - 1); + goto discard_open; + } + + /* Check SYN_RCVD ACK */ + if (conn->rdp.state == RDP_SYN_RCVD) { + if (rx_header->ack_nr != conn->rdp.snd_iss) { + csp_log_error("SYN-RCVD: Wrong ACK number"); + goto discard_close; + } + csp_log_protocol("RDP: NC: Connection OPEN"); + conn->rdp.state = RDP_OPEN; + + /* If a socket is set, this message is the first in a new connection + * so the connection must be queued to the socket. */ + if (conn->socket != NULL) { + + /* Try queueing */ + if (csp_queue_enqueue(conn->socket, &conn, 0) == CSP_QUEUE_FULL) { + csp_log_error("ERROR socket cannot accept more connections"); + goto discard_close; + } + + /* Ensure that this connection will not be posted to this socket again + * and remember that the connection handle has been passed to userspace + * by setting the socket = NULL */ + conn->socket = NULL; + } + + } + + /* Store current ack'ed sequence number */ + conn->rdp.snd_una = rx_header->ack_nr + 1; + + /* We have an EACK */ + if (rx_header->eak) { + if (packet->length > sizeof(rdp_header_t)) + csp_rdp_flush_eack(conn, packet); + goto discard_open; + } + + /* If no data, return here */ + if (packet->length <= sizeof(rdp_header_t)) + goto discard_open; + + /* If message is not in sequence, send EACK and store packet */ + if (rx_header->seq_nr != (uint16_t)(conn->rdp.rcv_cur + 1)) { + if (csp_rdp_rx_queue_add(conn, packet, rx_header->seq_nr) != CSP_QUEUE_OK) { + csp_log_protocol("Duplicate sequence number"); + csp_rdp_check_ack(conn); + goto discard_open; + } + csp_rdp_send_eack(conn); + goto accepted_open; + } + + /* Store sequence number before stripping RDP header */ + uint16_t seq_nr = rx_header->seq_nr; + + /* Receive data */ + if (csp_rdp_receive_data(conn, packet) != CSP_ERR_NONE) + goto discard_open; + + /* Update last received packet */ + conn->rdp.rcv_cur = seq_nr; + + /* Only ACK the message if there is room for a full window in the RX buffer. + * Unacknowledged segments are ACKed by csp_rdp_check_timeouts when the buffer is + * no longer full. */ + csp_rdp_check_ack(conn); + + /* Flush RX queue */ + csp_rdp_rx_queue_flush(conn); + + goto accepted_open; + + } + break; + + case RDP_CLOSE_WAIT: + + /* Ignore SYN or !ACK */ + if (rx_header->syn || !rx_header->ack) { + csp_log_protocol("Invalid SYN or no ACK in CLOSE-WAIT"); + goto discard_open; + } + + /* Check ACK number */ + if (!csp_rdp_seq_between(rx_header->ack_nr, conn->rdp.snd_una - 1 - (conn->rdp.window_size * 2), conn->rdp.snd_nxt - 1)) { + csp_log_error("Invalid ACK number! %u not between %u and %u", + rx_header->ack_nr, conn->rdp.snd_una - 1 - (conn->rdp.window_size * 2), conn->rdp.snd_nxt - 1); + goto discard_open; + } + + /* Store current ack'ed sequence number */ + conn->rdp.snd_una = rx_header->ack_nr + 1; + + /* Send back a reset */ + csp_rdp_send_cmp(conn, NULL, RDP_ACK | RDP_RST, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + + goto discard_open; + + default: + csp_log_error("RDP: ERROR default state!"); + goto discard_close; + } + +discard_close: + /* If user-space has received the connection handle, wake it up, + * by sending a NULL pointer, user-space should close connection */ + if (conn->socket == NULL) { + csp_log_protocol("RDP %p: Waiting for userspace to close", conn); + csp_conn_enqueue_packet(conn, NULL); + } else { + csp_close(conn); + } + +discard_open: + csp_buffer_free(packet); +accepted_open: + return; + +} + +int csp_rdp_connect(csp_conn_t * conn, uint32_t timeout) { + + int retry = 1; + + conn->rdp.window_size = csp_rdp_window_size; + conn->rdp.conn_timeout = csp_rdp_conn_timeout; + conn->rdp.packet_timeout = csp_rdp_packet_timeout; + conn->rdp.delayed_acks = csp_rdp_delayed_acks; + conn->rdp.ack_timeout = csp_rdp_ack_timeout; + conn->rdp.ack_delay_count = csp_rdp_ack_delay_count; + conn->rdp.ack_timestamp = csp_get_ms(); + +retry: + csp_log_protocol("RDP %p: Active connect, conn state %u", conn, conn->rdp.state); + + if (conn->rdp.state == RDP_OPEN) { + csp_log_error("RDP %p: Connection already open", conn); + return CSP_ERR_ALREADY; + } + + /* Randomize ISS */ + conn->rdp.snd_iss = (uint16_t)rand(); + + conn->rdp.snd_nxt = conn->rdp.snd_iss + 1; + conn->rdp.snd_una = conn->rdp.snd_iss; + + csp_log_protocol("RDP %p: AC: Sending SYN", conn); + + /* Ensure semaphore is busy, so router task can release it */ + csp_bin_sem_wait(&conn->rdp.tx_wait, 0); + + /* Send SYN message */ + conn->rdp.state = RDP_SYN_SENT; + if (csp_rdp_send_syn(conn) != CSP_ERR_NONE) + goto error; + + /* Wait for router task to release semaphore */ + csp_log_protocol("RDP %p: AC: Waiting for SYN/ACK reply...", conn); + int result = csp_bin_sem_wait(&conn->rdp.tx_wait, conn->rdp.conn_timeout); + + if (result == CSP_SEMAPHORE_OK) { + if (conn->rdp.state == RDP_OPEN) { + csp_log_protocol("RDP %p: AC: Connection OPEN", conn); + return CSP_ERR_NONE; + } else if(conn->rdp.state == RDP_SYN_SENT) { + if (retry) { + csp_log_warn("RDP %p: Half-open connection detected, RST sent, now retrying", conn); + csp_rdp_flush_all(conn); + retry = 0; + goto retry; + } else { + csp_log_error("RDP %p: Connection stayed half-open, even after RST and retry!", conn); + goto error; + } + } + } else { + csp_log_protocol("RDP %p: AC: Connection Failed", conn); + goto error; + } + +error: + conn->rdp.state = RDP_CLOSE_WAIT; + return CSP_ERR_TIMEDOUT; + +} + +int csp_rdp_send(csp_conn_t * conn, csp_packet_t * packet, uint32_t timeout) { + + if (conn->rdp.state != RDP_OPEN) { + csp_log_error("RDP: ERROR cannot send, connection reset"); + return CSP_ERR_RESET; + } + + while ((conn->rdp.state == RDP_OPEN) && (csp_rdp_is_conn_ready_for_tx(conn) == false)) { + csp_log_protocol("RDP %p: Waiting for window update before sending seq %u", conn, conn->rdp.snd_nxt); + if ((csp_bin_sem_wait(&conn->rdp.tx_wait, conn->rdp.conn_timeout)) != CSP_SEMAPHORE_OK) { + csp_log_error("RDP %p: Timeout during send", conn); + return CSP_ERR_TIMEDOUT; + } + } + + if (conn->rdp.state != RDP_OPEN) { + csp_log_error("RDP: ERROR cannot send, connection reset"); + return CSP_ERR_RESET; + } + + /* Add RDP header */ + rdp_header_t * tx_header = csp_rdp_header_add(packet); + tx_header->ack_nr = csp_hton16(conn->rdp.rcv_cur); + tx_header->seq_nr = csp_hton16(conn->rdp.snd_nxt); + tx_header->ack = 1; + + /* Send copy to tx_queue */ + rdp_packet_t * rdp_packet = csp_buffer_clone(packet); + if (rdp_packet == NULL) { + csp_log_error("Failed to allocate packet buffer"); + return CSP_ERR_NOMEM; + } + + rdp_packet->timestamp = csp_get_ms(); + rdp_packet->quarantine = 0; + if (csp_queue_enqueue(conn->rdp.tx_queue, &rdp_packet, 0) != CSP_QUEUE_OK) { + csp_log_error("No more space in RDP retransmit queue"); + csp_buffer_free(rdp_packet); + return CSP_ERR_NOBUFS; + } + + csp_log_protocol("RDP: Sending in S %u: syn %u, ack %u, eack %u, " + "rst %u, seq_nr %5u, ack_nr %5u, packet_len %u (%u)", + conn->rdp.state, tx_header->syn, tx_header->ack, tx_header->eak, + tx_header->rst, csp_ntoh16(tx_header->seq_nr), csp_ntoh16(tx_header->ack_nr), + packet->length, packet->length - sizeof(rdp_header_t)); + + conn->rdp.snd_nxt++; + return CSP_ERR_NONE; + +} + +int csp_rdp_allocate(csp_conn_t * conn) { + + csp_log_protocol("RDP: Creating RDP queues for conn %p", conn); + + /* Set initial state */ + conn->rdp.state = RDP_CLOSED; + conn->rdp.conn_timeout = csp_rdp_conn_timeout; + conn->rdp.packet_timeout = csp_rdp_packet_timeout; + + /* Create a binary semaphore to wait on for tasks */ + if (csp_bin_sem_create(&conn->rdp.tx_wait) != CSP_SEMAPHORE_OK) { + csp_log_error("Failed to initialize semaphore"); + return CSP_ERR_NOMEM; + } + + /* Create TX queue */ + conn->rdp.tx_queue = csp_queue_create(CSP_RDP_MAX_WINDOW, sizeof(csp_packet_t *)); + if (conn->rdp.tx_queue == NULL) { + csp_log_error("Failed to create TX queue for conn"); + csp_bin_sem_remove(&conn->rdp.tx_wait); + return CSP_ERR_NOMEM; + } + + /* Create RX queue */ + conn->rdp.rx_queue = csp_queue_create(CSP_RDP_MAX_WINDOW * 2, sizeof(csp_packet_t *)); + if (conn->rdp.rx_queue == NULL) { + csp_log_error("Failed to create RX queue for conn"); + csp_bin_sem_remove(&conn->rdp.tx_wait); + csp_queue_remove(conn->rdp.tx_queue); + return CSP_ERR_NOMEM; + } + + return CSP_ERR_NONE; + +} + +/** + * @note This function may only be called from csp_close, and is therefore + * without any checks for null pointers. + */ +int csp_rdp_close(csp_conn_t * conn) { + + if (conn->rdp.state == RDP_CLOSED) + return CSP_ERR_NONE; + + /* If message is open, send reset */ + if (conn->rdp.state != RDP_CLOSE_WAIT) { + conn->rdp.state = RDP_CLOSE_WAIT; + conn->timestamp = csp_get_ms(); + csp_rdp_send_cmp(conn, NULL, RDP_ACK | RDP_RST, conn->rdp.snd_nxt, conn->rdp.rcv_cur); + csp_log_protocol("RDP %p: Close, sent RST", conn); + csp_bin_sem_post(&conn->rdp.tx_wait); // wake up any pendng Tx + return CSP_ERR_AGAIN; + } + + csp_log_protocol("RDP %p: Close in CLOSE_WAIT, now closing", conn); + conn->rdp.state = RDP_CLOSED; + return CSP_ERR_NONE; + +} + +/** + * RDP Set socket options + * Controls important parameters of the RDP protocol. + * These settings will be applied to all new outgoing connections. + * The settings are global, so be sure no other task are conflicting with your settings. + */ +void csp_rdp_set_opt(unsigned int window_size, unsigned int conn_timeout_ms, + unsigned int packet_timeout_ms, unsigned int delayed_acks, + unsigned int ack_timeout, unsigned int ack_delay_count) { + csp_rdp_window_size = window_size; + csp_rdp_conn_timeout = conn_timeout_ms; + csp_rdp_packet_timeout = packet_timeout_ms; + csp_rdp_delayed_acks = delayed_acks; + csp_rdp_ack_timeout = ack_timeout; + csp_rdp_ack_delay_count = ack_delay_count; +} + +void csp_rdp_get_opt(unsigned int * window_size, unsigned int * conn_timeout_ms, + unsigned int * packet_timeout_ms, unsigned int * delayed_acks, + unsigned int * ack_timeout, unsigned int * ack_delay_count) { + + if (window_size) + *window_size = csp_rdp_window_size; + if (conn_timeout_ms) + *conn_timeout_ms = csp_rdp_conn_timeout; + if (packet_timeout_ms) + *packet_timeout_ms = csp_rdp_packet_timeout; + if (delayed_acks) + *delayed_acks = csp_rdp_delayed_acks; + if (ack_timeout) + *ack_timeout = csp_rdp_ack_timeout; + if (ack_delay_count) + *ack_delay_count = csp_rdp_ack_delay_count; +} + +#ifdef CSP_DEBUG +void csp_rdp_conn_print(csp_conn_t * conn) { + + if (conn == NULL) + return; + + printf("\tRDP: State %"PRIu16", rcv %"PRIu16", snd %"PRIu16", win %"PRIu32"\r\n", + conn->rdp.state, conn->rdp.rcv_cur, conn->rdp.snd_una, conn->rdp.window_size); + +} +#endif + +#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/transport/csp_transport.h b/gomspace/libgscsp/lib/libcsp/src/transport/csp_transport.h new file mode 100644 index 00000000..7fcda3dc --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/transport/csp_transport.h @@ -0,0 +1,46 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _CSP_TRANSPORT_H_ +#define _CSP_TRANSPORT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** ARRIVING SEGMENT */ +void csp_udp_new_packet(csp_conn_t * conn, csp_packet_t * packet); +void csp_rdp_new_packet(csp_conn_t * conn, csp_packet_t * packet); + +/** RDP: USER REQUESTS */ +int csp_rdp_connect(csp_conn_t * conn, uint32_t timeout); +int csp_rdp_allocate(csp_conn_t * conn); +int csp_rdp_close(csp_conn_t * conn); +void csp_rdp_conn_print(csp_conn_t * conn); +int csp_rdp_send(csp_conn_t * conn, csp_packet_t * packet, uint32_t timeout); +int csp_rdp_check_ack(csp_conn_t * conn); +void csp_rdp_check_timeouts(csp_conn_t * conn); +void csp_rdp_flush_all(csp_conn_t * conn); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _CSP_TRANSPORT_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/transport/csp_udp.c b/gomspace/libgscsp/lib/libcsp/src/transport/csp_udp.c new file mode 100644 index 00000000..61732703 --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/src/transport/csp_udp.c @@ -0,0 +1,49 @@ +/* +Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include "../csp_port.h" +#include "../csp_conn.h" +#include "csp_transport.h" + +void csp_udp_new_packet(csp_conn_t * conn, csp_packet_t * packet) { + + /* Enqueue */ + if (csp_conn_enqueue_packet(conn, packet) < 0) { + csp_log_error("Connection buffer queue full!"); + csp_buffer_free(packet); + return; + } + + /* Try to queue up the new connection pointer */ + if (conn->socket != NULL) { + if (csp_queue_enqueue(conn->socket, &conn, 0) != CSP_QUEUE_OK) { + csp_log_warn("Warning socket connection queue full"); + csp_close(conn); + return; + } + + /* Ensure that this connection will not be posted to this socket again */ + conn->socket = NULL; + } + +} + diff --git a/gomspace/libgscsp/lib/libcsp/utils/cfpsplit.py b/gomspace/libgscsp/lib/libcsp/utils/cfpsplit.py new file mode 100644 index 00000000..9a350e3e --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/utils/cfpsplit.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python + +# Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +# Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +# Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +# Split CFP header in protocol fields + +import sys + +def usage(): + print("usage: cfpsplit.py HEADER") + +def main(): + try: + hdr = sys.argv[1] + except: + usage() + sys.exit(-1) + + try: + hdrhex = int(hdr, 16) + except: + print("HEADER must be in hexadecimal format") + sys.exit(-1) + + if hdrhex > 0x1fffffff: + print("HEADER is not a valid CFP header") + sys.exit(-1) + + print("Source: {0}".format((hdrhex >> 24) & 0x1f)) + print("Destination: {0}".format((hdrhex >> 19) & 0x1f)) + print("Type: {0}".format("MORE" if ((hdrhex >> 18) & 0x01) else "BEGIN")) + print("Remain: {0}".format((hdrhex >> 10) & 0xff)) + print("Identifier: {0}".format((hdrhex >> 0) & 0x3ff)) + +if __name__ == "__main__": + main() diff --git a/gomspace/libgscsp/lib/libcsp/utils/cspsplit.py b/gomspace/libgscsp/lib/libcsp/utils/cspsplit.py new file mode 100644 index 00000000..f4ed942f --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/utils/cspsplit.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python + +# Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +# Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +# Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +# Split CSP header in protocol fields + +import sys + +def usage(): + print("usage: cspsplit.py HEADER") + +def main(): + try: + hdr = sys.argv[1] + except: + usage() + sys.exit(-1) + + try: + hdrhex = int(hdr, 16) + except: + print("HEADER must be in hexadecimal format") + sys.exit(-1) + + print("Priotity: {0}".format((hdrhex >> 30) & 0x03)) + print("Source: {0}".format((hdrhex >> 25) & 0x1f)) + print("Destination: {0}".format((hdrhex >> 20) & 0x1f)) + print("Destination port: {0}".format((hdrhex >> 14) & 0x3f)) + print("Source port: {0}".format((hdrhex >> 8) & 0x3f)) + print("HMAC: {0}".format("Yes" if ((hdrhex >> 3) & 0x01) else "No")) + print("XTEA: {0}".format("Yes" if ((hdrhex >> 2) & 0x01) else "No")) + print("RDP: {0}".format("Yes" if ((hdrhex >> 1) & 0x01) else "No")) + print("CRC32: {0}".format("Yes" if ((hdrhex >> 0) & 0x01) else "No")) + +if __name__ == "__main__": + main() diff --git a/gomspace/libgscsp/lib/libcsp/waf b/gomspace/libgscsp/lib/libcsp/waf new file mode 100644 index 00000000..4b322f1a --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/waf @@ -0,0 +1,170 @@ +#!/usr/bin/env python +# encoding: ISO8859-1 +# Thomas Nagy, 2005-2016 + +""" +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. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 AUTHOR 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. +""" + +import os, sys, inspect + +VERSION="1.8.19" +REVISION="b1fc8f7baef51bd2db4c2971909a568d" +GIT="22213cd8abbd141bda40667f7ca2a48f2d6ad785" +INSTALL='' +C1='#5' +C2='#/' +C3='#,' +cwd = os.getcwd() +join = os.path.join + + +WAF='waf' +def b(x): + return x +if sys.hexversion>0x300000f: + WAF='waf3' + def b(x): + return x.encode() + +def err(m): + print(('\033[91mError: %s\033[0m' % m)) + sys.exit(1) + +def unpack_wafdir(dir, src): + f = open(src,'rb') + c = 'corrupt archive (%d)' + while 1: + line = f.readline() + if not line: err('run waf-light from a folder containing waflib') + if line == b('#==>\n'): + txt = f.readline() + if not txt: err(c % 1) + if f.readline() != b('#<==\n'): err(c % 2) + break + if not txt: err(c % 3) + txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r')).replace(b(C3), b('\x00')) + + import shutil, tarfile + try: shutil.rmtree(dir) + except OSError: pass + try: + for x in ('Tools', 'extras'): + os.makedirs(join(dir, 'waflib', x)) + except OSError: + err("Cannot unpack waf lib into %s\nMove waf in a writable directory" % dir) + + os.chdir(dir) + tmp = 't.bz2' + t = open(tmp,'wb') + try: t.write(txt) + finally: t.close() + + try: + t = tarfile.open(tmp) + except: + try: + os.system('bunzip2 t.bz2') + t = tarfile.open('t') + tmp = 't' + except: + os.chdir(cwd) + try: shutil.rmtree(dir) + except OSError: pass + err("Waf cannot be unpacked, check that bzip2 support is present") + + try: + for x in t: t.extract(x) + finally: + t.close() + + for x in ('Tools', 'extras'): + os.chmod(join('waflib',x), 493) + + if sys.hexversion<0x300000f: + sys.path = [join(dir, 'waflib')] + sys.path + import fixpy2 + fixpy2.fixdir(dir) + + os.remove(tmp) + os.chdir(cwd) + + try: dir = unicode(dir, 'mbcs') + except: pass + try: + from ctypes import windll + windll.kernel32.SetFileAttributesW(dir, 2) + except: + pass + +def test(dir): + try: + os.stat(join(dir, 'waflib')) + return os.path.abspath(dir) + except OSError: + pass + +def find_lib(): + src = os.path.abspath(inspect.getfile(inspect.getmodule(err))) + base, name = os.path.split(src) + + #devs use $WAFDIR + w=test(os.environ.get('WAFDIR', '')) + if w: return w + + #waf-light + if name.endswith('waf-light'): + w = test(base) + if w: return w + err('waf-light requires waflib -> export WAFDIR=/folder') + + dirname = '%s-%s-%s' % (WAF, VERSION, REVISION) + for i in (INSTALL,'/usr','/usr/local','/opt'): + w = test(i + '/lib/' + dirname) + if w: return w + + #waf-local + dir = join(base, (sys.platform != 'win32' and '.' or '') + dirname) + w = test(dir) + if w: return w + + #unpack + unpack_wafdir(dir, src) + return dir + +wafdir = find_lib() +sys.path.insert(0, wafdir) + +if __name__ == '__main__': + + from waflib import Scripting + Scripting.waf_entry_point(cwd, VERSION, wafdir) + +#==> +#BZh91AY&SYmEõKQ#/ÿÿÿ°#,Óÿÿÿÿÿÿÿÿÿÿÿ„ Y Â#%H4#,`(bÜrû}Ñ#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,ÕÓ­ul]ZåÍë}i{l4­´ï±®í_pÝlkLϱ÷dzvúݺ{¾]òxì¾ó¥Ô´©…Rúøq楯½¯y\ÃÛe… h«Ì÷g¡éEm.Ç»u­w¦×ºÔë]2]ôõyk=·{»º¼å·[ž®×™½×ywÞ@=ggÅíkWe÷œ}}À}ìowÕãNzî#,#,#,è#, yì#,x->€è#,ûØÜ<¼À*©©{¸WLåÜû·a¦ƒOl¥Ø5nûÛ§FƒËÊ#,·m6Ð ØÑÛPP½ºu(QBª#5 JJöeGc@#,¤’ P6bªîàïA—nâûîׯZ>ÝÃãH½ž'»{´½íp#/ÍKØÔvPÊZ6îîûÞtÃjÒ>©·Þ·£¾{šûzèÓÝl›»_7Zíôìíëéß}ÙÛ¡¦MZûÚõlíζˮ83oM<€k=bWGÓªU¤Ž rz5O{½ÏyÞå뽇 ôz#/o3ÕPKh—F;ÛÝæ·Ûl5­#5ªvê½Ù¦‡¯f­î{©%žöëÕŽÚ»sg¼RÃË’î}¹Ÿ}ÞÐ#/#//·ZÅ"õîiµÍÀŸç@[ßsÇ­·®Øèì^s +ŽÞ€>û½îBqŸ*ÓKïxÓG5_/»=ÝÐ=ª£¾Ü'Ø}Â>9¶¦¶ë¯½÷e…åÏ6íëžÝÓmõvuÛnúåëÎãï{›E³{«·6·u.#/Ýö»ÎÛêï·îNî»^FM>ŽO}¤ÓˆßX¥­áÍL|R¡ZÛu.9ñ.÷;ìí«/nûÝÞÛ¯7rúçµj;<è¼ßF¾ù¹¾öogƒŸnžïj½zÛ|`uï¾uòú-íèúy=gÔ#, J=°#@˜S{0)ÚRO½Ôó5^‡¯^ñN²>·3îeÝÖk|½ÚðöP•Ü§;{¸Š‰ïUíØ)¨+×Kßw^|#,=Üu #,=ïŸ^—|ívõÞ§Ãv¾Ÿqw{ß]8¾ŽtÓz#¸§í×HÛ˜×@ÓÄåÎÙì^vÛlÒÈλ÷¼zÞ‹›g¾|å6ÝÛÀ%W ¢ëî»ïW×ݶûêx};ìßešô>æ&¾Ž{o=—Þ}î»{¶oŸkÛÝÞ:Þ{}»‡ÛkL}½>û>ya—Û½¾vòÛÀÖŠï°£®šqM_^/…ó:è5í„éx_-ê»IÚžÛíïynOµ@}o³+LUS¯4ºŸZ:û=àuîžæî­a+ïW{ëS¥¾ofw[{½ï\î7Ïvò_|î÷\VŠ€:Õ/±¡Û̳ÏnR„+Åw¨Ñ†#/×_wÑãÛ@mg #,#,ùíÜ:;¶5èkGv»sÉ®Wß"}½Àt@õïxõõèÞê“6ù·wuÏN×Vvû¤½­Îíº‹F’HÍÎ.î‰õ‡Sy½çUr^ßN/FϧÝîO®·Ð¦çq«^;N!ßyNû¬·£à´Ä“NŽí¸{›ovŒkwV¾]ÜÚÛv™òzÉ÷ßskí´ÙNÛ®Ûo6¾÷ÏSæo‡#|w M @#,É Ó#/ ™iODžˆ¥=CjA‰‘êx JhD@„Äi2hÔj6™Sð£D4òÓ'¨#,#,#,4#,#,A!! A¢bh' Sòh ž©6Dõ='©é6 Ð7©#,#,#,#,#,'ªQI4j<ši‰¤ôSf”ôÑ=OHz@#/#,Ш#,3I¡ #,#,#,#,$ˆ#, i0M#,§¡¦‰¦"{I“I‚O$z4Ð#,#,#,#,j"#, Ñ #5™é=SCÑ<©ížò‡Šzž§ê˜€ Ð#,È×ý+m«ÿîbcú†Ö¹µ¹uÉ~ÆÛS°“)#5=¶®º3&ª-5³åV­WêêmV¾Èþ#òþ'—òüµû #Îo{ÉÃMòÎg5ÌÇœ¦o9­Ì¦ç.înç9£šs-Ïð´èJ}B-~¨Z¯¦ÛRªßkæÈD&Tƒ%ŠªÆ(°xT)U\óâãóÏEÓ<š7^øIË̶ëXI³&>rµŒÕÞVª«L*ØiH ?#/ÕõŠ7ÀR ÀYeË©jÒµZ*Ú1µm#,-ÕB¨IX(¤È‚ ‚¡!„[*E±#,|à…R‚ Õ F±V«m¯¿kjµL‚@¡ ı™¦ &D4c6™QSR%Œ‰%(ÒŠm¤¨EL’X XMSQT”DJ “4M”-”ÆJÌ £I,hM0¥F’)6"ÑJmIJZS"Ô@ %–’#5’`˜2’)lQm“T#/A”²¢–&¥()%Ò‰Yš‹F¢´«iU©I6¢dÌ™4lUZ•¬f˜fÌÓ6¤±šm°KM±5-M2jadS$š djF•¤ÖB*M&ƒL’ZH-¦±’²h˜!`£3M1šlb`•4°HA˜†31#/†I‘(‰(l›R@‘KŠÉ¡’#2‘„–f–)2A´˜c%4–ÒTZ#/¦5*ECI†Š4Òl(’Q&È¥±1Pl™M¢’e¤2’&ƒF”ŒÉRŠ)™6ÈT2(–E’BH…6"ÒX5 ¨…"J*5D”…3b $Ô–)1H‰”Œd™3Fa-™S ØJ‚ˆ‰!*M‰ ’M%`Ä”–,³0lÚ#M#FÂJ!e$ ¤Í‘)š¥›,¥Ë0É¥’ji”h#/¥ŠK264ed&bIZ––HXCeA¦Ì Æ£f‘±†SKS[M†!3H¢ÌDjL”š@ÓIK-,©QQD‚Š#/‚&$Ȉ’”Æ4 #$4ÌP¢!•3-¤EaJ¤!”©&B”…6’ÒQl‘¬i&I% E’šÈ¶F̆LцÉ&Ê“L¦¢1Ë*™¥1 P©“DTѳSb“(²2bJE*I!e2,Ji‚´¤É²’f&É£&B¡¤`B5$Ë)YI†ÐY6J@“!%“(ÈE3A’2™HË0–’•Mš*6‹BeÈ”‘ÔbØÒLÖE#/&60’FTi#/*%k,˜Q¬eš™"f‹&–DJÅ,€5JJ2ŒÒ5µ6Ûh(¶0IS@´”ÊHÑb™)’cI£l–”³F˜¤Ìe3K*M”±jdcal’#5›(ÊFhÓe¯Úmv4…•¤¤%J2SX«EbÑQ²IšTDÓ%KAQ°Š’V¦"†Æ–!™e) RF³*Ô&Ú,Šk&Cc)–•E¡bd¦5-*c$&,32•Y£e”#k*ER©X¦Ê$²£)µdÔˆÖɦVD©5 [%YYJSL+f(i‘5£KMD–’%ƱXÕ3h¶ÛH3`±ªÂF¤Ñ¶Æѱ²Qª3LÄ5E!¨4jÅQ°ÍHmbY0¢5³Rhe1%‚h±„5(”Ú–Äm$šÆ5!b´’šµ³VÓA,#ei6F&³l‰3)©¥#5I–Õ6¢–’”Ô²¤¶š¦ÒZ¦˜“²¦Rɶ–m¦ÌZ4f¶k32I¬±¡›¤ÛKYRSJ(ˆ C5J4‰ŒQ°b„- 3–ѵ$JME2š£iI¥FLš#/%0ŠE,¨ŠAieH€i¢˜)’e6hbÄ„¤TZ,É b•š’ÀclË3K1š`©¨™Ñ2FLlBÌK!I´lI¤£&h4‹2‹S2TÅ4Rma3`Ñ#5TXÌ1S6 RÉBlE†54Ú3 3h¨±±±F„hÆÉ©¡"“aK-“$¤¦L¦Á’Ø…3R‰2I²ÒˆJ¨²Ô™¢6”ÒlÆÒei+Ä#”dfM”“BTš“)FÌÓj[,Ø´”³I²lbTQfŠJfdÑ©–´Œ”¥¢ÁH‘›$FY‘1¢Òš#@ÖY6Jhbb&“I F¢5BTmmˆ­1¤ÃI2ÄÊ &‘h¦•É K#5¥e$š *5“0²ie24´›mIkhЙfÚ‚H´–ÅA£ ,#/›R”JQliIš¨Ù&k2*H’£I"Ë*ÔƆMEc&&VJˆ¦”¡Q¥%4ET±*Je)FÛ`µ$Qd£dª0Ê6Kd¤Ô›j”ÑIEJjµ&ÅCI3d†RTXiH‹- ””ÆhÁ´˜#5‰3BÁª”FÈÊV&#JKEhƲEd„6%`Š1”¶#h¬¤”T€h1E& “V”ZST¦Òj-±¬VÍ1Y-f¢©š’‹Å(#(1³B$¡4l”Á£VÄm‹hØÒšÖHe¢#5Æ&¢Ñ­6Ë6£h´TZÆI5©fÍÒÊĪ1h³,UMIHÛ(Ë)DÒFÊÅ`’Æ’Ù-d¢Ô–±I´¦eM¢Â‘QIF‹kT­´ŒeCI¢$©”Z66† ÒZ[$ÛIŒÉl‚›%Eµ$¶ŠÑ­‹FÛhÚ¡K&ÖÄZ¦¥e´J2ŠbFÒL`©lMšlT‘²È¨ ™‰1$™I2$¡jM±fV¦?‹çý5üKý&¼ |ü©ŒRžÜÐZdI‹©±‡þå©-Iû²Ò/E¹±ò»´–^ï|¿¦¿¤ë×ô£Æ°Tԥƪ?ðÖã,Sý^‰b¨ O¦ò¢ób¬M4ºd7%‚•Ä3³m´5T;%ëvþ>zãyg÷îÐÿƒÌ³'ù£Ÿ,¯uc/eÕLŠYÝ]ÈZ1±, òt–u÷ë-²'«êÆÚe)‰QéjoÎQmå¦Ðn¥ØГfN½1j—qÈqÖ=c,„Â’¦6Ýr¸6=)`ó¨S‚¢5Š¨ªìÃKJÈÒ|9ëW®Y×[#¿Êní·ei”-M(¥@Ñ ¸_ñQ eRËFƶh&«ìºòO9Q ‰¸‘6Y6?óÀÝ€4Í5ȤU5vZ±ËQ­îX?ùhÿÀ¦ãaRµ^Ô›2Æ*Šžê2ØÁdX¿ë¹aßÝZ3#,©Ñ#57ªAOS(C (`)UAÒ¼®—é­u›ërÖæå‹òöêÞKŠež f>ÐD¹Ó§‘&²–9©%C™E¤¹æ%Š¿žªùOUòmº˜šƒ@ìQ†EÇÛ{zY]J4}]¢­0n(i¥JÂn@rpeË’nºìNºéŠƒ}K[ËÎÿlàUŠ ,D¬ÐÑ(Fí¶R·-"‚¿MTFzè­UiŽ´ÿÚz`™`ÿ¦ˆÎ™O-Li6ÂJ°¹@`@hÔ¨OÐVâ<çÕ€˜Ú˜Dã™{Œ’àq¶Ü`Cò“U}Ã]¿l]~>îÙ›ˆ­Vpò…§†o‘;J0Û)¨ãjåýeNôÕ8TãLhµÅ©j¶0æCfB(t\´Ã·µö% v3IêåS—ʉf´0 ÷09!àá­ñÁ±´µºÎš‰™Ú†{¦’z XZ%l²ÜÝ(ÂOa"ÚO– ½:Þ>×åŠ0ö@¨ÎÚÑfÉPe‰J#5WïÉ—RcäÝ¿£ZÁ6–‘»GÕ"_ºø7Ýv›$£#}þ»_zîF: ãe.¶W7"^*®P‹ÿ‰¥ð$cós´WŽLŽVÚiþÎУ²?.ãä]u6Š1£^9™dÞ5Ë–Æ«ù)¨Óï84mëwßêü¯ ™þº¾ïó{_Kâíå¹£UÝ\XŒQd$Äa–“Þ뻩 (hdS£C"¬éÊŒ&/º_†W x«¦¬oW“ñ{ÑJ_7*#5¾óáy›â¸ÌWíMu­»4 ‰"1SJBÌV·b·cX²júOöÅòW#kðº„"ȆùkÁ‡ÏPÐ?íV"0ãKŸEÓlØþz'<• "1Ò¶³d< ™!µõwë¼®mÔß9u#Es”H²sª›»Œ…¦õAu¢–•­Bz’ZÅŽ£”ÈP‚wQ&šÒ›³äšêP¨¬¢ÚTD×¾ï˜XùíÏIà•½raißÝv‘’dªFÓÊÊ90Õ L"ÈòªKv‰ÑÄ®áçˆ6ÊÃm-8ÂÉ2ÔQ¶Ùìᦻ`¶"§#5ôºœûªŒÀ(ò@Þø%€.ê}UÁ b‡dtAí²—ðŒ´Ö3Úá·0÷"+„úÇitˈ!cûœøÏE0Œ«“ꆀáÇ6¿v¹ÎÞ,MP—“$XŠ‚Œb‚ ÝT‚}åuÒV …H±CZ*SHuÅqf?áNåyaðÚ»™:¡¨ã…ufÿ/jiÉÐ80jN §Hï¯Öo/žø9`Î>®¿/,šÁ)Bµ)ÍA¿:—+«v#W*ƒÆ|™u ²&7½DjBQN84ÛüÕK°™&d¦«ý#5*mÏí¯gÓ|¸ÕÍŸQNoø (|‹¡Ù(ÅsÛ_á|¼»ðÄV'rï¾I3Æm¼c+¯-ÍIŸEMT}[×@0ØÏÂŽì$‰hJº¯ZÅX¿|ê*—º&dìFŽÚmÄŽÈŽ0¡üGʯg™kú‰;¼e ÷›¤x Á×ÇœønãoîqØàäñÕOì´÷¿.w’ô‡ž˜7p’3Œ¶=æF¶÷¿½P'ãûµ†HùOÀÌhËhÕq¦{æ2°oïüÒ¿„ѯ%BÒ„–¨¯:?_ÛëñͺC—öGÊŠo‡®.W’wD+:Äy/²"]žòæO{{õ•X*Rpª‘ëkq*(øV1)"­¯MëÝ´ò‹ýfŠì†˜­PcMïôå1­AÄ«pÒ¤V=§Aç=ÓFÐì¾ì¿n.ØÜ=oeŽH!aÝ$™hNü|dm«]-üÑ”ÈLÛ@áò:<¥—¤!iõ—o »h-ˆHAWã‰ûs2±ÃpTªj¹î]¬ð«³ƒ-öN˜H”Š#5Ft—æ¸>ªµ¨;ùÖ”ú?ÝŒv3ÜÜ¥D#PübžÐÓ®ÏZ:Ö4@Iî¥*h­=(<—Ü+Ã4—|õ#5ÇÅþŸšµB—_xá Ÿ>Ä4¯]ÀG§H­Ñ Œ|]#5b"«£.xù›ã•#/.SθÊîta¦aæ”ÚØ”†•7lDݶØ1Õmð¿þü,8HÑ“èºr.ÿ›>y#/‘A;÷Éí âo͘«HjEá¤Aƒhlù½W—â(¥ôvÝë\—évê0‚1:éeˆ9Jö0¯¢ÑG’·I”Ü•óåþÕéçþ§[Oïï¼û6±º{0)º¡J‰jUª×’ÒÙ.éaðg¸müÌAÖg­@I#5ÇBÞ‰¼`ÑG¡àaé-†{_#/™[á%Îs¶­OÏ>Ñ»5²F3Ù1õ «8 9ºùý71ÝF¿m€§zä¦(§-|4°²øbÌdj~.£áøQ’ʤX€Š=_©žoŽxpîð§çÌU5øøïWìýÊ,饌„{‰#ŒÖ³Õ'‘Tiç¯<P8°)‰:YßmMî£b‰w@ ‚Á@a”ãƒÓŒ=x³Õ¥dÀ}øëy”Ð+MuÞøb…#5nê3›°èM6~ŠR-äœÙ¡‡Žó\æòx@ëpÔ8\Ê6ir¢t{î¦P¤ª¡AFšòh„»ÜäSC°¡ã1ºb™RüŽÓ`^©š;4õªâÍl)W»µZ›ívE€Àe³CÌL¢ˆ²šèóª¤;&#/F‘Ò§»t^yyÊxq¦.K•ö3¸ë·á˜ËÌèQIŒ:d$Z¨g§7‹ ”†B©É=0JŠBJq¢}öÉé†>4ßi¶DÛ%RR„Ç’Â"[àCþõçoqE1×íàä‚ØáÚ{~Yƒ>«ÉökZ™;xZoÚ¤Lhø‰êÂ×VRŠÄ9³HÉ`œMuôÆÅxë²7cÌOrJD2ÇÓ: uÁv˜ôOîrÊêe“¦DeÿØ$Ï:3Îw׈X© *B²‹Ÿ,žöJø¾â¡œð½Úõˆ^ï0s‡wÒ‚åÓX‹F¶;¢ûn^Ÿß‡Ž›\ÍÈT#5p€Lt"Ý3ÃtíÝé8§Ç§„ÊóÑšMÀ¨§ƒHœ(£1ÅBP0ŒA¢Äßøºj¯f¯†§…Ó»}s[Õ{C©Ý}ÿ>Ï7M/e«å-o‘Œîe‡#5#5Ö¼ ¤dSRª{^{÷ê}i›ƒ¤#,$ ¡NjG÷G5íIÉOµÇÔ?Ë–ç§WègLäãóg]EÇòü*Ô;Þþù» ðzþ¨/o/b‘œwÒA«^?%g%ÛÓê÷ªzn©÷|ö.?#×}$éäüq=^E¤nñí¥¤Ö ìFcïv–f¦¶,ù#/³,ðgîg›œ!³¾#5~Š«ªPžâiå:: Ðš:䲦‰ïQi±WýÐÊ9ªÃÝkdUWk¢™B#/IMvýõgØøé(:0Ì"ðp8®H±/Fý“à@ô:Jæg‘ÿºÃª Uüבä¢e;tÊ™á‡óúÎ3†ÙöÛ¹ðÐC~ÛÍêÜôzM,„ÂçöÂÁT®œw6—j†)Ú!¥kûçövñ|­Cï£ÒPðˆ—.QËËÀGòB|‚rÆ=*D2•þ,Ñ®wÀ ÊÈßà›3•ÏÏÒìâý©ÕÈá´J?JwHMÂSÖ¥ÒXTñj,‡)< Ó'iÆ~ÈØG÷u>’wºÒ9×w5‘¬ú¹Lf8ë$„¿Z‹LÅfã4ž.çÒœLVsR÷¼`ÆY ALjg½)ÀÅ“BÏj~oJ“4„³}vZZÉU):èg {·£uü8P¹¨x󘳜ï³leüÊ:o]éùÙìÞÍÄîß<ï{ÔǽY/”?3Çðé5œÝà_µÊÐÓ1)4º:mË¿–šCuŒ›¥»¥ Ì „(b1#»/4ÜÂc-Å;Ä2Ž…Ç£«1T]†ÆcFzÏf¼ñ…YÕ#5FmUSZ6I»+dU½^¶S#/›4ãßO ËD=ô[¡©ÝqŒ1ùÚÕ¶UOÛÖ±Zä~ë3"Y·þ‚c|4oZ–0åÁËú]y‚üQ›‡ÛQâûÿFÃãó뼟#/6#/ùAA“Á©zø`e°¶÷¢—TT•˜,„UQ²–PûzÝkLCh¢%jV•MP-R‰¦˜.ð€èÔdNdƒMÙdJ¿•ù¢ç;­Ži]š\òQ?†8ÁUòØ–†Å#/ yJŸµRN5ûZ+H÷5úZ:||jînÖá¹½h§ÂqÖŽÌìëÙ˜ÕaÚtèI«Ý#¶Û‘‘§&ZƒÄ‹#Œå Ñß÷CÙmÃ)ã.#/„6G®it¬„/½iô®µP-§¥Ž¶›~òâZ0ú:¿~®J+JmÇM}î/sÚ»±¸´^i@ÁÑñ©Ç%”ÈCÊAòÍThÝ°Ñû|Æ‹Ç[4¨wpUüÜϧ‡ýú#稺…f¾\bÊÏLc‰Ñç¯B°Vü8éqæ÷ë²^©À€¡ Æ&[>¼Üµk6ª«Ž˜ñãl<ø9^K#/ÎÌSm/××;)ÂøtýVÖE×,×iýëþÖw-#5õÄ4&á7ÂߺutßÅdwçi#/>÷ÅZÙ~ŸÓ™¡©]w«DÚñ¥ï¨û|œ»}>˜ê®#uŸ¤†òñ´ÎÉáMgYYRóªó«TY¼q‰f¤Üбœ*qoj å›®¥ñ“f+­?Éæg—mº‡Ký¸Ç&Lã·C}W$3Ó«·4àe)„Þ«­býŒÕ“|×Æ©Ú²ÂÐ>u?……#/$î‡Ìã–æÂçŽi¤[Sß¹åÔ‰¦Ì“æƒïù¯|Ó #/‰é®Sw?„ëë›Ù{œùFÃÂ.Ó_Y$ŒøFïl;timâøv¬¨CÛÇO”+)ŽÐ~:*‰ºx­d!žÆ4W'߶Q1üÖðoØ„÷IëúÂfOÏËz6½Š²k.&Ü‚õwsŠð$D981…2â®Í»±í´øåsÊ#¬ŽOn6ÖØ›*3לÊ[LÖhùW’"¹#1˜|α#,TªME‹ºMqéªoävs6¸]–/œqŽ\ø<$öAó©C}¾%è•©LÑÉáSéM$ÔV9Ÿl{§šzk;öO~)tW¦\¹kר›¥§Uo‰˜–¬LÏ|^Ó‘s›¥žsÙe¶»¹ÖÎÝ›ìanÊ‘ üj‘@z•A6‹ßøý¼†ö´3Ž°¬·‚W{x‘a$ý++o}ÝZ¢@þ¨³e]Ò¡ºà•3¹äúT?Ù…S¨ÛU5ºÚaŽãnæ~ØbPI𥠮Ž¿/;#5ä‘ú ¦ÞªR“9ØK8ǣü¼9·Ùѽ(ÃKhœ-¡ºGsÂ(Ùk8Aqj wÇ”„Uü° s¢Ç“ÏŒÚãî‰Uy_¡'·~Â+Ž~ÕXgÔÒ]©I•â#/Lx¢ùBw3Â>gGè•B²BÇq×]!©¨w]ßçÏœ]vÆg›ëNßM4ô¾À§aBú9æsÒ5xöí¨£ÞsµG ’†Y¡Y†µ£$ÔÃîz´”¹@¾ì3š^Gt—+Î%y ݽ,Ù|ÛõR¡T¼$¥¼´IëCî—ÁYÛ;gX²$…MëÄäóÇC ÿ‰§Ù¢ªvgÑdKÍ9oI×V³…™ëÅ]ŸJÌvsȵ¤ŒPRÑ®¶Œa“¿÷3QÙ¬C Œ>©½–Bû÷ìÙ0´·¥òTUBšˆEeƒµ¶([¡(ùhí†G„\ìÙII“Þª‹K®D+²QÃášÀ«YÍÑæf®_m#/žìt};ôx#¡ZÍÎÖ·øÆ>cÿ8K|MPÓÃýPññå’ŒDÂd!,›I¶KƒÊæƒeN–ÇMÑbˆdÜ]‡ç;ê>¢ÉUò!¾yzwîgÓãòç¿ÐªPÛî[Õ@ðú?š@“L$NLjÿU­£¤PX´[7åä³ev4ú®P©iÏ›iyÐI'iq v†Êyº#/z¬¨¤8è‡Zõjòú¾›ž½¦Æ†þ Éîæwñz{&|I¾ÝZáÐX‰˜¼DÛFì Þy‰ÉT,cšÉ˜@#,˜`>únãùªfk­ÚøX~8Â~%·e“¨ócº¨šÝäÝÿ<ÿ¦æÒÛ Uí·i€Û À‰G’oŽ ÿ_;#/¿[´²Da©wà¨Õ  "Å‹>gΤÇÙµ]'•neÂfqU Å‘©z='U.aš6|½¥v•…O…¼¹süÓ¤QîüåÜÉšo$ !ãñU³,ÉU«}Z#W`åÕu”8Ò0HÈE[„^ÛÜ`//«]º#/tP^(ƒ–¸–wQná…·„VÍ%Ît’bƒ(ÚÌÌám˜Ìݽp“L'o˜“ 5û'ìs¥µË/”ô›Œ@ V„ÈM^%€æ-©ÞîbæaµÃÝ—«©bíð‡¢›ú~øûþâ€cþÕ À¬-Á§ø°t‰š„¯£PŽ#51U·Oìï,…P‡Â&£ïöw̯m¸âÇø?èòb®uYƒ©ëµ®Ê9•TñÏ?ŸM,ýxÁª·ögß ÌÚ¡¯F΃›ãӮݷXG÷ÂíÈÑU^ekuþß'TI²A¦Hk+Í~Fî!I—vsõ×^Å€ã€ÎQçs@õM=¸ä˜#/¤fÿ»¦ÙÕQL"žSL+Ü¡KSiÆÔ£ú sOǃ:…NVʹ”SsAßPT%B'ú? ˜u'.BÝÝ®³é©±ËPõŽÐh`¡¯1ŠÕ¾¤´¥æã@vü©õh7)ÝwÎyî*³Þ‘Á­I$5!ÝÂe‘óÌr&šmïC³C(¸³W&HLÁRÊý’iÚB­YàÓ{­ØNlÍ¡3¡†’)G¡5ç4nÛ@Û;Þ7覧þÊÍ‘‚)¾œuËÌÃVfeš5IDðç”jß„!@¿h¤ŠG4hf6D™X9FF)èÄ»ÝünZC†ÄDKßm£IúüyüÕ¶aÓÒå»4ÁAÀŲ¥Âñ?†¥´¦g² ýX<Ä ÂZ3°áÊÞ´IÊc#/ŸHªc?Œ‹œXXÌúéíåv‘ïìÏðŽ[Ù ¼»Œî*뉣êQÖ°ÆŸ{wN4‰Fè·ÀLdIAÛƒ´ˆŽší3¨×[”˜B¿wE fì°²‡Œ„©8÷p€»VCùô ¦§±#5÷L5i8.^£TéiݬòÇ40öþ\Î×s¶©ì\løîlÿ‹=ÄlêŸp·¯vöµ®M#/µ>ÇùòúàW§{ßl½3㢂̶WTô™ÈÀ×xTs+•¸S´ÀÚ{¥EP¹§~n^&¶þÅPï¦Ê.XZ9™IÑ®¿¥=SF™9ˆg!8ïyùþ—W¡4`˜üÔytÅ1î˜×ó©7,»/+i'}‰†nß”Ùðþî©“–Ðû†¤lï°#Ö:§¬>sñèÒòš§˜ÊÛl;BÞ`–§iùŸ•dŒVÁFú8Úq”ªtyG6¿Ÿ5#/+žÆúo¡E{fð÷w »¬ppÍ(”&d¥ïqÓ­|ŸÃf¸•‚áºÒIÀçË¿1œ åU‹c¿v¨Ø餑&`q|kŒLþ 5XQpùàâj‹‡Ü23(!°Èò¦íæËî–;¤„Aë|»¿Âö¢ãY#5mÜJä:Å!Ó·³¡ñ¦øïûkM³çV1»è¢ÊÇ“’&”˜«aÌ/†'Þóžk¦ùòԉ½ž*ŸNu½ÁD½L‚Á3´‰´µèJß?‡Ðg<á@dCDžÃ#5j3xÚX‹TiˆÒnÀ£:2.î\µÆ ¶Öƒi¤šQccyHà,ÇlÑa%Btš“0úæ?œq§¤ôÌü.£C¿ÿ`‘BÄ=uìç"1vŒ•€‹ ´‡Ðb*póÜÕe…6oçü¿ÈÌÌ¡™´!³¡!&[3F a6?>¹6LÕâå\¢•AuØÍ·¬.ÓªúR|ân [#5 hŒ;2ÌJAÈôSÄ£6.²ì³fÂJf”óêZ%•+æ|bôcÊN¶G.ä¢Óg]w$¯Çû93ÆÙéó?³ÄÉî®Ý5×J7*Wk˜²jrï•¡ ªÑÎ{ÈoóÆ;‹ÓXýZš„ww´Ù·¾ ØnÚ3‹óÄ@ûƒâ\ëÇHfÅ]†ZdjÊ!“â¼v¹5n>OsÔ5›_FjÂÿE[Å7sn×(Dð˜¤Úã¿ã©Û²f}‹ˆo(}Ë¥é/o¢ùÝ3MÔ#/*ô\˜ÒÛS‚c"ðµ]tÇe¢°üL(Dvó5èyÓCêÒeòó´Ky£lÎú!ÂÅ8–Ud˜ùî–Ià ‡0¹6ä`‹œ½B˜àB[‰CÕeØ©xìú\ªN¯ŸXÄ?Ÿ~öŒZWÞxßV8gŒâE/ptv6À¨¿1+Í- ÜKu—–™‡ÂÁ!+²5D7­KaA³Ù¦qšd·Žˆ=3`¢QSO›ú»ÓîŒýËñbYuvL 7´Æ` þ_Ïò3”‘ldÚZ¯®Ü+ÔCä–|’ó9©Ï»ÀªóÞùò{ê}2%\z¸m‘oM[ ‡þjÞ=Ì4å¾q0öÁH¦Y²aµ8B󺻼ó4æ¯;‘˜’,i•¦JH,Š£µ¾XÐLèÖ¿o?Gßœ=úr8üžLÔËe%0Š(5aH­RšÄPÁŒ+š>­{±­¢jED¥EAa zêVå —%YbTÂ}~Zâç 9‹×;® Š´< 9ÅFŸ*ŒP¢“’Oö~º+fcÈÇW%Ÿ®ƒ’莚ù¦‚0þ²HXºÐf¸0íf¼d­ø×Êú£Ç<wòÍT¿uH6\‰²E…0i©¥Ìà]äÉ*ê‚ÐÖD\LÄÀ‚l`Mü6W›ôñŶ•u=&0á‡t……"|"n¾½¨Æ¸‡L™×MoãùvÈ=Eóç'8H£¿ÈSÏ·©¢Œ–!#NÌí^ ýó†Z«¬i[<.ž6P*‰#5¥«7eP¹òƒS†¶ÙßÐ7bPžG®æˆŽRÖŸù2TÆ4`œ@×8jLL¦ŒF“K"áfƒµ™­ ‹å™›#5`g©¡œæÊ-TbB¢Â®¸ÜÑß]Mt:›´Ë®ñ^6ú-ËJöh?­‘¬ù¤1Š¢¶à¨%¢ó0ÝáÑ")œ…" G¿J.ëϯé‘úw½yŽüˆSªICQÄ(`a kï5¼UÉ4[5-Q¤aÉ‹#/XEÂV\ !<î­r×ÉnÍ⯄VêVÉ­š–½Q½é­°åBê£hD‡‹F{Ip×kN:µóŠW9HU’غ¯«U¥.àHªo>µ]Vâ"/z(•~©r#5°«+j¾O AÜÀÎÆîK]›ÈcÙ«×ûj¯v={[vëƒdIÑàj=qÞFRUxoÍ¥Ÿñp UswØU+nnÈ:.öÐÍôz¡êÓÓ–e~ƒ<P¶1öÊ1gMÛ7*â_'‚Ï0úº½ÀJÅ7(’Ù#5™H0Q’車£WË2¬úr«û³Õ“u˜­¨”»ŒªÜ¹hÂÊ) OƒnšÜt¾²I [º_Ž™Ù¿]A8âòVT‡ãP[úÜÔ“™NËù¿Å›¿»qž|tKƒê¹Î[ãðŸyVàWí­÷Íø6††Ná¡—´MŠ<·u,Ư âLÁ³:FßU¦hÞ‡1ü;HÆ‘Œ @ dJ•¦ÛÏ/5Ûòë±±^¸j-ñ/F‚d‹"ÂÈÐ ’ RE—‹¢¢²˜H4›I#/ I³.Îaϳš=u:Äj¢úc³ùô­5¾VR…k/’IÇú¬îvýÞ¼ñÇsÆc«üË©’è#ÒsD»OGÍøM‹F)ÅâH„cpÎ"MUöo¿WáÈu¡uG¾#–œ)˜{žSªd>?«ðr¨dÇr6&foÙ²j[!¬×J­!bSB»%ÖMk6{fþïp#/¶2ѲÞgZwéÊ/ê80n\„9PÁ$ï=®˜Xu,[À&ŽÅŠ­iêŸ ý§/ôËRdOʪ)È(dµûÓ.Z¤ØÆ(Q…E·T(0QµÔϵ’–L·:+wÚŒ‘gwÕ9¼†!ÇJ¯éiKËÈéÛ¥þ²ÙøÔÔs“Äf¨î¼ÜûN~¾\¤Èn€˜6ó$”Á<>)Î.±X‘! ö£&}÷·¿búŽŽ ð’þ2 ×z’lŽëì² ¬v×LT¢‰d$ŒyD}^ò—¶ßgöÎøNÑŒRèuÆ–8ÖT¤ˆ¡Ý®q/òÄ}–þ/)$·´Ø^sfõlÀ‡÷*ŒÛräÊ´‘¢Ì‹ÝU,^;æ\ÓæMt0se#5kã,6EUPq'=q#Ÿ^ºá§D>±à¡lÎF•¾)NB„xSqF†£ü* Y‚$/#/2·™&½¡¿ÙóŸòàû Àܲda=®ÄÝ­,ÕÂ\&ãf*ÑõÈZëÚjô¾½!ÊóŒ×;¤1î9TÆuCBs U.¢¢$ÚŒrÛ\ÚHµÍ¹­ÜÚÝ-¦iÌ÷n½öºDSU<*ì¨.;ð`X&Écñâ¤àèŽfÖ¡“ ¸n‰d©LNk”Ëë8ÇHQ¨rö>ÓÚzÂeâªhS30gÐcÕó`L#š~m!ô·#Íí#Ç/¿ÊFÝTŸoÇÝï]ýltËQ~×PÌbæiŽ«ê±­ #/„¬Q÷þõm¨ã¤ÿaëÑÕÚ-;ݾ´ÇêÞíÒŒ[ÓC%ߊãÊÉIŠ¼ÔÝåå«çÖjÖ<êyuåB?j§«`Áœ?Á½ÆhW,¿ëh¯ÖŽ2Îÿ>rã#íåoû«"å'RúÎôï ïPxÅ—²W–Ç+Û“Ë©­iÈ"#]“¼ 1û³BF]ÍãÈŒ²Ä½4†Ÿ=9üxOÏsÂzú_ìû;áDUãâÓ}><ûáË/1¤ÊÞ2n­ÿG&iŸ×LCk¸bÔƒ¨Òuüß«/5µÓÖ֓*“Ì:rëìÙ•·¯¡_ÑÄñ^+Ëùëûª•Òó]ÐZ!ê>Ì£Ù*6mçõ¿ðÍôcÙð>N¾+ú÷~Þ>ï·òųæ3öf_ž:Í´™Ø½gDøK;¹#5ì¡ ×‰E¦Qx Õ4{hyOçfßñì²Eʼnb|•ãŸ®_'¯AC9<Õ9³zt¢“FB”Ó–¨P!õ×­¿õL²k;±ù×Óöwé·•¶ ¾Ü#5ÇiéöY÷ÂŽÁ5‰V¡GW3à«Éa1¦”4Ü åÞQcziÉIP%4QhÕ¨%B¾ïßF¿Ä*†ÚhÿÒªB-ôÁä‡IWïü¿Nš¹™™‚–X0; ]ËÂâùsWŠùÿ{wëßÈsœ¡™ÄÜ"Ä[ø¶‰A™!!…Bb3âv´Lµ%“øÊæLHfÊ–%Iùf&’Ò£kúÿŽvÝlQY\Üvq0Ι ’ Þ&¹1 ¬=Å°ÝÖ^[-ŸÌÄ? MÃnzM¦v¶‰e4.Z)M!t¿}^Mzߣϻæù1ãDF"whª #52’ØO€b¢‘S†‚&H'{÷_ôLô®ÖxŽA‡N+Qó¡Ù ÈdD>žŸ{ý]L‡v0ŽQ£ˆ0›$3~ër½¿¿®¶¿B½EXŒ°ÚŒx¾gáb™d¿é«Hu¢„dY¼#5gEkò«Öõ·K^Í]J½ImóÑ\ˆ%%„Qñ.?äùÜúS¡Vª%´ÉlÞ"–eHhÀ¦#5[*‚‰àù]Ã11þCHOÑŸ0xjgüø/¦$(—ãoð³¿%Œ_ù#5»U0}q–_ùé§ï^™?3üììÙ:¦Ú [4À6?¸ ž³S»Lë[ž13£ŒN´?á½$y×%’1@z‰»qÁ„ ÓÎö ¥mú"Õz_ ΢׸n"=°áxM *¨èÎ3 뚣IU+«ÏN_F,Ýø#âI@ÿ·*"Ãû.N§#5è’‘P‰CdìQŒ.ð±q.CÛÒçúBkÝ…gâÖbkßùØdE=l|öDU)I÷0¤ý JÃõ´#·Mj°šëjú†Þâ–füÝuý‚å£W¨ê·/ÆÅ$㇮¥‰ƒCá?‹òÕÓåÛë>Tbß-ß»Ëñ§®¿¹Ú¸sÇž>8[Â%hæïÏïŸyù*ýÿMý"MÅy—JûŸNm…>‰Ö¿*™Ë匩E¬ÄÆi|ÿXçËgáÍa×vö1•t‡=¦ŽÏßH‡:ƒo­–ƒ˜–Rô<5áî{-ºÚG"j  Q‚¯•þ³&jçû(áÐ*ú°»#,ÀJo¹|ezmûf~áàµÅê¾?Ãþœ)í†ÌýúÓõé ¬»”M¹õÂ''ßÝV7q™°¹,RveS»wð28É/œVÄídîð$/@T\cLï¡îª´3cv¾»-E±Ø£L>ÝÀ4#,Ô%ñ3#5Oóô=Q[MW9ÙetŽ˜Æ=cñõ_[*[åØ´å§ÍEÍœÕÁ²Ï¥¯è—zµd ¦ã¯‘a¤ÃB#5LÜý445è>K·ñW*–¤ßYÜz¡=„¥ÆRLÜíã?Äܲ\*™wÂyÿ~ïÂ|ŒÎ¬ÜN& ^Û ?.¹©ÝT8#/ZÅ5ý­{ò€¤êÍÄ…¤c‘°o0€ÛNÂsüþ ›:Òß9t û „"uúO|ÈU¼&;éì·ïl}ðèÞIÈ~³ù¡Þš“°G-²DǯŠ‘,îìïå ßÜñ‹ýoÒÈo½Îc|ÈÑÙHxžG¤¯ÔDy¤!&B1d8ÐÁüóù Wð_¶?uŽÙ“fñ!’*„ùO@‰Ö˜|‡+N/•©ù?ºuôgYèÏn¥›y^9ÌœûS:gwi‡³ƒóDáIM~‰ˆÓ4ÑŠ »LFÚŸµè{!V4 A2IbçBÉpVl­à#ƒýYà.½Üât’‡cšH’LJ·×~µ ¦ÿüÁØòû»Õz0:* #5|ÀK‰¥TR#,Ý TDDEWåîñ† ÝÔîöLoÏ—M‰þeaüµúå”Ò%'ô©_ããÖ\Zñn2Sh2PÉ,ƒ ÎAÀ1¥ €ÒŒ]îoFƒåÖi31-´t¡1ûzŠÉøÓÔ¿ŸÍ³fîùfïû{{¸×êòâÇÛê>th|´tÜ»XöÝg»KzÿuÞÝGÈqü·Þsé#/xT{sÝ ìÀÛ3Gš¹ÆšðÆ/çPïêî?^½tiÇöíʼrÕÕùgÝQŸ£uÖBáUüèòá»~Tr«Žò¿úOœ¦~—½CÈ·x¹éþ8÷OMµ­³ –¼wkrùãWÔó‡DÍøÆ_)À§ÃuŸ^ýÞxú—ͧwÞDá¶ÍÝÍŸ<÷Ó»ö–†ˆözsËŸ²Û=méòñ5™°;²õz4ž\ú5žž^-mÓø7¯ùü~}7VGãi²f¶ÆœףɻÅ#/íæ×+%BÜ{bÚqóöž9N+ôÐŽ:àÞ‚¹í,9Ç?§fãÃg=÷í|ÝóÏú©–ª³Å»«–È×#/¯J¯ÌGFÎjàu~~=vû²l?¥0†zJäOtªå§Vy×l«4S\‘,‚ñZºö´Ipç=%Ò>^û.ðSž]Z·U³´UÒ:k²;9ÿ]1‚öâÜÕߤƎ|vø¡nj·gmJÊy çÝ—IÍ®Ìô°ù\ÀÆ2+ׯ‰#5U¨<8œ„äŠãô<¡÷üpm~òÝ:ê~Eüæë|°¸Ù·Ô´éJÝCø‘?wŲîû´úyüv–CŒ2ݳD'år.gmQ+õao.]¬ãÍeû=WUZeB+ÏÒ¦ÞZ¡#5•kôòvPÑþØÜ©ºþQÉ®S†Ùuü¾&¶7Ó3û¿ >¡´Iëæìüg™ïª’ѽSIŒ‹ÍR¯ß$£¹ÿMx~O6{‹!׿?ÎyÈß- ®+òÃdž_vÛ:¬È'ªÿò=Ê¢ï€AáPe Êß^»óÚlËuîŽßoš>ä¿n«—×áåáJbíÑüÌšÚÛ£þ÷×ðÚÕŸ»gËüý¸òÕ›B‘\çýœz*Ñ‘õzÆ¿W51ø/U[dXhÆݹ»gWó=™9µYgº€^ÞY÷}’¸³O]Ó/n¸{kÓÏÏüvëøº+¶ÉæMrôádÜ„ÿZK×\6¹þ8éjË“qpGtK³”×°Ž3öfÙ¶a²È—ú|ÿÎË~læmÙºOy·ý¿ËwÃäïúáXo?[ïæÛ|ñÏÓMB-Ñ^Ÿ]>&æª>ÚDò¼Ä(ŽøhðúwsþZ¿IºPØòÅè¢FFU!dÔú9Þå—ÒS“åáqC°H¤"œ‹L$⟎Ï_Å *l‰¦>@E ÃZ˜¶25˜fÚG˜—Ùòi÷ž ß»´«Ÿ´éê×óùù_ËÁ—¯òù~z÷öè#ð9‡œèòô°spšìúX¿oë­¼ñì;Ïô÷ño¯òþãfoš­Ñlí¯WEÞê›CTÚ|ú_Ó~˳s+\û~_x~;tÆ~£Iaæ&Ü^–¾7Í«/=f8|ÛEW.¾vÕ®ÉðÒ|ìº'ëÓi¿ðêÌS|²·•Rzì¹Û»låøرuû+êZtš§­­Pg•±JüíP9¡[ÈVË1qB T/;WRØž•¼/“Ý©tåÇTë²™^—Ç®œÞîeJKNWõf»–TäSsv'k»òÉ)Ês³—Ù Q¸ÂÜÍÍ)ÙýÜcÆy#E’I'!i!¹Ž¢Zƒ9/ÜÛ?#/^k#5óíõ ²¾>­_˜Ãâáâê¥;žÀÝ*kMê”;þ‘:ª'¶S©¨f‰Å<)ñí„>8Âœrìçß„1ds…óÂhœ!rÐ˦~߬rl}÷5ŠÕ½¹µwTb©<èäPÈØíÁõvDN¢Ô½ãvïŠ~¾UÞ±Þ·!žZ‡ŒüÒPéZ\ZgW ËDK¢’áBQx 3d¸YfHg¿ˆ—äöYp¸hâ×a-³Òf*•ùËrϯ˜ªÉ™l¶üÓ›™½[;âh÷üòÕauÀ‹bq&„ÑÆ%£–É„zV€Ë1 V­„±}2+†ó I–ºW k-ìÞ{ÿfë„'¦o›}†üµ=uÛ9c{bgîצ^cf·×mv·8›ôBP”+çšP[ÂiÃËMùõ>(c“9§HJíYŠ¿ÙàW§=‡ùK¼`¾—üÔ²y»5íÝÍò|•V¤r]:’®—vw×Ê—Ùëëü§GÃ/¨Ú#“tð5/ÓêÙ#/p<ël{ƒîŠ²Iÿ_/d¾Œºnå‹Ó¶žÉF Ùy!ÝÓ4"«ÎÞ6Ý}F8#/ÛôÇÕÓîóú¨cê4™G¼26©tÈÔsyJ\³Ó×Q`š„ùd`Žï>p#ûIȃU^^J¾Š¾©…×ê­õ.EwË»/¢ÜÕøý$¾ŸËWõ­a\q´ZŒÌ¹‘²¶ä%`Ïž*;GªAºÖÇuöÃta­¬¤°ŽƒšVŠ•$Ç´Cc†E„‚ª(8Ü#5*"ªjDÚF 6ΞšÛ[k[‰Ò `ÒŽ ÈLXµ‚V“a¦HhÄYSI¤ÝU X–š’¤0­Ò#@ÝÓ¶–k¨¨,›Ä06…ûóüY‹Ã8h Ô$m÷E¡=ø§M§X¾îóÈÞ³!¹À‚ŸìuòX~Õ1©&~˜­Zj]'åþáhkQ˜XÁàñغ9ˆˆ¢13S²%”R(Èùªæº t{¢t/9h#08Ž$ø™”ˆŽJ:QFk1}KIPc 0i`QV‹† M@„4í Dé Aà<Èwoì‡fIˆ”xS-ÇÔgoþl,î)~½ÿŸt»gÒ·Ÿ1‡ôëÂËóQ¨ñ/4W¥hÑÙÓ?¾«9¶Y¤æül¦Zµ%û½CÌ·þŸÉæÍ÷a_#/úz~Ó®ŒDÕ‹u~½-2üÔß]Ÿ%Ë<ãÙâ{n¹w;åmxû'š”ÓæýóÌ=ÇÏiäÐ1¯¥¬i5B·”}#5>fÅ®>ãÉÕêý_ƒÿ…^­ZýišöBB°ãÊ DÒ8%k½ÿw÷­?AfoºwqáÓ×¢}Y?¦ú‘³ñ…Ñþ’iIå)B1x×^@Àäêñã?åÛáO%>ÿ?㪥Íá4N=ßÜùÏ/ÉguÉ~>w祑ùkêøºÿºþ®þš»ïüìݸÝû«ü5zë(¨–‡î¤à}†spçGÁÊ|¢®õ?È~Aˆøo{Í8VšÏHm0ÿaÌcb!…hô22Ã!I¥n0KJÑÊØ¥ß%IH Ó@ÓHÁ˜2¬)#,i³ÜuF Ó¦$©Z¹LÚ›&ÈÉ®Ýôó^šö÷ÀÄŽ˜–™SÍ)jŠ€ÄÀr7h(UX¥¡`È£¡ÚHŒ*V&šefeX6<+-iNþüF„<Ç+Ú“{†º†Í„f#/² £IºàEƒ©‰‘AÆÚN…iÑÅv“yåN=Q˜R2ŠŠ9‰Á£DI°n€ÄB° ›pcK J ¸‘Š)"Éó†%ºæ¡¶„¦ˆ2)@lƃ2#/e&:EÕ‘'(<)‘LRÛŠX›-7օ̤«J#5%F#50¬ (älRÍ>7³Mi¡²ˆ‚Æ—s6„B§ˆ‘îÀÇ⢷f“ /öZU™¨¨V¦œ®Â jPï‚ÀÇX`- ed ?@¡ÐóÈQ§Â'Ѹ˜.j.DÝÊGºìqrº¡hs#/ü¸1”>=j0}'t’Pƒ»¼0ïsòM¬8…Ù#/¤$Ò¾«š0,ô.e‹/³ùÕå¹óš~hsÌÀ7ïQÉá8m5_:ˆñô{þdã·ltþTmg"éø•vS“Rìi— ²v÷I¢n7]#/CŒŠThb¬ƒÖ0£«ÊI¯DðZª^1¢ìfe!™i?Ï#8þ^[©50î!Ý5ô;ÖÿŒýÓôø›£<(.™£ÉÄ#äv;³)™ ·¢€¸ÄÐ|oà¨2{»ÙËþ\þûn¼XôÆ–TµMå Ú­EUµ6Ç?ðíS§Qá×±ÿfhèïÜTU¼Â[wBëµÛ¤/ÑÜž¼âBBåWÙ&Ž/^ša6¼yõ›¶MšºR—±FåºjnþHÉ$·o½•«hqØÏ#/<Ú”%­èµµ£&¯­¢r¶ý;_É56„UòȇÐVç1Ê'}˜}CŽnLé €ø •DÛÿ®±¦Ú¤ld„q‘!¨—ðb¶?Ó—MìÒ60¬Î8;"Ê·LÐ!ÅO7³éÕôztÝów—ÎõøOþ¿¦_DÉ‹cꀠˆTH(¤QŒèkš°ôÉ(VôMÁëLê ]Æ‚^©†1‘¡¥aÃ[ÌÃTu¢šùè] ÒÞà†r‚Ì2Æ¢Iæ¥f˜äq|(£x8V‘Šã3ƒˆ]»” Ò*0be¨°#5¾§¡è‘MÊx›X0¯g½«Èâ­–êŽÞÚÁgáó1@¼aå°Ù²=°¬h´;_ÞFC4FµÝ£*%ié†'äeCÑK9ntlV ‰ž™’Æ‘à:iëC9ª*‡·§iâ3‹b4‚ƒPK³5¾j&JQ@z+F ,#Q6ʵ´kï`bäJ.×^Î )iÄêvº‘rŒ‰6Q¨k0wçc+z;EA³¾hk ·ÄZ4”!÷îõ5M)Ž4ܦˆæšÑ ¦ŸüŸéž&ÿï?}éçʪ½Ñú;úéC£êÊÈô÷S^_kwž3^c¿ÏýÞrìº*>äV¿¿ˆü)úØmâËÎI ‘tÒHÜØêluÚ~&|f7¡TΘ77lÓ€ãDc#5çDŒx»S &´21· 1›l£'bF–åÖ“qÄB2š‹õ’,Ter¢Ö9q¼UºöT²ÀÐœj¸¹¦²dÄ…”9¨´SLŽÄËÌ…’™A ZaϬ|C;öÒ®½-j†‹´ªÁôÞŒ¥¤e]Jß1§×@l*œâCr¦[‚Çã9¼P@™è… àtДC0]#áŒfØûÓ³AqC­I*V÷Á“&sbÓ-Œ^,\ņÊy¹`tœZiAȤ ‚ŠGb“vHƈé”OR¿ºkYþkÓ¿©wóõä½üÅïŸïTGò†ÿgÇ«Ûë{ç1J6OøÅ)ÕãWj¶63sr²Ž„Z™ÓÀ˜0É©4NX°#I(9NÆÉ‹³»ÌlßGqªVdþ¸»­ÚcºLåpr¦v‰ˆa”G›Q#5šÐ&àð¼Ó‹0œ‹Ô„¿L¤—ô#fÌýí£#/êüj̳˜ ë;d3ÄÐãž,X« n¹bŒI”ÈòQ”pÔ.6ó²ÇâA±£a©¼l±·#f*U¼Ã2ÊeÃs]×›ËÍçW]9wP$$¡°`ÁÝšÙbЧ…ÂÍV¾þMw+^ïæÂ" 7¾+š±]š](Ò†‘ÔÀ¤Š¥R —mdÓ×GóÕ¤ÆúÿtD˜(4 x8)#5Ó°ã —È’4û5ÄlËŒH™˜¡#/§ao|›!ŽñBiNb™Ì!8˜‘±—#/’ÎoàDJÃö°Þ[áË€™%À‰Uº;åœ3˜aŒ/Í8kÒ fA#/¨í;æ~doa™]7›8:›ÙÉ°Ê`”ÂBLìívP¾|l¬kåóñx ¶Ð“ZôãÍ©u4„¯fù}’Ê]¤6ªºÉ²¡°,™&M+ˆwònÁµÛ#/à ƒˆ8,·äF Á‚÷r7Q¸J-âœÎ-“vmk­tQ6v5#5',ˆÇjŽÚÔÃv+zâ΃®©à+GÉcvs¦ÁÒ´ÝXÎÐqšW/€š!³X:XÆ1–¨qïìºÍfÙÂn¹ª\†¥HÕÐkƒ… µ‘Æ»\ëÙœL‹O¹®psnÝÔç\“..L“Òª™Zµ–ç%'frf“€ODHåaô;ôì÷Ž#/bûõL^…vîóØ\“#/ç<ÓLEç¥Æ#ÀŠ5x^éö'>7®±å->6ÚW¤òßoÌùëµôSƒ-¹ò~ÂÄoƒFqRæ2>De^ÌF/K©± ·}`²ÿÔsD!ô!à˜ÎÉŠÄç£ÿÉ&û|¾=mêw%²êOçÀõ¹£~k¿ †§µæesQ»?"ë0òJ»ˆØ+Uny\(·˜›qUF̳ÁSl¨·ï©ÆËês¶Œ]$„¥:dsu§‡å%ýš÷̧_#5sûL†3Ï‹{7Ó›fïÇ|2SDï錙49õÐèõi[ã>•&™0™2@×ÄrC’™wì®ï·ñÞfŸË™ŠÖYmsD¨ìz;A‡ËÃÍõ:vYÁ—Ášˆ˜1bð°]2ÔøÈCæDv!ÌRoñèqb|¥)iÅpg“¾«ŒÓ'šZlÿ¯GL·Û#/{Oíq„g=ùo¥‹X[èÃ¥¬@c«‡‹„CY·2Kdu£é}ÞˆêýÕk·;9Œ5[þ½§\A|+/éwÇè£b $Ú-2 exìÁ2f*Ÿ)ŽÑ—-üqÈØ2ô’½²\3°bB„b`•E£ú¦àoêf/\dÄ#/$]‘ ÉPq©A;HÁˆ¸;€Å3i»ø˜ô3žÏµ®³¾@˜)à‰DËùÛœsª¡àLï”þ¦íTãÑ¢¯´Ò©H©‘¤Jœ“ð&á=Så^;Üy¹…3«€’ƒÔž…K¿‘Ó#/ù²ôa¼#¶ßJ(¿¤ð©'ŽôZen· Zoí¢£Ü²[¹ƒ^o(5úÅd÷o]§h=Oh’G·&{¥ü#5dýZ…ðúgHÑzëºìCZ$V¢ð¼fS%¦Ã{i› n˧ª(“ ½‚0GË«ãšßÀ™)'¿|YÀôxÇhv¤™‚!Ƽ1ç׌ìÏsFÍ[HÜÑý½œuh劥ûÅÄxŽZ_)éúD©iœ¦jL<¹ ÖyÌc†Ì¯E¦²OóON4Z”ãæ&NFÛèÀ»C¹ÀeÑË5Üß$?ääS¯?ÜD3ÊŽ¦ÿN6ø¯³ v‡«.å:¼èÆ!€Hßã<ˆ]27|jƒ$Ó‘î¨0ÜÎTé$=Ì“,aÇgG>ãôDÞ‰á@'û.'Øøñ£_%æš·‡ ýUgn=-šåMŠroš^bZk£œÓI«&˜t:pé²2¬-{n»}nû10ÙÕcb(€–æº_FÕ±í£+ÅV›-÷´[}ʲ³PíŠÌ©¥ λ‰¡ÜëÂG‘Üv¨¨3^Í1'bøŸ˜ö/M˜ùöÑ„níevè›;ôJª®åÖ)l¹Ê—qµ‹w–‘¸Ìv]έ–j–f»ãÄ;ÿåQ_'.=”Ó‹÷¹”+Ãçå³ßá~ÃÝ‘œj°Òaß‹ˆg—Œ÷ÊXÆßXl´#5¬ya(\CÒv»±Å¿w¶í3Þqf2N"^JHç—æÊØ!þûÖ‡ø¬¦ìîË‚ÞSØà‰¹'*…Î {æç\•¥Ùq#/3”Ó†_gÀ’P—]ê<¸˜þ_Ê篵äúÞø¯Yï§:pùÁ"&¯-P&Ð5*¦÷¨Z¦–¼øL‰Ê™¶á™€ÚET4 Ë©:G¶ºXØ_sBÆ;2וZ~gÑqwF¸GFãÎ"[1”jjáuIý&™çà®V÷Ú›zC¿‡lg* ®¤]ƒ Û]jP‘Pí-Ç~Â#/Sa£â›[ëf<òÒ‹àrª9–b’ÐÐvÍzg¦­°¯\ë|õéQ’ h!ý^MÜmûcÎËÛ¸‹.Hn%ÓV3û—¬O¤ñNc3ßi{=Ûæ¿ÉÕ¬{ÙÛ|Á6ÓR„ÐâZôoÍcž.±ìÎäi.Ù(Ûa–U%ÎE;Å·¾aÐQŸ&Ò-FL4aØW*µ$MÚVÀƒ ¦!ÉæIˆ9Gתªúã§bDÝdÀ:Þ¤¥-WjjWÈè^6ôìUðäéÝ;§·KWñ×UvQ¬·.¡„*àóJ#,Ü‘$†s\’8¨±Ê'ø {ǧéÌ¿=sœ.ƒø/奊8<³W”¾=¦Z8l`ï;1)qŸZ·zΨœ{¹ÕQƒÂ‘ÌN'â{#,ï“ß®FâÄ›nØÑhùÇ;mñ1Mé²÷#œËŽ™q(¸VU qCáêÂ%I<ŽÎÍ™4s¶äH“°‡¿œË51€–$1¾È'lLq½-wqVaé¢4í&n½2/½¸œù§Go\ïµ\²t“÷—%øó¶ ìÖÉù*£ß2Š‡ðÜ÷ÎL$mð,¨‚<#5ëÆS2Ê[Áïs}ÌË¡¾Ïûï¬ Añ×R&9ðrD·,Ö(ƒKÉ賨Ê!L½FªFv³¦Â²P!f¾òynÌi&•îëaÁF,Î=x)“Re¦Þ¹=5"^#?#eóO•Ç-½eÀQ€~²,Äx-¸Lª ôÈlgW‡ÕHþÃ×—ÎÌ£}Š°˜ÜˆI n±hš{a¢ÐŒ¹ØšTéyV驵ú0ÞåèúÂÃýaãþvD^fÝßü~îMQN„ÉAÝWG~ïÕóÎÝŽÍQæ3]Ÿ)û#/»lÒîô\ñ|Þÿ•ùöH—ç.Øõ×f|`éøkÌhd7ˆ}g­gXVÖX%AE¯ÊŽÎV≟ £}ï õ/A ±ˆFõsÅÕY~’‰aG6âq¬¶©ªð;ŽÝJ*8…ê¦9íûüBºÊ—7o¿zí<œ}*ÏÉ´Q¦m¢ŽqI«ò8í8ZTD„¿ËúÁ¶[CNÒVF·¥üÅܳk%E^VÏ4Ä[w \3:“ñ¦jüRk)rP௼m9©¢Ûáe7ßÆ«ÌKpWW>ê]4÷‚ÂvÝ2YósÆuJ*rºO$¯œpí´Àž®zµÞÿ¯ñÝðßoÂý¸³°±ÛƼv'®’ŒfÊ”œ¾#ñ·H¾™ýUèi_Âëì}ØÅH¹÷D²ÌøÆšêãc1óI=ÝR¿™ùƒYSeY8=ùóXlY$®­]œ|•t”xJÍeÄ´N ÌŽ<Äckº\y!ý³ú<’2×–°ÓTNzw“^ÙPRiˆK»?…¡79ƒÞÏó{kõYX~›Æêãºmª³á'ámYªÂ™ðŒo€ˆ‘ "í¿ì®…e5,¶·½[—ÊP±µyo,­ž/ m±ë4ßH"$!LÚ&tŠWsW•èf5ð5fH‰l*;Ú®LOt3dcu r®‚#5a ô‰I<%Ç(G¦Uöø¶êªÚê.x—‰ô®Ô’—Òqðƒûf=b¹oG*0'ÍŒÄe{ÃË,bDŠDîÝÚ) ¼òB=‹¾Qe…£ÃG9l5až¼üÕ«¼s*+ó§¤ÊËçÎ̉{æàöþJâîÁìEiˆ‰díÊ£²Ço c[¥¾ —÷>ˆ6h_TvtÞ¿/>JÚ1†û"•Už5(÷ónšÜ2â*KCz×_[¡bú–QA]#èºfqiׇžUyNOS©çžq• ˆ7¹¡u×ø'Ò#5Ñy$ü rdòç53„å®äûÁÞúv{’ÜÉ-q¾1©4L“tpºo¢ß6YÍÏu¿"˜Ë2óWçØΪ9½VBâ§cÆ[Ù#5U;elóÌaWê[Sk\òVôËd.¯‡§§ÏaÌn5Ä“ß$‹Åó5j‡wǺ¬&6ßKxª®kk7q×î…ƒÓ¶d"õäö¬`|¯H²E°§ˆ©3êäÎ÷=k}ZǾéàŒ3÷NµŒóóßïX^XŽžÑ\Ü$Ξ‡Hi%ÙF裣ü|«<ãD U1Ÿœ{uÎ?o!¸Õü7t¯+Ô¿hÜôñkÓq3Wùbbüó-Æêxš…D:hvUƒÄ:s¿ãÄ÷?jZQ¸ŸG=y{ðîºâºã8­òúÏo~$èF øó'·7à 4³Ç ßWÇžkÏni’´9ùêÿ5Á£#5ªÆC¯5ò9çm±¡h3?¥lMAòÄصÜ`[U5¾<Ãœ¹[Unü±>Ü3bÑg\#uNI{®ýü秢Ïw>ÅñÛÓëY7ÎàNƒ‹•ënåçu6Lþ55Ê…vYª nª¨GF±®9Ú©¢Õ†’)¡¢.žÍ<9秊ãZ”YîôyBÇÙã™yj¬µÅrOíÎpe{#ç³êùé°ž•b\ãàA<`STO­ùžÙJ÷YŒL.g´šƒBV•Ae®ÜU‰®¸bU2²Õno’Š¯]`ªD{ÜTõ‹©wjuûD…4ð<梺âcŸ.ç”´}O>k¾úJb~÷n9ðFI럿›ŸOÎ#YÇB*4/9ž2ÿWö^“¬my$œýL{7½D°Œ.É¢98‘}ÑÇ—Æú#à¯:HóÑû®™Jk‡a›”#/û¥ÀòÍó‚¡/wéñã»]3¨mWQUpÕͦý÷™d”¢ÚE¨Ó^£sñ¤Ÿš¼ìÇÃzš0EüþŸ-ü+÷aöï­M‘kÕÝ¢›!Jë7YOß+O++^´A— ¬Úõ& SØžQ#/Ô2ÑG¯#5BAÓhêwlÍ*ìN§n-z×!å>+­5S¨§]S5Oš¶À°Õt#5ÚîTt>ڸϺSŽP×…ÇÚêz>7ñŸ4î·©ž"úxí0µÝ¯æ çzºÐXnß9~]ëVƒîÓro.˜iÇG¥\\\¨$y«…ȼÒAðwÉ2Š‡ TÜ‹´ N“çW4f²F¼Ù¿WÛéJÉå–Ëéﺙaf¯ñZF–Å zº±™$?CÀÍYײÖÌeÅùw$ ¾|µ<.‰_£æa«ŸÂ¹ãXGãF¾dªàx!ç+xóÔë#5B:&adΓ RÞª« hR#5DMüíÚhDc7,O=P®Ã1¿e0¥Ó|›e’ɇUlêÞžøü"¸í^UàPÔ›¿z¸nŒŸ¿=c&÷Ë—ÅM%çß”;º>^X­Ðß4}ÕÅsIñÚ¹¦¼§G{Õ"B×Åå¶o.ZµcJÅš&±š·Bd[× }άù!#5¬¯”%›šPËÍVŠo¡çòWA-«\c#,¶½1ˆD^æü¡§½‹ë¢Šny–„z_„NÛn/¹vÕÔtÞåÏw~ørÎkš$Îcy»ãªcüoÍ`]]¾~.÷ᄦ¯Å–2±†£äãÔøO­›ÄÕ×oÄ£52©Ãö¿âøò¦9ß#/ùÁ€KôŸ·ßÇÕ%½æyÜŸZ×Ãàð<â’¾ªeˆšƒB;s†ò‰n¼i[%§uÕ‘Ððœu¯DzÙÔÔ D]S1áËà ë +FËa  àìÖ#Ç1ú騃4uá2#/óÍôÍw¸@kS.‹s²Ïžwµ¥W‘Ct­p/Yk²Í—xGb;¬;«Ž.;EÇ´wΡ¦;a”'/[Ê© µÝÜ·Bvð«Ç‘(cÛ|7㟨]õæ¦bÖ‰C§d¦™YTc<7WÓ‹éÙUw=Zë0¼ÐǶþþknDqqZ7ÆPlÅR¨jsÕÃTõÕ¿Iï,ù³e šäÆÄ5ª1f÷nM<šÌ¢YdÍèIŒÂŠ³u˜žµ[\­gW…nïƒóV$QÍî>Õ¥÷ž¼TÕÉbåL/éˆb0›é׈֟ŽO³á÷]Mzà™î©²¼nKÒ¿Ôý»ôéÓªéËäܼ äy†—ÃÓW‡ˆAüFŸ.#5{ç®/~ä »ÈúÉmqoG:7—Rì<áá:ߣ2µcÚAuÒ^ºNš°!§CÚŠ\Œ³Ä€ C EÂ|HY9(îKÊ¿%ç#/'ýF/;Ìúj>`Ë_d¥º¨G’2/®^•Ûó‚úÄÈáÞ3—ò›=‘úðóÛÍŽÚ®üëÉtåìùl5J»ÎúúöÉãP?ßïHK×Øá×3¥œO2³ÝY<…òáT LâÊcÙø¡þï1. ËáѤü#/¿kUò„ž—š’ÞAøÄ ÑÈ’ÀÕG½ÉÖšèdÌ·éÅš–»âá3 ø£j±ˆ-1†7ÄŠÑh†K•BÚÕåqy§®ÆOG|`xO Qb(D£ª´\ÿd,¦ò XˆWõÔliï½2뉷íOØ•írqIÍzÎWÖ»,©õãD´Žö‡V·Å¶ûzþ³¦¦ÊÄoƒ]¹9ZbÔNŽoqÚäÂQç·l‘¨¹Ñ‘;¦Ó}óëUC‡Ôܧä -:úÕcó‰TsV씣§C¢Ñøm…dî«„œGlç*:¸IÊyH~Ž|,ðŠé†=Ð?‡n,OŠˆGv‚È–• vHø=Þ’1¾x3!>*Ý»L¡¾¡«µÞl™72éR šÁo¦(§LbåÖÿ5~CµâNá·w©{Eöº.“ƒH^:ì;Š™Žæ’tˆB—zéš³Þäç<&ÉTcKÚ#/vÙGÜPf¯e¿®f|ßÄzm$Ð爄rÿ{Žpr>ËISÀyYCdÅ5)œcÑ‹Æ<ÇxdÖ›Œæíû‘qˆ[¸)’RÔ'¢çË1È?¬·2¨é¬r”T·göl8ÈǤm›É0Ï–<ùËìf&&qÐà˜Ì¯…6e„œ34ëÑ7m+Ó‡ËrRÁ ï³}Pë.dž?g@ºÍ^,嫶cŒŠ:M:ÿ¦ëîÛÕ#,pöÿin-camvÙÒ™¦›ËŽ!hèÅJ¼3m׆Š„¿oŽñ~³›oA1 [Fy]}Œ¹gÒ1ÙS®Šïô;¤ÜI“vÑÂQßæƆ–ú#/»Ôü~¥î5Ù„°ƒÀ»TDJv®Þ_,pcÛê~Nö©ŸÚŽt×ô"ww__§n‚4N-uF:µWø½Úâñ½|~gû†÷bkKÀ#³¹ÐC»–¢— ât£ùÿJàú”äpðx})–) A.ç¢È„t3ïQ¨ÔðP„ó©uÔô,óÂ~;[Mc5)hº,ý§ñoš«nŸÌI|\!ë#h¹,ý§Ç¨V47£Á‹èõíôFãÎ<ý›Q¾9êNs_»)Áëìlîs+[-Ö¼¼3×li2ÂÚ6ý¦ÌJ:nW)C©øý>{­îñ´°ûå®R\¬Ù­3Dɾd7¥µ¿F?H¼\Zœ Hï\ uï?5–Ud!z!Ò˜µI§ëñhµN±#/$Û˜„†tÈöaùáqä³l1¶VÂèd¿¨í‘>¯ûÅCŠ0J¤‘Dm"¯§ò«‰˜+&Ö-X(¥Ìöf†#% !D è1È&çâæH+†›ÂP¦iÑQc7¡`«; sÅJm¥bÑ ØÒUòÖ­U"ª¥ƒÆù@1,>*«q“—pÝÛ¹‹'ª§jWµZ´R»4?ÆXlàFÒH‡Nì/ÈFT†¼ü‘…­é y›œlWƒ#/ïù2ÍÎ_Db´0©Ïí=ÚßKE*ªì<¾éýYT‘VqHTA|ÒÛÿeeÛF\P…äOô³7(Y~^êš½òøÃFº|Ý×[Mh­(÷¸Púö7fî„¿Çôzf{!P¦ÑLí1Ê”9C„5ð9ø›CS¾ÏUÞ|‚¿.fŽwûÎ1ü×Á¿'ÚÝÄgs¬ÏÁ+M-¹=Zqµ®îéjm}êŽ~ÊDŠkÐÃÌR$þI¼ ÓJ¯P|Ñ÷÷™úBm&2Q´û@°”ûÎ’ü¤;¬dØæR'ð~÷òUtˆb›ìDÂI«s’vCÙ¥JEP ÜhQû„c6AäQOê«žó‰6з='ïdXùÎYø}öíöýéo•n~ª3}é¡éS*ïBÒéìÒÖ˜r¿{o³Æì=ž›tÎúͶÅÁa#/J*#4«àWÁ¤¶0ˆS×F—q˜ß‡J6HGÚmÖ…ÏðÇ•Îè=#ÝÅ€V†Æ{‡y¢`‚wð©_“(Ìtñ³‚“b¸ò¬G¯•rÓX|Ulão,þï;²g„ðãxa»D,°ç#5¯¿JÏ>GòwG#îÜ$Ѓ-#,xÍ1w@P¾[wöp øIðúüÿé¬M=SÍRMÝ¡Aô¦à¼~q×Å1¦8D7‰àCœõÿVKÊmðí¡Õ¼N̓íªaì*R¡hÈlW¦f®ñ“QF¥á=Ú¦9Ë.wì:†3t)I†gRó ¢F¨ÝpÀцVÞL®Mvúa5#ª ?3ëιîTÖ‚q‘‚±BR‰½Ì7tñ©)–˜ÒâàmÀG(eA0€ï ¡Ãyßg üåµDŽß”_’ÕY*k~²+Q_Š©ê®*KNýæïN÷JË=L™õ û4¾q×RhíÝK«nf=`{ºàNV5ÊätÏr~]Oø•#@ªtFö«CãP È4 &“"Ó¢{t×H†wüìê¤ÚâòÏaÙPøÞ7vÊ[JŽª/y]‡T˜M¢8áÍL„ Ÿ-1¹×>ƒ“çêžêh°fÑk­bR‚MdR‹sðÓš§Ãmex:×#/µ¦^ž‘,…ðíòó„‘¢Aè{îÆ%ëdõ‚„ÍyóЪ] WžþÒYñ0kNRÉâ¯F9Wdo‡aKÑ|X"´ ‚2CÉ”¬PQìM ~‚«ã™´×a#5bÃï‰I#5Wc§ÁŽj9Åe¼¥÷[n cVÀù‚ßËñÔtÎSr‘72A¹‚Þ‰Ÿ²!t~¡®» ÄT%I³iL©±¾Y-Ù³t£tiq\;’Ño®âçN¹ÇNØ/+#/äÊzñ¥ÕTR8 )#/#/ˆ_#/—#/z—óÞÐ1/g§g–sºÐÔƒž(£ lâ%£·¾ÚsÄÚðuš…pIë—Y GA6Êx=ÌWà#«" Ô;MNü]ìàß‘¬;Ì|K4È!²/Ÿ@ä”CËC´µWW|3bÑ–Šóë­ˆ71žÍ|1€ýË6©–¡¦c.«æÌ<5oŽ OÀCI»fÎÙ÷Ï;¾#)Åa,~~X›Œ3q¨ÝvÀXÀgj3+ÅÕœŠñÑ;Îs’ˆ1âsÆO¥u¶ãÃÁ'Gø·NBæåˆË¬ŽG?£½ÂšßQ˜Á,]ôÀÄXL§I„þØ,¢uH§|i¸8††J(M¥ƒ˜–æ}«ž²ÄwÎÎûAº»˜/Wl#/s•3•GJ+Mã Ù %L¡œ\hå©LU2åkïÍlgß&ji±ÃXòLšPõÏiè÷ñVq!ÖÇüìo8s +#/ZלLVN‹<ðÇEÞH­¦Y(A¦\.{jÙŽWšNvµÝinæJÓŒÈ)«‰º6øÝtÔ5vjvãBg¢$ÐÔ #/#/—`’° 3ßvUo¯#5f›ÞväTšÙ9aï féÃ,}k¶¬ÚÖ©e&†r­ƒnx…¬R0!¡¹àÓØhŒ,í¬f]³>†|f´Ã±òÜ}ÜæÝ/7M¾ãAª•ò)(c5iE¤‹Ic#5m9øëòò9ʉ”xm4Ül4j†A8ÐÀ–MùûAÂ#5hÓ·«Ò·p³à&ºVî Õ&’¸E&‡©u¨<"Jl =>M|ØúÜ4"Rüås¾z§ï´þÈH?WúXRÏ.ï„O.Zè MP0ÿ¼…¿ÝJaÜ"ŠÍ6»._‘»o/<«1•*I ŸßüßÕãaʪTz¡ú”3þ¥6ï;M©ÅX}c! ¿ D&†aùº¸¿ók›V~tÓ¬ ¾0ø|eƒ„\gn$„¡›#5˜q’È:3þcÃ|½I&ŽD?fró¬Öºd9 BMtÃÜ¿u«-ÔÇ}8A^ZO÷¦£¿Ãã ð`x¡C†QõˆV-@‘Fè‹€);‘ Hb…˜{˜¢cÙˆ_c…9E’Ý#,ƒZÙI¥€Ø @ÓEL0î*"¯àï½Å.%%°R ÈçzG1”×éiEJ”Iá¨D*ΖÍ­‚í3<6f"È,²`‘¡Rè`Á…ÈSuï‚&g·X@’'ô q(&æ52ëI|]îëúóìóc‹/c—3³|šÿ!³Ù¹ì<²†"³ãöüfDÿ—Ë]q?ãÝlú6¿½%ýÏÊ[ûá…ÒÈ’Ä#/^!¸j 9q‰öŸ—ó®LŒý±=ŸMüÕðó¨(¸òéa‰épRjMŽTZ˜XxŒÌÁª™e1âcHIŠ~(´É{^£œÄz-#5ë?èÕGJ‹(9¸ÖÞˆ¶ˆ?£–r¨gCiŒõ¶>.sÎ`Œ¥é?äQ¦;#Ýçλ´ŒÌcr®·w’ŒyÖÝÉo Þiî«“VÈ,Ñ;mGJïlò) ]Ú,x3˜»AûÇ##/%iˆß!’aÇÀñ«Hl…uÎ#58 sV¢;Ê8–P±‘7(•¼hšèWÆPa)‹—/zU#/Ù;Æhê¨Õe#5OöÝïÊå3Å¡ ùü5!ä#¡ÄFŽíoÕ¿eCö[Ü:12µº ýp:Dì>F͇ðš(wQ–ëgaÌü(0Å¡{zƒ¼Õ+«ÂBCõð0óÎÇQ‰Eø®jøu×n#/,YÑ $dŒ‰^æõO39:Ñi¦¨©H¬PYET,í·¦³ q˜<ç3¹5wæm³GµÕºÖ&â’ð#/3p²»V`îƒ “IŒ¨$ˆ#5ñ*€¤Ý*”P!*¡Y_ŒA®D´Ýéó×õŽ}´#/B<»XÔ”î Â"B(T{#/Õ‘Œyõ†#/Pyög® 0ìÁ[’F pÎ8Ûmymp΢»H]!º ¶ƒÃ?9r':”"‚ÛMP:1H¸7 †Ó0´Nl`;(ÊΆ´qÌ£PKD}|ŽßUµÆ&>ul*ºŒ4¤TÛ¬à¡%Ýq­Äk^ø80 <'¬OH<,u³#ÛÊ)µ¹³·<ÎÄO}FÆpW|´yÓëÞdLÈó¼¬dd¨ªNÝÎéD8¦3¥ë#‘¶!ΉÎ4E„€gÒE8T„#5¢«­%WWMµí‘çö7UŒB¤ „D N<èdPF-©KfP‰"GÏ꯷/+Hå5I—té¡D–•¡/TÑÇ·€ˆmGšNG•t×¼ÈuJn1-Ȫ”%•É•37yzI ,jzüS&|YóÚNj…ÕOªê!äÑåR—(ÏŒ«òó¨s1ß>+#ÔÁ€‰Hˆ Õ\^âÞ¦„*pEëÎN>>ôŠ#L(ô1Œ#(.UÔ¸O{ɹÓ5D¢VÂ% ¡R] (׬Øó^Y¦O sУS7Å›`–C‘wÈ¢*ᩈØwÅ„NÖq°V4Ï=¬9ÚP’ ôa=J˜JúèC#,õÑAˆH=ùaఠȼHÐ}›=QÕ‚ )¨ÉÁ†tâæEÚékag=LÑ+¸ ÀMä¾ÂÞÃ)€Dˆ©Nï$[—”$!!&A… ¶àûº#xK"¸æÍú,M°¨Ïƒ3rçÑr4&z8éëJ VÉ›XXž­ºã#[•€`¢Z;Õ#5„dñÖótSO+k¸s!u~H£óíWZuË' e*:*ôÂ#5·ùÅóCr 2'o h(:¹ôÎϲ`L™²ÀwÝ@ ‚‡,7–÷ákW*ã/Ü-SÛÓKUB¼ÀZ#5±SB†Ò6é¾ÿ$çW(ŠÁ¹M‚Î%éCËÌùð8éÄÎ/ƒ:ì¢f‹ºêgÕæR‘þ<Ú#/1³Thõzõ½Ž…Ê®©ÑÉelUdà‹ÝÝßœB’“D¢H$ mTK=hŠA0i*zšëMË[ufr­7 63PA™ã“Ý9² N®ú-ŽX󹌊t;‡T±ñöÙPË1ømÝó³2RH(£XxM‚üŠ(”–!2ÉJöœ9ƒ7>®SXøžÎÛäc$õÆÅT#èær•8"p«ºÜyK}³ÊÛhŠG4!…Ä'–˜Ë)Õ)d °ÏÖùtó-vEØ…ª…[â÷ÙrCÙÛq[¤aÒ¸2.¦Ë8¨#/…(Ê6 mžJöU÷ùKf»QÂLï¸:kÁ’ȳö‹>‡~N•\&µÍ¿2BV~c‘˜ÛË7¯­¥ùãnü¦#/½­¸›üæÉŒy¢“ÄCØœ›4 øF¬ŠDA†'¥iT¦„Ù6¿èº8|#52Å"šê),(5#)Pö¢p ô9QòHmšt¯‡Çú,ë‘\tváv–‰ÛG.K} vCŽÞEâ«ÜÎŽ1£d4>?P=ˆ¾¶•M!5H«©Sà÷»Ñ|zë¹ÃÆÊ~x!Ë£»4­7ãíŸF'é’qŸ0ƒêìÎt,#Ñ÷¶ØðÖ[†A1,Xwl¥áý#5›ƒ{Ø‹KK9l£‡wÜ·#,ÝëÁ™¹!×I'D:u”ó!zÐÖs,ëÃ×ykåälö;ºÃ@#5L«qž½ÅZE µÅÙÍø̬#/¡uò‡;²)ÄCnûôõuÀófµ´5W´ˆó~£áÆç"&à±Î9Õ)Ò#ØA„-3aüFðÃ@J2ˆ÷}šyÃÁÎB;Zv`äYÔƒ¨­‘m„”ÒÅ£Öº©,É%)š1D5$:±0ðlT¥ªL—¨Øš57ˆq•‚¨=š%$7š#,zˆÞÛ˜“õÄ4—õzm‡SêS‹ß†t;ûùËJ,Á¯ìâuBuR!¿"¶Tï‘Iȃߣ5~#y5‡–$!¹t$à‡cò¯C™òlzEu]Åu&fr²Ëò^»j`…KJ ÐE#,Èôò–‘Ñ6z~ç ­œ›¾M‰:êƒÛ A2›ÉAÇÏNí»vlÃ1vkB>ÖÜ€–£–œ¾êسµÍp?tL“7‰1Æ÷2>9¢X’˜Öã+s¯:Å€°x~ÏϘdcDú>þXüœvÌ~ÿB¨e’¨o{l¾P3Š\yÑEºzC~à”äUdM"aùi¸K£š—ý¬ÌÁÓ(ò£ËËSû&R–iâf챇ùmåëÇÙÐÌâOt ½<#5VûZ:ï•»»\œXJ”ùžääÄÚ%o|©¾~À&b º“A+¸«: @Ï#50‹Y™ƒæ3­»ztÿa/da1A_âýã¤?Ô‘!!Êa/à ¨ù¾ÞtÙ]a¡¶&»e‘‚x@=æI®ûXt›õ ÂÌQBòüׂ“áeuÒ¯ÇÊ¥³éñÐ>Úôbý³Óm¹EoõÖOê•ÝÓwYmuwþ®'.pQ̆!3só÷œ»sñð»„#u1¥ygW[Ç#ùØsaI þ$¤¤(HŒ‘B¤?£%6¥ L¥þOyaýŸíÂ1÷úZ¨DoH˜j/½Øúañ|bB/ç‚P2w3ä£ur¡ ¡Ã¦;ÁqÓHq³äKD¥–•[Ž8V¾Þ±«˜öYŸ¤›~•ØÛGÔî#5šÖ2y_–Šçö~eÙÒõóÿÔÒïÞuø™†‹]fW—x€ Œ/®éîý÷ôá}•?ƒ30_¾}R«6-bj¬y‹;#/’`o§~VíÖ‡(uD×Y_s Îj&8Úc_¿yŽÌèfø¢e¡®G4·‡ÊŠ$Ôzj¯Îø1rVaD£ìkZWGó¾-·çg2mjˆ•Š¸gÕë}agæ+ª%ž®Þ³ê6açãwï1­rN–›Ns˜5311Pú`ŽKt¤yº¸æ!èóËÇwoëÅ‘`NÌ1/ú(KôÄkøÞ*²>²Š$>@ªˆ«ù~1[Þ+óÿ9RqXÌ°Ìr…§#,&éùúµs¹¥Cõ¢R"é&H<ìLjñã·¯œ‘º{ú(Ø».qÑAãºÉÂû¿Ñöc?‰.îöhD d(ù|mû7óê#/@OÖÈmLoO`•^.Þ²]ép0ÕÒûttð†WGš)xt áy(kÈóaöÙwu+°uÀ-‘³jß®Ï(ñ¿‡šÞÑ:l ^ÔuyãÉ¢Ë`Y-ŸAßêÜm z5ÄìØy½òT‹à禇˫çÑ¥"ß— ÌÁ'á9´äiÏ#5¡–´ÖÎÎÃ|©›fÇ"ÎÞ¸] ¶1z¬ë1[ĺ•|ý®®Z µ¤Ó’"kmõY‡lkø=xû|÷¾DYe-bBfGC\¦"ËÉ.}yfnûýÍÞ½ÿ5“Ïœûvúc1#,…† £E˜b"®P»–æ>!#ÚÞ³Ïí9NgÅ®¦ÓLOpÞ¶f`ý ¢'ÞÆã‹eå3šÒæÙh õæ„€’„)9⬣u4œ9À¯ãßsª"➺_ÂMÿÙåöÞ7Öÿ‡5ö¸ÒùLÃ.ì©"¸H¤{áÕup”æU“g†:¶z8]›½™˜}‡ßš2Ûª!Œ·@¼Ç3‰<“Nf?¿œi•A¨àÅ^½# ¼õ©ÉÛ<ï^Å¥ÎÞhmöÞ-4î¼3#,¬ßÕ½#/ÒüNªÞ,ÿW?]®É߈!Vâ šæ ‹¼Ãáà=PÌI êEš­/l×À’0iQýñ¿é–õû³”´wÕ""ª‡JæþöâB™PKE¿yŸžùçµæßþ¹®>Ó'#5|#/y²‹ð—;ÇÓb·sŸ*Ž/›öΠC÷xëƒñŒ’ýo‡×.^NÊ”:2t¸7·ä¸õ²OĆ!8KÁÛ’¥r„¥i‰(<öA³aNbìñ®SòþëÊw5Ú/ã¬Ow•Ë<‘0üÞ„z*Û/1IÊNyàÛõ¥w4Oª¡Ë^]¼/ ©/„»úÚðLz Ð M–óPÐòF×ù$sžHDŽO\°OQv¾/Úáªuñ\̉zà}Ûð‡˜ƒåÔ“¯Í¶N§Ž'¬âÇzžñ&]›ÇG:ñÄq£®ë~|Á83M0Ŷ-^\{uïŽñ×z+îs>ÛˆMgÙUùb6vLtOt*dƒdtºŠóõæèj·C‰~ÈyRãÈX¯~Lw$êéjãΫJÏœf.(ó|v5|cw1†”YùÝ%;ó‹;vÖ{ç]ëSª0¥“¨{ý#5™O~ªìù–aÁSúÞFÒº}“#5 SSa:›; bî4Í‘ÓM0–vñ®•8èL±ßðu_z<ÍQCØYª-™_¢eœö“"¡Ï¯# §ÒðÄ*‚Òð6¦yI¼GTWUñöò¬·/dzI#;~÷?N€ÀXó‰gíÖ©‹åðÃ2ô´ª3·kÓÀ…˜¹­1Ý›è›W®Ã¿.’ýQµlUŸõ}à«¢àu#ù6‘oÖé”ùÃZ¤î|üeyš¹áŒ|ÓÃ?u#/äˆyÌž0yÉ e²Á©}?6ÃöKžk›öò6^÷Ò$d›žÓ¬ú¡¬õ}lªŸAd0­•÷)¹eÓš*ŽñbfŽ\=~]H3ÑËÁGY'œ{l;üÅ8,J»Åž¤c.ê`ó—gÃG©½êÁ„çƒ÷¿ö«3õqà[Ci30öÔŠFª^;ÎlËškF½µíáøíwX56ZËY}.ˆsŸœušÿVÌŒsç9§wÃWi&yZ_ycé'-ê0ñÛÏ̽%êí¤uàÏAž«¬t?whlŸl?CUÀÓôÙl™ s¨#Ê·š¬§dÐRé.)NÈøõ}­¦r“öGüi©Ÿo‡6#¥Å)CýW_™ègß. ì,O/óD(-_ZÉA*9ìæZÜŠpÔìñ‚­þQàÌçÛeÁ×$n9µw;­-k1æ#/Ò·ÃùÐåÅÄ1èSñû2}j—Ç07ß?†ïŸmKó¢Iîìì‘lÝKpû‰Ä—æçÓÃÁÝú¹µømÛ¿Jç‚©£Fú%ü²ú3Ÿ)m5S0W–‚k(êN>vZ´9J =–âT*õ;ñRƒþkÀÍ á–¦·R^4ÞpÑðóï#5~§zHßÚžØ$ÇO¾p÷|œ-a{#õâaöýPt΢‘j+Vß3¯ZmY·EÛHÂDÚÛ´Bò…ñ¦dBi]×k%ôKÊ~âfQxô & Û´P“Å1¥8ƒÑGâ ´Å$¿äjêÅ‹ò‘à%ÄÎ{‡“éj£øYB®DÂ^Äi/¦ê8Ä0(O¬DãÔ,|–-‹$ʽ³—­.kstÓ‘Mâœ@Æ/(ì‹ðåñ 4(@vχ$ß㦔葠9#Æ_#5…“ôÌtMô4aþ¡G.ÚqÇò"Iêƒ";¼ÆøZó~”±Ë°#5±¹Ë£]õ5äÛ/èCKK–S¾üdûiÁxjÓ!ÒëqÄ ¦mäAìŽV-Ñ#b0ÿ9¢P“õUphÑñn‘kYB.Åã'Aˆly! ­ýw¬ÚmA/Ò³4ŒÞ¿Yþw6¿1…1>o„7?\/ŠM„‚ˆý±<#5³g‡‘ã"ÿ«îêÍÑ ìMSfé‡ZtžY´>õ”µ"ÙY:uè©×í7R§#Ö9D‰›/;¿+ü:ÈLœ20ÞÊ;ñ¿.ÎRýUß]§ì>öüM•cNnIï»ô#/OÐËâëøë峿ž,MÂ61ú¹§ù“Ë}^õ™¬'[XŒç*« J¼ßæ|wªŠsiùHÞ´½Å V’<°>ì³Oáð›Â+¸7þNE…»‹È„œ*jýI@ùJ„Hà8;׬×sº“uÁÂå¡É 0bî.ÊT÷À¼èôÀºSÖtǪ¦J+3½N°dl%ùðfg kD×Iú!{Hë_wçÛ†™Ï¶>ØéÎÇeâã(nvç"ìÊ<îB.&¥tÔwtô˜ëCYLæs¸™ª­$Ýh¨›±e—de^V©“ÊÿÇÝŸZ«Ûku$$Gpq3 Ý€Hb0PëÚ‹V#,°;«ÃO­=zò&°¨ã¾ZÊe2‰š7ˆ„Ý&q!þ±ãY}.+ÐWæ/b\îñ œn&݈vWdH% š=2ƒú®¹†!ð‚-Î5·6÷Ál÷ïÆCÜÅOèÉ@&àÕ=Js†¨Ï#,y]a>”VmÚ@ÂÊÕ{­y •OßAׄyáÄõ‚„× \ÖÞvæ,ÖTö²Ùá§N-e{ed:*gsàC;º¸Ü'ÆùJý~lŠHg Í®ð¸E¨‰W7‡ŽúŠžu+l¥­uSf½MÆYÔL`fe‡#/k8î± uŒq°å‡›9,èŸx$YG±©ä‚C¹ßMp­@üpÍkI·_luÌÇPaw=µ„H– w>õÉ©;qx,ÔñÈÂCÊX°L!T2šj‹vúˆeÛ.l:¼Á Úesj“5Æ2"X’~¦·O—¢ÉØ{{aϧy¼}á˜Û£ßÑ·›nÒVKJ3ÏlõʺÍ5N³¾Ò–¾Ú1,iª¬Ú{lÓ…åÚ³ u¯c³Ni0äÅtl_µ6ÔΚŽà#{³“AÁg©í¿<Šˆ{]ÉÓ^ÈsüS™)ZãÂÃij›ÞŒÄ“ú¸@è]ݤۻ¡}Ù¿<0UÆ&„Òþ¾¿7¼õßµ7È„u¯0$þÿÂ/ ˆÒ*‚g¿¶s§¦…áš¾}+˜óŒ 9ð7Ÿ‹®uüE4×J ï­±eóûú¬OÖ"&ܵ*£¤NžÓa•›ÄšcUÈ:bðÌÖxæÞxí*G¢¬¨sf¾&#/f2ÆJ&fŒ­·EVú‘ªfE*ä8R¦|¹çZV2©r¿«„Ý8Mý®Í«¢K¦p„þ•`©} 7É'˵U³QßùyØÞ9åͦQ#/(8z»X°Ìi¯KçÎÐÒe(U”W•0„~³ãøyÿ^¢ü(:zKk¬Ç’ ðŒdÀðV¨jÇŠ™û¾Õ~ënõÞNÍàã•ÊE^ÔúPù4ÆŽ„#5žBGeS‰Îá ¸éÆäiØ)ÏlO>hfëjÜj„ô¥f )•t~×3ߘŸ é BS/£j–n¬+²oº%ºCK›,¬†™k¿UE.ýЇ©šH”VéÃD/$ÏÛ»ÅD|¤îvá×Ý>}³ 1¯(Ç»àÆqš·¿EÙ°¹e% uÚ2öž§µ•ëÙi˜ÎÅÕ,Ѹ.'g±•b¹9€™YV#5ßk¯6ï#5êø*tòž0å#/2ÐRÀJ²Ÿ~Gó`jM½]å‹beýqKAJ`ñb¼­¼¿i8±!#/wî=„+-ÖØW8#,žp²CûÛˆÒÅ\wñ_Çc]îgÑ¿Ùõä_t…Ýy¼Õ×êßÝñÓC“9YH°fôQ¥þ5Œ´(ÛsŸ­š”›Í6ö8e6Äîè…;iøÑÁDvü7:L²í•ÓŠƒÍ:C¾ßÃŽï}y!!æT}£E#/înE ïQ†×ÔÒ&GÈaç´õ Ý#/=Ì4!´Kkúiÿ•†™7ô§s;cQ(Ò>=9\ÌeVŒé,¬,Y9µÜi@{}6ß_ßôÓ¶ëw0RDXìyð0Îh©ê~ú¯=O¶¥6Ê{k1¨÷|=9ñ©XÊƶØd{<³È½ˆRÔi##5;7¿ÑñP­‹R«”*&vl¸VO^5Ö5Žæq&ïèYè_f_ÑÆá‡óãÆ#5mÉÊÚ•äÒþÝ+ß FoÓœpÙŠvcgïøUôÈÈr°R~¹ÛyÜ"ij!”4f¬ä‹¢’d’K°™mí@(wÊaá›=§„õÇ“³®ã&öéQÑ\÷ú'âñÐ9Ý‚-ïß·®²GlM,]ÑÍä_Âyý?d¾÷CW“6#/úénP<¼å¹ú¯€Š¶W•ï6ì­²)†î9÷.¬9>sl:颅\†`ÒúgvÕ‡º9í>žª®ì¢YŒ0¡kË|`ÞÉ6´ÞéßìÕU¨%bÔ[ya·>ûé,ðÙq+Œ­Ci1b©œêíyØë3?TïñÆ..ˆ>Àè)®ýèÍxqûuÏz®Iûúo‡ßÄ`Ö5qŽYøç"­c0¬¦‡c5¶û´-à]¡àl„jÄ1Ï{bÜ…éÙšcçc‡GN=ýˆwä“Fz^`Å#5ç9HªÔmºj­Tœ ÕõDÈùNÛñÖóÆò#~¾Œù<Žù„&}<§åpÞ:òRÝQŽÏ4¬Œ3?–åœÙ½rÕFøðçómwÊ5èÚ@#<Ô–éPúS&79\Ó*E6HÜc>±n. E–gÛÀ: %“È{û°ä½(Ôa©#/Ó±8kŠ™‡nXÔÅ–ÌÀœS4AT(q»«Ýž2­Ÿ¯^M}PÀºm͵L‡túUø#3émk$íØä‚„¹üÆ¿Ç¡v˜Èº_=¶77˜ ‹¦Äån–âÛü æA ÈÒØFQ’›WÆbr%ºŒ)Øpr17ü çXÛŸÏ~è:«Sì~Ê:æíµük¶QË´88öÌ„¥q®0§kÕþ1Æ3ÄÉ%¿ué0#Pè!ÂÛ(¿##œÛn«jëŸf]š(ñÐh0r½tæ^ÃDYÑU{á‰ÛU »jz e~0Ž’^+c´x’ŽXuFOUY’Ëbpwù û*¬¯wIásÏ Z.7³A&ÐATiÆ$óÔtç‘ny[š«­ˆ_qsóK®·k*ºüœ9§ê†ÃÆ&Û`äe´>U\7ì¨Â&ØûËGI8å…û~_¹´€M’¬Y‡·Áù+•YcQTákC’+Ðg.ËÃUò­óÕ˜Ž.ñº4Ý5¨×œ¬gµÊê™S{w3ï¢ß¶ ­™©¦nªÔ·U@Ó\¸±l#5Zõ,Ô,nûdÆÆÔqr¯KŸŸ[߈jî[›%Ÿ&ºøLPIªä~býºaûŠú-ÍÈç#±¹€×¶,Pæ÷s®€Á0æÑeØ^8¹;=À'•¬=a Ó£MÛÔý9Y‘l˜V= Ê;ù˜®J͸j¸ººVÆ}ûg¶~·Ïfˆ;†ÄÚÆPË>¾wŠ¸Ò맶è™ðìÏù£ZëGÕVOA@%¿ùþ[?GÇñžÞóÛõxQÒÇD>ˆ¿ÒF¿”L+Й‡›ÿ›ÓDð˜ûâúìBµÝq< wõWÁ9äs¶¬ÖVj¢ªÄàÊ<ÎS¹9›-[61øØÓ_íëSïòóY{ŠûKãràr—é÷Û{yc‹v¾<ðSŸÉYâæsyV‡Õžâšr_e’ÌòÏûŸ§Ço›—Óù|–~—ól|Š²ð ÷5†ê¼c¦÷~‚ÖoÖg?ZÇVœ‰²°¶Ò#/ü ÏÇ–Z~¿ Xƒ¼áôËö&ÉÓeÑá@ªvH¡9” Ç ™–[_ì$÷~àt¿»6}ž/©\ ö°~ €ßb#,_`éÆ#/ο°`M™BI?ä/õÓÁ#,!ߢ¾™°€åa#±#/é‚6%Vá pU",#,þÇü¥ ËŽÝ³ü_Ôyk«·fDO+‘h›k öÁØ­™?Î=á6˜À Œyu£ íéÞn4LØv7*pÄÔ2“_vC„JÝn5 B"N¶¨Ö˜IµEœoRO—Å 3¹ Èz1~Ĉj á‚U1–º¢¼÷ò[§`áâÓѱîbv½çï°è|}þ Åú—Ú}®h£™¤=¨;!œ#,ÿdE, Þ.àø“­LÒËHæÆåî}ÖÉ52U¶u¨Yþ'צ* í ÞôÂêéú69¦‰èܼÇäÄAO´Oñ.‡‡øwwà¦ôé“âXñg\ÿMZ%Zß²mǸ°FG$-~AæþLéyOø/²í8Ô;:#/¼Úy >²1ò}~G×6ý¯SØ„ÑA`­'šü'ÕjY£›‚A"a‘KQ=eksý=ZŠ>'Ì2†ë¡ÌÈÙŸò“ Y*v}Ð7Wæ=¸¸;µçÃcUŒ%b.qJžº“XŽ\@"âØj.6IN‡Œ$6$ÇRg˜R±Du€Oä†AŸÑ<Š¼Þ¤?ËG¨bÿALxü*UVªa‰‘|O¢˜ÖR<¸€G°7®Ãknà#/€Çï$êÕ5îFÕïSqÜè‡#P-"†Ðñ²ÁŠ#/” )"b€N²cè{Ø\`pRƒK$aì-“"ÆÐ:\ÄNkÌ×"G:•°»°„,dLXÂT­J#/p/hÂQh:†÷çïH+P#/ Ðûâñ#5Ý™y‚ÝÕ¿õràÌ‘DÜã¡@Þ’¡€x͉¿.tJ‚†QÃBÆa2D‡ýd¹ÿ©ƒÝ ò€€xû‹—˜’#5ÒV}xT‚1òÿ+í‡ß\kƒgDÆ‹FhU<è…ÇCßá{‚JXÿÉq¯Õ¿Ï:‚ ˜(8£û<³êÎ&'[_ñÌõ³}fÖD»8RHç»?¨¸û]Á; ¨F#¸·yó4I“O}r$Õ’Ù9J>¥»äpææm9 Pþ{•T†ðüÏ)LHð§qDBD"S.‰Å¹Ÿ´ÚàáØëSHB3B= 8?ê—#/©Ä²í7ŽÿÝysµRTõ4ˆ„ €Sä4§äõþž‚ÕR„ÉƳ¼¥rl™ßm4ªUQÖ«lÕm ÏŸgzâŽý¸ag?q¸8àáæò8Ø?½÷ñqàGৈzNs‹,Xï×iå uÐÕ9”r4  îw`ä]Ñ,Û͈ÃôC­ú¾û-ë~“âF*^ƒä=ŠCÈ$%¯Rff{¿–š´6nÁkÝKIk}/òeŒʆº(ú&î?”û¤)#,ZÓ`ùT×ÐSÂû®3|s§V¸L[¡WwtÄ$N”Î êÒµ~à¤aA|‘¨Ÿñãäû!ƒ»KÓ4—iž#,,±*!¡5@´DÙ‡Ûgpøï]éá8„Ô‚Xd#åþè‰e¦JÓ¥aü”E"E‹|ƒ„¤4ìÕ:#/ú_¥Qqi,BT<Ú@Ò#,‹¼6?i`>|vîÞ#óaGÑ䘮dC1 Ž¬>¡J ¾ï»þ·46}¡öðð"*’™çÖ¦Ór‹Nñ‰Å³¸ÝP ëÒKÓb]ñÄ; #,GŽöŒD6™ø¥Ÿá±d6Q¿¡bÀûf(h©¾=ôÞé4¶xÄ—9°ˆŽF)R 0ñ‘Ã2‚Á!ÌIY"ÑÄÀ{ŽOwy_#,ÅÈšÄ>#×äଠ²‘Fm­Ïð~n5UB"{iÀâœ{Ty7, ?_ƒØ9¸Xf&f4e°³ØºS‘u0bØ.„ Xr!ù_¼ì7œûGû˜=/#,taû¿«÷÷l” `ÿ6…Ïß#$3<£¬m¡F’XÐß =.Y%„êüz¸Ž«ª¿#5Íùnî„»ìU[Ãu<ôhqkÈrªÍI ÕF³5„+Œ|‘ä|¥Ç·§HÞáI®T«|˜U3z5›–#ù¨‰z™Z›&`™±æ\ÈS©XD"“¦ìx N‡Ä£uEÈ÷iVeCMf°»D!cGùX@8l|߯èü‘¨,¨2"Hª~x¯Ù”ã,"s0þFŸó3Í®¤þ¿·ëõXö>ír6ýí÷W³—ÍU¾¦¿¾tvë€μ‚wCÅ¢$‰G$’I––ÆÉ#Ÿ`~ò xäa>Ÿ¯ô£ùDyý¨q§‡#,Þu(KCî!ÏÀ´%±°pxŠ‹_³G«K•ù—·7?h(ûãw|Ë4™fÈ‚Êñd“B¬Þ‹³XÄÄé•}Aá¸ÉɃ8)ÓID¾8ânòHàîât’HßUå]äúO<é'Wpë))¬éBŒCxÆ6ˆ,M^#yk#OFü#/Sfœ%Î;âSÜ÷‡-Q„Søï× ÷ÖgäÇ#,qô¾œ„ÉOHPÑFã›ä!dã²€½ø~•ö²Ð0¨‘#/ú/Ï\èn©¦æ5š6š6»¶×Ÿºû™ fï@xÖ$ü´ºü™Xƒ^æXö½€)g×H#,QT¹°CÔPô>ÞƒðC××÷?3ªOˆ›š±Z}ƒ@pH¾9¥¹‘#+ñ9„ ~Ç~¯pm>Þ ^óùè€F4äw_øŸ¬Óêlªr  $þËý({]›;Óñ7ˆpaÞ¬{E;#Dc‚;€àøx$Âd´lÊ6¤AÓç]qñwžAÅÜÑ€¶}¨Ïg"´DÊ<#,çá;ø”Ú4ÿŒê| ·pœ-ý9ðžÑPõ‚‚Š$!!|á4ȳ֧öKpx('™‰B&ÏEŽˆx'7ËðÌÜðäAjXúG®tŒ"± :dñ‡ÕÅCâp¯¬#5…ú»¿ã )úüt€_d„cÙù+ò }’e¯¾×Vñ=ÁàŸ(¶í~t3yxœÝähŸ *(kŒ-A[0ôº™6 b’z™$’y€\U=@f{8ÿ-´@µÊqͲ4dˆž¿GëñH¢^}ã3DI­VW½´£Ç»?¡>¾†  òå–Û¦rÜ«k|[çäÿ òÁnzŒã$ÙØF$ö·Añ‰`(2½0„*±u4Q“ŠÊÇf#5BËß…44ʽ‹…~ºTN;:šÔ)1J³ÛíøÈf &a™êQÈ$Šª&$0buq’ãÆñ#&Ën¾O5›˜NǨǠm}i§-î#,ˆ¼ÄöOg{®C1 ÷xX#/Ð_Ϭï<Á*B2† ôv;ŒDùÄj¶©vª­Kµg«³ˆ¦'¥'úÏX€ß0>¬žðö+Û¿„èêASÄ#,î6‡nÆŠrt`9+ÀR‹>SÅþAv%¿V^}MLÂÞ7 ‚iŒ3¯Ò·ôýÉ?¼Â)*Ÿç»¶'úmYCû^cCh:ÖiÆÍH#/3D"G[Ú¾#/B31tÔF®¤(wfC‡·OÍã«jç6¥­r„ˆîy­ƒf-`"÷•Ø®[ #,9RÕ|;ªªÙ,p…\À£þq6{˼Ññ ìó”*{€¡ÄcçxÛ°Ùô}FÓ`§0ô‹"¢)*F˜ >òÉÔý#,dû1EÉŠn‡e)Ô}a2}¹ÈÌ„9”hhX±ƒô\ì¹ÀðõWî»÷lËð1¯CÀWÄlŒhãYy°Ì홤w„NÒA$D"DŒQ ˆD˜Ð]È~™b!ï¢.Ì…ÌÎQgÕ}ÞáˆMwÒÕç uœ5@ŠbIrI2qÆöºDfä̦‚‚BLHzѽ`.~´P+g“P}BâQp=èþ„Á"#5° ÄP~ ôXŒ€ŒŒ2bÙ`’hXPÕèR@D0ƒ!#,báE&I¨‚dzý€¡Áƒšj4jZüÎì`Ro<ò÷¡âfFÆG‡Ž›Êø™&AB<A#ˆ°Ü«JQØÂÂõ_j4OP~1)Ù¼ÑLˆ}9šJ#5„IØ­ ÀˆGõ(þ¿ïøþèG>aöCÂï5AÈ#Uçì+)'µ¨£QÒ¡@ ±’m&S3oŸy«çï[;µskÎÜZÕÙB#bA#eSmw^xê³Ë®[Q‹{{>!œ9üíÓè«$Û:ü`x˜ÌÁ¡£Z]kuýà”ÝpËâÌA>²@%®Ð|Š( BùúÞ#,ÃUØÄ4´Ã°Úýú)’^ ”8‰l†•B‚ÁB) #56 ‚%›1Ä„:hf…È|è⥅¬”ñoòª²»ùÍ㜠=ïéveÌ^à„âE¥ÄyÑ¢A ›7'^äýSí¢–q®»´2œú¬‚m8…0-®Â‡lB¶É£Ÿ4{³ž^Æw[©š˜ÛÈFã#,Úf’³ƒ˜ÃÑm=ÿ zÈwwXÊ•®!^òÔÑ$¸Ù;Ág¶¯"ظn骔¬UQ|7¬+ýÀ?nÞÃéC .Ij^TÙHØÛên˜…}`À‡³cbåôoZýßœþé1†Ñ6}âØ«KL© ä â„‚#,ö$÷ &¸’O·êq0Y½¹‚ J<äÎ$ …Ô2¹”Àd£³#”T¢ƒ@’sì}Ýh¨€"r#ÕGSBPJfXâŽu2rŒrÙ±H&*7¦˜ "?P>'°¼ýžïп#¬¼˜“áÂÊô;OºZpìÙÕ!b÷Äã›$!·½Ï #äUóx÷37^Å7SÉ°®¡øï%by寧 bȱ;Ûõ¡PFKdZ˜*ví¥Š$™že¥ìÃxÉÉzOgÄGê#5MÉÁ ì.JGDÅþ|ÞôÌ¢¿RNÊ»Ë%ÙŠ+.ÀÄ©%#/ `ÄÀi1;½…&¥ø(­ÆrE„2–½Û# þq8D\èk\qÙõxø¦eŒ~¤`9•hT¥ŠÈ‰Ì\#…æy¼0nxho„H‡AL““#,T7»Ô#/‘ ¡l÷í-À#,@Óc¸?R(ØC·ÙöÙ.ŒL-ÈúzÎt fÌǨ u×¾øMœä" ‡ê²¦#5.€DìÕ û½X9ØrÄ:æP•×ˆ{ú“È;JéEX`“&@€YØoñ³›¹Ç¿4¬^m@ª1K ˜Ë I2mN/´ü›á2Eh®0­ÜŽ(¤Ùë^‰ûåI}²,€Ü#/ÑÞçP€‚ $4) zj™&“D);&$M¦ì/é×9À£¡ Ñ£D&èä$ZfÕÌ1úñ2:§6A¬å‰<—÷ˆþ¼£e“ë‡vÕrlwìC5s<%j¼™fgv÷§' ò´Öm¶3Dì=çëî”ðów]Ž£S£Ö{RD]‡#5â¿&Î.Aƒˆ+Ū9Wa¤Ö—^¢„Ì¥úÊ#Ú]§@ø$Ä å<“â—ëÇPIë§øeI$ÃŽÄ ;”­l h7àän\ÿV·· L‘ÓP‹É• è~‚(êgrò7·F0ŽrF* àF¯@l¤r7ÞŠà~xOZ/$ØhW§0øb˜¸Ñ ’¦%ª-‚¬LsÝ×ÀáÍíÌìsFEÞQB=õ´ÔÇ\ŸWÜè…³­<³·L¡¼îOÆRù!¨e/¥„ëõ™,<¢h<¾(ÖR,RåÜ#/™ò»w3vA&Ø?¬Þ¿O~÷¢Bâš¾"võÿRƒ3Ðn`ÌB®¥ÑQýñµ}/ =¶×ùc˜^65iÔKVäÜRMΟÎÞGgc›²h“š‚L!0‰IÈyÓvHðGiÕDçi2LÐ/ñµáTÍQþ^G4ìë ™¼Xtà†}p‰‡fì€ D Û|,8ݵ|²Û»ã†Ü3q׋±½?ˆ$ÏÖL@£ÄFL+¦Z÷‡Š4³FëŸ Ýt^ôpBÄ7£AµÁ#5CèÁ-4Hðp\ÆBÀ@è`©IõGãÞ`UîŽÓ LñûÚ(Çìˆ&\ ˆB$` Ÿ¿¨ï°.ªpmKÑèsîL»ÊÀ²à& Z*…ž‡¨àí{šfÐT7|ÿ­ÇÙ Ù=C¡ÍÆþœp„œbùôq¾XÆtL–?ëÐÄŸ€=ŽÒÞTVrG°.µ€\À'Ç8b\ÜÜàpqqÄp C¼È ¨ä•õû‰ªü{¾W€n88£·èJn»ÕG³Ã`Tv°)$+§ªüW¶ ©<ÂL«!{+ò>¿ô¸¤èU–#äˆÄíWt£ŠÅŠ2-µ#5˜ŒíøK•W iÛLY­À_Ù²’#l #¬­ÝŸÅµqíŠns¯ÞT‘¦–ôD·¿ðë?aÈžÔ­µ[i#/†Ú¡+ÒÐ¥f¶f,‹x ¸÷Õsà&öЂA–xno¾+½+'cùorXýºõ½9ŸoÚ—O²ó¨>óû_‰×õD~Gö!W*z&ýÌ*|õÒOö¸[|vKy¿y«¥ÖZæ¦o.qÓ2Ø6 jË A ,«L¢€~A¡€ÚF hàši²nÝ´ÒKÐbDÉŒJ1V4J¨„¨Ò´Ø#4°(‚±P¢¶„ˆ+Ùm·ÂÞÞu­â6ñIXÅ^à‰F ²*¤4ÿ€›Sþ g×#/ŒÜ„+ÿx¿Ôp‚Kf·Á=8 $Fhà BÈ(f¿€~}Bc‹Y$þõ–«Ô&1tõØ4AeòbÊïÝZ¹ôpÁqy :0¢G o~H wt«GRäÜÊô´*Äts† çk *ÅVLv Ä;/¦Ã7ÈLû›‡yêÐì{ȃHDS.W?=ÿ;~c³÷~/ûVñ@è„;ÁZÁ•ßƒlýFúQk¨˜¹Œgáþx»±Ú«úy/Ÿëý3b·Þl§~V’ÀÊe!’/‰ó¦f=¿ r’j‹Ð-"†œšÝý®ØN¯ äW¥¾ïÚ“×2 t“3¾î%š'3@ø@Dá' E·t@?Þcî.Î÷Ó¿´uñQì±—#/7dr‰Š*!9ÌNcÍØqúý‰F®;O7˜ŠBbqaHÌ€íøâ>>tɧ´ƒK×Ý7–1nóµÛì ¤W”P0€™À-PáBB™Ýõ¿Œ$ÍR$’R#5Á¿å‚"Fd(;ówI›Õä¤2dxDr¡øïdÞg¤qÈ!¼w ­¸3g׶£û[ØÔ)‚¶6åhJYšÃDlDÁt¡É#>jä)PÌ Åáù=nÌ7*ÛœˆA'P÷IÊï…ü†%l$Ž°¤„dàü©« 4¤áhîÕ‹@+!§§v‘‘²ç€k»ˆðsZš‹~‚üSºŒð!¿ŽñMO¦NZ3h>"Á#,R]"Aˆ HZig‰#/yš†!ç-üا“p¥Òûù¼Ÿý=ƒ´3‡×U<’mE™^ô:Œ‘EnBø¼É8<Ÿr‚°ÿOƪçÌüËšS¦¶ï©Âó¥Ñ=;iG\•;\×¾f óDœýLŸ¬õßhcÉË ·Ã_ÐãµwsI‘;-”™˜¶dˆ1êË+aïòYáT³GÒµ@ªY¬'îqÿgöŽ`”êhiôA˜"ÈžNÍñ»0¾D4ùµ4ªý|6¸ä¸Iµ&Єîu ‚¹ûàW-ÑÅDéW2Z9{š¼©%Ý$‘AQ)‘Æ|²±šôrE—yÌ!Vî=!#/iÊ:ƒŠaË¡².㼬†Z(}ø›U}¦¶BÎ~\šlG[I–÷+_OJܵÕÙv,´ÅË<ÈÃ4¥ß"¸ú A0Ž\&CïÉÛüôŽ>é’…—£EÛ#qVyO;õ#,‹Ž&¤U^#,ÛV¿#/ ÁA¿õØ/‹¯°øE·¼òi$©ñжœ•4Šõï•Hù,ù¡ü-„ó³+°Ì[„¾´Ñý VFl/žF%¦D©œ¼Œ @jñT#õ_UðÍS$hd8eb½í¯\%:LÔPþKÔÿw¾º~ß×µ’Ú=ÊoRJƒ¸›¢ñÝÏ]<áøEùÇ©}£Ãv‹#ÜøZé®#/­1RmªÄÆ}.ÚÛ•ˆµ¡¼F¸ñ×~Y#/çË›ï}&G;/kº«7å¼Àȸ칳\Œ‹•è¦*LFHzm€þ¹ðÔ¬¦×ë­*Y·^ŒíBå<žP¦Ë°@Mü²¿ ¡G5AsƒÚc Ñj«RsÍM¦óñ™ö¬&®Ü§„ÝqQ=%½‘=Pæ“ö„zt–J6œ^dxñvÓgŒïwHB^ÀíîQ#/´Ðº;œ;‹KÇEIõsyã!`Ôõõ¡ŠÒr6;öp{ëQ³ÕU9U1#01‰QS4h5)+5$ ÏQá­½ÑÆ9³•„¼>ÐfY0ã·nýˆE¥lßì{ä8¬¤ƒŒðÕlZ:¶•{V›*_ô8T50O‘ø~>_ô¯çù«ù.ÞÑœ¸äxô¼`KtymG"­Êk#/‰&³j-‘Ù³Ò¥÷YÐa]¹ïXR»‹ü*Š­Ô,Â$îÐéï«3Q¯GeR;tªá¸ò]>§óêåm§tNxPI_ñ:w‡ÞMgð9éy›ã9Ëƈ+²¬þ7=iÛü®ü˜øô<õÑŒž1é!»ŠÏ…#5ÇÛÁ1âEÙ㓶N¥Zw¾mA„¤ßar•š¡‹“;<邺ß2 !£ƒòŽ(ƒÜO~gÆ“µ¨ãX™ž;“0â !˜sG;Ì)¯`¿ëÎáõ·äûÛ§¶w÷\Ñò‡#/s%yOnËöpȇmdE‡,0;‘%°ü þc-{‰éÄñ¯U•3ì¥G¡ê«ƒ~£ßs‡†|m΋ŠæÜfûËOÁ5qow\;>Ã1Ê „këÃþª…ãéÒc}_Xó‚ÒLÃ:nWWwgºŽòÓËÙL:V€Ï›Èk©û¹ò ãÉ{Þ©­q:n³={r§¨³7 \;=¸ÝÐT ̈†P1‚ëÀó°¡¼ŠØˆƒ”Q#,("¹³0c¹Õ’Ü^7Rá@ãÌ„û¨J€ œPwAßåSŠkwÓûÕ^¦öElUNÙ ÂBïxF’sd4ó(ä†àV¶*r.¦ÙÕñ¼ægÝ]zB‚eÑ® ¡”ËØY˜.¢¬Oš©qªzyî­ó™à°dÈh›µý'¬Ì¬>´Siá(¦a¬b`îñ&@@ó rQäyW:ªÐ¤ðòÈ5Ü’¶e2W²&.ž¢ôÖÖŠcfJ3,xÎÏ~º?Å À<’4˜#ˆº€ÃYXa¡ET€0Á††±†ƒP‹J›®·£A¯ 1ÒQLç{8Š™#,p}郛!‰§¬¹à^^©~c^ÝÄé¸t'¯ÛE³{(,$’ö±!ÉaËmª©®¢a«Tbßj;[—!¼êçtvK£×.}Ú¿‡[µwôÂêì}½ý˜Æ­íøΓöj×CYËé§Ûÿ]¥Ú4Ýß¼]…€ã×M¡Cì7´‡mÊ;Š¨®ÈÕSxšŠl³ëd¼ FnË`((YM" â]•VÓŒýA&LJà/Þ•u¶î[‰5RÕýÏúŸÐø·ÄÍe,æo•Úo-ŠÙ]cU!%¤ª%„ƒòþÇT÷´¯±N!é!Q«»nÏ"¼î ‰¿½þÀz`ÉçÏm̦Ñ6“~¬IÁ| ú0‰„! +¬(ÏÚïyr.z“y ¶KK™cDw}’QµÄáÜ쨑¶Ò&¬;,„ŽCÂøb¶Ùº¼ò±EŽœ ¯\(°B,B&ðÍvȆšÔIg1G¼ÖŽ¦à&‚6Ô)ôàÀ„ÅQ˜Iã„Û'72…ÊYÄŽ{¯oãÚ믉|]T-4d¥_¤±ï.™ 01˳³¥¥­˜vyh¦ztÛ,¾@z¬”Àl qŽLBØ3vÛ ›zÍtj‚ZÙ»ø¡EYß•°ë¹«/¯5­NzʺáŽ.éÔ£)™ömk{U´i;ÊQiL<4êh±Ç6Ïqcã×WPr·Ç–ÎûÌœ"#ÓmÛû!wh”Ú^ÆŽ¼ì\¹Äa±ð[Y·¡èNZ)©lxÒ4S ^ÁÏôds>!ñà4‘“„ôî úÐÏÌb]n&ÆCÂF2îgÈ47„ë—(ÛÝçïØe×¼4,J'j=f)c òº¨MÇ8Mý|9eÝážÝwCF $‰dªIk6l~¹zôÉ«ŠRï¬{!ñ6òR`Šj‚Ó¼'ŒD˜!™½Ô22Þ$.¦3 HQ^‹5#y…ÀÆq3šÓ©²Ä)k°y ñÃzÅ,½|c¨FÄÀ‡»ùwu  ø;#/|4Ö >€·8HkÒÝ¡ì¯9Ç\x:GÕ”jì+¼Ü—7ÙG"&È÷(p³‰éz½cÔ&¦Ç¡  §q¨¡9#s oØë¹s2,©Úm#/Œha›X}ØÀÔƒà’9oVõqëÊwx„¹4ž„z/sÊâÆ9L6mt^”üJ†–$9^Æì’s¨ bˆ;xb\ðeÛþ»÷¨¡Rw»êXê-¾HÞˆ/‹™˜S¨dƒÄå @3‡Ã§ÉÀiº¶ø¯fï׃>çÞòÐOoªq›Âc-“ ,#/MÖ,û~ˆ÷Q¶Ã‰ 6‡ÔiØN<Ò¦2 ‘1ÃêŒÙ´×½d$è„ nyJ¦ÜD¦Î÷{Z$æ°`’ L¹}îšÑ\]Þ/bê`ôØȉÃÞ(‡¸Ü¤&‡QD^÷"àš@g0Gƒhj÷{0e! \(ÊBˆgüÿ@â= IMÊ’ˆÓÆmu±)¤H‘HvŠ›@×xdÙ>d¬j;ÕÉ£‡èÒ`DˆCáÁÉ¡ÃæK-„!™fBAG 1–i¡ÇØLái:àÙ6î/bŠ-jÍ~¢˜`3–3)ÝàJcXŠ¿Ÿ¡Ctˆ3(HÔbè0#,Œ] ¤;•x8Î!=–ÐÖü¦©áäf#5E!SNÙ9æ}ÿ^Ìô1¬¶˜³Ìð#5 !Ñøê`v#/s‘ 3ë©n%%=À{#:ŒŠãžÚ1@ˆ9s(ã ÍSCg³U¡@×,l¸Kd\²SU3Œ¬X7Š12âóæ›àðVp¦ne.S`a‹2=Í‚!ñ{dk2¢ÎÇFzæ9.þ—è„Ð¥aO%PÈ·LÃ#5˜Šd@g‰HzNcƒ”p›˜¬äd#Å:úŒ7¥p)¯¯Û%­ìŒæl9æÀŒ{^ðÂŽº2™–3^„¹´Ž2l#/¡F×q[–*.IÔe©RPY.ûsÙì¡Ý>¡­½‚Åžìcm¶ª]ꮪÚ³Ê]ªªª­yüîv$:†ìWÓáÖ—.DÑES1ÃÀ;Æ|¾8)›Ä5Žs¡åZNòcú¸¾„ʹ>Û žˆ˜CnÆŠdm#5ÆëU$5³Ñ3:g²¬’lf…-Ër%a=¥Š‚MXȵ‘À ÎF%F#, q.&gEÓ;-Ùê(ÊjÌ;2a!l†jŠof÷–rBgHÇ"-3$Ç(Øñ©ý° ®z}&Žž[†úíÛiu®&yüÍÅ‹±]ûDÿÖ„ íçÑ>¶ÍŒë‡ÿ:?ÛA£É!Ú=¯šæ»û0|x®Jü"©‹"¬VEø ÿÚ–,KËI‹NwïÝ]ì#/¤f‚…¤¡îòØ^zîú¸(Ö>%Â÷.X`Á**,F"”Y*–Áô( BQËú^‚‡±ª(h”ö\Š€!œ€˜:.m6#Ÿ9 ¢Ã£Ç¾0È?ÉÃýìÿŒüŪÇý?ôì I©¦5¸ô}Ð* °}ªùzvÛgêç³k³)4”ÕÚ·óճdz³ÑÞ=ÉÝJHlü=-ï)¹#,öiÏ &ýjR“Q²ÚdÛ) M¼ªŠ"HƒAHN QÏlÆ€9J·Ù\‘€Äš±iêüÓFFMlZ)rà3íþO:·Žû9qÛ¹xÀ ¬”“Ô.^Š<,û~ä„‘.ÄT¡¨ˆ4¢=Û('ïk©{¬r²5ì{ìUçýe\s´Œa©½‡‹âÒR|“ô÷ " ÌÊ%Œ A´& ¨üs=$ŠOÂ}òå4Ó#,ŒT²‚f®ªD@7)Ø @;ÐSÙ(hÀBDÈàªÀwûõŠ™—ÔsÒ¥ÂIäÅçy°Ìk1EAPp‰V ±±ŒEõÊ€Ù?AÆ&ŒF71ýí•FèkÙÜp‡”¬LhñÇãcí M`¡©³|„{L‰ÈªM°~eŠh•:üŠBÐH #,=fG@–ï§Ù 2cSàuQhbªÛÇXXÔP3–2Ï[ jFO#, kV–æ[†íû¬þtGÉ€+¦@`àÐ@ $EðÒû¦.ôÂ(A0 $ù'!:É÷ÅaDD$E"âD€W‡È.)åÅ$õ[u·[O.Þåáí×æîÓ'Ž;tUÏÕ©•¶¸ñIlNµƒXk#5iB Ð L”€¥BÉ‘6Sü¡þnW,jw^K{"õoK)%4[Þݼz­ÍìŠö\¹175ÒKË»–5Ç÷žkÇ.‘Ά74••Ýbå>¹ÛÊt»ëåk&±OªR*–‡x ‚hDÀÞ¿¤â32FÂRbkËÍ«ùðmø`\ ˆ§°˜¡q3þ‰K`Z6ôYûÈEEb±ê?)È'²×ð÷OçÈvû+“E’c©Bu‰Q¬C²æ¡È›0åˆÆÑJÒEj+”…‹œjNIA˜,¼íУž¬Ú3œú­´ÌÚZóà$`8Àãºr$ŠšR³¸®ºõU¿ÁÛ‚Ä"ª€qQàvÐ DŒd‰"áF,ŽFt#ÏÛ³–ëUH¯ñA1&öì¹äO ÇÓƒ‘Í_Jµ¼ '‚”àe#ÎTæ0¡É® \;Ò’hEd$rH”JÓntBt›)¥…%A€~,D ˆÇ®i¿‹u.œ0ðZ‡]Æ]Ámr85Ù2/â6ð݃ȓÞ8A4ÕÁRa#5î\K!¥Ž“ÏÁ1í#/#/¦¬8ˆÚ UƒµÞ^Ø!%ÔW¸/ØNÍôòý/Éus@øÄT{0îï徨å(´­õo÷ŸöÉ»nj좈AѳLË—eÌ!¡²ƒÉ™é}gÛ—¯è(Œ!EBŠ”RuvqÜœNå”rA5OM&t¾ˆ#,°‹(´3}ÒD~@ÆÌÉ ÓBéTáØ"jÓÌ¢ê–,è'žI×—Qm¡‘ 9§ö4º¬R¾þsîÒåÚfnKšÙc„@wxîÇumüþ>gaü,ÙeTJ$hªdTwÀ›ƒÀi¨Ý …Ñó #/£m±ªÅÕFEJ$¶*¦¥ZÌ…*’¥ª-’ՆʊÍšµ*Ø‚ˆúN ' òœmôÊ“”8lñ|‘a¨2 ȨœüÅ(VÑ#,@ ôý[Yœ½Lo’§…ˆp†ÚBØßì¸ðÊT`3#/ ±UÖ$ÌŒi(ô-ì;ѱ#,%• öÀÁX8±e:b=s˜z¬#/|÷U_… ÆØðGÕšFLöM6Ž˜Ë7L(âÃsCIFE h ˜6ZEWÉZ£9‰2銯·ëÚ¶D_nõ@V@Û´”ÑSc :³—hg=é9Ò­A‘m*]%]%¤#,”öÜ¿§³Á;ÈÀs ¤D*¨€;6„OÛ¼à<û6·Þ¯¼µd±ŠÍšÌªûÔáª*Jekr®Y+–»JfÅ“E¨¯ÆµÍÕãt-q+å*øÉ+8˜(n‹#, @AÈï]ç}z>Ž±µ¶úŽÿv[Êi£t´‡ü .7|^®­ ëz¤‡*ôù,‡²Ä‚$‡ïN"“Þ}¨ˆ•v>Å:ÿÙ»W¯Ëöýœßßþ6Ú˜9!Žuš.$@„ Îÿ2ü[p˜“,)µŠ’Й@îeî½*„?K ‘#5)Q`¢+åT:¶«n;N9XÉÖhæÐ)Qÿ\X/ç$&ÏÃIeTù¿öiª'T ?‚ï“Å:›x§¬1#/o / (gÂT¿«{ˆhbn#/´bDÖgdç®A²²c¨DH¥Ó¹2l`›zÝž‚ôaWõ\Ü0ÃÚ‚ÿ„Dvvu‘dC!«çq †ˆY‹ð:°°@¨i­ŒÅ¢6ÚÆA¸¿U#/¹‹o{dÖöˆä€¶úxÒ$ U 6$cL¹Ç¬zsE#5PþÇ›ç36pÅBAtʼn²¼–¶ÈÊâaDÜpÖò±ƒ@™ª‰®ËoÑO "¬ $(¾â’¢¡ëñ£¹T;5<€÷Òž1gN\Þ€ÝùÑùØÜ„Ê#ÅÐ~R›…BÖˆ)ª¢‚±eÄb]Vž¿·©æAHŒŠz‚¨¢$¨‚ #5DH ²xü‰2#,¦B†1X#,šd==ävߟsƒMjX3ù vNˆ#5Å÷QHFÅO~Úms`j#/6À#¡}@ô±d#, ² ”`†|ÁÃë²dèììõSö¿¿åŒdoß(ßž$ÛPîÂÕÛ8º“„‚"‚Ö[÷P–O|RMamC²¬. ý™³ãsg£B÷ÄL¤ø¼Ì’ù§ŸƒeZmr´¾#ÈbÒ¤GHJò8,öÒÿG‚tŒ>£Êâ÷òˆã4g¦#xVcmÖ¿[Dõ£DøL.z¦ ò­`tx~{SsÞ{.ž7Ö;g€Öœž×Ø<‘Ô²öýZFà[ÈQ0˜I»ñ~1Ï^zí…öÉT<Œ-ÀƒÌÁ`¡O¡dΙâXÈÇ×Û²X-SdéÒc(‚ˆ: ¿ÅçMÒûrw®ýGÞu£V‡ÏlþèZn uºc:·¼ü¸˜K‡­Ñ=ç–VuAÚ¨ÓFå§j–×J³5C¡!™œ°Ä+ÆB¯Ë¬1¦¶éO;îåò±#5<>?f×ëË»¿¬щ\^6&‰3Xi[²«Œ«}š^šèÅi°¥¾8Ž 66 `ÚŽÅÌ„G¬ê;8¡ÏÅ{Ôò-75¥­ hZšµ]ØzÑä¿®ÍZ[[»Š’'Šã,͵&æfñ¹«Ïf@ J0b¡cŠè©ª&hìÏ ‘‡äþ66mƒMž‹‹÷0äÞx®C¶×Ü"Ó±‚àÎo)žªÐb/ÇòrêïÞ™— /Æfï_#,À‡`À#¦3¾Fk‡¡£ ªk FÇÀf iœÂÉ“õµÂX“ ©,KíÀ/@÷lgèpÙ½œv7Â9ì¢isÙj.uäñC˜èÍqѤ÷†Fa"Ê íL(ËÂ8Aß(2p5S¯(SMUJ,b1d;vó%ÕD%&~×Ô„ÂÈ¢Ò)qæåÝ=DZ öí¾CDA‚F`˜õI=h§–}ïjá#/ÌPðŒwßàL!!“±s‘–DÊÆï˜øéÖÇ‹1;-°à9#,rF¾TÍœ îCGç³ðÿ‘ïxüÅM}`z| jFB‡*)ZP‡ÔÐ|*¦¤o/FGƒHqB:l×N0$—=HDégõ3¿vkï¼²wÁLÕ ÀØqdæõý[” 2!§}›Œc+äv@“¯ÝÚV»„Mþ§AçF6(ç,‘O#/óëÅ©š¦µ¼Úæ)dR›%E®–ìÕÔ³DÎíµuKk»ñ¬æëºë^/àxÞLj9bð¢Ô²! M¼;K˜ ‚SIyË»‹‡y¿ %„l+[óÞÚ¾Òû·ÊhjFRÔÈ«Q5ýS» ÚÃb4Z9˜œ^PmU¼{¯.³€\^øoúêýß›„žt2‰Dó.ËE#U ‰ßˆ±#€áE0žAªuªÂQÎ- YJÉCÞGB!ß#/ÿœÀï£éÀ>#/Ó'QtˆpòÉ#,#,rÛ#ÉåCª °¦C7;ë˜i’Í=h€÷%[»,9­ŒpQ9¡lGJ©„¢æe†¹újÄ3&šîÞµï@i¥ß±M †+e~Ì+‚âŽÿI%KLžÐ*¯©êdž|vž[ïH'$'ÓÐzSê¢bI"•jnÝ]hÖå»;­ÚêÝ­Ýo#CT’7©!Q4•ª#,#/$&H‚ØYöšJ…n¢B¡‚GA8žúXên%µ(.Ždb$ƒP(a áˆ}h¡–6Ï2`4LT5BÞ†ŠÏÙ£ž°šíÀÞI Žû×è<}O¿*¬-¶¶2<[ýY³ÏiÇ"Ëm±mž¢“Ä„‡V#,¥^¸aëš_» ó#/Í\vÈHPÌÃK#,ÓI:ˆ„RD#C·.#X¤7`q/ÇÈ¢éj¡Ö™Þ"ˆ wbwX‘D#v;¤á¶–·¾ÜÐCdXS à¡Øì449íÑD¼Gð¯»C4šËãz¦wÃëøóo5ìmìxÓ30ᤆ‚ÄZît¶6‰èù]ÇOÿdÅ34Q/¯Ï|r2oD”•²,HÈu¢#/±}gžÙ#òc¦³ÅZ’1ùCª¤Þü%à«Ò‘­5)$6‡߀£nÙü!û4ZÊ»I e@¯¹Ì\\6†ëNF¶Èn…$ £äµ)φ»pj²®¥J~Õ³rçÁÓÄÆ6~~–»3ÐС‚׎¨hãÒè„P®s¦úäÃ… jþÊŒ¨4ÌG9û(!¯EUCàì†3Ç7¨ÀÃ7n ­ÃA ´¼Ê/N6Aš ¨Q¸]\è|ò¡ B)L\Âaùƒa°{yÀ…Îl§²j Ð-" ê„„¹†¢Te…,‘9¿ÑÏ[²•üñ¡Ë3äCH&%•V «YAìU*#,…EV Òõ•ªœ$:Ä’ÙAÌ»±ˆF•$*$,„#2¥\c Ã3ØÒÖ“=Ì<šÍ¨Ül÷–ª3¢P A¾50tÖ,-(¸«jÙ‰€I0Ì‹#,Ûo)MD2› l²¶¾F#55`êR“®W¥GŸû'V/¾y”•Ýe•ë‰o¶”Ë‹$…;‹ÖT2‰±¤.; ººP– ã‘O”,HéÆÈ…EÙúDk-ö6™›PPrÌQ'äHéÅ´Íáµ^œSÜ‚Æ}“̶I†MK¹ue% ¼#/OwQÄö9oÌ’þ$áJ•‚ðÌ@ 9:Àq¶i#,,óF(ÐÎ$¡è/ãíÎd°À±~F6óññö÷#ìñâöšpoKž%EýKâF ©T+n‘„ã÷tæN»ô"s-qE’(¡—Yëï?µ ’B+!)ÐDè¥l>Ÿ¯W}ö†&ìÏ™kÖ2¥ž/Ë;Iëï3Ôz¨ñß…šjwHeSR‚Ž»Áp–0úžÛÉ{Óóõˆà¦&ƒìÔq¹áãøÇéˆ"ƒTIÙá„[\“Q êbçD BÍØNKœQPa0Nmj–pvT—sÖ#Þn#/ƒ~s_áò«{‡´`øæsp«í#,öþ³±…*/Z2)MÓzÕw0œâþÍÆñdoéO*TWäð4Ëõã8Ôîñ:Õ%ì(»ÕXÒrª°5ÁŸçgøY3ÒBnc1o|p#/7Ò[sQ¡¦!A9©«.Ë%Zo»-ïÜwJ,i¬#5#,U@W@t`¯?)@M†5B¨É2KäàÈ Ú'2/Z¤K@‘KÀ¹:EÊ ÈÈ –Æ#54ð ITpÇh8ÑÙœ¶ÏO&“‚ÅWMÊ8ZÂó\‰ô˜³a¦,ûŒ…aÆßé#/¶RÙÌOÊKl=ô—a<VN-ÛÅ¿IÍ+pÂ5A´ÐI§Ã$ñ ÖFh>àÕk;5åy¤2z/Ìm”„†Á5áÄÁ›‡±ÛQvb³ûÊ¢'G0Ð c#, Ŧϗ³¡;Ñõí4¶» A6e0!Šˆ¨4‹æ´¤ÏÇ¥ª.ƃ&ÆŽ%Ì”"Ùn±¤3M²IÄ#5i£I#/ #5 E4ðÒãc=íõ[&hˆ„¢ƒö³&úA…Y©b” ‘ ˆÇ@¸Ž#5 €ÞZÂãˆ}d “@¬ì‘¿ih`û^¿6ó€wn§§à™É§U>Õ0G©{`H‚@‹ ŽGYn#,5ïÑÓ«®Mc›=&Ø1¦Æ€wNÿGG"ÿa樌^oÊàq)8÷ä?L¹`—ÞOóAM ’g’©çÙdÿwæÈ!ÒB*B"‰sºvYƉè í­¿’Ðl‹6-oȹžunIKmÛ¯¹jª6Ô„‚ÿ`E´U´E$A¢ #5—iôê÷§¼£#,zˆÈ‘|ëî:¯iÏCÜ$©[¢X7ºz°îЀm…” T“íæu¦Vzž³äqHDî!2@‘†H%2RkHS$Ì–b“lZL´¥ÕÓ2¶˜dŠ6šT!’š#0)6IJÌ‘¯µÛ¦&Mi4h–R›Y¡S)™#0(Ð#/©‰I¡ÙÝD*hR$ŠIIbb Q’PZ4M’’Á(EŠiKQ²(š šFe‘¦£1!¥„”QŠ³Mgz»ö•;À8¦,ú0Ì9.ÛœX&Aò~u=JÎÙŸ·ôf̈ÿx¡=;p%­S*F9.¾ó•e† ì:¡§ºy®ƒ~)W¾/×ÝtÊe#/´îÕ¤•¬D!$Åt2ÒXï-œq1ñ ÐzŸM“Fýìß…Âöï7€y9,碓³¾åì¹·[BJ²G6”þ‰kÒË¥gßÏø¦dþ$¬|>˜/»}!‹…aº« ªhÀ\³#y,P!pÄ ^F¢ü#, @9/rÆcPÕ,ÒSiZMa4•¤¬ËL$$,qpxÖ}miåTx0ƒQÊ™Lø1Ç?büÄχŠ­ F=DØ„}ö“Dˆ•õêÚM³ ! ZÅ¥=ÙþÚäcõÖ;ÛÔµŽÅèõ}"DcqøC‘–Á[oZ}>·rþd‡/F› …Ùt”½*› Jè^á€faúþ‹²H1Õ‹õ‘½ZŽ 1d~æí“{©?å¼WÙÝ­Ûµ-ѵ´cH%µ“#V iô8$Ýiš m¿ ÒöÛMó“(á©ã#´Ê%j7®N.ø""àï3]{ãŽéDÆ°¢›Aa¿rP´OezA¹ÁÞi‚ìÆBÝ|J{Lš feðv^`ÙGäÌÜ$°Y¶ÜKß#5<öÒ@Ø#´ê@íÜeˆ¡ú½’ö?o-tž¼;î¿¢¼Í”‘@†kübØ<<õµc/Ñ´À5kìèrŸÏèÐ!V ÒiϸB½†vW5ƒI²¿5ç†ã-†?mg:eY| ±:YPìžì²ªôS||S%JÓÄ©=ý~õÊŽVpj@¨{% ܬ!¹Ï‘Ð3¯ ôœ²[ÓïäY ¸Y#,7\F0–rÑsÇ'B;Òmˤ7#5ˆÁñÞÉ ,>!C ÄÐ$ÃbaÌÃÔ#/Ôÿ¡¨Í}¤Cog‡ŸZ’ñI–ÓìvƤPû`M2!äûFˆèÖ Ó…-Ì­ÚÆÓÊ;Z#…ê¨Xe$|2’}ÙåÞùÍÖ?£V®lÛfI”Ô†ì)ÔÛÈïZºQW¬Æo a31þMf•.¥2^BåÒy51Á„-,.K¯W”£ÔZ1ìf¬Þž1`9Û©š‰”—ñ¢LKКB$ÎÔm¼JÝ µ6üt’AIÒÊΉÂæ>ùÛw•wws!šYÁŒL\.iäÁ Tø0R0JtÉžçOK7¢©á?óíÄÁz¶¹~#š¢ŒË­;"¥àFá`ÜådçάËì–Ã#5ƒC0jvœÖ ÚcTêX~Ôê¸Ü·1Roø‹g„r¤Øóˆ3%ÃÊ LBì 2´>t#/<;;, ú7žx¦dºCäÓ@Öp5‹¨íUƈڜ‘«y(aÌ\rm†–Âz¡W««2ùZBA¢ ¦³Wo0áë”àÛq’52v¾Ø³/Á§Áuy¾—h ûº;v[Û$ç3¨â3€ËÒÇu,­úfwÕØcbÔRd,vrhÀ L»_;l\;þNq#,X(‚‡cÆáŠ(ŠÕHeûÁ5-1”êqDW;4Xa&(Œ~]çªO÷Ž‡øÞu’ÛŽÇLêÀ¼øãs¸’xíÇ)Þns/x.ï>YÌ㦫 ¤’kL:‡C›Ø‘2Ž6I7= ¼c-l‚vÛ…É%ÅÞ“¥¢*êoNÐdÝΦ—ØÆëD@³ß™9;6.Än%à‘ÓÞÇG=²öâaÝðÜì¿Ün æˇbsÎéÎ'\µŽøRž¦Î]j)XÎÌqMíC“´#÷å¼—qê.gxÕßÃ7­0ln6Ôi•Â¸Ýq-n#ll#/j&¡Ü(]èºÇ&M–7K}KJÆèôRrA‘ƒaÎ`î¦é‹"Œm¾86v¤cpÎLc+ÑÆíÙ\»•ÓZÇsl£ÔÅ\#/e¬S!(òBƒfækKZï½´k**)šjÝ”ˆJfGºVXnÁC#ŸBÞ(BÛ‚ iÐ#5Ñ'Ks­ Á\½ Ï•1GQì±mP¹rIY¨M†1C8ÎÌöC´ù†ÇG2>TP™‘³.e†Ô[ê‡FPaNü+imðg`ÀŠrÐ5×U/V@ÅCd&Æ^‚,ÆÓI53S¥¤ ÓQ‰v9‡ Ta%3 8][ßPJc´$dÂ"méÙKJ¢P‘ê´TÕºùØÔ3‘É 3ø1z®C³mΕ­·Ìõ’`Lƒo´ÚwB\G,A(©Y+”;ßtÓcI¬7rX<ð5iaNF:tÞåt4 ÍËËÕ6ÂXK›e:G #5&$Y<Ú k‰ÈCEñçÃeá—Èã9€·zâòñ³Ñú‰ƒiÈDS‚QHn!¾¬s(a–M…d&°U2LŒTBš@»©O©6f¶RêT–Q§v(bÈ°2’P¹•40òd£zݘphU°-€`ªJº™8T-!–ój¬ YlY)7ªP1šË0`aV‚e©6IO$¤a–`J£€^¡ÓAX6öôÒŒM‡ Œ+ã¥dLÙR’Ù²[,¼Ô±›2evgrx³VE0`õQÇhc¶ögYföΔ:™]ë‰Ö©—ZRðz ‹LiM+ÙÂ3„‰‰w-Í ãÔ/®Ñ‰Ä!+)’e#,òôö ñ8à:H“a ë„<>VàÔ-gnK`lErùÔö×¥ó}™ÄŽí`G½+½è…PèP}R9‚AsI¦Ðî±¢`TiBƒfèÖ9³h'VÙåâ˜m‘#,@ ‡ ”ΆEÁ¶ÁÝÜÚ3#/¦Læ3ÈdçJ×¼ÑLMmH) #/¦á#H. ÑUV8(|WAÈ]G’DX°j(L Œ°:ˆÄõñÉ#,ß±ouš)‚&ßZ7-½m^¶¯%â-OnÛÒL6C„CŒŽÛ…o4ÌXn74§ž"£¯˜Ùä/ë¼ô|…‘æ#-¤J:?åike$‘#3 œ9ð3 £·}hELȆŒ÷ Ç ˜pqD` ¡‡­#/ŒAĶ‘@Š÷ǘ†ØhñÛ²M ÐQ£f&—¬GcrÕV ÒÅÚ•HˆurŽ˜U1Êò.IÀ8ɽÌ0(vî)7†Fk6Â&Â¥$,Ù3£™‰HB*Ùˆ@…À†Çc‘¾Œ8pv¨Ú‚‚x±£Iè,Òóa½Íf‘л/Y‘Øï%Óz`X†‰FÐÁÍuC­T¡k@º ,Ä׫zè6‚/#5úì”&i°ÜŒ`èpWî¬5M‡4f3•‰cžm,OqÞÁ™º5¡·#;pd0Ãr›\A¹Ë„á­Ê¡‰ªJ,&0  "BÁþÆ @‡ø¶”ôBE„M )˜»‰h °RÂìJU#5#/†ŸÞñWòx¿«Õ;€ÚüwV춌Œ‚²­M!¸>cûÌ‚N´TzÊqˆÒ—B«øÀï•#A¢¨³°µ¡²Ó!!ÜApVà^È;U îËKùEòù‡ÓÜÌj4ÈÉëÇÖ31®[>”çq9"ë_óADpX³[dú¡Ç.¦Ð‹¤ ih§¤#5tÄݺ…±RÍŽAiÅÎdÎ-+X¸#‘ƒ†Ûd¦¦k`(o Í[FFK¦ Œ#5ÚïMݧ`b̸«;¡b¨mMšv*†|.ã©´¶Œ÷À8›ˆKœd¹B‘$1ÜýÚСU{nÝ:Çk–emúi-m&ó@„U Œ‘›ïò‚PØ8„C‹ —§®‰€—#/yPåJ–,‚Ъ1Ã:z÷ E¸ª[géý?P±;÷ÇÊq:‡—à ²¯ÒE]¿vÓM+oßkè¼l¼%ɦcI]wfsu‰QmÒþÑy©ü÷#mg¢}Ƨ¦p¡Ô²¤g,rHȳÚÐ"Q#/Fžãò±2Ð>Uñø”Ýq Bá0®#/7>ÓGÞ‡ˆÈa$¶ÅRQ´¦Ú+FÕ%E-35PhÛEŒ#/ €I#, U¯ø&ïaážY‚_h –êSß·«½qLCà]NØ*~M¦½ÂžéØ˦Ÿ¹ç|ÞÉ}9š5v ²KÂÆÙ‰#Mè h$ÝFY•D…¤Ò ro!¬¨{§ŸM@H Šqö:-'„Íe¬ #ÎfÐu”/V*(~ÆRH)#,ÔÉRZ üä;¶#,÷v6hñçÑS¬Xd&A·ßUÆh*1’Ó"F¿#tJ²4&Ði©²#,\ŠÒ%¢ Ä«ÅmXÔ¸óD1–!p„HO“š3pÃLä\ÅÍeº&šEKÀ1€‰dÀfwùÏGÁðbvúÊ#/‚›”]! BÑjÅ l].t§Øè$ Ýq.´ýÄ[YD*"Ix¢ü,†ØŠä(£¹œFXÿB`>šùdé0òð°A |ûÅA¼$&œ ?mFƆ´Â~Ø#¥Ço´] 35o]ÈŠÈæºü!®Ï½ý ñk@nmpF_ol==1–„ɶW¤3ˆyQ„«Kc+ChãÚ la¦oZ4´cX±EzŸÝì°ó:ìҙǥ éVP½´[MÚé×3.º˜)d«Cƒaç¬074ê¥#53©#3“Îðãžfi™ª¿Â&©¨ý;dÎѱÎù!ÝÙÇ6Ü=ˆ.Ù¢“•@°.I›9Ä`5†#/#`†k”¢eL¬;C¬€Ú ÝÒ–S3:g"K`¹ AÍ=:j4Y%¸ºv~Øg3ˆj ‚qÚv†Ì6K:A‰F%‘–XÄ)¥rÔ)ÀÁ\Ød‰ #,ÅÌT°Ò¸0¦L1 ¦ ™C#/‹  †9‡Z$#5YEÇ„03#/Žnh/Ë[棈 ”¸?ã RD^„NFÝáeÓ×Ýë± ³Ùeýjæ°pH±]” £ý'ófn ?Q?T¡pü¡Î °Ÿ»â HÐ5à$éLò°]YG=#,‘Z@ùýPÍ)¥^î d#,ÓNqN˜U4QUUU#5¨4ïFßÛH²[h­’­bÕ¤«Uùµ”Û˜Æ~+ëÄÈ’8}üϸïd­¾h‹s#5}Ë#5ó”‹PꦊüOô`8ã¿›Ü:ubÅr¿½†âa©k²wŽËGº#/Š«d‹‘A“‡,ë§ q¤Ó2enjêˆMªt”’ÂÕÊu…®iubãê;ÞÚÊEF1¯p1¶×Ðèà\PàÄiÊtó©·¡ÁªR ‰1œ¤¥Ö;KÌ4›y¦óYÛ¢ÜÌZ’ž‡¾:Ý­t Ù&)§Už pQßPYbÞÈ…13±³Ë5B"òQ(ÜD е±fKñ-g)\áÎ:;X´3ßääáœBàQ‘2qño#"ì°˜±J|Å!¢ž†”ֵ̕+â;vÕ™§{o(Q4Þø½,m½MŒ/ˆêtQõ6ûe)Ég‰žL˜â}¶`òdCRŽ MNä2Jò¢ƒc`”VwvÍfÜË—\”ä† ¾,,Cˆî— "( ÌÅ9xokeAE¦ #,ƒPJ`Æ ˜¬FŒÍ2<Âå݈ Jte.%¡qžûæÅZóȹ4Rë&¶nÈĉ@K™…œBèÒ…8€Ð…úÙ¦#5:z¶ˆŒ©zÙŸÒ55 ø]ªîÝ’m[}Fù.Kµ³awsK·\f©Î·³s¦]ÎÉÆN»Œ¶ò‰ªéh6ëWi+r»®Ýݤů;¥5;Ow^o5¼jB×-¹­ÚTj“Ch*‘Êëi#/#/ii"Vª†…#,nÛ^62šÓI I‘6V6ÆÔÔ¢™®¥®•¥šX‰¬1b«"CÑå´ÙÀ0Æ fl#/’+[IQY’$AG‰?I«Ñ{%´"Й ö1‰±Œ˜‡}’Ã`¤¨œNM£.Ä¢-"°T†Hl²o‚ób ê;Ï;‰ØL'¬„Ï^‡êaKîZˆYLÃ?y·òb<´@÷Äà#/NíÍtFLJçmz¢×«å¾=›ÏT¯¤Kóéƒy#,ú¨UEÆz,qƒ‚æPî ‡ö¼Ïé’Hð|{†éLûK‚‡8Ú~šêÙL/B`ÁBÑjÔ‚ªÿ~ #5ÃlƒBfh •Z4XRÒ#/BD×d7Q¶Ûfv[MÅ)”a‚Ñû³3ߥ‹}Ù9-ù·XùÄ6kÚP%,jTŽ5\nƒ È3§vŠ'ݬJ¢s\mje2+çÅ@̪3p—¿ zϱ•¹êkÐ#ƒ§l‚Ó r*°+xºg"De“§çvJ9ó“Ýg ë‘t/Ð…ÂÌ(7$ÑtãxŸ§èk¨Ó¡®{ƤØkTcEÚnÍLRY&mÞfè·­Œ‡êøvüc-LªÔ„µrœä¦”Š(–·Ÿ|›[[å­ Þºf²Ò¢Y¦›i›El¤ÕJûKü?ÉÛ_¦Õ_&©¬Óm”µ¾­‘#|)‚D…š– gv¼™J×JƶrÅQm‚”o ÀÄ#/Ôˆ™ÐYÙ5ÜP£ÕH%A@$E 5Å-%&Õñiº0”jIk)¶­6ͦV̵šSE*KbÃ#ELª•±-¥0”PÚl¥2%I›)™´B˜Õ2‰)(¶5&²T•¨5)”Y šJjE(™±%©i²6jɵ4˜,‘T¦IY°•ZPl¥H”$’e’“)3’jdÑK6©¶1ª&Vƒ"FÔ”Ô¦Û*šÖ¥šL–4¦MJUK*Ù*Õ|ªµÝ­²²ÛM¤³i)*ùM­®•6mT¦Ûi*­«á«Í–¢«ÌÕcZÑl¦ØßZªåj‘5jUP‘CIF9Ÿ/HpnÏÀ–NÝoŽ†MYÛH÷e³{°Ù2í›0ñÑcBÝë'~«ÅÈ㸫 ©½»hYá$©=!â^#/)ÂÈÞD‡u/÷€1ؾèž_n'¢£²=PÂÇk´4#5.Ã,=ü½,k³g]¸bÙ 3meÌzË£»>™2Aó1ŽË`yd„E,Žàuõ¥¯¡}8þMCFßl¬ët+÷ŒYE„ Ã¥Q¦(fI QÖšÃM$DD‚jXªÅU#/ û#,;£Ü{dkù‹X'©Üè,š¡é5vî‡K°6Á0ùå&¹Ó’ v¢ª~#,© åžÅåûÐÀƒ1›°ý"|u‚E. y!ŒJ’Š­ÝÓ¯ÀºÆ2âCÛstæ¦!\ \£:q±1®"µàv_´• åïB*75¶0"t^+òA¦#/tøySyjzM‡I!Š“»4ê#ñôÇåo{ºòœÆa^E\^i­éY×O<íF‡ëu¼]ðи±FµÝ qWX¼4×Ñ沶ð·eÍ’¶½ºQW]ƒÙkÏc“B7kéR“ŽæÇ1…qPë6Mù«!ÎÿÌ]"LÅÃþŽHe™EÆZP+®ŒHŒ–Ú¹ÛéÆýƒ’cZPPRJA7+¯è—'±Š+ÚN…7HI!„ØòX;A¡–5g—ZÞÄXí=òª4ÍáGÄÔAFM#/½P*‘*0f=EîdÑhduç§ej®C2)Ò¬„BáPª °aAär+ò0€¢Ld^±zî.5£'[šÑ3D#5GÇx?!Ó¥ãQT­9ÖM°)¥hw)¹_cí#PEêzq–§MKCr¦ UK†QË4`ÅŽŽL·~%cÞPt#"#,ȆÈHÈýËiTÐëlñ¬ZŤŊ ”a&B[e¯Õ›2FŽìe$qJLØù ¯ÅÞöÌh”È#/"#,#¤Òløb#5&’G­*ä‹áÌTcÄÐhŸ,ô­†Þ-:Õ uåÕkQ5; 墬lí4QYTQ˜×¶˜Plv;¼ò´wÇy#/ÔcSfW<|ò:Òx½‚›PìàÓ·rì·NñA4ÒÀb²’tÁG­ R]Sc#Ng#>Ìðn,•D ´é‰B!²L8 ¡Írº$Š¢Jª¢„IÖ¥ ˆ[J¨ÝØY’k¦ëmGÉm½È¶+jòïY>!S®@‰Œ`F‚eAB¢*\¤–ÙB#µÄÄÌ0€}”Û×–Å׃Æd>É·#€ª1@ð3;õxÎ]Ü©q¦¸@åÝÑ"Zº#4Å–ŠW‹‰·ë_x ,À¥™ùúùùBkdÂ+õµ¢šâÿ!Õ€E‡:“A#/b`5|ܤ€(BÙ1UmµrÆͲÍ%6W]6‰×M5ŠÔj¿‘XŠ,I¶kÚQ­½÷«Ùl©hÄú?ª­#,a#,APÂ"PÆ7À°Î!Bå„îa”ü1NaÖ3÷¬ÝBÓçUk´0+Ø"A¡0¬ðf·×6˜Ä¿&®/†``i4‡ßø` `¢ì3›c°0-¡€*ŸŸÐmÃ#,ŒAV¢ª4JÑàÉg?+ŸUú›4ð;㺣,7–"’IÅ ˆψ¹ª‡×>;vI#,%ÖCh#/ý¹;Ç‘éO«Yöýyñ½Ïí½Ï镯 ­vǺ.øuQ³“‰Ûì!ø«6åF†n²àCw7i¨ÎD=wyG˜¢"»ØT"Ûöqô#¬pvv- @¡Y^F#Kô¼j(Ûh b¯XTe[1nŒX„ š¥ßìöoçÈ:Á2 B?PC¨Šq#/ªeÂÕ؃ÏÑ騱â¯Ó=ì_è0[ öúÄ=CmVKb¶¿Rjµ,®mu›U·Kj£i+¬µ¹ZÚ5²ú°ïFŘ¢‚TD$A¢% !&#,3«=wÞÂîËÑýpAW¹ÁVØÀ¹JPe$À" ê%#59#ª:BaXLÚhcAèÐÚÙw°»5 ÈÅ3a OÖsarz“Í(Ñê É8š£ÊÎ%cþQ:øÁGÁU,!ÜHwÑÞ< 1÷¤µH²ØR**+àvúÐÜQø÷hc10*Ä5Ã…hÂômXp[,‡šûä€&¡#/ÇŸq‘ãßM¼+1yåÖ~N,HVRª¡¤Àhxü½ü;;R#¨” 8J<ˆ¨R6USK‹Ç^4R †ÃÓ~¼Ÿ}ì_Œþ=!…„P6QúÉÊ&÷-š[­T&–"`åÕ¼Sh ‡ 1³ØW6¼s«¶î‰(Ù5&*RVѵ Ô×Ê[´i­¦•”öWRk%XªQÛ°-î¹@mßß¿p¥Á;#i“ïvÒEÇ€42£tñJ¶éÆ­…;ˆy³ÌoTŠU7ûmiàУ6ˆøêU&$¨gmÍ(¥8¸àðÝ`ÎqDUå‡Äa3œêèHzmW¹"Á(ª ¢ÅQ!Æêˆ#&Rä+YO’@Áa¸è ]æ’ Ø 1G¹wù '¥íí`u’$’LÀýq±ƒƒíõë¿×÷[ÝÅ é¤ÐqØ%³™¿wRh„"…›hÂ)V›¢`¿äøm#/¹›dŽzÈþzÌö‹ž–¶ün´h5õâR—¦È¬‰Cá :'ª¥t›ûŒÂQPnÊv@às’¾7i5$Ÿ{1#,Ø(2š0Ù†A“ ˆ†#/Ü …F%#,>Ìõý¸ñŸf“Õšà0†n(c‚<ù˜1ЫÌÒrÏõ¢#,¨å¤Ñ*M—ÙóTI%FÁÄ8¶Y0z¦$öi…“¾ñ“òÄt¿Š6ÒuuóObˆ{_zišó®˜‚|ºNµÄ&åßMå~hÖˆ´b-"„¡jM$%"’ªm´µ%¢Ú21™¯Ö› 2hJ‹K?q¶¹µ¦eR¥%XÔQM)i6ÓLKfµJÆ›YM-dÖ‰±ØÚPj•£"ËZQ¦U-*kU’)h5†‡æz”#/i„O÷?6“Žìd¶¤"f#€ƒˆ£ÕáücD‚5$AJ ÍZ£j5¨ÚêkZånÍà[2@$dH¸buC»«~H_r«o³¯£[š¹ÃW(ÆMÔ¿Áꄉù’ ² ùË”Íü¬¯¯uV,š”#/¤K>av\öýÙ#,2Ï~ñ¡: ·(Û°»`ˆÜ§.H€w`‰åßþw0âW„Ah€ÔöDáÏMÂzÓŠÙýÄ A2=‹öP•U*P” •¨ßäQ/j[¤(q XO½œ¯"ØÊ<Þ¿ §ðÌ•´Üm×Bƒ$€ÑÕÐ!=L=|î€âª¥Êh"jD£9–8˜'ëÝ•Å¿2Ð33²›–7ü}‚§¨‰Ú½&Œ$ziDk´ç*©°å4ø †õ@<{GÈ#/gA'1#,bjIÄ·Xj‡P3väž<䱬äN Hw0ãÈàlúḆ©ü\£Ï\»(ÍØH±’ƒŒÄ¡ýk<ÆÍœ„!pIª0Zà~¿ÙgÊ!G¹Ëú «÷Çòùi‹|@¡4´²/âçÝü¤û»My–Ôl&žä"Nçký’À½[FYD0uűŒ[ªd“Bd˜bû©e²¶ö¹Ò^^à07 š…ÅsC’»+Ž_°ÞäÂ} ‡±‡±»­S .Ü6‹i@11Å¥²„øf£&K>^&—×m5ŸFá~¬RE ‘AN䥂(Æ#b„ñKw>ïdŸ«6kG´:htt#,á=_ïÝŒ—¡p2€É¼n¬²ÈH‚‚£c¦TÛ=Ò1ˆÈ,¶’2&š,K¨QC£Ou†n–ê–‹4T$Y”²‚`UD)å-SÆ“¢~„˼S.›€(ÐÛ XcQ“¬qÀ-Ô' ùŠ÷ÁˆÌòAydfe@v`b qLqºß m]*H™ªJêä€Jd¹Ý¡-îÁçtõ¨vÁwÄ"Á\Ý++î6-¿KÍyñòåÕ7<“yrBóÎ¥~I#k,Œ'¢½>ÝÍ•E“\‘P3HoVžLÆ¢"3°ÇwkM´×m*o#/¡'EÚÖÆÆÒq8‹¹‹A-ÂH0„¤”z ]á£ïÒÖ ¤,€ÓŒQU¦¦¼ÌœÅ<eÍŸûB'0rwd§ëµ¸Žjá*Çy²K5^P¸Ç @œ3)ÙïcÞ·Ôº¨WŠ…RÅa0ý¸;§ÃaDȢ߅¶•Êoïó£}g%ø×Ã.³Ì¡T ÔåÊBIª¤‹n¼†È[FRPì#·[Ñ$Y íTiãŠ$økÒ¢µùfúÄ/êvAÎW<r²àˆ›®G$ÆbBÅÞì‰LCh~µ–Å…'6ÌA5F#,Öýäˆ7¤¥‰Oß¼(ÀF[$ï&»ÂZJËÜåóÞöcn½ŒBÛÁª?³ja䥅‹J“k.91-”âa¬†x}L®³Q·#/£ìfξž@¶k€jGR‚†‚РˆÙ±¼º]ª…`B@Fì(‰•iR´@HôE(¨„Ážf´#5¤•Àõw”:S §™±tEvoöο±P1uã±Ä5ç鬙kÈb¤ÄD(u’´ÇvËæð9´t` ¿«ØÜxÄD$6!É›UdE:ö`VAA%Z¬KÆö¶‹¸\ˆÙGèˆeêÉp×^Ó•³j‰©Èàýý°Öúü›Ý<‘}]ÜjÄ~ñhóuµ]v›xPšDÛ^ºò¥ƒQZ›JW 6ìB #,Æ„6’% 1‘¡(2¤*TUF¡ (PH}WC™È¢‚Ø÷P;{kTƒ¾ ˆ‹`©º›SU(ª¨€ªûù^§òW{Ä1\*ð&GaWŽ0­ n(šwŸ##57ôx—nïmëĬcºÂ[p™Œ(À#5Óa;@#:÷/2Þ(’µåÎæ“_R(ô€Ç¦9»ZÉ6ÐIN0ŒJlC*šDh) ›Ñ6¸L±"l˜sEg6f%Y¨–Sd WLë ÆžB]å0ìè›È‰Û­«DÈÂHÙ“Ä/òmZhl0Ò#/ós`Ö¤UD7wD 0ÚÄ1l®¤2Ž{TõEOé8 ÚpãÂB@„u"T#,/˜-ÙÖ—77¡çKïîcI©Ûê´Œ#d=^£š‘ix=KZ…ì#/À›'ùõ6á­•F¿sƒLu8š&ÇÀ:hì¡)#,êƒy, ‡¢*]ZRj™¶ÊZ6eLÖ¨ªRµùUù›[ò"W]¶Ú¹±…!(`°¤)’(£Î€‡Oݸcó!Ò<®Yh¹·£j˜_HqÚ#5€¬==Ö³VB¡ïš1NGŽÂ^uç–\T[”žö«öÑäÝYGÞAÏ ŒC#»:8ŒmNçÒãÓYÂÉŸ÷`â/ $–”kR/ë~ªÀÚE–y'áPÉ<Ö»ùf·˜ÀÚ4Ñ$ØÔÙ'½å2‰¡Ž’Êhå‡8á}“n±ªÓl@‹ŒQ:ÉP#5FõQA4ä'^ Ã#5 1ÉW)«¬ï½ºôë1LÅ‹=•_ ²¦))Š•*l#/r(\4JM¦f†AæwôÒþY’Kjé>Æ#/­µø˜þÜ‘cVÏN}M·ø¦<óMÛò#gz8ò!§Þì2vu¬#/eÁ;|jù`³ßÛDF`(ƒj¿ÕD«–™÷yyž#,zÐOIâ¢Û€Qž”`4jû{~Û‡œ^È”˜„ãÞ…ð dÅ(›N©È”ÕúñtHQ|ÑÑ÷&4Í@{R!ÄÇ*›ÑÀ܈7,cŒ —!Ïë`²|èVcSWn;>³<D’×—ê½õÓÖã„nŽ™àO‡d¿`”:üg„3!š¶#ªTÝ%T@÷DgD47:ÍŸvÁ£ Õ^}ó¯rû žŒGœ·1Ç+>ÇiïrC€Â'*¥YC(•9$—š 2idHAˆ½-"g7{´¿=Ù€¡¸/Bï6.®¯W°°³ý_EÞ+ Q!¶yVÑ`¨ÄÀdvÊ—RÚÕžvëÓ½©«lÍ[z­t֯ћSM_©uҕĈàVxâùÈ›ÍFFRàs±Ó$h1jšø$”¯ü_íbÇõ7ñ¶îÒÙè’¤=È?ìî› ƒÇ•™hæžrõ[F*&ƒkã±xŠ©ÄójV°¸²¡#Ê~HRe¬ç­ulLôеd#/0÷ƒ4â…ÅÁ±å­­Io#|Nz>P 4Ç–" ˆ§R7ø†%C2ämê﹄€G¢#`Â#5í‚H_8FHT¤Õ¨,±\ÝÂØJ€ ·vµ×,ÆÝn³Viµ›6ÔÍi’¥™«lËUu[7e4¼\“Jím}R¦bÚÙ`@E9Øèq`@ß: ë÷ÏDéÏÙñ»oUëÖæ÷<˜ÜÔ³ßÏØÒÙ5DzÌ"µäú*‘‹4„ª‡ÎÓ5!ñ>éMI¹ó†3lÂAëõlõš¾…ÒcZ<«ëÑÄ#/›rÄ£I-¥¦‹ý{¨l­>@ ÈÁkQ ²LU‡MFa°õ8½Ö¬ìbE,…” Æ4ú#/Sž¿Õ¹õ©ßW#/6ÞM»J16æ¸ß¸7plëÁð#/ÈâÊÅ_p6h^²oó®Ãnªø‚,ESøëÒ`ØßÕí[¸`”]Ô¶©#5hŽXæUÕ»°¨Dˆ€A¶ÄÂó RF~ÃVø‚Z*îÖÈ3%Ø÷Hk)JòFÛÐlÈ(3™TqMP90yÍEÁšAuög¡å#/­áTCð~”z,^G™"`÷¿=·<â‘I:~ÇÁï4òOZiƒ[9 ‰PÜäÈù}þg›òÙI0IÐFÿˆK÷#tH²À¬í dZvζâŒî0\7 ŠwnòÐ;#/ì8…‹È® Älô Ò¬ÜÖp#/ÇØ\×yܽ÷ù˜Œ"0ð3Ázõ¶ÛñâiK¸™íÚ(ˆ—IˆöÀ²RaDú•VIu }YK=™.!ö»Ò< áàE„Ö0‚È'!ÔeÁÝ)þ5‚›«1ŽÕÜkÂô Ž¡È3oÅ0ƒ? T7å àÜ„Aú tæ„&Øðº4qü`e3bXFËM£Lö›-¿#/ždl‰ß‚…@rMÓÔ±î£?Â27!áSÑ°»SXÇ•‚´ºÛ¬ÐÊR5vûÃÌø Š‡ÇßÊ|7ÓÜR~"Ä@ž €¨‰™ç;§2€^|7Á2ªº€¡êȵx«Qm¶Š¢¶Å¶£jŒQ!FÒ HP4&0»æû_ò__l'¬a€Ä;HÀ‰@?¿¡Á¹U{ ¸ØŽèØtÛO®¶qqFåœÃØ(nao3[²AD†¬Ì¹ë"1è2•Äšž—-¶ä+|±ÇšpAÌŸî#,í¦ž§˜`8óâŒ!o#˜$†Q[4ÆycP!øÖX¦20üÝ¡ðµ æú4ñý_­óU Q¨(¦‡­O^ýÔª›ÍÔ”IÐ(9†<„£ÄÏB€£`0Pž"ÂdvIOè!·ð©#/[IÀÔ£×ÇyÕ3†Ó}„ˆþ3ÍBçÕÜ|Fo«1=ð<6}Õ æeÖŽž˜Òbè T#/°*ãUÊJª’ƒÉïÁo6Í÷M¾¾å®Å]Ò«!²~Ô¡ˆÀˆ’{ÏaM² dp£AlMH?¿Ýî.xS>Cŧ£1îM|,‘¦Ýøòëd50®n>0†3¿hkľEƒÝFo5qIE.8<<4‰fjiªž ‹4ÍéßcÛC½U³5üïÂÙ”.!CF^ž¢2ónN£méEvÏ>†ùa0cc…¦ó±±—½æ¾¦ºèmi`Q00ƒ!’Ÿ€O¸eSiA›Léõ]-ÊÓ#âý%í»ìç/F 8éØ]T(£¾¬I¼¾ Úñƒ¼ç”ý8.0üa­áæy•žExѭퟧfpuꛧ<‘#5òáÃáŒÔ¤–%áq y³+Òž¤ÒœcÅQMBBÈniúÅI¼·Å‚ø¡d8ΓÙ#5ß<†×ÙÀ®Ù0áH:í@i}᤿5K`S™Ó#/$¦S«ø}aêêü“S.=êqP@o’ƒæ "¨ÌˆØZK‹d²¿8("|hUlºCHMœq­À°¦«2£J±¥ Á.å¾VñÒɼm»*®·6²m»ÇI±Z*òêK][r®íÈÌÝ×h®®ifÍÈÙ±²¥¹Â§vÖ’ÚM³l¬Œ#,´…ˆ BAB¨2ìÀl@¤œPK°ú†G ˆ­;ÑȨÛ£Ó)¡ñ¡Jk©ôaùuó÷¾vÖùµ`J•l¾5YpMZÒ”ºÕ»-¶ZóËlþ8¶P¸7Š‹Â6XjbH2@'%ÍÊÍ|my3D¶[kÊÕÑF.>/=òe5ŠÂ) €Ê„Ë!E´Vñ«©•I? íP%±X2”ض-¢1Y•Æ£TmTÍ££EE3F²Ve$ÈÍR Å´Í%±kf¯vè#5$9 ”A´÷ï°¡òÄÅ:þ,€ÉôÖ­{{#/&Õ„ “ky·í_‚ØúW§|vñm#/O:ˆ´OãÅÍ·’r½Š£]³„×VÃÑP"å#,‰H@Œ“¶rñMš*¯É+~&µ\JÚñ[¥ý[v"V)O7]&©ÝÕÓk·i)µ®&Åm£&²Vî®Ò›V•T¯W[KIQ‚”‹MÿÍ!Ä6^Ÿ™ A~’ŒüjIèJU G&0A´É F;JCay8ä X„EV)!­ÛP\7œøµJW#5#/ÅxaNŠ¦èŒ"ïW]0äÂñÕmúŸhP{ö5>Âo>«ãÆO~#5?^‹HÃ)AˆÃðEƒÞ~ÁÖ•84}& ð¸ëmf,FE[ÃôÙTlcUáŒcÓJ€ÐÒÌ­Y… ö2º$šhÁŒŸÇŠ÷ånµ´ÍáöLc,ÇzÈð³†d·øš˜ÛÇ¿aCsb­†á‹»±-PZ—öR#5¥(P ¼!Ûgꮤ¸MŒ;:>‡$Q8duÃ<^ÑwᲩœù½‹§[¢5]ÉÖó™¢mÜY`¾‚[hÆ‚QŸg{«42Š¸Ó-½?¾ãø“¾â ˆ#ö§Ö;ûñáÀ¬föÖãu»`vH©½O*£•ÄQÃ÷žt?º±ë0T‡!‰çÜLì3Kܺn¨E2ñ-Åõ!ó`y†f@<`«ôMmcTm¡-¾º_}µ¯Ï-äŒHÚGüäL¯J&12ˆÈg#,KEdχQlšÕZ5\Õµåuæê½À•ÜX1ü€nËÇ>pD  <ê0?a?C_¡ÏÙXZQ¶AÕ&´×_·y®ùq¢ÚÊV®––0£%îh€Ö ƒBƒKF¡¾@ÁÛXÍ…£ô½šØ‰Pl4$†ƒÚ¶ïvÕ¾Ø5ª™IŒQ­UãM±oŸ¸Ú¼î݉ð»Æ®¤J(D¦eR{Œ%—!a#‘¤šZawiZ{Ò¥cl¬Â‚àL#5X»‰›¹*Äid-Y* «°ˆ f c €ÂŠ‰(T(±`4½¨t6ÀLÁƒï¥¤µ\E”C2èËôé½q4bàÓ( ¢1‡¸–T„ ò_IP¼æð…#/JK¯¬úpcÒ4a`ªsõ€q•cõfLÜ&†CsÎÎWРèqŒc0Ô–£nÜþòÝš3³˜@9@’zDTQ1#,ò2“v¶ßIùüihqºX=nìšG·o¼7¢Éÿ¶¤²ÂçägƒgHÏíUyì78~X‡C8GG×!HC‘{zðç±úµ:Ô\9úpXÉŸWó𶖬¬äôþ1] ½þ¤q{8ë©qö8é ÖË(΀TáÇPUAà vü›&—ɷ䘎YJè’¤ÓHB eŠ#ÜÄI™˜ŸxÐ×mí Ç2¸¥©#5?U€yÈ,ª)ji-: [G„0÷KÁlÅ@(`-ËYEl8¶<¾€ÂàWH#“‘^yÎéáÏ>Â;u茒ÿi~6a“éã!ØgtÎÇ…ô+ÁæQÃË®6õ4õ5AÝþ÷@>þ¸’AðEUø&+»tî•\Õ¦·[MJ¾ü!VùîwÐP…D¨Þw&Vãû3‹u÷6Ûè×\J•Õ°fÓ±ˆF{‚Í…wŸ£Ù¸’I Ž-U#ÎòóÍ4櫆Iºï<Þe¢S–æ^s JjI’±”ªñmÕ+bÑ ÉcA²[Âk¦´š;¥uy¼GK¶è\·wn‘]/ñµx£ššW——mvœ¶e’uÏ5·U±«m±³MO5Ú“&Ôi6žuÜY.»­Ý”é·E+;®×*êNîÓbÑcš¨¦†(TE‡÷P(ÆÂ)qUö'²pØ`›‚‹Ù·×½UƘ[µ9QüžŠ$;ÔþÞñ-F :Eð„ €H–@S¹ˆ–U—Ú£ä$ëÄËóGÞŠÃx Ø×H7#,|`HŒLÃkÑÒûÙø¦‹õè•ÅÝ°ŒŠÐîõÞš7zòñŸu£á¹?GsÔ›NÀõ‘t•XÖfmQ)™¥ôÕíÌ$ è„#5uZ*Ðb Áp?„#,X(g:½ül*&ŒXEXD’0I†$OaáêPúÕBùòèØ5+¶u×wRÍEE»­w·m¼’ü>ï!ªgá#5ÂØÕ5jL¢·‹ÃÚR¨g ¢ÔA¢έðˆR&HÁz×M!;ŠH¢@0·1ÃB"ŠÌf£o¾uªˆÖ­×m»i³ìkÊŸë«nÕ»Ål¢&4:§žýé˜d'È@k:dÿGöáí)R0 L0)A´(‚#5l`|ÝüSCÙXÔ ú€î@#/ñ¦¶›YfËU4Ö¦ØÛi©ƒ†ð/#,1Û³é0VçQ#,uÌmõí³lšÊ¢¥Ô™›` *ÏÈñ`ÔÕT#¸ú0ÑFÑJRRj˜0²”€'ðP"$P ¹pÃrª¿êƒŽs[S>Šã5‹±\”å,AL•¦~>4Â7H΄ˆx²gW‹Llf-mEúºw÷c~«#,¥¼‘Šb„ BOÄ!{ßá?=¹^"Eå#,úe‡0ƒù³È8ƒÈg„+`_ÓÕ}CyfÊÈHC ÛIÚÔ4ˆ>7€ ÔÀÚz“8blfh J å…¡ü #>,-j#ø6 `j#/$Õ’1W&³hÂÁ8é$B(rA#/…Ú²¨0@ÞÝEd&1<¬¨#5´b#N°ÑM›¨X; •AµM¤‰„Xñ`]ÛL¨žúów•æ·ˆÖ-GŠ®X¼jå“W/‹*µâ¶«ÆW¬5úR¶Ûk;fN=Ñó{njöÖö‰0Ã#h~€bH$ÑG(‹"c\Æ<.ð ²Hk_Æ*-j‹Fž›i¡µ,Œ%£!Q*Ã6ÅîTb¨ÄIE#,ª5AE@‘‰w@ALZ`m6Ô]ƒÆC±Ï<±ÀHA}~…Ýɨ'§bWŒÅå½ù}$µ…ª ”Ž!A¤õ@Œ%(”Р7#/€º±—|ò³±†äOvj)À‘Œ$° ÄyDz·A¢ ²©€D‰(…B¨ ó÷E>A×óÕëX4¯ž6Y7OmwM¢ f#/”bubF(´„ÌèyCó?4YÐ5™á3˜Ag™OøÅ6¼zôþ¥üÔÎàÆ–ûlvAÈ[Ú>pZJ¥¤ÖðÀçÙ*üÍm5ÚFv“°ÃC$MËUÚèˆñt»¼îõÖë‰ùHÓF Á0cKOxÔÌnÉ©]!ýšp#/2ŒÃZ}G‡ý%R¨,¤³N ¢2M«O‘BPZÿ L–ڽϰÜtvc¦#5vbz"‰ù'‘êÔ/#/¦gyêA¼™Â ¯1>¸ìFâˆTWlüÕAœv÷ª ¹FEÆ"€HRD'º†˜ˆ¬¢#,‘#,“˜C¼"XSò#5â`yÓ`ì~ø#…¾Þ¨$ ¼Bﺌí§Pðþ>ödu½ê`B#’4”„§è¶¿nU°››¢ ’‚'ÐoÔ‡®Bx|úŸ¨WÓ—Jö•À."Š5'á±½}å™ÍP9JH”(˜ oÓì#MøÍõ-›¨6œh–Ã%wúÌ°:wýf79 ÕÓ¤’•*ø˜“c¥L°º†Ä@ûÐg¡Ð¢‡\ææiÆ`Ïz\·^è!ö!£[$f”§4XBKš LÈ­*­`&Y4n"Z}_$?/‚x*»ý»Û–&ào÷#/¼h‡¼Hba !ðd;¬_/Q­}h7Êúæ "/:ÜÏxð±Ö/Ë×ÆmàÛ™UT`ûäsž“»¼Ñ6]Y3PµŸÍ{4ÂÖšüÍ—èª;VÊBÝE‹–e0à:ûv„r¨Ã`Ð4#/'8eF©j¬qÛE¤¦‹„b±"À,q­Á#/#+Lé m-0f“Q2ÃìgrI §!Žú²Ù.¼æL;ëúµ HùƒNU”kbf CÕǯFsSÖçØ·÷R'¶ Kâv+Š`Ç”7±={9 lßGf-2>ú#¾Ýº‹xãˆZÞÂœ¡¨x‘ª†¯n¼ÇŸ‘ÞS¿eµI™Îé•|>Ÿõª·ò:lÊP#5Á.ƒÛ^)¥àIò z nÙp£¦ÓLMñéfÿÍß fæ‡ôl‚¥Þ5©^‡.ØÝJud„&ó#5!„3@8‡ )ùÔPhȘz#/QO@'»1ÔÃk:#/Âs>ø;ÁóÊõYZ”*€ðo†vfƒa‘UAÉðìêêÝž@JŸÏ8EuBåœs¦cÈÅš.oŽA°Mı Ô@i©Øp› n"õ¥R¡Û¯†VàeA‰Ð`T#š…pÿîöÔÀ¹@±~“K?¹’|v‘=•ýÞÐ0 Õ iL$DXªÝ–Y„´Œ` Ðò(ôêó®4 m¸¬žÝÍ#5hñ(>ú©¿Ñ1ðm§Ž#/?­üì9óœMI#5BHj¿ŸæÖÃ}_¹5}J#/~‡Ê­ÈÑ­¼šÒnD„ÄF‘ï’FrÙš»“…@ä7®ÇÍ<Ãó‡*„óÙµÉVÓee¿vÂvøxw$NIYúðñð›|h“"Øê½'¯dÐ<õCrÆXµÁ !߈h!2ocnÛìüÞZqpÂD¡ñ·=ØØ–ad1äm”" ¢#,™O2åkp´Î`ì ÒS¾ctà|]ËLõ¦ýW“„ 9Ñ1☖òFqexèô¤@îŽ?fëUÐÒáa¬';ôß¼tN*©&d8œ³ÇFÞ#/­bá=‚u³ž»YfŽ–¡˜ö:Ux1°ì¨HI$«6]ÇÖÂ0á|XBm™a¬Œ3¥|HM®JQ…8åÔæ,ãW7æï÷l—ÆŸÒÐ È9þ¹10H¤%¤"±Dô©ü‰¥a|> _éUƒw¸ˆŠ’H0ˆ²»KUÕ#/ŠŸ+›ägØ~Z}/¥0#/´Mê:·²1ƒÈ4=çÙ‡ä=éÙ.¢ý<ÍÌ4-à˜›Pr<ÎœD1Ûômz»¼Ì-¼¿jö¹ùäqò â admæC\ÕjÌ0¶ØÕ¬Õ­-K‡T\c#ç ŠÁ^%Š¤â#5šI#5–jwáx<ÖCí3ôƒhÇÕlº‰µ&W±Í-þž˜Å7AãÚo@Œ4œPCr‘†A)FP%DE!] þO¯*܆áĬé¼~žøÞÒ¿«·×½m™ Où¡TŠ´ÛÀ¤ê@>Í]`É÷*çÀt[6¸œpbZõõò`¡RÚ¡oB7‹#/]}Ùœf‰ <ŽF[CؘÀ€UUFëa…ß`}¦ì¥‘÷œ(–Æ®-Š ,HÀZÚÈ}x& ¢B·º²#/"PÔ³ÒäÃîË£©t3ìµ¢‘H";r÷ý{à~SH«ë¸î­ËmÜýû­RQ¬c[eRšVjlX–­*@B,êݲÀnxR…÷!ÄÄ ;òøô#5ŸKD‚R‘H(EÝ»ðå4Ó·ùo<ÀdRlÌÈËI&Â#/4”$¦Ä¡´ÊÃ%A²ÊšKHÓ"BÊ”©d)k÷s`Z#,Ç14t„ƒ¬GJf:Óc¡Îž©ËQ¦éá‡uáuž9Î.*v3#/&È„m1¨Œá˜A®¯ ´Ái¯%Q÷:¬Ë+Wwiå#Z¼tÃ+*qÝðif¤ž¸gè,LkzHÅâ ŠËÄ8öŽ \@ !ÞõóŸ)ãI³Ùœ¢»Bº@صYt+t'a¦˜¶@qÇ(£#”T‰¹ù&@b8˜ŽCq£â\Z.=ÛÏxÎ:oS,¢j¶†­õ¢²ö ߎ ÁÒägb5¥œÌ< 1wqáÇ&”¢òDd$‡(íõc_“#ã1ïQkR3„†ð×4V5ý ãÏóOíY;Ô1ZäI ¤þ4DF@ÂÕm¨¬‰–ÁºÆÄ#/24A#I`‚mŠ¶ CbH†Rg~¶®©\º«–›®Õ&·g%Í%æÊJ6Ć˜‰Å²´1¬™p.¶c6ÑŒ‹V#5ÀZ€;nR¡.Ñr!E’ŽË%#,æ8²¢ÚÔf?Ê#,*Â@c 3W¹“n].jw[¥¶Ûu{õ#/'·„ØÌÓšQŒAÌ<ë#,B™‘„#5ÅÓ#,{¨ãZm§ìU+qؼñA¬ ËÉXc)ÿ¼0Çðø›ÀÂB?'Yã ]5Ý]Ñ£È<ØüâWð/#5ŽÑ@Wjš2¥aeŽ(h¤b‚lt¬‡âÚlš(± ³\8l¨´›M ¢¼m¯smžæ-Ë·q‘Jr‰HÄÁ¸¢U =›y#iGM(ÚE¥ “š„qd ¾Dƒ,DCtF“X8¢‰Ë#QI_S³=Ok­{ïÃÂ%{Ž¸M- 6:7&Œ¡+…U§Kd2³ämbB¸ˆX°N5R+%"{2€±d+ 31ÆÒÆ6C ë ˜`ÃRtn(”¥#…IB=$yÔ*`ÝɳcšÖo(žjïzÝŠf;P˜›dÛ.ñæijæfyPŽ"eMž¡²X”™um[¸£ ‘Ƭ•¼#5Õds"X,#ËŒ£2†5€õˆß`ښÊÉïëñk†èh1ÐGC7DAŒj3l3 ™YÚ¨8‡¨Ñ#/j,Œ•Å‘ƒŒoÎàÃR féŒlñ­Y‚n(ë9·4TÖ€5#57× d.vt<Ô`¤yªŽŠ± á´¬f#/ôœ²j4œjŒ#/ ‚b¢Ý#5f“E³(È’Šɦ“bóLÛãÆMœcHB^»>hƒÛqËÙØÚ0‹£X>¥i °Nm(ÐvÖ­$äE‰l2ê’[BÜÁšf‰”,˜D„i4ÀND™…”’$119#,ƒ(`Pè…¤Œä¡¬GäV:Xi°Ç“Fµ}#,Œéáˆcm˜â¢6„˜&0‰ ‚hT‚"m#/,)^ª§FJ&ô{Xg&ÃAÏk´cG6»L~´c´¢¼A*u6(Ì&BÖ-#/4©ªcl[ÈËn“±1›g­M#m>Jash(Ë°Öšû¡ìbÂ…täDT×çѤpìEÐÄUHOID6<¥´ yÃpß4t=(·YeºU$â9¶H|“m'#,÷:hÜF [s(€Ùؘ;0fȈ„i-Æø*@Á’ä4!B†ÐQ bJŠ£"¤Á€4l`Ñö’È^)"¢à4fŸj´ÉÌéÜ‘iì%0±ý­*’ñ…*åM±“w½-åÝ›¤öñºë•ê¼^Mß]öWà´bƒkFª Qd`‘‹!GQ#5Õ?÷w#,YCüBd¼1#,.&ˆOϺýP6” $-Ù#,.vâ¢ê~Oæ2Æ÷¹E@_3#5#/(žª(ÔúˆBŠ2 ¨nÊH B"ˆÈ¢DŒ‹Fhƒ¸Š,™—±î B'¸¢´A9^çHä;æy{ìmò¡# BäR”Ÿ–Ÿ“Å!KFúÃyhÁ…ˆ7wRƒNçÖ‡uדù«xõÅœëcn®®š—¤ *©’Ásj‹G½%Ú¹™‚⋱‚†ótRSRHCö)gœ€víRK†æ¦ì·È˜Ê‰#/0ã§-™÷2cºþo£PDS{n)¥®åÙÞZƸK‘Þ¸k©ô¸–—à!ôÒ`6ùáw/hæÌŒGê]!¯Ú瘙Ií.À±œöÆ6AÈ¿x_Né‚!›Þq; þ°þH®­HD™¹§F*·;2“è×À “¿òyg©‰±!ê"^¸«gŸUݾÌõt48Y©/#/Ðý‡´HÆ"“L(òpDèE‘‚2%tù§`˜†Y‡¼ß{OGºÔwËRÃ*ãmTXÏêúçÖët©²å\T*#,›˜;Š5ÚkíÈ7–9”O.¢|ÂÀø`J¡Ù•[Y Ã¬Ã"ÜÎóh˜…²FbÁ"©TûY‚@ÀhZ¨ÑžæƒSé~'éãÅc«5nZUI'(i¶(°¦0%$Ù«âoƒ}Ì6À—r¾âçöåQB TÜ@´C!Uþ5A”ª¦t ÊKQ¶˜—VÅ×[ ÖOW4mðæ·_n›kžWbW¯®[kÇ5sh£xÜÖï;ZÅɵ!Ín•k`[%²BØ  KVØ#/ép¦Ýýæ·^ud®îå5\¯WÂ’,b#Hƒ¼aN@ð{4TÂØ8¦"|@º\GØ™ûƒÐb·²4c@IŠ¢å#,GÄŠÚ Ò#,z@÷?Ë€âEK´±ƒ»»omWÇ$ñ4§ƒ¾P¯Î!ÌSÎ)JÐ#—å?q @>úà…%Xù)Ô‰‚n"ÈUElïµ”×%­Ù¥®ãm×w#5ì¶tXîï.áB¶—T€§‚%€ÄÑ„pZÅj-¶´–¶íj&Úº„Y$#5j¤K6V#5˜vÉÄÂØ‘DNDQƒ$VHATˆ} #,Í#,t”¯ý¥Põ*†¿š£¥'U÷ÕOF¾áãA°GÞB&Çq–º¾ —ˆ#5©˜½¸³Àô¨!ÜzM‰X=ˆ`¿YÌÅéô”H'J^‡·`dÅï‚„:>B¹bEc„dR@²l¥14Øщ¡³-3DÊJI‰±´2¶ÑV¶Å¶ÅV›J¦U*Å©­cXÚf¢Í^hû‡Ÿik’2µ™¶@ Ð91‚•È‘>ü)pM#/1¨<¡–‘²1HEéd%T°5˜«ÊAh GGŒXÝ"˜W#5)`#/ƒeldE‘¡È1’T:„¨UFÁ‚44D"22*T ­Œ#,„•æfi–L"Ä'Ïõåkª&ô%¡ŠY¥¥Ý;7 ëO®׽^ùPD AF• B c#5FÖ‡h.*W N0é°^ËÅ6¦´“ÝshhyöKkÎ#/«EU)¥^ }#,1 ’´6ÃÃÛ±”!77´qÊà)…2u—ðm:;9øtM­`,Å#5ÎY!‹VF@A1ÄÞ©µ-Ö$<8k”bHµ›†µ’Âe.#,óm“Æááçç$¿Fb‰{¤£Žõç—]5ÕæÒåLÌßrý•ßÛ•F­¨ÛU\Õ\Ö»½¦©+ãkÝìÕÕààØç÷AÊ.qþY ”D³Úû°¹bVUÒã6±dš¤X|?f¸èmŽ8ÖAŒâ凔´}cï€r×BüÎÜâ'óÄË͸=÷PnÝO12R_áë'¸¯òvÛ¸‘´ÖâËϯ¿¶o.‘”‘ ï×eu¨={¬çpïÍl’×iõÜ“ÅÆ;ç:Ý7OKt Œk/ÑÂ)áÎ…-™Š—ÛÉ[ž/}‘äEð„/,L'ü©r‡B¤òŒ‹ôèþ©ºó’9·å]¸tMÐߊkåGW¨tYAÑ3Ï[”5ÑlJèÚ‡ÜEúy»F]Î×!Ý»®éŸÂ%#,âÅÃWN-¿b2 ÖtóßtU°uĶCŒ¯LÕK7ZXn®?“êv¹#,:°éÙN-Q“6ç¶<”h•Ò䮚ž¥°Ïå0¼‡99{ÃV48ŽŽÙ=4å²γÑ|=ÍÍvLç”ù·:8D§Èãwwj%™ ]N•æøkµŒa‚Ñnt{òƒu^9{’×F娄ǟ¥IÔ?9 ~\³½¶Í•Dã숭lÃ>7éŽÌʲéßá*ÔpDÝ5¿]NuD¤¨€ßTSLœEHˆE’æêßmyžú,[¯·ýxvvb–)ªÞWƒÕÛbOãdéb€ºL(«D”Ž—2ùÿS°wÈ´;¿®K×Oy7ËcÒ›c¢P4áÑ*“m…™¨W•Ï’’”ÇÊq[Û¾kÚwy@ûcoÍÑñð{ÃTã¢Ó<#1܇Ä÷Q'wbâü@ë¾½ìâ±ÊŽ¦u~HŠŠÉR×Þù*W˜çO•vé5Ó>ü¤#”F#5wÁTÀá öª'¤ÇRNÐú³†ºÐìÌ rldã5·îù<…ŽeÍëS’]žú=ÃñôÂ3«¦gÂH:&f#|8ßJÙjZœÊJÉÏËÇv0„! ³uŽ‹Šxéǘ!ÝÑÌ®ZœÕQ…sãšQ!Ô8s’„;È+Äu5LÆldR-ߧXRpËf‘(%¸t&!Hìj@"¢ˆÌkè/Nâ~’Ó#núž‰±gëFpðægž&˜Ý»áAÄÈéÐrúçü¾Õ´Ïq©6ºð?qä—™%bLn8ƒY|)®Ø¨ñ¬D¡ÙºøvKxdÍB—3¦zÛàMæ,4C^æ£ÜR£oä~‘¬—2_&O”O¼û˜¬àsÎÁÐç©7ï}ðkÄcŠvòÓ—#³ùônš8ü­øщH…Ë»<|:Ѫí`ƒ¬ºê‡ïD[¿e1›Ú\š»÷Æʤӱﳷ Üì.u«#ÑŸ^$àU†|£3ŸH%LôG›È´­$‰PúžÔªï¢sÇ,¤Ñlu;tm_8Ûð'äésâ]«1Çú`Ü©G„Aï‡#5ë?­å#­ðv(+t>Tú=õ®¾½<ö Aïäx @€2#5Õ‡¦æ¦&Gcª'!c–#/·Xäe“j•¦#/»•*Ô•©ò<óXœªG­_qû”4b8ì;z‹=AÀ~xHôj „qDÃ1#/*Î’v6˜±)‘){¬o¡xÑÇlè4gwò `¨äsÑ—ÅÏ•8Õ…•LbYˆØ-Á\/ILIUãœ)–Íd›mÀ9ÃmRº½Ã”(•‚YãJ^X*'¯$ÂõtÖþx“%S4!2Bð2Їs½le!ÒŠš #+‡—`“3‰—…ÚÊÂ\ºê!l2  ñ9’F£w»PW ¨ÞdÐÏa!HØ6Žã}i*ÔìÍ®“,Ìj]Š¹vmH+‘´¨óËnûd¥lrË-–¼œEŠ¡¹g2PÅj] Aò™–t#, )zè)É(— #5ˆF#,B(D[ðÄÑdÛ«…vmìdz²ÓÄ€îÐèRÏF‘,¨NHéÄÃ-òIÓ ®·@#/Ð3@Ë(ÈOœÔuç öÐÎ>± 9A%A‡š\=ZïëÅ?š•|4G°ª(="…LˆŽÈ»CÏ=Gš/¿ôK¾Ãßž<‡>7p%RÞh¥CÙL²s;Iî‡û‡H)Y.$gá„FÛ\ám°ØÌ>òùÓœ>O룦z“Ò»¢ãÕP{ƒ÷ó´‡M9ëµÉjj?Þ/£#/Û¿·k­¬„7U¨òƒ¹òwF‘®û³e1¶ˆÃw¿1¥6 X'#,Ä öJÇÄ·–Ûu¥¤kL9w*ûGnô |Pz iló0;®8~k¸óé¿F‹„ds$.j¦¸–S½£$2*!‘„’×S’Ú–3o`b‰#4@öæR÷àƒ ý8Dæ‚šyvvã˜b;8=qÀIzÓ¾.TéhünøÉÖáÆA¨Ò¦¼µØÖØq<3Gá¥:¸†ÀùŒ‘éÓM^áO•õÙK»p| 9#/š5ÞUš˜¡ª æË#5ïh*ÆN5²Qu}X5EG’ma¼°áÂÙeœ"5#/ƒ‹â¾—PAÍþüÆ8ýNœµ)é FT³†o—AÓ§\pµ Sh%¨ÔVÕ*ÉRXs›)ºÖfÌVjró¼ÊŒÌ•ÙË|¼ðL’vïlÇÉÀ´*C‚üô_ÊÇm PýX ¨ñÈ=À;ֈ缹e!M,à-²7‡R3±Áíu²œó3Îe²¸‡žy@ó((̈Æg„Py {»–ʤj®¡PÐׂ%öà˜Ì:f,øÒ­&CcÑ®d¥”Ò†#/¶…&„BÂ\ØH©½Ö–²›N,a$ß¾Mnô!Ìà:§ ØŒ ;$7„Ãj¬‘0çËì~€è®ÚòÔjxïédj†l#/~¿¯T~?"úµ¬%š—ò>œä=ÆòLo2±5!£À*€”‚}î·‰“¥D*Òs¬ðf…Ò³½1±fs“W‡D<=Áî^ÒØÈ÷¥£HQU:@ÐZX°æCV‹FѱD»¬ëw*I0 65'mû_±okV-ç–ºÕC0x5EÐØÑ¡Æ”£tZJ²F08ä àD¦@«fÞ­QA¬kšâsmͨõvíœiêGy£YUSq"T'†+·AêB¸`daL‹šbBÌQVd²ÕŒ{†±&0dUC¥›ÌwÓ6Î=>rFža†ßFv¶´O9×"}ª(ÙZ]›`Ú@ÚUÆ#¡DÐj¥†#2Yj2ZÝL3^‡võEÞ““')Œc !b3ä+•„nãËÃxºÍKÌÊ#c7ƒ´lÜA£A¶lȱÖ6¹¬5©Ñ™¼I¹s{)FÛmbm¥jZ#/µH›j¼0‹$ÍË_¦÷u®Œ½ÉÄ*qÔŠwœ#5Fu(3»ãƈŒ)a)ÓpM,(PÊ ©ÓcåƒfHÃSKÅ2¤Ô1wÌ¢ˆxpk3Žâ †iYŽ.Ílo! —R¤Æ±¶–ˆ@Óê+\ФIÛR¶Â7vÕÛmá¦oĨ#/)Âl¤‡æÂ41‰ïlñBMÐÑ¡ƒ[:JÓ6Ôj©je*Š¢…Xa†ñ“LV1·š‹.„ËÛ—KG]ÈŒ3…Ek©Š´š˜:¶†›¤†@aú°wmݳ hq²iƒ2òÈ ¶ûiæqõ<âñ˵aQÓèÃÙ”~n¡£UJ5™b´à£„Bc9GpáF2›¦ Q½åƒUƒ#cDÇF2#/BØR…hl;™1F%Ž´c4-]Fi¶pÂyë+`æ­z¥W¦dpìT¤ŠçaÌá“#jP˲ÆÔ£„rªÛ°ê ƒÐÖ?„… ­GÒ¦fn*£âjˆ‘ˆR-yZ«Œzp§m¥W—”\8@s¹eÇ-:1ês[u¡ñ­½,-™J`qšu6¾i¶Œ.òaZ³ JF™áÜ$go$®Öi‘Ôàè-2“FHÄFK3º*ÁÁ…ÓŒ»!^ž5¤E¤ŸIPÁQ®úµo´#/:Žp0ãG 0%2ÈÛ¾ÂlDqJs;¤*õÇŽ§åó„}+?_èX~×;ˆÒh©4n>õæóξw·¶zê_Ð×ÒŒ3+Ѧ#,B6i±J>°X"B“´*Q)#5UHkø¥2Iâû=µ(Òe!ߧeS¾¬gy­[€i T¦2Û³÷œŠ $UUFJ2ßê*{ÑŸñ/PèEÏó+ÚIŸCªšc‰jó=¾¸CÉûÀþ^°æ‹ëA"qm!–·JÍÈÍPƒ€ñÂ@A²ûµï¿JÙ&a28÷bÍ„Ú[Ýøš§Õ„zÞlº… uq–ÐúðöîF›ºNîäÈ!ݽx÷õ5¼i]tjaQp%-T¨Á³È3=‹g›ÝÆuë2‡^Ð÷¢? ;Q<ÍùT¡“ŒHQˆ á6o-ÕA#ôÏË9ž½Â(Vk{–±´à‘À]‰LÎÈ€ôRƒQ‘a#,X°Aˆ¯)¶¹µ«¦ñ­kË«¶¹¥R«ÍpÝüSòEæE?Aß×ß(Ò}ü$$ŒcPÙQ²’¶Ñ­(ÔF$ØQRRa¶¦VË2j’Ù¦ÅZÆÍ)*‰-&6fdÉ¥–Å)HÊZiR”fJˆ¡Šm¢l”li²Rš,Ô©¥h5"É› 0Œš2[V1­­üëßÒ¿%Þ‰‚ ñÀö¼«hâ/¶%¸PyòŒå¸ûæåteÌÄóÜýOÐ×ó°›ü\÷Õêî¶Ï\ÚD‡ÆsVÑ|’aAdƒpp½ïj–«U¬ZÊ#/5ÂþGŸ§Ç4AóÙÔo³Dó.F#5ä´v‚~Y»zOg†ƒƒM#55n’öÄ 5/öî„ð )"‚‹¬kI­}æÕ®[1¬)4H)-A›_r]¡j•BÅ#5PÅFR>´²eÏ€`'qxå!BŒ*O·Û˜\3W@Ëd}ö^¿°¸j@j" þ˜QjxoCŸŽ]+L"k¦VºŠŒ èËRûŽQÌE4\#/4‹¡w›¢eÙ“$ÂXÃ#,4Ž±w$Âl&‡…1H ªÏmM–ê”$ÅP* ÖXj%í%†¥ñÝ›&õÙcßÍÕõÍz“zÑmF:š¢¬´ò½¥*KHÆ‘#55Q’¥Ñ#5E#,ï8ã'áí5§æá ÙòÅ6FK^΃ҺâP{7¿g_©y»Þ-FÞ­»"’bTi²ƒYDqbÊÿÙÒÈlÐ.g›.j˜R´4•/ ¦d£$1A€`½Qˆ<,1‚:5$m|Ú¬ 8tˆDn`*LCq-ä "I$‘ÁPÙ·‡dœÐʨg˜b¥(¡˜HѨ€7$Ç¡æi;¼ÄMó­#/é\W‡_78ÏÚ•×(,ú/dî"B_òá6ø0 hú½*s¬añ²‰ª£-n]MµA}êÂRЗ0 úT%Ý|È#,ñ‚¿ ¡p˜{ ÄW(4ôçèþ·Œªôn%Ô¢•[«xc%Ö~~>O–ºèjIÛ:ãØ?‘ëSQž‹ñ*ûó)¤ÒÂ:#Êse·ö˜#Ø8…ïúèbáöôaç¦~ÉäX2ŸaÌÈWJñÆÓ­Œz™TZ™ÎÚäÉ64.Œ#51B}©%÷s]kÉ^vœƒ-¾ßaî°i«Ð=v²¾´äœ­r4ié>4"’§< f׸‘©"ø5,:ã»;í˶LÏgÕ&åØ›>f;}J`8§²$DW‘ë5êOñšØ§¦#/‡÷œËEŽç`VŽ@)2g³š Ú611ÿ}XwÄh7!€ì#QýÿTÄ7vuI¨™3>Þ_b7Olbwr>^þ‘BIDI(€Š%çìBöÕ(´jtû´íƒ }'‘n,,)Ÿ¿.¾¯ÏD~ìèGëì~Ç­n~MLáØÎôFB«¦‹ PÆ,+rc¹`Ã6'^ž]hlÅ0ÔU÷¡ƒÑËqQ$îö¡š©*}_m[îÃx`¾fo\e#/1IqˆoÁÚkö‰¼¤þB%„Ž¹°ÙW*Y5ÔX6Gîg|¢ƒ]82¿’Ü1´„–‘™Ÿèw»Þ:*DôyG7p‘l¹ 9R%T:­+ŠŽ\~q5Œæg”à§FÔ²4Ã0ÖÚbj„‚"Bl3Æ 2&#,¤LífÚŸÔZV’ÐÈúˆ¨ª) Ìú—l!Ã4ÈvWº«²™º"¨ih±bE `BFÈ„TIx6;8ØÓâ„Gx£½¡Èk™¡¤’9É¢K7PeÌÓ=™Ø#,˳RƘÈ­h¦RĹ”6ºsÐÙLv‘ƒª³”¬A‡8¦Më¥×'“&èy¶ ÃD…ˆ³Z(`€nQ©ê?i˜` `‚PÈÄ̃Þ"¸7§VŽ¨hͤ•B[ÊBÒ£SÈ4,U±M‚FÌÝîãø¥‘Y-…mÃs=rkš†™Ü±Qš ²dãg[YšÔE`؈‚Ù™ƒNcQ¨œWõúù¾¹Þ ûëgC‹èý #àSAcÕ›f&3ÖF|N.š°cðœ(F®u0ù„õ\ô€Ç;9ç5`Ž¯…í.†êiа;eÛCÀûï&:V3+»ä:ô)˜–t[½C‚;Î’Š[„.êö†5¦9Î'½‡<³‚XÐŽ8-TÑGˆ’Iº›AÊ… °4IAŠ’³#5Ð(„4Ãà˜o³Â^+Þž£ÈFÝøf´kq’Ç—á“SîÃJj—9½Ú›Ê㶠cïLé”hG“×2©á¤AkHÌŽqlcŒ°—Ó`CF”„8íîŠã ÎöêØDI"ÒÆL¨¬2‹™C4 xv´ÚMBÔrç4è…"•j‰D°Î²Òb|ErEbÝc,n#/3AÃkPÁ- A èw ƒ¦¶FH¨åJKy|2”˜LÕÙSÙÚâs\Iu`B2 ëÆÛ#/H³%@òÚ™Þju ©æ>Ír+R–fCÂÐe¶2g=×Ü×mtyBçC‘±Öi ¡f°E2Ç#,Ò7 ƒ@毧̇jXH8ºÎ.Q0tWF;bÑtç±Ócir8ŽMÒ(e#?ê‡h0._Òƒ Ì–‰Ó57“HaÊ< $t3 Sl†tÓi#,s´“Uˆ²P¢& mð±N5:þ[VÆ-ÎPd+‚¶’к0psW)„‡.˜(êã–Kiä¶ 5˜šf…PŒ`dYˆc0’“™Øïú×;ËÓð1 ¸ë\‡Zg;‰Ø0SC#,šÊ©&;XÒ){(zžpÛhK“bK¶èä&º†2Žƒö_ø6˜¶ÎS9’Ô`ôÊŒ¯ƒòö“wLôöx€51X0“Í“¹š£~G36‹ xÑ4õë~F´(ã›ky%\»}ˆGGѼ³Ñ_ k§Žp9kI©X«Ob\8W˜¬L°ˆ3‡f²á G”› ¥£íéxıu»Ú“¶¸ò• #5ÒtÚš–b¿o[£¦ À"l]D¥!Á˜¡*£ó~í¥¥÷ ƹȴš·¿¼7½NP¡Ù¨‚Ê]<ä¹nî7ƒ»åZ íû‚ï¨ò žzbŠd׎(ÍÙ1Ä0ã2ölUñ7’¼–¹¤å£^·*éÁX)ðžäŽtÂfªH›¦ -¬¸1laù¦‡@Íå1¯GYÛv"öÉ,˜;ç„ÎCÉœÉÕZÒ¾Rê41ë~¦XŸŸ•ôÎ0ÑÈ*ÐÆ»ùœ‚#FÎf;&Úlðæd#/ø´3J±v2›§œ¶/5Ê·æF*VøDtCH>4š[ï ’u,w1Œ`¢ÑÌËá¥GBmðX¿cõy­ÓŒÞ0fßE4Q«HˆPÈz!‹ªhEçAFH"¸ªPÝÖMO6÷ÜÉÂÄ;½S¤]Áõë- 2m)\g†`uns…˜®EÌv#DÌ" 3µœúQ4ºÙ"6#/KÀ2ÁÐÃDb¬HªŒbj0¦Iz©#/ÎUñO/wÉHRöYu,««DëJb(‘ÙÅ®ÿ#,Ì1aª"/eHÚ‚žhïCÀø3bi˜RœÊ»ƒÀ CiÁ¨Q Á’pìŒÆá Äaƒ¨bb_BÖŠ*EsI`dl!‚LZÐ6؈‰ ìªXò¨¦&Ý„—²z½}'Ñu”¹F TTEA³GnP]f^®¹=£`Ë*„;E„HH)¨ 5#,æE~íÿÜ[ײöUAÖs—¯}Ø* &ɸ‰U$_°. Äh”"%Q Èvøž@PÈO.Mæ31<Â+"Æ’©bP2Á8âd‚TLc`Ç4kÄÕçxKÍÝbT®[ÞëA±ä! d… È𢢌A¨5%TABJ‹J :éˆã#, >l|si(A¤:ënKßwL¹C®’dˆdÐØ&`¬R, „Nˆ{úÓ³´|û¼B|&>~šíFù ½pà‡ˆ)òáõ´Æ~嚈•Î†Ÿ×3¹FŒPp ‰R‘Ks1ŒµVDD Ð9†Y~И]ÄcaS&¾¨™Jëä%„õuØ'CŸAMìM€ð iÉîŽã¡L’xØÃ)âA!ÜH‹Žû"ÌCÉ©ä±Í#,…0¿‡B°ˆX¥ àïÙϲ؂l‚H„€†a>’6LNpNþ=AÓU7ö#5‡h‚˜|>#, t"qvõl"HÐjá†Tvè®#5dÜ:cD“A‘„\r,É#/ör}°áM‹BÏÌ~eŠ0„a#¥¹#ÏK5 Nè"‚i¢1XY«:ÔEŠñd<¹饤CM"ò£¿!Ý,FÙ‡†a­4¦…ªÂšØ}C¹Ï;PÚC-¶`¯³k9NPïÃ+Zë-sŸ‘‘ƒNÉ ; Ô÷gÛl¨í­õÛ”I°6“jÀ*á,YpèhYhý[¾¸©¼ïðQãU#,E€§¹% 6Ø¢j2‹•1pA-šý–a]Z³š‹06ˆpM Nÿ¬NJJ†RS,Ûs#,Þ&àŠN|P¤¡#,ë:Ûv¬®¾`R)eZ·Ò —Aý‚«! Ó.¾™Âþd|yõl C7Y0Ó®e‰ÖpLCÍ8äP$ E`AAÀU€®ç²=|°Mß#ÆƉòõª×aÈáÐ-@ª!RÈ.B¨6#,R¼„j#5~'»èý½ø$Àce„Yˆž>ߣáQ¼æÅœ+4¢SøÑÈtx×_¢ŠRÉk ‚ß…Ãð?ɨ|>>ïo*ÌŒ>k,"˜ö{M þ3Ah„'ÿÕ·Ä–ŽoN憨m·4kÊ«@(í#,¥$HßÝE‡*oßû©hÚä¾’¿ª ÝZDúbl *|ûÇd,)À_ï€vX.Øbvòر-¸$HÈLÈÅç\¬VaI)"îåŠûžtÞh5xñ^5û’çž^o+Ï|ñM¦«´E°ÙT"6¯uÛ¨à &³KQD™ Q底6Ó6†˜@J” *pþ$Šl¢›OùÊ_w›¼½y$†@!» ¼9›Æ@eÖD«M"¦!ë5ùßHö#,õö‡ok"È,€ÁH1FItIÜ‚Œ‚HKJ“$–*eh²YfKf’m_õãc}ÍWòõô)TC™Qª4še,Òîü°IüOÈEP¨‰Ÿ²–»|Æf7Ò@,)ºî¦I#,àOØc_T½´Ý×6bldÔM¬ÚŠ*Åe¦FÒ{çžjˆ@B {(#,´D"ïŸóD-ÍA5ÿ‡‰˜uw“âú¾¸Á×Iâ¯A5ÕÁ¾Cxtœþ{ŠÊÄ "ñ½WDLp1 ÷¢ž$‹Á¥ÇŠ3˜)–S T‘²Â½´`ÏžfÆð)B°ÆÄ%—óéA¸{ù›iq¢à2 Fû˜ã†1Øž¥MÂÀËCÚXS¢yL@A|Á€A¤Ím6´”„$µÍÉ­R­)6¦Útï–¦‚ Š)sVÛ7“Tì"®J€Ø=Z”`J¦H(HöÚÃe·XOn’ãK¸Ý¨ÕZ¦µÂ} @xÉàRŽ˜ô<ýT-ÙÉiHØœý4#âì:ÆØ£"H›hx’öBVÜÛl Lµ‰Ž„À?,·ïgÍóºÒå†.[6oYhD x˜`næçü¥¿©¶ÕÕúº¾¹}¾:(52&‰RE‘¬SEŠ)(*"Ú2UB•È­úm¯5#5- ÚJ€¦§á•³ñQ –|dK,'Ü2n„ŒD*–QE1cG¢Šh™ññ5± *…¡·`'¥ïŸ\p]»% n»š ´È‚…dCDZ‚´¡¬P›i²ƒ!ƒ$`'‰µòíÌÛæÎíí¥VXjc·Õ¾>øÁW6¾¿9Ž>¢ZØ–0l³(CÝÚmwû š_©ý~C´+CaXe²œÚã-‚#"T²44x d`;ý´:`&ÍlkrÜ’•}}«•¼»¨’Ú*+|®ëÎ˱\ÚZõ©ç[[Æ£E¥™ªÏrGë6³#¸Qý¥d8$-#,Ì,&íOQÏ¢I¨u#œˆr"ĺ3Çü3AZM±¦¬M ( pÈõhX}tfò]JCñ`aÀP®%Li¾pCq5‚u‚]¶ÅaÕ%A‘B0Xs¢k”´nåÕã^o*ëIbÝš™™UÜí´Ò¦Ô¡¯{µÎV+*TÔQ±­çvךû+½¡A#,¦Ac)H&5„h`ÆÈÚ[R•¥4ËfZé·nè”Ò ‚ˆNE¡RDBNεm!‰°éžXK„=¢ºÿÛ—òà«‚Yƒg±¯¤Uòf┘4Ñ8/Ž1†aU3ç qyjI²ë²©Ùíîù"Ö/PXL*&†©J8»÷zÞìñ0lèÑcMû=#/fü…º³ìÛÕB(£Š‡"­yšëÚ%ôÉ!ô^ˆKž‰ BA¢"˜5‰#/ðè:8$ÉQ;’ý 6’_éc MæÿÀZ׎§_¬•¥Çk“Û|å†ýi‹in‘Û¦Jµ ª-ä~?Prg´š¼<ûh_cBQ‘ƒQºô0m­Têð#/(PD>›r8”š_™­ê`×L‹ãõ9ô`¢ÀŸ~úÙ¤q<–ó€’Ešôbä¡HXÜáÛ(Mˉ‚„KÆV#5vÂ9¡4k%Pm¬ýLzŒlŒ¶Œ"À×F\¢é¿HbqK÷M|§hͤ†ÉpdLT“‘=Ic0äd¸(ŒR„¥ €CJâ'#Ãg¥1üÙå—÷#ö^3À!Ç<ª„¤2îz?2P?ø>³Ê¿DÉB6 ʇr³¯y±cÞÀÉï;ݦ"ó¥jIb8h™#ߎ'\¥„Ç:-¥i#,¾e#CûaU°þ¦ŠùŠ¶Ý¿hzž­:µ9´ â(dÿj‡©†È˜2*&½5趙®õmÑ߶…ÆÆF Ú[âôv3óŒõÞäB4Db†'RÖèmI€*™‚ØB#˜BC¡â”_óÄÈé†`– ¯N—À±¤ˆçç"RÚº#,“m2hæaŒ‡/b"fg;Q‰¬ãÛ¬˜‚ö ¬;h-Oî5z¼ìw™hiìºâˆ¤ýØA´ ¨cñ¯Ž+qÎz)\ X¡7 uâÆtù–‚ åþ%)`aá<‘êz¢¾*~LÌÁù]ü7¼žÜ4Ò÷̺‹DSo·\-baúâ.èg_îþ_áò~øÿ»ýÿîÿ»þͶ¿þ^Ïû7¿ÿ‡þ¼?ãþ_÷}ÿþ¹~ÿü<¿ŸüÿúßÿWûçÿ<ßønëÿ—§ðéŸþ?ùYýÿ÷ÿûÿ‡§þ{>ð³þ_ñïÿ‡øËÿχåÍÿøÿËþîÿ¯Ü~O÷þÿ¿7ßùéñ87ÝõõvŸù]†‡ô‡õ«b"jy6Å5M…\?Ð9ßJ<˜«î°B U!œpEÝ!#ZûW‘nóøwïi|§ñyÎî™$Š¢1Œy„ô2IRC²Šl`†éÝG¹¯(Ay4Ú!®z©¨§#,˜6Ç3ø]þꥂƒÜ?îßžÔÓi˜\Ùp–êx†ëqFï„_÷TK´,ã5(„æ)A@µ|nÌ&8ãt§00ÀQa×úèS<šßSÌÿxÿ/ûÞÒÊ?÷yšz6¦ÌÖÐèQþmIŒ‰ôŠ‚Å ºI'ˆÈeŒÌ ¯I?ôÍ@œIÀÜq¿ ÿ•ieqÖ&!3"…2*×r­göòì {­0ªB Ü”Ï&QFišÈ4).¨±ƒ—Y/$³ýùã’ìç1UjUø¦‘2ðÍD)(»p®ýq¡X0š+šANL1#/(=í8C(hškT˜mѤÝEpq1›ˆŒZæá–°ÛÖÓF˜›H†CÄ#/ÿeÉV×#/(k†â¯ÙæIJƒˆ”iåÅÓ%KK¦#/¡²°(R°™ÍŽÆo®'?ì&#/ôçÌö~¨]1ì¾3.ÊbVæ.Èœ¼Óò™àƲÌÌ5¡‘Þø(ÛÚ¿¤—^Íár#%µíÒsVoîÀUÓØÃy…I9óovÿy–#Ûî h1‡¢ #eëÛ³¶5c+KMoÎÃX`­±Œ9¤ž$½CÛ#/V¡¶çB¡<)aó¯´×»á¸ F¼6 ».ˆ¥ÔÏ×·*•ØŘ/S8òÒ`y±3DEa éŠHÎûs#1ïÎËXÍ¡&Hc|·E!Š†Q‹{ňPÑ~––2© E$€¨šy‘¨§J'\3Z€#,À’1-î ü ‰bfi¾ØX(/Õa狸1ågi±ZÒ#‘»#Rý^¼<À¦S ‚ˆ‹ ËJ%B…ATZ²”ʶJÒkL”²C`ÆÊú]ªå#,2Ê€qS#,™?Þ@2ˆÈÁ?ß&<*›(«yÁ-‹'3Ù( %ÂT@¥b(yóúCèïGU¤?ê‘Œ‰ yNð`ò54±Í%2gúF„c!t§“ì#5„Âdx‡‰útttþó‰,¤TG3‡ êú¥#5%±œsøâÓoæ0Ï{BŸûdk»:uNô§VÇë*K~¯xÆ=%ȼ©¾=Í©ò°ööpcõ•]*Se`nL2\aÓs.® #^áÆÙ²Ñ>Ê,7Ÿt›Qyä>–*m4ØšÙîá=(Ýá{.eoÆD'4Š°‡TCVzI”D%%Ý€-W­nm¥•´¥ëk^·ÂÕ}Ëã­IQTZ“D³hŒÆ#/1(мf±Ó¬"5Ýa+O(~^“ÒõÃñ¢ K‡?ìÄø KÔiµ @r19Nac#56œìÁäK–*%*¸”øóèI}0í$&PšÕk##=”´î#5'¯òŸe»".hp ÒH²!!7’æE Ðö‡qFO$v£“íà'‡ŒÿØ ¸zäj*„bECkµÇf•„”ÕË›­«%jF¸jûr¼Ûo%Wؽh›53_•ZüÈ£h€#,ˆäw·Ïá™åóÿ×Ö‚w!=~¨©ãå(ø{f8ò0m¶ÖŸŒx;.‰x§ª#/gȤòû?ñÿ¡EB§ýZþvÌÌ#/l‚Å'ù< Ué6áæçûÔU'ý]¿Å¨£Sõ#/ J®ýá—Ò>ý{pæWi.ò#/¹ÿÜZXßæ§wú¿ì†¯SüþÓúùµµ™ù#¥l³·¢1¡¨zeë¢×Ç¥vñ‰’©œ~®yËAƒSù>¶ÉÓ¶ˆÄÆVJsøzK„pYkϼ#Dâ¢ZÍÆ! ^G¿§,ÀŠÃ$ Œ}ûYOÎÏužº6³8•È'ÇõçÙL*Ï«Ï£o3¸žÍ~ŸWüÕ‘àRsŒâ;Ó¹j¬b/È5Y_ç²V7Ä|¤É{~¯ÿþ.äŠp¡ Ú‹ê– +#<== +#-----BEGIN PGP SIGNATURE-----\nVersion: GnuPG v2\n\niQIcBAABCgAGBQJWpU3oAAoJEGelZe39+Q5kv04P/iyvALGAg2Z8oICEDjFkEXWW\nh2CMGLItAhqb3xNeV8WUMMpY4MbRRpN6cU/SPmt+as4oVn2pozca93eWD7yOxukK\n10seOyLTBamS0Wf+BNr6jYXZRQ2N7inc2p6AD75pMOFSg2HeIeQJ0aUIAxNeeojZ\nmUiLYMdtcrF1Kh7KWZAkYSbIAEjJeobLqk2oY7UyqKcODc4RtZJV1InnO4DItEWD\nnd3F5kkVMw4pwYAXaikmCXYBKHXdF5w82KxqEjrAWSoULipX0BVCsSbQ2L0UOs5h\nKXUS4M7AaYKyCcO17E7CnVXaW+vOVyGEECxtSaExWgK5MvYHIGE1OFvb12PkUvUY\nc7CiBxk6X5eZkPyxgxDj20r8zNQVGZ8jDI8Wg08yTAl8+09qCtkE8gGMdNeHYwX8\n2xDH+A3+19022ZZdyO2t5+2AzU6Kkl1qTPKaXJWFRtr8ApD45Y4D3/GAsTNqdOMi\nWeh1XvqQdHjm9rEoJX8aBXShzCMCNhmZalbUhrdzQY6/hnl0PqnlPtyvtkjCvWoF\nXLF6q8YV/ZtqCc36vePZ6lpUQB6FG3g6fhMGraT2VOmT3TROcG17pqIz5y9+85xy\nVSaDc82uHlyzIsZ7vuhV6d9x4yXnFkjMAogCJv6mitFbQsd+LtXYkU+2Zq6wOoEp\ndLLfK0Km4Vs9FYAUbuUi\n=7D7V\n-----END PGP SIGNATURE-----\n diff --git a/gomspace/libgscsp/lib/libcsp/wscript b/gomspace/libgscsp/lib/libcsp/wscript new file mode 100644 index 00000000..7b9cbdba --- /dev/null +++ b/gomspace/libgscsp/lib/libcsp/wscript @@ -0,0 +1,346 @@ +#!/usr/bin/env python +# encoding: utf-8 + +# Cubesat Space Protocol - A small network-layer protocol designed for Cubesats +# Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) +# Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import os + +APPNAME = 'libcsp' +VERSION = '1.5' + +top = '.' +out = 'build' + +def options(ctx): + # Load GCC options + ctx.load('gcc') + + ctx.add_option('--toolchain', default=None, help='Set toolchain prefix') + + # Set libcsp options + gr = ctx.add_option_group('libcsp options') + gr.add_option('--includes', default='', help='Add additional include paths. Separate with comma') + gr.add_option('--install-csp', action='store_true', help='Installs CSP headers and lib') + + gr.add_option('--disable-output', action='store_true', help='Disable CSP output') + gr.add_option('--disable-stlib', action='store_true', help='Build objects only') + gr.add_option('--enable-rdp', action='store_true', help='Enable RDP support') + gr.add_option('--enable-qos', action='store_true', help='Enable Quality of Service support') + gr.add_option('--enable-promisc', action='store_true', help='Enable promiscuous mode support') + gr.add_option('--enable-crc32', action='store_true', help='Enable CRC32 support') + gr.add_option('--enable-hmac', action='store_true', help='Enable HMAC-SHA1 support') + gr.add_option('--enable-xtea', action='store_true', help='Enable XTEA support') + gr.add_option('--enable-bindings', action='store_true', help='Enable Python bindings') + gr.add_option('--enable-python3-bindings', action='store_true', help='Enable Python3 bindings') + gr.add_option('--enable-examples', action='store_true', help='Enable examples') + gr.add_option('--enable-dedup', action='store_true', help='Enable packet deduplicator') + + # Interfaces + gr.add_option('--enable-if-i2c', action='store_true', help='Enable I2C interface') + gr.add_option('--enable-if-kiss', action='store_true', help='Enable KISS/RS.232 interface') + gr.add_option('--enable-if-can', action='store_true', help='Enable CAN interface') + gr.add_option('--enable-if-zmqhub', action='store_true', help='Enable ZMQHUB interface') + + # Drivers + gr.add_option('--enable-can-socketcan', action='store_true', help='Enable Linux socketcan driver') + gr.add_option('--with-driver-usart', default=None, metavar='DRIVER', help='Build USART driver. [windows, linux, None]') + + # OS + gr.add_option('--with-os', metavar='OS', default='posix', help='Set operating system. Must be either \'posix\', \'macosx\', \'windows\' or \'freertos\'') + gr.add_option('--enable-init-shutdown', action='store_true', help='Use init system commands for shutdown/reboot') + + # Options + gr.add_option('--with-rdp-max-window', metavar='SIZE', type=int, default=20, help='Set maximum window size for RDP') + gr.add_option('--with-max-bind-port', metavar='PORT', type=int, default=31, help='Set maximum bindable port') + gr.add_option('--with-max-connections', metavar='COUNT', type=int, default=10, help='Set maximum number of concurrent connections') + gr.add_option('--with-conn-queue-length', metavar='SIZE', type=int, default=100, help='Set maximum number of packets in queue for a connection') + gr.add_option('--with-router-queue-length', metavar='SIZE', type=int, default=10, help='Set maximum number of packets to be queued at the input of the router') + gr.add_option('--with-padding', metavar='BYTES', type=int, default=8, help='Set padding bytes before packet length field') + gr.add_option('--with-loglevel', metavar='LEVEL', default='debug', help='Set minimum compile time log level. Must be one of \'error\', \'warn\', \'info\' or \'debug\'') + gr.add_option('--with-rtable', metavar='TABLE', default='static', help='Set routing table type') + gr.add_option('--with-connection-so', metavar='CSP_SO', type=int, default='0x0000', help='Set outgoing connection socket options, see csp.h for valid values') + gr.add_option('--with-bufalign', metavar='BYTES', type=int, help='Set buffer alignment') + +def configure(ctx): + # Validate OS + if not ctx.options.with_os in ('posix', 'windows', 'freertos', 'macosx'): + ctx.fatal('--with-os must be either \'posix\', \'windows\', \'macosx\' or \'freertos\'') + + # Validate USART drivers + if not ctx.options.with_driver_usart in (None, 'windows', 'linux'): + ctx.fatal('--with-driver-usart must be either \'windows\' or \'linux\'') + + if not ctx.options.with_loglevel in ('error', 'warn', 'info', 'debug'): + ctx.fatal('--with-loglevel must be either \'error\', \'warn\', \'info\' or \'debug\'') + + # Setup and validate toolchain + if (len(ctx.stack_path) <= 1) and ctx.options.toolchain: + ctx.env.CC = ctx.options.toolchain + 'gcc' + ctx.env.AR = ctx.options.toolchain + 'ar' + + ctx.load('gcc') + + # Set git revision define + git_rev = os.popen('git describe --always 2> /dev/null || echo unknown').read().strip() + + # Setup DEFINES + ctx.define('GIT_REV', git_rev) + + # Set build output format + ctx.env.FEATURES = ['c'] + if not ctx.options.disable_stlib: + ctx.env.FEATURES += ['cstlib'] + + # Setup CFLAGS + if (len(ctx.stack_path) <= 1) and (len(ctx.env.CFLAGS) == 0): + ctx.env.prepend_value('CFLAGS', ["-std=gnu99", "-g", "-Os", "-Wall", "-Wextra", "-Wshadow", "-Wcast-align", "-Wwrite-strings", "-Wno-unused-parameter"]) + + # Setup extra includes + ctx.env.append_unique('INCLUDES_CSP', ['include'] + ctx.options.includes.split(',')) + + # Add default files + ctx.env.append_unique('FILES_CSP', ['src/*.c','src/interfaces/csp_if_lo.c','src/transport/csp_udp.c','src/arch/{0}/**/*.c'.format(ctx.options.with_os)]) + + # Store OS as env variable + ctx.env.append_unique('OS', ctx.options.with_os) + + # Libs + if 'posix' in ctx.env.OS: + ctx.env.append_unique('LIBS', ['rt', 'pthread', 'util']) + elif 'macosx' in ctx.env.OS: + ctx.env.append_unique('LIBS', ['pthread']) + + # Check for recursion + if ctx.path == ctx.srcnode: + ctx.options.install_csp = True + + # Windows build flags + if ctx.options.with_os == 'windows': + ctx.env.append_unique('CFLAGS', ['-D_WIN32_WINNT=0x0600']) + + ctx.define_cond('CSP_FREERTOS', ctx.options.with_os == 'freertos') + ctx.define_cond('CSP_POSIX', ctx.options.with_os == 'posix') + ctx.define_cond('CSP_WINDOWS', ctx.options.with_os == 'windows') + ctx.define_cond('CSP_MACOSX', ctx.options.with_os == 'macosx') + + # Add CAN driver + if ctx.options.enable_can_socketcan: + ctx.env.append_unique('FILES_CSP', 'src/drivers/can/can_socketcan.c') + + # Add USART driver + if ctx.options.with_driver_usart != None: + ctx.env.append_unique('FILES_CSP', 'src/drivers/usart/usart_{0}.c'.format(ctx.options.with_driver_usart)) + + # Interfaces + if ctx.options.enable_if_can: + ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_can.c') + ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_can_pbuf.c') + if ctx.options.enable_if_i2c: + ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_i2c.c') + if ctx.options.enable_if_kiss: + ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_kiss.c') + if ctx.options.enable_if_zmqhub: + ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_zmqhub.c') + ctx.check_cfg(package='libzmq', args='--cflags --libs') + ctx.env.append_unique('LIBS', ctx.env.LIB_LIBZMQ) + + # Store configuration options + ctx.env.ENABLE_BINDINGS = ctx.options.enable_bindings + ctx.env.ENABLE_EXAMPLES = ctx.options.enable_examples + + # Check for python development + if ctx.options.enable_bindings: + ctx.env.LIBCSP_PYTHON2 = ctx.check_cfg(package='python2', args='--cflags --libs', atleast_version='2.7', mandatory=False) + if ctx.options.enable_python3_bindings: + ctx.env.LIBCSP_PYTHON3 = ctx.check_cfg(package='python3', args='--cflags --libs', atleast_version='3.5', mandatory=False) + + # Create config file + if not ctx.options.disable_output: + ctx.env.append_unique('FILES_CSP', 'src/csp_debug.c') + else: + ctx.env.append_unique('EXCL_CSP', 'src/csp_debug.c') + + if ctx.options.enable_rdp: + ctx.env.append_unique('FILES_CSP', 'src/transport/csp_rdp.c') + + if ctx.options.enable_crc32: + ctx.env.append_unique('FILES_CSP', 'src/csp_crc32.c') + else: + ctx.env.append_unique('EXCL_CSP', 'src/csp_crc32.c') + + if not ctx.options.enable_dedup: + ctx.env.append_unique('EXCL_CSP', 'src/csp_dedup.c') + + if ctx.options.enable_hmac: + ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_hmac.c') + ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_sha1.c') + + if ctx.options.enable_xtea: + ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_xtea.c') + ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_sha1.c') + + ctx.env.append_unique('FILES_CSP', 'src/rtable/csp_rtable_' + ctx.options.with_rtable + '.c') + + ctx.define_cond('CSP_DEBUG', not ctx.options.disable_output) + ctx.define_cond('CSP_USE_RDP', ctx.options.enable_rdp) + ctx.define_cond('CSP_USE_CRC32', ctx.options.enable_crc32) + ctx.define_cond('CSP_USE_HMAC', ctx.options.enable_hmac) + ctx.define_cond('CSP_USE_XTEA', ctx.options.enable_xtea) + ctx.define_cond('CSP_USE_PROMISC', ctx.options.enable_promisc) + ctx.define_cond('CSP_USE_QOS', ctx.options.enable_qos) + ctx.define_cond('CSP_USE_DEDUP', ctx.options.enable_dedup) + ctx.define_cond('CSP_USE_INIT_SHUTDOWN', ctx.options.enable_init_shutdown) + ctx.define_cond('CSP_USE_CAN', ctx.options.enable_if_can) + ctx.define_cond('CSP_USE_I2C', ctx.options.enable_if_i2c) + ctx.define_cond('CSP_USE_KISS', ctx.options.enable_if_kiss) + ctx.define_cond('CSP_USE_ZMQHUB', ctx.options.enable_if_zmqhub) + ctx.define('CSP_CONN_MAX', ctx.options.with_max_connections) + ctx.define('CSP_CONN_QUEUE_LENGTH', ctx.options.with_conn_queue_length) + ctx.define('CSP_FIFO_INPUT', ctx.options.with_router_queue_length) + ctx.define('CSP_MAX_BIND_PORT', ctx.options.with_max_bind_port) + ctx.define('CSP_RDP_MAX_WINDOW', ctx.options.with_rdp_max_window) + ctx.define('CSP_PADDING_BYTES', ctx.options.with_padding) + ctx.define('CSP_CONNECTION_SO', ctx.options.with_connection_so) + + if ctx.options.with_bufalign != None: + ctx.define('CSP_BUFFER_ALIGN', ctx.options.with_bufalign) + + # Set logging level + ctx.define_cond('CSP_LOG_LEVEL_DEBUG', ctx.options.with_loglevel in ('debug')) + ctx.define_cond('CSP_LOG_LEVEL_INFO', ctx.options.with_loglevel in ('debug', 'info')) + ctx.define_cond('CSP_LOG_LEVEL_WARN', ctx.options.with_loglevel in ('debug', 'info', 'warn')) + ctx.define_cond('CSP_LOG_LEVEL_ERROR', ctx.options.with_loglevel in ('debug', 'info', 'warn', 'error')) + + # Check compiler endianness + endianness = ctx.check_endianness() + ctx.define_cond('CSP_LITTLE_ENDIAN', endianness == 'little') + ctx.define_cond('CSP_BIG_ENDIAN', endianness == 'big') + + # Check for stdbool.h + ctx.check_cc(header_name='stdbool.h', mandatory=False, define_name='CSP_HAVE_STDBOOL_H', type='cstlib') + + # Check for libsocketcan.h + if ctx.options.enable_if_can and ctx.options.enable_can_socketcan: + have_socketcan = ctx.check_cc(lib='socketcan', mandatory=False, define_name='CSP_HAVE_LIBSOCKETCAN') + if have_socketcan: + ctx.env.append_unique('LIBS', ['socketcan']) + + ctx.define('LIBCSP_VERSION', VERSION) + + ctx.write_config_header('include/csp/csp_autoconfig.h') + +def build(ctx): + + # Set install path for header files + install_path = False + if ctx.options.install_csp: + install_path = '${PREFIX}/lib' + ctx.install_files('${PREFIX}/include/csp', ctx.path.ant_glob('include/csp/*.h')) + ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_lo.h') + + if 'src/interfaces/csp_if_can.c' in ctx.env.FILES_CSP: + ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_can.h') + if 'src/interfaces/csp_if_i2c.c' in ctx.env.FILES_CSP: + ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_i2c.h') + if 'src/interfaces/csp_if_kiss.c' in ctx.env.FILES_CSP: + ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_kiss.h') + if 'src/interfaces/csp_if_zmqhub.c' in ctx.env.FILES_CSP: + ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_zmqhub.h') + if 'src/drivers/usart/usart_{0}.c'.format(ctx.options.with_driver_usart) in ctx.env.FILES_CSP: + ctx.install_as('${PREFIX}/include/csp/drivers/usart.h', 'include/csp/drivers/usart.h') + if 'src/drivers/can/can_socketcan.c' in ctx.env.FILES_CSP: + ctx.install_as('${PREFIX}/include/csp/drivers/can_socketcan.h', 'include/csp/drivers/can_socketcan.h') + + ctx.install_files('${PREFIX}/include/csp', 'include/csp/csp_autoconfig.h', cwd=ctx.bldnode) + + ctx(export_includes='include', name='csp_h') + + ctx(features=ctx.env.FEATURES, + source=ctx.path.ant_glob(ctx.env.FILES_CSP, excl=ctx.env.EXCL_CSP), + target = 'csp', + includes= ctx.env.INCLUDES_CSP, + export_includes = ctx.env.INCLUDES_CSP, + use = 'include freertos_h', + install_path = install_path, + ) + + # Build shared library for Python bindings + if ctx.env.ENABLE_BINDINGS: + ctx.shlib(source = ctx.path.ant_glob(ctx.env.FILES_CSP, excl=ctx.env.EXCL_CSP), + name = 'csp_shlib', + target = 'csp', + includes = ctx.env.INCLUDES_CSP, + export_includes = 'include', + use = ['include'], + lib = ctx.env.LIBS) + + # python3 bindings + if ctx.env.LIBCSP_PYTHON3: + ctx.shlib(source = ['src/bindings/python/pycsp.c'], + target = 'csp_py3', + includes = ctx.env.INCLUDES_CSP + ctx.env.INCLUDES_PYTHON3, + export_includes = 'include', + use = ['csp_shlib', 'include'], + lib = ctx.env.LIBS) + + # python2 bindings + if ctx.env.LIBCSP_PYTHON2: + ctx.shlib(source = ['src/bindings/python/pycsp.c'], + target = 'csp_py2', + includes = ctx.env.INCLUDES_CSP + ctx.env.INCLUDES_PYTHON2, + export_includes = 'include', + use = ['csp_shlib', 'include'], + lib = ctx.env.LIBS) + + if ctx.env.ENABLE_EXAMPLES: + ctx.program(source = ctx.path.ant_glob('examples/simple.c'), + target = 'simple', + includes = ctx.env.INCLUDES_CSP, + lib = ctx.env.LIBS, + use = 'csp') + + if ctx.options.enable_if_kiss: + ctx.program(source = 'examples/kiss.c', + target = 'kiss', + includes = ctx.env.INCLUDES_CSP, + lib = ctx.env.LIBS, + use = 'csp') + + if ctx.options.enable_if_zmqhub: + ctx.program(source = 'examples/zmqproxy.c', + target = 'zmqproxy', + includes = ctx.env.INCLUDES_CSP, + lib = ctx.env.LIBS, + use = 'csp') + + if 'posix' in ctx.env.OS: + ctx.program(source = 'examples/csp_if_fifo.c', + target = 'fifo', + includes = ctx.env.INCLUDES_CSP, + lib = ctx.env.LIBS, + use = 'csp') + + if 'windows' in ctx.env.OS: + ctx.program(source = ctx.path.ant_glob('examples/csp_if_fifo_windows.c'), + target = 'csp_if_fifo', + includes = ctx.env.INCLUDES_CSP, + use = 'csp') + +def dist(ctx): + ctx.excl = 'build/* **/.* **/*.pyc **/*.o **/*~ *.tar.gz' diff --git a/gomspace/libgscsp/src/bindings/python/pygscsp.c b/gomspace/libgscsp/src/bindings/python/pygscsp.c new file mode 100644 index 00000000..c69d346b --- /dev/null +++ b/gomspace/libgscsp/src/bindings/python/pygscsp.c @@ -0,0 +1,61 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +#include + +#include + +#if PY_MAJOR_VERSION == 3 +#define IS_PY3 +#endif + +/* gs_error_t gs_csp_i2c_init(uint8_t device, uint8_t csp_addr); */ +static PyObject* pygscsp_csp_i2c_init(PyObject *self, PyObject *args) { + uint8_t device; + uint8_t csp_addr; + + if (!PyArg_ParseTuple(args, "BB", &device, &csp_addr)) { + Py_RETURN_NONE; + } + + return Py_BuildValue("i", gs_csp_i2c_init(device, csp_addr)); +} + + +static PyMethodDef methods[] = { + + {"i2c_init", pygscsp_csp_i2c_init, METH_VARARGS, ""}, + + /* sentinel */ + {NULL, NULL, 0, NULL} +}; + +#ifdef IS_PY3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "libgscsp_py3", + NULL, + -1, + methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +#ifdef IS_PY3 +PyMODINIT_FUNC PyInit_libgscsp_py3(void) { +#else +PyMODINIT_FUNC initlibgscsp_py2(void) { +#endif + +#ifdef IS_PY3 + PyObject* m = PyModule_Create(&moduledef); +#else + Py_InitModule("libgscsp_py2", methods); +#endif + +#ifdef IS_PY3 + return m; +#endif + } + diff --git a/gomspace/libgscsp/src/clock.c b/gomspace/libgscsp/src/clock.c new file mode 100644 index 00000000..9e9a7d53 --- /dev/null +++ b/gomspace/libgscsp/src/clock.c @@ -0,0 +1,23 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ +/** + @file + + Required by libcsp. + Proto-typed in ./libcsp/include/csp/arch/csp_clock.h, but with different argumet! + + __attribute__((weak)) extern void clock_get_time(csp_timestamp_t * time); + __attribute__((weak)) extern void clock_set_time(csp_timestamp_t * time); +*/ + +#include +#include + +void clock_get_time(csp_timestamp_t * time) +{ + gs_clock_get_time((gs_timestamp_t*)time); +} + +void clock_set_time(csp_timestamp_t * time) +{ + gs_clock_set_time((gs_timestamp_t*)time); +} diff --git a/gomspace/libgscsp/src/commands.c b/gomspace/libgscsp/src/commands.c new file mode 100644 index 00000000..6abd3019 --- /dev/null +++ b/gomspace/libgscsp/src/commands.c @@ -0,0 +1,652 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static gs_error_t parse_node_timeout(gs_command_context_t *ctx, int node_index, uint8_t * node, int timeout_index, uint32_t * timeout) +{ + gs_error_t error = GS_OK; + if (node) { + *node = csp_get_address(); + + if (ctx->argc > node_index) { + error = gs_string_to_uint8(ctx->argv[node_index], node); + } + } + + if (timeout && (error == GS_OK)) { + *timeout = 1000; + + if (ctx->argc > timeout_index) { + error = gs_string_to_uint32(ctx->argv[timeout_index], timeout); + } + } + + return error; +} + +static int cmd_ping(gs_command_context_t *ctx) +{ + uint8_t node; + uint32_t timeout; + int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); + if (res) { + return res; + } + + uint32_t size = 1; + if ((ctx->argc > 3) && (gs_string_to_uint32(ctx->argv[3], &size) != GS_OK)) { + return GS_ERROR_ARG; + } + + uint32_t options = CSP_O_NONE; + if (ctx->argc > 4) { + const char * features = ctx->argv[4]; + if (strchr(features, 'r')) + options |= CSP_O_RDP; + if (strchr(features, 'x')) + options |= CSP_O_XTEA; + if (strchr(features, 'h')) + options |= CSP_O_HMAC; + if (strchr(features, 'c')) + options |= CSP_O_CRC32; + } + + printf("Ping node %u, timeout %" PRIu32 ", size %" PRIu32 ": options: 0x%" PRIx32 " ... ", node, timeout, size, options); + + const uint64_t start = gs_clock_get_nsec(); + const int time = csp_ping(node, timeout, size, options); + const uint64_t stop = gs_clock_get_nsec(); + const float elapsed = (((float)(stop - start)) / 1E6); + if (time < 0) { + printf("timeout after %.03f ms\r\n", elapsed); + return GS_ERROR_TIMEOUT; + } + + printf("reply in %.03f ms\r\n", elapsed); + + return GS_OK; +} + +static int cmd_ps(gs_command_context_t *ctx) +{ + uint8_t node; + uint32_t timeout; + int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); + if (res) { + return res; + } + + csp_ps(node, timeout); + + return GS_OK; +} + +static int cmd_memfree(gs_command_context_t *ctx) +{ + uint8_t node; + uint32_t timeout; + int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); + if (res) { + return res; + } + + csp_memfree(node, timeout); + + return GS_OK; +} + +static int cmd_reboot(gs_command_context_t *ctx) +{ + if (ctx->argc < 2) { + return GS_ERROR_ARG; + } + uint8_t node; + int res = parse_node_timeout(ctx, 1, &node, 0, NULL); + if (res) { + return res; + } + + csp_reboot(node); + + return GS_OK; +} + +static int cmd_shutdown(gs_command_context_t *ctx) +{ + if (ctx->argc < 2) { + return GS_ERROR_ARG; + } + uint8_t node; + int res = parse_node_timeout(ctx, 1, &node, 0, NULL); + if (res) { + return res; + } + + csp_shutdown(node); + + return GS_OK; +} + +static int cmd_buf_free(gs_command_context_t *ctx) +{ + uint8_t node; + uint32_t timeout; + int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); + if (res) { + return res; + } + + csp_buf_free(node, timeout); + + return GS_OK; +} + +static int cmd_uptime(gs_command_context_t *ctx) +{ + uint8_t node; + uint32_t timeout; + int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); + if (res) { + return res; + } + + csp_uptime(node, timeout); + + return GS_OK; +} + +#ifdef CSP_DEBUG + +static int cmd_csp_route_print_table(gs_command_context_t *ctx) +{ + csp_route_print_table(); + return GS_OK; +} + +static int cmd_csp_route_print_interfaces(gs_command_context_t *ctx) +{ + csp_route_print_interfaces(); + return GS_OK; +} + +static int cmd_csp_conn_print_table(gs_command_context_t *ctx) +{ + csp_conn_print_table(); + return GS_OK; +} + +#endif + +#if CSP_USE_RDP +static int cmd_csp_rdp_set_opt(gs_command_context_t *ctx) +{ + if (ctx->argc < 7) { + return GS_ERROR_ARG; + } + int res; + uint32_t window_size; + if ((res = gs_string_to_uint32(ctx->argv[1], &window_size))) { + return res; + } + uint32_t conn_timeout; + if ((res = gs_string_to_uint32(ctx->argv[2], &conn_timeout))) { + return res; + } + uint32_t packet_timeout; + if ((res = gs_string_to_uint32(ctx->argv[3], &packet_timeout))) { + return res; + } + uint32_t delayed_acks; + if ((res = gs_string_to_uint32(ctx->argv[4], &delayed_acks))) { + return res; + } + uint32_t ack_timeout; + if ((res = gs_string_to_uint32(ctx->argv[5], &ack_timeout))) { + return res; + } + uint32_t ack_delay_count; + if ((res = gs_string_to_uint32(ctx->argv[6], &ack_delay_count))) { + return res; + } + + printf("Setting arguments to: window size %" PRIu32 ", conn timeout %" PRIu32 ", packet timeout %" PRIu32 ", delayed acks %" PRIu32 ", ack timeout %" PRIu32 ", ack delay count %" PRIu32 "\r\n", + window_size, conn_timeout, packet_timeout, delayed_acks, ack_timeout, ack_delay_count); + + csp_rdp_set_opt(window_size, conn_timeout, packet_timeout, delayed_acks, ack_timeout, ack_delay_count); + + return GS_OK; +} +#endif + +static int cmd_cmp_ident(gs_command_context_t *ctx) +{ + uint8_t node; + uint32_t timeout; + int ret = parse_node_timeout(ctx, 1, &node, 2, &timeout); + if (ret) { + return ret; + } + + struct csp_cmp_message msg; + + ret = csp_cmp_ident(node, timeout, &msg); + if (ret != CSP_ERR_NONE) { + printf("CSP error: %d\r\n", ret); + return gs_csp_error(ret);; + } + + printf("Hostname: %s\r\n", msg.ident.hostname); + printf("Model: %s\r\n", msg.ident.model); + printf("Revision: %s\r\n", msg.ident.revision); + printf("Date: %s\r\n", msg.ident.date); + printf("Time: %s\r\n", msg.ident.time); + + return GS_OK; +} + +static int cmd_cmp_route_set(gs_command_context_t *ctx) +{ + if (ctx->argc != 6) + return GS_ERROR_ARG; + + uint8_t node = atoi(ctx->argv[1]); + uint32_t timeout = atoi(ctx->argv[2]); + printf("Sending route_set to node %"PRIu8" timeout %"PRIu32"\r\n", node, timeout); + + struct csp_cmp_message msg; + msg.route_set.dest_node = atoi(ctx->argv[3]); + msg.route_set.next_hop_mac = atoi(ctx->argv[4]); + strncpy(msg.route_set.interface, ctx->argv[5], 10); + printf("Dest_node: %u, next_hop_mac: %u, interface %s\r\n", msg.route_set.dest_node, msg.route_set.next_hop_mac, msg.route_set.interface); + + int ret = csp_cmp_route_set(node, timeout, &msg); + if (ret != CSP_ERR_NONE) { + printf("CSP error: %d\r\n", ret); + return gs_csp_error(ret); + } + + return GS_OK; +} + +static int cmd_cmp_ifc(gs_command_context_t *ctx) { + + uint8_t node; + uint32_t timeout; + char * interface; + + if (ctx->argc > 4 || ctx->argc < 3) + return GS_ERROR_ARG; + + node = atoi(ctx->argv[1]); + interface = ctx->argv[2]; + + if (ctx->argc < 4) + timeout = 1000; + else + timeout = atoi(ctx->argv[3]); + + struct csp_cmp_message msg; + strncpy(msg.if_stats.interface, interface, CSP_CMP_ROUTE_IFACE_LEN); + + printf("Requesting interface stats for interface %s\r\n", interface); + + int ret = csp_cmp_if_stats(node, timeout, &msg); + if (ret != CSP_ERR_NONE) { + printf("CSP error: %d\r\n", ret); + return gs_csp_error(ret); + } + + msg.if_stats.tx = csp_ntoh32(msg.if_stats.tx); + msg.if_stats.rx = csp_ntoh32(msg.if_stats.rx); + msg.if_stats.tx_error = csp_ntoh32(msg.if_stats.tx_error); + msg.if_stats.rx_error = csp_ntoh32(msg.if_stats.rx_error); + msg.if_stats.drop = csp_ntoh32(msg.if_stats.drop); + msg.if_stats.autherr = csp_ntoh32(msg.if_stats.autherr); + msg.if_stats.frame = csp_ntoh32(msg.if_stats.frame); + msg.if_stats.txbytes = csp_ntoh32(msg.if_stats.txbytes); + msg.if_stats.rxbytes = csp_ntoh32(msg.if_stats.rxbytes); + msg.if_stats.irq = csp_ntoh32(msg.if_stats.irq); + + printf("%-5s tx: %05"PRIu32" rx: %05"PRIu32" txe: %05"PRIu32" rxe: %05"PRIu32"\r\n" + " drop: %05"PRIu32" autherr: %05"PRIu32 " frame: %05"PRIu32"\r\n" + " txb: %"PRIu32" rxb: %"PRIu32"\r\n\r\n", + msg.if_stats.interface, msg.if_stats.tx, msg.if_stats.rx, msg.if_stats.tx_error, msg.if_stats.rx_error, msg.if_stats.drop, + msg.if_stats.autherr, msg.if_stats.frame, msg.if_stats.txbytes, msg.if_stats.rxbytes); + + return GS_OK; +} + +static int cmd_cmp_peek(gs_command_context_t *ctx) +{ + if ((ctx->argc != 4) && (ctx->argc != 5)) + return GS_ERROR_ARG; + + uint8_t node; + uint32_t timeout; + int res = parse_node_timeout(ctx, 1, &node, 4, &timeout); + if (res) { + return res; + } + + uint32_t addr; + if (gs_string_to_uint32(ctx->argv[2], &addr)) { + return GS_ERROR_ARG; + } + + uint32_t len; + if (gs_string_to_uint32(ctx->argv[3], &len)) { + return GS_ERROR_ARG; + } + if (len > CSP_CMP_PEEK_MAX_LEN) { + return GS_ERROR_RANGE; + } + + printf("Dumping mem from node %u addr 0x%"PRIx32" len %"PRIx32" timeout %"PRIu32"\r\n", node, addr, len, timeout); + + struct csp_cmp_message msg; + msg.peek.addr = csp_hton32(addr); + msg.peek.len = len; + + int ret = csp_cmp_peek(node, timeout, &msg); + if (ret != CSP_ERR_NONE) { + printf("CSP error: %d\r\n", ret); + return gs_csp_error(ret); + } + + gs_hexdump_addr(msg.peek.data, len, GS_TYPES_UINT2PTR(addr)); + + return GS_OK; +} + +static int cmd_cmp_poke(gs_command_context_t *ctx) +{ + if ((ctx->argc != 4) && (ctx->argc != 5)) + return GS_ERROR_ARG; + + uint8_t node; + uint32_t timeout; + int res = parse_node_timeout(ctx, 1, &node, 4, &timeout); + if (res) { + return res; + } + + uint32_t addr; + if (gs_string_to_uint32(ctx->argv[2], &addr)) { + return GS_ERROR_ARG; + } + + unsigned char data[CSP_CMP_POKE_MAX_LEN]; + uint32_t len = base16_decode(ctx->argv[3], data); + if (len > CSP_CMP_PEEK_MAX_LEN) { + printf("Max length is: %u\r\n", CSP_CMP_PEEK_MAX_LEN); + return GS_ERROR_RANGE; + } + + printf("Writing to mem at node %u addr 0x%"PRIx32" len %"PRIx32" timeout %"PRIu32"\r\n", node, addr, len, timeout); + gs_hexdump_addr(data, len, GS_TYPES_UINT2PTR(addr)); + + struct csp_cmp_message msg; + msg.poke.addr = csp_hton32(addr); + msg.poke.len = len; + memcpy(msg.poke.data, data, CSP_CMP_POKE_MAX_LEN); + + int ret = csp_cmp_poke(node, timeout, &msg); + if (ret != CSP_ERR_NONE) { + printf("CSP error: %d\r\n", ret); + return gs_csp_error(ret); + } + + return GS_OK; +} + +static int cmd_cmp_clock(gs_command_context_t *ctx, uint32_t node, uint32_t timeout, const gs_timestamp_t * set) +{ + char tbuf[GS_CLOCK_ISO8601_BUFFER_LENGTH]; + struct csp_cmp_message msg; + memset(&msg, 0, sizeof(msg)); + + if (set) { + gs_clock_to_iso8601_string(set, tbuf, sizeof(tbuf)); + printf("Set time: %s (%" PRIu32 ".%09" PRIu32 " sec)\r\n", tbuf, set->tv_sec, set->tv_nsec); + msg.clock.tv_sec = csp_hton32(set->tv_sec); + msg.clock.tv_nsec = csp_hton32(set->tv_nsec); + } + + gs_timestamp_t t1, t2; + gs_clock_get_time(&t1); + int ret = csp_cmp_clock(node, timeout, &msg); + if (ret != CSP_ERR_NONE) { + return gs_csp_error(ret); + } + gs_clock_get_time(&t2); + + /* Calculate round-trip time */ + const int64_t rtt = ((uint64_t)t2.tv_sec * 1000000000 + t2.tv_nsec) - ((uint64_t)t1.tv_sec * 1000000000 + t1.tv_nsec); + + gs_timestamp_t timestamp; + timestamp.tv_sec = csp_ntoh32(msg.clock.tv_sec); + timestamp.tv_nsec = csp_ntoh32(msg.clock.tv_nsec); + + gs_clock_to_iso8601_string(×tamp, tbuf, sizeof(tbuf)); + printf("Get time: %s (%" PRIu32 ".%09" PRIu32 " sec)\r\n", tbuf, timestamp.tv_sec, timestamp.tv_nsec); + + /* Calculate time difference to local clock. This takes the round-trip + * into account, but assumes a symmetrical link */ + const int64_t remote = (uint64_t)timestamp.tv_sec * 1000000000 + timestamp.tv_nsec; + const int64_t local = (uint64_t)t1.tv_sec * 1000000000 + t1.tv_nsec + rtt / 2; + + const double diff = (remote - local) / 1000000.0; + printf("Remote is %f ms %s local time\r\n", fabs(diff), diff > 0 ? "ahead of" : "behind"); + + return GS_OK; +} + +static int cmd_cmp_clock_get(gs_command_context_t *ctx) +{ + if (ctx->argc < 2) { + return GS_ERROR_ARG; + } + + uint32_t node; + if (gs_string_to_uint32(ctx->argv[1], &node) != GS_OK) { + return GS_ERROR_ARG; + } + + uint32_t timeout = 1000; + if (ctx->argc > 2) { + if (gs_string_to_uint32(ctx->argv[2], &timeout) != GS_OK) { + return GS_ERROR_ARG; + } + } + + return cmd_cmp_clock(ctx, node, timeout, NULL); +} + +static int cmd_cmp_clock_set(gs_command_context_t *ctx) +{ + if (ctx->argc < 3) { + return GS_ERROR_ARG; + } + + uint32_t node; + if (gs_string_to_uint32(ctx->argv[1], &node) != GS_OK) { + return GS_ERROR_ARG; + } + + gs_timestamp_t ts; + if (gs_clock_from_string(ctx->argv[2], &ts) != GS_OK) { + return GS_ERROR_ARG; + } + + uint32_t timeout = 1000; + if (ctx->argc > 3) { + if (gs_string_to_uint32(ctx->argv[3], &timeout) != GS_OK) { + return GS_ERROR_ARG; + } + } + + return cmd_cmp_clock(ctx, node, timeout, &ts); +} + +static int cmd_cmp_clock_sync(gs_command_context_t *ctx) +{ + if (ctx->argc < 2) { + return GS_ERROR_ARG; + } + + uint32_t node; + if (gs_string_to_uint32(ctx->argv[1], &node) != GS_OK) { + return GS_ERROR_ARG; + } + + uint32_t timeout = 1000; + if (ctx->argc > 2) { + if (gs_string_to_uint32(ctx->argv[2], &timeout) != GS_OK) { + return GS_ERROR_ARG; + } + } + + gs_timestamp_t ts; + gs_clock_get_time(&ts); + + return cmd_cmp_clock(ctx, node, timeout, &ts); +} + +static const gs_command_t GS_COMMAND_SUB cmp_clock_commands[] = { + { + .name = "get", + .help = "Get clock on ", + .usage = " [timeout]", + .handler = cmd_cmp_clock_get, + }, + { + .name = "set", + .help = "Set time of ", + .usage = " [timeout]", + .handler = cmd_cmp_clock_set, + }, + { + .name = "sync", + .help = "Sync/set time of to time of this node", + .usage = " [timeout]", + .handler = cmd_cmp_clock_sync, + } +}; + +static const gs_command_t GS_COMMAND_SUB cmp_commands[] = { + { + .name = "ident", + .help = "Node id", + .usage = "[node] [timeout]", + .handler = cmd_cmp_ident, + },{ + .name = "route_set", + .help = "Update table", + .usage = " ", + .handler = cmd_cmp_route_set, + },{ + .name = "ifc", + .help = "Remote IFC", + .usage = " [timeout]", + .handler = cmd_cmp_ifc, + },{ + .name = "peek", + .help = "Show remote memory", + .usage = " [timeout]", + .handler = cmd_cmp_peek, + },{ + .name = "poke", + .help = "Modify remote memory", + .usage = " [timeout]", + .handler = cmd_cmp_poke, + },{ + .name = "clock", + .help = "Get/set clock", + .chain = GS_COMMAND_INIT_CHAIN(cmp_clock_commands), + } +}; + +static const gs_command_t GS_COMMAND_ROOT csp_commands[] = { + { + .name = "ping", + .help = "csp: Ping", + .usage = "[node] [timeout] [size] [opt: r|x|h|c]", + .handler = cmd_ping, + },{ + .name = "rps", + .help = "csp: Remote ps", + .usage = "[node] [timeout]", + .handler = cmd_ps, + },{ + .name = "memfree", + .help = "csp: Memory free", + .usage = "[node] [timeout]", + .handler = cmd_memfree, + },{ + .name = "buffree", + .help = "csp: Buffer free", + .usage = "[node] [timeout]", + .handler = cmd_buf_free, + },{ + .name = "reboot", + .help = "csp: Reboot", + .usage = "", + .handler = cmd_reboot, + },{ + .name = "shutdown", + .help = "csp: Shutdown", + .usage = "", + .handler = cmd_shutdown, + },{ + .name = "uptime", + .help = "csp: Uptime", + .usage = "[node] [timeout]", + .handler = cmd_uptime, + },{ + .name = "cmp", + .help = "csp: Management", + .chain = GS_COMMAND_INIT_CHAIN(cmp_commands), + }, +#ifdef CSP_DEBUG + { + .name = "route", + .help = "csp: Show routing table", + .handler = cmd_csp_route_print_table, + },{ + .name = "ifc", + .help = "csp: Show interfaces", + .handler = cmd_csp_route_print_interfaces, + },{ + .name = "conn", + .help = "csp: Show connection table", + .handler = cmd_csp_conn_print_table, + }, +#endif +#if CSP_USE_RDP + { + .name = "rdpopt", + .help = "csp: Set RDP options", + .handler = cmd_csp_rdp_set_opt, + .usage = " " + }, +#endif +}; + +gs_error_t gs_csp_register_commands(void) +{ + return GS_COMMAND_REGISTER(csp_commands); +} diff --git a/gomspace/libgscsp/src/conn.c b/gomspace/libgscsp/src/conn.c new file mode 100644 index 00000000..05e6459e --- /dev/null +++ b/gomspace/libgscsp/src/conn.c @@ -0,0 +1,22 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include <../lib/libcsp/src/csp_conn.h> // internal libcsp header + +size_t gs_csp_conn_get_open(void) +{ + size_t open = 0; + size_t max_connections; + const csp_conn_t * connections = csp_conn_get_array(&max_connections); + if (connections) { + for (unsigned int i = 0; i < max_connections; ++i) { + if (connections[i].state != CONN_CLOSED) { + ++open; + } + } + } + + // csp_conn_print_table(); + + return open; +} diff --git a/gomspace/libgscsp/src/csp.c b/gomspace/libgscsp/src/csp.c new file mode 100644 index 00000000..2367ec6a --- /dev/null +++ b/gomspace/libgscsp/src/csp.c @@ -0,0 +1,91 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include "local.h" + +void gs_csp_conf_get_defaults_embedded(gs_csp_conf_t * conf) +{ + static const gs_csp_conf_t defaults = { + .use_gs_log = true, + .use_command_line_options = true, + .csp_buffer_size = 256, // typical MTU size is 256 + .csp_buffers = 10, // in case of RDP connections, must be > RDP Windows size + .address = 1, + .hostname = "hostname", + .model = "model", + .revision = "revision", + }; + + *conf = defaults; + +#if GS_CSP_COMMAND_LINE_SUPPORT + conf->address = gs_csp_command_line_get_address(); +#endif +} + +void gs_csp_conf_get_defaults_server(gs_csp_conf_t * conf) +{ + gs_csp_conf_get_defaults_embedded(conf); + conf->csp_buffer_size = 512; + conf->csp_buffers = 400; +} + +gs_error_t gs_csp_init(const gs_csp_conf_t * conf) +{ + GS_CHECK_ARG(conf != NULL); + + if (conf->use_gs_log) { + gs_csp_log_init(); + } + + int res = csp_buffer_init(conf->csp_buffers, conf->csp_buffer_size); + if (res != CSP_ERR_NONE) { + log_error("%s: csp_buffer_init(buffers: %u, size: %u) failed, CSP error: %d, error: %d", + __FUNCTION__, (unsigned int) conf->csp_buffers, (unsigned int) conf->csp_buffer_size, res, gs_csp_error(res)); + return gs_csp_error(res); + } + + csp_set_hostname(conf->hostname); + csp_set_model(conf->model); + csp_set_revision(conf->revision); + + uint8_t csp_address = conf->address; +#if GS_CSP_COMMAND_LINE_SUPPORT + if (gs_csp_command_line_is_address_set()) { + csp_address = gs_csp_command_line_get_address(); + } +#endif + + res = csp_init(csp_address); + if (res != CSP_ERR_NONE) { + log_error("%s: csp_init(address: %u) failed, CSP error: %d, error: %d", + __FUNCTION__, conf->address, res, gs_csp_error(res)); + return gs_csp_error(res); + } + +#if GS_CSP_COMMAND_LINE_SUPPORT + if (conf->use_command_line_options) { + gs_error_t error = gs_csp_command_line_configure_interfaces(); + if (error) { + log_error("%s: gs_csp_command_line_configure_interfaces() failed, error: %d", + __FUNCTION__, error); + return error; + } + } +#endif + + return GS_OK; +} + +bool gs_csp_is_address_valid(uint8_t address) +{ + if (address < 1) { + return false; + } + if (address >= 33) { + return false; + } + return true; +} diff --git a/gomspace/libgscsp/src/drivers/can/can.c b/gomspace/libgscsp/src/drivers/can/can.c new file mode 100644 index 00000000..965977ca --- /dev/null +++ b/gomspace/libgscsp/src/drivers/can/can.c @@ -0,0 +1,108 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NO_OF_CAN_CHANNELS 2 +#define MAX_NAME_LENGTH 10 // It says in csp_types.h, that it should be below 10 bytes + +// change default log group +#define LOG_DEFAULT gs_can_log + +typedef struct { + // self reference device handle + uint8_t can_ch; + // CSP interface name + char interface_name[MAX_NAME_LENGTH]; + // CSP interface + csp_iface_t interface; +} gs_csp_can_interface_t; + +static gs_csp_can_interface_t csp_can_interfaces[NO_OF_CAN_CHANNELS]; + +static void gs_csp_can_rxdata_callback_isr(int hdl, + uint32_t canMsgId, + bool extendedMsgId, + const void * data, + size_t data_size, + uint32_t nowMs, + void * user_data, + gs_context_switch_t * cswitch) +{ + csp_can_rx(&csp_can_interfaces[hdl].interface, canMsgId, data, data_size, &cswitch->task_woken); +} + +// Required by libcsp +int csp_can_tx_frame(csp_iface_t *interface, uint32_t id, const uint8_t * data, uint8_t dlc) +{ + return gs_can_send_extended(((gs_csp_can_interface_t *)interface->driver)->can_ch, id, data, dlc, 1000); +} + +gs_error_t gs_csp_can_init2(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, bool set_default_route, csp_iface_t ** csp_if) +{ + GS_CHECK_HANDLE(device < NO_OF_CAN_CHANNELS); + gs_csp_can_interface_t * interface = &csp_can_interfaces[device]; + + // Register/subscribe to CAN frames for CSP + const uint32_t can_id = CFP_MAKE_DST(csp_get_address()); + const uint32_t can_mask = CFP_MAKE_DST((1 << CFP_HOST_SIZE) - 1); + + log_debug("%s(%u): id=0x%" PRIx32 ", mask=0x%" PRIx32, __FUNCTION__, device, can_id, can_mask); + + if (gs_string_empty(name)) { + name = GS_CSP_CAN_DEFAULT_IF_NAME; + } + if (strlen(name) >= MAX_NAME_LENGTH) { + return GS_ERROR_ARG; + } + + if (csp_iflist_get_by_name(name)) { + log_error("%s(%u): name: [%s] - already exists", __FUNCTION__, device, name); + return GS_ERROR_EXIST; + } + + // hook CAN into CSP + GS_STRNCPY(interface->interface_name, name); + interface->interface.name = interface->interface_name; + interface->interface.nexthop = csp_can_tx; + interface->interface.mtu = mtu; + interface->interface.driver = interface; + + csp_iflist_add(&interface->interface); + + if (csp_if) { + *csp_if = &interface->interface; + } + + gs_error_t error = gs_can_set_extended_filter_mask(0, can_id, can_mask, gs_csp_can_rxdata_callback_isr, NULL); + if (error) { + log_error("%s: gs_can_set_extended_filter_mask() failed, error: %s", __FUNCTION__, gs_error_string(error)); + return error; + } + + error = gs_can_start(device); + if (error) { + log_error("%s: gs_can_start() failed, error: %s", __FUNCTION__, gs_error_string(error)); + return error; + } + + if (set_default_route) { + // Route all to CAN + csp_rtable_set(0, 0, &interface->interface, CSP_NODE_MAC); + } + + return GS_OK; +} + +gs_error_t gs_csp_can_init(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, csp_iface_t ** csp_if) +{ + return gs_csp_can_init2(device, csp_addr, mtu, name, true, csp_if); +} diff --git a/gomspace/libgscsp/src/drivers/i2c/i2c.c b/gomspace/libgscsp/src/drivers/i2c/i2c.c new file mode 100644 index 00000000..c40cd9c8 --- /dev/null +++ b/gomspace/libgscsp/src/drivers/i2c/i2c.c @@ -0,0 +1,77 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#include +#if !defined(__linux__) +#include +#endif + +#define E_FAIL -19 // The CSP I2C driver evaluates any other value than -1 as fail + +#define I2C_FRAME_OVERHEAD (sizeof(i2c_frame_t) - sizeof(((i2c_frame_t *)0)->data)) + +static void gs_csp_i2c_rxdata_callback_isr(uint8_t handle, const uint8_t * rx, size_t rx_length, gs_context_switch_t * cswitch) +{ + i2c_frame_t * frame = (i2c_frame_t *) (rx - I2C_FRAME_OVERHEAD); + frame->len = rx_length; +#if (__linux__) + csp_i2c_rx(frame, NULL); +#else + csp_i2c_rx(frame, &cswitch->task_woken); +#endif +} + +static void * gs_csp_i2c_get_buffer(uint8_t handle) +{ + void * buff = csp_buffer_get_isr(I2C_MTU); + if (buff != NULL) { + buff = ((uint8_t *)buff) + I2C_FRAME_OVERHEAD; + } + return buff; +} + +/** + CSP send function, required by libcsp + */ +int i2c_send(int handle, i2c_frame_t * frame, uint16_t timeout) +{ + int res_tx = gs_i2c_master_transaction(handle, frame->dest, frame->data, frame->len, 0, 0, timeout); + if (res_tx == GS_OK) { + csp_buffer_free(frame); + return E_NO_ERR; + } else { + return E_FAIL; + } +} + +/** + CSP init function, required by libcsp + */ +int i2c_init(int handle, int mode, uint8_t addr, uint16_t speed, int queue_len_tx, int queue_len_rx, + i2c_callback_t callback) +{ + if (gs_i2c_slave_set_rx(handle, gs_csp_i2c_rxdata_callback_isr) != GS_OK) { + return E_FAIL; + } + if (gs_i2c_slave_set_get_rx_buf(handle, gs_csp_i2c_get_buffer, I2C_MTU) != GS_OK) { + return E_FAIL; + } + if (gs_i2c_slave_start(handle) != GS_OK) { + return E_FAIL; + } + return E_NO_ERR; +} + +gs_error_t gs_csp_i2c_init(uint8_t device, uint8_t csp_addr) +{ + int dummy_speed = 0; // Speed not used + + /* Calls CSP I2C init, which has the I2C interface instance + From here the above "i2c_init" is called */ + return gs_csp_error(csp_i2c_init(csp_addr, device, dummy_speed)); +} diff --git a/gomspace/libgscsp/src/drivers/kiss/kiss.c b/gomspace/libgscsp/src/drivers/kiss/kiss.c new file mode 100644 index 00000000..c3357f7d --- /dev/null +++ b/gomspace/libgscsp/src/drivers/kiss/kiss.c @@ -0,0 +1,36 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include + +static csp_iface_t csp_if_kiss; +static uint8_t uart_csp_device; + +static void usart_rx_callback(void * user_data, const uint8_t * data, size_t data_size, gs_context_switch_t * cswitch) +{ + csp_kiss_rx(&csp_if_kiss, (uint8_t *)data, data_size, cswitch); +} + +static void csp_kiss_putc(char c) +{ + gs_uart_write(uart_csp_device, -1, c); +} + +static void csp_kiss_discard(char c, void *pxTaskWoken) +{ + // Do nothing with discarded characters +} + +gs_error_t gs_csp_kiss_init(uint8_t device) +{ + static csp_kiss_handle_t csp_kiss_driver; + static const char * kiss_name = "KISS"; + csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_kiss, CSP_NODE_MAC); + + csp_kiss_init(&csp_if_kiss, &csp_kiss_driver, csp_kiss_putc, csp_kiss_discard, kiss_name); + + uart_csp_device = device; + + return gs_uart_set_rx_callback(device, usart_rx_callback, NULL); +} diff --git a/gomspace/libgscsp/src/error.c b/gomspace/libgscsp/src/error.c new file mode 100644 index 00000000..45777e31 --- /dev/null +++ b/gomspace/libgscsp/src/error.c @@ -0,0 +1,54 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +gs_error_t gs_csp_error(int csp_error) +{ + switch (csp_error) { + case CSP_ERR_NONE: /* No error */ + return GS_OK; + + case CSP_ERR_NOMEM: /* Not enough memory */ + return GS_ERROR_ALLOC; + + case CSP_ERR_INVAL: /* Invalid argument */ + return GS_ERROR_ARG; + + case CSP_ERR_TIMEDOUT: /* Operation timed out */ + return GS_ERROR_TIMEOUT; + + case CSP_ERR_USED: /* Resource already in use */ + return GS_ERROR_IN_USE; + + case CSP_ERR_NOTSUP: /* Operation not supported */ + return GS_ERROR_NOT_SUPPORTED; + + case CSP_ERR_BUSY: /* Device or resource busy */ + return GS_ERROR_BUSY; + + case CSP_ERR_ALREADY: /* Connection already in progress */ + return GS_ERROR_ALREADY_IN_PROGRESS; + + case CSP_ERR_RESET: /* Connection reset */ + return GS_ERROR_CONNECTION_RESET; + + case CSP_ERR_NOBUFS: /* No more buffer space available */ + return GS_ERROR_NO_BUFFERS; + + case CSP_ERR_TX: /* Transmission failed */ + case CSP_ERR_DRIVER: /* Error in driver layer */ + return GS_ERROR_IO; + + case CSP_ERR_AGAIN: + return GS_ERROR_AGAIN; + + case CSP_ERR_HMAC: /* HMAC failed */ + case CSP_ERR_XTEA: /* XTEA failed */ + case CSP_ERR_CRC32: /* CRC32 failed */ + return GS_ERROR_DATA; + + default: + break; + } + return csp_error; +} diff --git a/gomspace/libgscsp/src/freertos/cpu.c b/gomspace/libgscsp/src/freertos/cpu.c new file mode 100644 index 00000000..a17fd62b --- /dev/null +++ b/gomspace/libgscsp/src/freertos/cpu.c @@ -0,0 +1,8 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include + +void cpu_reset(void) +{ + gs_sys_reset(GS_SYS_RESET_CSP); +} diff --git a/gomspace/libgscsp/src/linux/command_line.c b/gomspace/libgscsp/src/linux/command_line.c new file mode 100644 index 00000000..7c2b9bec --- /dev/null +++ b/gomspace/libgscsp/src/linux/command_line.c @@ -0,0 +1,265 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include "../local.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IF_NAME "if" + +#define DEFAULT_CAN_DEVICE "can0" + +#define DEFAULT_KISS_IF_NAME "KISS" +#define DEFAULT_KISS_DEVICE "/dev/ttyUSB0" +#define KISS_SPEED "speed" +#define DEFAULT_KISS_SPEED 500000 + +#define DEFAULT_ZMQ_SERVER "localhost" + +#define DEFAULT_I2C_DEVICE "0" + +#define CSP_ADDRESS_NOT_SET 255 +#define DEFAULT_CSP_ADDRESS 8 + +static uint8_t csp_address = CSP_ADDRESS_NOT_SET; +static const char * csp_can_device = NULL; +static const char * csp_kiss_device = NULL; +static const char * csp_i2c_device = NULL; +static const char * csp_zmq_server = NULL; +static const char * csp_rtable = NULL; + +static int parser(int key, char *arg, struct argp_state *state) +{ +switch (key) { + case 'a': + return gs_string_to_uint8(arg, &csp_address); + + case 'c': + if (csp_can_device) { + return GS_ERROR_IN_USE; + } + if (arg) { + csp_can_device = arg; + } else { + csp_can_device = DEFAULT_CAN_DEVICE; + } + break; + + case 'k': + if (csp_kiss_device) { + return GS_ERROR_IN_USE; + } + if (arg) { + csp_kiss_device = arg; + } else { + csp_kiss_device = DEFAULT_KISS_DEVICE; + } + break; + + case 'i': + if (csp_i2c_device) { + return GS_ERROR_IN_USE; + } + if (arg) { + csp_i2c_device = arg; + } else { + csp_i2c_device = DEFAULT_I2C_DEVICE; + } + break; + + case 'z': + if (csp_zmq_server) { + return GS_ERROR_IN_USE; + } + if (arg) { + csp_zmq_server = arg; + } else { + csp_zmq_server = DEFAULT_ZMQ_SERVER; + } + break; + + case 'R': + csp_rtable = arg; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static const struct argp_option options[] = { + { + .name = "csp-address", + .key = 'a', + .arg = "ADDR", + .flags = 0, + .doc = "Set address, default: " GS_DEF2STRING(DEFAULT_CSP_ADDRESS) + }, + { + .name = "csp-rtable", + .key = 'R', + .arg = "RTABLE", + .flags = 0, + .doc = "Set routing table\nRTABLE=
/ [mac]\nExample: \"0/0 ZMQHUB 24, 24/2 ZMQHUB\"" + }, +#if (CSP_USE_CAN) + { + .name = "csp-can", + .key = 'c', + .arg = "DEVICE", + .flags = OPTION_ARG_OPTIONAL, + .doc = "Add CAN interface\nDEVICE=" DEFAULT_CAN_DEVICE + }, +#endif +#if (CSP_USE_KISS) + { + .name = "csp-kiss", + .key = 'k', + .arg = "DEVICE", + .flags = OPTION_ARG_OPTIONAL, + .doc = "Add KISS over UART interface\nDEVICE=" DEFAULT_KISS_DEVICE "," IF_NAME "=" DEFAULT_KISS_IF_NAME","KISS_SPEED"=" GS_DEF2STRING(DEFAULT_KISS_SPEED) + }, +#endif +#if (CSP_USE_I2C) + { + .name = "csp-i2c", + .key = 'i', + .arg = "DEVICE", + .flags = OPTION_ARG_OPTIONAL, + .doc = "Add I2C interface\nDEVICE=0,"GS_I2C_COMMAND_LINE_SPEED"=" GS_DEF2STRING(GS_I2C_DEFAULT_BPS) "," GS_I2C_COMMAND_LINE_ADDRESS "=1," GS_I2C_COMMAND_LINE_DEVICE "=" GS_DEF2STRING(GS_I2C_ALL_DEVICES) + }, +#endif +#if (CSP_USE_ZMQHUB) + { + .name = "csp-zmq", + .key = 'z', + .arg = "SERVER", + .flags = OPTION_ARG_OPTIONAL, + .doc = "Add ZMQ interface\nSERVER=" DEFAULT_ZMQ_SERVER + }, +#endif + { + .flags = OPTION_DOC, + .name = "Examples:" +#if (CSP_USE_CAN) + "\n CAN: configure address 10 and CAN interface can0:" + "\n $ -a10 -ccan0" +#endif +#if (CSP_USE_KISS) + "\n KISS: configure address 10 and uart on /dev/ttyUSB0 at baudrate 500000:" + "\n $ -a10 -k/dev/ttyUSB0,speed=500000" +#endif +#if (CSP_USE_I2C) + "\n I2C: configure address 10 and I2C Aardvark dongle with id 2238384015, speed 400K:" + "\n $ -a10 -i2238384015,speed=400000" +#endif +#if (CSP_USE_ZMQHUB) + "\n ZMQ: configure address 10 and ZMQ proxy on localhost:" + "\n $ -a10 -zlocalhost" +#endif + }, + {0} +}; + +static const struct argp argp = {.options = options, .parser = parser}; + +const struct argp_child gs_csp_command_line_options = {.argp = &argp, .header = "CSP"}; + +gs_error_t gs_csp_command_line_configure_interfaces(void) +{ +#if (CSP_USE_KISS) + // KISS - only here, because the embedded init functions are stubbed in libemul + if (csp_kiss_device) { + static char device[50]; + static char ifname[50]; + uint32_t speed; + int res = gs_string_get_suboption_string(csp_kiss_device, NULL, DEFAULT_KISS_DEVICE, device, sizeof(device)); + res |= gs_string_get_suboption_string(csp_kiss_device, IF_NAME, DEFAULT_KISS_IF_NAME, ifname, sizeof(ifname)); + res |= gs_string_get_suboption_uint32(csp_kiss_device, KISS_SPEED, DEFAULT_KISS_SPEED, &speed); + if (res == GS_OK) { + static csp_iface_t csp_if_kiss; + static csp_kiss_handle_t csp_kiss_driver; + csp_kiss_init(&csp_if_kiss, &csp_kiss_driver, usart_putc, usart_insert, ifname); + struct usart_conf conf = {.device = device, .baudrate = speed}; + usart_init(&conf); + void my_usart_rx(uint8_t * buf, int len, void * pxTaskWoken) { + csp_kiss_rx(&csp_if_kiss, buf, len, pxTaskWoken); + } + usart_set_callback(my_usart_rx); + } + } +#endif + +#if (CSP_USE_CAN) + // CAN - only here, because the embedded init functions are stubbed in libemul + if (csp_can_device) { + char device[50]; + int res = gs_string_get_suboption_string(csp_can_device, NULL, DEFAULT_CAN_DEVICE, device, sizeof(device)); + if (res == GS_OK) { + csp_can_socketcan_init(device, 0, 0); + } + } +#endif + +#if (CSP_USE_ZMQHUB) + // ZMQ - currently ZMQ is only supported on Linux, and therefor handled here + if (csp_zmq_server) { + char server[50]; + int res = gs_string_get_suboption_string(csp_zmq_server, NULL, DEFAULT_ZMQ_SERVER, server, sizeof(server)); + if (res == GS_OK) { + csp_zmqhub_init(csp_get_address(), server); + } + } +#endif + +#if (CSP_USE_I2C) + // I2C + if (csp_i2c_device) { + uint8_t device = 0; + gs_string_get_suboption_uint8(csp_i2c_device, GS_I2C_COMMAND_LINE_DEVICE, GS_I2C_ALL_DEVICES, &device); + if (device == GS_I2C_ALL_DEVICES) { + device = 0; + } + + char modified_options[300]; + snprintf(modified_options, sizeof(modified_options), "%s,%s=%u", csp_i2c_device, GS_I2C_COMMAND_LINE_ADDRESS, csp_get_address()); + gs_error_t error = gs_function_invoke("i2c", modified_options); + if (error) { + log_error("Failed to initialize I2C adapter, error: %s", gs_error_string(error)); + } else { + error = gs_csp_i2c_init(device, csp_get_address()); + if (error) { + log_error("gs_csp_i2c_init(%u, %u) failed, error: %s", device, csp_get_address(), gs_error_string(error)); + } + } + } +#endif + + return GS_OK; +} + +bool gs_csp_command_line_is_address_set(void) +{ + return (csp_address != CSP_ADDRESS_NOT_SET); +} + +uint8_t gs_csp_command_line_get_address(void) +{ + if (gs_csp_command_line_is_address_set()) { + return csp_address; + } + return DEFAULT_CSP_ADDRESS; +} + +const char * gs_csp_command_line_get_rtable(void) +{ + return csp_rtable; +} diff --git a/gomspace/libgscsp/src/local.h b/gomspace/libgscsp/src/local.h new file mode 100644 index 00000000..5c033c14 --- /dev/null +++ b/gomspace/libgscsp/src/local.h @@ -0,0 +1,21 @@ +#ifndef GS_CSP_SRC_LOCAL_H +#define GS_CSP_SRC_LOCAL_H +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#if (__linux__) +#define GS_CSP_COMMAND_LINE_SUPPORT 1 +#include +#endif + +GS_LOG_GROUP_EXTERN(gs_csp_log); +#define LOG_DEFAULT gs_csp_log + +// local command line APIs +bool gs_csp_command_line_is_address_set(void); +uint8_t gs_csp_command_line_get_address(void); +const char * gs_csp_command_line_get_rtable(void); +gs_error_t gs_csp_command_line_configure_interfaces(void); + +#endif diff --git a/gomspace/libgscsp/src/log.c b/gomspace/libgscsp/src/log.c new file mode 100644 index 00000000..932e5394 --- /dev/null +++ b/gomspace/libgscsp/src/log.c @@ -0,0 +1,64 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include "local.h" + +GS_LOG_GROUP(gs_csp_log, "csp", GS_LOG_CAT_CSP, LOG_DEFAULT_MASK); + +static void gs_log_csp_debug_hook(csp_debug_level_t level, const char *format, va_list args) +{ + gs_log_level_t mapped_level; + + switch (level) { + /* Regular log levels */ + default: + case CSP_ERROR: + mapped_level = LOG_ERROR; + break; + case CSP_WARN: + mapped_level = LOG_WARNING; + break; + case CSP_INFO: + mapped_level = LOG_INFO; + break; + /* Extended log levels */ + case CSP_BUFFER: + mapped_level = LOG_TRACE; + break; + case CSP_PACKET: + mapped_level = LOG_INFO; + break; + case CSP_PROTOCOL: + mapped_level = LOG_DEBUG; + break; + case CSP_LOCK: + mapped_level = LOG_TRACE; + break; + } + + const int do_log = ((LOG_DEFAULT->mask & (1 << mapped_level)) > 0); + + if (do_log) { + /* forward to log system */ + gs_log_va(mapped_level, LOG_DEFAULT, format, args); + } +} + +gs_error_t gs_csp_log_init(void) +{ + gs_log_group_register(LOG_DEFAULT); + + csp_debug_set_level(CSP_ERROR, true); + csp_debug_set_level(CSP_WARN, true); + csp_debug_set_level(CSP_INFO, true); + csp_debug_set_level(CSP_BUFFER, true); + csp_debug_set_level(CSP_PACKET, true); + csp_debug_set_level(CSP_PROTOCOL, true); + csp_debug_set_level(CSP_LOCK, true); + + csp_debug_hook_set(gs_log_csp_debug_hook); + + return GS_OK; +} diff --git a/gomspace/libgscsp/src/router.c b/gomspace/libgscsp/src/router.c new file mode 100644 index 00000000..95f013eb --- /dev/null +++ b/gomspace/libgscsp/src/router.c @@ -0,0 +1,84 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#include +#include "../lib/libcsp/src/csp_qfifo.h" // internal libcsp header -> FIFO_TIMEOUT, csp_qfifo_wake_up() +#include <../lib/libcsp/src/csp_conn.h> // internal libcsp header +#include "local.h" + +typedef struct { + bool run; + gs_thread_t thread; +} gs_csp_router_t; + +static gs_csp_router_t gs_csp_router; + +static void * gs_csp_router_task(void *param) +{ + /* Here there be routing */ + while (gs_csp_router.run) { + csp_route_work(FIFO_TIMEOUT); + } + log_info("CSP router task terminating"); + gs_thread_exit(0); +} + +gs_error_t gs_csp_router_task_stop(void) +{ + GS_CHECK_HANDLE(gs_csp_router.run && (gs_csp_router.thread != 0)); + + // Close connections in state "RDP closing" - instead of waiting for timeout +#ifdef CSP_USE_RDP + { + size_t max_connections; + const csp_conn_t * conn = csp_conn_get_array(&max_connections); + if (conn && max_connections) { + for (unsigned int i = 0; i < max_connections; ++i, ++conn) { + if ((conn->state == CONN_OPEN) && (conn->rdp.state == RDP_CLOSE_WAIT)) { + log_info("Force close RDP %p in state closing", conn); + csp_close((csp_conn_t *) conn); + } + } + } + } +#endif + + // wait for RDP connections to close + unsigned int open = gs_csp_conn_get_open(); + if (open) { + const unsigned int MAX_TIMEOUT_MS = 30000; + log_info("Waiting up to %u mS for %u connection(s) to timeout/close ...", MAX_TIMEOUT_MS, open); + const uint32_t start_ms = gs_time_rel_ms(); + while (gs_csp_conn_get_open() && (gs_time_diff_ms(start_ms, gs_time_rel_ms()) < MAX_TIMEOUT_MS)) { + gs_time_sleep_ms(200); + } + } + + log_info("Waiting for CSP router task to stop ..."); + gs_csp_router.run = false; + csp_qfifo_wake_up(); + gs_error_t error = gs_thread_join(gs_csp_router.thread, NULL); + memset(&gs_csp_router, 0, sizeof(gs_csp_router)); + log_info("CSP router task stopped"); + return error; +} + +gs_error_t gs_csp_router_task_start(size_t stack_size, gs_thread_priority_t priority) +{ + if (gs_csp_router.run) { + return GS_ERROR_IN_USE; + } + + gs_csp_router.run = true; + gs_error_t error = gs_thread_create("RTE", gs_csp_router_task, NULL, stack_size, priority, + GS_THREAD_CREATE_JOINABLE, &gs_csp_router.thread); + if (error) { + memset(&gs_csp_router, 0, sizeof(gs_csp_router)); + } + return error; +} diff --git a/gomspace/libgscsp/src/rtable.c b/gomspace/libgscsp/src/rtable.c new file mode 100644 index 00000000..f836e3d0 --- /dev/null +++ b/gomspace/libgscsp/src/rtable.c @@ -0,0 +1,69 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include "local.h" + +// Return interface, if only one configured +static csp_iface_t * get_single_if(unsigned int * return_count) +{ + unsigned int count = 0; + csp_iface_t * found = NULL; + + for (csp_iface_t * ifc = csp_iflist_get(); ifc; ifc = ifc->next) { + if (strcasecmp(ifc->name, "LOOP") == 0) { + // ignore loopback + } else { + ++count; + found = ifc; + } + } + *return_count = count; + return found; +} + +gs_error_t gs_csp_rtable_load(const char * rtable, bool set_default_route, bool use_command_line_option) +{ + //csp_rtable_clear(); + +#if GS_CSP_COMMAND_LINE_SUPPORT + if (use_command_line_option && gs_string_empty(rtable)) { + // try rtable from command line (if set) + rtable = gs_csp_command_line_get_rtable(); + } +#endif + + if (gs_string_empty(rtable) == false) { + + if (csp_rtable_check(rtable) > 0) { + csp_rtable_load(rtable); + log_info("%s: loaded routing table [%s]", __FUNCTION__, rtable); + return GS_OK; + } + + log_warning("%s: ignoring route table: [%s] due to error(s)", __FUNCTION__, rtable); + } + + if (set_default_route) { + unsigned int count = 0; + csp_iface_t * ifc = get_single_if(&count); + if (count == 0) { + log_warning("%s: no interfaces configured", __FUNCTION__); + return GS_ERROR_NOT_FOUND; + } + + if (count > 1) { + log_warning("%s: %u interfaces configured - will not set default routes", __FUNCTION__, count); + return GS_ERROR_AMBIGUOUS; + } + + // set default route + int res = csp_route_set(CSP_DEFAULT_ROUTE, ifc, CSP_NODE_MAC); + if (res != CSP_ERR_NONE) { + log_warning("%s: failed to set default route on interface: [%s], CSP error: %d", __FUNCTION__, ifc->name, res); + return gs_csp_error(res); + } + } + + return GS_OK; +} diff --git a/gomspace/libgscsp/src/service_dispatcher.c b/gomspace/libgscsp/src/service_dispatcher.c new file mode 100644 index 00000000..507549af --- /dev/null +++ b/gomspace/libgscsp/src/service_dispatcher.c @@ -0,0 +1,213 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include +#include +#include "../lib/libcsp/src/csp_conn.h" // internal libcsp header +#include "local.h" + +static GS_LOG_GROUP(gs_cspdispatcher_log, "cspdispatcher", GS_LOG_CAT_CSP, LOG_DEFAULT_MASK); +#undef LOG_DEFAULT +#define LOG_DEFAULT gs_cspdispatcher_log + +#define WD_TIMEOUT_SECOUNDS 30 +#define DEFAULT_TIMEOUT_MS (((WD_TIMEOUT_SECOUNDS * 1000) / 3) * 2) + +struct gs_csp_service_dispatcher { + // Configuration + const gs_csp_service_dispatcher_conf_t * conf; + // Run or stop/exit. + bool run; + // Server socket + csp_socket_t * socket; + // Software watchdog + gs_swwd_hdl_t * wd; + // Thread handle. + gs_thread_t thread; +}; + +static void * service_dispatcher_task(void * parameter) +{ + gs_csp_service_dispatcher_t handle = parameter; + + unsigned int timeout_ms = (handle->conf->callback) ? 0 : DEFAULT_TIMEOUT_MS; + + log_debug("[%s] entering connection loop, timeout: %u mS", handle->conf->name, timeout_ms); + + while (handle->run) { + if (handle->wd) { + gs_swwd_touch(handle->wd); + } + + /* Wait for incoming connection, or timeout */ + csp_conn_t * conn = csp_accept(handle->socket, timeout_ms); + + if (conn) { + unsigned int in_port = csp_conn_dport(conn); + + log_debug("[%s] new connection %p on port: %u, source: %d:%d, flags: 0x%x", + handle->conf->name, conn, in_port, csp_conn_src(conn), csp_conn_sport(conn), csp_conn_flags(conn)); + + gs_csp_service_handler_t handler; + if (in_port < handle->conf->handler_array_size) { + handler = handle->conf->handler_array[in_port]; + } else { + handler = NULL; + } + + if (handler) { + gs_error_t error = (handler)(conn); + log_debug("[%s] connection on port: %u processed by %p, error: %s", + handle->conf->name, in_port, handler, gs_error_string(error)); + } else { + log_warning("[%s] no handler on port: %u - closing connection: source: %d:%d, flags: 0x%x", + handle->conf->name, in_port, csp_conn_src(conn), csp_conn_sport(conn), csp_conn_flags(conn)); + csp_close(conn); + } + } + + if (handle->conf->callback) { + timeout_ms = handle->conf->callback(); + if (timeout_ms > DEFAULT_TIMEOUT_MS) { + timeout_ms = DEFAULT_TIMEOUT_MS; + } + } + } + + log_debug("[%s] terminating ...", handle->conf->name); + gs_thread_exit(NULL); +} + +static gs_error_t service_dispatcher_create(const gs_csp_service_dispatcher_conf_t * conf, + size_t stack_size, + gs_thread_priority_t priority, + gs_csp_service_dispatcher_t * return_handle) +{ + gs_csp_service_dispatcher_t handle = calloc(1, sizeof(*handle)); + if (handle == 0) { + return GS_ERROR_ALLOC; + } + + *return_handle = handle; + + handle->conf = conf; + + // Create watchdog + if (conf->disable_watchdog == false) { + gs_error_t error = gs_swwd_register(&handle->wd, WD_TIMEOUT_SECOUNDS, NULL, NULL, conf->name); + if (error) { + log_error("[%s] gs_swwd_register(%s, %u) failed, error: %d", + conf->name, conf->name, WD_TIMEOUT_SECOUNDS, error); + handle->wd = NULL; + return error; + } + } + + // Open "server" socket + handle->socket = csp_socket(conf->socket_options); + if (handle->socket == NULL) { + log_error("[%s] csp_socket(0) failed", + conf->name); + return GS_ERROR_ALLOC; + } + + // Bind to port(s) to socket + for (unsigned int i = 0; i < conf->handler_array_size; ++i) { + if (conf->handler_array[i]) { + int res = csp_bind(handle->socket, i); + if (res) { + log_error("[%s] csp_bind(socket: %p, port: %u) failed, result: %d", + conf->name, handle->socket, i, res); + return GS_ERROR_IN_USE; + } + } + } + + // Bind on "any" port? + if (conf->bind_any) { + int res = csp_bind(handle->socket, CSP_ANY); + if (res) { + log_error("[%s] csp_bind(socket: %p, port: %u) failed, result: %d", + conf->name, handle->socket, CSP_ANY, res); + return GS_ERROR_IN_USE; + } + } + + // Create listen backlog + { + size_t backlog = conf->listen_backlog ? conf->listen_backlog : 10; + int res = csp_listen(handle->socket, backlog); + if (res) { + log_error("[%s] csp_listen(%p, %zu) failed, result: %d", + conf->name, handle->socket, backlog, res); + return GS_ERROR_UNKNOWN; + } + } + + // Launch thread + handle->run = true; + gs_error_t error = gs_thread_create(handle->conf->name, service_dispatcher_task, handle, stack_size, priority, + GS_THREAD_CREATE_JOINABLE, &handle->thread); + if (error) { + handle->thread = 0; + } + + return error; +} + +gs_error_t gs_csp_service_dispatcher_create(const gs_csp_service_dispatcher_conf_t * conf, + size_t stack_size, + gs_thread_priority_t priority, + gs_csp_service_dispatcher_t * return_handle) +{ + GS_CHECK_ARG(conf != NULL); + + gs_log_group_register(gs_cspdispatcher_log); + + gs_csp_service_dispatcher_t handle; + gs_error_t error = service_dispatcher_create(conf, stack_size, priority, &handle); + if (error) { + //gs_csp_service_dispatcher_destroy(handle); + handle = NULL; + } + + if (return_handle) { + *return_handle = handle; + } + + return error; +} + +gs_error_t gs_csp_service_dispatcher_wake_up(gs_csp_service_dispatcher_t handle) +{ + GS_CHECK_HANDLE(handle && handle->socket && handle->socket->socket); + csp_packet_t * packet = NULL; + int res = csp_queue_enqueue(handle->socket->socket, &packet, 0); + return (res == CSP_QUEUE_OK) ? GS_OK : GS_ERROR_FULL; +} + +gs_error_t gs_csp_service_dispatcher_destroy(gs_csp_service_dispatcher_t handle) +{ + GS_CHECK_HANDLE(handle && handle->conf); + + log_debug("[%s] stopping dispatcher ...", handle->conf->name); + + handle->run = false; + if (handle->thread) { + gs_csp_service_dispatcher_wake_up(handle); + gs_thread_join(handle->thread, NULL); + } + + csp_close(handle->socket); + + if (handle->wd) { + gs_swwd_deregister(&handle->wd); + } + + memset(handle, 0, sizeof(*handle)); + free(handle); + + return GS_OK; +} diff --git a/gomspace/libgscsp/src/service_handler.c b/gomspace/libgscsp/src/service_handler.c new file mode 100644 index 00000000..b602847d --- /dev/null +++ b/gomspace/libgscsp/src/service_handler.c @@ -0,0 +1,86 @@ +/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ + +#include +#include +#include +#include + +// callback for processing packets on a connection. +typedef void (*csp_service_packet_handler_t)(csp_conn_t * conn, csp_packet_t * packet); + +// Process all packets on the connectio and close it when done. +static gs_error_t call_csp_packet_handler(csp_conn_t * conn, csp_service_packet_handler_t handler) +{ + csp_packet_t *packet; + while ((packet = csp_read(conn, 0))) { + (handler)(conn, packet); + } + csp_close(conn); + return GS_OK; +} + +gs_error_t gs_csp_cmp_service_handler(csp_conn_t * conn) +{ + return call_csp_packet_handler(conn, csp_service_handler); +} + +gs_error_t gs_csp_ping_service_handler(csp_conn_t * conn) +{ + return call_csp_packet_handler(conn, csp_service_handler); +} + +gs_error_t gs_csp_ps_service_handler(csp_conn_t * conn) +{ + return call_csp_packet_handler(conn, csp_service_handler); +} + +static void memfree(csp_conn_t * conn, csp_packet_t * packet) +{ + uint32_t mem_free = 0; + + gs_mem_ram_type_t ram_type = gs_mem_get_ram_default(); + gs_mem_ram_stat_t ram_stat; + if(gs_mem_get_ram_stat(ram_type, &ram_stat) == GS_OK) { + mem_free = ram_stat.available; + } + + mem_free = util_hton32(mem_free); + memcpy(packet->data, &mem_free, sizeof(mem_free)); + packet->length = sizeof(mem_free); + + if (!csp_send(conn, packet, 0)) { + csp_buffer_free(packet); + } +} + +gs_error_t gs_csp_mem_free_service_handler(csp_conn_t * conn) +{ + return call_csp_packet_handler(conn, memfree); +} + +gs_error_t gs_csp_reboot_service_handler(csp_conn_t * conn) +{ + return call_csp_packet_handler(conn, csp_service_handler); +} + +gs_error_t gs_csp_buf_free_service_handler(csp_conn_t * conn) +{ + return call_csp_packet_handler(conn, csp_service_handler); +} + +static void uptime(csp_conn_t * conn, csp_packet_t * packet) +{ + uint32_t time = gs_time_uptime(); + time = util_hton32(time); + memcpy(packet->data, &time, sizeof(time)); + packet->length = sizeof(time); + + if (!csp_send(conn, packet, 0)) { + csp_buffer_free(packet); + } +} + +gs_error_t gs_csp_uptime_service_handler(csp_conn_t * conn) +{ + return call_csp_packet_handler(conn, uptime); +} diff --git a/gomspace/libgscsp/src/transaction.c b/gomspace/libgscsp/src/transaction.c new file mode 100644 index 00000000..96ba262a --- /dev/null +++ b/gomspace/libgscsp/src/transaction.c @@ -0,0 +1,67 @@ +/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ + +#include +#include + +gs_error_t gs_csp_transaction_persistent(csp_conn_t * conn, uint32_t timeout, const void * tx_buf, + size_t tx_len, void * rx_buf, size_t rx_max_len, size_t * rx_len) +{ + GS_CHECK_HANDLE(conn != NULL); + + size_t size = (rx_max_len > tx_len) ? rx_max_len : tx_len; + csp_packet_t * packet = csp_buffer_get(size); + if (packet == NULL) { + return GS_ERROR_ALLOC; + } + + /* Copy the request */ + if (tx_len > 0 && tx_buf != NULL) { + memcpy(packet->data, tx_buf, tx_len); + } + + packet->length = tx_len; + + if (!csp_send(conn, packet, timeout)) { + csp_buffer_free(packet); + return GS_ERROR_IO; + } + + /* If no reply is expected, return now */ + if (rx_max_len == 0) { + return GS_OK; + } + + packet = csp_read(conn, timeout); + if (packet == NULL) { + return GS_ERROR_IO; + } + + gs_error_t return_val; + if (rx_max_len >= packet->length) { + size = packet->length; + return_val = GS_OK; + } else { + csp_log_error("Reply length %u, buffer only %u", packet->length, rx_max_len); + size = rx_max_len; + return_val = GS_ERROR_OVERFLOW; + } + memcpy(rx_buf, packet->data, size); + *rx_len = packet->length; + csp_buffer_free(packet); + return return_val; +} + +gs_error_t gs_csp_transaction2(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, const void * tx_buf, + size_t tx_len, void * rx_buf, size_t rx_max_len, size_t * rx_len, uint32_t opts) +{ + csp_conn_t * conn = csp_connect(prio, dest, port, 0, opts); + if (conn == NULL) { + return GS_ERROR_HANDLE; + } + + gs_error_t res = gs_csp_transaction_persistent(conn, timeout, tx_buf, tx_len, rx_buf, rx_max_len, rx_len); + + csp_close(conn); + + return res; +} diff --git a/gomspace/libgscsp/wscript b/gomspace/libgscsp/wscript new file mode 100644 index 00000000..a78d7f56 --- /dev/null +++ b/gomspace/libgscsp/wscript @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# encoding: utf-8 +# Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. + +import gs_gcc +import gs_doc +from waflib.Build import BuildContext + +APPNAME = 'gscsp' + + +def libcsp_with_os(ctx): + if ctx.gs_is_linux(): + return 'posix' + if ctx.gs_is_freertos(): + return 'freertos' + return None + + +def libcsp_with_driver_usart(ctx): + if ctx.gs_is_linux(): + return 'linux' + return None + + +def options(ctx): + ctx.load('gs_gcc gs_doc') + gs_gcc.gs_recurse(ctx) + + +def configure(ctx): + ctx.load('gs_gcc gs_doc') + + ctx.env.append_unique('FILES_GSCSP', 'src/*.c') + ctx.env.append_unique('USE_GSCSP', ['csp', 'csp_h', 'util']) + + if ctx.options.enable_if_i2c: + ctx.env.append_unique('FILES_GSCSP', 'src/drivers/i2c/*.c') + + if ctx.gs_is_freertos(): + ctx.env.append_unique('FILES_GSCSP', 'src/drivers/can/*.c') + ctx.env.append_unique('FILES_GSCSP', 'src/drivers/kiss/*.c') + ctx.env.append_unique('FILES_GSCSP', 'src/freertos/*.c') + ctx.env.append_unique('USE_GSCSP', ['embed']) + + if ctx.gs_is_linux(): + ctx.env.append_unique('FILES_GSCSP', 'src/linux/*.c') + + # libcsp options + ctx.options.with_os = libcsp_with_os(ctx) + ctx.options.with_driver_usart = libcsp_with_driver_usart(ctx) + bindings = True if (ctx.gs_is_linux() and not ctx.gs_is_build_disabled(['shlib', 'csp_shlib'])) else False + ctx.options.enable_bindings = bindings + ctx.options.enable_python3_bindings = bindings + ctx.options.disable_stlib = True + ctx.options.enable_crc32 = True + ctx.options.with_connection_so = ctx.options.with_connection_so | 0x0040 # always CRC32, disable CSP_O_NOCRC32 + + if ctx.options.enable_if_can and ctx.options.enable_can_socketcan: + ctx.check_cc(lib='socketcan', mandatory=True) + + ctx.gs_add_doxygen(input=['include', 'lib/libcsp/include']) + + gs_gcc.gs_recurse(ctx) + + +def build(ctx): + gs_gcc.gs_recurse(ctx) + + public_include = ctx.gs_include(name=APPNAME, + includes=['include']) + + ctx.gs_objects(source=ctx.path.ant_glob(ctx.env.FILES_GSCSP), + target=APPNAME, + use=ctx.env.USE_GSCSP + [public_include]) + + ctx.gs_shlib(source=ctx.path.ant_glob(ctx.env.FILES_GSCSP), + target=APPNAME, + gs_prefix='', # make library libgscsp + gs_use_shlib=ctx.env.USE_GSCSP + [public_include]) + + ctx.gs_python_bindings(source=ctx.path.ant_glob('src/bindings/python/pygscsp.c'), + target=APPNAME, + gs_prefix='', # make library libgscsp + gs_use_shlib=ctx.env.USE_GSCSP + [APPNAME, public_include], + package='libgscsp') + + +def doc(ctx): + gs_doc.add_task_library_doc(ctx, keyvalues={ + 'gs_prod_name': 'lib'+APPNAME, + 'gs_prod_desc': 'GomSpace CSP extension', + }) + + +class Doc(BuildContext): + cmd = fun = 'doc' + + +def gs_dist(ctx): + gs_gcc.gs_recurse(ctx) + ctx.add_default_files(source_module=True) + ctx.add_files(ctx.path.ant_glob(['lib/libcsp/**/*'])) + ctx.add_license_file("CSP", "lib/libcsp/COPYING") diff --git a/gomspace/libparam_client/include/gs/param/internal/types.h b/gomspace/libparam_client/include/gs/param/internal/types.h index 5cefc4c0..2644cc62 100644 --- a/gomspace/libparam_client/include/gs/param/internal/types.h +++ b/gomspace/libparam_client/include/gs/param/internal/types.h @@ -2,8 +2,6 @@ #define GS_PARAM_INTERNAL_TYPES_H /* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -#if (GS_PARAM_INTERNAL_USE) - #include #ifdef __cplusplus @@ -126,4 +124,3 @@ struct gs_param_table_instance { } #endif #endif -#endif diff --git a/gomspace/libutil/include/gs/util/log/log.h b/gomspace/libutil/include/gs/util/log/log.h index 53470a75..9781bb09 100644 --- a/gomspace/libutil/include/gs/util/log/log.h +++ b/gomspace/libutil/include/gs/util/log/log.h @@ -610,7 +610,7 @@ gs_error_t gs_log_string_to_mask(const char *str, uint8_t current_mask, uint8_t Unless levels are individually defined, this will be the default value. */ #if !defined(GS_LOG_DISABLE_ALL) -#define GS_LOG_DISABLE_ALL 0 +#define GS_LOG_DISABLE_ALL 1 #endif /** diff --git a/test/testtasks/P60DockTestTask.cpp b/test/testtasks/P60DockTestTask.cpp index 8e929e75..2a8444e8 100644 --- a/test/testtasks/P60DockTestTask.cpp +++ b/test/testtasks/P60DockTestTask.cpp @@ -6,9 +6,9 @@ */ #include +#include "P60DockTestTask.h" #include -#include "P60DockTestTask.h" P60DockTestTask::P60DockTestTask(object_id_t objectId_): SystemObject(objectId_){ @@ -23,6 +23,10 @@ ReturnValue_t P60DockTestTask::performOperation(uint8_t operationCode) { if(sendPacket() != HasReturnvaluesIF::RETURN_OK){ return HasReturnvaluesIF::RETURN_FAILED; } + + if(getParameters() != HasReturnvaluesIF::RETURN_OK){ + return HasReturnvaluesIF::RETURN_FAILED; + } return HasReturnvaluesIF::RETURN_OK; } @@ -74,17 +78,23 @@ ReturnValue_t P60DockTestTask::sendPacket(void){ ReturnValue_t P60DockTestTask::getParameters(void) { - gs_param_table_instance_t node_hk; // int result = rparam_get_full_table(&node_hk, p60dock_node, P60_PORT_RPARAM, - uint32_t timeout; - int result = p60dock_get_hk(&node_hk, p60dock_node, timeout); + uint32_t timeout = 1000; + node_hk.rows = (gs_param_table_row_t*)p60dock_hk; + node_hk.id = P60DOCK_HK; + node_hk.row_count = p60dock_hk_count; + node_hk.memory_size = P60DOCK_HK_SIZE; + node_hk.memory = hk_mem; + int result = gs_rparam_get_full_table(&node_hk, p60dockAddress, node_hk.id, + GS_RPARAM_MAGIC_CHECKSUM, timeout); + if (result != 0) { sif::info << "Error retrieving P60 Dock housekeeping\n" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } else { uint8_t tableOffsetTemperature = 0x44; - uint8_t temperature[2]; - size_t parameterSize = 2; + int16_t temperature[2]; + size_t parameterSize = sizeof(temperature); uint32_t flags = 0; result = gs_param_get_data((gs_param_table_instance_t*) &node_hk, tableOffsetTemperature, temperature, parameterSize, flags); diff --git a/test/testtasks/P60DockTestTask.h b/test/testtasks/P60DockTestTask.h index 90d810bd..e5270263 100644 --- a/test/testtasks/P60DockTestTask.h +++ b/test/testtasks/P60DockTestTask.h @@ -11,12 +11,11 @@ #include #include #include -#include -extern "C" { +#include +#include #include #include -} class P60DockTestTask: public SystemObject, @@ -40,6 +39,7 @@ private: uint8_t hk_mem[P60DOCK_HK_SIZE]; uint8_t p60dock_node = 4; + gs_param_table_instance_t node_hk; ReturnValue_t sendPacket(void); ReturnValue_t initializeCSPStack(void); From 0a4a7de58e0f02ffc8374f42d974da904395a3b6 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 3 Dec 2020 12:49:14 +0100 Subject: [PATCH 008/360] taken over source lis3mdl device --- mission/devices/MGMHandlerLIS3MDL.cpp | 205 ++++++++++++++++---------- mission/devices/MGMHandlerLIS3MDL.h | 34 ++++- 2 files changed, 158 insertions(+), 81 deletions(-) diff --git a/mission/devices/MGMHandlerLIS3MDL.cpp b/mission/devices/MGMHandlerLIS3MDL.cpp index 099f0da4..77b1a300 100644 --- a/mission/devices/MGMHandlerLIS3MDL.cpp +++ b/mission/devices/MGMHandlerLIS3MDL.cpp @@ -1,13 +1,18 @@ #include "MGMHandlerLIS3MDL.h" + MGMHandlerLIS3MDL::MGMHandlerLIS3MDL(object_id_t objectId, object_id_t deviceCommunication, CookieIF* comCookie): DeviceHandlerBase(objectId, deviceCommunication, comCookie) { - registers[0] = 0x00; - registers[1] = 0x00; - registers[2] = 0x00; - registers[3] = 0x00; - registers[4] = 0x00; +#if OBSW_ENHANCED_PRINTOUT == 1 + debugDivider = new PeriodicOperationDivider(10); +#endif + // Set to default values right away. + registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; + registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; + registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; + registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; + registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; } @@ -29,18 +34,14 @@ void MGMHandlerLIS3MDL::doStartUp() { internalState = STATE_CHECK_REGISTERS; break; - case STATE_CHECK_REGISTERS: - if (setupMGM() == RETURN_OK) { - for (size_t i = 1; i <= MGMLIS3MDL::NR_OF_CTRL_REGISTERS; i++) { - if (registers[i - 1] != commandBuffer[i]) { - break; - } - } - setMode(_MODE_TO_ON); + case STATE_CHECK_REGISTERS: { + // Set up cached registers which will be used to configure the MGM. + if(commandExecuted) { + commandExecuted = false; + setMode(MODE_NORMAL); } - break; - + } default: break; } @@ -63,7 +64,7 @@ ReturnValue_t MGMHandlerLIS3MDL::buildTransitionDeviceCommand( break; case STATE_CHECK_REGISTERS: - *id = MGMLIS3MDL::READALL_MGM; + *id = MGMLIS3MDL::READ_CONFIG_AND_DATA; break; default: @@ -88,25 +89,33 @@ uint8_t MGMHandlerLIS3MDL::writeCommand(uint8_t command, bool continuousCom) { return command; } -ReturnValue_t MGMHandlerLIS3MDL::setupMGM() { +void MGMHandlerLIS3MDL::setupMgm() { - registers[0] = (1 << MGMLIS3MDL::TEMP_EN) | (1 << MGMLIS3MDL::OM1) - | (1 << MGMLIS3MDL::DO0) | (1 << MGMLIS3MDL::DO1) - | (1 << MGMLIS3MDL::DO2); - registers[1] = 0; - registers[2] = 0; - registers[3] = (1 << MGMLIS3MDL::OMZ1); - registers[4] = 0; - - return prepareCtrlRegisterWrite(); + registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; + registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; + registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; + registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; + registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; + prepareCtrlRegisterWrite(); } ReturnValue_t MGMHandlerLIS3MDL::buildNormalDeviceCommand( DeviceCommandId_t *id) { - //defines CommandID of MGM in normal operation and build command from command - *id = MGMLIS3MDL::READALL_MGM; - return buildCommandFromCommand(*id, NULL, 0); + // Data/config register will be read in an alternating manner. + if(communicationStep == CommunicationStep::DATA) { + lastSentCommand = MGMLIS3MDL::READ_CONFIG_AND_DATA; + *id = MGMLIS3MDL::READ_CONFIG_AND_DATA; + communicationStep = CommunicationStep::TEMPERATURE; + return buildCommandFromCommand(*id, NULL, 0); + } + else { + lastSentCommand = MGMLIS3MDL::READ_TEMPERATURE; + *id = MGMLIS3MDL::READ_TEMPERATURE; + communicationStep = CommunicationStep::DATA; + return buildCommandFromCommand(*id, NULL, 0); + } + } ReturnValue_t MGMHandlerLIS3MDL::buildCommandFromCommand( @@ -114,13 +123,22 @@ ReturnValue_t MGMHandlerLIS3MDL::buildCommandFromCommand( size_t commandDataLen) { lastSentCommand = deviceCommand; switch(deviceCommand) { - case(MGMLIS3MDL::READALL_MGM): { + case(MGMLIS3MDL::READ_CONFIG_AND_DATA): { std::memset(commandBuffer, 0, sizeof(commandBuffer)); - commandBuffer[0] = readCommand(0, true); + commandBuffer[0] = readCommand(MGMLIS3MDL::CTRL_REG1, true); rawPacket = commandBuffer; - rawPacketLen = sizeof(commandBuffer); - return HasReturnvaluesIF::RETURN_OK; + rawPacketLen = MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1; + return RETURN_OK; + } + case(MGMLIS3MDL::READ_TEMPERATURE): { + std::memset(commandBuffer, 0, 3); + commandBuffer[0] = readCommand(MGMLIS3MDL::TEMP_LOWBYTE, true); + + rawPacket = commandBuffer; + rawPacketLen = 3; + return RETURN_OK; + } case(MGMLIS3MDL::IDENTIFY_DEVICE): { return identifyDevice(); } @@ -128,7 +146,8 @@ ReturnValue_t MGMHandlerLIS3MDL::buildCommandFromCommand( return enableTemperatureSensor(commandData, commandDataLen); } case(MGMLIS3MDL::SETUP_MGM): { - return setupMGM(); + setupMgm(); + return HasReturnvaluesIF::RETURN_OK; } case(MGMLIS3MDL::ACCURACY_OP_MODE_SET): { return setOperatingMode(commandData, commandDataLen); @@ -137,7 +156,6 @@ ReturnValue_t MGMHandlerLIS3MDL::buildCommandFromCommand( lastSentCommand = DeviceHandlerIF::NO_COMMAND; return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; } - } return HasReturnvaluesIF::RETURN_FAILED; } @@ -155,22 +173,33 @@ ReturnValue_t MGMHandlerLIS3MDL::identifyDevice() { ReturnValue_t MGMHandlerLIS3MDL::scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId, size_t *foundLen) { *foundLen = len; - if (len == MGMLIS3MDL::TOTAL_NR_OF_ADRESSES + 1) { + if (len == MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1) { *foundLen = len; - *foundId = MGMLIS3MDL::READALL_MGM; - //WHO AM I test - if (*(start + 16) != MGMLIS3MDL::DEVICE_ID) { + *foundId = MGMLIS3MDL::READ_CONFIG_AND_DATA; + // Check validity by checking config registers + if (start[1] != registers[0] or start[2] != registers[1] or + start[3] != registers[2] or start[4] != registers[3] or + start[5] != registers[4]) { return DeviceHandlerIF::INVALID_DATA; } + if(mode == _MODE_START_UP) { + commandExecuted = true; + } - } else if (len == MGMLIS3MDL::SETUP_REPLY) { + } + else if(len == MGMLIS3MDL::TEMPERATURE_REPLY_LEN) { + *foundLen = len; + *foundId = MGMLIS3MDL::READ_TEMPERATURE; + } + else if (len == MGMLIS3MDL::SETUP_REPLY_LEN) { *foundLen = len; *foundId = MGMLIS3MDL::SETUP_MGM; - } else if (len == SINGLE_COMMAND_ANSWER_LEN) { + } + else if (len == SINGLE_COMMAND_ANSWER_LEN) { *foundLen = len; *foundId = lastSentCommand; - } else { - + } + else { return DeviceHandlerIF::INVALID_DATA; } @@ -193,43 +222,53 @@ ReturnValue_t MGMHandlerLIS3MDL::interpretDeviceReply(DeviceCommandId_t id, case MGMLIS3MDL::SETUP_MGM: { break; } - case MGMLIS3MDL::READALL_MGM: { + case MGMLIS3MDL::READ_CONFIG_AND_DATA: { // TODO: Store configuration and sensor values in new local datasets. - registers[0] = *(packet + 33); - registers[1] = *(packet + 34); - registers[2] = *(packet + 35); - registers[3] = *(packet + 36); - registers[4] = *(packet + 37); - uint8_t reg2_value = *(packet + 34); - uint8_t scale = getFullScale(®2_value); + uint8_t scale = getFullScale(registers[2]); float sensitivityFactor = getSensitivityFactor(scale); - int16_t x_value_raw; - int16_t y_value_raw; - int16_t z_value_raw; - int16_t temp_value_raw; - //size_t size = 2; - uint8_t *accessBuffer; - accessBuffer = const_cast(packet + 41); + int16_t mgmMeasurementRawX = packet[MGMLIS3MDL::X_HIGHBYTE_IDX] << 8 + | packet[MGMLIS3MDL::X_LOWBYTE_IDX] ; + int16_t mgmMeasurementRawY = packet[MGMLIS3MDL::Y_HIGHBYTE_IDX] << 8 + | packet[MGMLIS3MDL::Y_LOWBYTE_IDX] ; + int16_t mgmMeasurementRawZ = packet[MGMLIS3MDL::Z_HIGHBYTE_IDX] << 8 + | packet[MGMLIS3MDL::Z_LOWBYTE_IDX] ; - x_value_raw = *(accessBuffer + 1) << 8 | *(accessBuffer); - accessBuffer += 2; - y_value_raw = *(accessBuffer + 1) << 8 | *(accessBuffer); - accessBuffer += 2; - z_value_raw = *(accessBuffer + 1) << 8 | *(accessBuffer); - accessBuffer += 2; - - temp_value_raw = *(accessBuffer + 1) << 8 | *(accessBuffer); - - float x_value = static_cast(x_value_raw) * sensitivityFactor; - float y_value = static_cast(y_value_raw) * sensitivityFactor; - float z_value = static_cast(z_value_raw) * sensitivityFactor; - float temp_value = 25.0 + ((static_cast(temp_value_raw)) / 8.0); + // Target value in microtesla + float mgmX = static_cast(mgmMeasurementRawX) * sensitivityFactor + * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + float mgmY = static_cast(mgmMeasurementRawY) * sensitivityFactor + * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + float mgmZ = static_cast(mgmMeasurementRawZ) * sensitivityFactor + * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; +#if OBSW_ENHANCED_PRINTOUT == 1 + if(debugDivider->checkAndIncrement()) { + sif::info << "MGMHandlerLIS3: Magnetic field strength in" + " microtesla:" << std::endl; + // Set terminal to utf-8 if there is an issue with micro printout. + sif::info << "X: " << mgmX << " \xC2\xB5T" << std::endl; + sif::info << "Y: " << mgmY << " \xC2\xB5T" << std::endl; + sif::info << "Z: " << mgmZ << " \xC2\xB5T" << std::endl; + } +#endif break; } + case MGMLIS3MDL::READ_TEMPERATURE: { + int16_t tempValueRaw = packet[2] << 8 | packet[1]; + float tempValue = 25.0 + ((static_cast(tempValueRaw)) / 8.0); +#if OBSW_ENHANCED_PRINTOUT == 1 + if(debugDivider->check()) { + // Set terminal to utf-8 if there is an issue with micro printout. + sif::info << "MGMHandlerLIS3: Temperature: " << tempValue<< " °C" + << std::endl; + } +#endif + break; + } + default: { return DeviceHandlerIF::UNKNOW_DEVICE_REPLY; } @@ -238,12 +277,12 @@ ReturnValue_t MGMHandlerLIS3MDL::interpretDeviceReply(DeviceCommandId_t id, return RETURN_OK; } -uint8_t MGMHandlerLIS3MDL::getFullScale(uint8_t *reg2) { +uint8_t MGMHandlerLIS3MDL::getFullScale(uint8_t ctrlRegister2) { bool FS0 = false; bool FS1 = false; - if ((*reg2 >> 5) == 1) + if ((ctrlRegister2 >> 5) == 1) FS0 = true; - if ((*reg2 >> 6) == 1) + if ((ctrlRegister2 >> 6) == 1) FS1 = true; if ((FS0 == true) && (FS1 == true)) return 16; @@ -333,7 +372,8 @@ void MGMHandlerLIS3MDL::fillCommandAndReplyMap() { * We dont read single registers, we just expect special * reply from he Readall_MGM */ - insertInCommandAndReplyMap(MGMLIS3MDL::READALL_MGM, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::READ_CONFIG_AND_DATA, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::READ_TEMPERATURE, 1); insertInCommandAndReplyMap(MGMLIS3MDL::SETUP_MGM, 1); insertInCommandAndReplyMap(MGMLIS3MDL::IDENTIFY_DEVICE, 1); insertInCommandAndReplyMap(MGMLIS3MDL::TEMP_SENSOR_ENABLE, 1); @@ -348,7 +388,7 @@ ReturnValue_t MGMHandlerLIS3MDL::prepareCtrlRegisterWrite() { commandBuffer[i + 1] = registers[i]; } rawPacket = commandBuffer; - rawPacketLen = MGMLIS3MDL::NR_OF_CTRL_REGISTERS; + rawPacketLen = MGMLIS3MDL::NR_OF_CTRL_REGISTERS + 1; // We dont have to check if this is working because we just did it return RETURN_OK; @@ -369,3 +409,16 @@ uint32_t MGMHandlerLIS3MDL::getTransitionDelayMs(Mode_t from, Mode_t to) { void MGMHandlerLIS3MDL::modeChanged(void) { internalState = STATE_NONE; } + +ReturnValue_t MGMHandlerLIS3MDL::initializeLocalDataPool( + LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_X, + new PoolEntry({0.0})); + localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_Y, + new PoolEntry({0.0})); + localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_Z, + new PoolEntry({0.0})); + localDataPoolMap.emplace(MGMLIS3MDL::TEMPERATURE_CELCIUS, + new PoolEntry({0.0})); + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/mission/devices/MGMHandlerLIS3MDL.h b/mission/devices/MGMHandlerLIS3MDL.h index eaac4381..0ff4d198 100644 --- a/mission/devices/MGMHandlerLIS3MDL.h +++ b/mission/devices/MGMHandlerLIS3MDL.h @@ -1,9 +1,14 @@ #ifndef MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ #define MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ -#include #include "devicedefinitions/MGMHandlerLIS3Definitions.h" -#include + +#include + +#include +#include + +#include /** * @brief Device handler object for the LIS3MDL 3-axis magnetometer @@ -14,6 +19,12 @@ */ class MGMHandlerLIS3MDL: public DeviceHandlerBase { public: + + enum class CommunicationStep { + DATA, + TEMPERATURE + }; + static const uint8_t INTERFACE_ID = CLASS_ID::MGM_LIS3MDL; static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MGM_LIS3MDL; //Notifies a command to change the setup parameters @@ -44,8 +55,12 @@ protected: virtual void fillCommandAndReplyMap() override; virtual void modeChanged(void) override; void setNormalDatapoolEntriesInvalid() override; + ReturnValue_t initializeLocalDataPool(LocalDataPool &localDataPoolMap, + LocalDataPoolManager &poolManager) override; + private: + /*------------------------------------------------------------------------*/ /* Device specific commands and variables */ /*------------------------------------------------------------------------*/ @@ -68,7 +83,7 @@ private: * e.g.: +- 4 gauss. See p.25 datasheet. * @return The ReturnValue does not contain the sign of the value */ - uint8_t getFullScale(uint8_t *reg2); + uint8_t getFullScale(uint8_t ctrlReg2); /** * The 16 bit value needs to be divided by the full range of a 16bit value @@ -86,7 +101,7 @@ private: */ ReturnValue_t identifyDevice(); - virtual ReturnValue_t setupMGM(); + virtual void setupMgm(); /*------------------------------------------------------------------------*/ /* Non normal commands */ @@ -114,7 +129,7 @@ private: //Single SPIcommand has 2 bytes, first for adress, second for content size_t singleComandSize = 2; //has the size for all adresses of the lis3mdl + the continous write bit - uint8_t commandBuffer[MGMLIS3MDL::TOTAL_NR_OF_ADRESSES + 1]; + uint8_t commandBuffer[MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1]; /** * We want to save the registers we set, so we dont have to read the @@ -123,6 +138,9 @@ private: */ uint8_t registers[MGMLIS3MDL::NR_OF_CTRL_REGISTERS]; + uint8_t statusRegister = 0; + + /** * As this is a SPI Device, we get the Answer of the last sent command in * the next read cycle, so we could check the command for identification. @@ -142,6 +160,12 @@ private: }; InternalState internalState = STATE_NONE; + CommunicationStep communicationStep = CommunicationStep::DATA; + bool commandExecuted = false; + +#if OBSW_ENHANCED_PRINTOUT == 1 + PeriodicOperationDivider* debugDivider; +#endif }; From 08fa7d9e8b6ae22193fb38396a9c2b222008674d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 3 Dec 2020 12:57:44 +0100 Subject: [PATCH 009/360] device definition adaptions taken over --- .../MGMHandlerLIS3Definitions.h | 62 ++++++++++++++++--- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/mission/devices/devicedefinitions/MGMHandlerLIS3Definitions.h b/mission/devices/devicedefinitions/MGMHandlerLIS3Definitions.h index 388b11e2..2518af15 100644 --- a/mission/devices/devicedefinitions/MGMHandlerLIS3Definitions.h +++ b/mission/devices/devicedefinitions/MGMHandlerLIS3Definitions.h @@ -1,6 +1,9 @@ #ifndef MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERLIS3DEFINITIONS_H_ #define MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERLIS3DEFINITIONS_H_ +#include +#include +#include #include namespace MGMLIS3MDL { @@ -12,11 +15,14 @@ enum opMode { LOW, MEDIUM, HIGH, ULTRA }; +static constexpr uint8_t GAUSS_TO_MICROTESLA_FACTOR = 100; + static const DeviceCommandId_t SETUP_MGM = 0x00; -static const DeviceCommandId_t READALL_MGM = 0x01; -static const DeviceCommandId_t IDENTIFY_DEVICE = 0x02; -static const DeviceCommandId_t TEMP_SENSOR_ENABLE = 0x03; -static const DeviceCommandId_t ACCURACY_OP_MODE_SET = 0x04; +static const DeviceCommandId_t READ_CONFIG_AND_DATA = 0x01; +static const DeviceCommandId_t READ_TEMPERATURE = 0x02; +static const DeviceCommandId_t IDENTIFY_DEVICE = 0x03; +static const DeviceCommandId_t TEMP_SENSOR_ENABLE = 0x04; +static const DeviceCommandId_t ACCURACY_OP_MODE_SET = 0x05; //Number of all control registers static const uint8_t NR_OF_CTRL_REGISTERS = 5; @@ -24,7 +30,9 @@ static const uint8_t NR_OF_CTRL_REGISTERS = 5; static const uint8_t NR_OF_REGISTERS = 19; //Total number of adresses for all registers static const uint8_t TOTAL_NR_OF_ADRESSES = 52; -static const uint8_t SETUP_REPLY = 6; +static const uint8_t NR_OF_DATA_AND_CFG_REGISTERS = 14; +static const uint8_t TEMPERATURE_REPLY_LEN = 3; +static const uint8_t SETUP_REPLY_LEN = 6; /*------------------------------------------------------------------------*/ /* Register adresses */ @@ -45,19 +53,26 @@ static const uint8_t CTRL_REG4 = 0b00100011; static const uint8_t CTRL_REG5 = 0b00100100; //Register adress to access status register +static const uint8_t STATUS_REG_IDX = 8; static const uint8_t STATUS_REG = 0b00100111; //Register adress to access low byte of x-axis +static const uint8_t X_LOWBYTE_IDX = 9; static const uint8_t X_LOWBYTE = 0b00101000; //Register adress to access high byte of x-axis +static const uint8_t X_HIGHBYTE_IDX = 10; static const uint8_t X_HIGHBYTE = 0b00101001; //Register adress to access low byte of y-axis +static const uint8_t Y_LOWBYTE_IDX = 11; static const uint8_t Y_LOWBYTE = 0b00101010; //Register adress to access high byte of y-axis +static const uint8_t Y_HIGHBYTE_IDX = 12; static const uint8_t Y_HIGHBYTE = 0b00101011; //Register adress to access low byte of z-axis +static const uint8_t Z_LOWBYTE_IDX = 13; static const uint8_t Z_LOWBYTE = 0b00101100; //Register adress to access high byte of z-axis +static const uint8_t Z_HIGHBYTE_IDX = 14; static const uint8_t Z_HIGHBYTE = 0b00101101; //Register adress to access low byte of temperature sensor @@ -66,7 +81,7 @@ static const uint8_t TEMP_LOWBYTE = 0b00101110; static const uint8_t TEMP_HIGHBYTE = 0b00101111; /*------------------------------------------------------------------------*/ -/* Initialize Setup Register set bits +/* Initialize Setup Register set bits */ /*------------------------------------------------------------------------*/ /* General transfer bits */ // Read=1 / Write=0 Bit @@ -84,6 +99,8 @@ static const uint8_t DO2 = 4; // Output data rate bit 4 static const uint8_t OM0 = 5; // XY operating mode bit 5 static const uint8_t OM1 = 6; // XY operating mode bit 6 static const uint8_t TEMP_EN = 7; // Temperature sensor enable enabled = 1 +static const uint8_t CTRL_REG1_DEFAULT = (1 << TEMP_EN) | (1 << OM1) | + (1 << DO0) | (1 << DO1) | (1 << DO2); /* CTRL_REG2 bits */ //reset configuration registers and user registers @@ -91,6 +108,7 @@ static const uint8_t SOFT_RST = 2; static const uint8_t REBOOT = 3; //reboot memory content static const uint8_t FSO = 5; //full-scale selection bit 5 static const uint8_t FS1 = 6; //full-scale selection bit 6 +static const uint8_t CTRL_REG2_DEFAULT = 0; /* CTRL_REG3 bits */ static const uint8_t MD0 = 0; //Operating mode bit 0 @@ -98,18 +116,48 @@ static const uint8_t MD1 = 1; //Operating mode bit 1 //SPI serial interface mode selection enabled = 3-wire-mode static const uint8_t SIM = 2; static const uint8_t LP = 5; //low-power mode +static const uint8_t CTRL_REG3_DEFAULT = 0; /* CTRL_REG4 bits */ //big/little endian data selection enabled = MSb at lower adress static const uint8_t BLE = 1; static const uint8_t OMZ0 = 2; //Z operating mode bit 2 static const uint8_t OMZ1 = 3; //Z operating mode bit 3 +static const uint8_t CTRL_REG4_DEFAULT = (1 << OMZ1); /* CTRL_REG5 bits */ static const uint8_t BDU = 6; //Block data update static const uint8_t FAST_READ = 7; //Fast read enabled = 1 +static const uint8_t CTRL_REG5_DEFAULT = 0; + +static const uint32_t MGM_DATA_SET_ID = 0; + +enum MgmPoolIds: lp_id_t { + FIELD_STRENGTH_X, + FIELD_STRENGTH_Y, + FIELD_STRENGTH_Z, + TEMPERATURE_CELCIUS +}; + +class MgmPrimaryDataset: public StaticLocalDataSet<3 * sizeof(float)> { +public: + MgmPrimaryDataset(HasLocalDataPoolIF* hkOwner): + StaticLocalDataSet(hkOwner, MGM_DATA_SET_ID) {} + + MgmPrimaryDataset(object_id_t mgmId): + StaticLocalDataSet(sid_t(mgmId, MGM_DATA_SET_ID)) {} + + lp_var_t angVelocityX = lp_var_t(sid.objectId, + FIELD_STRENGTH_X, this); + lp_var_t angVelocityY = lp_var_t(sid.objectId, + FIELD_STRENGTH_Y, this); + lp_var_t angVelocityZ = lp_var_t(sid.objectId, + FIELD_STRENGTH_Z, this); + lp_var_t temperature = lp_var_t(sid.objectId, + TEMPERATURE_CELCIUS, this); +}; + } - #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERLIS3DEFINITIONS_H_ */ From 87e121f0160267cb5b4859ca205fcbd0cd73dd82 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Fri, 4 Dec 2020 14:14:08 +0100 Subject: [PATCH 010/360] parts of p60dock handler --- bsp_linux/InitMission.cpp | 10 + bsp_linux/bsp_linux.mk | 2 + bsp_linux/comIF/ArduinoComIF.cpp | 648 +++++++++--------- bsp_linux/comIF/P60DockComIF.cpp | 120 ++++ bsp_linux/comIF/P60DockComIF.h | 52 ++ .../comIF/{ => cookies}/ArduinoCookie.cpp | 0 bsp_linux/comIF/{ => cookies}/ArduinoCookie.h | 0 bsp_linux/comIF/cookies/P60DockCookie.cpp | 38 + bsp_linux/comIF/cookies/P60DockCookie.h | 49 ++ fsfwconfig/OBSWConfig.h | 2 +- .../{logicalAddresses.cpp => addresses.cpp} | 2 +- .../{logicalAddresses.h => addresses.h} | 15 +- fsfwconfig/objects/systemObjectList.h | 6 +- mission/core/GenericFactory.cpp | 15 + mission/devices/P60DockHandler.cpp | 101 ++- mission/devices/P60DockHandler.h | 48 +- .../P60DockHandlerDefinitions.h | 58 ++ test/testtasks/P60DockTestTask.cpp | 87 +-- test/testtasks/P60DockTestTask.h | 19 +- 19 files changed, 830 insertions(+), 442 deletions(-) create mode 100644 bsp_linux/comIF/P60DockComIF.cpp create mode 100644 bsp_linux/comIF/P60DockComIF.h rename bsp_linux/comIF/{ => cookies}/ArduinoCookie.cpp (100%) rename bsp_linux/comIF/{ => cookies}/ArduinoCookie.h (100%) create mode 100644 bsp_linux/comIF/cookies/P60DockCookie.cpp create mode 100644 bsp_linux/comIF/cookies/P60DockCookie.h rename fsfwconfig/devices/{logicalAddresses.cpp => addresses.cpp} (52%) rename fsfwconfig/devices/{logicalAddresses.h => addresses.h} (51%) create mode 100644 mission/devices/devicedefinitions/P60DockHandlerDefinitions.h diff --git a/bsp_linux/InitMission.cpp b/bsp_linux/InitMission.cpp index 92cd0853..04e79a12 100644 --- a/bsp_linux/InitMission.cpp +++ b/bsp_linux/InitMission.cpp @@ -129,6 +129,14 @@ void InitMission::initTasks(){ sif::error << "Object add component failed" << std::endl; } + /* Device Handler */ + PeriodicTaskIF* DeviceHandler = TaskFactory::instance()-> + createPeriodicTask("Device Handler", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE, + 1, nullptr); + result = DeviceHandler->addComponent(objects::P60DOCK_HANDLER); + if(result!=HasReturnvaluesIF::RETURN_OK){ + sif::error << "Object add component failed" << std::endl; + } #if ADD_TEST_CODE == 1 // FixedTimeslotTaskIF* TestTimeslotTask = TaskFactory::instance()-> @@ -160,6 +168,8 @@ void InitMission::initTasks(){ PusHighPrio->startTask(); PusMedPrio->startTask(); PusLowPrio->startTask(); + + DeviceHandler->startTask(); #if ADD_TEST_CODE == 1 // TestTimeslotTask->startTask(); P60DockTestTask->startTask(); diff --git a/bsp_linux/bsp_linux.mk b/bsp_linux/bsp_linux.mk index f7f9a469..93bfdc78 100644 --- a/bsp_linux/bsp_linux.mk +++ b/bsp_linux/bsp_linux.mk @@ -1,4 +1,6 @@ CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/comIF/cookies/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/comIF/*.cpp) CSRC += $(wildcard $(CURRENTPATH)/*.c) CSRC += $(wildcard $(CURRENTPATH)/boardconfig/*.c) \ No newline at end of file diff --git a/bsp_linux/comIF/ArduinoComIF.cpp b/bsp_linux/comIF/ArduinoComIF.cpp index ffc59b47..77088a63 100644 --- a/bsp_linux/comIF/ArduinoComIF.cpp +++ b/bsp_linux/comIF/ArduinoComIF.cpp @@ -1,324 +1,324 @@ -#include "ArduinoCookie.h" -#include "ArduinoComIF.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -ArduinoCommInterface::ArduinoCommInterface(object_id_t setObjectId, - const char *serialDevice) : - spiMap(MAX_NUMBER_OF_SPI_DEVICES), rxBuffer( - MAX_PACKET_SIZE * MAX_NUMBER_OF_SPI_DEVICES*10, true), SystemObject(setObjectId) { - initialized = false; - serialPort = ::open("/dev/ttyUSB0", O_RDWR); - - if (serialPort < 0) { - //configuration error - printf("Error %i from open: %s\n", errno, strerror(errno)); - return; - } - - struct termios tty; - memset(&tty, 0, sizeof tty); - - // Read in existing settings, and handle any error - if (tcgetattr(serialPort, &tty) != 0) { - printf("Error %i from tcgetattr: %s\n", errno, strerror(errno)); - return; - } - - tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity - tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication - tty.c_cflag |= CS8; // 8 bits per byte - tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control - tty.c_lflag &= ~ICANON; //Disable Canonical Mode - tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars) - tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed - tty.c_cc[VTIME] = 0; // Non Blocking - tty.c_cc[VMIN] = 0; - - cfsetispeed(&tty, B9600); //Baudrate - - if (tcsetattr(serialPort, TCSANOW, &tty) != 0) { - //printf("Error %i from tcsetattr: %s\n", errno, strerror(errno)); - return; - } - - initialized = true; - -} - -ArduinoCommInterface::~ArduinoCommInterface() { - ::close(serialPort); -} - -ReturnValue_t ArduinoCommInterface::open(Cookie **cookie, uint32_t address, - uint32_t maxReplyLen) { - //This is a hack, will be gone with https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/19 - switch ((address >> 8) & 0xff) { - case 0: - *cookie = new ArduinoCookie(ArduinoCookie::SPI, address, maxReplyLen); - spiMap.insert(address, (ArduinoCookie*) *cookie); //Yes, I *do* know that it is an ArduinoSpiCookie, I just new'd it - break; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t ArduinoCommInterface::reOpen(Cookie *cookie, uint32_t address, - uint32_t maxReplyLen) { - //too lazy right now will be irrelevant with https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/19 - return HasReturnvaluesIF::RETURN_FAILED; -} - -void ArduinoCommInterface::close(Cookie *cookie) { - //too lazy as well, find the correct Map, delete it there, then the cookie... -} - -ReturnValue_t ArduinoCommInterface::sendMessage(Cookie *cookie, uint8_t *data, - uint32_t len) { - ArduinoCookie *arduinoCookie = dynamic_cast(cookie); - if (arduinoCookie == NULL) { - return INVALID_COOKIE_TYPE; - } - - return sendMessage(arduinoCookie->command, arduinoCookie->address, data, - len); -} - -ReturnValue_t ArduinoCommInterface::getSendSuccess(Cookie *cookie) { - return RETURN_OK; -} - -ReturnValue_t ArduinoCommInterface::requestReceiveMessage(Cookie *cookie) { - return RETURN_OK; -} - -ReturnValue_t ArduinoCommInterface::readReceivedMessage(Cookie *cookie, - uint8_t **buffer, uint32_t *size) { - - handleSerialPortRx(); - - ArduinoCookie *arduinoCookie = dynamic_cast(cookie); - if (arduinoCookie == NULL) { - return INVALID_COOKIE_TYPE; - } - - *buffer = arduinoCookie->replyBuffer; - *size = arduinoCookie->receivedDataLen; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t ArduinoCommInterface::setAddress(Cookie *cookie, - uint32_t address) { - //not implemented - return RETURN_FAILED; -} - -uint32_t ArduinoCommInterface::getAddress(Cookie *cookie) { - //not implemented - return 0; -} - -ReturnValue_t ArduinoCommInterface::setParameter(Cookie *cookie, - uint32_t parameter) { - //not implemented - return RETURN_FAILED; -} - -uint32_t ArduinoCommInterface::getParameter(Cookie *cookie) { - //not implemented - return 0; -} - -ReturnValue_t ArduinoCommInterface::sendMessage(uint8_t command, - uint8_t address, const uint8_t *data, size_t dataLen) { - if (dataLen > UINT16_MAX) { - return TOO_MUCH_DATA; - } - - //being conservative here - uint8_t sendBuffer[(dataLen + 6) * 2 + 2]; - - sendBuffer[0] = DleEncoder::STX; - - uint8_t *currentPosition = sendBuffer + 1; - size_t remainingLen = sizeof(sendBuffer) - 1; - uint32_t encodedLen; - - ReturnValue_t result = DleEncoder::encode(&command, 1, currentPosition, - remainingLen, &encodedLen, false); - if (result != RETURN_OK) { - return result; - } - currentPosition += encodedLen; - remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen - - result = DleEncoder::encode(&address, 1, currentPosition, remainingLen, - &encodedLen, false); - if (result != RETURN_OK) { - return result; - } - currentPosition += encodedLen; - remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen - - uint8_t temporaryBuffer[2]; - - //note to Lukas: yes we _could_ use Serialize here, but for 16 bit it is a bit too much... - temporaryBuffer[0] = dataLen >> 8; //we checked dataLen above - temporaryBuffer[1] = dataLen; - - result = DleEncoder::encode(temporaryBuffer, 2, currentPosition, - remainingLen, &encodedLen, false); - if (result != RETURN_OK) { - return result; - } - currentPosition += encodedLen; - remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen - - //encoding the actual data - result = DleEncoder::encode(data, dataLen, currentPosition, remainingLen, - &encodedLen, false); - if (result != RETURN_OK) { - return result; - } - currentPosition += encodedLen; - remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen - - uint16_t crc = CRC::crc16ccitt(&command, 1); - crc = CRC::crc16ccitt(&address, 1, crc); - //fortunately the length is still there - crc = CRC::crc16ccitt(temporaryBuffer, 2, crc); - crc = CRC::crc16ccitt(data, dataLen, crc); - - temporaryBuffer[0] = crc >> 8; - temporaryBuffer[1] = crc; - - result = DleEncoder::encode(temporaryBuffer, 2, currentPosition, - remainingLen, &encodedLen, false); - if (result != RETURN_OK) { - return result; - } - currentPosition += encodedLen; - remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen - - if (remainingLen > 0) { - *currentPosition = DleEncoder::ETX; - } - remainingLen -= 1; - - encodedLen = sizeof(sendBuffer) - remainingLen; - - ssize_t writtenlen = write(serialPort, sendBuffer, encodedLen); - if (writtenlen < 0) { - //we could try to find out what happened... - return RETURN_FAILED; - } - if (writtenlen != encodedLen) { - //the OS failed us, we do not try to block until everything is written, as - //we can not block the whole system here - return RETURN_FAILED; - } - return RETURN_OK; -} - -void ArduinoCommInterface::handleSerialPortRx() { - uint32_t availableSpace = rxBuffer.availableWriteSpace(); - - uint8_t dataFromSerial[availableSpace]; - - ssize_t bytesRead = read(serialPort, dataFromSerial, - sizeof(dataFromSerial)); - - if (bytesRead < 0) { - return; - } - - rxBuffer.writeData(dataFromSerial, bytesRead); - - uint8_t dataReceivedSoFar[rxBuffer.maxSize()]; - - uint32_t dataLenReceivedSoFar = 0; - - rxBuffer.readData(dataReceivedSoFar, sizeof(dataReceivedSoFar), true, - &dataLenReceivedSoFar); - - //look for STX - size_t firstSTXinRawData = 0; - while ((firstSTXinRawData < dataLenReceivedSoFar) - && (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX)) { - firstSTXinRawData++; - } - - if (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX) { - //there is no STX in our data, throw it away... - rxBuffer.deleteData(dataLenReceivedSoFar); - return; - } - - uint8_t packet[MAX_PACKET_SIZE]; - uint32_t packetLen; - - uint32_t readSize; - - ReturnValue_t result = DleEncoder::decode( - dataReceivedSoFar + firstSTXinRawData, - dataLenReceivedSoFar - firstSTXinRawData, &readSize, packet, - sizeof(packet), &packetLen); - - size_t toDelete = firstSTXinRawData; - if (result == HasReturnvaluesIF::RETURN_OK) { - handlePacket(packet, packetLen); - - //after handling the packet, we can delete it from the raw stream, it has been copied to packet - toDelete += readSize; - } - - //remove Data which was processed - rxBuffer.deleteData(toDelete); -} - -void ArduinoCommInterface::handlePacket(uint8_t *packet, size_t packetLen) { - uint16_t crc = CRC::crc16ccitt(packet, packetLen); - if (crc != 0) { - //CRC error - return; - } - - uint8_t command = packet[0]; - uint8_t address = packet[1]; - - uint16_t size = (packet[2] << 8) + packet[3]; - - if (size != packetLen - 6) { - //Invalid Length - return; - } - - switch (command) { - case ArduinoCookie::SPI: { - ArduinoCookie **itsComplicated; - ReturnValue_t result = spiMap.find(address, &itsComplicated); - if (result != RETURN_OK) { - //we do no know this address - return; - } - ArduinoCookie *theActualCookie = *itsComplicated; - if (packetLen > theActualCookie->maxReplySize + 6) { - packetLen = theActualCookie->maxReplySize + 6; - } - memcpy(theActualCookie->replyBuffer, packet + 4, packetLen - 6); - theActualCookie->receivedDataLen = packetLen - 6; - } - break; - default: - return; - } -} +//#include "cookies/ArduinoCookie.h" +//#include "ArduinoComIF.h" +// +//#include +//#include +//#include +//#include +//#include +//#include +//#include +// +//#include +// +//ArduinoCommInterface::ArduinoCommInterface(object_id_t setObjectId, +// const char *serialDevice) : +// spiMap(MAX_NUMBER_OF_SPI_DEVICES), rxBuffer( +// MAX_PACKET_SIZE * MAX_NUMBER_OF_SPI_DEVICES*10, true), SystemObject(setObjectId) { +// initialized = false; +// serialPort = ::open("/dev/ttyUSB0", O_RDWR); +// +// if (serialPort < 0) { +// //configuration error +// printf("Error %i from open: %s\n", errno, strerror(errno)); +// return; +// } +// +// struct termios tty; +// memset(&tty, 0, sizeof tty); +// +// // Read in existing settings, and handle any error +// if (tcgetattr(serialPort, &tty) != 0) { +// printf("Error %i from tcgetattr: %s\n", errno, strerror(errno)); +// return; +// } +// +// tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity +// tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication +// tty.c_cflag |= CS8; // 8 bits per byte +// tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control +// tty.c_lflag &= ~ICANON; //Disable Canonical Mode +// tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars) +// tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed +// tty.c_cc[VTIME] = 0; // Non Blocking +// tty.c_cc[VMIN] = 0; +// +// cfsetispeed(&tty, B9600); //Baudrate +// +// if (tcsetattr(serialPort, TCSANOW, &tty) != 0) { +// //printf("Error %i from tcsetattr: %s\n", errno, strerror(errno)); +// return; +// } +// +// initialized = true; +// +//} +// +//ArduinoCommInterface::~ArduinoCommInterface() { +// ::close(serialPort); +//} +// +//ReturnValue_t ArduinoCommInterface::open(Cookie **cookie, uint32_t address, +// uint32_t maxReplyLen) { +// //This is a hack, will be gone with https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/19 +// switch ((address >> 8) & 0xff) { +// case 0: +// *cookie = new ArduinoCookie(ArduinoCookie::SPI, address, maxReplyLen); +// spiMap.insert(address, (ArduinoCookie*) *cookie); //Yes, I *do* know that it is an ArduinoSpiCookie, I just new'd it +// break; +// default: +// return HasReturnvaluesIF::RETURN_FAILED; +// } +// return HasReturnvaluesIF::RETURN_OK; +//} +// +//ReturnValue_t ArduinoCommInterface::reOpen(Cookie *cookie, uint32_t address, +// uint32_t maxReplyLen) { +// //too lazy right now will be irrelevant with https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/19 +// return HasReturnvaluesIF::RETURN_FAILED; +//} +// +//void ArduinoCommInterface::close(Cookie *cookie) { +// //too lazy as well, find the correct Map, delete it there, then the cookie... +//} +// +//ReturnValue_t ArduinoCommInterface::sendMessage(Cookie *cookie, uint8_t *data, +// uint32_t len) { +// ArduinoCookie *arduinoCookie = dynamic_cast(cookie); +// if (arduinoCookie == NULL) { +// return INVALID_COOKIE_TYPE; +// } +// +// return sendMessage(arduinoCookie->command, arduinoCookie->address, data, +// len); +//} +// +//ReturnValue_t ArduinoCommInterface::getSendSuccess(Cookie *cookie) { +// return RETURN_OK; +//} +// +//ReturnValue_t ArduinoCommInterface::requestReceiveMessage(Cookie *cookie) { +// return RETURN_OK; +//} +// +//ReturnValue_t ArduinoCommInterface::readReceivedMessage(Cookie *cookie, +// uint8_t **buffer, uint32_t *size) { +// +// handleSerialPortRx(); +// +// ArduinoCookie *arduinoCookie = dynamic_cast(cookie); +// if (arduinoCookie == NULL) { +// return INVALID_COOKIE_TYPE; +// } +// +// *buffer = arduinoCookie->replyBuffer; +// *size = arduinoCookie->receivedDataLen; +// return HasReturnvaluesIF::RETURN_OK; +//} +// +//ReturnValue_t ArduinoCommInterface::setAddress(Cookie *cookie, +// uint32_t address) { +// //not implemented +// return RETURN_FAILED; +//} +// +//uint32_t ArduinoCommInterface::getAddress(Cookie *cookie) { +// //not implemented +// return 0; +//} +// +//ReturnValue_t ArduinoCommInterface::setParameter(Cookie *cookie, +// uint32_t parameter) { +// //not implemented +// return RETURN_FAILED; +//} +// +//uint32_t ArduinoCommInterface::getParameter(Cookie *cookie) { +// //not implemented +// return 0; +//} +// +//ReturnValue_t ArduinoCommInterface::sendMessage(uint8_t command, +// uint8_t address, const uint8_t *data, size_t dataLen) { +// if (dataLen > UINT16_MAX) { +// return TOO_MUCH_DATA; +// } +// +// //being conservative here +// uint8_t sendBuffer[(dataLen + 6) * 2 + 2]; +// +// sendBuffer[0] = DleEncoder::STX; +// +// uint8_t *currentPosition = sendBuffer + 1; +// size_t remainingLen = sizeof(sendBuffer) - 1; +// uint32_t encodedLen; +// +// ReturnValue_t result = DleEncoder::encode(&command, 1, currentPosition, +// remainingLen, &encodedLen, false); +// if (result != RETURN_OK) { +// return result; +// } +// currentPosition += encodedLen; +// remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen +// +// result = DleEncoder::encode(&address, 1, currentPosition, remainingLen, +// &encodedLen, false); +// if (result != RETURN_OK) { +// return result; +// } +// currentPosition += encodedLen; +// remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen +// +// uint8_t temporaryBuffer[2]; +// +// //note to Lukas: yes we _could_ use Serialize here, but for 16 bit it is a bit too much... +// temporaryBuffer[0] = dataLen >> 8; //we checked dataLen above +// temporaryBuffer[1] = dataLen; +// +// result = DleEncoder::encode(temporaryBuffer, 2, currentPosition, +// remainingLen, &encodedLen, false); +// if (result != RETURN_OK) { +// return result; +// } +// currentPosition += encodedLen; +// remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen +// +// //encoding the actual data +// result = DleEncoder::encode(data, dataLen, currentPosition, remainingLen, +// &encodedLen, false); +// if (result != RETURN_OK) { +// return result; +// } +// currentPosition += encodedLen; +// remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen +// +// uint16_t crc = CRC::crc16ccitt(&command, 1); +// crc = CRC::crc16ccitt(&address, 1, crc); +// //fortunately the length is still there +// crc = CRC::crc16ccitt(temporaryBuffer, 2, crc); +// crc = CRC::crc16ccitt(data, dataLen, crc); +// +// temporaryBuffer[0] = crc >> 8; +// temporaryBuffer[1] = crc; +// +// result = DleEncoder::encode(temporaryBuffer, 2, currentPosition, +// remainingLen, &encodedLen, false); +// if (result != RETURN_OK) { +// return result; +// } +// currentPosition += encodedLen; +// remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen +// +// if (remainingLen > 0) { +// *currentPosition = DleEncoder::ETX; +// } +// remainingLen -= 1; +// +// encodedLen = sizeof(sendBuffer) - remainingLen; +// +// ssize_t writtenlen = write(serialPort, sendBuffer, encodedLen); +// if (writtenlen < 0) { +// //we could try to find out what happened... +// return RETURN_FAILED; +// } +// if (writtenlen != encodedLen) { +// //the OS failed us, we do not try to block until everything is written, as +// //we can not block the whole system here +// return RETURN_FAILED; +// } +// return RETURN_OK; +//} +// +//void ArduinoCommInterface::handleSerialPortRx() { +// uint32_t availableSpace = rxBuffer.availableWriteSpace(); +// +// uint8_t dataFromSerial[availableSpace]; +// +// ssize_t bytesRead = read(serialPort, dataFromSerial, +// sizeof(dataFromSerial)); +// +// if (bytesRead < 0) { +// return; +// } +// +// rxBuffer.writeData(dataFromSerial, bytesRead); +// +// uint8_t dataReceivedSoFar[rxBuffer.maxSize()]; +// +// uint32_t dataLenReceivedSoFar = 0; +// +// rxBuffer.readData(dataReceivedSoFar, sizeof(dataReceivedSoFar), true, +// &dataLenReceivedSoFar); +// +// //look for STX +// size_t firstSTXinRawData = 0; +// while ((firstSTXinRawData < dataLenReceivedSoFar) +// && (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX)) { +// firstSTXinRawData++; +// } +// +// if (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX) { +// //there is no STX in our data, throw it away... +// rxBuffer.deleteData(dataLenReceivedSoFar); +// return; +// } +// +// uint8_t packet[MAX_PACKET_SIZE]; +// uint32_t packetLen; +// +// uint32_t readSize; +// +// ReturnValue_t result = DleEncoder::decode( +// dataReceivedSoFar + firstSTXinRawData, +// dataLenReceivedSoFar - firstSTXinRawData, &readSize, packet, +// sizeof(packet), &packetLen); +// +// size_t toDelete = firstSTXinRawData; +// if (result == HasReturnvaluesIF::RETURN_OK) { +// handlePacket(packet, packetLen); +// +// //after handling the packet, we can delete it from the raw stream, it has been copied to packet +// toDelete += readSize; +// } +// +// //remove Data which was processed +// rxBuffer.deleteData(toDelete); +//} +// +//void ArduinoCommInterface::handlePacket(uint8_t *packet, size_t packetLen) { +// uint16_t crc = CRC::crc16ccitt(packet, packetLen); +// if (crc != 0) { +// //CRC error +// return; +// } +// +// uint8_t command = packet[0]; +// uint8_t address = packet[1]; +// +// uint16_t size = (packet[2] << 8) + packet[3]; +// +// if (size != packetLen - 6) { +// //Invalid Length +// return; +// } +// +// switch (command) { +// case ArduinoCookie::SPI: { +// ArduinoCookie **itsComplicated; +// ReturnValue_t result = spiMap.find(address, &itsComplicated); +// if (result != RETURN_OK) { +// //we do no know this address +// return; +// } +// ArduinoCookie *theActualCookie = *itsComplicated; +// if (packetLen > theActualCookie->maxReplySize + 6) { +// packetLen = theActualCookie->maxReplySize + 6; +// } +// memcpy(theActualCookie->replyBuffer, packet + 4, packetLen - 6); +// theActualCookie->receivedDataLen = packetLen - 6; +// } +// break; +// default: +// return; +// } +//} diff --git a/bsp_linux/comIF/P60DockComIF.cpp b/bsp_linux/comIF/P60DockComIF.cpp new file mode 100644 index 00000000..bf97c2e3 --- /dev/null +++ b/bsp_linux/comIF/P60DockComIF.cpp @@ -0,0 +1,120 @@ +#include "P60DockComIF.h" + +#include +#include +#include +#include +#include + +P60DockComIF::P60DockComIF(object_id_t objectId) : + SystemObject(objectId) { + +} + +P60DockComIF::~P60DockComIF() { +} + +ReturnValue_t P60DockComIF::initializeInterface(CookieIF *cookie) { + if(cookie == nullptr) { + return NULLPOINTER; + } + + P60DockCookie* p60DockCookie = dynamic_cast(cookie); + uint8_t cspAddress = p60DockCookie->getCspAddress(); + char* canInterface = p60DockCookie->getCanIf(); + int bitrate = p60DockCookie->getBitrate(); + + int buf_count = 10; + int buf_size = 300; + /* Init CSP and CSP buffer system */ + if (csp_init(cspAddress) != CSP_ERR_NONE + || csp_buffer_init(buf_count, buf_size) != CSP_ERR_NONE) { + sif::error << "Failed to init CSP\r\n" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + int promisc = 0; // Set filter mode on + csp_iface_t *csp_if_ptr = &csp_if; + csp_if_ptr = csp_can_socketcan_init(canInterface, bitrate, promisc); + + /* Set default route and start router */ + uint8_t address = CSP_DEFAULT_ROUTE; + uint8_t netmask = 0; + uint8_t mac = CSP_NODE_MAC; + int result = csp_rtable_set(address, netmask, csp_if_ptr, mac); + if(result != CSP_ERR_NONE){ + sif::error << "Failed to add can interface to router table" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + /* Start the route task */ + unsigned int task_stack_size = 512; + unsigned int priority = 0; + result = csp_route_start_task(task_stack_size, priority); + if(result != CSP_ERR_NONE){ + sif::error << "Failed to start csp route task" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t P60DockComIF::sendMessage(CookieIF *cookie, + const uint8_t * sendData, size_t sendLen) { + P60DockCookie* p60DockCookie = dynamic_cast (cookie); + MessageType_t messageType = p60DockCookie->getMessageType(); + + switch(messageType){ + case(P60DockCookie::REBOOT):{ + csp_reboot(p60DockCookie->getCspAddress()); + break; + } + default: + break; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t P60DockComIF::getSendSuccess(CookieIF *cookie) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t P60DockComIF::requestReceiveMessage(CookieIF *cookie, + size_t requestLen) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t P60DockComIF::readReceivedMessage(CookieIF *cookie, + uint8_t** buffer, size_t* size) { + P60DockCookie* p60DockCookie = dynamic_cast (cookie); + MessageType_t messageType = p60DockCookie->getMessageType(); + + switch(messageType){ + case(P60DockCookie::READ_MODULE_CONFIG):{ + uint32_t timeout = 1000; + uint8_t p60dockAddress = p60DockCookie->getCspAddress(); + gs_param_table_instance_t moduleConfig; + moduleConfig.rows = moduleConfigTable; + moduleConfig.id = p60dockAddress; + moduleConfig.row_count = p60dock_hk_count; + moduleConfig.memory_size = P60DOCK_HK_SIZE; + moduleConfig.memory = *buffer; + /* Read complete module configuration table from P60 Dock and store data + * in buffer */ + int result = gs_rparam_get_full_table(&moduleConfig, p60dockAddress, + node_hk.id, GS_RPARAM_MAGIC_CHECKSUM, timeout); + *size = P60DOCK_HK_SIZE; + if (result != GS_OK) { + sif::info + << "Failed retrieving module configuration from P60 dock with error code " + << result << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + break; + } + default: + break; + } + return HasReturnvaluesIF::RETURN_OK; +} + diff --git a/bsp_linux/comIF/P60DockComIF.h b/bsp_linux/comIF/P60DockComIF.h new file mode 100644 index 00000000..994eeb73 --- /dev/null +++ b/bsp_linux/comIF/P60DockComIF.h @@ -0,0 +1,52 @@ +/* + * P60DockComIF.h + * + * Created on: 01.12.2020 + * Author: jakob + */ + +#ifndef BSP_LINUX_COMIF_P60DOCKCOMIF_H_ +#define BSP_LINUX_COMIF_P60DOCKCOMIF_H_ + +#include +#include +#include + +#include +#include +#include +#include + +/** + * @brief This is the communication interface to the cubesat space protocol + * stack. The physical layer used for this implementation is CAN. + * @author Jakob Meier + */ +class P60DockComIF: public DeviceCommunicationIF, public SystemObject { +public: + P60DockComIF(object_id_t objectId); + virtual ~P60DockComIF(); + + ReturnValue_t initializeInterface(CookieIF * cookie) override; + ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t * sendData, + size_t sendLen) override; + ReturnValue_t getSendSuccess(CookieIF *cookie) override; + ReturnValue_t requestReceiveMessage(CookieIF *cookie, + size_t requestLen) override; + ReturnValue_t readReceivedMessage(CookieIF *cookie, + uint8_t **readData, size_t *readLen) override; + +private: + /* Interface struct for csp protocol stack */ + csp_iface_t csp_if; + /* Table definitions. According to gomspace software documentation there + * exist four tables each identified by a number*/ + uint8_t boardConfigTable = 0; + uint8_t modulConfigTable = 1; + uint8_t calibrationParamTable = 2; + uint8_t tmDataTable = 4; + unsigned int moduleConfigTableRows = 32; + +}; + +#endif /* BSP_LINUX_COMIF_P60DOCKCOMIF_H_ */ diff --git a/bsp_linux/comIF/ArduinoCookie.cpp b/bsp_linux/comIF/cookies/ArduinoCookie.cpp similarity index 100% rename from bsp_linux/comIF/ArduinoCookie.cpp rename to bsp_linux/comIF/cookies/ArduinoCookie.cpp diff --git a/bsp_linux/comIF/ArduinoCookie.h b/bsp_linux/comIF/cookies/ArduinoCookie.h similarity index 100% rename from bsp_linux/comIF/ArduinoCookie.h rename to bsp_linux/comIF/cookies/ArduinoCookie.h diff --git a/bsp_linux/comIF/cookies/P60DockCookie.cpp b/bsp_linux/comIF/cookies/P60DockCookie.cpp new file mode 100644 index 00000000..7ed238f2 --- /dev/null +++ b/bsp_linux/comIF/cookies/P60DockCookie.cpp @@ -0,0 +1,38 @@ +#include "bsp_linux/comIF/cookies/P60DockCookie.h" + + +P60DockCookie::P60DockCookie(char* canInterface_, uint8_t cspAddress_) : + canInterface(canInterface_), cspAddress(cspAddress_) { + +} + +P60DockCookie::~P60DockCookie() { +} + +uint8_t P60DockCookie::getCspAddress(){ + return cspAddress; +} + +char* P60DockCookie::getCanIf(){ + return canInterface; +} + +int P60DockCookie::getBitrate(){ + return bitrate; +} + +void P60DockCookie::setPingMessage(){ + nextMessage = PING; +} + +void P60DockCookie::setRebootMessage(){ + nextMessage = REBOOT; +} + +void P60DockCookie::setReadModuleCfgMessage(){ + nextMessage = READ_MODULE_CONFIG; +} + +MessageType_t P60DockCookie::getMessageType(){ + return nextMessage; +} diff --git a/bsp_linux/comIF/cookies/P60DockCookie.h b/bsp_linux/comIF/cookies/P60DockCookie.h new file mode 100644 index 00000000..30d78f7b --- /dev/null +++ b/bsp_linux/comIF/cookies/P60DockCookie.h @@ -0,0 +1,49 @@ +#ifndef BSP_LINUX_COMIF_COOKIES_P60DockCookie_H_ +#define BSP_LINUX_COMIF_COOKIES_P60DockCookie_H_ + +#include + +typedef uint32_t MessageType_t; + +/** + * @brief This is the cookie for the communication interface to the cubesat + * space protocol (CSP) implementation of gomspace. The communication + * interface uses CAN as the physical layer. Therefore the cookie also + * holds the CAN instance to use. + * @author Jakob Meier + */ +class P60DockCookie: public CookieIF { +public: + /** + * Constructor for the CSP cookie + * @param canInterface_ The CAN interface to use. E.g. "can0" or "can1". + * @param cspAddress_ The CSP address of the target device. + */ + P60DockCookie(char* canInterface_, uint8_t cspAddress_); + virtual ~P60DockCookie(); + + uint8_t getCspAddress(); + char* getCanIf(); + int getBitrate(); + void setPingMessage(); + void setRebootMessage(); + void setReadModuleCfgMessage(); + MessageType_t getMessageType(); + + /* Message type defines the type of the next data transfer between the + * CSP device and the OBC. */ + static const MessageType_t MESSAGE_NONE = 0x0; + static const MessageType_t PING = 0x1; + static const MessageType_t REBOOT = 0x4; + static const MessageType_t READ_MODULE_CONFIG = 0x71; + + +private: + + char* canInterface; + uint8_t cspAddress; + int bitrate = 1000; + MessageType_t nextMessage = MESSAGE_NONE; +}; + +#endif /* BSP_LINUX_COMIF_COOKIES_P60DockCookie_H_ */ diff --git a/fsfwconfig/OBSWConfig.h b/fsfwconfig/OBSWConfig.h index 7e59992c..59a09ba4 100644 --- a/fsfwconfig/OBSWConfig.h +++ b/fsfwconfig/OBSWConfig.h @@ -6,7 +6,7 @@ #ifndef FSFWCONFIG_OBSWCONFIG_H_ #define FSFWCONFIG_OBSWCONFIG_H_ -#define ADD_TEST_CODE 1 +#define ADD_TEST_CODE 0 // Define not used yet, PUS stack and TMTC tasks are always started #define ADD_PUS_STACK 1 diff --git a/fsfwconfig/devices/logicalAddresses.cpp b/fsfwconfig/devices/addresses.cpp similarity index 52% rename from fsfwconfig/devices/logicalAddresses.cpp rename to fsfwconfig/devices/addresses.cpp index a6f0aa15..38877737 100644 --- a/fsfwconfig/devices/logicalAddresses.cpp +++ b/fsfwconfig/devices/addresses.cpp @@ -4,7 +4,7 @@ * \date 06.11.2019 */ -#include +#include "addresses.h" diff --git a/fsfwconfig/devices/logicalAddresses.h b/fsfwconfig/devices/addresses.h similarity index 51% rename from fsfwconfig/devices/logicalAddresses.h rename to fsfwconfig/devices/addresses.h index 922c9ce1..210881e6 100644 --- a/fsfwconfig/devices/logicalAddresses.h +++ b/fsfwconfig/devices/addresses.h @@ -1,11 +1,11 @@ /** - * \file logicalAddresses.cpp + * \file addresses.cpp * * \date 07.11.2019 */ -#ifndef FSFWCONFIG_DEVICES_LOGICALADDRESSES_H_ -#define FSFWCONFIG_DEVICES_LOGICALADDRESSES_H_ +#ifndef FSFWCONFIG_DEVICES_ADDRESSES_H_ +#define FSFWCONFIG_DEVICES_ADDRESSES_H_ #include #include #include @@ -20,7 +20,14 @@ namespace addresses { DUMMY_GPS0 = 130, DUMMY_GPS1 = 131, }; + + /* Addresses of devices supporting the CSP protocol */ + enum cspAddresses: uint8_t { + P60DOCK = 4, + /* PDU2 occupies X4 slot of P60Dock */ + PDU2 = 6 + }; } -#endif /* FSFWCONFIG_DEVICES_LOGICALADDRESSES_H_ */ +#endif /* FSFWCONFIG_DEVICES_ADDRESSES_H_ */ diff --git a/fsfwconfig/objects/systemObjectList.h b/fsfwconfig/objects/systemObjectList.h index a77b8a7b..52b62db1 100644 --- a/fsfwconfig/objects/systemObjectList.h +++ b/fsfwconfig/objects/systemObjectList.h @@ -27,10 +27,14 @@ namespace objects { TEST_TASK = 0x42694269, DUMMY_INTERFACE = 0xCAFECAFE, DUMMY_HANDLER = 0x4400AFFE, + P60DOCK_TEST_TASK = 0x00005060, /* 0x49 ('I') for Communication Interfaces **/ ARDUINO_COM_IF = 0x49000001, - P60DOCK_TEST_TASK = 0x00005060 + P60_DOCK_COM_IF = 0x49000002, + + /* 0x44 ('D') for device handlers */ + P60DOCK_HANDLER = 0x44000001 }; } diff --git a/mission/core/GenericFactory.cpp b/mission/core/GenericFactory.cpp index cfdf297f..db3639d6 100644 --- a/mission/core/GenericFactory.cpp +++ b/mission/core/GenericFactory.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -19,6 +20,9 @@ #include #include #include +#include +#include +#include #if ADD_TEST_CODE == 1 //#include @@ -81,6 +85,17 @@ void ObjectFactory::produceGenericObjects() { new CService200ModeCommanding(objects::PUS_SERVICE_200_MODE_MGMT, apid::EIVE_OBSW, pus::PUS_SERVICE_200); + char canInterface[] = "can0"; + /* Cookies */ + P60DockCookie* p60DockCookie = new P60DockCookie(canInterface, addresses::P60DOCK); + + /* Communication interfaces */ + new P60DockComIF(objects::P60_DOCK_COM_IF); + + /* Device Handler */ + new P60DockHandler(objects::P60DOCK_HANDLER, objects::P60_DOCK_COM_IF, + p60DockCookie); + /* Test Device Handler */ #if ADD_TEST_CODE == 1 // new TestTask(objects::TEST_TASK); diff --git a/mission/devices/P60DockHandler.cpp b/mission/devices/P60DockHandler.cpp index f3ccc925..61358464 100644 --- a/mission/devices/P60DockHandler.cpp +++ b/mission/devices/P60DockHandler.cpp @@ -1,23 +1,84 @@ -/* - * P60DockHandler.cpp - * - * Created on: 18.11.2020 - * Author: jakob - */ - #include #include -#include "P60DockHandler.h" +#include +#include "bsp_linux/comIF/cookies/P60DockCookie.h" +#include "bsp_linux/comIF/P60DockComIF.h" + +P60DockHandler::P60DockHandler(object_id_t objectId, object_id_t comIF, + CookieIF * comCookie):DeviceHandlerBase(objectId, comIF, comCookie) { +} + +P60DockHandler::~P60DockHandler() { +} + + +void P60DockHandler::doStartUp(){ + +} + +void P60DockHandler::doShutDown(){ + +} + +ReturnValue_t P60DockHandler::buildNormalDeviceCommand(DeviceCommandId_t * id){ + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t P60DockHandler::buildTransitionDeviceCommand( + DeviceCommandId_t * id){ + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t P60DockHandler::buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t * commandData, + size_t commandDataLen) { + switch(deviceCommand) { + case(READ_MODULE_CFG):{ + internalState = InternalStates::READ_MODULE_CFG; + break; + } + case(PING): { + break; + } + default: + break; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void P60DockHandler::fillCommandAndReplyMap(){ + this->insertInCommandAndReplyMap(READ_MODULE_CFG, 3); +} + +ReturnValue_t P60DockHandler::scanForReply(const uint8_t *start, + size_t remainingSize, DeviceCommandId_t *foundId, size_t *foundLen) { + switch(internalState) { + case(InternalStates::READ_MODULE_CFG): { + *foundId = READ_MODULE_CFG; + *foundLen = moduleCfgTableSize; + break; + } + default: + return IGNORE_REPLY_DATA; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t P60DockHandler::interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) { + switch(id) { + case(READ_MODULE_CFG): { + handleDeviceTM((SerializeIF*)packet, id, true, true); + break; + } + default: + break; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void setNormalDatapoolEntriesInvalid(){ + +} + -//P60DockHandler::P60DockHandler() { -// -//} -// -// -//P60DockHandler::~P60DockHandler() { -//} -// -// -//P60DockHandler::performOperation(uint8_t operationCode) { -// -//} diff --git a/mission/devices/P60DockHandler.h b/mission/devices/P60DockHandler.h index 20078cd8..1c093f4b 100644 --- a/mission/devices/P60DockHandler.h +++ b/mission/devices/P60DockHandler.h @@ -1,18 +1,40 @@ -/* - * P60DockHandler.h - * - * Created on: 18.11.2020 - * Author: jakob - */ - #ifndef MISSION_DEVICES_P60DOCKHANDLER_H_ #define MISSION_DEVICES_P60DOCKHANDLER_H_ -//class P60DockHandler: public DeviceHandlerBase { -//public: -// P60DockHandler(); -// virtual ~P60DockHandler(); -// virtual ReturnValue_t performOperation(uint8_t operationCode = 0); -//}; +#include + +class P60DockHandler: public DeviceHandlerBase { +public: + P60DockHandler(object_id_t objectId, object_id_t comIF, + CookieIF * comCookie); + virtual ~P60DockHandler(); + +protected: + void doStartUp() override; + void doShutDown() override; + ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) override; + ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t * id) override; + void fillCommandAndReplyMap() override; + ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, + const uint8_t * commandData,size_t commandDataLen) override; + ReturnValue_t scanForReply(const uint8_t *start, size_t remainingSize, + DeviceCommandId_t *foundId, size_t *foundLen) override; + ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) override; + void setNormalDatapoolEntriesInvalid() override; + +private: + + static const DeviceCommandId_t PING = 0x1; //!< [EXPORT] : [COMMAND] + static const DeviceCommandId_t READ_MODULE_CFG = 0xE; //!< [EXPORT] : [COMMAND] + + enum class InternalStates { + STATE_NONE, + READ_MODULE_CFG + }; + InternalStates internalState = InternalStates::STATE_NONE; + + size_t moduleCfgTableSize = 188; +}; #endif /* MISSION_DEVICES_P60DOCKHANDLER_H_ */ diff --git a/mission/devices/devicedefinitions/P60DockHandlerDefinitions.h b/mission/devices/devicedefinitions/P60DockHandlerDefinitions.h new file mode 100644 index 00000000..001c7b76 --- /dev/null +++ b/mission/devices/devicedefinitions/P60DockHandlerDefinitions.h @@ -0,0 +1,58 @@ +#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_P60DOCKHANDLERDEFINITIONS_H_ +#define MISSION_DEVICES_DEVICEDEFINITIONS_P60DOCKHANDLERDEFINITIONS_H_ + +/** + * @brief This class helps to serialize and deserialze the P60 dock packet + * holding information about the module configuration. The parameters + * of this table are described in the gs-man-nanopower-p60-dock-2.2.9.pdf + * on page 16. + */ +//class ModuleConfigTable : public SerialLinkedListAdapter { //!< [EXPORT] : [SUBSERVICE] 2 +//public: +// typedef char dataBufferType; +// typedef uint8_t typeOfMaxData; +// +// ModuleConfigTable() { +// setStart(&objectId); +// objectId.setNext(&sizeOfRepositoryPath); +// sizeOfRepositoryPath.setNext(&repositoryPath); +// repositoryPath.setNext(&sizeOfFilename); +// sizeOfFilename.setNext(&filename); +// /* Add string terminator to filename and repository path */ +// repositoryPath.entry.insert('\0'); +// filename.entry.insert('\0'); +// } +// +// uint32_t getSizeOfRepositoryPath() { +// return sizeOfRepositoryPath; +// } +// +// uint32_t getSizeOfFilename() { +// return sizeOfFilename; +// } +// +// uint8_t * getRepositoryPath() { +// return repositoryPath.entry.front(); +// } +// +// uint8_t getFilename() { +// return filename.entry.front(); +// } +// +//private: +// /* Prevent object copying */ +// ModuleConfigTable(const ModuleConfigTable &obj); +// +// SerializeElement> out_name; +// SerializeElement> out_en; +// SerializeElement> out_on_cnt; +// SerializeElement> out_on_cnt; +// SerializeElement sizeOfRepositoryPath; +// SerializeElement> repositoryPath; +// SerializeElement sizeOfFilename; +// SerializeElement> filename; +//}; + + + +#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_P60DOCKHANDLERDEFINITIONS_H_ */ diff --git a/test/testtasks/P60DockTestTask.cpp b/test/testtasks/P60DockTestTask.cpp index 2a8444e8..42067b01 100644 --- a/test/testtasks/P60DockTestTask.cpp +++ b/test/testtasks/P60DockTestTask.cpp @@ -20,7 +20,7 @@ SystemObject(objectId_){ ReturnValue_t P60DockTestTask::performOperation(uint8_t operationCode) { - if(sendPacket() != HasReturnvaluesIF::RETURN_OK){ + if(pingP60dock() != HasReturnvaluesIF::RETURN_OK){ return HasReturnvaluesIF::RETURN_FAILED; } @@ -31,43 +31,7 @@ ReturnValue_t P60DockTestTask::performOperation(uint8_t operationCode) { } -ReturnValue_t P60DockTestTask::sendPacket(void){ - -// char *msg = "HELLO"; -// /* Get packet buffer for data */ -// csp_packet_t *packet = csp_buffer_get(strlen(msg)); -// if (packet == NULL) { -// /* Could not get buffer element */ -// sif::error("Failed to get buffer element\\n"); -// return HasReturnvaluesIF::RETURN_FAILED; -// } -// -// /* Connect P60 Dock */ -// csp_conn_t *conn = csp_connect(CSP_PRIO_NORM, c, CSP_PING, -// 1000, CSP_O_NONE); -// -// if (conn == NULL) { -// /* Connect failed */ -// sif::error("Connection failed\\n"); -// /* Remember to free packet buffer */ -// csp_buffer_free(packet); -// return HasReturnvaluesIF::RETURN_FAILED; -// } -// -// /* Copy message to packet */ -// strcpy(packet->data, msg); -// /* Set packet length */ -// packet->length = strlen(msg); -// -// /* Send packet */ -// if (!csp_send(conn, packet, 1000)) { -// /* Send failed */ -// sif::error("Send failed\\n"); -// csp_buffer_free(packet); -// } -// /* Close connection */ -// csp_close(conn); - +ReturnValue_t P60DockTestTask::pingP60dock(void){ uint32_t timeout = 1000; unsigned int pingSize = 100; // 100 bytes uint32_t replyTime = csp_ping(p60dockAddress, timeout, pingSize, CSP_O_NONE); @@ -78,54 +42,35 @@ ReturnValue_t P60DockTestTask::sendPacket(void){ ReturnValue_t P60DockTestTask::getParameters(void) { -// int result = rparam_get_full_table(&node_hk, p60dock_node, P60_PORT_RPARAM, uint32_t timeout = 1000; node_hk.rows = (gs_param_table_row_t*)p60dock_hk; node_hk.id = P60DOCK_HK; node_hk.row_count = p60dock_hk_count; node_hk.memory_size = P60DOCK_HK_SIZE; - node_hk.memory = hk_mem; + node_hk.memory = hkMem; + /* Retriev all houskeeping data from the P60 dock and store it in hkMem + * array */ int result = gs_rparam_get_full_table(&node_hk, p60dockAddress, node_hk.id, GS_RPARAM_MAGIC_CHECKSUM, timeout); if (result != 0) { - sif::info << "Error retrieving P60 Dock housekeeping\n" << std::endl; + sif::info << "Error retrieving P60 Dock housekeeping" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } else { uint8_t tableOffsetTemperature = 0x44; - int16_t temperature[2]; + int16_t temperature; size_t parameterSize = sizeof(temperature); uint32_t flags = 0; result = gs_param_get_data((gs_param_table_instance_t*) &node_hk, - tableOffsetTemperature, temperature, parameterSize, flags); - sif::info << "P60 Dock Temperature 1: " << temperature[0] << std::endl; - sif::info << "P60 Dock Temperature 2: " << temperature[1] << std::endl; + tableOffsetTemperature, &temperature, parameterSize, flags); + sif::info << "P60 Dock Temperature: " << temperature << std::endl; -// sif::info << "Retrieved P60 Dock housekeeping\n" << std::endl; -// /* List all out_en[] values, using parameter name */ -// const param_table_t * param = param_find_name(node_hk.table, -// node_hk.count, "out_en"); -// if (param != NULL) { -// for (uint8_t index = 0; index < 13; index++) { -// /* Read parameter using name */ -// uint8_t *out_en = param_read_addr( -// param->addr + param->size * index, &node_hk, -// param->size); -// sif::info << "out_en" << index << ": " << *out_en << std::endl; -// } -// } -// /* List all c_out[] values, using parameter address */ -// param = param_find_addr(node_hk.table, node_hk.count, 0x0000); -// if (param != NULL) { -// for (uint8_t index = 0; index < 13; index++) { -// /* Read parameter using address */ -// int16_t *c_out = param_read_addr( -// param->addr + param->size * index, &node_hk, -// param->size); -// sif::info << "c_out" << index << ": " << *c_out << "mA" -// << std::endl; -// } -// } + uint16_t vbat_v; + parameterSize = sizeof(vbat_v); + uint8_t vbat_v_offset = 0x74; + result = gs_param_get_data((gs_param_table_instance_t*) &node_hk, + vbat_v_offset, &vbat_v, parameterSize, flags); + sif::info << "VBAT_V: " << vbat_v << std::endl; } return HasReturnvaluesIF::RETURN_OK; } @@ -133,7 +78,7 @@ ReturnValue_t P60DockTestTask::getParameters(void) { ReturnValue_t P60DockTestTask::initializeCSPStack(void){ /* Init CSP and CSP buffer system */ - if (csp_init(cspAddress) != CSP_ERR_NONE + if (csp_init(cspClientAddress) != CSP_ERR_NONE || csp_buffer_init(10, 300) != CSP_ERR_NONE) { sif::error << "Failed to init CSP\r\n" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; diff --git a/test/testtasks/P60DockTestTask.h b/test/testtasks/P60DockTestTask.h index e5270263..f631c18c 100644 --- a/test/testtasks/P60DockTestTask.h +++ b/test/testtasks/P60DockTestTask.h @@ -30,21 +30,26 @@ public: private: /* Interface struct for csp protocol stack */ csp_iface_t csp_if; + /* CSP address of P60 dock */ uint8_t p60dockAddress = 4; - uint8_t CSP_PING = 1; - uint8_t cspAddress = 1; + /* Client CSP address */ + uint8_t cspClientAddress = 1; + /* CAN interface used by CSP */ const char* canIf = "can0"; int bitrate = 1000; // bitrate of can int promisc = 0; // set to 0 to enable filter mode - - uint8_t hk_mem[P60DOCK_HK_SIZE]; - uint8_t p60dock_node = 4; + /* P60 Dock houskeeping parameters will be stored in this buffer */ + uint8_t hkMem[P60DOCK_HK_SIZE]; gs_param_table_instance_t node_hk; + /* Port of CSP ping requests on P60 dock */ + uint8_t CSP_PING = 1; - ReturnValue_t sendPacket(void); + /* Sends ping request and receives ping reply */ + ReturnValue_t pingP60dock(void); ReturnValue_t initializeCSPStack(void); + /* Temperature and raw battery voltage are read from the P60 dock by this + * function */ ReturnValue_t getParameters(void); - }; #endif /* TEST_TESTTASKS_P60DOCKTESTTASK_H_ */ From ad97a5538c0b80a64344310c8f0dcaf4e1dd8728 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Fri, 4 Dec 2020 20:08:58 +0100 Subject: [PATCH 011/360] p60dock read config table compiling --- bsp_linux/comIF/P60DockComIF.cpp | 10 +++++----- bsp_linux/comIF/P60DockComIF.h | 4 +++- mission/devices/P60DockHandler.cpp | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/bsp_linux/comIF/P60DockComIF.cpp b/bsp_linux/comIF/P60DockComIF.cpp index bf97c2e3..5bc1d4f9 100644 --- a/bsp_linux/comIF/P60DockComIF.cpp +++ b/bsp_linux/comIF/P60DockComIF.cpp @@ -94,16 +94,16 @@ ReturnValue_t P60DockComIF::readReceivedMessage(CookieIF *cookie, uint32_t timeout = 1000; uint8_t p60dockAddress = p60DockCookie->getCspAddress(); gs_param_table_instance_t moduleConfig; - moduleConfig.rows = moduleConfigTable; + moduleConfig.rows = (gs_param_table_row_t*)p60dock_config; moduleConfig.id = p60dockAddress; - moduleConfig.row_count = p60dock_hk_count; - moduleConfig.memory_size = P60DOCK_HK_SIZE; + moduleConfig.row_count = p60dock_config_count; + moduleConfig.memory_size = moduleCfgTableSize; moduleConfig.memory = *buffer; /* Read complete module configuration table from P60 Dock and store data * in buffer */ int result = gs_rparam_get_full_table(&moduleConfig, p60dockAddress, - node_hk.id, GS_RPARAM_MAGIC_CHECKSUM, timeout); - *size = P60DOCK_HK_SIZE; + moduleConfig.id, GS_RPARAM_MAGIC_CHECKSUM, timeout); + *size = moduleCfgTableSize; if (result != GS_OK) { sif::info << "Failed retrieving module configuration from P60 dock with error code " diff --git a/bsp_linux/comIF/P60DockComIF.h b/bsp_linux/comIF/P60DockComIF.h index 994eeb73..4595e9dd 100644 --- a/bsp_linux/comIF/P60DockComIF.h +++ b/bsp_linux/comIF/P60DockComIF.h @@ -16,6 +16,7 @@ #include #include #include +#include /** * @brief This is the communication interface to the cubesat space protocol @@ -42,10 +43,11 @@ private: /* Table definitions. According to gomspace software documentation there * exist four tables each identified by a number*/ uint8_t boardConfigTable = 0; - uint8_t modulConfigTable = 1; + uint8_t moduleConfigTable = 1; uint8_t calibrationParamTable = 2; uint8_t tmDataTable = 4; unsigned int moduleConfigTableRows = 32; + uint16_t moduleCfgTableSize = 412; }; diff --git a/mission/devices/P60DockHandler.cpp b/mission/devices/P60DockHandler.cpp index 61358464..c7cd8402 100644 --- a/mission/devices/P60DockHandler.cpp +++ b/mission/devices/P60DockHandler.cpp @@ -77,7 +77,7 @@ ReturnValue_t P60DockHandler::interpretDeviceReply(DeviceCommandId_t id, return HasReturnvaluesIF::RETURN_OK; } -void setNormalDatapoolEntriesInvalid(){ +void P60DockHandler::setNormalDatapoolEntriesInvalid(){ } From c0ce686478304f3ac02622f2f94d4ae71d17a87f Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Sat, 5 Dec 2020 14:52:18 +0100 Subject: [PATCH 012/360] some changes for P60Dock cookie --- bsp_linux/comIF/cookies/P60DockCookie.cpp | 4 ++-- bsp_linux/comIF/cookies/P60DockCookie.h | 5 ++--- mission/core/GenericFactory.cpp | 3 +-- tmtc | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/bsp_linux/comIF/cookies/P60DockCookie.cpp b/bsp_linux/comIF/cookies/P60DockCookie.cpp index 7ed238f2..ccc6e09b 100644 --- a/bsp_linux/comIF/cookies/P60DockCookie.cpp +++ b/bsp_linux/comIF/cookies/P60DockCookie.cpp @@ -1,8 +1,8 @@ #include "bsp_linux/comIF/cookies/P60DockCookie.h" -P60DockCookie::P60DockCookie(char* canInterface_, uint8_t cspAddress_) : - canInterface(canInterface_), cspAddress(cspAddress_) { +P60DockCookie::P60DockCookie(uint8_t cspAddress_) : + cspAddress(cspAddress_) { } diff --git a/bsp_linux/comIF/cookies/P60DockCookie.h b/bsp_linux/comIF/cookies/P60DockCookie.h index 30d78f7b..eef7b417 100644 --- a/bsp_linux/comIF/cookies/P60DockCookie.h +++ b/bsp_linux/comIF/cookies/P60DockCookie.h @@ -16,10 +16,9 @@ class P60DockCookie: public CookieIF { public: /** * Constructor for the CSP cookie - * @param canInterface_ The CAN interface to use. E.g. "can0" or "can1". * @param cspAddress_ The CSP address of the target device. */ - P60DockCookie(char* canInterface_, uint8_t cspAddress_); + P60DockCookie(uint8_t cspAddress_); virtual ~P60DockCookie(); uint8_t getCspAddress(); @@ -40,7 +39,7 @@ public: private: - char* canInterface; + char canInterface[5] = "can0"; uint8_t cspAddress; int bitrate = 1000; MessageType_t nextMessage = MESSAGE_NONE; diff --git a/mission/core/GenericFactory.cpp b/mission/core/GenericFactory.cpp index db3639d6..b350cbd4 100644 --- a/mission/core/GenericFactory.cpp +++ b/mission/core/GenericFactory.cpp @@ -85,9 +85,8 @@ void ObjectFactory::produceGenericObjects() { new CService200ModeCommanding(objects::PUS_SERVICE_200_MODE_MGMT, apid::EIVE_OBSW, pus::PUS_SERVICE_200); - char canInterface[] = "can0"; /* Cookies */ - P60DockCookie* p60DockCookie = new P60DockCookie(canInterface, addresses::P60DOCK); + P60DockCookie* p60DockCookie = new P60DockCookie(addresses::P60DOCK); /* Communication interfaces */ new P60DockComIF(objects::P60_DOCK_COM_IF); diff --git a/tmtc b/tmtc index 3fc71f90..0c0e0595 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 3fc71f9094e8fb670942f0c29a9dea0b6e03d17f +Subproject commit 0c0e0595f177b8fe4100902058a10e8d5ad34663 From c82cdf96dbc9a84c69e50b29cddd84356c12056e Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Wed, 9 Dec 2020 12:00:24 +0100 Subject: [PATCH 013/360] read module cfg and read hk from p60 dock, intermediate state --- bsp_linux/InitMission.cpp | 21 +++++----- bsp_linux/comIF/P60DockComIF.cpp | 39 ++++++++++++++++--- bsp_linux/comIF/P60DockComIF.h | 14 ++++--- bsp_linux/comIF/cookies/P60DockCookie.cpp | 4 ++ bsp_linux/comIF/cookies/P60DockCookie.h | 2 + .../PollingSequenceFactory.cpp | 22 +++++++++++ .../pollingsequence/PollingSequenceFactory.h | 7 ++++ .../include/gs/p60-dock/param/p60dock_hk.h | 1 + gomspace/p60-dock_client/src/p60dock_client.c | 1 + mission/devices/P60DockHandler.cpp | 27 ++++++++++++- mission/devices/P60DockHandler.h | 11 ++++-- 11 files changed, 126 insertions(+), 23 deletions(-) diff --git a/bsp_linux/InitMission.cpp b/bsp_linux/InitMission.cpp index 04e79a12..94f58991 100644 --- a/bsp_linux/InitMission.cpp +++ b/bsp_linux/InitMission.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -129,14 +130,15 @@ void InitMission::initTasks(){ sif::error << "Object add component failed" << std::endl; } - /* Device Handler */ - PeriodicTaskIF* DeviceHandler = TaskFactory::instance()-> - createPeriodicTask("Device Handler", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE, - 1, nullptr); - result = DeviceHandler->addComponent(objects::P60DOCK_HANDLER); - if(result!=HasReturnvaluesIF::RETURN_OK){ - sif::error << "Object add component failed" << std::endl; - } + FixedTimeslotTaskIF* GomSpacePstTask = TaskFactory::instance()-> + createFixedTimeslotTask("GS_PST_TASK", 10, + PeriodicTaskIF::MINIMUM_STACK_SIZE*4, 1.0, nullptr); + result = pst::gomspacePstInit(GomSpacePstTask); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "InitMission::initTasks: GomSpace PST initialization " + << "failed!" << std::endl; +} + #if ADD_TEST_CODE == 1 // FixedTimeslotTaskIF* TestTimeslotTask = TaskFactory::instance()-> @@ -163,13 +165,14 @@ void InitMission::initTasks(){ UdpBridgeTask->startTask(); UdpPollingTask->startTask(); + GomSpacePstTask->startTask(); + PusVerification->startTask(); PusEvents->startTask(); PusHighPrio->startTask(); PusMedPrio->startTask(); PusLowPrio->startTask(); - DeviceHandler->startTask(); #if ADD_TEST_CODE == 1 // TestTimeslotTask->startTask(); P60DockTestTask->startTask(); diff --git a/bsp_linux/comIF/P60DockComIF.cpp b/bsp_linux/comIF/P60DockComIF.cpp index 5bc1d4f9..d37e652b 100644 --- a/bsp_linux/comIF/P60DockComIF.cpp +++ b/bsp_linux/comIF/P60DockComIF.cpp @@ -86,7 +86,14 @@ ReturnValue_t P60DockComIF::requestReceiveMessage(CookieIF *cookie, ReturnValue_t P60DockComIF::readReceivedMessage(CookieIF *cookie, uint8_t** buffer, size_t* size) { + if(cookie == NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } P60DockCookie* p60DockCookie = dynamic_cast (cookie); + if(p60DockCookie == NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } + MessageType_t messageType = p60DockCookie->getMessageType(); switch(messageType){ @@ -95,10 +102,10 @@ ReturnValue_t P60DockComIF::readReceivedMessage(CookieIF *cookie, uint8_t p60dockAddress = p60DockCookie->getCspAddress(); gs_param_table_instance_t moduleConfig; moduleConfig.rows = (gs_param_table_row_t*)p60dock_config; - moduleConfig.id = p60dockAddress; + moduleConfig.id = moduleCfgTableNum; moduleConfig.row_count = p60dock_config_count; - moduleConfig.memory_size = moduleCfgTableSize; - moduleConfig.memory = *buffer; + moduleConfig.memory_size = p60dock_config_size; + moduleConfig.memory = replyBuffer; /* Read complete module configuration table from P60 Dock and store data * in buffer */ int result = gs_rparam_get_full_table(&moduleConfig, p60dockAddress, @@ -106,8 +113,30 @@ ReturnValue_t P60DockComIF::readReceivedMessage(CookieIF *cookie, *size = moduleCfgTableSize; if (result != GS_OK) { sif::info - << "Failed retrieving module configuration from P60 dock with error code " - << result << std::endl; + << "Failed retrieving module configuration from P60 dock " + << "with error code " << result << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + break; + } + case(P60DockCookie::READ_HK):{ + uint32_t timeout = 1000; + uint8_t p60dockAddress = p60DockCookie->getCspAddress(); + gs_param_table_instance_t tmData; + tmData.rows = (gs_param_table_row_t*)p60dock_hk; + tmData.id = tmTableNum; + tmData.row_count = p60dock_hk_count; + tmData.memory_size = tmTableSize; + tmData.memory = replyBuffer; + /* Read complete module configuration table from P60 Dock and store data + * in buffer */ + int result = gs_rparam_get_full_table(&tmData, p60dockAddress, + tmData.id, GS_RPARAM_MAGIC_CHECKSUM, timeout); + *size = tmTableSize; + if (result != GS_OK) { + sif::info + << "Failed retrieving telemetry from P60 dock with error " + << "code " << result << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } break; diff --git a/bsp_linux/comIF/P60DockComIF.h b/bsp_linux/comIF/P60DockComIF.h index 4595e9dd..411b3b99 100644 --- a/bsp_linux/comIF/P60DockComIF.h +++ b/bsp_linux/comIF/P60DockComIF.h @@ -25,6 +25,8 @@ */ class P60DockComIF: public DeviceCommunicationIF, public SystemObject { public: + static const uint8_t maxReplyLength = 188; + P60DockComIF(object_id_t objectId); virtual ~P60DockComIF(); @@ -42,12 +44,14 @@ private: csp_iface_t csp_if; /* Table definitions. According to gomspace software documentation there * exist four tables each identified by a number*/ - uint8_t boardConfigTable = 0; - uint8_t moduleConfigTable = 1; - uint8_t calibrationParamTable = 2; - uint8_t tmDataTable = 4; + uint8_t boardConfigTableNum = 0; + uint8_t moduleCfgTableNum = 1; + uint8_t calibrationParamTableNum = 2; + uint8_t tmTableNum = 4; unsigned int moduleConfigTableRows = 32; - uint16_t moduleCfgTableSize = 412; + uint8_t moduleCfgTableSize = 188; + uint8_t tmTableSize = 188; + uint8_t replyBuffer[P60DockComIF::maxReplyLength]; }; diff --git a/bsp_linux/comIF/cookies/P60DockCookie.cpp b/bsp_linux/comIF/cookies/P60DockCookie.cpp index ccc6e09b..b4b83bbe 100644 --- a/bsp_linux/comIF/cookies/P60DockCookie.cpp +++ b/bsp_linux/comIF/cookies/P60DockCookie.cpp @@ -33,6 +33,10 @@ void P60DockCookie::setReadModuleCfgMessage(){ nextMessage = READ_MODULE_CONFIG; } +void P60DockCookie::setReadHkMessage(){ + nextMessage = READ_HK; +} + MessageType_t P60DockCookie::getMessageType(){ return nextMessage; } diff --git a/bsp_linux/comIF/cookies/P60DockCookie.h b/bsp_linux/comIF/cookies/P60DockCookie.h index eef7b417..e8a1c42c 100644 --- a/bsp_linux/comIF/cookies/P60DockCookie.h +++ b/bsp_linux/comIF/cookies/P60DockCookie.h @@ -27,6 +27,7 @@ public: void setPingMessage(); void setRebootMessage(); void setReadModuleCfgMessage(); + void setReadHkMessage(); MessageType_t getMessageType(); /* Message type defines the type of the next data transfer between the @@ -35,6 +36,7 @@ public: static const MessageType_t PING = 0x1; static const MessageType_t REBOOT = 0x4; static const MessageType_t READ_MODULE_CONFIG = 0x71; + static const MessageType_t READ_HK = 0x74; private: diff --git a/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp b/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp index 22c00034..6370efa5 100644 --- a/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp +++ b/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp @@ -28,3 +28,25 @@ ReturnValue_t pst::pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence) } } +ReturnValue_t pst::gomspacePstInit(FixedTimeslotTaskIF *thisSequence){ + + uint32_t length = thisSequence->getPeriodMs(); + + thisSequence->addSlot(objects::P60DOCK_HANDLER, + length * 0, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::P60DOCK_HANDLER, + length * 0.25, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::P60DOCK_HANDLER, + length * 0.5, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::P60DOCK_HANDLER, + length * 0.75, DeviceHandlerIF::GET_READ); + + if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + sif::error << "Initialization of GomSpace PST failed" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } +} + diff --git a/fsfwconfig/pollingsequence/PollingSequenceFactory.h b/fsfwconfig/pollingsequence/PollingSequenceFactory.h index b6cc2f1e..0b12e6b8 100644 --- a/fsfwconfig/pollingsequence/PollingSequenceFactory.h +++ b/fsfwconfig/pollingsequence/PollingSequenceFactory.h @@ -26,6 +26,13 @@ namespace pst { /* 0.4 second period init*/ ReturnValue_t pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence); +/** + * @brief This function creates the PST for all gomspace devices. They are + * scheduled in a separate PST because the gomspace library uses + * blocking calls when requesting data from devices. + */ +ReturnValue_t gomspacePstInit(FixedTimeslotTaskIF *thisSequence); } + #endif /* POLLINGSEQUENCEINIT_H_ */ diff --git a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h index 63797e37..3db66959 100644 --- a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h +++ b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h @@ -47,5 +47,6 @@ extern const param_table_t p60dock_hk[]; extern const int p60dock_hk_count; +extern const int p60dock_config_size; #endif /* P60DOCK_HK_H_ */ diff --git a/gomspace/p60-dock_client/src/p60dock_client.c b/gomspace/p60-dock_client/src/p60dock_client.c index 2fa3232b..5ca69126 100644 --- a/gomspace/p60-dock_client/src/p60dock_client.c +++ b/gomspace/p60-dock_client/src/p60dock_client.c @@ -64,6 +64,7 @@ const param_table_t p60dock_config[] = { }; const int p60dock_config_count = sizeof(p60dock_config) / sizeof(p60dock_config[0]); +const int p60dock_config_size = sizeof(p60dock_config); /** * Setup info about calibration parameters diff --git a/mission/devices/P60DockHandler.cpp b/mission/devices/P60DockHandler.cpp index c7cd8402..24a9c200 100644 --- a/mission/devices/P60DockHandler.cpp +++ b/mission/devices/P60DockHandler.cpp @@ -6,6 +6,14 @@ P60DockHandler::P60DockHandler(object_id_t objectId, object_id_t comIF, CookieIF * comCookie):DeviceHandlerBase(objectId, comIF, comCookie) { + mode = MODE_NORMAL; + if(comCookie == NULL){ + sif::error << "P60DockHandler invalid com cookie" << std::endl; + } + p60DockCookie = dynamic_cast (comCookie); + if(p60DockCookie == NULL){ + sif::error << "P60DockHandler failed to get P60DockCookie" << std::endl; + } } P60DockHandler::~P60DockHandler() { @@ -13,7 +21,6 @@ P60DockHandler::~P60DockHandler() { void P60DockHandler::doStartUp(){ - } void P60DockHandler::doShutDown(){ @@ -34,7 +41,15 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( size_t commandDataLen) { switch(deviceCommand) { case(READ_MODULE_CFG):{ + p60DockCookie->setReadModuleCfgMessage(); internalState = InternalStates::READ_MODULE_CFG; + this->pstStep = GET_READ; + break; + } + case(READ_HK):{ + p60DockCookie->setReadHkMessage(); + internalState = InternalStates::READ_HK; + this->pstStep = GET_READ; break; } case(PING): { @@ -48,6 +63,7 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( void P60DockHandler::fillCommandAndReplyMap(){ this->insertInCommandAndReplyMap(READ_MODULE_CFG, 3); + this->insertInCommandAndReplyMap(READ_HK, 3); } ReturnValue_t P60DockHandler::scanForReply(const uint8_t *start, @@ -58,6 +74,11 @@ ReturnValue_t P60DockHandler::scanForReply(const uint8_t *start, *foundLen = moduleCfgTableSize; break; } + case(InternalStates::READ_HK): { + *foundId = READ_HK; + *foundLen = hkTableSize; + break; + } default: return IGNORE_REPLY_DATA; } @@ -71,6 +92,10 @@ ReturnValue_t P60DockHandler::interpretDeviceReply(DeviceCommandId_t id, handleDeviceTM((SerializeIF*)packet, id, true, true); break; } + case(READ_HK): { + handleDeviceTM((SerializeIF*)packet, id, true, true); + break; + } default: break; } diff --git a/mission/devices/P60DockHandler.h b/mission/devices/P60DockHandler.h index 1c093f4b..a55580ea 100644 --- a/mission/devices/P60DockHandler.h +++ b/mission/devices/P60DockHandler.h @@ -2,6 +2,7 @@ #define MISSION_DEVICES_P60DOCKHANDLER_H_ #include +#include class P60DockHandler: public DeviceHandlerBase { public: @@ -26,15 +27,19 @@ protected: private: static const DeviceCommandId_t PING = 0x1; //!< [EXPORT] : [COMMAND] - static const DeviceCommandId_t READ_MODULE_CFG = 0xE; //!< [EXPORT] : [COMMAND] + static const DeviceCommandId_t READ_MODULE_CFG = 0x71; //!< [EXPORT] : [COMMAND] + static const DeviceCommandId_t READ_HK = 0x72; //!< [EXPORT] : [COMMAND] enum class InternalStates { STATE_NONE, - READ_MODULE_CFG + READ_MODULE_CFG, + READ_HK }; InternalStates internalState = InternalStates::STATE_NONE; + uint8_t moduleCfgTableSize = 188; + uint8_t hkTableSize = 188; - size_t moduleCfgTableSize = 188; + P60DockCookie* p60DockCookie; }; #endif /* MISSION_DEVICES_P60DOCKHANDLER_H_ */ From 988b61a3208f2a1e3b6f0b08816d81386f5f61bd Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Wed, 9 Dec 2020 12:24:34 +0100 Subject: [PATCH 014/360] timeout error in hk read --- bsp_linux/comIF/P60DockComIF.cpp | 3 +-- bsp_linux/comIF/P60DockComIF.h | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bsp_linux/comIF/P60DockComIF.cpp b/bsp_linux/comIF/P60DockComIF.cpp index d37e652b..7445c03b 100644 --- a/bsp_linux/comIF/P60DockComIF.cpp +++ b/bsp_linux/comIF/P60DockComIF.cpp @@ -122,11 +122,10 @@ ReturnValue_t P60DockComIF::readReceivedMessage(CookieIF *cookie, case(P60DockCookie::READ_HK):{ uint32_t timeout = 1000; uint8_t p60dockAddress = p60DockCookie->getCspAddress(); - gs_param_table_instance_t tmData; tmData.rows = (gs_param_table_row_t*)p60dock_hk; tmData.id = tmTableNum; tmData.row_count = p60dock_hk_count; - tmData.memory_size = tmTableSize; + tmData.memory_size = P60DOCK_HK_SIZE; tmData.memory = replyBuffer; /* Read complete module configuration table from P60 Dock and store data * in buffer */ diff --git a/bsp_linux/comIF/P60DockComIF.h b/bsp_linux/comIF/P60DockComIF.h index 411b3b99..3279f64e 100644 --- a/bsp_linux/comIF/P60DockComIF.h +++ b/bsp_linux/comIF/P60DockComIF.h @@ -51,7 +51,8 @@ private: unsigned int moduleConfigTableRows = 32; uint8_t moduleCfgTableSize = 188; uint8_t tmTableSize = 188; - uint8_t replyBuffer[P60DockComIF::maxReplyLength]; + uint8_t replyBuffer[188]; + gs_param_table_instance_t tmData; }; From 106ced96879486abac7f6dcf86e89e24eb3a2412 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Thu, 10 Dec 2020 10:01:45 +0100 Subject: [PATCH 015/360] read module config and read hk working --- bsp_linux/InitMission.cpp | 12 +++- bsp_linux/comIF/P60DockComIF.cpp | 68 ++++++++++++------- bsp_linux/comIF/P60DockComIF.h | 13 ++-- bsp_linux/comIF/cookies/P60DockCookie.cpp | 4 ++ bsp_linux/comIF/cookies/P60DockCookie.h | 1 + .../include/gs/p60-dock/param/p60dock_hk.h | 2 - gomspace/p60-dock_client/src/p60dock_client.c | 1 - mission/devices/P60DockHandler.cpp | 24 ++++--- mission/devices/P60DockHandler.h | 9 +-- test/testtasks/P60DockTestTask.cpp | 2 +- 10 files changed, 84 insertions(+), 52 deletions(-) diff --git a/bsp_linux/InitMission.cpp b/bsp_linux/InitMission.cpp index 94f58991..4be8be72 100644 --- a/bsp_linux/InitMission.cpp +++ b/bsp_linux/InitMission.cpp @@ -130,8 +130,16 @@ void InitMission::initTasks(){ sif::error << "Object add component failed" << std::endl; } +// PeriodicTaskIF* P60DockTask = TaskFactory::instance()-> +// createPeriodicTask("P60Dock Task", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE*4, +// 1.6, nullptr); +// result = P60DockTask->addComponent(objects::P60DOCK_HANDLER); +// if(result!=HasReturnvaluesIF::RETURN_OK){ +// sif::error << "Object add component failed" << std::endl; +// } + FixedTimeslotTaskIF* GomSpacePstTask = TaskFactory::instance()-> - createFixedTimeslotTask("GS_PST_TASK", 10, + createFixedTimeslotTask("GS_PST_TASK", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE*4, 1.0, nullptr); result = pst::gomspacePstInit(GomSpacePstTask); if(result != HasReturnvaluesIF::RETURN_OK) { @@ -173,6 +181,8 @@ void InitMission::initTasks(){ PusMedPrio->startTask(); PusLowPrio->startTask(); +// P60DockTask->startTask(); + #if ADD_TEST_CODE == 1 // TestTimeslotTask->startTask(); P60DockTestTask->startTask(); diff --git a/bsp_linux/comIF/P60DockComIF.cpp b/bsp_linux/comIF/P60DockComIF.cpp index 7445c03b..07af81e6 100644 --- a/bsp_linux/comIF/P60DockComIF.cpp +++ b/bsp_linux/comIF/P60DockComIF.cpp @@ -20,14 +20,16 @@ ReturnValue_t P60DockComIF::initializeInterface(CookieIF *cookie) { } P60DockCookie* p60DockCookie = dynamic_cast(cookie); - uint8_t cspAddress = p60DockCookie->getCspAddress(); + if(p60DockCookie == nullptr) { + return NULLPOINTER; + } char* canInterface = p60DockCookie->getCanIf(); int bitrate = p60DockCookie->getBitrate(); - + /* Define the memory to allocate for the CSP stack */ int buf_count = 10; int buf_size = 300; /* Init CSP and CSP buffer system */ - if (csp_init(cspAddress) != CSP_ERR_NONE + if (csp_init(cspClientAddress) != CSP_ERR_NONE || csp_buffer_init(buf_count, buf_size) != CSP_ERR_NONE) { sif::error << "Failed to init CSP\r\n" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; @@ -49,22 +51,42 @@ ReturnValue_t P60DockComIF::initializeInterface(CookieIF *cookie) { } /* Start the route task */ - unsigned int task_stack_size = 512; + unsigned int task_stack_size = 500; unsigned int priority = 0; result = csp_route_start_task(task_stack_size, priority); if(result != CSP_ERR_NONE){ sif::error << "Failed to start csp route task" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t P60DockComIF::sendMessage(CookieIF *cookie, const uint8_t * sendData, size_t sendLen) { + if(cookie == NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } P60DockCookie* p60DockCookie = dynamic_cast (cookie); + if(p60DockCookie == NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } + MessageType_t messageType = p60DockCookie->getMessageType(); switch(messageType){ + case(P60DockCookie::PING):{ + uint32_t timeout = 1000; // ms + unsigned int pingSize = 100; // 100 bytes + uint8_t p60DockAddress = p60DockCookie->getCspAddress(); + uint32_t replyTime = csp_ping(p60DockAddress, timeout, pingSize, + CSP_O_NONE); + sif::info << "Ping address: " << p60DockAddress << ", reply after " + << replyTime << " ms" << std::endl; + /* Store reply time in reply buffer * */ + memcpy(replyBuffer, &replyTime, sizeof(replyTime)); + break; + } case(P60DockCookie::REBOOT):{ csp_reboot(p60DockCookie->getCspAddress()); break; @@ -98,19 +120,19 @@ ReturnValue_t P60DockComIF::readReceivedMessage(CookieIF *cookie, switch(messageType){ case(P60DockCookie::READ_MODULE_CONFIG):{ - uint32_t timeout = 1000; + uint32_t timeout = 1000; // ms uint8_t p60dockAddress = p60DockCookie->getCspAddress(); - gs_param_table_instance_t moduleConfig; - moduleConfig.rows = (gs_param_table_row_t*)p60dock_config; - moduleConfig.id = moduleCfgTableNum; - moduleConfig.row_count = p60dock_config_count; - moduleConfig.memory_size = p60dock_config_size; - moduleConfig.memory = replyBuffer; + gs_param_table_instance_t table; + table.rows = (gs_param_table_row_t*)p60dock_config; + table.id = moduleCfgTableNum; + table.row_count = p60dock_config_count; + table.memory_size = P60DOCK_PARAM_SIZE; + table.memory = replyBuffer; /* Read complete module configuration table from P60 Dock and store data * in buffer */ - int result = gs_rparam_get_full_table(&moduleConfig, p60dockAddress, - moduleConfig.id, GS_RPARAM_MAGIC_CHECKSUM, timeout); - *size = moduleCfgTableSize; + int result = gs_rparam_get_full_table(&table, p60dockAddress, + table.id, GS_RPARAM_MAGIC_CHECKSUM, timeout); + *size = P60DOCK_PARAM_SIZE; if (result != GS_OK) { sif::info << "Failed retrieving module configuration from P60 dock " @@ -120,18 +142,18 @@ ReturnValue_t P60DockComIF::readReceivedMessage(CookieIF *cookie, break; } case(P60DockCookie::READ_HK):{ - uint32_t timeout = 1000; + uint32_t timeout = 1000; // ms uint8_t p60dockAddress = p60DockCookie->getCspAddress(); - tmData.rows = (gs_param_table_row_t*)p60dock_hk; - tmData.id = tmTableNum; - tmData.row_count = p60dock_hk_count; - tmData.memory_size = P60DOCK_HK_SIZE; - tmData.memory = replyBuffer; + table.rows = (gs_param_table_row_t*)p60dock_hk; + table.id = tmTableNum; + table.row_count = p60dock_hk_count; + table.memory_size = P60DOCK_HK_SIZE; + table.memory = replyBuffer; /* Read complete module configuration table from P60 Dock and store data * in buffer */ - int result = gs_rparam_get_full_table(&tmData, p60dockAddress, - tmData.id, GS_RPARAM_MAGIC_CHECKSUM, timeout); - *size = tmTableSize; + int result = gs_rparam_get_full_table(&table, p60dockAddress, + table.id, GS_RPARAM_MAGIC_CHECKSUM, timeout); + *size = P60DOCK_HK_SIZE; if (result != GS_OK) { sif::info << "Failed retrieving telemetry from P60 dock with error " diff --git a/bsp_linux/comIF/P60DockComIF.h b/bsp_linux/comIF/P60DockComIF.h index 3279f64e..3aed2f25 100644 --- a/bsp_linux/comIF/P60DockComIF.h +++ b/bsp_linux/comIF/P60DockComIF.h @@ -25,7 +25,7 @@ */ class P60DockComIF: public DeviceCommunicationIF, public SystemObject { public: - static const uint8_t maxReplyLength = 188; + static const uint16_t maxReplyLength = 412; P60DockComIF(object_id_t objectId); virtual ~P60DockComIF(); @@ -40,19 +40,18 @@ public: uint8_t **readData, size_t *readLen) override; private: + /* This is the CSP address of the OBC. */ + uint8_t cspClientAddress = 1; /* Interface struct for csp protocol stack */ csp_iface_t csp_if; /* Table definitions. According to gomspace software documentation there * exist four tables each identified by a number*/ - uint8_t boardConfigTableNum = 0; uint8_t moduleCfgTableNum = 1; uint8_t calibrationParamTableNum = 2; uint8_t tmTableNum = 4; - unsigned int moduleConfigTableRows = 32; - uint8_t moduleCfgTableSize = 188; - uint8_t tmTableSize = 188; - uint8_t replyBuffer[188]; - gs_param_table_instance_t tmData; + /* Replies of P60 dock are written to this buffer */ + uint8_t replyBuffer[P60DockComIF::maxReplyLength]; + gs_param_table_instance_t table; }; diff --git a/bsp_linux/comIF/cookies/P60DockCookie.cpp b/bsp_linux/comIF/cookies/P60DockCookie.cpp index b4b83bbe..4f1c87d2 100644 --- a/bsp_linux/comIF/cookies/P60DockCookie.cpp +++ b/bsp_linux/comIF/cookies/P60DockCookie.cpp @@ -21,6 +21,10 @@ int P60DockCookie::getBitrate(){ return bitrate; } +void P60DockCookie::resetMessageType(){ + nextMessage = MESSAGE_NONE; +} + void P60DockCookie::setPingMessage(){ nextMessage = PING; } diff --git a/bsp_linux/comIF/cookies/P60DockCookie.h b/bsp_linux/comIF/cookies/P60DockCookie.h index e8a1c42c..8d54104c 100644 --- a/bsp_linux/comIF/cookies/P60DockCookie.h +++ b/bsp_linux/comIF/cookies/P60DockCookie.h @@ -29,6 +29,7 @@ public: void setReadModuleCfgMessage(); void setReadHkMessage(); MessageType_t getMessageType(); + void resetMessageType(); /* Message type defines the type of the next data transfer between the * CSP device and the OBC. */ diff --git a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h index 3db66959..b9c9f17a 100644 --- a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h +++ b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h @@ -42,11 +42,9 @@ #define P60DOCK_HK_ANT6_DEPL 0xBA /* int8_t */ #define P60DOCK_HK_AR6_DEPL 0xBB /* int8_t */ -/** Define the memory size */ #define P60DOCK_HK_SIZE 0xBC extern const param_table_t p60dock_hk[]; extern const int p60dock_hk_count; -extern const int p60dock_config_size; #endif /* P60DOCK_HK_H_ */ diff --git a/gomspace/p60-dock_client/src/p60dock_client.c b/gomspace/p60-dock_client/src/p60dock_client.c index 5ca69126..2fa3232b 100644 --- a/gomspace/p60-dock_client/src/p60dock_client.c +++ b/gomspace/p60-dock_client/src/p60dock_client.c @@ -64,7 +64,6 @@ const param_table_t p60dock_config[] = { }; const int p60dock_config_count = sizeof(p60dock_config) / sizeof(p60dock_config[0]); -const int p60dock_config_size = sizeof(p60dock_config); /** * Setup info about calibration parameters diff --git a/mission/devices/P60DockHandler.cpp b/mission/devices/P60DockHandler.cpp index 24a9c200..fa4ebebb 100644 --- a/mission/devices/P60DockHandler.cpp +++ b/mission/devices/P60DockHandler.cpp @@ -40,19 +40,16 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( DeviceCommandId_t deviceCommand, const uint8_t * commandData, size_t commandDataLen) { switch(deviceCommand) { + case(PING): { + p60DockCookie->setPingMessage(); + break; + } case(READ_MODULE_CFG):{ p60DockCookie->setReadModuleCfgMessage(); - internalState = InternalStates::READ_MODULE_CFG; - this->pstStep = GET_READ; break; } case(READ_HK):{ p60DockCookie->setReadHkMessage(); - internalState = InternalStates::READ_HK; - this->pstStep = GET_READ; - break; - } - case(PING): { break; } default: @@ -62,19 +59,25 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( } void P60DockHandler::fillCommandAndReplyMap(){ + this->insertInCommandAndReplyMap(PING, 3); this->insertInCommandAndReplyMap(READ_MODULE_CFG, 3); this->insertInCommandAndReplyMap(READ_HK, 3); } ReturnValue_t P60DockHandler::scanForReply(const uint8_t *start, size_t remainingSize, DeviceCommandId_t *foundId, size_t *foundLen) { - switch(internalState) { - case(InternalStates::READ_MODULE_CFG): { + MessageType_t messageType = p60DockCookie->getMessageType(); + switch(messageType) { + case(PING): + *foundId = PING; + *foundLen = 4; + break; + case(READ_MODULE_CFG): { *foundId = READ_MODULE_CFG; *foundLen = moduleCfgTableSize; break; } - case(InternalStates::READ_HK): { + case(READ_HK): { *foundId = READ_HK; *foundLen = hkTableSize; break; @@ -82,6 +85,7 @@ ReturnValue_t P60DockHandler::scanForReply(const uint8_t *start, default: return IGNORE_REPLY_DATA; } + p60DockCookie->resetMessageType(); return HasReturnvaluesIF::RETURN_OK; } diff --git a/mission/devices/P60DockHandler.h b/mission/devices/P60DockHandler.h index a55580ea..40161e42 100644 --- a/mission/devices/P60DockHandler.h +++ b/mission/devices/P60DockHandler.h @@ -30,13 +30,8 @@ private: static const DeviceCommandId_t READ_MODULE_CFG = 0x71; //!< [EXPORT] : [COMMAND] static const DeviceCommandId_t READ_HK = 0x72; //!< [EXPORT] : [COMMAND] - enum class InternalStates { - STATE_NONE, - READ_MODULE_CFG, - READ_HK - }; - InternalStates internalState = InternalStates::STATE_NONE; - uint8_t moduleCfgTableSize = 188; + uint16_t moduleCfgTableSize = 412; + uint8_t calibrationTableSize = 174; uint8_t hkTableSize = 188; P60DockCookie* p60DockCookie; diff --git a/test/testtasks/P60DockTestTask.cpp b/test/testtasks/P60DockTestTask.cpp index 42067b01..985e69a3 100644 --- a/test/testtasks/P60DockTestTask.cpp +++ b/test/testtasks/P60DockTestTask.cpp @@ -36,7 +36,7 @@ ReturnValue_t P60DockTestTask::pingP60dock(void){ unsigned int pingSize = 100; // 100 bytes uint32_t replyTime = csp_ping(p60dockAddress, timeout, pingSize, CSP_O_NONE); sif::info << "Ping address: " << p60dockAddress << ", reply after " - << replyTime << "ms" << std::endl; + << replyTime << " ms" << std::endl; return HasReturnvaluesIF::RETURN_OK; } From 3dbe63dbdbc84ac0dac020c60c274c071cee5bdf Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Mon, 14 Dec 2020 08:42:21 +0100 Subject: [PATCH 016/360] wip CspComIF --- gomspace/libcsp/CHANGELOG | 113 -------- gomspace/libcsp/CONTRIBUTORS | 3 - gomspace/libcsp/COPYING | 503 ----------------------------------- gomspace/libcsp/INSTALL.rst | 30 --- gomspace/libcsp/README.rst | 41 --- gomspace/libcsp/waf | 170 ------------ gomspace/libcsp/wscript | 346 ------------------------ 7 files changed, 1206 deletions(-) delete mode 100644 gomspace/libcsp/CHANGELOG delete mode 100644 gomspace/libcsp/CONTRIBUTORS delete mode 100644 gomspace/libcsp/COPYING delete mode 100644 gomspace/libcsp/INSTALL.rst delete mode 100644 gomspace/libcsp/README.rst delete mode 100644 gomspace/libcsp/waf delete mode 100644 gomspace/libcsp/wscript diff --git a/gomspace/libcsp/CHANGELOG b/gomspace/libcsp/CHANGELOG deleted file mode 100644 index a4945716..00000000 --- a/gomspace/libcsp/CHANGELOG +++ /dev/null @@ -1,113 +0,0 @@ -libcsp 1.4, 07-05-2015 ----------------------- -- new: General rtable interface with support for STATIC or CIDR format -- new: CIDR (classless interdomain routing) route table format with netmasks -- new: Bridge capability -- new: Added routing table (de)serialization functions for load/save -- new: Automatic packet deduplication using CRC32 (compile time option) -- new: Autogenerated python bindings using ctypesgen -- new: Task-less operation with router invocation from external scheduler function -- api: Refactor route_if_add to csp_iflist_add -- api: Refactor route_set and friends to rtable_set -- api: Refactor csp_fifo_qos to csp_qfifo -- api: Added defined to be backwards compatible with 1.x -- interfaces: Drop packets on LOOP interface not for own address (blackhole) -- interfaces: New ZMQHUB interface (using zeroMQ over TCP) -- other: Increase stack size from 250 to 1100 for csp_can_rx_task -- other: Cleanup in csp_route.c -- other: Show incoming interface name in debug message -- other: Remove newlines from debug calls -- improvement: Reduce debug hook function complexity with valist passing -- fix: csp_sleep_ms did not work - -libcsp 1.3, 07-05-2015 ----------------------- -- new: Split long process lists into multiple packets -- new: Added posix csp_clock.h -- new: cmp clock functions (requires that you provide csp_clock.h implementation) -- new: Added SFP (Small fragmentation protocol) for larger data chunks -- fix: csp_if_fifo example -- fix: NULL char at the end of rps -- doc: Updated mtu documentation -- other: Tested with FreeRTOS 8.0 -- other: Added disable-stlib option to build only object files - -libcsp 1.2, 25-10-2013 ----------------------- -- Feature release -- New: CMP service for peek and poke of memory -- New: CMP interface statistics struct is now packed -- New: Faster O(1) buffer system with reference counting and automatic alignment -- New: Thread safe KISS driver with support for multiple interfaces -- New: CSP interface struct now holds an opaque pointer to driver handle -- New: removed TXBUF from KISS driver entirely to minimize stack usage, added TX lock instead -- New: Pre-calculated CRC table .romem or PROGMEM on __avr__ -- New: Added buffer overflow protection to KISS interface -- New: Allow posting null pointers on conn RX queues -- New: Lower memory usage on AVR8 -- New: csp_route_save and csp_route_load functions -- New: option --disable-verbose to disable filenames and linenumber on debug -- Protocol: KISS uses csp_crc32 instead of it own embedded crc32 -- Improvement: Use buffer clone function to copy promisc packets -- Bugfix: Fix pointer size (32/16bit) in cmp_peek/poke -- Bugfix: Issue with double free in KISS fixed -- Bugfix: Change rdp_send timeout from packet to connection timeout to make sending task block longer -- Bugfix: Fix conn pool leak when using security check and discarding new packets -- Bugfix: Add packet too short check for CRC32 -- Bugfix: Accept CRC32 responses from nodes without CRC support -- Bugfix: Ensure csp_ping works for packets > 256 bytes -- Bugfix: Cleanup printf inside ISR functions -- Bugfix: Do not add forwarded packets to promisc queue twice -- Bugfix: Fix return value bug of csp_buffer_get when out of buffers -- Bugfix: Always post null pointer with lowest priority, not highest -- Bugfix: Add check on debug level before calling do_csp_debug, fixes #35 -- Other: Export csp/arch include files -- Other: Remove the use of bool type from csp_debug -- Other: Moved csp debug functions to csp_debug.h instead of csp.h -- Other: Ensure assignment of id happens using the uint32_t .ext value of the union, quenches warning - -libcsp 1.1, 24-08-2012 ----------------------- -- Feature release -- Defacto stable since Feb 2012 -- New: I2C interface -- New: KISS interface -- New: USART drivers for Linux, Mac and Windows -- New: Windows/MinGW support -- New: MacOSX support -- New: Interface register function -- New: Interface search function -- New: CMP service for remote route updating -- New: CMP service for interface statistics -- Improvement: Better QoS support -- Improvement: Send RDP control messages with high priority -- Improvement: WAF distcheck now works -- Improvement: Automatic endian discovery -- Improvement: Accept packets with CRC32 checksum if compiled without CRC32 support -- Improvement: Do not wake the router task if RDP is not enabled -- Improvement: Save 102 bytes of RAM by packing route entries -- Cleanup: Simplify CAN configuration -- Cleanup: Move architecture specific code to src/arch -- Bugfix: CSP_MEMFREE gives wrong answer on freertos AVR due to truncation -- Bugfix: Fixed wrong 64-bit size_t in csp_service_handler -- Bugfix: Fixed problem in csp_if_kiss when out of buffers -- Bigfix: Handle bus-off CAN IRQ for AT90CAN128 - -libcsp 1.0.1, 30-10-2011 ------------------------- -- Hotfix release -- Bugfix: missing extern in csp_if_lo.h - -libcsp 1.0, 24-10-2011 ----------------------- -- First official release -- New: CSP 32-bit header 1.0 -- Features: Network Router with promiscous mode, broadcast and QoS -- Features: Connection-oriented transport protocol w. flow-control -- Features: Connection-less "UDP" like transport -- Features: Encryption, Authentication and message check -- Features: Loopback interface -- Features: Python Bindings -- Features: CAN interface w. drivers for several chips -- Features: CSP-services (ping, reboot, uptime, memfree, buffree, ident) - diff --git a/gomspace/libcsp/CONTRIBUTORS b/gomspace/libcsp/CONTRIBUTORS deleted file mode 100644 index 97240f60..00000000 --- a/gomspace/libcsp/CONTRIBUTORS +++ /dev/null @@ -1,3 +0,0 @@ -Jeppe Ledet-Pedersen -Johan De Claville Christiansen -Dan Erik Holmstrøm diff --git a/gomspace/libcsp/COPYING b/gomspace/libcsp/COPYING deleted file mode 100644 index 54c619ad..00000000 --- a/gomspace/libcsp/COPYING +++ /dev/null @@ -1,503 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - diff --git a/gomspace/libcsp/INSTALL.rst b/gomspace/libcsp/INSTALL.rst deleted file mode 100644 index e68a46ed..00000000 --- a/gomspace/libcsp/INSTALL.rst +++ /dev/null @@ -1,30 +0,0 @@ -How to install LibCSP -===================== - -CSP uses the `waf` build system (http://code.google.com/p/waf/). In order to -compile CSP, you first need to configure the toolchain, what operating system -to compile for, the location of required libraries and whether to enable -certain optional features. - -To configure CSP to build with the AVR32 toolchain for FreeRTOS and output -the compiled libcsp.a and header files to the install directory, issue: - -.. code-block:: bash - - ./waf configure --toolchain=avr32- --with-os=freertos --prefix=install - -When compiling for FreeRTOS, the path to the FreeRTOS header files must be -specified with `--with-freertos=PATH.` - -A number of optional features can be enabled by from the configure script. -Support for XTEA encryption can e.g. be enabled with `--enable-xtea`. Run -`./waf configure --help` to list the available configure options. - -The CAN drivers can be enabled by appending the configure option `--with-driver-can=CHIP`, -where CHIP is one of 'socketcan', 'at91sam7a1', 'at91sam7a3' or 'at90can128'. - -To build and copy the library to the location specified with --prefix, use: - -.. code-block:: bash - - ./waf build install diff --git a/gomspace/libcsp/README.rst b/gomspace/libcsp/README.rst deleted file mode 100644 index c8aff3d8..00000000 --- a/gomspace/libcsp/README.rst +++ /dev/null @@ -1,41 +0,0 @@ -The Cubesat Space Protocol -========================== - -Cubesat Space Protocol (CSP) is a small protocol stack written in C. CSP is designed to ease communication between distributed embedded systems in smaller networks, such as Cubesats. The design follows the TCP/IP model and includes a transport protocol, a routing protocol and several MAC-layer interfaces. The core of libcsp includes a router, a socket buffer pool and a connection oriented socket API. - -The protocol is based on a 32-bit header containing both transport and network-layer information. Its implementation is designed for, but not limited to, embedded systems such as the 8-bit AVR microprocessor and the 32-bit ARM and AVR from Atmel. The implementation is written in GNU C and is currently ported to run on FreeRTOS or POSIX operating systems such as Linux. - -The idea is to give sub-system developers of cubesats the same features of a TCP/IP stack, but without adding the huge overhead of the IP header. The small footprint and simple implementation allows a small 8-bit system with less than 4 kB of RAM to be fully connected on the network. This allows all subsystems to provide their services on the same network level, without any master node required. Using a service oriented architecture has several advantages compared to the traditional mater/slave topology used on many cubesats. - - * Standardised network protocol: All subsystems can communicate with eachother - * Service loose coupling: Services maintain a relationship that minimizes dependencies between subsystems - * Service abstraction: Beyond descriptions in the service contract, services hide logic from the outside world - * Service reusability: Logic is divided into services with the intention of promoting reuse. - * Service autonomy: Services have control over the logic they encapsulate. - * Service Redundancy: Easily add redundant services to the bus - * Reduces single point of failure: The complexity is moved from a single master node to several well defines services on the network - -The implementation of LibCSP is written with simplicity in mind, but it's compile time configuration allows it to have some rather advanced features as well: - -Features --------- - - * Thread safe Socket API - * Router task with Quality of Services - * Connection-oriented operation (RFC 908 and 1151). - * Connection-less operation (similar to UDP) - * ICMP-like requests such as ping and buffer status. - * Loopback interface - * Very Small Footprint 48 kB code and less that 1kB ram required on ARM - * Zero-copy buffer and queue system - * Modular network interface system - * Modular OS interface, ported to FreeRTOS, windows (cygwin) and Linux - * Broadcast traffic - * Promiscuous mode - * Encrypted packets with XTEA in CTR mode - * Truncated HMAC-SHA1 Authentication (RFC 2104) - -LGPL Software license ---------------------- -The source code is available under an LGPL 2.1 license. See COPYING for the license text. - diff --git a/gomspace/libcsp/waf b/gomspace/libcsp/waf deleted file mode 100644 index 4b322f1a..00000000 --- a/gomspace/libcsp/waf +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env python -# encoding: ISO8859-1 -# Thomas Nagy, 2005-2016 - -""" -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. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 AUTHOR 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. -""" - -import os, sys, inspect - -VERSION="1.8.19" -REVISION="b1fc8f7baef51bd2db4c2971909a568d" -GIT="22213cd8abbd141bda40667f7ca2a48f2d6ad785" -INSTALL='' -C1='#5' -C2='#/' -C3='#,' -cwd = os.getcwd() -join = os.path.join - - -WAF='waf' -def b(x): - return x -if sys.hexversion>0x300000f: - WAF='waf3' - def b(x): - return x.encode() - -def err(m): - print(('\033[91mError: %s\033[0m' % m)) - sys.exit(1) - -def unpack_wafdir(dir, src): - f = open(src,'rb') - c = 'corrupt archive (%d)' - while 1: - line = f.readline() - if not line: err('run waf-light from a folder containing waflib') - if line == b('#==>\n'): - txt = f.readline() - if not txt: err(c % 1) - if f.readline() != b('#<==\n'): err(c % 2) - break - if not txt: err(c % 3) - txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r')).replace(b(C3), b('\x00')) - - import shutil, tarfile - try: shutil.rmtree(dir) - except OSError: pass - try: - for x in ('Tools', 'extras'): - os.makedirs(join(dir, 'waflib', x)) - except OSError: - err("Cannot unpack waf lib into %s\nMove waf in a writable directory" % dir) - - os.chdir(dir) - tmp = 't.bz2' - t = open(tmp,'wb') - try: t.write(txt) - finally: t.close() - - try: - t = tarfile.open(tmp) - except: - try: - os.system('bunzip2 t.bz2') - t = tarfile.open('t') - tmp = 't' - except: - os.chdir(cwd) - try: shutil.rmtree(dir) - except OSError: pass - err("Waf cannot be unpacked, check that bzip2 support is present") - - try: - for x in t: t.extract(x) - finally: - t.close() - - for x in ('Tools', 'extras'): - os.chmod(join('waflib',x), 493) - - if sys.hexversion<0x300000f: - sys.path = [join(dir, 'waflib')] + sys.path - import fixpy2 - fixpy2.fixdir(dir) - - os.remove(tmp) - os.chdir(cwd) - - try: dir = unicode(dir, 'mbcs') - except: pass - try: - from ctypes import windll - windll.kernel32.SetFileAttributesW(dir, 2) - except: - pass - -def test(dir): - try: - os.stat(join(dir, 'waflib')) - return os.path.abspath(dir) - except OSError: - pass - -def find_lib(): - src = os.path.abspath(inspect.getfile(inspect.getmodule(err))) - base, name = os.path.split(src) - - #devs use $WAFDIR - w=test(os.environ.get('WAFDIR', '')) - if w: return w - - #waf-light - if name.endswith('waf-light'): - w = test(base) - if w: return w - err('waf-light requires waflib -> export WAFDIR=/folder') - - dirname = '%s-%s-%s' % (WAF, VERSION, REVISION) - for i in (INSTALL,'/usr','/usr/local','/opt'): - w = test(i + '/lib/' + dirname) - if w: return w - - #waf-local - dir = join(base, (sys.platform != 'win32' and '.' or '') + dirname) - w = test(dir) - if w: return w - - #unpack - unpack_wafdir(dir, src) - return dir - -wafdir = find_lib() -sys.path.insert(0, wafdir) - -if __name__ == '__main__': - - from waflib import Scripting - Scripting.waf_entry_point(cwd, VERSION, wafdir) - -#==> -#BZh91AY&SYmEõKQ#/ÿÿÿ°#,Óÿÿÿÿÿÿÿÿÿÿÿ„ Y Â#%H4#,`(bÜrû}Ñ#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,ÕÓ­ul]ZåÍë}i{l4­´ï±®í_pÝlkLϱ÷dzvúݺ{¾]òxì¾ó¥Ô´©…Rúøq楯½¯y\ÃÛe… h«Ì÷g¡éEm.Ç»u­w¦×ºÔë]2]ôõyk=·{»º¼å·[ž®×™½×ywÞ@=ggÅíkWe÷œ}}À}ìowÕãNzî#,#,#,è#, yì#,x->€è#,ûØÜ<¼À*©©{¸WLåÜû·a¦ƒOl¥Ø5nûÛ§FƒËÊ#,·m6Ð ØÑÛPP½ºu(QBª#5 JJöeGc@#,¤’ P6bªîàïA—nâûîׯZ>ÝÃãH½ž'»{´½íp#/ÍKØÔvPÊZ6îîûÞtÃjÒ>©·Þ·£¾{šûzèÓÝl›»_7Zíôìíëéß}ÙÛ¡¦MZûÚõlíζˮ83oM<€k=bWGÓªU¤Ž rz5O{½ÏyÞå뽇 ôz#/o3ÕPKh—F;ÛÝæ·Ûl5­#5ªvê½Ù¦‡¯f­î{©%žöëÕŽÚ»sg¼RÃË’î}¹Ÿ}ÞÐ#/#//·ZÅ"õîiµÍÀŸç@[ßsÇ­·®Øèì^s +ŽÞ€>û½îBqŸ*ÓKïxÓG5_/»=ÝÐ=ª£¾Ü'Ø}Â>9¶¦¶ë¯½÷e…åÏ6íëžÝÓmõvuÛnúåëÎãï{›E³{«·6·u.#/Ýö»ÎÛêï·îNî»^FM>ŽO}¤ÓˆßX¥­áÍL|R¡ZÛu.9ñ.÷;ìí«/nûÝÞÛ¯7rúçµj;<è¼ßF¾ù¹¾öogƒŸnžïj½zÛ|`uï¾uòú-íèúy=gÔ#, J=°#@˜S{0)ÚRO½Ôó5^‡¯^ñN²>·3îeÝÖk|½ÚðöP•Ü§;{¸Š‰ïUíØ)¨+×Kßw^|#,=Üu #,=ïŸ^—|ívõÞ§Ãv¾Ÿqw{ß]8¾ŽtÓz#¸§í×HÛ˜×@ÓÄåÎÙì^vÛlÒÈλ÷¼zÞ‹›g¾|å6ÝÛÀ%W ¢ëî»ïW×ݶûêx};ìßešô>æ&¾Ž{o=—Þ}î»{¶oŸkÛÝÞ:Þ{}»‡ÛkL}½>û>ya—Û½¾vòÛÀÖŠï°£®šqM_^/…ó:è5í„éx_-ê»IÚžÛíïynOµ@}o³+LUS¯4ºŸZ:û=àuîžæî­a+ïW{ëS¥¾ofw[{½ï\î7Ïvò_|î÷\VŠ€:Õ/±¡Û̳ÏnR„+Åw¨Ñ†#/×_wÑãÛ@mg #,#,ùíÜ:;¶5èkGv»sÉ®Wß"}½Àt@õïxõõèÞê“6ù·wuÏN×Vvû¤½­Îíº‹F’HÍÎ.î‰õ‡Sy½çUr^ßN/FϧÝîO®·Ð¦çq«^;N!ßyNû¬·£à´Ä“NŽí¸{›ovŒkwV¾]ÜÚÛv™òzÉ÷ßskí´ÙNÛ®Ûo6¾÷ÏSæo‡#|w M @#,É Ó#/ ™iODžˆ¥=CjA‰‘êx JhD@„Äi2hÔj6™Sð£D4òÓ'¨#,#,#,4#,#,A!! A¢bh' Sòh ž©6Dõ='©é6 Ð7©#,#,#,#,#,'ªQI4j<ši‰¤ôSf”ôÑ=OHz@#/#,Ш#,3I¡ #,#,#,#,$ˆ#, i0M#,§¡¦‰¦"{I“I‚O$z4Ð#,#,#,#,j"#, Ñ #5™é=SCÑ<©ížò‡Šzž§ê˜€ Ð#,È×ý+m«ÿîbcú†Ö¹µ¹uÉ~ÆÛS°“)#5=¶®º3&ª-5³åV­WêêmV¾Èþ#òþ'—òüµû #Îo{ÉÃMòÎg5ÌÇœ¦o9­Ì¦ç.înç9£šs-Ïð´èJ}B-~¨Z¯¦ÛRªßkæÈD&Tƒ%ŠªÆ(°xT)U\óâãóÏEÓ<š7^øIË̶ëXI³&>rµŒÕÞVª«L*ØiH ?#/ÕõŠ7ÀR ÀYeË©jÒµZ*Ú1µm#,-ÕB¨IX(¤È‚ ‚¡!„[*E±#,|à…R‚ Õ F±V«m¯¿kjµL‚@¡ ı™¦ &D4c6™QSR%Œ‰%(ÒŠm¤¨EL’X XMSQT”DJ “4M”-”ÆJÌ £I,hM0¥F’)6"ÑJmIJZS"Ô@ %–’#5’`˜2’)lQm“T#/A”²¢–&¥()%Ò‰Yš‹F¢´«iU©I6¢dÌ™4lUZ•¬f˜fÌÓ6¤±šm°KM±5-M2jadS$š djF•¤ÖB*M&ƒL’ZH-¦±’²h˜!`£3M1šlb`•4°HA˜†31#/†I‘(‰(l›R@‘KŠÉ¡’#2‘„–f–)2A´˜c%4–ÒTZ#/¦5*ECI†Š4Òl(’Q&È¥±1Pl™M¢’e¤2’&ƒF”ŒÉRŠ)™6ÈT2(–E’BH…6"ÒX5 ¨…"J*5D”…3b $Ô–)1H‰”Œd™3Fa-™S ØJ‚ˆ‰!*M‰ ’M%`Ä”–,³0lÚ#M#FÂJ!e$ ¤Í‘)š¥›,¥Ë0É¥’ji”h#/¥ŠK264ed&bIZ––HXCeA¦Ì Æ£f‘±†SKS[M†!3H¢ÌDjL”š@ÓIK-,©QQD‚Š#/‚&$Ȉ’”Æ4 #$4ÌP¢!•3-¤EaJ¤!”©&B”…6’ÒQl‘¬i&I% E’šÈ¶F̆LцÉ&Ê“L¦¢1Ë*™¥1 P©“DTѳSb“(²2bJE*I!e2,Ji‚´¤É²’f&É£&B¡¤`B5$Ë)YI†ÐY6J@“!%“(ÈE3A’2™HË0–’•Mš*6‹BeÈ”‘ÔbØÒLÖE#/&60’FTi#/*%k,˜Q¬eš™"f‹&–DJÅ,€5JJ2ŒÒ5µ6Ûh(¶0IS@´”ÊHÑb™)’cI£l–”³F˜¤Ìe3K*M”±jdcal’#5›(ÊFhÓe¯Úmv4…•¤¤%J2SX«EbÑQ²IšTDÓ%KAQ°Š’V¦"†Æ–!™e) RF³*Ô&Ú,Šk&Cc)–•E¡bd¦5-*c$&,32•Y£e”#k*ER©X¦Ê$²£)µdÔˆÖɦVD©5 [%YYJSL+f(i‘5£KMD–’%ƱXÕ3h¶ÛH3`±ªÂF¤Ñ¶Æѱ²Qª3LÄ5E!¨4jÅQ°ÍHmbY0¢5³Rhe1%‚h±„5(”Ú–Äm$šÆ5!b´’šµ³VÓA,#ei6F&³l‰3)©¥#5I–Õ6¢–’”Ô²¤¶š¦ÒZ¦˜“²¦Rɶ–m¦ÌZ4f¶k32I¬±¡›¤ÛKYRSJ(ˆ C5J4‰ŒQ°b„- 3–ѵ$JME2š£iI¥FLš#/%0ŠE,¨ŠAieH€i¢˜)’e6hbÄ„¤TZ,É b•š’ÀclË3K1š`©¨™Ñ2FLlBÌK!I´lI¤£&h4‹2‹S2TÅ4Rma3`Ñ#5TXÌ1S6 RÉBlE†54Ú3 3h¨±±±F„hÆÉ©¡"“aK-“$¤¦L¦Á’Ø…3R‰2I²ÒˆJ¨²Ô™¢6”ÒlÆÒei+Ä#”dfM”“BTš“)FÌÓj[,Ø´”³I²lbTQfŠJfdÑ©–´Œ”¥¢ÁH‘›$FY‘1¢Òš#@ÖY6Jhbb&“I F¢5BTmmˆ­1¤ÃI2ÄÊ &‘h¦•É K#5¥e$š *5“0²ie24´›mIkhЙfÚ‚H´–ÅA£ ,#/›R”JQliIš¨Ù&k2*H’£I"Ë*ÔƆMEc&&VJˆ¦”¡Q¥%4ET±*Je)FÛ`µ$Qd£dª0Ê6Kd¤Ô›j”ÑIEJjµ&ÅCI3d†RTXiH‹- ””ÆhÁ´˜#5‰3BÁª”FÈÊV&#JKEhƲEd„6%`Š1”¶#h¬¤”T€h1E& “V”ZST¦Òj-±¬VÍ1Y-f¢©š’‹Å(#(1³B$¡4l”Á£VÄm‹hØÒšÖHe¢#5Æ&¢Ñ­6Ë6£h´TZÆI5©fÍÒÊĪ1h³,UMIHÛ(Ë)DÒFÊÅ`’Æ’Ù-d¢Ô–±I´¦eM¢Â‘QIF‹kT­´ŒeCI¢$©”Z66† ÒZ[$ÛIŒÉl‚›%Eµ$¶ŠÑ­‹FÛhÚ¡K&ÖÄZ¦¥e´J2ŠbFÒL`©lMšlT‘²È¨ ™‰1$™I2$¡jM±fV¦?‹çý5üKý&¼ |ü©ŒRžÜÐZdI‹©±‡þå©-Iû²Ò/E¹±ò»´–^ï|¿¦¿¤ë×ô£Æ°Tԥƪ?ðÖã,Sý^‰b¨ O¦ò¢ób¬M4ºd7%‚•Ä3³m´5T;%ëvþ>zãyg÷îÐÿƒÌ³'ù£Ÿ,¯uc/eÕLŠYÝ]ÈZ1±, òt–u÷ë-²'«êÆÚe)‰QéjoÎQmå¦Ðn¥ØГfN½1j—qÈqÖ=c,„Â’¦6Ýr¸6=)`ó¨S‚¢5Š¨ªìÃKJÈÒ|9ëW®Y×[#¿Êní·ei”-M(¥@Ñ ¸_ñQ eRËFƶh&«ìºòO9Q ‰¸‘6Y6?óÀÝ€4Í5ȤU5vZ±ËQ­îX?ùhÿÀ¦ãaRµ^Ô›2Æ*Šžê2ØÁdX¿ë¹aßÝZ3#,©Ñ#57ªAOS(C (`)UAÒ¼®—é­u›ërÖæå‹òöêÞKŠež f>ÐD¹Ó§‘&²–9©%C™E¤¹æ%Š¿žªùOUòmº˜šƒ@ìQ†EÇÛ{zY]J4}]¢­0n(i¥JÂn@rpeË’nºìNºéŠƒ}K[ËÎÿlàUŠ ,D¬ÐÑ(Fí¶R·-"‚¿MTFzè­UiŽ´ÿÚz`™`ÿ¦ˆÎ™O-Li6ÂJ°¹@`@hÔ¨OÐVâ<çÕ€˜Ú˜Dã™{Œ’àq¶Ü`Cò“U}Ã]¿l]~>îÙ›ˆ­Vpò…§†o‘;J0Û)¨ãjåýeNôÕ8TãLhµÅ©j¶0æCfB(t\´Ã·µö% v3IêåS—ʉf´0 ÷09!àá­ñÁ±´µºÎš‰™Ú†{¦’z XZ%l²ÜÝ(ÂOa"ÚO– ½:Þ>×åŠ0ö@¨ÎÚÑfÉPe‰J#5WïÉ—RcäÝ¿£ZÁ6–‘»GÕ"_ºø7Ýv›$£#}þ»_zîF: ãe.¶W7"^*®P‹ÿ‰¥ð$cós´WŽLŽVÚiþÎУ²?.ãä]u6Š1£^9™dÞ5Ë–Æ«ù)¨Óï84mëwßêü¯ ™þº¾ïó{_Kâíå¹£UÝ\XŒQd$Äa–“Þ뻩 (hdS£C"¬éÊŒ&/º_†W x«¦¬oW“ñ{ÑJ_7*#5¾óáy›â¸ÌWíMu­»4 ‰"1SJBÌV·b·cX²júOöÅòW#kðº„"ȆùkÁ‡ÏPÐ?íV"0ãKŸEÓlØþz'<• "1Ò¶³d< ™!µõwë¼®mÔß9u#Es”H²sª›»Œ…¦õAu¢–•­Bz’ZÅŽ£”ÈP‚wQ&šÒ›³äšêP¨¬¢ÚTD×¾ï˜XùíÏIà•½raißÝv‘’dªFÓÊÊ90Õ L"ÈòªKv‰ÑÄ®áçˆ6ÊÃm-8ÂÉ2ÔQ¶Ùìᦻ`¶"§#5ôºœûªŒÀ(ò@Þø%€.ê}UÁ b‡dtAí²—ðŒ´Ö3Úá·0÷"+„úÇitˈ!cûœøÏE0Œ«“ꆀáÇ6¿v¹ÎÞ,MP—“$XŠ‚Œb‚ ÝT‚}åuÒV …H±CZ*SHuÅqf?áNåyaðÚ»™:¡¨ã…ufÿ/jiÉÐ80jN §Hï¯Öo/žø9`Î>®¿/,šÁ)Bµ)ÍA¿:—+«v#W*ƒÆ|™u ²&7½DjBQN84ÛüÕK°™&d¦«ý#5*mÏí¯gÓ|¸ÕÍŸQNoø (|‹¡Ù(ÅsÛ_á|¼»ðÄV'rï¾I3Æm¼c+¯-ÍIŸEMT}[×@0ØÏÂŽì$‰hJº¯ZÅX¿|ê*—º&dìFŽÚmÄŽÈŽ0¡üGʯg™kú‰;¼e ÷›¤x Á×ÇœønãoîqØàäñÕOì´÷¿.w’ô‡ž˜7p’3Œ¶=æF¶÷¿½P'ãûµ†HùOÀÌhËhÕq¦{æ2°oïüÒ¿„ѯ%BÒ„–¨¯:?_ÛëñͺC—öGÊŠo‡®.W’wD+:Äy/²"]žòæO{{õ•X*Rpª‘ëkq*(øV1)"­¯MëÝ´ò‹ýfŠì†˜­PcMïôå1­AÄ«pÒ¤V=§Aç=ÓFÐì¾ì¿n.ØÜ=oeŽH!aÝ$™hNü|dm«]-üÑ”ÈLÛ@áò:<¥—¤!iõ—o »h-ˆHAWã‰ûs2±ÃpTªj¹î]¬ð«³ƒ-öN˜H”Š#5Ft—æ¸>ªµ¨;ùÖ”ú?ÝŒv3ÜÜ¥D#PübžÐÓ®ÏZ:Ö4@Iî¥*h­=(<—Ü+Ã4—|õ#5ÇÅþŸšµB—_xá Ÿ>Ä4¯]ÀG§H­Ñ Œ|]#5b"«£.xù›ã•#/.SθÊîta¦aæ”ÚØ”†•7lDݶØ1Õmð¿þü,8HÑ“èºr.ÿ›>y#/‘A;÷Éí âo͘«HjEá¤Aƒhlù½W—â(¥ôvÝë\—évê0‚1:éeˆ9Jö0¯¢ÑG’·I”Ü•óåþÕéçþ§[Oïï¼û6±º{0)º¡J‰jUª×’ÒÙ.éaðg¸müÌAÖg­@I#5ÇBÞ‰¼`ÑG¡àaé-†{_#/™[á%Îs¶­OÏ>Ñ»5²F3Ù1õ «8 9ºùý71ÝF¿m€§zä¦(§-|4°²øbÌdj~.£áøQ’ʤX€Š=_©žoŽxpîð§çÌU5øøïWìýÊ,饌„{‰#ŒÖ³Õ'‘Tiç¯<P8°)‰:YßmMî£b‰w@ ‚Á@a”ãƒÓŒ=x³Õ¥dÀ}øëy”Ð+MuÞøb…#5nê3›°èM6~ŠR-äœÙ¡‡Žó\æòx@ëpÔ8\Ê6ir¢t{î¦P¤ª¡AFšòh„»ÜäSC°¡ã1ºb™RüŽÓ`^©š;4õªâÍl)W»µZ›ívE€Àe³CÌL¢ˆ²šèóª¤;&#/F‘Ò§»t^yyÊxq¦.K•ö3¸ë·á˜ËÌèQIŒ:d$Z¨g§7‹ ”†B©É=0JŠBJq¢}öÉé†>4ßi¶DÛ%RR„Ç’Â"[àCþõçoqE1×íàä‚ØáÚ{~Yƒ>«ÉökZ™;xZoÚ¤Lhø‰êÂ×VRŠÄ9³HÉ`œMuôÆÅxë²7cÌOrJD2ÇÓ: uÁv˜ôOîrÊêe“¦DeÿØ$Ï:3Îw׈X© *B²‹Ÿ,žöJø¾â¡œð½Úõˆ^ï0s‡wÒ‚åÓX‹F¶;¢ûn^Ÿß‡Ž›\ÍÈT#5p€Lt"Ý3ÃtíÝé8§Ç§„ÊóÑšMÀ¨§ƒHœ(£1ÅBP0ŒA¢Äßøºj¯f¯†§…Ó»}s[Õ{C©Ý}ÿ>Ï7M/e«å-o‘Œîe‡#5#5Ö¼ ¤dSRª{^{÷ê}i›ƒ¤#,$ ¡NjG÷G5íIÉOµÇÔ?Ë–ç§WègLäãóg]EÇòü*Ô;Þþù» ðzþ¨/o/b‘œwÒA«^?%g%ÛÓê÷ªzn©÷|ö.?#×}$éäüq=^E¤nñí¥¤Ö ìFcïv–f¦¶,ù#/³,ðgîg›œ!³¾#5~Š«ªPžâiå:: Ðš:䲦‰ïQi±WýÐÊ9ªÃÝkdUWk¢™B#/IMvýõgØøé(:0Ì"ðp8®H±/Fý“à@ô:Jæg‘ÿºÃª Uüבä¢e;tÊ™á‡óúÎ3†ÙöÛ¹ðÐC~ÛÍêÜôzM,„ÂçöÂÁT®œw6—j†)Ú!¥kûçövñ|­Cï£ÒPðˆ—.QËËÀGòB|‚rÆ=*D2•þ,Ñ®wÀ ÊÈßà›3•ÏÏÒìâý©ÕÈá´J?JwHMÂSÖ¥ÒXTñj,‡)< Ó'iÆ~ÈØG÷u>’wºÒ9×w5‘¬ú¹Lf8ë$„¿Z‹LÅfã4ž.çÒœLVsR÷¼`ÆY ALjg½)ÀÅ“BÏj~oJ“4„³}vZZÉU):èg {·£uü8P¹¨x󘳜ï³leüÊ:o]éùÙìÞÍÄîß<ï{ÔǽY/”?3Çðé5œÝà_µÊÐÓ1)4º:mË¿–šCuŒ›¥»¥ Ì „(b1#»/4ÜÂc-Å;Ä2Ž…Ç£«1T]†ÆcFzÏf¼ñ…YÕ#5FmUSZ6I»+dU½^¶S#/›4ãßO ËD=ô[¡©ÝqŒ1ùÚÕ¶UOÛÖ±Zä~ë3"Y·þ‚c|4oZ–0åÁËú]y‚üQ›‡ÛQâûÿFÃãó뼟#/6#/ùAA“Á©zø`e°¶÷¢—TT•˜,„UQ²–PûzÝkLCh¢%jV•MP-R‰¦˜.ð€èÔdNdƒMÙdJ¿•ù¢ç;­Ži]š\òQ?†8ÁUòØ–†Å#/ yJŸµRN5ûZ+H÷5úZ:||jînÖá¹½h§ÂqÖŽÌìëÙ˜ÕaÚtèI«Ý#¶Û‘‘§&ZƒÄ‹#Œå Ñß÷CÙmÃ)ã.#/„6G®it¬„/½iô®µP-§¥Ž¶›~òâZ0ú:¿~®J+JmÇM}î/sÚ»±¸´^i@ÁÑñ©Ç%”ÈCÊAòÍThÝ°Ñû|Æ‹Ç[4¨wpUüÜϧ‡ýú#稺…f¾\bÊÏLc‰Ñç¯B°Vü8éqæ÷ë²^©À€¡ Æ&[>¼Üµk6ª«Ž˜ñãl<ø9^K#/ÎÌSm/××;)ÂøtýVÖE×,×iýëþÖw-#5õÄ4&á7ÂߺutßÅdwçi#/>÷ÅZÙ~ŸÓ™¡©]w«DÚñ¥ï¨û|œ»}>˜ê®#uŸ¤†òñ´ÎÉáMgYYRóªó«TY¼q‰f¤Üбœ*qoj å›®¥ñ“f+­?Éæg—mº‡Ký¸Ç&Lã·C}W$3Ó«·4àe)„Þ«­býŒÕ“|×Æ©Ú²ÂÐ>u?……#/$î‡Ìã–æÂçŽi¤[Sß¹åÔ‰¦Ì“æƒïù¯|Ó #/‰é®Sw?„ëë›Ù{œùFÃÂ.Ó_Y$ŒøFïl;timâøv¬¨CÛÇO”+)ŽÐ~:*‰ºx­d!žÆ4W'߶Q1üÖðoØ„÷IëúÂfOÏËz6½Š²k.&Ü‚õwsŠð$D981…2â®Í»±í´øåsÊ#¬ŽOn6ÖØ›*3לÊ[LÖhùW’"¹#1˜|α#,TªME‹ºMqéªoävs6¸]–/œqŽ\ø<$öAó©C}¾%è•©LÑÉáSéM$ÔV9Ÿl{§šzk;öO~)tW¦\¹kר›¥§Uo‰˜–¬LÏ|^Ó‘s›¥žsÙe¶»¹ÖÎÝ›ìanÊ‘ üj‘@z•A6‹ßøý¼†ö´3Ž°¬·‚W{x‘a$ý++o}ÝZ¢@þ¨³e]Ò¡ºà•3¹äúT?Ù…S¨ÛU5ºÚaŽãnæ~ØbPI𥠮Ž¿/;#5ä‘ú ¦ÞªR“9ØK8ǣü¼9·Ùѽ(ÃKhœ-¡ºGsÂ(Ùk8Aqj wÇ”„Uü° s¢Ç“ÏŒÚãî‰Uy_¡'·~Â+Ž~ÕXgÔÒ]©I•â#/Lx¢ùBw3Â>gGè•B²BÇq×]!©¨w]ßçÏœ]vÆg›ëNßM4ô¾À§aBú9æsÒ5xöí¨£ÞsµG ’†Y¡Y†µ£$ÔÃîz´”¹@¾ì3š^Gt—+Î%y ݽ,Ù|ÛõR¡T¼$¥¼´IëCî—ÁYÛ;gX²$…MëÄäóÇC ÿ‰§Ù¢ªvgÑdKÍ9oI×V³…™ëÅ]ŸJÌvsȵ¤ŒPRÑ®¶Œa“¿÷3QÙ¬C Œ>©½–Bû÷ìÙ0´·¥òTUBšˆEeƒµ¶([¡(ùhí†G„\ìÙII“Þª‹K®D+²QÃášÀ«YÍÑæf®_m#/žìt};ôx#¡ZÍÎÖ·øÆ>cÿ8K|MPÓÃýPññå’ŒDÂd!,›I¶KƒÊæƒeN–ÇMÑbˆdÜ]‡ç;ê>¢ÉUò!¾yzwîgÓãòç¿ÐªPÛî[Õ@ðú?š@“L$NLjÿU­£¤PX´[7åä³ev4ú®P©iÏ›iyÐI'iq v†Êyº#/z¬¨¤8è‡Zõjòú¾›ž½¦Æ†þ Éîæwñz{&|I¾ÝZáÐX‰˜¼DÛFì Þy‰ÉT,cšÉ˜@#,˜`>únãùªfk­ÚøX~8Â~%·e“¨ócº¨šÝäÝÿ<ÿ¦æÒÛ Uí·i€Û À‰G’oŽ ÿ_;#/¿[´²Da©wà¨Õ  "Å‹>gΤÇÙµ]'•neÂfqU Å‘©z='U.aš6|½¥v•…O…¼¹süÓ¤QîüåÜÉšo$ !ãñU³,ÉU«}Z#W`åÕu”8Ò0HÈE[„^ÛÜ`//«]º#/tP^(ƒ–¸–wQná…·„VÍ%Ît’bƒ(ÚÌÌám˜Ìݽp“L'o˜“ 5û'ìs¥µË/”ô›Œ@ V„ÈM^%€æ-©ÞîbæaµÃÝ—«©bíð‡¢›ú~øûþâ€cþÕ À¬-Á§ø°t‰š„¯£PŽ#51U·Oìï,…P‡Â&£ïöw̯m¸âÇø?èòb®uYƒ©ëµ®Ê9•TñÏ?ŸM,ýxÁª·ögß ÌÚ¡¯F΃›ãӮݷXG÷ÂíÈÑU^ekuþß'TI²A¦Hk+Í~Fî!I—vsõ×^Å€ã€ÎQçs@õM=¸ä˜#/¤fÿ»¦ÙÕQL"žSL+Ü¡KSiÆÔ£ú sOǃ:…NVʹ”SsAßPT%B'ú? ˜u'.BÝÝ®³é©±ËPõŽÐh`¡¯1ŠÕ¾¤´¥æã@vü©õh7)ÝwÎyî*³Þ‘Á­I$5!ÝÂe‘óÌr&šmïC³C(¸³W&HLÁRÊý’iÚB­YàÓ{­ØNlÍ¡3¡†’)G¡5ç4nÛ@Û;Þ7覧þÊÍ‘‚)¾œuËÌÃVfeš5IDðç”jß„!@¿h¤ŠG4hf6D™X9FF)èÄ»ÝünZC†ÄDKßm£IúüyüÕ¶aÓÒå»4ÁAÀŲ¥Âñ?†¥´¦g² ýX<Ä ÂZ3°áÊÞ´IÊc#/ŸHªc?Œ‹œXXÌúéíåv‘ïìÏðŽ[Ù ¼»Œî*뉣êQÖ°ÆŸ{wN4‰Fè·ÀLdIAÛƒ´ˆŽší3¨×[”˜B¿wE fì°²‡Œ„©8÷p€»VCùô ¦§±#5÷L5i8.^£TéiݬòÇ40öþ\Î×s¶©ì\løîlÿ‹=ÄlêŸp·¯vöµ®M#/µ>ÇùòúàW§{ßl½3㢂̶WTô™ÈÀ×xTs+•¸S´ÀÚ{¥EP¹§~n^&¶þÅPï¦Ê.XZ9™IÑ®¿¥=SF™9ˆg!8ïyùþ—W¡4`˜üÔytÅ1î˜×ó©7,»/+i'}‰†nß”Ùðþî©“–Ðû†¤lï°#Ö:§¬>sñèÒòš§˜ÊÛl;BÞ`–§iùŸ•dŒVÁFú8Úq”ªtyG6¿Ÿ5#/+žÆúo¡E{fð÷w »¬ppÍ(”&d¥ïqÓ­|ŸÃf¸•‚áºÒIÀçË¿1œ åU‹c¿v¨Ø餑&`q|kŒLþ 5XQpùàâj‹‡Ü23(!°Èò¦íæËî–;¤„Aë|»¿Âö¢ãY#5mÜJä:Å!Ó·³¡ñ¦øïûkM³çV1»è¢ÊÇ“’&”˜«aÌ/†'Þóžk¦ùòԉ½ž*ŸNu½ÁD½L‚Á3´‰´µèJß?‡Ðg<á@dCDžÃ#5j3xÚX‹TiˆÒnÀ£:2.î\µÆ ¶Öƒi¤šQccyHà,ÇlÑa%Btš“0úæ?œq§¤ôÌü.£C¿ÿ`‘BÄ=uìç"1vŒ•€‹ ´‡Ðb*póÜÕe…6oçü¿ÈÌÌ¡™´!³¡!&[3F a6?>¹6LÕâå\¢•AuØÍ·¬.ÓªúR|ân [#5 hŒ;2ÌJAÈôSÄ£6.²ì³fÂJf”óêZ%•+æ|bôcÊN¶G.ä¢Óg]w$¯Çû93ÆÙéó?³ÄÉî®Ý5×J7*Wk˜²jrï•¡ ªÑÎ{ÈoóÆ;‹ÓXýZš„ww´Ù·¾ ØnÚ3‹óÄ@ûƒâ\ëÇHfÅ]†ZdjÊ!“â¼v¹5n>OsÔ5›_FjÂÿE[Å7sn×(Dð˜¤Úã¿ã©Û²f}‹ˆo(}Ë¥é/o¢ùÝ3MÔ#/*ô\˜ÒÛS‚c"ðµ]tÇe¢°üL(Dvó5èyÓCêÒeòó´Ky£lÎú!ÂÅ8–Ud˜ùî–Ià ‡0¹6ä`‹œ½B˜àB[‰CÕeØ©xìú\ªN¯ŸXÄ?Ÿ~öŒZWÞxßV8gŒâE/ptv6À¨¿1+Í- ÜKu—–™‡ÂÁ!+²5D7­KaA³Ù¦qšd·Žˆ=3`¢QSO›ú»ÓîŒýËñbYuvL 7´Æ` þ_Ïò3”‘ldÚZ¯®Ü+ÔCä–|’ó9©Ï»ÀªóÞùò{ê}2%\z¸m‘oM[ ‡þjÞ=Ì4å¾q0öÁH¦Y²aµ8B󺻼ó4æ¯;‘˜’,i•¦JH,Š£µ¾XÐLèÖ¿o?Gßœ=úr8üžLÔËe%0Š(5aH­RšÄPÁŒ+š>­{±­¢jED¥EAa zêVå —%YbTÂ}~Zâç 9‹×;® Š´< 9ÅFŸ*ŒP¢“’Oö~º+fcÈÇW%Ÿ®ƒ’莚ù¦‚0þ²HXºÐf¸0íf¼d­ø×Êú£Ç<wòÍT¿uH6\‰²E…0i©¥Ìà]äÉ*ê‚ÐÖD\LÄÀ‚l`Mü6W›ôñŶ•u=&0á‡t……"|"n¾½¨Æ¸‡L™×MoãùvÈ=Eóç'8H£¿ÈSÏ·©¢Œ–!#NÌí^ ýó†Z«¬i[<.ž6P*‰#5¥«7eP¹òƒS†¶ÙßÐ7bPžG®æˆŽRÖŸù2TÆ4`œ@×8jLL¦ŒF“K"áfƒµ™­ ‹å™›#5`g©¡œæÊ-TbB¢Â®¸ÜÑß]Mt:›´Ë®ñ^6ú-ËJöh?­‘¬ù¤1Š¢¶à¨%¢ó0ÝáÑ")œ…" G¿J.ëϯé‘úw½yŽüˆSªICQÄ(`a kï5¼UÉ4[5-Q¤aÉ‹#/XEÂV\ !<î­r×ÉnÍ⯄VêVÉ­š–½Q½é­°åBê£hD‡‹F{Ip×kN:µóŠW9HU’غ¯«U¥.àHªo>µ]Vâ"/z(•~©r#5°«+j¾O AÜÀÎÆîK]›ÈcÙ«×ûj¯v={[vëƒdIÑàj=qÞFRUxoÍ¥Ÿñp UswØU+nnÈ:.öÐÍôz¡êÓÓ–e~ƒ<P¶1öÊ1gMÛ7*â_'‚Ï0úº½ÀJÅ7(’Ù#5™H0Q’車£WË2¬úr«û³Õ“u˜­¨”»ŒªÜ¹hÂÊ) OƒnšÜt¾²I [º_Ž™Ù¿]A8âòVT‡ãP[úÜÔ“™NËù¿Å›¿»qž|tKƒê¹Î[ãðŸyVàWí­÷Íø6††Ná¡—´MŠ<·u,Ư âLÁ³:FßU¦hÞ‡1ü;HÆ‘Œ @ dJ•¦ÛÏ/5Ûòë±±^¸j-ñ/F‚d‹"ÂÈÐ ’ RE—‹¢¢²˜H4›I#/ I³.Îaϳš=u:Äj¢úc³ùô­5¾VR…k/’IÇú¬îvýÞ¼ñÇsÆc«üË©’è#ÒsD»OGÍøM‹F)ÅâH„cpÎ"MUöo¿WáÈu¡uG¾#–œ)˜{žSªd>?«ðr¨dÇr6&foÙ²j[!¬×J­!bSB»%ÖMk6{fþïp#/¶2ѲÞgZwéÊ/ê80n\„9PÁ$ï=®˜Xu,[À&ŽÅŠ­iêŸ ý§/ôËRdOʪ)È(dµûÓ.Z¤ØÆ(Q…E·T(0QµÔϵ’–L·:+wÚŒ‘gwÕ9¼†!ÇJ¯éiKËÈéÛ¥þ²ÙøÔÔs“Äf¨î¼ÜûN~¾\¤Èn€˜6ó$”Á<>)Î.±X‘! ö£&}÷·¿búŽŽ ð’þ2 ×z’lŽëì² ¬v×LT¢‰d$ŒyD}^ò—¶ßgöÎøNÑŒRèuÆ–8ÖT¤ˆ¡Ý®q/òÄ}–þ/)$·´Ø^sfõlÀ‡÷*ŒÛräÊ´‘¢Ì‹ÝU,^;æ\ÓæMt0se#5kã,6EUPq'=q#Ÿ^ºá§D>±à¡lÎF•¾)NB„xSqF†£ü* Y‚$/#/2·™&½¡¿ÙóŸòàû Àܲda=®ÄÝ­,ÕÂ\&ãf*ÑõÈZëÚjô¾½!ÊóŒ×;¤1î9TÆuCBs U.¢¢$ÚŒrÛ\ÚHµÍ¹­ÜÚÝ-¦iÌ÷n½öºDSU<*ì¨.;ð`X&Écñâ¤àèŽfÖ¡“ ¸n‰d©LNk”Ëë8ÇHQ¨rö>ÓÚzÂeâªhS30gÐcÕó`L#š~m!ô·#Íí#Ç/¿ÊFÝTŸoÇÝï]ýltËQ~×PÌbæiŽ«ê±­ #/„¬Q÷þõm¨ã¤ÿaëÑÕÚ-;ݾ´ÇêÞíÒŒ[ÓC%ߊãÊÉIŠ¼ÔÝåå«çÖjÖ<êyuåB?j§«`Áœ?Á½ÆhW,¿ëh¯ÖŽ2Îÿ>rã#íåoû«"å'RúÎôï ïPxÅ—²W–Ç+Û“Ë©­iÈ"#]“¼ 1û³BF]ÍãÈŒ²Ä½4†Ÿ=9üxOÏsÂzú_ìû;áDUãâÓ}><ûáË/1¤ÊÞ2n­ÿG&iŸ×LCk¸bÔƒ¨Òuüß«/5µÓÖ֓*“Ì:rëìÙ•·¯¡_ÑÄñ^+Ëùëûª•Òó]ÐZ!ê>Ì£Ù*6mçõ¿ðÍôcÙð>N¾+ú÷~Þ>ï·òųæ3öf_ž:Í´™Ø½gDøK;¹#5ì¡ ×‰E¦Qx Õ4{hyOçfßñì²Eʼnb|•ãŸ®_'¯AC9<Õ9³zt¢“FB”Ó–¨P!õ×­¿õL²k;±ù×Óöwé·•¶ ¾Ü#5ÇiéöY÷ÂŽÁ5‰V¡GW3à«Éa1¦”4Ü åÞQcziÉIP%4QhÕ¨%B¾ïßF¿Ä*†ÚhÿÒªB-ôÁä‡IWïü¿Nš¹™™‚–X0; ]ËÂâùsWŠùÿ{wëßÈsœ¡™ÄÜ"Ä[ø¶‰A™!!…Bb3âv´Lµ%“øÊæLHfÊ–%Iùf&’Ò£kúÿŽvÝlQY\Üvq0Ι ’ Þ&¹1 ¬=Å°ÝÖ^[-ŸÌÄ? MÃnzM¦v¶‰e4.Z)M!t¿}^Mzߣϻæù1ãDF"whª #52’ØO€b¢‘S†‚&H'{÷_ôLô®ÖxŽA‡N+Qó¡Ù ÈdD>žŸ{ý]L‡v0ŽQ£ˆ0›$3~ër½¿¿®¶¿B½EXŒ°ÚŒx¾gáb™d¿é«Hu¢„dY¼#5gEkò«Öõ·K^Í]J½ImóÑ\ˆ%%„Qñ.?äùÜúS¡Vª%´ÉlÞ"–eHhÀ¦#5[*‚‰àù]Ã11þCHOÑŸ0xjgüø/¦$(—ãoð³¿%Œ_ù#5»U0}q–_ùé§ï^™?3üììÙ:¦Ú [4À6?¸ ž³S»Lë[ž13£ŒN´?á½$y×%’1@z‰»qÁ„ ÓÎö ¥mú"Õz_ ΢׸n"=°áxM *¨èÎ3 뚣IU+«ÏN_F,Ýø#âI@ÿ·*"Ãû.N§#5è’‘P‰CdìQŒ.ð±q.CÛÒçúBkÝ…gâÖbkßùØdE=l|öDU)I÷0¤ý JÃõ´#·Mj°šëjú†Þâ–füÝuý‚å£W¨ê·/ÆÅ$㇮¥‰ƒCá?‹òÕÓåÛë>Tbß-ß»Ëñ§®¿¹Ú¸sÇž>8[Â%hæïÏïŸyù*ýÿMý"MÅy—JûŸNm…>‰Ö¿*™Ë匩E¬ÄÆi|ÿXçËgáÍa×vö1•t‡=¦ŽÏßH‡:ƒo­–ƒ˜–Rô<5áî{-ºÚG"j  Q‚¯•þ³&jçû(áÐ*ú°»#,ÀJo¹|ezmûf~áàµÅê¾?Ãþœ)í†ÌýúÓõé ¬»”M¹õÂ''ßÝV7q™°¹,RveS»wð28É/œVÄídîð$/@T\cLï¡îª´3cv¾»-E±Ø£L>ÝÀ4#,Ô%ñ3#5Oóô=Q[MW9ÙetŽ˜Æ=cñõ_[*[åØ´å§ÍEÍœÕÁ²Ï¥¯è—zµd ¦ã¯‘a¤ÃB#5LÜý445è>K·ñW*–¤ßYÜz¡=„¥ÆRLÜíã?Äܲ\*™wÂyÿ~ïÂ|ŒÎ¬ÜN& ^Û ?.¹©ÝT8#/ZÅ5ý­{ò€¤êÍÄ…¤c‘°o0€ÛNÂsüþ ›:Òß9t û „"uúO|ÈU¼&;éì·ïl}ðèÞIÈ~³ù¡Þš“°G-²DǯŠ‘,îìïå ßÜñ‹ýoÒÈo½Îc|ÈÑÙHxžG¤¯ÔDy¤!&B1d8ÐÁüóù Wð_¶?uŽÙ“fñ!’*„ùO@‰Ö˜|‡+N/•©ù?ºuôgYèÏn¥›y^9ÌœûS:gwi‡³ƒóDáIM~‰ˆÓ4ÑŠ »LFÚŸµè{!V4 A2IbçBÉpVl­à#ƒýYà.½Üât’‡cšH’LJ·×~µ ¦ÿüÁØòû»Õz0:* #5|ÀK‰¥TR#,Ý TDDEWåîñ† ÝÔîöLoÏ—M‰þeaüµúå”Ò%'ô©_ããÖ\Zñn2Sh2PÉ,ƒ ÎAÀ1¥ €ÒŒ]îoFƒåÖi31-´t¡1ûzŠÉøÓÔ¿ŸÍ³fîùfïû{{¸×êòâÇÛê>th|´tÜ»XöÝg»KzÿuÞÝGÈqü·Þsé#/xT{sÝ ìÀÛ3Gš¹ÆšðÆ/çPïêî?^½tiÇöíʼrÕÕùgÝQŸ£uÖBáUüèòá»~Tr«Žò¿úOœ¦~—½CÈ·x¹éþ8÷OMµ­³ –¼wkrùãWÔó‡DÍøÆ_)À§ÃuŸ^ýÞxú—ͧwÞDá¶ÍÝÍŸ<÷Ó»ö–†ˆözsËŸ²Û=méòñ5™°;²õz4ž\ú5žž^-mÓø7¯ùü~}7VGãi²f¶ÆœףɻÅ#/íæ×+%BÜ{bÚqóöž9N+ôÐŽ:àÞ‚¹í,9Ç?§fãÃg=÷í|ÝóÏú©–ª³Å»«–È×#/¯J¯ÌGFÎjàu~~=vû²l?¥0†zJäOtªå§Vy×l«4S\‘,‚ñZºö´Ipç=%Ò>^û.ðSž]Z·U³´UÒ:k²;9ÿ]1‚öâÜÕߤƎ|vø¡nj·gmJÊy çÝ—IÍ®Ìô°ù\ÀÆ2+ׯ‰#5U¨<8œ„äŠãô<¡÷üpm~òÝ:ê~Eüæë|°¸Ù·Ô´éJÝCø‘?wŲîû´úyüv–CŒ2ݳD'år.gmQ+õao.]¬ãÍeû=WUZeB+ÏÒ¦ÞZ¡#5•kôòvPÑþØÜ©ºþQÉ®S†Ùuü¾&¶7Ó3û¿ >¡´Iëæìüg™ïª’ѽSIŒ‹ÍR¯ß$£¹ÿMx~O6{‹!׿?ÎyÈß- ®+òÃdž_vÛ:¬È'ªÿò=Ê¢ï€AáPe Êß^»óÚlËuîŽßoš>ä¿n«—×áåáJbíÑüÌšÚÛ£þ÷×ðÚÕŸ»gËüý¸òÕ›B‘\çýœz*Ñ‘õzÆ¿W51ø/U[dXhÆݹ»gWó=™9µYgº€^ÞY÷}’¸³O]Ó/n¸{kÓÏÏüvëøº+¶ÉæMrôádÜ„ÿZK×\6¹þ8éjË“qpGtK³”×°Ž3öfÙ¶a²È—ú|ÿÎË~læmÙºOy·ý¿ËwÃäïúáXo?[ïæÛ|ñÏÓMB-Ñ^Ÿ]>&æª>ÚDò¼Ä(ŽøhðúwsþZ¿IºPØòÅè¢FFU!dÔú9Þå—ÒS“åáqC°H¤"œ‹L$⟎Ï_Å *l‰¦>@E ÃZ˜¶25˜fÚG˜—Ùòi÷ž ß»´«Ÿ´éê×óùù_ËÁ—¯òù~z÷öè#ð9‡œèòô°spšìúX¿oë­¼ñì;Ïô÷ño¯òþãfoš­Ñlí¯WEÞê›CTÚ|ú_Ó~˳s+\û~_x~;tÆ~£Iaæ&Ü^–¾7Í«/=f8|ÛEW.¾vÕ®ÉðÒ|ìº'ëÓi¿ðêÌS|²·•Rzì¹Û»låøرuû+êZtš§­­Pg•±JüíP9¡[ÈVË1qB T/;WRØž•¼/“Ý©tåÇTë²™^—Ç®œÞîeJKNWõf»–TäSsv'k»òÉ)Ês³—Ù Q¸ÂÜÍÍ)ÙýÜcÆy#E’I'!i!¹Ž¢Zƒ9/ÜÛ?#/^k#5óíõ ²¾>­_˜Ãâáâê¥;žÀÝ*kMê”;þ‘:ª'¶S©¨f‰Å<)ñí„>8Âœrìçß„1ds…óÂhœ!rÐ˦~߬rl}÷5ŠÕ½¹µwTb©<èäPÈØíÁõvDN¢Ô½ãvïŠ~¾UÞ±Þ·!žZ‡ŒüÒPéZ\ZgW ËDK¢’áBQx 3d¸YfHg¿ˆ—äöYp¸hâ×a-³Òf*•ùËrϯ˜ªÉ™l¶üÓ›™½[;âh÷üòÕauÀ‹bq&„ÑÆ%£–É„zV€Ë1 V­„±}2+†ó I–ºW k-ìÞ{ÿfë„'¦o›}†üµ=uÛ9c{bgîצ^cf·×mv·8›ôBP”+çšP[ÂiÃËMùõ>(c“9§HJíYŠ¿ÙàW§=‡ùK¼`¾—üÔ²y»5íÝÍò|•V¤r]:’®—vw×Ê—Ùëëü§GÃ/¨Ú#“tð5/ÓêÙ#/p<ël{ƒîŠ²Iÿ_/d¾Œºnå‹Ó¶žÉF Ùy!ÝÓ4"«ÎÞ6Ý}F8#/ÛôÇÕÓîóú¨cê4™G¼26©tÈÔsyJ\³Ó×Q`š„ùd`Žï>p#ûIȃU^^J¾Š¾©…×ê­õ.EwË»/¢ÜÕøý$¾ŸËWõ­a\q´ZŒÌ¹‘²¶ä%`Ïž*;GªAºÖÇuöÃta­¬¤°ŽƒšVŠ•$Ç´Cc†E„‚ª(8Ü#5*"ªjDÚF 6ΞšÛ[k[‰Ò `ÒŽ ÈLXµ‚V“a¦HhÄYSI¤ÝU X–š’¤0­Ò#@ÝÓ¶–k¨¨,›Ä06…ûóüY‹Ã8h Ô$m÷E¡=ø§M§X¾îóÈÞ³!¹À‚ŸìuòX~Õ1©&~˜­Zj]'åþáhkQ˜XÁàñغ9ˆˆ¢13S²%”R(Èùªæº t{¢t/9h#08Ž$ø™”ˆŽJ:QFk1}KIPc 0i`QV‹† M@„4í Dé Aà<Èwoì‡fIˆ”xS-ÇÔgoþl,î)~½ÿŸt»gÒ·Ÿ1‡ôëÂËóQ¨ñ/4W¥hÑÙÓ?¾«9¶Y¤æül¦Zµ%û½CÌ·þŸÉæÍ÷a_#/úz~Ó®ŒDÕ‹u~½-2üÔß]Ÿ%Ë<ãÙâ{n¹w;åmxû'š”ÓæýóÌ=ÇÏiäÐ1¯¥¬i5B·”}#5>fÅ®>ãÉÕêý_ƒÿ…^­ZýišöBB°ãÊ DÒ8%k½ÿw÷­?AfoºwqáÓ×¢}Y?¦ú‘³ñ…Ñþ’iIå)B1x×^@Àäêñã?åÛáO%>ÿ?㪥Íá4N=ßÜùÏ/ÉguÉ~>w祑ùkêøºÿºþ®þš»ïüìݸÝû«ü5zë(¨–‡î¤à}†spçGÁÊ|¢®õ?È~Aˆøo{Í8VšÏHm0ÿaÌcb!…hô22Ã!I¥n0KJÑÊØ¥ß%IH Ó@ÓHÁ˜2¬)#,i³ÜuF Ó¦$©Z¹LÚ›&ÈÉ®Ýôó^šö÷ÀÄŽ˜–™SÍ)jŠ€ÄÀr7h(UX¥¡`È£¡ÚHŒ*V&šefeX6<+-iNþüF„<Ç+Ú“{†º†Í„f#/² £IºàEƒ©‰‘AÆÚN…iÑÅv“yåN=Q˜R2ŠŠ9‰Á£DI°n€ÄB° ›pcK J ¸‘Š)"Éó†%ºæ¡¶„¦ˆ2)@lƃ2#/e&:EÕ‘'(<)‘LRÛŠX›-7օ̤«J#5%F#50¬ (älRÍ>7³Mi¡²ˆ‚Æ—s6„B§ˆ‘îÀÇ⢷f“ /öZU™¨¨V¦œ®Â jPï‚ÀÇX`- ed ?@¡ÐóÈQ§Â'Ѹ˜.j.DÝÊGºìqrº¡hs#/ü¸1”>=j0}'t’Pƒ»¼0ïsòM¬8…Ù#/¤$Ò¾«š0,ô.e‹/³ùÕå¹óš~hsÌÀ7ïQÉá8m5_:ˆñô{þdã·ltþTmg"éø•vS“Rìi— ²v÷I¢n7]#/CŒŠThb¬ƒÖ0£«ÊI¯DðZª^1¢ìfe!™i?Ï#8þ^[©50î!Ý5ô;ÖÿŒýÓôø›£<(.™£ÉÄ#äv;³)™ ·¢€¸ÄÐ|oà¨2{»ÙËþ\þûn¼XôÆ–TµMå Ú­EUµ6Ç?ðíS§Qá×±ÿfhèïÜTU¼Â[wBëµÛ¤/ÑÜž¼âBBåWÙ&Ž/^ša6¼yõ›¶MšºR—±FåºjnþHÉ$·o½•«hqØÏ#/<Ú”%­èµµ£&¯­¢r¶ý;_É56„UòȇÐVç1Ê'}˜}CŽnLé €ø •DÛÿ®±¦Ú¤ld„q‘!¨—ðb¶?Ó—MìÒ60¬Î8;"Ê·LÐ!ÅO7³éÕôztÝów—ÎõøOþ¿¦_DÉ‹cꀠˆTH(¤QŒèkš°ôÉ(VôMÁëLê ]Æ‚^©†1‘¡¥aÃ[ÌÃTu¢šùè] ÒÞà†r‚Ì2Æ¢Iæ¥f˜äq|(£x8V‘Šã3ƒˆ]»” Ò*0be¨°#5¾§¡è‘MÊx›X0¯g½«Èâ­–êŽÞÚÁgáó1@¼aå°Ù²=°¬h´;_ÞFC4FµÝ£*%ié†'äeCÑK9ntlV ‰ž™’Æ‘à:iëC9ª*‡·§iâ3‹b4‚ƒPK³5¾j&JQ@z+F ,#Q6ʵ´kï`bäJ.×^Î )iÄêvº‘rŒ‰6Q¨k0wçc+z;EA³¾hk ·ÄZ4”!÷îõ5M)Ž4ܦˆæšÑ ¦ŸüŸéž&ÿï?}éçʪ½Ñú;úéC£êÊÈô÷S^_kwž3^c¿ÏýÞrìº*>äV¿¿ˆü)úØmâËÎI ‘tÒHÜØêluÚ~&|f7¡TΘ77lÓ€ãDc#5çDŒx»S &´21· 1›l£'bF–åÖ“qÄB2š‹õ’,Ter¢Ö9q¼UºöT²ÀÐœj¸¹¦²dÄ…”9¨´SLŽÄËÌ…’™A ZaϬ|C;öÒ®½-j†‹´ªÁôÞŒ¥¤e]Jß1§×@l*œâCr¦[‚Çã9¼P@™è… àtДC0]#áŒfØûÓ³AqC­I*V÷Á“&sbÓ-Œ^,\ņÊy¹`tœZiAȤ ‚ŠGb“vHƈé”OR¿ºkYþkÓ¿©wóõä½üÅïŸïTGò†ÿgÇ«Ûë{ç1J6OøÅ)ÕãWj¶63sr²Ž„Z™ÓÀ˜0É©4NX°#I(9NÆÉ‹³»ÌlßGqªVdþ¸»­ÚcºLåpr¦v‰ˆa”G›Q#5šÐ&àð¼Ó‹0œ‹Ô„¿L¤—ô#fÌýí£#/êüj̳˜ ë;d3ÄÐãž,X« n¹bŒI”ÈòQ”pÔ.6ó²ÇâA±£a©¼l±·#f*U¼Ã2ÊeÃs]×›ËÍçW]9wP$$¡°`ÁÝšÙbЧ…ÂÍV¾þMw+^ïæÂ" 7¾+š±]š](Ò†‘ÔÀ¤Š¥R —mdÓ×GóÕ¤ÆúÿtD˜(4 x8)#5Ó°ã —È’4û5ÄlËŒH™˜¡#/§ao|›!ŽñBiNb™Ì!8˜‘±—#/’ÎoàDJÃö°Þ[áË€™%À‰Uº;åœ3˜aŒ/Í8kÒ fA#/¨í;æ~doa™]7›8:›ÙÉ°Ê`”ÂBLìívP¾|l¬kåóñx ¶Ð“ZôãÍ©u4„¯fù}’Ê]¤6ªºÉ²¡°,™&M+ˆwònÁµÛ#/à ƒˆ8,·äF Á‚÷r7Q¸J-âœÎ-“vmk­tQ6v5#5',ˆÇjŽÚÔÃv+zâ΃®©à+GÉcvs¦ÁÒ´ÝXÎÐqšW/€š!³X:XÆ1–¨qïìºÍfÙÂn¹ª\†¥HÕÐkƒ… µ‘Æ»\ëÙœL‹O¹®psnÝÔç\“..L“Òª™Zµ–ç%'frf“€ODHåaô;ôì÷Ž#/bûõL^…vîóØ\“#/ç<ÓLEç¥Æ#ÀŠ5x^éö'>7®±å->6ÚW¤òßoÌùëµôSƒ-¹ò~ÂÄoƒFqRæ2>De^ÌF/K©± ·}`²ÿÔsD!ô!à˜ÎÉŠÄç£ÿÉ&û|¾=mêw%²êOçÀõ¹£~k¿ †§µæesQ»?"ë0òJ»ˆØ+Uny\(·˜›qUF̳ÁSl¨·ï©ÆËês¶Œ]$„¥:dsu§‡å%ýš÷̧_#5sûL†3Ï‹{7Ó›fïÇ|2SDï錙49õÐèõi[ã>•&™0™2@×ÄrC’™wì®ï·ñÞfŸË™ŠÖYmsD¨ìz;A‡ËÃÍõ:vYÁ—Ášˆ˜1bð°]2ÔøÈCæDv!ÌRoñèqb|¥)iÅpg“¾«ŒÓ'šZlÿ¯GL·Û#/{Oíq„g=ùo¥‹X[èÃ¥¬@c«‡‹„CY·2Kdu£é}ÞˆêýÕk·;9Œ5[þ½§\A|+/éwÇè£b $Ú-2 exìÁ2f*Ÿ)ŽÑ—-üqÈØ2ô’½²\3°bB„b`•E£ú¦àoêf/\dÄ#/$]‘ ÉPq©A;HÁˆ¸;€Å3i»ø˜ô3žÏµ®³¾@˜)à‰DËùÛœsª¡àLï”þ¦íTãÑ¢¯´Ò©H©‘¤Jœ“ð&á=Så^;Üy¹…3«€’ƒÔž…K¿‘Ó#/ù²ôa¼#¶ßJ(¿¤ð©'ŽôZen· Zoí¢£Ü²[¹ƒ^o(5úÅd÷o]§h=Oh’G·&{¥ü#5dýZ…ðúgHÑzëºìCZ$V¢ð¼fS%¦Ã{i› n˧ª(“ ½‚0GË«ãšßÀ™)'¿|YÀôxÇhv¤™‚!Ƽ1ç׌ìÏsFÍ[HÜÑý½œuh劥ûÅÄxŽZ_)éúD©iœ¦jL<¹ ÖyÌc†Ì¯E¦²OóON4Z”ãæ&NFÛèÀ»C¹ÀeÑË5Üß$?ääS¯?ÜD3ÊŽ¦ÿN6ø¯³ v‡«.å:¼èÆ!€Hßã<ˆ]27|jƒ$Ó‘î¨0ÜÎTé$=Ì“,aÇgG>ãôDÞ‰á@'û.'Øøñ£_%æš·‡ ýUgn=-šåMŠroš^bZk£œÓI«&˜t:pé²2¬-{n»}nû10ÙÕcb(€–æº_FÕ±í£+ÅV›-÷´[}ʲ³PíŠÌ©¥ λ‰¡ÜëÂG‘Üv¨¨3^Í1'bøŸ˜ö/M˜ùöÑ„níevè›;ôJª®åÖ)l¹Ê—qµ‹w–‘¸Ìv]έ–j–f»ãÄ;ÿåQ_'.=”Ó‹÷¹”+Ãçå³ßá~ÃÝ‘œj°Òaß‹ˆg—Œ÷ÊXÆßXl´#5¬ya(\CÒv»±Å¿w¶í3Þqf2N"^JHç—æÊØ!þûÖ‡ø¬¦ìîË‚ÞSØà‰¹'*…Î {æç\•¥Ùq#/3”Ó†_gÀ’P—]ê<¸˜þ_Ê篵äúÞø¯Yï§:pùÁ"&¯-P&Ð5*¦÷¨Z¦–¼øL‰Ê™¶á™€ÚET4 Ë©:G¶ºXØ_sBÆ;2וZ~gÑqwF¸GFãÎ"[1”jjáuIý&™çà®V÷Ú›zC¿‡lg* ®¤]ƒ Û]jP‘Pí-Ç~Â#/Sa£â›[ëf<òÒ‹àrª9–b’ÐÐvÍzg¦­°¯\ë|õéQ’ h!ý^MÜmûcÎËÛ¸‹.Hn%ÓV3û—¬O¤ñNc3ßi{=Ûæ¿ÉÕ¬{ÙÛ|Á6ÓR„ÐâZôoÍcž.±ìÎäi.Ù(Ûa–U%ÎE;Å·¾aÐQŸ&Ò-FL4aØW*µ$MÚVÀƒ ¦!ÉæIˆ9Gתªúã§bDÝdÀ:Þ¤¥-WjjWÈè^6ôìUðäéÝ;§·KWñ×UvQ¬·.¡„*àóJ#,Ü‘$†s\’8¨±Ê'ø {ǧéÌ¿=sœ.ƒø/奊8<³W”¾=¦Z8l`ï;1)qŸZ·zΨœ{¹ÕQƒÂ‘ÌN'â{#,ï“ß®FâÄ›nØÑhùÇ;mñ1Mé²÷#œËŽ™q(¸VU qCáêÂ%I<ŽÎÍ™4s¶äH“°‡¿œË51€–$1¾È'lLq½-wqVaé¢4í&n½2/½¸œù§Go\ïµ\²t“÷—%øó¶ ìÖÉù*£ß2Š‡ðÜ÷ÎL$mð,¨‚<#5ëÆS2Ê[Áïs}ÌË¡¾Ïûï¬ Añ×R&9ðrD·,Ö(ƒKÉ賨Ê!L½FªFv³¦Â²P!f¾òynÌi&•îëaÁF,Î=x)“Re¦Þ¹=5"^#?#eóO•Ç-½eÀQ€~²,Äx-¸Lª ôÈlgW‡ÕHþÃ×—ÎÌ£}Š°˜ÜˆI n±hš{a¢ÐŒ¹ØšTéyV驵ú0ÞåèúÂÃýaãþvD^fÝßü~îMQN„ÉAÝWG~ïÕóÎÝŽÍQæ3]Ÿ)û#/»lÒîô\ñ|Þÿ•ùöH—ç.Øõ×f|`éøkÌhd7ˆ}g­gXVÖX%AE¯ÊŽÎV≟ £}ï õ/A ±ˆFõsÅÕY~’‰aG6âq¬¶©ªð;ŽÝJ*8…ê¦9íûüBºÊ—7o¿zí<œ}*ÏÉ´Q¦m¢ŽqI«ò8í8ZTD„¿ËúÁ¶[CNÒVF·¥üÅܳk%E^VÏ4Ä[w \3:“ñ¦jüRk)rP௼m9©¢Ûáe7ßÆ«ÌKpWW>ê]4÷‚ÂvÝ2YósÆuJ*rºO$¯œpí´Àž®zµÞÿ¯ñÝðßoÂý¸³°±ÛƼv'®’ŒfÊ”œ¾#ñ·H¾™ýUèi_Âëì}ØÅH¹÷D²ÌøÆšêãc1óI=ÝR¿™ùƒYSeY8=ùóXlY$®­]œ|•t”xJÍeÄ´N ÌŽ<Äckº\y!ý³ú<’2×–°ÓTNzw“^ÙPRiˆK»?…¡79ƒÞÏó{kõYX~›Æêãºmª³á'ámYªÂ™ðŒo€ˆ‘ "í¿ì®…e5,¶·½[—ÊP±µyo,­ž/ m±ë4ßH"$!LÚ&tŠWsW•èf5ð5fH‰l*;Ú®LOt3dcu r®‚#5a ô‰I<%Ç(G¦Uöø¶êªÚê.x—‰ô®Ô’—Òqðƒûf=b¹oG*0'ÍŒÄe{ÃË,bDŠDîÝÚ) ¼òB=‹¾Qe…£ÃG9l5až¼üÕ«¼s*+ó§¤ÊËçÎ̉{æàöþJâîÁìEiˆ‰díÊ£²Ço c[¥¾ —÷>ˆ6h_TvtÞ¿/>JÚ1†û"•Už5(÷ónšÜ2â*KCz×_[¡bú–QA]#èºfqiׇžUyNOS©çžq• ˆ7¹¡u×ø'Ò#5Ñy$ü rdòç53„å®äûÁÞúv{’ÜÉ-q¾1©4L“tpºo¢ß6YÍÏu¿"˜Ë2óWçØΪ9½VBâ§cÆ[Ù#5U;elóÌaWê[Sk\òVôËd.¯‡§§ÏaÌn5Ä“ß$‹Åó5j‡wǺ¬&6ßKxª®kk7q×î…ƒÓ¶d"õäö¬`|¯H²E°§ˆ©3êäÎ÷=k}ZǾéàŒ3÷NµŒóóßïX^XŽžÑ\Ü$Ξ‡Hi%ÙF裣ü|«<ãD U1Ÿœ{uÎ?o!¸Õü7t¯+Ô¿hÜôñkÓq3Wùbbüó-Æêxš…D:hvUƒÄ:s¿ãÄ÷?jZQ¸ŸG=y{ðîºâºã8­òúÏo~$èF øó'·7à 4³Ç ßWÇžkÏni’´9ùêÿ5Á£#5ªÆC¯5ò9çm±¡h3?¥lMAòÄصÜ`[U5¾<Ãœ¹[Unü±>Ü3bÑg\#uNI{®ýü秢Ïw>ÅñÛÓëY7ÎàNƒ‹•ënåçu6Lþ55Ê…vYª nª¨GF±®9Ú©¢Õ†’)¡¢.žÍ<9秊ãZ”YîôyBÇÙã™yj¬µÅrOíÎpe{#ç³êùé°ž•b\ãàA<`STO­ùžÙJ÷YŒL.g´šƒBV•Ae®ÜU‰®¸bU2²Õno’Š¯]`ªD{ÜTõ‹©wjuûD…4ð<梺âcŸ.ç”´}O>k¾úJb~÷n9ðFI럿›ŸOÎ#YÇB*4/9ž2ÿWö^“¬my$œýL{7½D°Œ.É¢98‘}ÑÇ—Æú#à¯:HóÑû®™Jk‡a›”#/û¥ÀòÍó‚¡/wéñã»]3¨mWQUpÕͦý÷™d”¢ÚE¨Ó^£sñ¤Ÿš¼ìÇÃzš0EüþŸ-ü+÷aöï­M‘kÕÝ¢›!Jë7YOß+O++^´A— ¬Úõ& SØžQ#/Ô2ÑG¯#5BAÓhêwlÍ*ìN§n-z×!å>+­5S¨§]S5Oš¶À°Õt#5ÚîTt>ڸϺSŽP×…ÇÚêz>7ñŸ4î·©ž"úxí0µÝ¯æ çzºÐXnß9~]ëVƒîÓro.˜iÇG¥\\\¨$y«…ȼÒAðwÉ2Š‡ TÜ‹´ N“çW4f²F¼Ù¿WÛéJÉå–Ëéﺙaf¯ñZF–Å zº±™$?CÀÍYײÖÌeÅùw$ ¾|µ<.‰_£æa«ŸÂ¹ãXGãF¾dªàx!ç+xóÔë#5B:&adΓ RÞª« hR#5DMüíÚhDc7,O=P®Ã1¿e0¥Ó|›e’ɇUlêÞžøü"¸í^UàPÔ›¿z¸nŒŸ¿=c&÷Ë—ÅM%çß”;º>^X­Ðß4}ÕÅsIñÚ¹¦¼§G{Õ"B×Åå¶o.ZµcJÅš&±š·Bd[× }άù!#5¬¯”%›šPËÍVŠo¡çòWA-«\c#,¶½1ˆD^æü¡§½‹ë¢Šny–„z_„NÛn/¹vÕÔtÞåÏw~ørÎkš$Îcy»ãªcüoÍ`]]¾~.÷ᄦ¯Å–2±†£äãÔøO­›ÄÕ×oÄ£52©Ãö¿âøò¦9ß#/ùÁ€KôŸ·ßÇÕ%½æyÜŸZ×Ãàð<â’¾ªeˆšƒB;s†ò‰n¼i[%§uÕ‘Ððœu¯DzÙÔÔ D]S1áËà ë +FËa  àìÖ#Ç1ú騃4uá2#/óÍôÍw¸@kS.‹s²Ïžwµ¥W‘Ct­p/Yk²Í—xGb;¬;«Ž.;EÇ´wΡ¦;a”'/[Ê© µÝÜ·Bvð«Ç‘(cÛ|7㟨]õæ¦bÖ‰C§d¦™YTc<7WÓ‹éÙUw=Zë0¼ÐǶþþknDqqZ7ÆPlÅR¨jsÕÃTõÕ¿Iï,ù³e šäÆÄ5ª1f÷nM<šÌ¢YdÍèIŒÂŠ³u˜žµ[\­gW…nïƒóV$QÍî>Õ¥÷ž¼TÕÉbåL/éˆb0›é׈֟ŽO³á÷]Mzà™î©²¼nKÒ¿Ôý»ôéÓªéËäܼ äy†—ÃÓW‡ˆAüFŸ.#5{ç®/~ä »ÈúÉmqoG:7—Rì<áá:ߣ2µcÚAuÒ^ºNš°!§CÚŠ\Œ³Ä€ C EÂ|HY9(îKÊ¿%ç#/'ýF/;Ìúj>`Ë_d¥º¨G’2/®^•Ûó‚úÄÈáÞ3—ò›=‘úðóÛÍŽÚ®üëÉtåìùl5J»ÎúúöÉãP?ßïHK×Øá×3¥œO2³ÝY<…òáT LâÊcÙø¡þï1. ËáѤü#/¿kUò„ž—š’ÞAøÄ ÑÈ’ÀÕG½ÉÖšèdÌ·éÅš–»âá3 ø£j±ˆ-1†7ÄŠÑh†K•BÚÕåqy§®ÆOG|`xO Qb(D£ª´\ÿd,¦ò XˆWõÔliï½2뉷íOØ•írqIÍzÎWÖ»,©õãD´Žö‡V·Å¶ûzþ³¦¦ÊÄoƒ]¹9ZbÔNŽoqÚäÂQç·l‘¨¹Ñ‘;¦Ó}óëUC‡Ôܧä -:úÕcó‰TsV씣§C¢Ñøm…dî«„œGlç*:¸IÊyH~Ž|,ðŠé†=Ð?‡n,OŠˆGv‚È–• vHø=Þ’1¾x3!>*Ý»L¡¾¡«µÞl™72éR šÁo¦(§LbåÖÿ5~CµâNá·w©{Eöº.“ƒH^:ì;Š™Žæ’tˆB—zéš³Þäç<&ÉTcKÚ#/vÙGÜPf¯e¿®f|ßÄzm$Ð爄rÿ{Žpr>ËISÀyYCdÅ5)œcÑ‹Æ<ÇxdÖ›Œæíû‘qˆ[¸)’RÔ'¢çË1È?¬·2¨é¬r”T·göl8ÈǤm›É0Ï–<ùËìf&&qÐà˜Ì¯…6e„œ34ëÑ7m+Ó‡ËrRÁ ï³}Pë.dž?g@ºÍ^,嫶cŒŠ:M:ÿ¦ëîÛÕ#,pöÿin-camvÙÒ™¦›ËŽ!hèÅJ¼3m׆Š„¿oŽñ~³›oA1 [Fy]}Œ¹gÒ1ÙS®Šïô;¤ÜI“vÑÂQßæƆ–ú#/»Ôü~¥î5Ù„°ƒÀ»TDJv®Þ_,pcÛê~Nö©ŸÚŽt×ô"ww__§n‚4N-uF:µWø½Úâñ½|~gû†÷bkKÀ#³¹ÐC»–¢— ât£ùÿJàú”äpðx})–) A.ç¢È„t3ïQ¨ÔðP„ó©uÔô,óÂ~;[Mc5)hº,ý§ñoš«nŸÌI|\!ë#h¹,ý§Ç¨V47£Á‹èõíôFãÎ<ý›Q¾9êNs_»)Áëìlîs+[-Ö¼¼3×li2ÂÚ6ý¦ÌJ:nW)C©øý>{­îñ´°ûå®R\¬Ù­3Dɾd7¥µ¿F?H¼\Zœ Hï\ uï?5–Ud!z!Ò˜µI§ëñhµN±#/$Û˜„†tÈöaùáqä³l1¶VÂèd¿¨í‘>¯ûÅCŠ0J¤‘Dm"¯§ò«‰˜+&Ö-X(¥Ìöf†#% !D è1È&çâæH+†›ÂP¦iÑQc7¡`«; sÅJm¥bÑ ØÒUòÖ­U"ª¥ƒÆù@1,>*«q“—pÝÛ¹‹'ª§jWµZ´R»4?ÆXlàFÒH‡Nì/ÈFT†¼ü‘…­é y›œlWƒ#/ïù2ÍÎ_Db´0©Ïí=ÚßKE*ªì<¾éýYT‘VqHTA|ÒÛÿeeÛF\P…äOô³7(Y~^êš½òøÃFº|Ý×[Mh­(÷¸Púö7fî„¿Çôzf{!P¦ÑLí1Ê”9C„5ð9ø›CS¾ÏUÞ|‚¿.fŽwûÎ1ü×Á¿'ÚÝÄgs¬ÏÁ+M-¹=Zqµ®îéjm}êŽ~ÊDŠkÐÃÌR$þI¼ ÓJ¯P|Ñ÷÷™úBm&2Q´û@°”ûÎ’ü¤;¬dØæR'ð~÷òUtˆb›ìDÂI«s’vCÙ¥JEP ÜhQû„c6AäQOê«žó‰6з='ïdXùÎYø}öíöýéo•n~ª3}é¡éS*ïBÒéìÒÖ˜r¿{o³Æì=ž›tÎúͶÅÁa#/J*#4«àWÁ¤¶0ˆS×F—q˜ß‡J6HGÚmÖ…ÏðÇ•Îè=#ÝÅ€V†Æ{‡y¢`‚wð©_“(Ìtñ³‚“b¸ò¬G¯•rÓX|Ulão,þï;²g„ðãxa»D,°ç#5¯¿JÏ>GòwG#îÜ$Ѓ-#,xÍ1w@P¾[wöp øIðúüÿé¬M=SÍRMÝ¡Aô¦à¼~q×Å1¦8D7‰àCœõÿVKÊmðí¡Õ¼N̓íªaì*R¡hÈlW¦f®ñ“QF¥á=Ú¦9Ë.wì:†3t)I†gRó ¢F¨ÝpÀцVÞL®Mvúa5#ª ?3ëιîTÖ‚q‘‚±BR‰½Ì7tñ©)–˜ÒâàmÀG(eA0€ï ¡Ãyßg üåµDŽß”_’ÕY*k~²+Q_Š©ê®*KNýæïN÷JË=L™õ û4¾q×RhíÝK«nf=`{ºàNV5ÊätÏr~]Oø•#@ªtFö«CãP È4 &“"Ó¢{t×H†wüìê¤ÚâòÏaÙPøÞ7vÊ[JŽª/y]‡T˜M¢8áÍL„ Ÿ-1¹×>ƒ“çêžêh°fÑk­bR‚MdR‹sðÓš§Ãmex:×#/µ¦^ž‘,…ðíòó„‘¢Aè{îÆ%ëdõ‚„ÍyóЪ] WžþÒYñ0kNRÉâ¯F9Wdo‡aKÑ|X"´ ‚2CÉ”¬PQìM ~‚«ã™´×a#5bÃï‰I#5Wc§ÁŽj9Åe¼¥÷[n cVÀù‚ßËñÔtÎSr‘72A¹‚Þ‰Ÿ²!t~¡®» ÄT%I³iL©±¾Y-Ù³t£tiq\;’Ño®âçN¹ÇNØ/+#/äÊzñ¥ÕTR8 )#/#/ˆ_#/—#/z—óÞÐ1/g§g–sºÐÔƒž(£ lâ%£·¾ÚsÄÚðuš…pIë—Y GA6Êx=ÌWà#«" Ô;MNü]ìàß‘¬;Ì|K4È!²/Ÿ@ä”CËC´µWW|3bÑ–Šóë­ˆ71žÍ|1€ýË6©–¡¦c.«æÌ<5oŽ OÀCI»fÎÙ÷Ï;¾#)Åa,~~X›Œ3q¨ÝvÀXÀgj3+ÅÕœŠñÑ;Îs’ˆ1âsÆO¥u¶ãÃÁ'Gø·NBæåˆË¬ŽG?£½ÂšßQ˜Á,]ôÀÄXL§I„þØ,¢uH§|i¸8††J(M¥ƒ˜–æ}«ž²ÄwÎÎûAº»˜/Wl#/s•3•GJ+Mã Ù %L¡œ\hå©LU2åkïÍlgß&ji±ÃXòLšPõÏiè÷ñVq!ÖÇüìo8s +#/ZלLVN‹<ðÇEÞH­¦Y(A¦\.{jÙŽWšNvµÝinæJÓŒÈ)«‰º6øÝtÔ5vjvãBg¢$ÐÔ #/#/—`’° 3ßvUo¯#5f›ÞväTšÙ9aï féÃ,}k¶¬ÚÖ©e&†r­ƒnx…¬R0!¡¹àÓØhŒ,í¬f]³>†|f´Ã±òÜ}ÜæÝ/7M¾ãAª•ò)(c5iE¤‹Ic#5m9øëòò9ʉ”xm4Ül4j†A8ÐÀ–MùûAÂ#5hÓ·«Ò·p³à&ºVî Õ&’¸E&‡©u¨<"Jl =>M|ØúÜ4"Rüås¾z§ï´þÈH?WúXRÏ.ï„O.Zè MP0ÿ¼…¿ÝJaÜ"ŠÍ6»._‘»o/<«1•*I ŸßüßÕãaʪTz¡ú”3þ¥6ï;M©ÅX}c! ¿ D&†aùº¸¿ók›V~tÓ¬ ¾0ø|eƒ„\gn$„¡›#5˜q’È:3þcÃ|½I&ŽD?fró¬Öºd9 BMtÃÜ¿u«-ÔÇ}8A^ZO÷¦£¿Ãã ð`x¡C†QõˆV-@‘Fè‹€);‘ Hb…˜{˜¢cÙˆ_c…9E’Ý#,ƒZÙI¥€Ø @ÓEL0î*"¯àï½Å.%%°R ÈçzG1”×éiEJ”Iá¨D*ΖÍ­‚í3<6f"È,²`‘¡Rè`Á…ÈSuï‚&g·X@’'ô q(&æ52ëI|]îëúóìóc‹/c—3³|šÿ!³Ù¹ì<²†"³ãöüfDÿ—Ë]q?ãÝlú6¿½%ýÏÊ[ûá…ÒÈ’Ä#/^!¸j 9q‰öŸ—ó®LŒý±=ŸMüÕðó¨(¸òéa‰épRjMŽTZ˜XxŒÌÁª™e1âcHIŠ~(´É{^£œÄz-#5ë?èÕGJ‹(9¸ÖÞˆ¶ˆ?£–r¨gCiŒõ¶>.sÎ`Œ¥é?äQ¦;#Ýçλ´ŒÌcr®·w’ŒyÖÝÉo Þiî«“VÈ,Ñ;mGJïlò) ]Ú,x3˜»AûÇ##/%iˆß!’aÇÀñ«Hl…uÎ#58 sV¢;Ê8–P±‘7(•¼hšèWÆPa)‹—/zU#/Ù;Æhê¨Õe#5OöÝïÊå3Å¡ ùü5!ä#¡ÄFŽíoÕ¿eCö[Ü:12µº ýp:Dì>F͇ðš(wQ–ëgaÌü(0Å¡{zƒ¼Õ+«ÂBCõð0óÎÇQ‰Eø®jøu×n#/,YÑ $dŒ‰^æõO39:Ñi¦¨©H¬PYET,í·¦³ q˜<ç3¹5wæm³GµÕºÖ&â’ð#/3p²»V`îƒ “IŒ¨$ˆ#5ñ*€¤Ý*”P!*¡Y_ŒA®D´Ýéó×õŽ}´#/B<»XÔ”î Â"B(T{#/Õ‘Œyõ†#/Pyög® 0ìÁ[’F pÎ8Ûmymp΢»H]!º ¶ƒÃ?9r':”"‚ÛMP:1H¸7 †Ó0´Nl`;(ÊΆ´qÌ£PKD}|ŽßUµÆ&>ul*ºŒ4¤TÛ¬à¡%Ýq­Äk^ø80 <'¬OH<,u³#ÛÊ)µ¹³·<ÎÄO}FÆpW|´yÓëÞdLÈó¼¬dd¨ªNÝÎéD8¦3¥ë#‘¶!ΉÎ4E„€gÒE8T„#5¢«­%WWMµí‘çö7UŒB¤ „D N<èdPF-©KfP‰"GÏ꯷/+Hå5I—té¡D–•¡/TÑÇ·€ˆmGšNG•t×¼ÈuJn1-Ȫ”%•É•37yzI ,jzüS&|YóÚNj…ÕOªê!äÑåR—(ÏŒ«òó¨s1ß>+#ÔÁ€‰Hˆ Õ\^âÞ¦„*pEëÎN>>ôŠ#L(ô1Œ#(.UÔ¸O{ɹÓ5D¢VÂ% ¡R] (׬Øó^Y¦O sУS7Å›`–C‘wÈ¢*ᩈØwÅ„NÖq°V4Ï=¬9ÚP’ ôa=J˜JúèC#,õÑAˆH=ùaఠȼHÐ}›=QÕ‚ )¨ÉÁ†tâæEÚékag=LÑ+¸ ÀMä¾ÂÞÃ)€Dˆ©Nï$[—”$!!&A… ¶àûº#xK"¸æÍú,M°¨Ïƒ3rçÑr4&z8éëJ VÉ›XXž­ºã#[•€`¢Z;Õ#5„dñÖótSO+k¸s!u~H£óíWZuË' e*:*ôÂ#5·ùÅóCr 2'o h(:¹ôÎϲ`L™²ÀwÝ@ ‚‡,7–÷ákW*ã/Ü-SÛÓKUB¼ÀZ#5±SB†Ò6é¾ÿ$çW(ŠÁ¹M‚Î%éCËÌùð8éÄÎ/ƒ:ì¢f‹ºêgÕæR‘þ<Ú#/1³Thõzõ½Ž…Ê®©ÑÉelUdà‹ÝÝßœB’“D¢H$ mTK=hŠA0i*zšëMË[ufr­7 63PA™ã“Ý9² N®ú-ŽX󹌊t;‡T±ñöÙPË1ømÝó³2RH(£XxM‚üŠ(”–!2ÉJöœ9ƒ7>®SXøžÎÛäc$õÆÅT#èær•8"p«ºÜyK}³ÊÛhŠG4!…Ä'–˜Ë)Õ)d °ÏÖùtó-vEØ…ª…[â÷ÙrCÙÛq[¤aÒ¸2.¦Ë8¨#/…(Ê6 mžJöU÷ùKf»QÂLï¸:kÁ’ȳö‹>‡~N•\&µÍ¿2BV~c‘˜ÛË7¯­¥ùãnü¦#/½­¸›üæÉŒy¢“ÄCØœ›4 øF¬ŠDA†'¥iT¦„Ù6¿èº8|#52Å"šê),(5#)Pö¢p ô9QòHmšt¯‡Çú,ë‘\tváv–‰ÛG.K} vCŽÞEâ«ÜÎŽ1£d4>?P=ˆ¾¶•M!5H«©Sà÷»Ñ|zë¹ÃÆÊ~x!Ë£»4­7ãíŸF'é’qŸ0ƒêìÎt,#Ñ÷¶ØðÖ[†A1,Xwl¥áý#5›ƒ{Ø‹KK9l£‡wÜ·#,ÝëÁ™¹!×I'D:u”ó!zÐÖs,ëÃ×ykåälö;ºÃ@#5L«qž½ÅZE µÅÙÍø̬#/¡uò‡;²)ÄCnûôõuÀófµ´5W´ˆó~£áÆç"&à±Î9Õ)Ò#ØA„-3aüFðÃ@J2ˆ÷}šyÃÁÎB;Zv`äYÔƒ¨­‘m„”ÒÅ£Öº©,É%)š1D5$:±0ðlT¥ªL—¨Øš57ˆq•‚¨=š%$7š#,zˆÞÛ˜“õÄ4—õzm‡SêS‹ß†t;ûùËJ,Á¯ìâuBuR!¿"¶Tï‘Iȃߣ5~#y5‡–$!¹t$à‡cò¯C™òlzEu]Åu&fr²Ëò^»j`…KJ ÐE#,Èôò–‘Ñ6z~ç ­œ›¾M‰:êƒÛ A2›ÉAÇÏNí»vlÃ1vkB>ÖÜ€–£–œ¾êسµÍp?tL“7‰1Æ÷2>9¢X’˜Öã+s¯:Å€°x~ÏϘdcDú>þXüœvÌ~ÿB¨e’¨o{l¾P3Š\yÑEºzC~à”äUdM"aùi¸K£š—ý¬ÌÁÓ(ò£ËËSû&R–iâf챇ùmåëÇÙÐÌâOt ½<#5VûZ:ï•»»\œXJ”ùžääÄÚ%o|©¾~À&b º“A+¸«: @Ï#50‹Y™ƒæ3­»ztÿa/da1A_âýã¤?Ô‘!!Êa/à ¨ù¾ÞtÙ]a¡¶&»e‘‚x@=æI®ûXt›õ ÂÌQBòüׂ“áeuÒ¯ÇÊ¥³éñÐ>Úôbý³Óm¹EoõÖOê•ÝÓwYmuwþ®'.pQ̆!3só÷œ»sñð»„#u1¥ygW[Ç#ùØsaI þ$¤¤(HŒ‘B¤?£%6¥ L¥þOyaýŸíÂ1÷úZ¨DoH˜j/½Øúañ|bB/ç‚P2w3ä£ur¡ ¡Ã¦;ÁqÓHq³äKD¥–•[Ž8V¾Þ±«˜öYŸ¤›~•ØÛGÔî#5šÖ2y_–Šçö~eÙÒõóÿÔÒïÞuø™†‹]fW—x€ Œ/®éîý÷ôá}•?ƒ30_¾}R«6-bj¬y‹;#/’`o§~VíÖ‡(uD×Y_s Îj&8Úc_¿yŽÌèfø¢e¡®G4·‡ÊŠ$Ôzj¯Îø1rVaD£ìkZWGó¾-·çg2mjˆ•Š¸gÕë}agæ+ª%ž®Þ³ê6açãwï1­rN–›Ns˜5311Pú`ŽKt¤yº¸æ!èóËÇwoëÅ‘`NÌ1/ú(KôÄkøÞ*²>²Š$>@ªˆ«ù~1[Þ+óÿ9RqXÌ°Ìr…§#,&éùúµs¹¥Cõ¢R"é&H<ìLjñã·¯œ‘º{ú(Ø».qÑAãºÉÂû¿Ñöc?‰.îöhD d(ù|mû7óê#/@OÖÈmLoO`•^.Þ²]ép0ÕÒûttð†WGš)xt áy(kÈóaöÙwu+°uÀ-‘³jß®Ï(ñ¿‡šÞÑ:l ^ÔuyãÉ¢Ë`Y-ŸAßêÜm z5ÄìØy½òT‹à禇˫çÑ¥"ß— ÌÁ'á9´äiÏ#5¡–´ÖÎÎÃ|©›fÇ"ÎÞ¸] ¶1z¬ë1[ĺ•|ý®®Z µ¤Ó’"kmõY‡lkø=xû|÷¾DYe-bBfGC\¦"ËÉ.}yfnûýÍÞ½ÿ5“Ïœûvúc1#,…† £E˜b"®P»–æ>!#ÚÞ³Ïí9NgÅ®¦ÓLOpÞ¶f`ý ¢'ÞÆã‹eå3šÒæÙh õæ„€’„)9⬣u4œ9À¯ãßsª"➺_ÂMÿÙåöÞ7Öÿ‡5ö¸ÒùLÃ.ì©"¸H¤{áÕup”æU“g†:¶z8]›½™˜}‡ßš2Ûª!Œ·@¼Ç3‰<“Nf?¿œi•A¨àÅ^½# ¼õ©ÉÛ<ï^Å¥ÎÞhmöÞ-4î¼3#,¬ßÕ½#/ÒüNªÞ,ÿW?]®É߈!Vâ šæ ‹¼Ãáà=PÌI êEš­/l×À’0iQýñ¿é–õû³”´wÕ""ª‡JæþöâB™PKE¿yŸžùçµæßþ¹®>Ó'#5|#/y²‹ð—;ÇÓb·sŸ*Ž/›öΠC÷xëƒñŒ’ýo‡×.^NÊ”:2t¸7·ä¸õ²OĆ!8KÁÛ’¥r„¥i‰(<öA³aNbìñ®SòþëÊw5Ú/ã¬Ow•Ë<‘0üÞ„z*Û/1IÊNyàÛõ¥w4Oª¡Ë^]¼/ ©/„»úÚðLz Ð M–óPÐòF×ù$sžHDŽO\°OQv¾/Úáªuñ\̉zà}Ûð‡˜ƒåÔ“¯Í¶N§Ž'¬âÇzžñ&]›ÇG:ñÄq£®ë~|Á83M0Ŷ-^\{uïŽñ×z+îs>ÛˆMgÙUùb6vLtOt*dƒdtºŠóõæèj·C‰~ÈyRãÈX¯~Lw$êéjãΫJÏœf.(ó|v5|cw1†”YùÝ%;ó‹;vÖ{ç]ëSª0¥“¨{ý#5™O~ªìù–aÁSúÞFÒº}“#5 SSa:›; bî4Í‘ÓM0–vñ®•8èL±ßðu_z<ÍQCØYª-™_¢eœö“"¡Ï¯# §ÒðÄ*‚Òð6¦yI¼GTWUñöò¬·/dzI#;~÷?N€ÀXó‰gíÖ©‹åðÃ2ô´ª3·kÓÀ…˜¹­1Ý›è›W®Ã¿.’ýQµlUŸõ}à«¢àu#ù6‘oÖé”ùÃZ¤î|üeyš¹áŒ|ÓÃ?u#/äˆyÌž0yÉ e²Á©}?6ÃöKžk›öò6^÷Ò$d›žÓ¬ú¡¬õ}lªŸAd0­•÷)¹eÓš*ŽñbfŽ\=~]H3ÑËÁGY'œ{l;üÅ8,J»Åž¤c.ê`ó—gÃG©½êÁ„çƒ÷¿ö«3õqà[Ci30öÔŠFª^;ÎlËškF½µíáøíwX56ZËY}.ˆsŸœušÿVÌŒsç9§wÃWi&yZ_ycé'-ê0ñÛÏ̽%êí¤uàÏAž«¬t?whlŸl?CUÀÓôÙl™ s¨#Ê·š¬§dÐRé.)NÈøõ}­¦r“öGüi©Ÿo‡6#¥Å)CýW_™ègß. ì,O/óD(-_ZÉA*9ìæZÜŠpÔìñ‚­þQàÌçÛeÁ×$n9µw;­-k1æ#/Ò·ÃùÐåÅÄ1èSñû2}j—Ç07ß?†ïŸmKó¢Iîìì‘lÝKpû‰Ä—æçÓÃÁÝú¹µømÛ¿Jç‚©£Fú%ü²ú3Ÿ)m5S0W–‚k(êN>vZ´9J =–âT*õ;ñRƒþkÀÍ á–¦·R^4ÞpÑðóï#5~§zHßÚžØ$ÇO¾p÷|œ-a{#õâaöýPt΢‘j+Vß3¯ZmY·EÛHÂDÚÛ´Bò…ñ¦dBi]×k%ôKÊ~âfQxô & Û´P“Å1¥8ƒÑGâ ´Å$¿äjêÅ‹ò‘à%ÄÎ{‡“éj£øYB®DÂ^Äi/¦ê8Ä0(O¬DãÔ,|–-‹$ʽ³—­.kstÓ‘Mâœ@Æ/(ì‹ðåñ 4(@vχ$ß㦔葠9#Æ_#5…“ôÌtMô4aþ¡G.ÚqÇò"Iêƒ";¼ÆøZó~”±Ë°#5±¹Ë£]õ5äÛ/èCKK–S¾üdûiÁxjÓ!ÒëqÄ ¦mäAìŽV-Ñ#b0ÿ9¢P“õUphÑñn‘kYB.Åã'Aˆly! ­ýw¬ÚmA/Ò³4ŒÞ¿Yþw6¿1…1>o„7?\/ŠM„‚ˆý±<#5³g‡‘ã"ÿ«îêÍÑ ìMSfé‡ZtžY´>õ”µ"ÙY:uè©×í7R§#Ö9D‰›/;¿+ü:ÈLœ20ÞÊ;ñ¿.ÎRýUß]§ì>öüM•cNnIï»ô#/OÐËâëøë峿ž,MÂ61ú¹§ù“Ë}^õ™¬'[XŒç*« J¼ßæ|wªŠsiùHÞ´½Å V’<°>ì³Oáð›Â+¸7þNE…»‹È„œ*jýI@ùJ„Hà8;׬×sº“uÁÂå¡É 0bî.ÊT÷À¼èôÀºSÖtǪ¦J+3½N°dl%ùðfg kD×Iú!{Hë_wçÛ†™Ï¶>ØéÎÇeâã(nvç"ìÊ<îB.&¥tÔwtô˜ëCYLæs¸™ª­$Ýh¨›±e—de^V©“ÊÿÇÝŸZ«Ûku$$Gpq3 Ý€Hb0PëÚ‹V#,°;«ÃO­=zò&°¨ã¾ZÊe2‰š7ˆ„Ý&q!þ±ãY}.+ÐWæ/b\îñ œn&݈vWdH% š=2ƒú®¹†!ð‚-Î5·6÷Ál÷ïÆCÜÅOèÉ@&àÕ=Js†¨Ï#,y]a>”VmÚ@ÂÊÕ{­y •OßAׄyáÄõ‚„× \ÖÞvæ,ÖTö²Ùá§N-e{ed:*gsàC;º¸Ü'ÆùJý~lŠHg Í®ð¸E¨‰W7‡ŽúŠžu+l¥­uSf½MÆYÔL`fe‡#/k8î± uŒq°å‡›9,èŸx$YG±©ä‚C¹ßMp­@üpÍkI·_luÌÇPaw=µ„H– w>õÉ©;qx,ÔñÈÂCÊX°L!T2šj‹vúˆeÛ.l:¼Á Úesj“5Æ2"X’~¦·O—¢ÉØ{{aϧy¼}á˜Û£ßÑ·›nÒVKJ3ÏlõʺÍ5N³¾Ò–¾Ú1,iª¬Ú{lÓ…åÚ³ u¯c³Ni0äÅtl_µ6ÔΚŽà#{³“AÁg©í¿<Šˆ{]ÉÓ^ÈsüS™)ZãÂÃij›ÞŒÄ“ú¸@è]ݤۻ¡}Ù¿<0UÆ&„Òþ¾¿7¼õßµ7È„u¯0$þÿÂ/ ˆÒ*‚g¿¶s§¦…áš¾}+˜óŒ 9ð7Ÿ‹®uüE4×J ï­±eóûú¬OÖ"&ܵ*£¤NžÓa•›ÄšcUÈ:bðÌÖxæÞxí*G¢¬¨sf¾&#/f2ÆJ&fŒ­·EVú‘ªfE*ä8R¦|¹çZV2©r¿«„Ý8Mý®Í«¢K¦p„þ•`©} 7É'˵U³QßùyØÞ9åͦQ#/(8z»X°Ìi¯KçÎÐÒe(U”W•0„~³ãøyÿ^¢ü(:zKk¬Ç’ ðŒdÀðV¨jÇŠ™û¾Õ~ënõÞNÍàã•ÊE^ÔúPù4ÆŽ„#5žBGeS‰Îá ¸éÆäiØ)ÏlO>hfëjÜj„ô¥f )•t~×3ߘŸ é BS/£j–n¬+²oº%ºCK›,¬†™k¿UE.ýЇ©šH”VéÃD/$ÏÛ»ÅD|¤îvá×Ý>}³ 1¯(Ç»àÆqš·¿EÙ°¹e% uÚ2öž§µ•ëÙi˜ÎÅÕ,Ѹ.'g±•b¹9€™YV#5ßk¯6ï#5êø*tòž0å#/2ÐRÀJ²Ÿ~Gó`jM½]å‹beýqKAJ`ñb¼­¼¿i8±!#/wî=„+-ÖØW8#,žp²CûÛˆÒÅ\wñ_Çc]îgÑ¿Ùõä_t…Ýy¼Õ×êßÝñÓC“9YH°fôQ¥þ5Œ´(ÛsŸ­š”›Í6ö8e6Äîè…;iøÑÁDvü7:L²í•ÓŠƒÍ:C¾ßÃŽï}y!!æT}£E#/înE ïQ†×ÔÒ&GÈaç´õ Ý#/=Ì4!´Kkúiÿ•†™7ô§s;cQ(Ò>=9\ÌeVŒé,¬,Y9µÜi@{}6ß_ßôÓ¶ëw0RDXìyð0Îh©ê~ú¯=O¶¥6Ê{k1¨÷|=9ñ©XÊƶØd{<³È½ˆRÔi##5;7¿ÑñP­‹R«”*&vl¸VO^5Ö5Žæq&ïèYè_f_ÑÆá‡óãÆ#5mÉÊÚ•äÒþÝ+ß FoÓœpÙŠvcgïøUôÈÈr°R~¹ÛyÜ"ij!”4f¬ä‹¢’d’K°™mí@(wÊaá›=§„õÇ“³®ã&öéQÑ\÷ú'âñÐ9Ý‚-ïß·®²GlM,]ÑÍä_Âyý?d¾÷CW“6#/úénP<¼å¹ú¯€Š¶W•ï6ì­²)†î9÷.¬9>sl:颅\†`ÒúgvÕ‡º9í>žª®ì¢YŒ0¡kË|`ÞÉ6´ÞéßìÕU¨%bÔ[ya·>ûé,ðÙq+Œ­Ci1b©œêíyØë3?TïñÆ..ˆ>Àè)®ýèÍxqûuÏz®Iûúo‡ßÄ`Ö5qŽYøç"­c0¬¦‡c5¶û´-à]¡àl„jÄ1Ï{bÜ…éÙšcçc‡GN=ýˆwä“Fz^`Å#5ç9HªÔmºj­Tœ ÕõDÈùNÛñÖóÆò#~¾Œù<Žù„&}<§åpÞ:òRÝQŽÏ4¬Œ3?–åœÙ½rÕFøðçómwÊ5èÚ@#<Ô–éPúS&79\Ó*E6HÜc>±n. E–gÛÀ: %“È{û°ä½(Ôa©#/Ó±8kŠ™‡nXÔÅ–ÌÀœS4AT(q»«Ýž2­Ÿ¯^M}PÀºm͵L‡túUø#3émk$íØä‚„¹üÆ¿Ç¡v˜Èº_=¶77˜ ‹¦Äån–âÛü æA ÈÒØFQ’›WÆbr%ºŒ)Øpr17ü çXÛŸÏ~è:«Sì~Ê:æíµük¶QË´88öÌ„¥q®0§kÕþ1Æ3ÄÉ%¿ué0#Pè!ÂÛ(¿##œÛn«jëŸf]š(ñÐh0r½tæ^ÃDYÑU{á‰ÛU »jz e~0Ž’^+c´x’ŽXuFOUY’Ëbpwù û*¬¯wIásÏ Z.7³A&ÐATiÆ$óÔtç‘ny[š«­ˆ_qsóK®·k*ºüœ9§ê†ÃÆ&Û`äe´>U\7ì¨Â&ØûËGI8å…û~_¹´€M’¬Y‡·Áù+•YcQTákC’+Ðg.ËÃUò­óÕ˜Ž.ñº4Ý5¨×œ¬gµÊê™S{w3ï¢ß¶ ­™©¦nªÔ·U@Ó\¸±l#5Zõ,Ô,nûdÆÆÔqr¯KŸŸ[߈jî[›%Ÿ&ºøLPIªä~býºaûŠú-ÍÈç#±¹€×¶,Pæ÷s®€Á0æÑeØ^8¹;=À'•¬=a Ó£MÛÔý9Y‘l˜V= Ê;ù˜®J͸j¸ººVÆ}ûg¶~·Ïfˆ;†ÄÚÆPË>¾wŠ¸Ò맶è™ðìÏù£ZëGÕVOA@%¿ùþ[?GÇñžÞóÛõxQÒÇD>ˆ¿ÒF¿”L+Й‡›ÿ›ÓDð˜ûâúìBµÝq< wõWÁ9äs¶¬ÖVj¢ªÄàÊ<ÎS¹9›-[61øØÓ_íëSïòóY{ŠûKãràr—é÷Û{yc‹v¾<ðSŸÉYâæsyV‡Õžâšr_e’ÌòÏûŸ§Ço›—Óù|–~—ól|Š²ð ÷5†ê¼c¦÷~‚ÖoÖg?ZÇVœ‰²°¶Ò#/ü ÏÇ–Z~¿ Xƒ¼áôËö&ÉÓeÑá@ªvH¡9” Ç ™–[_ì$÷~àt¿»6}ž/©\ ö°~ €ßb#,_`éÆ#/ο°`M™BI?ä/õÓÁ#,!ߢ¾™°€åa#±#/é‚6%Vá pU",#,þÇü¥ ËŽÝ³ü_Ôyk«·fDO+‘h›k öÁØ­™?Î=á6˜À Œyu£ íéÞn4LØv7*pÄÔ2“_vC„JÝn5 B"N¶¨Ö˜IµEœoRO—Å 3¹ Èz1~Ĉj á‚U1–º¢¼÷ò[§`áâÓѱîbv½çï°è|}þ Åú—Ú}®h£™¤=¨;!œ#,ÿdE, Þ.àø“­LÒËHæÆåî}ÖÉ52U¶u¨Yþ'צ* í ÞôÂêéú69¦‰èܼÇäÄAO´Oñ.‡‡øwwà¦ôé“âXñg\ÿMZ%Zß²mǸ°FG$-~AæþLéyOø/²í8Ô;:#/¼Úy >²1ò}~G×6ý¯SØ„ÑA`­'šü'ÕjY£›‚A"a‘KQ=eksý=ZŠ>'Ì2†ë¡ÌÈÙŸò“ Y*v}Ð7Wæ=¸¸;µçÃcUŒ%b.qJžº“XŽ\@"âØj.6IN‡Œ$6$ÇRg˜R±Du€Oä†AŸÑ<Š¼Þ¤?ËG¨bÿALxü*UVªa‰‘|O¢˜ÖR<¸€G°7®Ãknà#/€Çï$êÕ5îFÕïSqÜè‡#P-"†Ðñ²ÁŠ#/” )"b€N²cè{Ø\`pRƒK$aì-“"ÆÐ:\ÄNkÌ×"G:•°»°„,dLXÂT­J#/p/hÂQh:†÷çïH+P#/ Ðûâñ#5Ý™y‚ÝÕ¿õràÌ‘DÜã¡@Þ’¡€x͉¿.tJ‚†QÃBÆa2D‡ýd¹ÿ©ƒÝ ò€€xû‹—˜’#5ÒV}xT‚1òÿ+í‡ß\kƒgDÆ‹FhU<è…ÇCßá{‚JXÿÉq¯Õ¿Ï:‚ ˜(8£û<³êÎ&'[_ñÌõ³}fÖD»8RHç»?¨¸û]Á; ¨F#¸·yó4I“O}r$Õ’Ù9J>¥»äpææm9 Pþ{•T†ðüÏ)LHð§qDBD"S.‰Å¹Ÿ´ÚàáØëSHB3B= 8?ê—#/©Ä²í7ŽÿÝysµRTõ4ˆ„ €Sä4§äõþž‚ÕR„ÉƳ¼¥rl™ßm4ªUQÖ«lÕm ÏŸgzâŽý¸ag?q¸8àáæò8Ø?½÷ñqàGৈzNs‹,Xï×iå uÐÕ9”r4  îw`ä]Ñ,Û͈ÃôC­ú¾û-ë~“âF*^ƒä=ŠCÈ$%¯Rff{¿–š´6nÁkÝKIk}/òeŒʆº(ú&î?”û¤)#,ZÓ`ùT×ÐSÂû®3|s§V¸L[¡WwtÄ$N”Î êÒµ~à¤aA|‘¨Ÿñãäû!ƒ»KÓ4—iž#,,±*!¡5@´DÙ‡Ûgpøï]éá8„Ô‚Xd#åþè‰e¦JÓ¥aü”E"E‹|ƒ„¤4ìÕ:#/ú_¥Qqi,BT<Ú@Ò#,‹¼6?i`>|vîÞ#óaGÑ䘮dC1 Ž¬>¡J ¾ï»þ·46}¡öðð"*’™çÖ¦Ór‹Nñ‰Å³¸ÝP ëÒKÓb]ñÄ; #,GŽöŒD6™ø¥Ÿá±d6Q¿¡bÀûf(h©¾=ôÞé4¶xÄ—9°ˆŽF)R 0ñ‘Ã2‚Á!ÌIY"ÑÄÀ{ŽOwy_#,ÅÈšÄ>#×äଠ²‘Fm­Ïð~n5UB"{iÀâœ{Ty7, ?_ƒØ9¸Xf&f4e°³ØºS‘u0bØ.„ Xr!ù_¼ì7œûGû˜=/#,taû¿«÷÷l” `ÿ6…Ïß#$3<£¬m¡F’XÐß =.Y%„êüz¸Ž«ª¿#5Íùnî„»ìU[Ãu<ôhqkÈrªÍI ÕF³5„+Œ|‘ä|¥Ç·§HÞáI®T«|˜U3z5›–#ù¨‰z™Z›&`™±æ\ÈS©XD"“¦ìx N‡Ä£uEÈ÷iVeCMf°»D!cGùX@8l|߯èü‘¨,¨2"Hª~x¯Ù”ã,"s0þFŸó3Í®¤þ¿·ëõXö>ír6ýí÷W³—ÍU¾¦¿¾tvë€μ‚wCÅ¢$‰G$’I––ÆÉ#Ÿ`~ò xäa>Ÿ¯ô£ùDyý¨q§‡#,Þu(KCî!ÏÀ´%±°pxŠ‹_³G«K•ù—·7?h(ûãw|Ë4™fÈ‚Êñd“B¬Þ‹³XÄÄé•}Aá¸ÉɃ8)ÓID¾8ânòHàîât’HßUå]äúO<é'Wpë))¬éBŒCxÆ6ˆ,M^#yk#OFü#/Sfœ%Î;âSÜ÷‡-Q„Søï× ÷ÖgäÇ#,qô¾œ„ÉOHPÑFã›ä!dã²€½ø~•ö²Ð0¨‘#/ú/Ï\èn©¦æ5š6š6»¶×Ÿºû™ fï@xÖ$ü´ºü™Xƒ^æXö½€)g×H#,QT¹°CÔPô>ÞƒðC××÷?3ªOˆ›š±Z}ƒ@pH¾9¥¹‘#+ñ9„ ~Ç~¯pm>Þ ^óùè€F4äw_øŸ¬Óêlªr  $þËý({]›;Óñ7ˆpaÞ¬{E;#Dc‚;€àøx$Âd´lÊ6¤AÓç]qñwžAÅÜÑ€¶}¨Ïg"´DÊ<#,çá;ø”Ú4ÿŒê| ·pœ-ý9ðžÑPõ‚‚Š$!!|á4ȳ֧öKpx('™‰B&ÏEŽˆx'7ËðÌÜðäAjXúG®tŒ"± :dñ‡ÕÅCâp¯¬#5…ú»¿ã )úüt€_d„cÙù+ò }’e¯¾×Vñ=ÁàŸ(¶í~t3yxœÝähŸ *(kŒ-A[0ôº™6 b’z™$’y€\U=@f{8ÿ-´@µÊqͲ4dˆž¿GëñH¢^}ã3DI­VW½´£Ç»?¡>¾†  òå–Û¦rÜ«k|[çäÿ òÁnzŒã$ÙØF$ö·Añ‰`(2½0„*±u4Q“ŠÊÇf#5BËß…44ʽ‹…~ºTN;:šÔ)1J³ÛíøÈf &a™êQÈ$Šª&$0buq’ãÆñ#&Ën¾O5›˜NǨǠm}i§-î#,ˆ¼ÄöOg{®C1 ÷xX#/Ð_Ϭï<Á*B2† ôv;ŒDùÄj¶©vª­Kµg«³ˆ¦'¥'úÏX€ß0>¬žðö+Û¿„èêASÄ#,î6‡nÆŠrt`9+ÀR‹>SÅþAv%¿V^}MLÂÞ7 ‚iŒ3¯Ò·ôýÉ?¼Â)*Ÿç»¶'úmYCû^cCh:ÖiÆÍH#/3D"G[Ú¾#/B31tÔF®¤(wfC‡·OÍã«jç6¥­r„ˆîy­ƒf-`"÷•Ø®[ #,9RÕ|;ªªÙ,p…\À£þq6{˼Ññ ìó”*{€¡ÄcçxÛ°Ùô}FÓ`§0ô‹"¢)*F˜ >òÉÔý#,dû1EÉŠn‡e)Ô}a2}¹ÈÌ„9”hhX±ƒô\ì¹ÀðõWî»÷lËð1¯CÀWÄlŒhãYy°Ì홤w„NÒA$D"DŒQ ˆD˜Ð]È~™b!ï¢.Ì…ÌÎQgÕ}ÞáˆMwÒÕç uœ5@ŠbIrI2qÆöºDfä̦‚‚BLHzѽ`.~´P+g“P}BâQp=èþ„Á"#5° ÄP~ ôXŒ€ŒŒ2bÙ`’hXPÕèR@D0ƒ!#,báE&I¨‚dzý€¡Áƒšj4jZüÎì`Ro<ò÷¡âfFÆG‡Ž›Êø™&AB<A#ˆ°Ü«JQØÂÂõ_j4OP~1)Ù¼ÑLˆ}9šJ#5„IØ­ ÀˆGõ(þ¿ïøþèG>aöCÂï5AÈ#Uçì+)'µ¨£QÒ¡@ ±’m&S3oŸy«çï[;µskÎÜZÕÙB#bA#eSmw^xê³Ë®[Q‹{{>!œ9üíÓè«$Û:ü`x˜ÌÁ¡£Z]kuýà”ÝpËâÌA>²@%®Ð|Š( BùúÞ#,ÃUØÄ4´Ã°Úýú)’^ ”8‰l†•B‚ÁB) #56 ‚%›1Ä„:hf…È|è⥅¬”ñoòª²»ùÍ㜠=ïéveÌ^à„âE¥ÄyÑ¢A ›7'^äýSí¢–q®»´2œú¬‚m8…0-®Â‡lB¶É£Ÿ4{³ž^Æw[©š˜ÛÈFã#,Úf’³ƒ˜ÃÑm=ÿ zÈwwXÊ•®!^òÔÑ$¸Ù;Ág¶¯"ظn骔¬UQ|7¬+ýÀ?nÞÃéC .Ij^TÙHØÛên˜…}`À‡³cbåôoZýßœþé1†Ñ6}âØ«KL© ä â„‚#,ö$÷ &¸’O·êq0Y½¹‚ J<äÎ$ …Ô2¹”Àd£³#”T¢ƒ@’sì}Ýh¨€"r#ÕGSBPJfXâŽu2rŒrÙ±H&*7¦˜ "?P>'°¼ýžïп#¬¼˜“áÂÊô;OºZpìÙÕ!b÷Äã›$!·½Ï #äUóx÷37^Å7SÉ°®¡øï%by寧 bȱ;Ûõ¡PFKdZ˜*ví¥Š$™že¥ìÃxÉÉzOgÄGê#5MÉÁ ì.JGDÅþ|ÞôÌ¢¿RNÊ»Ë%ÙŠ+.ÀÄ©%#/ `ÄÀi1;½…&¥ø(­ÆrE„2–½Û# þq8D\èk\qÙõxø¦eŒ~¤`9•hT¥ŠÈ‰Ì\#…æy¼0nxho„H‡AL““#,T7»Ô#/‘ ¡l÷í-À#,@Óc¸?R(ØC·ÙöÙ.ŒL-ÈúzÎt fÌǨ u×¾øMœä" ‡ê²¦#5.€DìÕ û½X9ØrÄ:æP•×ˆ{ú“È;JéEX`“&@€YØoñ³›¹Ç¿4¬^m@ª1K ˜Ë I2mN/´ü›á2Eh®0­ÜŽ(¤Ùë^‰ûåI}²,€Ü#/ÑÞçP€‚ $4) zj™&“D);&$M¦ì/é×9À£¡ Ñ£D&èä$ZfÕÌ1úñ2:§6A¬å‰<—÷ˆþ¼£e“ë‡vÕrlwìC5s<%j¼™fgv÷§' ò´Öm¶3Dì=çëî”ðów]Ž£S£Ö{RD]‡#5â¿&Î.Aƒˆ+Ū9Wa¤Ö—^¢„Ì¥úÊ#Ú]§@ø$Ä å<“â—ëÇPIë§øeI$ÃŽÄ ;”­l h7àän\ÿV·· L‘ÓP‹É• è~‚(êgrò7·F0ŽrF* àF¯@l¤r7ÞŠà~xOZ/$ØhW§0øb˜¸Ñ ’¦%ª-‚¬LsÝ×ÀáÍíÌìsFEÞQB=õ´ÔÇ\ŸWÜè…³­<³·L¡¼îOÆRù!¨e/¥„ëõ™,<¢h<¾(ÖR,RåÜ#/™ò»w3vA&Ø?¬Þ¿O~÷¢Bâš¾"võÿRƒ3Ðn`ÌB®¥ÑQýñµ}/ =¶×ùc˜^65iÔKVäÜRMΟÎÞGgc›²h“š‚L!0‰IÈyÓvHðGiÕDçi2LÐ/ñµáTÍQþ^G4ìë ™¼Xtà†}p‰‡fì€ D Û|,8ݵ|²Û»ã†Ü3q׋±½?ˆ$ÏÖL@£ÄFL+¦Z÷‡Š4³FëŸ Ýt^ôpBÄ7£AµÁ#5CèÁ-4Hðp\ÆBÀ@è`©IõGãÞ`UîŽÓ LñûÚ(Çìˆ&\ ˆB$` Ÿ¿¨ï°.ªpmKÑèsîL»ÊÀ²à& Z*…ž‡¨àí{šfÐT7|ÿ­ÇÙ Ù=C¡ÍÆþœp„œbùôq¾XÆtL–?ëÐÄŸ€=ŽÒÞTVrG°.µ€\À'Ç8b\ÜÜàpqqÄp C¼È ¨ä•õû‰ªü{¾W€n88£·èJn»ÕG³Ã`Tv°)$+§ªüW¶ ©<ÂL«!{+ò>¿ô¸¤èU–#äˆÄíWt£ŠÅŠ2-µ#5˜ŒíøK•W iÛLY­À_Ù²’#l #¬­ÝŸÅµqíŠns¯ÞT‘¦–ôD·¿ðë?aÈžÔ­µ[i#/†Ú¡+ÒÐ¥f¶f,‹x ¸÷Õsà&öЂA–xno¾+½+'cùorXýºõ½9ŸoÚ—O²ó¨>óû_‰×õD~Gö!W*z&ýÌ*|õÒOö¸[|vKy¿y«¥ÖZæ¦o.qÓ2Ø6 jË A ,«L¢€~A¡€ÚF hàši²nÝ´ÒKÐbDÉŒJ1V4J¨„¨Ò´Ø#4°(‚±P¢¶„ˆ+Ùm·ÂÞÞu­â6ñIXÅ^à‰F ²*¤4ÿ€›Sþ g×#/ŒÜ„+ÿx¿Ôp‚Kf·Á=8 $Fhà BÈ(f¿€~}Bc‹Y$þõ–«Ô&1tõØ4AeòbÊïÝZ¹ôpÁqy :0¢G o~H wt«GRäÜÊô´*Äts† çk *ÅVLv Ä;/¦Ã7ÈLû›‡yêÐì{ȃHDS.W?=ÿ;~c³÷~/ûVñ@è„;ÁZÁ•ßƒlýFúQk¨˜¹Œgáþx»±Ú«úy/Ÿëý3b·Þl§~V’ÀÊe!’/‰ó¦f=¿ r’j‹Ð-"†œšÝý®ØN¯ äW¥¾ïÚ“×2 t“3¾î%š'3@ø@Dá' E·t@?Þcî.Î÷Ó¿´uñQì±—#/7dr‰Š*!9ÌNcÍØqúý‰F®;O7˜ŠBbqaHÌ€íøâ>>tɧ´ƒK×Ý7–1nóµÛì ¤W”P0€™À-PáBB™Ýõ¿Œ$ÍR$’R#5Á¿å‚"Fd(;ówI›Õä¤2dxDr¡øïdÞg¤qÈ!¼w ­¸3g׶£û[ØÔ)‚¶6åhJYšÃDlDÁt¡É#>jä)PÌ Åáù=nÌ7*ÛœˆA'P÷IÊï…ü†%l$Ž°¤„dàü©« 4¤áhîÕ‹@+!§§v‘‘²ç€k»ˆðsZš‹~‚üSºŒð!¿ŽñMO¦NZ3h>"Á#,R]"Aˆ HZig‰#/yš†!ç-üا“p¥Òûù¼Ÿý=ƒ´3‡×U<’mE™^ô:Œ‘EnBø¼É8<Ÿr‚°ÿOƪçÌüËšS¦¶ï©Âó¥Ñ=;iG\•;\×¾f óDœýLŸ¬õßhcÉË ·Ã_ÐãµwsI‘;-”™˜¶dˆ1êË+aïòYáT³GÒµ@ªY¬'îqÿgöŽ`”êhiôA˜"ÈžNÍñ»0¾D4ùµ4ªý|6¸ä¸Iµ&Єîu ‚¹ûàW-ÑÅDéW2Z9{š¼©%Ý$‘AQ)‘Æ|²±šôrE—yÌ!Vî=!#/iÊ:ƒŠaË¡².㼬†Z(}ø›U}¦¶BÎ~\šlG[I–÷+_OJܵÕÙv,´ÅË<ÈÃ4¥ß"¸ú A0Ž\&CïÉÛüôŽ>é’…—£EÛ#qVyO;õ#,‹Ž&¤U^#,ÛV¿#/ ÁA¿õØ/‹¯°øE·¼òi$©ñжœ•4Šõï•Hù,ù¡ü-„ó³+°Ì[„¾´Ñý VFl/žF%¦D©œ¼Œ @jñT#õ_UðÍS$hd8eb½í¯\%:LÔPþKÔÿw¾º~ß×µ’Ú=ÊoRJƒ¸›¢ñÝÏ]<áøEùÇ©}£Ãv‹#ÜøZé®#/­1RmªÄÆ}.ÚÛ•ˆµ¡¼F¸ñ×~Y#/çË›ï}&G;/kº«7å¼Àȸ칳\Œ‹•è¦*LFHzm€þ¹ðÔ¬¦×ë­*Y·^ŒíBå<žP¦Ë°@Mü²¿ ¡G5AsƒÚc Ñj«RsÍM¦óñ™ö¬&®Ü§„ÝqQ=%½‘=Pæ“ö„zt–J6œ^dxñvÓgŒïwHB^ÀíîQ#/´Ðº;œ;‹KÇEIõsyã!`Ôõõ¡ŠÒr6;öp{ëQ³ÕU9U1#01‰QS4h5)+5$ ÏQá­½ÑÆ9³•„¼>ÐfY0ã·nýˆE¥lßì{ä8¬¤ƒŒðÕlZ:¶•{V›*_ô8T50O‘ø~>_ô¯çù«ù.ÞÑœ¸äxô¼`KtymG"­Êk#/‰&³j-‘Ù³Ò¥÷YÐa]¹ïXR»‹ü*Š­Ô,Â$îÐéï«3Q¯GeR;tªá¸ò]>§óêåm§tNxPI_ñ:w‡ÞMgð9éy›ã9Ëƈ+²¬þ7=iÛü®ü˜øô<õÑŒž1é!»ŠÏ…#5ÇÛÁ1âEÙ㓶N¥Zw¾mA„¤ßar•š¡‹“;<邺ß2 !£ƒòŽ(ƒÜO~gÆ“µ¨ãX™ž;“0â !˜sG;Ì)¯`¿ëÎáõ·äûÛ§¶w÷\Ñò‡#/s%yOnËöpȇmdE‡,0;‘%°ü þc-{‰éÄñ¯U•3ì¥G¡ê«ƒ~£ßs‡†|m΋ŠæÜfûËOÁ5qow\;>Ã1Ê „këÃþª…ãéÒc}_Xó‚ÒLÃ:nWWwgºŽòÓËÙL:V€Ï›Èk©û¹ò ãÉ{Þ©­q:n³={r§¨³7 \;=¸ÝÐT ̈†P1‚ëÀó°¡¼ŠØˆƒ”Q#,("¹³0c¹Õ’Ü^7Rá@ãÌ„û¨J€ œPwAßåSŠkwÓûÕ^¦öElUNÙ ÂBïxF’sd4ó(ä†àV¶*r.¦ÙÕñ¼ægÝ]zB‚eÑ® ¡”ËØY˜.¢¬Oš©qªzyî­ó™à°dÈh›µý'¬Ì¬>´Siá(¦a¬b`îñ&@@ó rQäyW:ªÐ¤ðòÈ5Ü’¶e2W²&.ž¢ôÖÖŠcfJ3,xÎÏ~º?Å À<’4˜#ˆº€ÃYXa¡ET€0Á††±†ƒP‹J›®·£A¯ 1ÒQLç{8Š™#,p}郛!‰§¬¹à^^©~c^ÝÄé¸t'¯ÛE³{(,$’ö±!ÉaËmª©®¢a«Tbßj;[—!¼êçtvK£×.}Ú¿‡[µwôÂêì}½ý˜Æ­íøΓöj×CYËé§Ûÿ]¥Ú4Ýß¼]…€ã×M¡Cì7´‡mÊ;Š¨®ÈÕSxšŠl³ëd¼ FnË`((YM" â]•VÓŒýA&LJà/Þ•u¶î[‰5RÕýÏúŸÐø·ÄÍe,æo•Úo-ŠÙ]cU!%¤ª%„ƒòþÇT÷´¯±N!é!Q«»nÏ"¼î ‰¿½þÀz`ÉçÏm̦Ñ6“~¬IÁ| ú0‰„! +¬(ÏÚïyr.z“y ¶KK™cDw}’QµÄáÜ쨑¶Ò&¬;,„ŽCÂøb¶Ùº¼ò±EŽœ ¯\(°B,B&ðÍvȆšÔIg1G¼ÖŽ¦à&‚6Ô)ôàÀ„ÅQ˜Iã„Û'72…ÊYÄŽ{¯oãÚ믉|]T-4d¥_¤±ï.™ 01˳³¥¥­˜vyh¦ztÛ,¾@z¬”Àl qŽLBØ3vÛ ›zÍtj‚ZÙ»ø¡EYß•°ë¹«/¯5­NzʺáŽ.éÔ£)™ömk{U´i;ÊQiL<4êh±Ç6Ïqcã×WPr·Ç–ÎûÌœ"#ÓmÛû!wh”Ú^ÆŽ¼ì\¹Äa±ð[Y·¡èNZ)©lxÒ4S ^ÁÏôds>!ñà4‘“„ôî úÐÏÌb]n&ÆCÂF2îgÈ47„ë—(ÛÝçïØe×¼4,J'j=f)c òº¨MÇ8Mý|9eÝážÝwCF $‰dªIk6l~¹zôÉ«ŠRï¬{!ñ6òR`Šj‚Ó¼'ŒD˜!™½Ô22Þ$.¦3 HQ^‹5#y…ÀÆq3šÓ©²Ä)k°y ñÃzÅ,½|c¨FÄÀ‡»ùwu  ø;#/|4Ö >€·8HkÒÝ¡ì¯9Ç\x:GÕ”jì+¼Ü—7ÙG"&È÷(p³‰éz½cÔ&¦Ç¡  §q¨¡9#s oØë¹s2,©Úm#/Œha›X}ØÀÔƒà’9oVõqëÊwx„¹4ž„z/sÊâÆ9L6mt^”üJ†–$9^Æì’s¨ bˆ;xb\ðeÛþ»÷¨¡Rw»êXê-¾HÞˆ/‹™˜S¨dƒÄå @3‡Ã§ÉÀiº¶ø¯fï׃>çÞòÐOoªq›Âc-“ ,#/MÖ,û~ˆ÷Q¶Ã‰ 6‡ÔiØN<Ò¦2 ‘1ÃêŒÙ´×½d$è„ nyJ¦ÜD¦Î÷{Z$æ°`’ L¹}îšÑ\]Þ/bê`ôØȉÃÞ(‡¸Ü¤&‡QD^÷"àš@g0Gƒhj÷{0e! \(ÊBˆgüÿ@â= IMÊ’ˆÓÆmu±)¤H‘HvŠ›@×xdÙ>d¬j;ÕÉ£‡èÒ`DˆCáÁÉ¡ÃæK-„!™fBAG 1–i¡ÇØLái:àÙ6î/bŠ-jÍ~¢˜`3–3)ÝàJcXŠ¿Ÿ¡Ctˆ3(HÔbè0#,Œ] ¤;•x8Î!=–ÐÖü¦©áäf#5E!SNÙ9æ}ÿ^Ìô1¬¶˜³Ìð#5 !Ñøê`v#/s‘ 3ë©n%%=À{#:ŒŠãžÚ1@ˆ9s(ã ÍSCg³U¡@×,l¸Kd\²SU3Œ¬X7Š12âóæ›àðVp¦ne.S`a‹2=Í‚!ñ{dk2¢ÎÇFzæ9.þ—è„Ð¥aO%PÈ·LÃ#5˜Šd@g‰HzNcƒ”p›˜¬äd#Å:úŒ7¥p)¯¯Û%­ìŒæl9æÀŒ{^ðÂŽº2™–3^„¹´Ž2l#/¡F×q[–*.IÔe©RPY.ûsÙì¡Ý>¡­½‚Åžìcm¶ª]ꮪÚ³Ê]ªªª­yüîv$:†ìWÓáÖ—.DÑES1ÃÀ;Æ|¾8)›Ä5Žs¡åZNòcú¸¾„ʹ>Û žˆ˜CnÆŠdm#5ÆëU$5³Ñ3:g²¬’lf…-Ër%a=¥Š‚MXȵ‘À ÎF%F#, q.&gEÓ;-Ùê(ÊjÌ;2a!l†jŠof÷–rBgHÇ"-3$Ç(Øñ©ý° ®z}&Žž[†úíÛiu®&yüÍÅ‹±]ûDÿÖ„ íçÑ>¶ÍŒë‡ÿ:?ÛA£É!Ú=¯šæ»û0|x®Jü"©‹"¬VEø ÿÚ–,KËI‹NwïÝ]ì#/¤f‚…¤¡îòØ^zîú¸(Ö>%Â÷.X`Á**,F"”Y*–Áô( BQËú^‚‡±ª(h”ö\Š€!œ€˜:.m6#Ÿ9 ¢Ã£Ç¾0È?ÉÃýìÿŒüŪÇý?ôì I©¦5¸ô}Ð* °}ªùzvÛgêç³k³)4”ÕÚ·óճdz³ÑÞ=ÉÝJHlü=-ï)¹#,öiÏ &ýjR“Q²ÚdÛ) M¼ªŠ"HƒAHN QÏlÆ€9J·Ù\‘€Äš±iêüÓFFMlZ)rà3íþO:·Žû9qÛ¹xÀ ¬”“Ô.^Š<,û~ä„‘.ÄT¡¨ˆ4¢=Û('ïk©{¬r²5ì{ìUçýe\s´Œa©½‡‹âÒR|“ô÷ " ÌÊ%Œ A´& ¨üs=$ŠOÂ}òå4Ó#,ŒT²‚f®ªD@7)Ø @;ÐSÙ(hÀBDÈàªÀwûõŠ™—ÔsÒ¥ÂIäÅçy°Ìk1EAPp‰V ±±ŒEõÊ€Ù?AÆ&ŒF71ýí•FèkÙÜp‡”¬LhñÇãcí M`¡©³|„{L‰ÈªM°~eŠh•:üŠBÐH #,=fG@–ï§Ù 2cSàuQhbªÛÇXXÔP3–2Ï[ jFO#, kV–æ[†íû¬þtGÉ€+¦@`àÐ@ $EðÒû¦.ôÂ(A0 $ù'!:É÷ÅaDD$E"âD€W‡È.)åÅ$õ[u·[O.Þåáí×æîÓ'Ž;tUÏÕ©•¶¸ñIlNµƒXk#5iB Ð L”€¥BÉ‘6Sü¡þnW,jw^K{"õoK)%4[Þݼz­ÍìŠö\¹175ÒKË»–5Ç÷žkÇ.‘Ά74••Ýbå>¹ÛÊt»ëåk&±OªR*–‡x ‚hDÀÞ¿¤â32FÂRbkËÍ«ùðmø`\ ˆ§°˜¡q3þ‰K`Z6ôYûÈEEb±ê?)È'²×ð÷OçÈvû+“E’c©Bu‰Q¬C²æ¡È›0åˆÆÑJÒEj+”…‹œjNIA˜,¼íУž¬Ú3œú­´ÌÚZóà$`8Àãºr$ŠšR³¸®ºõU¿ÁÛ‚Ä"ª€qQàvÐ DŒd‰"áF,ŽFt#ÏÛ³–ëUH¯ñA1&öì¹äO ÇÓƒ‘Í_Jµ¼ '‚”àe#ÎTæ0¡É® \;Ò’hEd$rH”JÓntBt›)¥…%A€~,D ˆÇ®i¿‹u.œ0ðZ‡]Æ]Ámr85Ù2/â6ð݃ȓÞ8A4ÕÁRa#5î\K!¥Ž“ÏÁ1í#/#/¦¬8ˆÚ UƒµÞ^Ø!%ÔW¸/ØNÍôòý/Éus@øÄT{0îï徨å(´­õo÷ŸöÉ»nj좈AѳLË—eÌ!¡²ƒÉ™é}gÛ—¯è(Œ!EBŠ”RuvqÜœNå”rA5OM&t¾ˆ#,°‹(´3}ÒD~@ÆÌÉ ÓBéTáØ"jÓÌ¢ê–,è'žI×—Qm¡‘ 9§ö4º¬R¾þsîÒåÚfnKšÙc„@wxîÇumüþ>gaü,ÙeTJ$hªdTwÀ›ƒÀi¨Ý …Ñó #/£m±ªÅÕFEJ$¶*¦¥ZÌ…*’¥ª-’ՆʊÍšµ*Ø‚ˆúN ' òœmôÊ“”8lñ|‘a¨2 ȨœüÅ(VÑ#,@ ôý[Yœ½Lo’§…ˆp†ÚBØßì¸ðÊT`3#/ ±UÖ$ÌŒi(ô-ì;ѱ#,%• öÀÁX8±e:b=s˜z¬#/|÷U_… ÆØðGÕšFLöM6Ž˜Ë7L(âÃsCIFE h ˜6ZEWÉZ£9‰2銯·ëÚ¶D_nõ@V@Û´”ÑSc :³—hg=é9Ò­A‘m*]%]%¤#,”öÜ¿§³Á;ÈÀs ¤D*¨€;6„OÛ¼à<û6·Þ¯¼µd±ŠÍšÌªûÔáª*Jekr®Y+–»JfÅ“E¨¯ÆµÍÕãt-q+å*øÉ+8˜(n‹#, @AÈï]ç}z>Ž±µ¶úŽÿv[Êi£t´‡ü .7|^®­ ëz¤‡*ôù,‡²Ä‚$‡ïN"“Þ}¨ˆ•v>Å:ÿÙ»W¯Ëöýœßßþ6Ú˜9!Žuš.$@„ Îÿ2ü[p˜“,)µŠ’Й@îeî½*„?K ‘#5)Q`¢+åT:¶«n;N9XÉÖhæÐ)Qÿ\X/ç$&ÏÃIeTù¿öiª'T ?‚ï“Å:›x§¬1#/o / (gÂT¿«{ˆhbn#/´bDÖgdç®A²²c¨DH¥Ó¹2l`›zÝž‚ôaWõ\Ü0ÃÚ‚ÿ„Dvvu‘dC!«çq †ˆY‹ð:°°@¨i­ŒÅ¢6ÚÆA¸¿U#/¹‹o{dÖöˆä€¶úxÒ$ U 6$cL¹Ç¬zsE#5PþÇ›ç36pÅBAtʼn²¼–¶ÈÊâaDÜpÖò±ƒ@™ª‰®ËoÑO "¬ $(¾â’¢¡ëñ£¹T;5<€÷Òž1gN\Þ€ÝùÑùØÜ„Ê#ÅÐ~R›…BÖˆ)ª¢‚±eÄb]Vž¿·©æAHŒŠz‚¨¢$¨‚ #5DH ²xü‰2#,¦B†1X#,šd==ävߟsƒMjX3ù vNˆ#5Å÷QHFÅO~Úms`j#/6À#¡}@ô±d#, ² ”`†|ÁÃë²dèììõSö¿¿åŒdoß(ßž$ÛPîÂÕÛ8º“„‚"‚Ö[÷P–O|RMamC²¬. ý™³ãsg£B÷ÄL¤ø¼Ì’ù§ŸƒeZmr´¾#ÈbÒ¤GHJò8,öÒÿG‚tŒ>£Êâ÷òˆã4g¦#xVcmÖ¿[Dõ£DøL.z¦ ò­`tx~{SsÞ{.ž7Ö;g€Öœž×Ø<‘Ô²öýZFà[ÈQ0˜I»ñ~1Ï^zí…öÉT<Œ-ÀƒÌÁ`¡O¡dΙâXÈÇ×Û²X-SdéÒc(‚ˆ: ¿ÅçMÒûrw®ýGÞu£V‡ÏlþèZn uºc:·¼ü¸˜K‡­Ñ=ç–VuAÚ¨ÓFå§j–×J³5C¡!™œ°Ä+ÆB¯Ë¬1¦¶éO;îåò±#5<>?f×ëË»¿¬щ\^6&‰3Xi[²«Œ«}š^šèÅi°¥¾8Ž 66 `ÚŽÅÌ„G¬ê;8¡ÏÅ{Ôò-75¥­ hZšµ]ØzÑä¿®ÍZ[[»Š’'Šã,͵&æfñ¹«Ïf@ J0b¡cŠè©ª&hìÏ ‘‡äþ66mƒMž‹‹÷0äÞx®C¶×Ü"Ó±‚àÎo)žªÐb/ÇòrêïÞ™— /Æfï_#,À‡`À#¦3¾Fk‡¡£ ªk FÇÀf iœÂÉ“õµÂX“ ©,KíÀ/@÷lgèpÙ½œv7Â9ì¢isÙj.uäñC˜èÍqѤ÷†Fa"Ê íL(ËÂ8Aß(2p5S¯(SMUJ,b1d;vó%ÕD%&~×Ô„ÂÈ¢Ò)qæåÝ=DZ öí¾CDA‚F`˜õI=h§–}ïjá#/ÌPðŒwßàL!!“±s‘–DÊÆï˜øéÖÇ‹1;-°à9#,rF¾TÍœ îCGç³ðÿ‘ïxüÅM}`z| jFB‡*)ZP‡ÔÐ|*¦¤o/FGƒHqB:l×N0$—=HDégõ3¿vkï¼²wÁLÕ ÀØqdæõý[” 2!§}›Œc+äv@“¯ÝÚV»„Mþ§AçF6(ç,‘O#/óëÅ©š¦µ¼Úæ)dR›%E®–ìÕÔ³DÎíµuKk»ñ¬æëºë^/àxÞLj9bð¢Ô²! M¼;K˜ ‚SIyË»‹‡y¿ %„l+[óÞÚ¾Òû·ÊhjFRÔÈ«Q5ýS» ÚÃb4Z9˜œ^PmU¼{¯.³€\^øoúêýß›„žt2‰Dó.ËE#U ‰ßˆ±#€áE0žAªuªÂQÎ- YJÉCÞGB!ß#/ÿœÀï£éÀ>#/Ó'QtˆpòÉ#,#,rÛ#ÉåCª °¦C7;ë˜i’Í=h€÷%[»,9­ŒpQ9¡lGJ©„¢æe†¹újÄ3&šîÞµï@i¥ß±M †+e~Ì+‚âŽÿI%KLžÐ*¯©êdž|vž[ïH'$'ÓÐzSê¢bI"•jnÝ]hÖå»;­ÚêÝ­Ýo#CT’7©!Q4•ª#,#/$&H‚ØYöšJ…n¢B¡‚GA8žúXên%µ(.Ždb$ƒP(a áˆ}h¡–6Ï2`4LT5BÞ†ŠÏÙ£ž°šíÀÞI Žû×è<}O¿*¬-¶¶2<[ýY³ÏiÇ"Ëm±mž¢“Ä„‡V#,¥^¸aëš_» ó#/Í\vÈHPÌÃK#,ÓI:ˆ„RD#C·.#X¤7`q/ÇÈ¢éj¡Ö™Þ"ˆ wbwX‘D#v;¤á¶–·¾ÜÐCdXS à¡Øì449íÑD¼Gð¯»C4šËãz¦wÃëøóo5ìmìxÓ30ᤆ‚ÄZît¶6‰èù]ÇOÿdÅ34Q/¯Ï|r2oD”•²,HÈu¢#/±}gžÙ#òc¦³ÅZ’1ùCª¤Þü%à«Ò‘­5)$6‡߀£nÙü!û4ZÊ»I e@¯¹Ì\\6†ëNF¶Èn…$ £äµ)φ»pj²®¥J~Õ³rçÁÓÄÆ6~~–»3ÐС‚׎¨hãÒè„P®s¦úäÃ… jþÊŒ¨4ÌG9û(!¯EUCàì†3Ç7¨ÀÃ7n ­ÃA ´¼Ê/N6Aš ¨Q¸]\è|ò¡ B)L\Âaùƒa°{yÀ…Îl§²j Ð-" ê„„¹†¢Te…,‘9¿ÑÏ[²•üñ¡Ë3äCH&%•V «YAìU*#,…EV Òõ•ªœ$:Ä’ÙAÌ»±ˆF•$*$,„#2¥\c Ã3ØÒÖ“=Ì<šÍ¨Ül÷–ª3¢P A¾50tÖ,-(¸«jÙ‰€I0Ì‹#,Ûo)MD2› l²¶¾F#55`êR“®W¥GŸû'V/¾y”•Ýe•ë‰o¶”Ë‹$…;‹ÖT2‰±¤.; ººP– ã‘O”,HéÆÈ…EÙúDk-ö6™›PPrÌQ'äHéÅ´Íáµ^œSÜ‚Æ}“̶I†MK¹ue% ¼#/OwQÄö9oÌ’þ$áJ•‚ðÌ@ 9:Àq¶i#,,óF(ÐÎ$¡è/ãíÎd°À±~F6óññö÷#ìñâöšpoKž%EýKâF ©T+n‘„ã÷tæN»ô"s-qE’(¡—Yëï?µ ’B+!)ÐDè¥l>Ÿ¯W}ö†&ìÏ™kÖ2¥ž/Ë;Iëï3Ôz¨ñß…šjwHeSR‚Ž»Áp–0úžÛÉ{Óóõˆà¦&ƒìÔq¹áãøÇéˆ"ƒTIÙá„[\“Q êbçD BÍØNKœQPa0Nmj–pvT—sÖ#Þn#/ƒ~s_áò«{‡´`øæsp«í#,öþ³±…*/Z2)MÓzÕw0œâþÍÆñdoéO*TWäð4Ëõã8Ôîñ:Õ%ì(»ÕXÒrª°5ÁŸçgøY3ÒBnc1o|p#/7Ò[sQ¡¦!A9©«.Ë%Zo»-ïÜwJ,i¬#5#,U@W@t`¯?)@M†5B¨É2KäàÈ Ú'2/Z¤K@‘KÀ¹:EÊ ÈÈ –Æ#54ð ITpÇh8ÑÙœ¶ÏO&“‚ÅWMÊ8ZÂó\‰ô˜³a¦,ûŒ…aÆßé#/¶RÙÌOÊKl=ô—a<VN-ÛÅ¿IÍ+pÂ5A´ÐI§Ã$ñ ÖFh>àÕk;5åy¤2z/Ìm”„†Á5áÄÁ›‡±ÛQvb³ûÊ¢'G0Ð c#, Ŧϗ³¡;Ñõí4¶» A6e0!Šˆ¨4‹æ´¤ÏÇ¥ª.ƃ&ÆŽ%Ì”"Ùn±¤3M²IÄ#5i£I#/ #5 E4ðÒãc=íõ[&hˆ„¢ƒö³&úA…Y©b” ‘ ˆÇ@¸Ž#5 €ÞZÂãˆ}d “@¬ì‘¿ih`û^¿6ó€wn§§à™É§U>Õ0G©{`H‚@‹ ŽGYn#,5ïÑÓ«®Mc›=&Ø1¦Æ€wNÿGG"ÿa樌^oÊàq)8÷ä?L¹`—ÞOóAM ’g’©çÙdÿwæÈ!ÒB*B"‰sºvYƉè í­¿’Ðl‹6-oȹžunIKmÛ¯¹jª6Ô„‚ÿ`E´U´E$A¢ #5—iôê÷§¼£#,zˆÈ‘|ëî:¯iÏCÜ$©[¢X7ºz°îЀm…” T“íæu¦Vzž³äqHDî!2@‘†H%2RkHS$Ì–b“lZL´¥ÕÓ2¶˜dŠ6šT!’š#0)6IJÌ‘¯µÛ¦&Mi4h–R›Y¡S)™#0(Ð#/©‰I¡ÙÝD*hR$ŠIIbb Q’PZ4M’’Á(EŠiKQ²(š šFe‘¦£1!¥„”QŠ³Mgz»ö•;À8¦,ú0Ì9.ÛœX&Aò~u=JÎÙŸ·ôf̈ÿx¡=;p%­S*F9.¾ó•e† ì:¡§ºy®ƒ~)W¾/×ÝtÊe#/´îÕ¤•¬D!$Åt2ÒXï-œq1ñ ÐzŸM“Fýìß…Âöï7€y9,碓³¾åì¹·[BJ²G6”þ‰kÒË¥gßÏø¦dþ$¬|>˜/»}!‹…aº« ªhÀ\³#y,P!pÄ ^F¢ü#, @9/rÆcPÕ,ÒSiZMa4•¤¬ËL$$,qpxÖ}miåTx0ƒQÊ™Lø1Ç?büÄχŠ­ F=DØ„}ö“Dˆ•õêÚM³ ! ZÅ¥=ÙþÚäcõÖ;ÛÔµŽÅèõ}"DcqøC‘–Á[oZ}>·rþd‡/F› …Ùt”½*› Jè^á€faúþ‹²H1Õ‹õ‘½ZŽ 1d~æí“{©?å¼WÙÝ­Ûµ-ѵ´cH%µ“#V iô8$Ýiš m¿ ÒöÛMó“(á©ã#´Ê%j7®N.ø""àï3]{ãŽéDÆ°¢›Aa¿rP´OezA¹ÁÞi‚ìÆBÝ|J{Lš feðv^`ÙGäÌÜ$°Y¶ÜKß#5<öÒ@Ø#´ê@íÜeˆ¡ú½’ö?o-tž¼;î¿¢¼Í”‘@†kübØ<<õµc/Ñ´À5kìèrŸÏèÐ!V ÒiϸB½†vW5ƒI²¿5ç†ã-†?mg:eY| ±:YPìžì²ªôS||S%JÓÄ©=ý~õÊŽVpj@¨{% ܬ!¹Ï‘Ð3¯ ôœ²[ÓïäY ¸Y#,7\F0–rÑsÇ'B;Òmˤ7#5ˆÁñÞÉ ,>!C ÄÐ$ÃbaÌÃÔ#/Ôÿ¡¨Í}¤Cog‡ŸZ’ñI–ÓìvƤPû`M2!äûFˆèÖ Ó…-Ì­ÚÆÓÊ;Z#…ê¨Xe$|2’}ÙåÞùÍÖ?£V®lÛfI”Ô†ì)ÔÛÈïZºQW¬Æo a31þMf•.¥2^BåÒy51Á„-,.K¯W”£ÔZ1ìf¬Þž1`9Û©š‰”—ñ¢LKКB$ÎÔm¼JÝ µ6üt’AIÒÊΉÂæ>ùÛw•wws!šYÁŒL\.iäÁ Tø0R0JtÉžçOK7¢©á?óíÄÁz¶¹~#š¢ŒË­;"¥àFá`ÜådçάËì–Ã#5ƒC0jvœÖ ÚcTêX~Ôê¸Ü·1Roø‹g„r¤Øóˆ3%ÃÊ LBì 2´>t#/<;;, ú7žx¦dºCäÓ@Öp5‹¨íUƈڜ‘«y(aÌ\rm†–Âz¡W««2ùZBA¢ ¦³Wo0áë”àÛq’52v¾Ø³/Á§Áuy¾—h ûº;v[Û$ç3¨â3€ËÒÇu,­úfwÕØcbÔRd,vrhÀ L»_;l\;þNq#,X(‚‡cÆáŠ(ŠÕHeûÁ5-1”êqDW;4Xa&(Œ~]çªO÷Ž‡øÞu’ÛŽÇLêÀ¼øãs¸’xíÇ)Þns/x.ï>YÌ㦫 ¤’kL:‡C›Ø‘2Ž6I7= ¼c-l‚vÛ…É%ÅÞ“¥¢*êoNÐdÝΦ—ØÆëD@³ß™9;6.Än%à‘ÓÞÇG=²öâaÝðÜì¿Ün æˇbsÎéÎ'\µŽøRž¦Î]j)XÎÌqMíC“´#÷å¼—qê.gxÕßÃ7­0ln6Ôi•Â¸Ýq-n#ll#/j&¡Ü(]èºÇ&M–7K}KJÆèôRrA‘ƒaÎ`î¦é‹"Œm¾86v¤cpÎLc+ÑÆíÙ\»•ÓZÇsl£ÔÅ\#/e¬S!(òBƒfækKZï½´k**)šjÝ”ˆJfGºVXnÁC#ŸBÞ(BÛ‚ iÐ#5Ñ'Ks­ Á\½ Ï•1GQì±mP¹rIY¨M†1C8ÎÌöC´ù†ÇG2>TP™‘³.e†Ô[ê‡FPaNü+imðg`ÀŠrÐ5×U/V@ÅCd&Æ^‚,ÆÓI53S¥¤ ÓQ‰v9‡ Ta%3 8][ßPJc´$dÂ"méÙKJ¢P‘ê´TÕºùØÔ3‘É 3ø1z®C³mΕ­·Ìõ’`Lƒo´ÚwB\G,A(©Y+”;ßtÓcI¬7rX<ð5iaNF:tÞåt4 ÍËËÕ6ÂXK›e:G #5&$Y<Ú k‰ÈCEñçÃeá—Èã9€·zâòñ³Ñú‰ƒiÈDS‚QHn!¾¬s(a–M…d&°U2LŒTBš@»©O©6f¶RêT–Q§v(bÈ°2’P¹•40òd£zݘphU°-€`ªJº™8T-!–ój¬ YlY)7ªP1šË0`aV‚e©6IO$¤a–`J£€^¡ÓAX6öôÒŒM‡ Œ+ã¥dLÙR’Ù²[,¼Ô±›2evgrx³VE0`õQÇhc¶ögYföΔ:™]ë‰Ö©—ZRðz ‹LiM+ÙÂ3„‰‰w-Í ãÔ/®Ñ‰Ä!+)’e#,òôö ñ8à:H“a ë„<>VàÔ-gnK`lErùÔö×¥ó}™ÄŽí`G½+½è…PèP}R9‚AsI¦Ðî±¢`TiBƒfèÖ9³h'VÙåâ˜m‘#,@ ‡ ”ΆEÁ¶ÁÝÜÚ3#/¦Læ3ÈdçJ×¼ÑLMmH) #/¦á#H. ÑUV8(|WAÈ]G’DX°j(L Œ°:ˆÄõñÉ#,ß±ouš)‚&ßZ7-½m^¶¯%â-OnÛÒL6C„CŒŽÛ…o4ÌXn74§ž"£¯˜Ùä/ë¼ô|…‘æ#-¤J:?åike$‘#3 œ9ð3 £·}hELȆŒ÷ Ç ˜pqD` ¡‡­#/ŒAĶ‘@Š÷ǘ†ØhñÛ²M ÐQ£f&—¬GcrÕV ÒÅÚ•HˆurŽ˜U1Êò.IÀ8ɽÌ0(vî)7†Fk6Â&Â¥$,Ù3£™‰HB*Ùˆ@…À†Çc‘¾Œ8pv¨Ú‚‚x±£Iè,Òóa½Íf‘л/Y‘Øï%Óz`X†‰FÐÁÍuC­T¡k@º ,Ä׫zè6‚/#5úì”&i°ÜŒ`èpWî¬5M‡4f3•‰cžm,OqÞÁ™º5¡·#;pd0Ãr›\A¹Ë„á­Ê¡‰ªJ,&0  "BÁþÆ @‡ø¶”ôBE„M )˜»‰h °RÂìJU#5#/†ŸÞñWòx¿«Õ;€ÚüwV춌Œ‚²­M!¸>cûÌ‚N´TzÊqˆÒ—B«øÀï•#A¢¨³°µ¡²Ó!!ÜApVà^È;U îËKùEòù‡ÓÜÌj4ÈÉëÇÖ31®[>”çq9"ë_óADpX³[dú¡Ç.¦Ð‹¤ ih§¤#5tÄݺ…±RÍŽAiÅÎdÎ-+X¸#‘ƒ†Ûd¦¦k`(o Í[FFK¦ Œ#5ÚïMݧ`b̸«;¡b¨mMšv*†|.ã©´¶Œ÷À8›ˆKœd¹B‘$1ÜýÚСU{nÝ:Çk–emúi-m&ó@„U Œ‘›ïò‚PØ8„C‹ —§®‰€—#/yPåJ–,‚Ъ1Ã:z÷ E¸ª[géý?P±;÷ÇÊq:‡—à ²¯ÒE]¿vÓM+oßkè¼l¼%ɦcI]wfsu‰QmÒþÑy©ü÷#mg¢}Ƨ¦p¡Ô²¤g,rHȳÚÐ"Q#/Fžãò±2Ð>Uñø”Ýq Bá0®#/7>ÓGÞ‡ˆÈa$¶ÅRQ´¦Ú+FÕ%E-35PhÛEŒ#/ €I#, U¯ø&ïaážY‚_h –êSß·«½qLCà]NØ*~M¦½ÂžéØ˦Ÿ¹ç|ÞÉ}9š5v ²KÂÆÙ‰#Mè h$ÝFY•D…¤Ò ro!¬¨{§ŸM@H Šqö:-'„Íe¬ #ÎfÐu”/V*(~ÆRH)#,ÔÉRZ üä;¶#,÷v6hñçÑS¬Xd&A·ßUÆh*1’Ó"F¿#tJ²4&Ði©²#,\ŠÒ%¢ Ä«ÅmXÔ¸óD1–!p„HO“š3pÃLä\ÅÍeº&šEKÀ1€‰dÀfwùÏGÁðbvúÊ#/‚›”]! BÑjÅ l].t§Øè$ Ýq.´ýÄ[YD*"Ix¢ü,†ØŠä(£¹œFXÿB`>šùdé0òð°A |ûÅA¼$&œ ?mFƆ´Â~Ø#¥Ço´] 35o]ÈŠÈæºü!®Ï½ý ñk@nmpF_ol==1–„ɶW¤3ˆyQ„«Kc+ChãÚ la¦oZ4´cX±EzŸÝì°ó:ìҙǥ éVP½´[MÚé×3.º˜)d«Cƒaç¬074ê¥#53©#3“Îðãžfi™ª¿Â&©¨ý;dÎѱÎù!ÝÙÇ6Ü=ˆ.Ù¢“•@°.I›9Ä`5†#/#`†k”¢eL¬;C¬€Ú ÝÒ–S3:g"K`¹ AÍ=:j4Y%¸ºv~Øg3ˆj ‚qÚv†Ì6K:A‰F%‘–XÄ)¥rÔ)ÀÁ\Ød‰ #,ÅÌT°Ò¸0¦L1 ¦ ™C#/‹  †9‡Z$#5YEÇ„03#/Žnh/Ë[棈 ”¸?ã RD^„NFÝáeÓ×Ýë± ³Ùeýjæ°pH±]” £ý'ófn ?Q?T¡pü¡Î °Ÿ»â HÐ5à$éLò°]YG=#,‘Z@ùýPÍ)¥^î d#,ÓNqN˜U4QUUU#5¨4ïFßÛH²[h­’­bÕ¤«Uùµ”Û˜Æ~+ëÄÈ’8}üϸïd­¾h‹s#5}Ë#5ó”‹PꦊüOô`8ã¿›Ü:ubÅr¿½†âa©k²wŽËGº#/Š«d‹‘A“‡,ë§ q¤Ó2enjêˆMªt”’ÂÕÊu…®iubãê;ÞÚÊEF1¯p1¶×Ðèà\PàÄiÊtó©·¡ÁªR ‰1œ¤¥Ö;KÌ4›y¦óYÛ¢ÜÌZ’ž‡¾:Ý­t Ù&)§Už pQßPYbÞÈ…13±³Ë5B"òQ(ÜD е±fKñ-g)\áÎ:;X´3ßääáœBàQ‘2qño#"ì°˜±J|Å!¢ž†”ֵ̕+â;vÕ™§{o(Q4Þø½,m½MŒ/ˆêtQõ6ûe)Ég‰žL˜â}¶`òdCRŽ MNä2Jò¢ƒc`”VwvÍfÜË—\”ä† ¾,,Cˆî— "( ÌÅ9xokeAE¦ #,ƒPJ`Æ ˜¬FŒÍ2<Âå݈ Jte.%¡qžûæÅZóȹ4Rë&¶nÈĉ@K™…œBèÒ…8€Ð…úÙ¦#5:z¶ˆŒ©zÙŸÒ55 ø]ªîÝ’m[}Fù.Kµ³awsK·\f©Î·³s¦]ÎÉÆN»Œ¶ò‰ªéh6ëWi+r»®Ýݤů;¥5;Ow^o5¼jB×-¹­ÚTj“Ch*‘Êëi#/#/ii"Vª†…#,nÛ^62šÓI I‘6V6ÆÔÔ¢™®¥®•¥šX‰¬1b«"CÑå´ÙÀ0Æ fl#/’+[IQY’$AG‰?I«Ñ{%´"Й ö1‰±Œ˜‡}’Ã`¤¨œNM£.Ä¢-"°T†Hl²o‚ób ê;Ï;‰ØL'¬„Ï^‡êaKîZˆYLÃ?y·òb<´@÷Äà#/NíÍtFLJçmz¢×«å¾=›ÏT¯¤Kóéƒy#,ú¨UEÆz,qƒ‚æPî ‡ö¼Ïé’Hð|{†éLûK‚‡8Ú~šêÙL/B`ÁBÑjÔ‚ªÿ~ #5ÃlƒBfh •Z4XRÒ#/BD×d7Q¶Ûfv[MÅ)”a‚Ñû³3ߥ‹}Ù9-ù·XùÄ6kÚP%,jTŽ5\nƒ È3§vŠ'ݬJ¢s\mje2+çÅ@̪3p—¿ zϱ•¹êkÐ#ƒ§l‚Ó r*°+xºg"De“§çvJ9ó“Ýg ë‘t/Ð…ÂÌ(7$ÑtãxŸ§èk¨Ó¡®{ƤØkTcEÚnÍLRY&mÞfè·­Œ‡êøvüc-LªÔ„µrœä¦”Š(–·Ÿ|›[[å­ Þºf²Ò¢Y¦›i›El¤ÕJûKü?ÉÛ_¦Õ_&©¬Óm”µ¾­‘#|)‚D…š– gv¼™J×JƶrÅQm‚”o ÀÄ#/Ôˆ™ÐYÙ5ÜP£ÕH%A@$E 5Å-%&Õñiº0”jIk)¶­6ͦV̵šSE*KbÃ#ELª•±-¥0”PÚl¥2%I›)™´B˜Õ2‰)(¶5&²T•¨5)”Y šJjE(™±%©i²6jɵ4˜,‘T¦IY°•ZPl¥H”$’e’“)3’jdÑK6©¶1ª&Vƒ"FÔ”Ô¦Û*šÖ¥šL–4¦MJUK*Ù*Õ|ªµÝ­²²ÛM¤³i)*ùM­®•6mT¦Ûi*­«á«Í–¢«ÌÕcZÑl¦ØßZªåj‘5jUP‘CIF9Ÿ/HpnÏÀ–NÝoŽ†MYÛH÷e³{°Ù2í›0ñÑcBÝë'~«ÅÈ㸫 ©½»hYá$©=!â^#/)ÂÈÞD‡u/÷€1ؾèž_n'¢£²=PÂÇk´4#5.Ã,=ü½,k³g]¸bÙ 3meÌzË£»>™2Aó1ŽË`yd„E,Žàuõ¥¯¡}8þMCFßl¬ët+÷ŒYE„ Ã¥Q¦(fI QÖšÃM$DD‚jXªÅU#/ û#,;£Ü{dkù‹X'©Üè,š¡é5vî‡K°6Á0ùå&¹Ó’ v¢ª~#,© åžÅåûÐÀƒ1›°ý"|u‚E. y!ŒJ’Š­ÝÓ¯ÀºÆ2âCÛstæ¦!\ \£:q±1®"µàv_´• åïB*75¶0"t^+òA¦#/tøySyjzM‡I!Š“»4ê#ñôÇåo{ºòœÆa^E\^i­éY×O<íF‡ëu¼]ðи±FµÝ qWX¼4×Ñ沶ð·eÍ’¶½ºQW]ƒÙkÏc“B7kéR“ŽæÇ1…qPë6Mù«!ÎÿÌ]"LÅÃþŽHe™EÆZP+®ŒHŒ–Ú¹ÛéÆýƒ’cZPPRJA7+¯è—'±Š+ÚN…7HI!„ØòX;A¡–5g—ZÞÄXí=òª4ÍáGÄÔAFM#/½P*‘*0f=EîdÑhduç§ej®C2)Ò¬„BáPª °aAär+ò0€¢Ld^±zî.5£'[šÑ3D#5GÇx?!Ó¥ãQT­9ÖM°)¥hw)¹_cí#PEêzq–§MKCr¦ UK†QË4`ÅŽŽL·~%cÞPt#"#,ȆÈHÈýËiTÐëlñ¬ZŤŊ ”a&B[e¯Õ›2FŽìe$qJLØù ¯ÅÞöÌh”È#/"#,#¤Òløb#5&’G­*ä‹áÌTcÄÐhŸ,ô­†Þ-:Õ uåÕkQ5; 墬lí4QYTQ˜×¶˜Plv;¼ò´wÇy#/ÔcSfW<|ò:Òx½‚›PìàÓ·rì·NñA4ÒÀb²’tÁG­ R]Sc#Ng#>Ìðn,•D ´é‰B!²L8 ¡Írº$Š¢Jª¢„IÖ¥ ˆ[J¨ÝØY’k¦ëmGÉm½È¶+jòïY>!S®@‰Œ`F‚eAB¢*\¤–ÙB#µÄÄÌ0€}”Û×–Å׃Æd>É·#€ª1@ð3;õxÎ]Ü©q¦¸@åÝÑ"Zº#4Å–ŠW‹‰·ë_x ,À¥™ùúùùBkdÂ+õµ¢šâÿ!Õ€E‡:“A#/b`5|ܤ€(BÙ1UmµrÆͲÍ%6W]6‰×M5ŠÔj¿‘XŠ,I¶kÚQ­½÷«Ùl©hÄú?ª­#,a#,APÂ"PÆ7À°Î!Bå„îa”ü1NaÖ3÷¬ÝBÓçUk´0+Ø"A¡0¬ðf·×6˜Ä¿&®/†``i4‡ßø` `¢ì3›c°0-¡€*ŸŸÐmÃ#,ŒAV¢ª4JÑàÉg?+ŸUú›4ð;㺣,7–"’IÅ ˆψ¹ª‡×>;vI#,%ÖCh#/ý¹;Ç‘éO«Yöýyñ½Ïí½Ï镯 ­vǺ.øuQ³“‰Ûì!ø«6åF†n²àCw7i¨ÎD=wyG˜¢"»ØT"Ûöqô#¬pvv- @¡Y^F#Kô¼j(Ûh b¯XTe[1nŒX„ š¥ßìöoçÈ:Á2 B?PC¨Šq#/ªeÂÕ؃ÏÑ騱â¯Ó=ì_è0[ öúÄ=CmVKb¶¿Rjµ,®mu›U·Kj£i+¬µ¹ZÚ5²ú°ïFŘ¢‚TD$A¢% !&#,3«=wÞÂîËÑýpAW¹ÁVØÀ¹JPe$À" ê%#59#ª:BaXLÚhcAèÐÚÙw°»5 ÈÅ3a OÖsarz“Í(Ñê É8š£ÊÎ%cþQ:øÁGÁU,!ÜHwÑÞ< 1÷¤µH²ØR**+àvúÐÜQø÷hc10*Ä5Ã…hÂômXp[,‡šûä€&¡#/ÇŸq‘ãßM¼+1yåÖ~N,HVRª¡¤Àhxü½ü;;R#¨” 8J<ˆ¨R6USK‹Ç^4R †ÃÓ~¼Ÿ}ì_Œþ=!…„P6QúÉÊ&÷-š[­T&–"`åÕ¼Sh ‡ 1³ØW6¼s«¶î‰(Ù5&*RVѵ Ô×Ê[´i­¦•”öWRk%XªQÛ°-î¹@mßß¿p¥Á;#i“ïvÒEÇ€42£tñJ¶éÆ­…;ˆy³ÌoTŠU7ûmiàУ6ˆøêU&$¨gmÍ(¥8¸àðÝ`ÎqDUå‡Äa3œêèHzmW¹"Á(ª ¢ÅQ!Æêˆ#&Rä+YO’@Áa¸è ]æ’ Ø 1G¹wù '¥íí`u’$’LÀýq±ƒƒíõë¿×÷[ÝÅ é¤ÐqØ%³™¿wRh„"…›hÂ)V›¢`¿äøm#/¹›dŽzÈþzÌö‹ž–¶ün´h5õâR—¦È¬‰Cá :'ª¥t›ûŒÂQPnÊv@às’¾7i5$Ÿ{1#,Ø(2š0Ù†A“ ˆ†#/Ü …F%#,>Ìõý¸ñŸf“Õšà0†n(c‚<ù˜1ЫÌÒrÏõ¢#,¨å¤Ñ*M—ÙóTI%FÁÄ8¶Y0z¦$öi…“¾ñ“òÄt¿Š6ÒuuóObˆ{_zišó®˜‚|ºNµÄ&åßMå~hÖˆ´b-"„¡jM$%"’ªm´µ%¢Ú21™¯Ö› 2hJ‹K?q¶¹µ¦eR¥%XÔQM)i6ÓLKfµJÆ›YM-dÖ‰±ØÚPj•£"ËZQ¦U-*kU’)h5†‡æz”#/i„O÷?6“Žìd¶¤"f#€ƒˆ£ÕáücD‚5$AJ ÍZ£j5¨ÚêkZånÍà[2@$dH¸buC»«~H_r«o³¯£[š¹ÃW(ÆMÔ¿Áꄉù’ ² ùË”Íü¬¯¯uV,š”#/¤K>av\öýÙ#,2Ï~ñ¡: ·(Û°»`ˆÜ§.H€w`‰åßþw0âW„Ah€ÔöDáÏMÂzÓŠÙýÄ A2=‹öP•U*P” •¨ßäQ/j[¤(q XO½œ¯"ØÊ<Þ¿ §ðÌ•´Üm×Bƒ$€ÑÕÐ!=L=|î€âª¥Êh"jD£9–8˜'ëÝ•Å¿2Ð33²›–7ü}‚§¨‰Ú½&Œ$ziDk´ç*©°å4ø †õ@<{GÈ#/gA'1#,bjIÄ·Xj‡P3väž<䱬äN Hw0ãÈàlúḆ©ü\£Ï\»(ÍØH±’ƒŒÄ¡ýk<ÆÍœ„!pIª0Zà~¿ÙgÊ!G¹Ëú «÷Çòùi‹|@¡4´²/âçÝü¤û»My–Ôl&žä"Nçký’À½[FYD0uűŒ[ªd“Bd˜bû©e²¶ö¹Ò^^à07 š…ÅsC’»+Ž_°ÞäÂ} ‡±‡±»­S .Ü6‹i@11Å¥²„øf£&K>^&—×m5ŸFá~¬RE ‘AN䥂(Æ#b„ñKw>ïdŸ«6kG´:htt#,á=_ïÝŒ—¡p2€É¼n¬²ÈH‚‚£c¦TÛ=Ò1ˆÈ,¶’2&š,K¨QC£Ou†n–ê–‹4T$Y”²‚`UD)å-SÆ“¢~„˼S.›€(ÐÛ XcQ“¬qÀ-Ô' ùŠ÷ÁˆÌòAydfe@v`b qLqºß m]*H™ªJêä€Jd¹Ý¡-îÁçtõ¨vÁwÄ"Á\Ý++î6-¿KÍyñòåÕ7<“yrBóÎ¥~I#k,Œ'¢½>ÝÍ•E“\‘P3HoVžLÆ¢"3°ÇwkM´×m*o#/¡'EÚÖÆÆÒq8‹¹‹A-ÂH0„¤”z ]á£ïÒÖ ¤,€ÓŒQU¦¦¼ÌœÅ<eÍŸûB'0rwd§ëµ¸Žjá*Çy²K5^P¸Ç @œ3)ÙïcÞ·Ôº¨WŠ…RÅa0ý¸;§ÃaDȢ߅¶•Êoïó£}g%ø×Ã.³Ì¡T ÔåÊBIª¤‹n¼†È[FRPì#·[Ñ$Y íTiãŠ$økÒ¢µùfúÄ/êvAÎW<r²àˆ›®G$ÆbBÅÞì‰LCh~µ–Å…'6ÌA5F#,Öýäˆ7¤¥‰Oß¼(ÀF[$ï&»ÂZJËÜåóÞöcn½ŒBÛÁª?³ja䥅‹J“k.91-”âa¬†x}L®³Q·#/£ìfξž@¶k€jGR‚†‚РˆÙ±¼º]ª…`B@Fì(‰•iR´@HôE(¨„Ážf´#5¤•Àõw”:S §™±tEvoöο±P1uã±Ä5ç鬙kÈb¤ÄD(u’´ÇvËæð9´t` ¿«ØÜxÄD$6!É›UdE:ö`VAA%Z¬KÆö¶‹¸\ˆÙGèˆeêÉp×^Ó•³j‰©Èàýý°Öúü›Ý<‘}]ÜjÄ~ñhóuµ]v›xPšDÛ^ºò¥ƒQZ›JW 6ìB #,Æ„6’% 1‘¡(2¤*TUF¡ (PH}WC™È¢‚Ø÷P;{kTƒ¾ ˆ‹`©º›SU(ª¨€ªûù^§òW{Ä1\*ð&GaWŽ0­ n(šwŸ##57ôx—nïmëĬcºÂ[p™Œ(À#5Óa;@#:÷/2Þ(’µåÎæ“_R(ô€Ç¦9»ZÉ6ÐIN0ŒJlC*šDh) ›Ñ6¸L±"l˜sEg6f%Y¨–Sd WLë ÆžB]å0ìè›È‰Û­«DÈÂHÙ“Ä/òmZhl0Ò#/ós`Ö¤UD7wD 0ÚÄ1l®¤2Ž{TõEOé8 ÚpãÂB@„u"T#,/˜-ÙÖ—77¡çKïîcI©Ûê´Œ#d=^£š‘ix=KZ…ì#/À›'ùõ6á­•F¿sƒLu8š&ÇÀ:hì¡)#,êƒy, ‡¢*]ZRj™¶ÊZ6eLÖ¨ªRµùUù›[ò"W]¶Ú¹±…!(`°¤)’(£Î€‡Oݸcó!Ò<®Yh¹·£j˜_HqÚ#5€¬==Ö³VB¡ïš1NGŽÂ^uç–\T[”žö«öÑäÝYGÞAÏ ŒC#»:8ŒmNçÒãÓYÂÉŸ÷`â/ $–”kR/ë~ªÀÚE–y'áPÉ<Ö»ùf·˜ÀÚ4Ñ$ØÔÙ'½å2‰¡Ž’Êhå‡8á}“n±ªÓl@‹ŒQ:ÉP#5FõQA4ä'^ Ã#5 1ÉW)«¬ï½ºôë1LÅ‹=•_ ²¦))Š•*l#/r(\4JM¦f†AæwôÒþY’Kjé>Æ#/­µø˜þÜ‘cVÏN}M·ø¦<óMÛò#gz8ò!§Þì2vu¬#/eÁ;|jù`³ßÛDF`(ƒj¿ÕD«–™÷yyž#,zÐOIâ¢Û€Qž”`4jû{~Û‡œ^È”˜„ãÞ…ð dÅ(›N©È”ÕúñtHQ|ÑÑ÷&4Í@{R!ÄÇ*›ÑÀ܈7,cŒ —!Ïë`²|èVcSWn;>³<D’×—ê½õÓÖã„nŽ™àO‡d¿`”:üg„3!š¶#ªTÝ%T@÷DgD47:ÍŸvÁ£ Õ^}ó¯rû žŒGœ·1Ç+>ÇiïrC€Â'*¥YC(•9$—š 2idHAˆ½-"g7{´¿=Ù€¡¸/Bï6.®¯W°°³ý_EÞ+ Q!¶yVÑ`¨ÄÀdvÊ—RÚÕžvëÓ½©«lÍ[z­t֯ћSM_©uҕĈàVxâùÈ›ÍFFRàs±Ó$h1jšø$”¯ü_íbÇõ7ñ¶îÒÙè’¤=È?ìî› ƒÇ•™hæžrõ[F*&ƒkã±xŠ©ÄójV°¸²¡#Ê~HRe¬ç­ulLôеd#/0÷ƒ4â…ÅÁ±å­­Io#|Nz>P 4Ç–" ˆ§R7ø†%C2ämê﹄€G¢#`Â#5í‚H_8FHT¤Õ¨,±\ÝÂØJ€ ·vµ×,ÆÝn³Viµ›6ÔÍi’¥™«lËUu[7e4¼\“Jím}R¦bÚÙ`@E9Øèq`@ß: ë÷ÏDéÏÙñ»oUëÖæ÷<˜ÜÔ³ßÏØÒÙ5DzÌ"µäú*‘‹4„ª‡ÎÓ5!ñ>éMI¹ó†3lÂAëõlõš¾…ÒcZ<«ëÑÄ#/›rÄ£I-¥¦‹ý{¨l­>@ ÈÁkQ ²LU‡MFa°õ8½Ö¬ìbE,…” Æ4ú#/Sž¿Õ¹õ©ßW#/6ÞM»J16æ¸ß¸7plëÁð#/ÈâÊÅ_p6h^²oó®Ãnªø‚,ESøëÒ`ØßÕí[¸`”]Ô¶©#5hŽXæUÕ»°¨Dˆ€A¶ÄÂó RF~ÃVø‚Z*îÖÈ3%Ø÷Hk)JòFÛÐlÈ(3™TqMP90yÍEÁšAuög¡å#/­áTCð~”z,^G™"`÷¿=·<â‘I:~ÇÁï4òOZiƒ[9 ‰PÜäÈù}þg›òÙI0IÐFÿˆK÷#tH²À¬í dZvζâŒî0\7 ŠwnòÐ;#/ì8…‹È® Älô Ò¬ÜÖp#/ÇØ\×yܽ÷ù˜Œ"0ð3Ázõ¶ÛñâiK¸™íÚ(ˆ—IˆöÀ²RaDú•VIu }YK=™.!ö»Ò< áàE„Ö0‚È'!ÔeÁÝ)þ5‚›«1ŽÕÜkÂô Ž¡È3oÅ0ƒ? T7å àÜ„Aú tæ„&Øðº4qü`e3bXFËM£Lö›-¿#/ždl‰ß‚…@rMÓÔ±î£?Â27!áSÑ°»SXÇ•‚´ºÛ¬ÐÊR5vûÃÌø Š‡ÇßÊ|7ÓÜR~"Ä@ž €¨‰™ç;§2€^|7Á2ªº€¡êȵx«Qm¶Š¢¶Å¶£jŒQ!FÒ HP4&0»æû_ò__l'¬a€Ä;HÀ‰@?¿¡Á¹U{ ¸ØŽèØtÛO®¶qqFåœÃØ(nao3[²AD†¬Ì¹ë"1è2•Äšž—-¶ä+|±ÇšpAÌŸî#,í¦ž§˜`8óâŒ!o#˜$†Q[4ÆycP!øÖX¦20üÝ¡ðµ æú4ñý_­óU Q¨(¦‡­O^ýÔª›ÍÔ”IÐ(9†<„£ÄÏB€£`0Pž"ÂdvIOè!·ð©#/[IÀÔ£×ÇyÕ3†Ó}„ˆþ3ÍBçÕÜ|Fo«1=ð<6}Õ æeÖŽž˜Òbè T#/°*ãUÊJª’ƒÉïÁo6Í÷M¾¾å®Å]Ò«!²~Ô¡ˆÀˆ’{ÏaM² dp£AlMH?¿Ýî.xS>Cŧ£1îM|,‘¦Ýøòëd50®n>0†3¿hkľEƒÝFo5qIE.8<<4‰fjiªž ‹4ÍéßcÛC½U³5üïÂÙ”.!CF^ž¢2ónN£méEvÏ>†ùa0cc…¦ó±±—½æ¾¦ºèmi`Q00ƒ!’Ÿ€O¸eSiA›Léõ]-ÊÓ#âý%í»ìç/F 8éØ]T(£¾¬I¼¾ Úñƒ¼ç”ý8.0üa­áæy•žExѭퟧfpuꛧ<‘#5òáÃáŒÔ¤–%áq y³+Òž¤ÒœcÅQMBBÈniúÅI¼·Å‚ø¡d8ΓÙ#5ß<†×ÙÀ®Ù0áH:í@i}᤿5K`S™Ó#/$¦S«ø}aêêü“S.=êqP@o’ƒæ "¨ÌˆØZK‹d²¿8("|hUlºCHMœq­À°¦«2£J±¥ Á.å¾VñÒɼm»*®·6²m»ÇI±Z*òêK][r®íÈÌÝ×h®®ifÍÈÙ±²¥¹Â§vÖ’ÚM³l¬Œ#,´…ˆ BAB¨2ìÀl@¤œPK°ú†G ˆ­;ÑȨÛ£Ó)¡ñ¡Jk©ôaùuó÷¾vÖùµ`J•l¾5YpMZÒ”ºÕ»-¶ZóËlþ8¶P¸7Š‹Â6XjbH2@'%ÍÊÍ|my3D¶[kÊÕÑF.>/=òe5ŠÂ) €Ê„Ë!E´Vñ«©•I? íP%±X2”ض-¢1Y•Æ£TmTÍ££EE3F²Ve$ÈÍR Å´Í%±kf¯vè#5$9 ”A´÷ï°¡òÄÅ:þ,€ÉôÖ­{{#/&Õ„ “ky·í_‚ØúW§|vñm#/O:ˆ´OãÅÍ·’r½Š£]³„×VÃÑP"å#,‰H@Œ“¶rñMš*¯É+~&µ\JÚñ[¥ý[v"V)O7]&©ÝÕÓk·i)µ®&Åm£&²Vî®Ò›V•T¯W[KIQ‚”‹MÿÍ!Ä6^Ÿ™ A~’ŒüjIèJU G&0A´É F;JCay8ä X„EV)!­ÛP\7œøµJW#5#/ÅxaNŠ¦èŒ"ïW]0äÂñÕmúŸhP{ö5>Âo>«ãÆO~#5?^‹HÃ)AˆÃðEƒÞ~ÁÖ•84}& ð¸ëmf,FE[ÃôÙTlcUáŒcÓJ€ÐÒÌ­Y… ö2º$šhÁŒŸÇŠ÷ånµ´ÍáöLc,ÇzÈð³†d·øš˜ÛÇ¿aCsb­†á‹»±-PZ—öR#5¥(P ¼!Ûgꮤ¸MŒ;:>‡$Q8duÃ<^ÑwᲩœù½‹§[¢5]ÉÖó™¢mÜY`¾‚[hÆ‚QŸg{«42Š¸Ó-½?¾ãø“¾â ˆ#ö§Ö;ûñáÀ¬föÖãu»`vH©½O*£•ÄQÃ÷žt?º±ë0T‡!‰çÜLì3Kܺn¨E2ñ-Åõ!ó`y†f@<`«ôMmcTm¡-¾º_}µ¯Ï-äŒHÚGüäL¯J&12ˆÈg#,KEdχQlšÕZ5\Õµåuæê½À•ÜX1ü€nËÇ>pD  <ê0?a?C_¡ÏÙXZQ¶AÕ&´×_·y®ùq¢ÚÊV®––0£%îh€Ö ƒBƒKF¡¾@ÁÛXÍ…£ô½šØ‰Pl4$†ƒÚ¶ïvÕ¾Ø5ª™IŒQ­UãM±oŸ¸Ú¼î݉ð»Æ®¤J(D¦eR{Œ%—!a#‘¤šZawiZ{Ò¥cl¬Â‚àL#5X»‰›¹*Äid-Y* «°ˆ f c €ÂŠ‰(T(±`4½¨t6ÀLÁƒï¥¤µ\E”C2èËôé½q4bàÓ( ¢1‡¸–T„ ò_IP¼æð…#/JK¯¬úpcÒ4a`ªsõ€q•cõfLÜ&†CsÎÎWРèqŒc0Ô–£nÜþòÝš3³˜@9@’zDTQ1#,ò2“v¶ßIùüihqºX=nìšG·o¼7¢Éÿ¶¤²ÂçägƒgHÏíUyì78~X‡C8GG×!HC‘{zðç±úµ:Ô\9úpXÉŸWó𶖬¬äôþ1] ½þ¤q{8ë©qö8é ÖË(΀TáÇPUAà vü›&—ɷ䘎YJè’¤ÓHB eŠ#ÜÄI™˜ŸxÐ×mí Ç2¸¥©#5?U€yÈ,ª)ji-: [G„0÷KÁlÅ@(`-ËYEl8¶<¾€ÂàWH#“‘^yÎéáÏ>Â;u茒ÿi~6a“éã!ØgtÎÇ…ô+ÁæQÃË®6õ4õ5AÝþ÷@>þ¸’AðEUø&+»tî•\Õ¦·[MJ¾ü!VùîwÐP…D¨Þw&Vãû3‹u÷6Ûè×\J•Õ°fÓ±ˆF{‚Í…wŸ£Ù¸’I Ž-U#ÎòóÍ4櫆Iºï<Þe¢S–æ^s JjI’±”ªñmÕ+bÑ ÉcA²[Âk¦´š;¥uy¼GK¶è\·wn‘]/ñµx£ššW——mvœ¶e’uÏ5·U±«m±³MO5Ú“&Ôi6žuÜY.»­Ý”é·E+;®×*êNîÓbÑcš¨¦†(TE‡÷P(ÆÂ)qUö'²pØ`›‚‹Ù·×½UƘ[µ9QüžŠ$;ÔþÞñ-F :Eð„ €H–@S¹ˆ–U—Ú£ä$ëÄËóGÞŠÃx Ø×H7#,|`HŒLÃkÑÒûÙø¦‹õè•ÅÝ°ŒŠÐîõÞš7zòñŸu£á¹?GsÔ›NÀõ‘t•XÖfmQ)™¥ôÕíÌ$ è„#5uZ*Ðb Áp?„#,X(g:½ül*&ŒXEXD’0I†$OaáêPúÕBùòèØ5+¶u×wRÍEE»­w·m¼’ü>ï!ªgá#5ÂØÕ5jL¢·‹ÃÚR¨g ¢ÔA¢έðˆR&HÁz×M!;ŠH¢@0·1ÃB"ŠÌf£o¾uªˆÖ­×m»i³ìkÊŸë«nÕ»Ål¢&4:§žýé˜d'È@k:dÿGöáí)R0 L0)A´(‚#5l`|ÝüSCÙXÔ ú€î@#/ñ¦¶›YfËU4Ö¦ØÛi©ƒ†ð/#,1Û³é0VçQ#,uÌmõí³lšÊ¢¥Ô™›` *ÏÈñ`ÔÕT#¸ú0ÑFÑJRRj˜0²”€'ðP"$P ¹pÃrª¿êƒŽs[S>Šã5‹±\”å,AL•¦~>4Â7H΄ˆx²gW‹Llf-mEúºw÷c~«#,¥¼‘Šb„ BOÄ!{ßá?=¹^"Eå#,úe‡0ƒù³È8ƒÈg„+`_ÓÕ}CyfÊÈHC ÛIÚÔ4ˆ>7€ ÔÀÚz“8blfh J å…¡ü #>,-j#ø6 `j#/$Õ’1W&³hÂÁ8é$B(rA#/…Ú²¨0@ÞÝEd&1<¬¨#5´b#N°ÑM›¨X; •AµM¤‰„Xñ`]ÛL¨žúów•æ·ˆÖ-GŠ®X¼jå“W/‹*µâ¶«ÆW¬5úR¶Ûk;fN=Ñó{njöÖö‰0Ã#h~€bH$ÑG(‹"c\Æ<.ð ²Hk_Æ*-j‹Fž›i¡µ,Œ%£!Q*Ã6ÅîTb¨ÄIE#,ª5AE@‘‰w@ALZ`m6Ô]ƒÆC±Ï<±ÀHA}~…Ýɨ'§bWŒÅå½ù}$µ…ª ”Ž!A¤õ@Œ%(”Р7#/€º±—|ò³±†äOvj)À‘Œ$° ÄyDz·A¢ ²©€D‰(…B¨ ó÷E>A×óÕëX4¯ž6Y7OmwM¢ f#/”bubF(´„ÌèyCó?4YÐ5™á3˜Ag™OøÅ6¼zôþ¥üÔÎàÆ–ûlvAÈ[Ú>pZJ¥¤ÖðÀçÙ*üÍm5ÚFv“°ÃC$MËUÚèˆñt»¼îõÖë‰ùHÓF Á0cKOxÔÌnÉ©]!ýšp#/2ŒÃZ}G‡ý%R¨,¤³N ¢2M«O‘BPZÿ L–ڽϰÜtvc¦#5vbz"‰ù'‘êÔ/#/¦gyêA¼™Â ¯1>¸ìFâˆTWlüÕAœv÷ª ¹FEÆ"€HRD'º†˜ˆ¬¢#,‘#,“˜C¼"XSò#5â`yÓ`ì~ø#…¾Þ¨$ ¼Bﺌí§Pðþ>ödu½ê`B#’4”„§è¶¿nU°››¢ ’‚'ÐoÔ‡®Bx|úŸ¨WÓ—Jö•À."Š5'á±½}å™ÍP9JH”(˜ oÓì#MøÍõ-›¨6œh–Ã%wúÌ°:wýf79 ÕÓ¤’•*ø˜“c¥L°º†Ä@ûÐg¡Ð¢‡\ææiÆ`Ïz\·^è!ö!£[$f”§4XBKš LÈ­*­`&Y4n"Z}_$?/‚x*»ý»Û–&ào÷#/¼h‡¼Hba !ðd;¬_/Q­}h7Êúæ "/:ÜÏxð±Ö/Ë×ÆmàÛ™UT`ûäsž“»¼Ñ6]Y3PµŸÍ{4ÂÖšüÍ—èª;VÊBÝE‹–e0à:ûv„r¨Ã`Ð4#/'8eF©j¬qÛE¤¦‹„b±"À,q­Á#/#+Lé m-0f“Q2ÃìgrI §!Žú²Ù.¼æL;ëúµ HùƒNU”kbf CÕǯFsSÖçØ·÷R'¶ Kâv+Š`Ç”7±={9 lßGf-2>ú#¾Ýº‹xãˆZÞÂœ¡¨x‘ª†¯n¼ÇŸ‘ÞS¿eµI™Îé•|>Ÿõª·ò:lÊP#5Á.ƒÛ^)¥àIò z nÙp£¦ÓLMñéfÿÍß fæ‡ôl‚¥Þ5©^‡.ØÝJud„&ó#5!„3@8‡ )ùÔPhȘz#/QO@'»1ÔÃk:#/Âs>ø;ÁóÊõYZ”*€ðo†vfƒa‘UAÉðìêêÝž@JŸÏ8EuBåœs¦cÈÅš.oŽA°Mı Ô@i©Øp› n"õ¥R¡Û¯†VàeA‰Ð`T#š…pÿîöÔÀ¹@±~“K?¹’|v‘=•ýÞÐ0 Õ iL$DXªÝ–Y„´Œ` Ðò(ôêó®4 m¸¬žÝÍ#5hñ(>ú©¿Ñ1ðm§Ž#/?­üì9óœMI#5BHj¿ŸæÖÃ}_¹5}J#/~‡Ê­ÈÑ­¼šÒnD„ÄF‘ï’FrÙš»“…@ä7®ÇÍ<Ãó‡*„óÙµÉVÓee¿vÂvøxw$NIYúðñð›|h“"Øê½'¯dÐ<õCrÆXµÁ !߈h!2ocnÛìüÞZqpÂD¡ñ·=ØØ–ad1äm”" ¢#,™O2åkp´Î`ì ÒS¾ctà|]ËLõ¦ýW“„ 9Ñ1☖òFqexèô¤@îŽ?fëUÐÒáa¬';ôß¼tN*©&d8œ³ÇFÞ#/­bá=‚u³ž»YfŽ–¡˜ö:Ux1°ì¨HI$«6]ÇÖÂ0á|XBm™a¬Œ3¥|HM®JQ…8åÔæ,ãW7æï÷l—ÆŸÒÐ È9þ¹10H¤%¤"±Dô©ü‰¥a|> _éUƒw¸ˆŠ’H0ˆ²»KUÕ#/ŠŸ+›ägØ~Z}/¥0#/´Mê:·²1ƒÈ4=çÙ‡ä=éÙ.¢ý<ÍÌ4-à˜›Pr<ÎœD1Ûômz»¼Ì-¼¿jö¹ùäqò â admæC\ÕjÌ0¶ØÕ¬Õ­-K‡T\c#ç ŠÁ^%Š¤â#5šI#5–jwáx<ÖCí3ôƒhÇÕlº‰µ&W±Í-þž˜Å7AãÚo@Œ4œPCr‘†A)FP%DE!] þO¯*܆áĬé¼~žøÞÒ¿«·×½m™ Où¡TŠ´ÛÀ¤ê@>Í]`É÷*çÀt[6¸œpbZõõò`¡RÚ¡oB7‹#/]}Ùœf‰ <ŽF[CؘÀ€UUFëa…ß`}¦ì¥‘÷œ(–Æ®-Š ,HÀZÚÈ}x& ¢B·º²#/"PÔ³ÒäÃîË£©t3ìµ¢‘H";r÷ý{à~SH«ë¸î­ËmÜýû­RQ¬c[eRšVjlX–­*@B,êݲÀnxR…÷!ÄÄ ;òøô#5ŸKD‚R‘H(EÝ»ðå4Ó·ùo<ÀdRlÌÈËI&Â#/4”$¦Ä¡´ÊÃ%A²ÊšKHÓ"BÊ”©d)k÷s`Z#,Ç14t„ƒ¬GJf:Óc¡Îž©ËQ¦éá‡uáuž9Î.*v3#/&È„m1¨Œá˜A®¯ ´Ái¯%Q÷:¬Ë+Wwiå#Z¼tÃ+*qÝðif¤ž¸gè,LkzHÅâ ŠËÄ8öŽ \@ !ÞõóŸ)ãI³Ùœ¢»Bº@صYt+t'a¦˜¶@qÇ(£#”T‰¹ù&@b8˜ŽCq£â\Z.=ÛÏxÎ:oS,¢j¶†­õ¢²ö ߎ ÁÒägb5¥œÌ< 1wqáÇ&”¢òDd$‡(íõc_“#ã1ïQkR3„†ð×4V5ý ãÏóOíY;Ô1ZäI ¤þ4DF@ÂÕm¨¬‰–ÁºÆÄ#/24A#I`‚mŠ¶ CbH†Rg~¶®©\º«–›®Õ&·g%Í%æÊJ6Ć˜‰Å²´1¬™p.¶c6ÑŒ‹V#5ÀZ€;nR¡.Ñr!E’ŽË%#,æ8²¢ÚÔf?Ê#,*Â@c 3W¹“n].jw[¥¶Ûu{õ#/'·„ØÌÓšQŒAÌ<ë#,B™‘„#5ÅÓ#,{¨ãZm§ìU+qؼñA¬ ËÉXc)ÿ¼0Çðø›ÀÂB?'Yã ]5Ý]Ñ£È<ØüâWð/#5ŽÑ@Wjš2¥aeŽ(h¤b‚lt¬‡âÚlš(± ³\8l¨´›M ¢¼m¯smžæ-Ë·q‘Jr‰HÄÁ¸¢U =›y#iGM(ÚE¥ “š„qd ¾Dƒ,DCtF“X8¢‰Ë#QI_S³=Ok­{ïÃÂ%{Ž¸M- 6:7&Œ¡+…U§Kd2³ämbB¸ˆX°N5R+%"{2€±d+ 31ÆÒÆ6C ë ˜`ÃRtn(”¥#…IB=$yÔ*`ÝɳcšÖo(žjïzÝŠf;P˜›dÛ.ñæijæfyPŽ"eMž¡²X”™um[¸£ ‘Ƭ•¼#5Õds"X,#ËŒ£2†5€õˆß`ښÊÉïëñk†èh1ÐGC7DAŒj3l3 ™YÚ¨8‡¨Ñ#/j,Œ•Å‘ƒŒoÎàÃR féŒlñ­Y‚n(ë9·4TÖ€5#57× d.vt<Ô`¤yªŽŠ± á´¬f#/ôœ²j4œjŒ#/ ‚b¢Ý#5f“E³(È’Šɦ“bóLÛãÆMœcHB^»>hƒÛqËÙØÚ0‹£X>¥i °Nm(ÐvÖ­$äE‰l2ê’[BÜÁšf‰”,˜D„i4ÀND™…”’$119#,ƒ(`Pè…¤Œä¡¬GäV:Xi°Ç“Fµ}#,Œéáˆcm˜â¢6„˜&0‰ ‚hT‚"m#/,)^ª§FJ&ô{Xg&ÃAÏk´cG6»L~´c´¢¼A*u6(Ì&BÖ-#/4©ªcl[ÈËn“±1›g­M#m>Jash(Ë°Öšû¡ìbÂ…täDT×çѤpìEÐÄUHOID6<¥´ yÃpß4t=(·YeºU$â9¶H|“m'#,÷:hÜF [s(€Ùؘ;0fȈ„i-Æø*@Á’ä4!B†ÐQ bJŠ£"¤Á€4l`Ñö’È^)"¢à4fŸj´ÉÌéÜ‘iì%0±ý­*’ñ…*åM±“w½-åÝ›¤öñºë•ê¼^Mß]öWà´bƒkFª Qd`‘‹!GQ#5Õ?÷w#,YCüBd¼1#,.&ˆOϺýP6” $-Ù#,.vâ¢ê~Oæ2Æ÷¹E@_3#5#/(žª(ÔúˆBŠ2 ¨nÊH B"ˆÈ¢DŒ‹Fhƒ¸Š,™—±î B'¸¢´A9^çHä;æy{ìmò¡# BäR”Ÿ–Ÿ“Å!KFúÃyhÁ…ˆ7wRƒNçÖ‡uדù«xõÅœëcn®®š—¤ *©’Ásj‹G½%Ú¹™‚⋱‚†ótRSRHCö)gœ€víRK†æ¦ì·È˜Ê‰#/0ã§-™÷2cºþo£PDS{n)¥®åÙÞZƸK‘Þ¸k©ô¸–—à!ôÒ`6ùáw/hæÌŒGê]!¯Ú瘙Ií.À±œöÆ6AÈ¿x_Né‚!›Þq; þ°þH®­HD™¹§F*·;2“è×À “¿òyg©‰±!ê"^¸«gŸUݾÌõt48Y©/#/Ðý‡´HÆ"“L(òpDèE‘‚2%tù§`˜†Y‡¼ß{OGºÔwËRÃ*ãmTXÏêúçÖët©²å\T*#,›˜;Š5ÚkíÈ7–9”O.¢|ÂÀø`J¡Ù•[Y Ã¬Ã"ÜÎóh˜…²FbÁ"©TûY‚@ÀhZ¨ÑžæƒSé~'éãÅc«5nZUI'(i¶(°¦0%$Ù«âoƒ}Ì6À—r¾âçöåQB TÜ@´C!Uþ5A”ª¦t ÊKQ¶˜—VÅ×[ ÖOW4mðæ·_n›kžWbW¯®[kÇ5sh£xÜÖï;ZÅɵ!Ín•k`[%²BØ  KVØ#/ép¦Ýýæ·^ud®îå5\¯WÂ’,b#Hƒ¼aN@ð{4TÂØ8¦"|@º\GØ™ûƒÐb·²4c@IŠ¢å#,GÄŠÚ Ò#,z@÷?Ë€âEK´±ƒ»»omWÇ$ñ4§ƒ¾P¯Î!ÌSÎ)JÐ#—å?q @>úà…%Xù)Ô‰‚n"ÈUElïµ”×%­Ù¥®ãm×w#5ì¶tXîï.áB¶—T€§‚%€ÄÑ„pZÅj-¶´–¶íj&Úº„Y$#5j¤K6V#5˜vÉÄÂØ‘DNDQƒ$VHATˆ} #,Í#,t”¯ý¥Põ*†¿š£¥'U÷ÕOF¾áãA°GÞB&Çq–º¾ —ˆ#5©˜½¸³Àô¨!ÜzM‰X=ˆ`¿YÌÅéô”H'J^‡·`dÅï‚„:>B¹bEc„dR@²l¥14Øщ¡³-3DÊJI‰±´2¶ÑV¶Å¶ÅV›J¦U*Å©­cXÚf¢Í^hû‡Ÿik’2µ™¶@ Ð91‚•È‘>ü)pM#/1¨<¡–‘²1HEéd%T°5˜«ÊAh GGŒXÝ"˜W#5)`#/ƒeldE‘¡È1’T:„¨UFÁ‚44D"22*T ­Œ#,„•æfi–L"Ä'Ïõåkª&ô%¡ŠY¥¥Ý;7 ëO®׽^ùPD AF• B c#5FÖ‡h.*W N0é°^ËÅ6¦´“ÝshhyöKkÎ#/«EU)¥^ }#,1 ’´6ÃÃÛ±”!77´qÊà)…2u—ðm:;9øtM­`,Å#5ÎY!‹VF@A1ÄÞ©µ-Ö$<8k”bHµ›†µ’Âe.#,óm“Æááçç$¿Fb‰{¤£Žõç—]5ÕæÒåLÌßrý•ßÛ•F­¨ÛU\Õ\Ö»½¦©+ãkÝìÕÕààØç÷AÊ.qþY ”D³Úû°¹bVUÒã6±dš¤X|?f¸èmŽ8ÖAŒâ凔´}cï€r×BüÎÜâ'óÄË͸=÷PnÝO12R_áë'¸¯òvÛ¸‘´ÖâËϯ¿¶o.‘”‘ ï×eu¨={¬çpïÍl’×iõÜ“ÅÆ;ç:Ý7OKt Œk/ÑÂ)áÎ…-™Š—ÛÉ[ž/}‘äEð„/,L'ü©r‡B¤òŒ‹ôèþ©ºó’9·å]¸tMÐߊkåGW¨tYAÑ3Ï[”5ÑlJèÚ‡ÜEúy»F]Î×!Ý»®éŸÂ%#,âÅÃWN-¿b2 ÖtóßtU°uĶCŒ¯LÕK7ZXn®?“êv¹#,:°éÙN-Q“6ç¶<”h•Ò䮚ž¥°Ïå0¼‡99{ÃV48ŽŽÙ=4å²γÑ|=ÍÍvLç”ù·:8D§Èãwwj%™ ]N•æøkµŒa‚Ñnt{òƒu^9{’×F娄ǟ¥IÔ?9 ~\³½¶Í•Dã숭lÃ>7éŽÌʲéßá*ÔpDÝ5¿]NuD¤¨€ßTSLœEHˆE’æêßmyžú,[¯·ýxvvb–)ªÞWƒÕÛbOãdéb€ºL(«D”Ž—2ùÿS°wÈ´;¿®K×Oy7ËcÒ›c¢P4áÑ*“m…™¨W•Ï’’”ÇÊq[Û¾kÚwy@ûcoÍÑñð{ÃTã¢Ó<#1܇Ä÷Q'wbâü@ë¾½ìâ±ÊŽ¦u~HŠŠÉR×Þù*W˜çO•vé5Ó>ü¤#”F#5wÁTÀá öª'¤ÇRNÐú³†ºÐìÌ rldã5·îù<…ŽeÍëS’]žú=ÃñôÂ3«¦gÂH:&f#|8ßJÙjZœÊJÉÏËÇv0„! ³uŽ‹Šxéǘ!ÝÑÌ®ZœÕQ…sãšQ!Ô8s’„;È+Äu5LÆldR-ߧXRpËf‘(%¸t&!Hìj@"¢ˆÌkè/Nâ~’Ó#núž‰±gëFpðægž&˜Ý»áAÄÈéÐrúçü¾Õ´Ïq©6ºð?qä—™%bLn8ƒY|)®Ø¨ñ¬D¡ÙºøvKxdÍB—3¦zÛàMæ,4C^æ£ÜR£oä~‘¬—2_&O”O¼û˜¬àsÎÁÐç©7ï}ðkÄcŠvòÓ—#³ùônš8ü­øщH…Ë»<|:Ѫí`ƒ¬ºê‡ïD[¿e1›Ú\š»÷Æʤӱﳷ Üì.u«#ÑŸ^$àU†|£3ŸH%LôG›È´­$‰PúžÔªï¢sÇ,¤Ñlu;tm_8Ûð'äésâ]«1Çú`Ü©G„Aï‡#5ë?­å#­ðv(+t>Tú=õ®¾½<ö Aïäx @€2#5Õ‡¦æ¦&Gcª'!c–#/·Xäe“j•¦#/»•*Ô•©ò<óXœªG­_qû”4b8ì;z‹=AÀ~xHôj „qDÃ1#/*Î’v6˜±)‘){¬o¡xÑÇlè4gwò `¨äsÑ—ÅÏ•8Õ…•LbYˆØ-Á\/ILIUãœ)–Íd›mÀ9ÃmRº½Ã”(•‚YãJ^X*'¯$ÂõtÖþx“%S4!2Bð2Їs½le!ÒŠš #+‡—`“3‰—…ÚÊÂ\ºê!l2  ñ9’F£w»PW ¨ÞdÐÏa!HØ6Žã}i*ÔìÍ®“,Ìj]Š¹vmH+‘´¨óËnûd¥lrË-–¼œEŠ¡¹g2PÅj] Aò™–t#, )zè)É(— #5ˆF#,B(D[ðÄÑdÛ«…vmìdz²ÓÄ€îÐèRÏF‘,¨NHéÄÃ-òIÓ ®·@#/Ð3@Ë(ÈOœÔuç öÐÎ>± 9A%A‡š\=ZïëÅ?š•|4G°ª(="…LˆŽÈ»CÏ=Gš/¿ôK¾Ãßž<‡>7p%RÞh¥CÙL²s;Iî‡û‡H)Y.$gá„FÛ\ám°ØÌ>òùÓœ>O룦z“Ò»¢ãÕP{ƒ÷ó´‡M9ëµÉjj?Þ/£#/Û¿·k­¬„7U¨òƒ¹òwF‘®û³e1¶ˆÃw¿1¥6 X'#,Ä öJÇÄ·–Ûu¥¤kL9w*ûGnô |Pz iló0;®8~k¸óé¿F‹„ds$.j¦¸–S½£$2*!‘„’×S’Ú–3o`b‰#4@öæR÷àƒ ý8Dæ‚šyvvã˜b;8=qÀIzÓ¾.TéhünøÉÖáÆA¨Ò¦¼µØÖØq<3Gá¥:¸†ÀùŒ‘éÓM^áO•õÙK»p| 9#/š5ÞUš˜¡ª æË#5ïh*ÆN5²Qu}X5EG’ma¼°áÂÙeœ"5#/ƒ‹â¾—PAÍþüÆ8ýNœµ)é FT³†o—AÓ§\pµ Sh%¨ÔVÕ*ÉRXs›)ºÖfÌVjró¼ÊŒÌ•ÙË|¼ðL’vïlÇÉÀ´*C‚üô_ÊÇm PýX ¨ñÈ=À;ֈ缹e!M,à-²7‡R3±Áíu²œó3Îe²¸‡žy@ó((̈Æg„Py {»–ʤj®¡PÐׂ%öà˜Ì:f,øÒ­&CcÑ®d¥”Ò†#/¶…&„BÂ\ØH©½Ö–²›N,a$ß¾Mnô!Ìà:§ ØŒ ;$7„Ãj¬‘0çËì~€è®ÚòÔjxïédj†l#/~¿¯T~?"úµ¬%š—ò>œä=ÆòLo2±5!£À*€”‚}î·‰“¥D*Òs¬ðf…Ò³½1±fs“W‡D<=Áî^ÒØÈ÷¥£HQU:@ÐZX°æCV‹FѱD»¬ëw*I0 65'mû_±okV-ç–ºÕC0x5EÐØÑ¡Æ”£tZJ²F08ä àD¦@«fÞ­QA¬kšâsmͨõvíœiêGy£YUSq"T'†+·AêB¸`daL‹šbBÌQVd²ÕŒ{†±&0dUC¥›ÌwÓ6Î=>rFža†ßFv¶´O9×"}ª(ÙZ]›`Ú@ÚUÆ#¡DÐj¥†#2Yj2ZÝL3^‡võEÞ““')Œc !b3ä+•„nãËÃxºÍKÌÊ#c7ƒ´lÜA£A¶lȱÖ6¹¬5©Ñ™¼I¹s{)FÛmbm¥jZ#/µH›j¼0‹$ÍË_¦÷u®Œ½ÉÄ*qÔŠwœ#5Fu(3»ãƈŒ)a)ÓpM,(PÊ ©ÓcåƒfHÃSKÅ2¤Ô1wÌ¢ˆxpk3Žâ †iYŽ.Ílo! —R¤Æ±¶–ˆ@Óê+\ФIÛR¶Â7vÕÛmá¦oĨ#/)Âl¤‡æÂ41‰ïlñBMÐÑ¡ƒ[:JÓ6Ôj©je*Š¢…Xa†ñ“LV1·š‹.„ËÛ—KG]ÈŒ3…Ek©Š´š˜:¶†›¤†@aú°wmݳ hq²iƒ2òÈ ¶ûiæqõ<âñ˵aQÓèÃÙ”~n¡£UJ5™b´à£„Bc9GpáF2›¦ Q½åƒUƒ#cDÇF2#/BØR…hl;™1F%Ž´c4-]Fi¶pÂyë+`æ­z¥W¦dpìT¤ŠçaÌá“#jP˲ÆÔ£„rªÛ°ê ƒÐÖ?„… ­GÒ¦fn*£âjˆ‘ˆR-yZ«Œzp§m¥W—”\8@s¹eÇ-:1ês[u¡ñ­½,-™J`qšu6¾i¶Œ.òaZ³ JF™áÜ$go$®Öi‘Ôàè-2“FHÄFK3º*ÁÁ…ÓŒ»!^ž5¤E¤ŸIPÁQ®úµo´#/:Žp0ãG 0%2ÈÛ¾ÂlDqJs;¤*õÇŽ§åó„}+?_èX~×;ˆÒh©4n>õæóξw·¶zê_Ð×ÒŒ3+Ѧ#,B6i±J>°X"B“´*Q)#5UHkø¥2Iâû=µ(Òe!ߧeS¾¬gy­[€i T¦2Û³÷œŠ $UUFJ2ßê*{ÑŸñ/PèEÏó+ÚIŸCªšc‰jó=¾¸CÉûÀþ^°æ‹ëA"qm!–·JÍÈÍPƒ€ñÂ@A²ûµï¿JÙ&a28÷bÍ„Ú[Ýøš§Õ„zÞlº… uq–ÐúðöîF›ºNîäÈ!ݽx÷õ5¼i]tjaQp%-T¨Á³È3=‹g›ÝÆuë2‡^Ð÷¢? ;Q<ÍùT¡“ŒHQˆ á6o-ÕA#ôÏË9ž½Â(Vk{–±´à‘À]‰LÎÈ€ôRƒQ‘a#,X°Aˆ¯)¶¹µ«¦ñ­kË«¶¹¥R«ÍpÝüSòEæE?Aß×ß(Ò}ü$$ŒcPÙQ²’¶Ñ­(ÔF$ØQRRa¶¦VË2j’Ù¦ÅZÆÍ)*‰-&6fdÉ¥–Å)HÊZiR”fJˆ¡Šm¢l”li²Rš,Ô©¥h5"É› 0Œš2[V1­­üëßÒ¿%Þ‰‚ ñÀö¼«hâ/¶%¸PyòŒå¸ûæåteÌÄóÜýOÐ×ó°›ü\÷Õêî¶Ï\ÚD‡ÆsVÑ|’aAdƒpp½ïj–«U¬ZÊ#/5ÂþGŸ§Ç4AóÙÔo³Dó.F#5ä´v‚~Y»zOg†ƒƒM#55n’öÄ 5/öî„ð )"‚‹¬kI­}æÕ®[1¬)4H)-A›_r]¡j•BÅ#5PÅFR>´²eÏ€`'qxå!BŒ*O·Û˜\3W@Ëd}ö^¿°¸j@j" þ˜QjxoCŸŽ]+L"k¦VºŠŒ èËRûŽQÌE4\#/4‹¡w›¢eÙ“$ÂXÃ#,4Ž±w$Âl&‡…1H ªÏmM–ê”$ÅP* ÖXj%í%†¥ñÝ›&õÙcßÍÕõÍz“zÑmF:š¢¬´ò½¥*KHÆ‘#55Q’¥Ñ#5E#,ï8ã'áí5§æá ÙòÅ6FK^΃ҺâP{7¿g_©y»Þ-FÞ­»"’bTi²ƒYDqbÊÿÙÒÈlÐ.g›.j˜R´4•/ ¦d£$1A€`½Qˆ<,1‚:5$m|Ú¬ 8tˆDn`*LCq-ä "I$‘ÁPÙ·‡dœÐʨg˜b¥(¡˜HѨ€7$Ç¡æi;¼ÄMó­#/é\W‡_78ÏÚ•×(,ú/dî"B_òá6ø0 hú½*s¬añ²‰ª£-n]MµA}êÂRЗ0 úT%Ý|È#,ñ‚¿ ¡p˜{ ÄW(4ôçèþ·Œªôn%Ô¢•[«xc%Ö~~>O–ºèjIÛ:ãØ?‘ëSQž‹ñ*ûó)¤ÒÂ:#Êse·ö˜#Ø8…ïúèbáöôaç¦~ÉäX2ŸaÌÈWJñÆÓ­Œz™TZ™ÎÚäÉ64.Œ#51B}©%÷s]kÉ^vœƒ-¾ßaî°i«Ð=v²¾´äœ­r4ié>4"’§< f׸‘©"ø5,:ã»;í˶LÏgÕ&åØ›>f;}J`8§²$DW‘ë5êOñšØ§¦#/‡÷œËEŽç`VŽ@)2g³š Ú611ÿ}XwÄh7!€ì#QýÿTÄ7vuI¨™3>Þ_b7Olbwr>^þ‘BIDI(€Š%çìBöÕ(´jtû´íƒ }'‘n,,)Ÿ¿.¾¯ÏD~ìèGëì~Ç­n~MLáØÎôFB«¦‹ PÆ,+rc¹`Ã6'^ž]hlÅ0ÔU÷¡ƒÑËqQ$îö¡š©*}_m[îÃx`¾fo\e#/1IqˆoÁÚkö‰¼¤þB%„Ž¹°ÙW*Y5ÔX6Gîg|¢ƒ]82¿’Ü1´„–‘™Ÿèw»Þ:*DôyG7p‘l¹ 9R%T:­+ŠŽ\~q5Œæg”à§FÔ²4Ã0ÖÚbj„‚"Bl3Æ 2&#,¤LífÚŸÔZV’ÐÈúˆ¨ª) Ìú—l!Ã4ÈvWº«²™º"¨ih±bE `BFÈ„TIx6;8ØÓâ„Gx£½¡Èk™¡¤’9É¢K7PeÌÓ=™Ø#,˳RƘÈ­h¦RĹ”6ºsÐÙLv‘ƒª³”¬A‡8¦Më¥×'“&èy¶ ÃD…ˆ³Z(`€nQ©ê?i˜` `‚PÈÄ̃Þ"¸7§VŽ¨hͤ•B[ÊBÒ£SÈ4,U±M‚FÌÝîãø¥‘Y-…mÃs=rkš†™Ü±Qš ²dãg[YšÔE`؈‚Ù™ƒNcQ¨œWõúù¾¹Þ ûëgC‹èý #àSAcÕ›f&3ÖF|N.š°cðœ(F®u0ù„õ\ô€Ç;9ç5`Ž¯…í.†êiа;eÛCÀûï&:V3+»ä:ô)˜–t[½C‚;Î’Š[„.êö†5¦9Î'½‡<³‚XÐŽ8-TÑGˆ’Iº›AÊ… °4IAŠ’³#5Ð(„4Ãà˜o³Â^+Þž£ÈFÝøf´kq’Ç—á“SîÃJj—9½Ú›Ê㶠cïLé”hG“×2©á¤AkHÌŽqlcŒ°—Ó`CF”„8íîŠã ÎöêØDI"ÒÆL¨¬2‹™C4 xv´ÚMBÔrç4è…"•j‰D°Î²Òb|ErEbÝc,n#/3AÃkPÁ- A èw ƒ¦¶FH¨åJKy|2”˜LÕÙSÙÚâs\Iu`B2 ëÆÛ#/H³%@òÚ™Þju ©æ>Ír+R–fCÂÐe¶2g=×Ü×mtyBçC‘±Öi ¡f°E2Ç#,Ò7 ƒ@毧̇jXH8ºÎ.Q0tWF;bÑtç±Ócir8ŽMÒ(e#?ê‡h0._Òƒ Ì–‰Ó57“HaÊ< $t3 Sl†tÓi#,s´“Uˆ²P¢& mð±N5:þ[VÆ-ÎPd+‚¶’к0psW)„‡.˜(êã–Kiä¶ 5˜šf…PŒ`dYˆc0’“™Øïú×;ËÓð1 ¸ë\‡Zg;‰Ø0SC#,šÊ©&;XÒ){(zžpÛhK“bK¶èä&º†2Žƒö_ø6˜¶ÎS9’Ô`ôÊŒ¯ƒòö“wLôöx€51X0“Í“¹š£~G36‹ xÑ4õë~F´(ã›ky%\»}ˆGGѼ³Ñ_ k§Žp9kI©X«Ob\8W˜¬L°ˆ3‡f²á G”› ¥£íéxıu»Ú“¶¸ò• #5ÒtÚš–b¿o[£¦ À"l]D¥!Á˜¡*£ó~í¥¥÷ ƹȴš·¿¼7½NP¡Ù¨‚Ê]<ä¹nî7ƒ»åZ íû‚ï¨ò žzbŠd׎(ÍÙ1Ä0ã2ölUñ7’¼–¹¤å£^·*éÁX)ðžäŽtÂfªH›¦ -¬¸1laù¦‡@Íå1¯GYÛv"öÉ,˜;ç„ÎCÉœÉÕZÒ¾Rê41ë~¦XŸŸ•ôÎ0ÑÈ*ÐÆ»ùœ‚#FÎf;&Úlðæd#/ø´3J±v2›§œ¶/5Ê·æF*VøDtCH>4š[ï ’u,w1Œ`¢ÑÌËá¥GBmðX¿cõy­ÓŒÞ0fßE4Q«HˆPÈz!‹ªhEçAFH"¸ªPÝÖMO6÷ÜÉÂÄ;½S¤]Áõë- 2m)\g†`uns…˜®EÌv#DÌ" 3µœúQ4ºÙ"6#/KÀ2ÁÐÃDb¬HªŒbj0¦Iz©#/ÎUñO/wÉHRöYu,««DëJb(‘ÙÅ®ÿ#,Ì1aª"/eHÚ‚žhïCÀø3bi˜RœÊ»ƒÀ CiÁ¨Q Á’pìŒÆá Äaƒ¨bb_BÖŠ*EsI`dl!‚LZÐ6؈‰ ìªXò¨¦&Ý„—²z½}'Ñu”¹F TTEA³GnP]f^®¹=£`Ë*„;E„HH)¨ 5#,æE~íÿÜ[ײöUAÖs—¯}Ø* &ɸ‰U$_°. Äh”"%Q Èvøž@PÈO.Mæ31<Â+"Æ’©bP2Á8âd‚TLc`Ç4kÄÕçxKÍÝbT®[ÞëA±ä! d… È𢢌A¨5%TABJ‹J :éˆã#, >l|si(A¤:ënKßwL¹C®’dˆdÐØ&`¬R, „Nˆ{úÓ³´|û¼B|&>~šíFù ½pà‡ˆ)òáõ´Æ~嚈•Î†Ÿ×3¹FŒPp ‰R‘Ks1ŒµVDD Ð9†Y~И]ÄcaS&¾¨™Jëä%„õuØ'CŸAMìM€ð iÉîŽã¡L’xØÃ)âA!ÜH‹Žû"ÌCÉ©ä±Í#,…0¿‡B°ˆX¥ àïÙϲ؂l‚H„€†a>’6LNpNþ=AÓU7ö#5‡h‚˜|>#, t"qvõl"HÐjá†Tvè®#5dÜ:cD“A‘„\r,É#/ör}°áM‹BÏÌ~eŠ0„a#¥¹#ÏK5 Nè"‚i¢1XY«:ÔEŠñd<¹饤CM"ò£¿!Ý,FÙ‡†a­4¦…ªÂšØ}C¹Ï;PÚC-¶`¯³k9NPïÃ+Zë-sŸ‘‘ƒNÉ ; Ô÷gÛl¨í­õÛ”I°6“jÀ*á,YpèhYhý[¾¸©¼ïðQãU#,E€§¹% 6Ø¢j2‹•1pA-šý–a]Z³š‹06ˆpM Nÿ¬NJJ†RS,Ûs#,Þ&àŠN|P¤¡#,ë:Ûv¬®¾`R)eZ·Ò —Aý‚«! Ó.¾™Âþd|yõl C7Y0Ó®e‰ÖpLCÍ8äP$ E`AAÀU€®ç²=|°Mß#ÆƉòõª×aÈáÐ-@ª!RÈ.B¨6#,R¼„j#5~'»èý½ø$Àce„Yˆž>ߣáQ¼æÅœ+4¢SøÑÈtx×_¢ŠRÉk ‚ß…Ãð?ɨ|>>ïo*ÌŒ>k,"˜ö{M þ3Ah„'ÿÕ·Ä–ŽoN憨m·4kÊ«@(í#,¥$HßÝE‡*oßû©hÚä¾’¿ª ÝZDúbl *|ûÇd,)À_ï€vX.Øbvòر-¸$HÈLÈÅç\¬VaI)"îåŠûžtÞh5xñ^5û’çž^o+Ï|ñM¦«´E°ÙT"6¯uÛ¨à &³KQD™ Q底6Ó6†˜@J” *pþ$Šl¢›OùÊ_w›¼½y$†@!» ¼9›Æ@eÖD«M"¦!ë5ùßHö#,õö‡ok"È,€ÁH1FItIÜ‚Œ‚HKJ“$–*eh²YfKf’m_õãc}ÍWòõô)TC™Qª4še,Òîü°IüOÈEP¨‰Ÿ²–»|Æf7Ò@,)ºî¦I#,àOØc_T½´Ý×6bldÔM¬ÚŠ*Åe¦FÒ{çžjˆ@B {(#,´D"ïŸóD-ÍA5ÿ‡‰˜uw“âú¾¸Á×Iâ¯A5ÕÁ¾Cxtœþ{ŠÊÄ "ñ½WDLp1 ÷¢ž$‹Á¥ÇŠ3˜)–S T‘²Â½´`ÏžfÆð)B°ÆÄ%—óéA¸{ù›iq¢à2 Fû˜ã†1Øž¥MÂÀËCÚXS¢yL@A|Á€A¤Ím6´”„$µÍÉ­R­)6¦Útï–¦‚ Š)sVÛ7“Tì"®J€Ø=Z”`J¦H(HöÚÃe·XOn’ãK¸Ý¨ÕZ¦µÂ} @xÉàRŽ˜ô<ýT-ÙÉiHØœý4#âì:ÆØ£"H›hx’öBVÜÛl Lµ‰Ž„À?,·ïgÍóºÒå†.[6oYhD x˜`næçü¥¿©¶ÕÕúº¾¹}¾:(52&‰RE‘¬SEŠ)(*"Ú2UB•È­úm¯5#5- ÚJ€¦§á•³ñQ –|dK,'Ü2n„ŒD*–QE1cG¢Šh™ññ5± *…¡·`'¥ïŸ\p]»% n»š ´È‚…dCDZ‚´¡¬P›i²ƒ!ƒ$`'‰µòíÌÛæÎíí¥VXjc·Õ¾>øÁW6¾¿9Ž>¢ZØ–0l³(CÝÚmwû š_©ý~C´+CaXe²œÚã-‚#"T²44x d`;ý´:`&ÍlkrÜ’•}}«•¼»¨’Ú*+|®ëÎ˱\ÚZõ©ç[[Æ£E¥™ªÏrGë6³#¸Qý¥d8$-#,Ì,&íOQÏ¢I¨u#œˆr"ĺ3Çü3AZM±¦¬M ( pÈõhX}tfò]JCñ`aÀP®%Li¾pCq5‚u‚]¶ÅaÕ%A‘B0Xs¢k”´nåÕã^o*ëIbÝš™™UÜí´Ò¦Ô¡¯{µÎV+*TÔQ±­çvךû+½¡A#,¦Ac)H&5„h`ÆÈÚ[R•¥4ËfZé·nè”Ò ‚ˆNE¡RDBNεm!‰°éžXK„=¢ºÿÛ—òà«‚Yƒg±¯¤Uòf┘4Ñ8/Ž1†aU3ç qyjI²ë²©Ùíîù"Ö/PXL*&†©J8»÷zÞìñ0lèÑcMû=#/fü…º³ìÛÕB(£Š‡"­yšëÚ%ôÉ!ô^ˆKž‰ BA¢"˜5‰#/ðè:8$ÉQ;’ý 6’_éc MæÿÀZ׎§_¬•¥Çk“Û|å†ýi‹in‘Û¦Jµ ª-ä~?Prg´š¼<ûh_cBQ‘ƒQºô0m­Têð#/(PD>›r8”š_™­ê`×L‹ãõ9ô`¢ÀŸ~úÙ¤q<–ó€’Ešôbä¡HXÜáÛ(Mˉ‚„KÆV#5vÂ9¡4k%Pm¬ýLzŒlŒ¶Œ"À×F\¢é¿HbqK÷M|§hͤ†ÉpdLT“‘=Ic0äd¸(ŒR„¥ €CJâ'#Ãg¥1üÙå—÷#ö^3À!Ç<ª„¤2îz?2P?ø>³Ê¿DÉB6 ʇr³¯y±cÞÀÉï;ݦ"ó¥jIb8h™#ߎ'\¥„Ç:-¥i#,¾e#CûaU°þ¦ŠùŠ¶Ý¿hzž­:µ9´ â(dÿj‡©†È˜2*&½5趙®õmÑ߶…ÆÆF Ú[âôv3óŒõÞäB4Db†'RÖèmI€*™‚ØB#˜BC¡â”_óÄÈé†`– ¯N—À±¤ˆçç"RÚº#,“m2hæaŒ‡/b"fg;Q‰¬ãÛ¬˜‚ö ¬;h-Oî5z¼ìw™hiìºâˆ¤ýØA´ ¨cñ¯Ž+qÎz)\ X¡7 uâÆtù–‚ åþ%)`aá<‘êz¢¾*~LÌÁù]ü7¼žÜ4Ò÷̺‹DSo·\-baúâ.èg_îþ_áò~øÿ»ýÿîÿ»þͶ¿þ^Ïû7¿ÿ‡þ¼?ãþ_÷}ÿþ¹~ÿü<¿ŸüÿúßÿWûçÿ<ßønëÿ—§ðéŸþ?ùYýÿ÷ÿûÿ‡§þ{>ð³þ_ñïÿ‡øËÿχåÍÿøÿËþîÿ¯Ü~O÷þÿ¿7ßùéñ87ÝõõvŸù]†‡ô‡õ«b"jy6Å5M…\?Ð9ßJ<˜«î°B U!œpEÝ!#ZûW‘nóøwïi|§ñyÎî™$Š¢1Œy„ô2IRC²Šl`†éÝG¹¯(Ay4Ú!®z©¨§#,˜6Ç3ø]þꥂƒÜ?îßžÔÓi˜\Ùp–êx†ëqFï„_÷TK´,ã5(„æ)A@µ|nÌ&8ãt§00ÀQa×úèS<šßSÌÿxÿ/ûÞÒÊ?÷yšz6¦ÌÖÐèQþmIŒ‰ôŠ‚Å ºI'ˆÈeŒÌ ¯I?ôÍ@œIÀÜq¿ ÿ•ieqÖ&!3"…2*×r­göòì {­0ªB Ü”Ï&QFišÈ4).¨±ƒ—Y/$³ýùã’ìç1UjUø¦‘2ðÍD)(»p®ýq¡X0š+šANL1#/(=í8C(hškT˜mѤÝEpq1›ˆŒZæá–°ÛÖÓF˜›H†CÄ#/ÿeÉV×#/(k†â¯ÙæIJƒˆ”iåÅÓ%KK¦#/¡²°(R°™ÍŽÆo®'?ì&#/ôçÌö~¨]1ì¾3.ÊbVæ.Èœ¼Óò™àƲÌÌ5¡‘Þø(ÛÚ¿¤—^Íár#%µíÒsVoîÀUÓØÃy…I9óovÿy–#Ûî h1‡¢ #eëÛ³¶5c+KMoÎÃX`­±Œ9¤ž$½CÛ#/V¡¶çB¡<)aó¯´×»á¸ F¼6 ».ˆ¥ÔÏ×·*•ØŘ/S8òÒ`y±3DEa éŠHÎûs#1ïÎËXÍ¡&Hc|·E!Š†Q‹{ňPÑ~––2© E$€¨šy‘¨§J'\3Z€#,À’1-î ü ‰bfi¾ØX(/Õa狸1ågi±ZÒ#‘»#Rý^¼<À¦S ‚ˆ‹ ËJ%B…ATZ²”ʶJÒkL”²C`ÆÊú]ªå#,2Ê€qS#,™?Þ@2ˆÈÁ?ß&<*›(«yÁ-‹'3Ù( %ÂT@¥b(yóúCèïGU¤?ê‘Œ‰ yNð`ò54±Í%2gúF„c!t§“ì#5„Âdx‡‰útttþó‰,¤TG3‡ êú¥#5%±œsøâÓoæ0Ï{BŸûdk»:uNô§VÇë*K~¯xÆ=%ȼ©¾=Í©ò°ööpcõ•]*Se`nL2\aÓs.® #^áÆÙ²Ñ>Ê,7Ÿt›Qyä>–*m4ØšÙîá=(Ýá{.eoÆD'4Š°‡TCVzI”D%%Ý€-W­nm¥•´¥ëk^·ÂÕ}Ëã­IQTZ“D³hŒÆ#/1(мf±Ó¬"5Ýa+O(~^“ÒõÃñ¢ K‡?ìÄø KÔiµ @r19Nac#56œìÁäK–*%*¸”øóèI}0í$&PšÕk##=”´î#5'¯òŸe»".hp ÒH²!!7’æE Ðö‡qFO$v£“íà'‡ŒÿØ ¸zäj*„bECkµÇf•„”ÕË›­«%jF¸jûr¼Ûo%Wؽh›53_•ZüÈ£h€#,ˆäw·Ïá™åóÿ×Ö‚w!=~¨©ãå(ø{f8ò0m¶ÖŸŒx;.‰x§ª#/gȤòû?ñÿ¡EB§ýZþvÌÌ#/l‚Å'ù< Ué6áæçûÔU'ý]¿Å¨£Sõ#/ J®ýá—Ò>ý{pæWi.ò#/¹ÿÜZXßæ§wú¿ì†¯SüþÓúùµµ™ù#¥l³·¢1¡¨zeë¢×Ç¥vñ‰’©œ~®yËAƒSù>¶ÉÓ¶ˆÄÆVJsøzK„pYkϼ#Dâ¢ZÍÆ! ^G¿§,ÀŠÃ$ Œ}ûYOÎÏužº6³8•È'ÇõçÙL*Ï«Ï£o3¸žÍ~ŸWüÕ‘àRsŒâ;Ó¹j¬b/È5Y_ç²V7Ä|¤É{~¯ÿþ.äŠp¡ Ú‹ê– -#<== -#-----BEGIN PGP SIGNATURE-----\nVersion: GnuPG v2\n\niQIcBAABCgAGBQJWpU3oAAoJEGelZe39+Q5kv04P/iyvALGAg2Z8oICEDjFkEXWW\nh2CMGLItAhqb3xNeV8WUMMpY4MbRRpN6cU/SPmt+as4oVn2pozca93eWD7yOxukK\n10seOyLTBamS0Wf+BNr6jYXZRQ2N7inc2p6AD75pMOFSg2HeIeQJ0aUIAxNeeojZ\nmUiLYMdtcrF1Kh7KWZAkYSbIAEjJeobLqk2oY7UyqKcODc4RtZJV1InnO4DItEWD\nnd3F5kkVMw4pwYAXaikmCXYBKHXdF5w82KxqEjrAWSoULipX0BVCsSbQ2L0UOs5h\nKXUS4M7AaYKyCcO17E7CnVXaW+vOVyGEECxtSaExWgK5MvYHIGE1OFvb12PkUvUY\nc7CiBxk6X5eZkPyxgxDj20r8zNQVGZ8jDI8Wg08yTAl8+09qCtkE8gGMdNeHYwX8\n2xDH+A3+19022ZZdyO2t5+2AzU6Kkl1qTPKaXJWFRtr8ApD45Y4D3/GAsTNqdOMi\nWeh1XvqQdHjm9rEoJX8aBXShzCMCNhmZalbUhrdzQY6/hnl0PqnlPtyvtkjCvWoF\nXLF6q8YV/ZtqCc36vePZ6lpUQB6FG3g6fhMGraT2VOmT3TROcG17pqIz5y9+85xy\nVSaDc82uHlyzIsZ7vuhV6d9x4yXnFkjMAogCJv6mitFbQsd+LtXYkU+2Zq6wOoEp\ndLLfK0Km4Vs9FYAUbuUi\n=7D7V\n-----END PGP SIGNATURE-----\n diff --git a/gomspace/libcsp/wscript b/gomspace/libcsp/wscript deleted file mode 100644 index 7b9cbdba..00000000 --- a/gomspace/libcsp/wscript +++ /dev/null @@ -1,346 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 - -# Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -# Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -# Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import os - -APPNAME = 'libcsp' -VERSION = '1.5' - -top = '.' -out = 'build' - -def options(ctx): - # Load GCC options - ctx.load('gcc') - - ctx.add_option('--toolchain', default=None, help='Set toolchain prefix') - - # Set libcsp options - gr = ctx.add_option_group('libcsp options') - gr.add_option('--includes', default='', help='Add additional include paths. Separate with comma') - gr.add_option('--install-csp', action='store_true', help='Installs CSP headers and lib') - - gr.add_option('--disable-output', action='store_true', help='Disable CSP output') - gr.add_option('--disable-stlib', action='store_true', help='Build objects only') - gr.add_option('--enable-rdp', action='store_true', help='Enable RDP support') - gr.add_option('--enable-qos', action='store_true', help='Enable Quality of Service support') - gr.add_option('--enable-promisc', action='store_true', help='Enable promiscuous mode support') - gr.add_option('--enable-crc32', action='store_true', help='Enable CRC32 support') - gr.add_option('--enable-hmac', action='store_true', help='Enable HMAC-SHA1 support') - gr.add_option('--enable-xtea', action='store_true', help='Enable XTEA support') - gr.add_option('--enable-bindings', action='store_true', help='Enable Python bindings') - gr.add_option('--enable-python3-bindings', action='store_true', help='Enable Python3 bindings') - gr.add_option('--enable-examples', action='store_true', help='Enable examples') - gr.add_option('--enable-dedup', action='store_true', help='Enable packet deduplicator') - - # Interfaces - gr.add_option('--enable-if-i2c', action='store_true', help='Enable I2C interface') - gr.add_option('--enable-if-kiss', action='store_true', help='Enable KISS/RS.232 interface') - gr.add_option('--enable-if-can', action='store_true', help='Enable CAN interface') - gr.add_option('--enable-if-zmqhub', action='store_true', help='Enable ZMQHUB interface') - - # Drivers - gr.add_option('--enable-can-socketcan', action='store_true', help='Enable Linux socketcan driver') - gr.add_option('--with-driver-usart', default=None, metavar='DRIVER', help='Build USART driver. [windows, linux, None]') - - # OS - gr.add_option('--with-os', metavar='OS', default='posix', help='Set operating system. Must be either \'posix\', \'macosx\', \'windows\' or \'freertos\'') - gr.add_option('--enable-init-shutdown', action='store_true', help='Use init system commands for shutdown/reboot') - - # Options - gr.add_option('--with-rdp-max-window', metavar='SIZE', type=int, default=20, help='Set maximum window size for RDP') - gr.add_option('--with-max-bind-port', metavar='PORT', type=int, default=31, help='Set maximum bindable port') - gr.add_option('--with-max-connections', metavar='COUNT', type=int, default=10, help='Set maximum number of concurrent connections') - gr.add_option('--with-conn-queue-length', metavar='SIZE', type=int, default=100, help='Set maximum number of packets in queue for a connection') - gr.add_option('--with-router-queue-length', metavar='SIZE', type=int, default=10, help='Set maximum number of packets to be queued at the input of the router') - gr.add_option('--with-padding', metavar='BYTES', type=int, default=8, help='Set padding bytes before packet length field') - gr.add_option('--with-loglevel', metavar='LEVEL', default='debug', help='Set minimum compile time log level. Must be one of \'error\', \'warn\', \'info\' or \'debug\'') - gr.add_option('--with-rtable', metavar='TABLE', default='static', help='Set routing table type') - gr.add_option('--with-connection-so', metavar='CSP_SO', type=int, default='0x0000', help='Set outgoing connection socket options, see csp.h for valid values') - gr.add_option('--with-bufalign', metavar='BYTES', type=int, help='Set buffer alignment') - -def configure(ctx): - # Validate OS - if not ctx.options.with_os in ('posix', 'windows', 'freertos', 'macosx'): - ctx.fatal('--with-os must be either \'posix\', \'windows\', \'macosx\' or \'freertos\'') - - # Validate USART drivers - if not ctx.options.with_driver_usart in (None, 'windows', 'linux'): - ctx.fatal('--with-driver-usart must be either \'windows\' or \'linux\'') - - if not ctx.options.with_loglevel in ('error', 'warn', 'info', 'debug'): - ctx.fatal('--with-loglevel must be either \'error\', \'warn\', \'info\' or \'debug\'') - - # Setup and validate toolchain - if (len(ctx.stack_path) <= 1) and ctx.options.toolchain: - ctx.env.CC = ctx.options.toolchain + 'gcc' - ctx.env.AR = ctx.options.toolchain + 'ar' - - ctx.load('gcc') - - # Set git revision define - git_rev = os.popen('git describe --always 2> /dev/null || echo unknown').read().strip() - - # Setup DEFINES - ctx.define('GIT_REV', git_rev) - - # Set build output format - ctx.env.FEATURES = ['c'] - if not ctx.options.disable_stlib: - ctx.env.FEATURES += ['cstlib'] - - # Setup CFLAGS - if (len(ctx.stack_path) <= 1) and (len(ctx.env.CFLAGS) == 0): - ctx.env.prepend_value('CFLAGS', ["-std=gnu99", "-g", "-Os", "-Wall", "-Wextra", "-Wshadow", "-Wcast-align", "-Wwrite-strings", "-Wno-unused-parameter"]) - - # Setup extra includes - ctx.env.append_unique('INCLUDES_CSP', ['include'] + ctx.options.includes.split(',')) - - # Add default files - ctx.env.append_unique('FILES_CSP', ['src/*.c','src/interfaces/csp_if_lo.c','src/transport/csp_udp.c','src/arch/{0}/**/*.c'.format(ctx.options.with_os)]) - - # Store OS as env variable - ctx.env.append_unique('OS', ctx.options.with_os) - - # Libs - if 'posix' in ctx.env.OS: - ctx.env.append_unique('LIBS', ['rt', 'pthread', 'util']) - elif 'macosx' in ctx.env.OS: - ctx.env.append_unique('LIBS', ['pthread']) - - # Check for recursion - if ctx.path == ctx.srcnode: - ctx.options.install_csp = True - - # Windows build flags - if ctx.options.with_os == 'windows': - ctx.env.append_unique('CFLAGS', ['-D_WIN32_WINNT=0x0600']) - - ctx.define_cond('CSP_FREERTOS', ctx.options.with_os == 'freertos') - ctx.define_cond('CSP_POSIX', ctx.options.with_os == 'posix') - ctx.define_cond('CSP_WINDOWS', ctx.options.with_os == 'windows') - ctx.define_cond('CSP_MACOSX', ctx.options.with_os == 'macosx') - - # Add CAN driver - if ctx.options.enable_can_socketcan: - ctx.env.append_unique('FILES_CSP', 'src/drivers/can/can_socketcan.c') - - # Add USART driver - if ctx.options.with_driver_usart != None: - ctx.env.append_unique('FILES_CSP', 'src/drivers/usart/usart_{0}.c'.format(ctx.options.with_driver_usart)) - - # Interfaces - if ctx.options.enable_if_can: - ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_can.c') - ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_can_pbuf.c') - if ctx.options.enable_if_i2c: - ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_i2c.c') - if ctx.options.enable_if_kiss: - ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_kiss.c') - if ctx.options.enable_if_zmqhub: - ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_zmqhub.c') - ctx.check_cfg(package='libzmq', args='--cflags --libs') - ctx.env.append_unique('LIBS', ctx.env.LIB_LIBZMQ) - - # Store configuration options - ctx.env.ENABLE_BINDINGS = ctx.options.enable_bindings - ctx.env.ENABLE_EXAMPLES = ctx.options.enable_examples - - # Check for python development - if ctx.options.enable_bindings: - ctx.env.LIBCSP_PYTHON2 = ctx.check_cfg(package='python2', args='--cflags --libs', atleast_version='2.7', mandatory=False) - if ctx.options.enable_python3_bindings: - ctx.env.LIBCSP_PYTHON3 = ctx.check_cfg(package='python3', args='--cflags --libs', atleast_version='3.5', mandatory=False) - - # Create config file - if not ctx.options.disable_output: - ctx.env.append_unique('FILES_CSP', 'src/csp_debug.c') - else: - ctx.env.append_unique('EXCL_CSP', 'src/csp_debug.c') - - if ctx.options.enable_rdp: - ctx.env.append_unique('FILES_CSP', 'src/transport/csp_rdp.c') - - if ctx.options.enable_crc32: - ctx.env.append_unique('FILES_CSP', 'src/csp_crc32.c') - else: - ctx.env.append_unique('EXCL_CSP', 'src/csp_crc32.c') - - if not ctx.options.enable_dedup: - ctx.env.append_unique('EXCL_CSP', 'src/csp_dedup.c') - - if ctx.options.enable_hmac: - ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_hmac.c') - ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_sha1.c') - - if ctx.options.enable_xtea: - ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_xtea.c') - ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_sha1.c') - - ctx.env.append_unique('FILES_CSP', 'src/rtable/csp_rtable_' + ctx.options.with_rtable + '.c') - - ctx.define_cond('CSP_DEBUG', not ctx.options.disable_output) - ctx.define_cond('CSP_USE_RDP', ctx.options.enable_rdp) - ctx.define_cond('CSP_USE_CRC32', ctx.options.enable_crc32) - ctx.define_cond('CSP_USE_HMAC', ctx.options.enable_hmac) - ctx.define_cond('CSP_USE_XTEA', ctx.options.enable_xtea) - ctx.define_cond('CSP_USE_PROMISC', ctx.options.enable_promisc) - ctx.define_cond('CSP_USE_QOS', ctx.options.enable_qos) - ctx.define_cond('CSP_USE_DEDUP', ctx.options.enable_dedup) - ctx.define_cond('CSP_USE_INIT_SHUTDOWN', ctx.options.enable_init_shutdown) - ctx.define_cond('CSP_USE_CAN', ctx.options.enable_if_can) - ctx.define_cond('CSP_USE_I2C', ctx.options.enable_if_i2c) - ctx.define_cond('CSP_USE_KISS', ctx.options.enable_if_kiss) - ctx.define_cond('CSP_USE_ZMQHUB', ctx.options.enable_if_zmqhub) - ctx.define('CSP_CONN_MAX', ctx.options.with_max_connections) - ctx.define('CSP_CONN_QUEUE_LENGTH', ctx.options.with_conn_queue_length) - ctx.define('CSP_FIFO_INPUT', ctx.options.with_router_queue_length) - ctx.define('CSP_MAX_BIND_PORT', ctx.options.with_max_bind_port) - ctx.define('CSP_RDP_MAX_WINDOW', ctx.options.with_rdp_max_window) - ctx.define('CSP_PADDING_BYTES', ctx.options.with_padding) - ctx.define('CSP_CONNECTION_SO', ctx.options.with_connection_so) - - if ctx.options.with_bufalign != None: - ctx.define('CSP_BUFFER_ALIGN', ctx.options.with_bufalign) - - # Set logging level - ctx.define_cond('CSP_LOG_LEVEL_DEBUG', ctx.options.with_loglevel in ('debug')) - ctx.define_cond('CSP_LOG_LEVEL_INFO', ctx.options.with_loglevel in ('debug', 'info')) - ctx.define_cond('CSP_LOG_LEVEL_WARN', ctx.options.with_loglevel in ('debug', 'info', 'warn')) - ctx.define_cond('CSP_LOG_LEVEL_ERROR', ctx.options.with_loglevel in ('debug', 'info', 'warn', 'error')) - - # Check compiler endianness - endianness = ctx.check_endianness() - ctx.define_cond('CSP_LITTLE_ENDIAN', endianness == 'little') - ctx.define_cond('CSP_BIG_ENDIAN', endianness == 'big') - - # Check for stdbool.h - ctx.check_cc(header_name='stdbool.h', mandatory=False, define_name='CSP_HAVE_STDBOOL_H', type='cstlib') - - # Check for libsocketcan.h - if ctx.options.enable_if_can and ctx.options.enable_can_socketcan: - have_socketcan = ctx.check_cc(lib='socketcan', mandatory=False, define_name='CSP_HAVE_LIBSOCKETCAN') - if have_socketcan: - ctx.env.append_unique('LIBS', ['socketcan']) - - ctx.define('LIBCSP_VERSION', VERSION) - - ctx.write_config_header('include/csp/csp_autoconfig.h') - -def build(ctx): - - # Set install path for header files - install_path = False - if ctx.options.install_csp: - install_path = '${PREFIX}/lib' - ctx.install_files('${PREFIX}/include/csp', ctx.path.ant_glob('include/csp/*.h')) - ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_lo.h') - - if 'src/interfaces/csp_if_can.c' in ctx.env.FILES_CSP: - ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_can.h') - if 'src/interfaces/csp_if_i2c.c' in ctx.env.FILES_CSP: - ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_i2c.h') - if 'src/interfaces/csp_if_kiss.c' in ctx.env.FILES_CSP: - ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_kiss.h') - if 'src/interfaces/csp_if_zmqhub.c' in ctx.env.FILES_CSP: - ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_zmqhub.h') - if 'src/drivers/usart/usart_{0}.c'.format(ctx.options.with_driver_usart) in ctx.env.FILES_CSP: - ctx.install_as('${PREFIX}/include/csp/drivers/usart.h', 'include/csp/drivers/usart.h') - if 'src/drivers/can/can_socketcan.c' in ctx.env.FILES_CSP: - ctx.install_as('${PREFIX}/include/csp/drivers/can_socketcan.h', 'include/csp/drivers/can_socketcan.h') - - ctx.install_files('${PREFIX}/include/csp', 'include/csp/csp_autoconfig.h', cwd=ctx.bldnode) - - ctx(export_includes='include', name='csp_h') - - ctx(features=ctx.env.FEATURES, - source=ctx.path.ant_glob(ctx.env.FILES_CSP, excl=ctx.env.EXCL_CSP), - target = 'csp', - includes= ctx.env.INCLUDES_CSP, - export_includes = ctx.env.INCLUDES_CSP, - use = 'include freertos_h', - install_path = install_path, - ) - - # Build shared library for Python bindings - if ctx.env.ENABLE_BINDINGS: - ctx.shlib(source = ctx.path.ant_glob(ctx.env.FILES_CSP, excl=ctx.env.EXCL_CSP), - name = 'csp_shlib', - target = 'csp', - includes = ctx.env.INCLUDES_CSP, - export_includes = 'include', - use = ['include'], - lib = ctx.env.LIBS) - - # python3 bindings - if ctx.env.LIBCSP_PYTHON3: - ctx.shlib(source = ['src/bindings/python/pycsp.c'], - target = 'csp_py3', - includes = ctx.env.INCLUDES_CSP + ctx.env.INCLUDES_PYTHON3, - export_includes = 'include', - use = ['csp_shlib', 'include'], - lib = ctx.env.LIBS) - - # python2 bindings - if ctx.env.LIBCSP_PYTHON2: - ctx.shlib(source = ['src/bindings/python/pycsp.c'], - target = 'csp_py2', - includes = ctx.env.INCLUDES_CSP + ctx.env.INCLUDES_PYTHON2, - export_includes = 'include', - use = ['csp_shlib', 'include'], - lib = ctx.env.LIBS) - - if ctx.env.ENABLE_EXAMPLES: - ctx.program(source = ctx.path.ant_glob('examples/simple.c'), - target = 'simple', - includes = ctx.env.INCLUDES_CSP, - lib = ctx.env.LIBS, - use = 'csp') - - if ctx.options.enable_if_kiss: - ctx.program(source = 'examples/kiss.c', - target = 'kiss', - includes = ctx.env.INCLUDES_CSP, - lib = ctx.env.LIBS, - use = 'csp') - - if ctx.options.enable_if_zmqhub: - ctx.program(source = 'examples/zmqproxy.c', - target = 'zmqproxy', - includes = ctx.env.INCLUDES_CSP, - lib = ctx.env.LIBS, - use = 'csp') - - if 'posix' in ctx.env.OS: - ctx.program(source = 'examples/csp_if_fifo.c', - target = 'fifo', - includes = ctx.env.INCLUDES_CSP, - lib = ctx.env.LIBS, - use = 'csp') - - if 'windows' in ctx.env.OS: - ctx.program(source = ctx.path.ant_glob('examples/csp_if_fifo_windows.c'), - target = 'csp_if_fifo', - includes = ctx.env.INCLUDES_CSP, - use = 'csp') - -def dist(ctx): - ctx.excl = 'build/* **/.* **/*.pyc **/*.o **/*~ *.tar.gz' From bf7ab7195c84139ec50039d2bf6dfc796cf36977 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Mon, 14 Dec 2020 08:42:48 +0100 Subject: [PATCH 017/360] wip CspComIF --- bsp_linux/comIF/CspComIF.cpp | 167 +++++++++ bsp_linux/comIF/CspComIF.h | 66 ++++ bsp_linux/comIF/cookies/CspCookie.cpp | 24 ++ bsp_linux/comIF/cookies/CspCookie.h | 31 ++ mission/core/GenericFactory.cpp | 11 +- mission/devices/P60DockHandler.cpp | 84 +++-- mission/devices/P60DockHandler.h | 22 +- .../devicedefinitions/GomSpacePackets.h | 332 ++++++++++++++++++ .../P60DockHandlerDefinitions.h | 32 ++ 9 files changed, 727 insertions(+), 42 deletions(-) create mode 100644 bsp_linux/comIF/CspComIF.cpp create mode 100644 bsp_linux/comIF/CspComIF.h create mode 100644 bsp_linux/comIF/cookies/CspCookie.cpp create mode 100644 bsp_linux/comIF/cookies/CspCookie.h create mode 100644 mission/devices/devicedefinitions/GomSpacePackets.h diff --git a/bsp_linux/comIF/CspComIF.cpp b/bsp_linux/comIF/CspComIF.cpp new file mode 100644 index 00000000..6716c530 --- /dev/null +++ b/bsp_linux/comIF/CspComIF.cpp @@ -0,0 +1,167 @@ +#include "CspComIF.h" +#include +#include +#include +#include + +CspComIF::CspComIF(object_id_t objectId) : + SystemObject(objectId) { + +} + +CspComIF::~CspComIF() { +} + +ReturnValue_t CspComIF::initializeInterface(CookieIF *cookie) { + if(cookie == nullptr) { + return NULLPOINTER; + } + + CspCookie* cspCookie = dynamic_cast(cookie); + if(cspCookie == nullptr) { + return NULLPOINTER; + } + char* canInterface = cspCookie->getCanIf(); + int bitrate = cspCookie->getBitrate(); + /* Define the memory to allocate for the CSP stack */ + int buf_count = 10; + int buf_size = 300; + /* Init CSP and CSP buffer system */ + if (csp_init(cspClientAddress) != CSP_ERR_NONE + || csp_buffer_init(buf_count, buf_size) != CSP_ERR_NONE) { + sif::error << "Failed to init CSP\r\n" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + int promisc = 0; // Set filter mode on + csp_iface_t *csp_if_ptr = &csp_if; + csp_if_ptr = csp_can_socketcan_init(canInterface, bitrate, promisc); + + /* Set default route and start router */ + uint8_t address = CSP_DEFAULT_ROUTE; + uint8_t netmask = 0; + uint8_t mac = CSP_NODE_MAC; + int result = csp_rtable_set(address, netmask, csp_if_ptr, mac); + if(result != CSP_ERR_NONE){ + sif::error << "Failed to add can interface to router table" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + /* Start the route task */ + unsigned int task_stack_size = 500; + unsigned int priority = 0; + result = csp_route_start_task(task_stack_size, priority); + if(result != CSP_ERR_NONE){ + sif::error << "Failed to start csp route task" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + uint8_t cspAddress = cspCookie->getCspAddress(); + uint16_t maxReplyLength = cspCookie->getMaxReplyLength(); + if(cspDeviceMap.find(cspAddress) != cspDeviceMap.end()){ + /* Insert device information in CSP map */ + cspDeviceMap.emplace(cspAddress, vectorBuffer(maxReplyLength)); + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CspComIF::sendMessage(CookieIF *cookie, + const uint8_t * sendData, size_t sendLen) { + int result; + if(cookie == NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } + CspCookie* cspCookie = dynamic_cast (cookie); + if(cspCookie == NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } + + /* Extract csp port and bytes to query from command buffer */ + uint8_t cspPort; + uint16_t querySize; + SerializeAdapter::deSerialize(&cspPort, &sendData, &sendLen, + SerializeIF::Endianness::BIG); + SerializeAdapter::deSerialize(&querySize, &sendData, &sendLen, + SerializeIF::Endianness::BIG); + uint8_t cspAddress = cspCookie->getCspAddress(); + + if(cspPort == csp_reserved_ports_e::CSP_PING){ + uint32_t timeout = 1000; // ms + unsigned int pingSize = 100; // 100 bytes + uint32_t replyTime = csp_ping(cspAddress, timeout, pingSize, + CSP_O_NONE); + sif::info << "Ping address: " << cspAddress << ", reply after " + << replyTime << " ms" << std::endl; + /* Store reply time in reply buffer * */ + uint8_t* replyBuffer = cspDeviceMap[cspAddress].data(); + memcpy(replyBuffer, &replyTime, sizeof(replyTime)); + } + else if(cspPort == csp_reserved_ports_e::CSP_REBOOT){ + csp_reboot(cspCookie->getCspAddress()); + } + else{ + /* No CSP fixed port was selected. Send data to the specified port and + * wait for querySize number of bytes */ + result = cspTransfer(cspAddress, cspPort, sendData, sendLen, + querySize); + if(result != HasReturnvaluesIF::RETURN_OK){ + return HasReturnvaluesIF::RETURN_FAILED; + } + rememberQuerySize = querySize; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CspComIF::getSendSuccess(CookieIF *cookie) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CspComIF::requestReceiveMessage(CookieIF *cookie, + size_t requestLen) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CspComIF::readReceivedMessage(CookieIF *cookie, + uint8_t** buffer, size_t* size) { + if(cookie == NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } + CspCookie* cspCookie = dynamic_cast (cookie); + if(cspCookie == NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } + + uint8_t cspAddress = cspCookie->getCspAddress(); + + *buffer = cspDeviceMap[cspAddress].data(); + *size = rememberQuerySize; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CspComIF::cspTransfer(uint8_t cspAddress, uint8_t cspPort, + const uint8_t* cmdBuffer, int cmdBufferLen, uint16_t querySize) { + + uint32_t timeout_ms = 1000; + uint8_t* replyBuffer = cspDeviceMap[cspAddress].data(); + uint8_t tmpCmdBuffer[cmdBufferLen]; + memcpy(tmpCmdBuffer, cmdBuffer, cmdBufferLen); + + csp_conn_t * conn = csp_connect(CSP_PRIO_HIGH, cspAddress, cspPort, 0, + CSP_O_NONE); + + querySize = 12; + int receivedBytes = csp_transaction_persistent(conn, timeout_ms, + tmpCmdBuffer, cmdBufferLen, replyBuffer, querySize); + if(receivedBytes != querySize){ + sif::error << "CSP transfer failed to receive all requested bytes " + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + csp_close(conn); + + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/bsp_linux/comIF/CspComIF.h b/bsp_linux/comIF/CspComIF.h new file mode 100644 index 00000000..4fb24226 --- /dev/null +++ b/bsp_linux/comIF/CspComIF.h @@ -0,0 +1,66 @@ +#ifndef BSP_LINUX_COMIF_COOKIES_CSPCOMIF_H_ +#define BSP_LINUX_COMIF_COOKIES_CSPCOMIF_H_ + +#include +#include +#include +#include + +#include +#include + +/** + * @brief This class is serves as the communication interface to devices + * supporting the CSP protocol. For now as physical interface only + * CAN is supported by this CSP implementation. + * @author Jakob Meier + */ +class CspComIF: public DeviceCommunicationIF, public SystemObject { +public: + CspComIF(object_id_t objectId); + virtual ~CspComIF(); + + ReturnValue_t initializeInterface(CookieIF * cookie) override; + ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t * sendData, + size_t sendLen) override; + ReturnValue_t getSendSuccess(CookieIF *cookie) override; + ReturnValue_t requestReceiveMessage(CookieIF *cookie, + size_t requestLen) override; + ReturnValue_t readReceivedMessage(CookieIF *cookie, + uint8_t **readData, size_t *readLen) override; + +private: + + /** + * @brief This function initiates the CSP transfer. + * + * @param cspAddress The CSP address of the target device. + * @param cspPort The port of the target device. + * @param timeout The timeout to wait for csp_send and csp_read + * functions. Specifies how long the functions wait + * for a successful operation. + * @param cmdBuffer The data to send. + * @param cmpBuffer The number of bytes to send. + * @param querySize The size of the requested message. + */ + ReturnValue_t cspTransfer(uint8_t cspAddress, uint8_t cspPort, + const uint8_t* cmdBuffer, int cmdBufferLen, uint16_t querySize); + + typedef uint8_t node_t; + using vectorBuffer = std::vector; + using VectorBufferMap = std::unordered_map; + using vectorBufferIter = VectorBufferMap::iterator; + + /* In this map assigns reply buffers to a CSP device */ + VectorBufferMap cspDeviceMap; + + uint16_t rememberQuerySize = 0; + + /* This is the CSP address of the OBC. */ + node_t cspClientAddress = 1; + + /* Interface struct for csp protocol stack */ + csp_iface_t csp_if; +}; + +#endif /* BSP_LINUX_COMIF_COOKIES_CSPCOMIF_H_ */ diff --git a/bsp_linux/comIF/cookies/CspCookie.cpp b/bsp_linux/comIF/cookies/CspCookie.cpp new file mode 100644 index 00000000..64c160f5 --- /dev/null +++ b/bsp_linux/comIF/cookies/CspCookie.cpp @@ -0,0 +1,24 @@ +#include "CspCookie.h" + +CspCookie::CspCookie(uint16_t maxReplyLength_, uint8_t cspAddress_) : + maxReplyLength(maxReplyLength_), cspAddress(cspAddress_) { +} + +CspCookie::~CspCookie() { +} + +uint16_t CspCookie::getMaxReplyLength(){ + return maxReplyLength; +} + +uint8_t CspCookie::getCspAddress(){ + return cspAddress; +} + +char* CspCookie::getCanIf(){ + return canInterface; +} + +int CspCookie::getBitrate(){ + return bitrate; +} diff --git a/bsp_linux/comIF/cookies/CspCookie.h b/bsp_linux/comIF/cookies/CspCookie.h new file mode 100644 index 00000000..5dfebfc0 --- /dev/null +++ b/bsp_linux/comIF/cookies/CspCookie.h @@ -0,0 +1,31 @@ +#ifndef BSP_LINUX_COMIF_COOKIES_CSPCOOKIE_H_ +#define BSP_LINUX_COMIF_COOKIES_CSPCOOKIE_H_ + +#include +#include + +/** + * @brief This is the cookie for devices supporting the CSP (CubeSat Space + * Protocol). + * @author J. Meier + */ +class CspCookie: public CookieIF { +public: + + CspCookie(uint16_t maxReplyLength_, uint8_t cspAddress_); + virtual ~CspCookie(); + + uint16_t getMaxReplyLength(); + uint8_t getCspAddress(); + char* getCanIf(); + int getBitrate(); + +private: + + uint16_t maxReplyLength; + char canInterface[5] = "can0"; + uint8_t cspAddress; + int bitrate = 1000; +}; + +#endif /* BSP_LINUX_COMIF_COOKIES_CSPCOOKIE_H_ */ diff --git a/mission/core/GenericFactory.cpp b/mission/core/GenericFactory.cpp index b350cbd4..2964e0d3 100644 --- a/mission/core/GenericFactory.cpp +++ b/mission/core/GenericFactory.cpp @@ -21,8 +21,8 @@ #include #include #include -#include -#include +#include +#include #if ADD_TEST_CODE == 1 //#include @@ -86,14 +86,15 @@ void ObjectFactory::produceGenericObjects() { apid::EIVE_OBSW, pus::PUS_SERVICE_200); /* Cookies */ - P60DockCookie* p60DockCookie = new P60DockCookie(addresses::P60DOCK); + CspCookie* p60DockCspCookie = new CspCookie(P60Dock::MAX_REPLY_LENGTH, + addresses::P60DOCK); /* Communication interfaces */ - new P60DockComIF(objects::P60_DOCK_COM_IF); + new CspComIF(objects::P60_DOCK_COM_IF); /* Device Handler */ new P60DockHandler(objects::P60DOCK_HANDLER, objects::P60_DOCK_COM_IF, - p60DockCookie); + p60DockCspCookie); /* Test Device Handler */ #if ADD_TEST_CODE == 1 diff --git a/mission/devices/P60DockHandler.cpp b/mission/devices/P60DockHandler.cpp index fa4ebebb..ab914681 100644 --- a/mission/devices/P60DockHandler.cpp +++ b/mission/devices/P60DockHandler.cpp @@ -1,8 +1,5 @@ -#include -#include #include -#include "bsp_linux/comIF/cookies/P60DockCookie.h" -#include "bsp_linux/comIF/P60DockComIF.h" +#include P60DockHandler::P60DockHandler(object_id_t objectId, object_id_t comIF, CookieIF * comCookie):DeviceHandlerBase(objectId, comIF, comCookie) { @@ -10,10 +7,6 @@ P60DockHandler::P60DockHandler(object_id_t objectId, object_id_t comIF, if(comCookie == NULL){ sif::error << "P60DockHandler invalid com cookie" << std::endl; } - p60DockCookie = dynamic_cast (comCookie); - if(p60DockCookie == NULL){ - sif::error << "P60DockHandler failed to get P60DockCookie" << std::endl; - } } P60DockHandler::~P60DockHandler() { @@ -41,15 +34,39 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( size_t commandDataLen) { switch(deviceCommand) { case(PING): { - p60DockCookie->setPingMessage(); break; } - case(READ_MODULE_CFG):{ - p60DockCookie->setReadModuleCfgMessage(); + case(PARAM_SET):{ break; } - case(READ_HK):{ - p60DockCookie->setReadHkMessage(); + case(PARAM_GET):{ + /* Unpack the received action message */ + GetParamMessageUnpacker getParamMessage(commandData, commandDataLen); + uint8_t tableId = getParamMessage.getTableId(); + uint16_t address = getParamMessage.getAddress(); + uint16_t length = EndianConverter::convertLittleEndian( + sizeof(address)); + uint16_t checksum = GOMSPACE::IGNORE_CHECKSUM; + uint16_t seq = 0; + uint16_t total = 0; + uint16_t querySize = getParamMessage.getQuerySize(); + + /* Generate the CSP command to send to the P60 Dock */ + CspGetParamCommand getParamCmd(querySize, PARAM_GET, tableId, length, + checksum, seq, total, address); + size_t cspPacketLen = 0; + uint8_t* buffer = cspPacket; + getParamCmd.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), + SerializeIF::Endianness::BIG); + if(cspPacketLen > MAX_PACKET_LEN){ + sif::error << "P60DockHandler: Received invalid get parameter " + "command" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + rawPacket = cspPacket; + rawPacketLen = cspPacketLen; + rememberRequestedSize = querySize; + rememberCommandId = PARAM_GET; break; } default: @@ -60,44 +77,51 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( void P60DockHandler::fillCommandAndReplyMap(){ this->insertInCommandAndReplyMap(PING, 3); - this->insertInCommandAndReplyMap(READ_MODULE_CFG, 3); - this->insertInCommandAndReplyMap(READ_HK, 3); + this->insertInCommandAndReplyMap(PARAM_SET, 3); + this->insertInCommandAndReplyMap(PARAM_GET, 3); } ReturnValue_t P60DockHandler::scanForReply(const uint8_t *start, size_t remainingSize, DeviceCommandId_t *foundId, size_t *foundLen) { - MessageType_t messageType = p60DockCookie->getMessageType(); - switch(messageType) { + switch(rememberCommandId) { case(PING): *foundId = PING; - *foundLen = 4; + *foundLen = rememberRequestedSize; + rememberCommandId = NONE; break; - case(READ_MODULE_CFG): { - *foundId = READ_MODULE_CFG; - *foundLen = moduleCfgTableSize; - break; - } - case(READ_HK): { - *foundId = READ_HK; - *foundLen = hkTableSize; + case(PARAM_GET): { + *foundId = PARAM_GET; + *foundLen = rememberRequestedSize + CspGetParamReply::GS_HDR_LENGTH; + rememberCommandId = NONE; break; } default: return IGNORE_REPLY_DATA; } - p60DockCookie->resetMessageType(); return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t P60DockHandler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) { switch(id) { - case(READ_MODULE_CFG): { + case(PING): { handleDeviceTM((SerializeIF*)packet, id, true, true); break; } - case(READ_HK): { - handleDeviceTM((SerializeIF*)packet, id, true, true); + case(PARAM_GET): { + uint16_t payloadLength = *(packet + 2); + uint8_t tempPayloadBuffer[payloadLength]; + CspGetParamReply cspGetParamReply(tempPayloadBuffer, payloadLength); + uint8_t action = cspGetParamReply.getAction(); + uint8_t tableId = cspGetParamReply.getTableId(); + uint16_t length = cspGetParamReply.getLength(); + uint16_t address = cspGetParamReply.getAddress(); + size_t size = CspGetParamReply::GS_HDR_LENGTH + payloadLength; + cspGetParamReply.deSerialize(&packet, &size, + SerializeIF::Endianness::LITTLE); + ParamReply paramReply(action, tableId, address, length, tempPayloadBuffer, + payloadLength); + handleDeviceTM(¶mReply, id, true, true); break; } default: diff --git a/mission/devices/P60DockHandler.h b/mission/devices/P60DockHandler.h index 40161e42..abb61ba4 100644 --- a/mission/devices/P60DockHandler.h +++ b/mission/devices/P60DockHandler.h @@ -4,6 +4,13 @@ #include #include +namespace P60Dock{ + /* The maximum size of a reply from the P60 dock. Maximum size is reached + * when retrieving the full parameter configuration table. 412 bytes of + * payload data and 12 bytes of CSP header data. */ + static const uint16_t MAX_REPLY_LENGTH = 424; +} + class P60DockHandler: public DeviceHandlerBase { public: P60DockHandler(object_id_t objectId, object_id_t comIF, @@ -26,15 +33,16 @@ protected: private: + static const uint8_t MAX_PACKET_LEN = 36; + /* Device commands are derived from the rparam.h of the gomspace lib */ static const DeviceCommandId_t PING = 0x1; //!< [EXPORT] : [COMMAND] - static const DeviceCommandId_t READ_MODULE_CFG = 0x71; //!< [EXPORT] : [COMMAND] - static const DeviceCommandId_t READ_HK = 0x72; //!< [EXPORT] : [COMMAND] + static const DeviceCommandId_t NONE = 0x2; // Set when no command is pending + static const DeviceCommandId_t PARAM_GET = 0x00; //!< [EXPORT] : [COMMAND] + static const DeviceCommandId_t PARAM_SET = 0xFF; //!< [EXPORT] : [COMMAND] - uint16_t moduleCfgTableSize = 412; - uint8_t calibrationTableSize = 174; - uint8_t hkTableSize = 188; - - P60DockCookie* p60DockCookie; + uint8_t rememberRequestedSize = 0; + uint8_t rememberCommandId = NONE; + uint8_t cspPacket[MAX_PACKET_LEN]; }; #endif /* MISSION_DEVICES_P60DOCKHANDLER_H_ */ diff --git a/mission/devices/devicedefinitions/GomSpacePackets.h b/mission/devices/devicedefinitions/GomSpacePackets.h new file mode 100644 index 00000000..5fab5a8b --- /dev/null +++ b/mission/devices/devicedefinitions/GomSpacePackets.h @@ -0,0 +1,332 @@ +#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEPACKETS_H_ +#define MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEPACKETS_H_ + +#include "fsfw/serialize/SerialBufferAdapter.h" +#include "fsfw/serialize/SerializeElement.h" +#include "fsfw/serialize/SerialLinkedListAdapter.h" + +namespace GOMSPACE{ + static const uint16_t IGNORE_CHECKSUM = 0x0bb0; + /* CSP port to ping gomspace devices. */ + static const uint8_t PING_PORT = 1; + static const uint8_t REBOOT_PORT = 4; + /* CSP port of gomspace devices to request or set parameters */ + static const uint8_t PARAM_PORT = 7; +} + +/** + * @brief A serial linked list adapter implementation to generate ping + * messages for gomspace devices. + * + * @details A ping request simply sends back the received data provided by the + * data buffer. cspPort and querySize are only informations required + * by the CspComI and other than the data array not physically + * transmitted to the target device. + */ +class CspPing : public SerialLinkedListAdapter { +public: + /** + * @brief Constructor + * + * @param querySize_ The size of bytes replied by the ping request. + * Amounts to the number of bytes send. + * @param parameters_ Pointer to data which should be sent to the device. + * All data will be sent back by the ping target. + * @param paramterCount_ Number of bytes to send with the ping request. + */ + CspPing(uint16_t querySize_, const uint8_t* parameters_, + uint8_t parameterCount_) : + querySize(querySize_), data(parameters_, parameterCount_) { + setLinks(); + } + +private: + CspPing(const CspPing &command); + void setLinks() { + setStart(&cspPort); + cspPort.setNext(&querySize); + querySize.setNext(&data); + } + SerializeElement cspPort = GOMSPACE::PING_PORT; + SerializeElement querySize; + SerializeElement> data; +}; + + +/** + * @brief A serial linked list adapter implementation of the gs_rparam_query_t + * struct defined in rparam.h. Can be used to build the message to set + * a parameter in gomspace devices. + * + * @note cspPort and querySize will not be sent with the CSP packet to the + * gomspace device but are required for the CspComIF to get the port + * and the size to query. + */ +class CspSetParamCommand : public SerialLinkedListAdapter { +public: + CspSetParamCommand(uint8_t action_, uint8_t tableId_, + uint16_t addresslength_, uint16_t checksum_, uint16_t seq_, + uint16_t total_, uint16_t addr_, const uint8_t* parameters_, + uint8_t parameterCount_) : + action(action_), tableId(tableId_), addresslength(addresslength_), checksum( + checksum_), seq(seq_), total(total_), addr(addr_), parameters( + parameters_, parameterCount_) { + setLinks(); + } + +private: + CspSetParamCommand(const CspSetParamCommand &command); + void setLinks() { + setStart(&cspPort); + cspPort.setNext(&querySize); + querySize.setNext(&action); + action.setNext(&tableId); + tableId.setNext(&addresslength); + addresslength.setNext(&checksum); + checksum.setNext(&seq); + seq.setNext(&addr); + addr.setNext(¶meters); + } + SerializeElement cspPort = GOMSPACE::PARAM_PORT; + /* Only parameters are set. No data will be queried with this command */ + SerializeElement querySize = 0; + SerializeElement action; + SerializeElement tableId; + SerializeElement addresslength; + SerializeElement checksum; + SerializeElement seq; + SerializeElement total; + SerializeElement addr; + SerializeElement> parameters; +}; + + +/** + * @brief This class can be used to generate a get param command for the + * gomspace devices which will be sent to the device communication + * interface object. + * + * @note cspPort and querySize only serve as information for the CspComIF + * and will not be transmitted physically to the target device. + */ +class CspGetParamCommand : public SerialLinkedListAdapter { +public: + + CspGetParamCommand(uint16_t querySize_, uint8_t action_, uint8_t tableId_, + uint16_t addresslength_, uint16_t checksum_, uint16_t seq_, + uint16_t total_, uint16_t addr_) : + querySize(querySize_), action(action_), tableId(tableId_), addresslength( + addresslength_), checksum(checksum_), seq(seq_), total( + total_), addr(addr_) { + fixedValuesInit(); + setLinks(); + } + +private: + CspGetParamCommand(const CspGetParamCommand &command); + void setLinks() { + setStart(&cspPort); + cspPort.setNext(&querySize); + querySize.setNext(&action); + action.setNext(&tableId); + tableId.setNext(&addresslength); + addresslength.setNext(&checksum); + checksum.setNext(&seq); + seq.setNext(&total); + total.setNext(&addr); + } + void fixedValuesInit(){ + cspPort.entry = GOMSPACE::PARAM_PORT; + } + SerializeElement cspPort; + SerializeElement querySize; // size of bytes to query + /* Following information will also be physically transmitted to the target + * device*/ + SerializeElement action; + SerializeElement tableId; + SerializeElement addresslength; // size of address + SerializeElement checksum; + SerializeElement seq; + SerializeElement total; + SerializeElement addr; +}; + + +/** + * @brief This class can be used to deserialize replies from gomspace devices + * and extract the relevant data. + */ +class CspGetParamReply : public SerialLinkedListAdapter { +public: + /* The size of the header of a gomspace CSP packet. */ + static const uint8_t GS_HDR_LENGTH = 12; + /** + * @brief Constructor + * + * @param payloadBuffer Pointer to a buffer to store the payload data of + * the CSP packet. + * @param payloadBufferSz The size of the payload buffer where the payload + * data will be stored. + */ + CspGetParamReply(uint8_t* payloadBuffer_, uint8_t payloadBufferSz_) : + payload(payloadBuffer_, payloadBufferSz_) { + setLinks(); + } + + uint8_t getAction(){ + return action; + } + + uint8_t getTableId(){ + return tableId; + } + + uint16_t getLength(){ + return length; + } + + uint16_t getAddress(){ + return addr; + } + +private: + CspGetParamReply(const CspGetParamReply &reply); + void setLinks() { + setStart(&action); + action.setNext(&tableId); + seq.setNext(&addr); + addr.setNext(&payload); + } + + SerializeElement action; + SerializeElement tableId; + SerializeElement length; //length of payload data + SerializeElement checksum; + SerializeElement seq; + SerializeElement total; + SerializeElement addr; + SerializeElement> payload; +}; + + +/** + * @brief This class generates telemetry packets containing data from + * CSP get-parameter-replies. + */ +class ParamReply : public SerialLinkedListAdapter { +public: + /** + * @brief Constructor + * + * @param payloadBuffer Pointer to a buffer to store the payload data of + * the CSP packet. + * @param payloadBufferSz The size of the payload buffer where the payload + * data will be stored. + */ + ParamReply(uint8_t action_, uint8_t tableId_, uint16_t addr_, + uint16_t length_, uint8_t* payloadBuffer_, uint8_t payloadBufferSz_) : + payload(payloadBuffer_, payloadBufferSz_) { + setLinks(); + } + +private: + ParamReply(const CspGetParamReply &reply); + void setLinks() { + setStart(&action); + action.setNext(&tableId); + tableId.setNext(&addr); + addr.setNext(&length); + length.setNext(&payload); + } + SerializeElement action; + SerializeElement tableId; + SerializeElement addr; + SerializeElement length; + SerializeElement> payload; +}; + + +/** + * @brief This class helps to unpack information from an action messages + * to set a parameter in gomspace devices. The action message can be + * for example received from the PUS Service 8. + */ +class SetParamMessageUnpacker: public SerialLinkedListAdapter { +public: + + SetParamMessageUnpacker(const uint8_t* commandData, size_t commandDataLen) { + SerializeAdapter::deSerialize(&tableId, &commandData, &commandDataLen, + SerializeIF::Endianness::BIG); + SerializeAdapter::deSerialize(&address, &commandData, &commandDataLen, + SerializeIF::Endianness::BIG); + parameterBuffer = commandData; + parameterCount = commandDataLen; + } + + uint8_t getTableId() const { + return tableId; + } + + uint16_t getAddress() const { + return address; + } + + const uint8_t* getParameters() { + return parameterBuffer; + } + + uint8_t getParameterCount(){ + return parameterCount; + } + + +private: + SetParamMessageUnpacker(const SetParamMessageUnpacker &message); + uint8_t tableId; + uint16_t address; + /* Parameter buffer holds the values of the parameters to set while the + * address points to the location of a parameter. */ + const uint8_t * parameterBuffer; + uint8_t parameterCount; +}; + + +/** + * @brief This class helps to unpack information from an action message + * to get a parameter from gomspace devices. The action message can be + * for example received from the PUS Service 8. + */ +class GetParamMessageUnpacker: public SerialLinkedListAdapter { +public: + + GetParamMessageUnpacker(const uint8_t* commandData, size_t commandDataLen) { + SerializeAdapter::deSerialize(&tableId, &commandData, &commandDataLen, + SerializeIF::Endianness::BIG); + SerializeAdapter::deSerialize(&address, &commandData, &commandDataLen, + SerializeIF::Endianness::BIG); + SerializeAdapter::deSerialize(&querySize, &commandData, &commandDataLen, + SerializeIF::Endianness::BIG); + } + + uint8_t getTableId() const { + return tableId; + } + + uint16_t getAddress() const { + return address; + } + + uint8_t getQuerySize(){ + return querySize; + } + + +private: + GetParamMessageUnpacker(const GetParamMessageUnpacker &message); + uint8_t tableId; + uint16_t address; //The memory address offset within the table + uint8_t querySize; //defines number of bytes to query +}; + + +#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEPACKETS_H_ */ diff --git a/mission/devices/devicedefinitions/P60DockHandlerDefinitions.h b/mission/devices/devicedefinitions/P60DockHandlerDefinitions.h index 001c7b76..756c52bd 100644 --- a/mission/devices/devicedefinitions/P60DockHandlerDefinitions.h +++ b/mission/devices/devicedefinitions/P60DockHandlerDefinitions.h @@ -53,6 +53,38 @@ // SerializeElement> filename; //}; +/** + * @brief A serial linked list adapter implementation of the gs_rparam_query_t struct + * defined in rparam.h + */ +class GetParamCommand: public SerialLinkedListAdapter { //!< [EXPORT] : [SUBSERVICE] 130 +public: + typedef uint16_t typeOfMaxDataSize; + static const uint16_t MAX_DATA_LENGTH = sizeof(typeOfMaxDataSize); + GetParamCommand(uint8_t objectId_, ActionId_t actionId_, + const uint8_t * replyDataBuffer_ = NULL, uint16_t replyDataSize_ = 0): + objectId(objectId_), actionId(actionId_), replyData(replyDataBuffer_,replyDataSize_){ + setLinks(); + } +private: + GetParamCommand(const GetParamCommand &reply); + void setLinks() { + setStart(&action); + action.setNext(&tableId); + tableId.setNext(&length); + lenght.setNext(&checksum); + checksum.setNext(&seq); + checksum.setNext(&addr); + } + SerializeElement cspPort = 7; + SerializeElement action; + SerializeElement tableId; + SerializeElement length; + SerializeElement checksum; + SerializeElement seq; + SerializeElement total; + SerializeElement addr; +}; #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_P60DOCKHANDLERDEFINITIONS_H_ */ From aae6c919aa2c7974b4a75a9901c4d681f9b499c4 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Mon, 14 Dec 2020 09:46:59 +0100 Subject: [PATCH 018/360] successful temperature reading --- bsp_linux/comIF/CspComIF.cpp | 11 ++++++++--- mission/devices/P60DockHandler.cpp | 7 ++++--- mission/devices/devicedefinitions/GomSpacePackets.h | 4 +++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/bsp_linux/comIF/CspComIF.cpp b/bsp_linux/comIF/CspComIF.cpp index 6716c530..e7616bba 100644 --- a/bsp_linux/comIF/CspComIF.cpp +++ b/bsp_linux/comIF/CspComIF.cpp @@ -59,7 +59,7 @@ ReturnValue_t CspComIF::initializeInterface(CookieIF *cookie) { uint8_t cspAddress = cspCookie->getCspAddress(); uint16_t maxReplyLength = cspCookie->getMaxReplyLength(); - if(cspDeviceMap.find(cspAddress) != cspDeviceMap.end()){ + if(cspDeviceMap.find(cspAddress) == cspDeviceMap.end()){ /* Insert device information in CSP map */ cspDeviceMap.emplace(cspAddress, vectorBuffer(maxReplyLength)); } @@ -145,14 +145,19 @@ ReturnValue_t CspComIF::cspTransfer(uint8_t cspAddress, uint8_t cspPort, const uint8_t* cmdBuffer, int cmdBufferLen, uint16_t querySize) { uint32_t timeout_ms = 1000; - uint8_t* replyBuffer = cspDeviceMap[cspAddress].data(); + vectorBufferIter iter = cspDeviceMap.find(cspAddress); + if(iter == cspDeviceMap.end()){ + sif::error << "CSP device with address " << cspAddress << " no found in" + << " device map" << std::endl; + } + uint8_t* replyBuffer = iter->second.data(); uint8_t tmpCmdBuffer[cmdBufferLen]; memcpy(tmpCmdBuffer, cmdBuffer, cmdBufferLen); csp_conn_t * conn = csp_connect(CSP_PRIO_HIGH, cspAddress, cspPort, 0, CSP_O_NONE); - querySize = 12; + querySize = 14; int receivedBytes = csp_transaction_persistent(conn, timeout_ms, tmpCmdBuffer, cmdBufferLen, replyBuffer, querySize); if(receivedBytes != querySize){ diff --git a/mission/devices/P60DockHandler.cpp b/mission/devices/P60DockHandler.cpp index ab914681..f1950f50 100644 --- a/mission/devices/P60DockHandler.cpp +++ b/mission/devices/P60DockHandler.cpp @@ -43,14 +43,15 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( /* Unpack the received action message */ GetParamMessageUnpacker getParamMessage(commandData, commandDataLen); uint8_t tableId = getParamMessage.getTableId(); - uint16_t address = getParamMessage.getAddress(); + uint16_t address = EndianConverter::convertLittleEndian( + getParamMessage.getAddress()); uint16_t length = EndianConverter::convertLittleEndian( sizeof(address)); uint16_t checksum = GOMSPACE::IGNORE_CHECKSUM; uint16_t seq = 0; uint16_t total = 0; - uint16_t querySize = getParamMessage.getQuerySize(); - + uint16_t querySize = getParamMessage.getQuerySize() + + CspGetParamCommand::GS_HDR_LENGTH; /* Generate the CSP command to send to the P60 Dock */ CspGetParamCommand getParamCmd(querySize, PARAM_GET, tableId, length, checksum, seq, total, address); diff --git a/mission/devices/devicedefinitions/GomSpacePackets.h b/mission/devices/devicedefinitions/GomSpacePackets.h index 5fab5a8b..025beeb8 100644 --- a/mission/devices/devicedefinitions/GomSpacePackets.h +++ b/mission/devices/devicedefinitions/GomSpacePackets.h @@ -6,7 +6,7 @@ #include "fsfw/serialize/SerialLinkedListAdapter.h" namespace GOMSPACE{ - static const uint16_t IGNORE_CHECKSUM = 0x0bb0; + static const uint16_t IGNORE_CHECKSUM = 0xb00b; /* CSP port to ping gomspace devices. */ static const uint8_t PING_PORT = 1; static const uint8_t REBOOT_PORT = 4; @@ -111,6 +111,8 @@ private: */ class CspGetParamCommand : public SerialLinkedListAdapter { public: + /* The size of the header of a gomspace CSP packet. */ + static const uint8_t GS_HDR_LENGTH = 12; CspGetParamCommand(uint16_t querySize_, uint8_t action_, uint8_t tableId_, uint16_t addresslength_, uint16_t checksum_, uint16_t seq_, From c91497e4de8d89a5baaf25e4a672b49de3809e25 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 14 Dec 2020 13:03:47 +0100 Subject: [PATCH 019/360] some fixes --- Makefile-Hosted | 2 +- {hosted => bsp_hosted}/InitMission.cpp | 0 {hosted => bsp_hosted}/InitMission.h | 0 {hosted => bsp_hosted}/ObjectFactory.cpp | 2 +- {hosted => bsp_hosted}/ObjectFactory.h | 0 {hosted => bsp_hosted}/boardconfig/etl_profile.h | 0 {hosted => bsp_hosted}/boardconfig/gcov.h | 0 {hosted => bsp_hosted}/boardconfig/print.c | 1 + bsp_hosted/boardconfig/print.h | 8 ++++++++ hosted/hosted.mk => bsp_hosted/bsp_hosted.mk | 3 ++- {hosted => bsp_hosted}/comIF/ArduinoComIF.cpp | 5 ++--- {hosted => bsp_hosted}/comIF/ArduinoComIF.h | 0 {hosted => bsp_hosted}/comIF/ArduinoCookie.cpp | 2 +- {hosted => bsp_hosted}/comIF/ArduinoCookie.h | 0 {hosted => bsp_hosted}/fsfwconfig/FSFWConfig.h | 0 {hosted => bsp_hosted}/fsfwconfig/OBSWConfig.h | 0 {hosted => bsp_hosted}/fsfwconfig/OBSWVersion.h | 0 .../fsfwconfig/events/subsystemIdRanges.h | 0 {hosted => bsp_hosted}/fsfwconfig/fsfwconfig.mk | 0 .../fsfwconfig/ipc/MissionMessageTypes.cpp | 2 +- .../fsfwconfig/ipc/MissionMessageTypes.h | 0 {hosted => bsp_hosted}/fsfwconfig/returnvalues/classIds.h | 0 {hosted => bsp_hosted}/main.cpp | 3 +-- fsfw | 2 +- hosted/boardconfig/print.h | 8 -------- 25 files changed, 19 insertions(+), 19 deletions(-) rename {hosted => bsp_hosted}/InitMission.cpp (100%) rename {hosted => bsp_hosted}/InitMission.h (100%) rename {hosted => bsp_hosted}/ObjectFactory.cpp (100%) rename {hosted => bsp_hosted}/ObjectFactory.h (100%) rename {hosted => bsp_hosted}/boardconfig/etl_profile.h (100%) rename {hosted => bsp_hosted}/boardconfig/gcov.h (100%) rename {hosted => bsp_hosted}/boardconfig/print.c (99%) create mode 100644 bsp_hosted/boardconfig/print.h rename hosted/hosted.mk => bsp_hosted/bsp_hosted.mk (76%) rename {hosted => bsp_hosted}/comIF/ArduinoComIF.cpp (99%) rename {hosted => bsp_hosted}/comIF/ArduinoComIF.h (100%) rename {hosted => bsp_hosted}/comIF/ArduinoCookie.cpp (83%) rename {hosted => bsp_hosted}/comIF/ArduinoCookie.h (100%) rename {hosted => bsp_hosted}/fsfwconfig/FSFWConfig.h (100%) rename {hosted => bsp_hosted}/fsfwconfig/OBSWConfig.h (100%) rename {hosted => bsp_hosted}/fsfwconfig/OBSWVersion.h (100%) rename {hosted => bsp_hosted}/fsfwconfig/events/subsystemIdRanges.h (100%) rename {hosted => bsp_hosted}/fsfwconfig/fsfwconfig.mk (100%) rename {hosted => bsp_hosted}/fsfwconfig/ipc/MissionMessageTypes.cpp (75%) rename {hosted => bsp_hosted}/fsfwconfig/ipc/MissionMessageTypes.h (100%) rename {hosted => bsp_hosted}/fsfwconfig/returnvalues/classIds.h (100%) rename {hosted => bsp_hosted}/main.cpp (95%) delete mode 100644 hosted/boardconfig/print.h diff --git a/Makefile-Hosted b/Makefile-Hosted index bb56fec5..9dff3677 100644 --- a/Makefile-Hosted +++ b/Makefile-Hosted @@ -15,7 +15,7 @@ CUSTOM_DEFINES := # Chip & board used for compilation # (can be overriden by adding CHIP=chip and BOARD=board to the command-line) -BOARD_FILE_ROOT = hosted +BOARD_FILE_ROOT = bsp_hosted BOARD = host OS_FSFW = host CUSTOM_DEFINES += -D$(OS_FSFW) diff --git a/hosted/InitMission.cpp b/bsp_hosted/InitMission.cpp similarity index 100% rename from hosted/InitMission.cpp rename to bsp_hosted/InitMission.cpp diff --git a/hosted/InitMission.h b/bsp_hosted/InitMission.h similarity index 100% rename from hosted/InitMission.h rename to bsp_hosted/InitMission.h diff --git a/hosted/ObjectFactory.cpp b/bsp_hosted/ObjectFactory.cpp similarity index 100% rename from hosted/ObjectFactory.cpp rename to bsp_hosted/ObjectFactory.cpp index 09c69082..798fa7ec 100644 --- a/hosted/ObjectFactory.cpp +++ b/bsp_hosted/ObjectFactory.cpp @@ -1,7 +1,7 @@ #include "ObjectFactory.h" -#include #include +#include #include #include diff --git a/hosted/ObjectFactory.h b/bsp_hosted/ObjectFactory.h similarity index 100% rename from hosted/ObjectFactory.h rename to bsp_hosted/ObjectFactory.h diff --git a/hosted/boardconfig/etl_profile.h b/bsp_hosted/boardconfig/etl_profile.h similarity index 100% rename from hosted/boardconfig/etl_profile.h rename to bsp_hosted/boardconfig/etl_profile.h diff --git a/hosted/boardconfig/gcov.h b/bsp_hosted/boardconfig/gcov.h similarity index 100% rename from hosted/boardconfig/gcov.h rename to bsp_hosted/boardconfig/gcov.h diff --git a/hosted/boardconfig/print.c b/bsp_hosted/boardconfig/print.c similarity index 99% rename from hosted/boardconfig/print.c rename to bsp_hosted/boardconfig/print.c index f409ee1b..f35f9447 100644 --- a/hosted/boardconfig/print.c +++ b/bsp_hosted/boardconfig/print.c @@ -1,4 +1,5 @@ #include "print.h" + #include void printChar(const char* character, bool errStream) { diff --git a/bsp_hosted/boardconfig/print.h b/bsp_hosted/boardconfig/print.h new file mode 100644 index 00000000..84798490 --- /dev/null +++ b/bsp_hosted/boardconfig/print.h @@ -0,0 +1,8 @@ +#ifndef BSP_HOSTED_BOARDCONFIG_PRINT_H_ +#define BSP_HOSTED_BOARDCONFIG_PRINT_H_ + +#include + +void printChar(const char* character, bool errStream); + +#endif /* BSP_HOSTED_BOARDCONFIG_PRINT_H_ */ diff --git a/hosted/hosted.mk b/bsp_hosted/bsp_hosted.mk similarity index 76% rename from hosted/hosted.mk rename to bsp_hosted/bsp_hosted.mk index 8bd29bc1..9595ffbf 100644 --- a/hosted/hosted.mk +++ b/bsp_hosted/bsp_hosted.mk @@ -7,4 +7,5 @@ CSRC += $(wildcard $(CURRENTPATH)/boardconfig/*.c) CXXSRC += $(wildcard $(CURRENTPATH)/comIF/*.cpp) CSRC += $(wildcard $(CURRENTPATH)/comIF/*.c) -INCLUDES += $(CURRENTPATH)/boardconfig \ No newline at end of file +INCLUDES += $(CURRENTPATH)/boardconfig +INCLUDES += $(CURRENTPATH)/fsfwconfig \ No newline at end of file diff --git a/hosted/comIF/ArduinoComIF.cpp b/bsp_hosted/comIF/ArduinoComIF.cpp similarity index 99% rename from hosted/comIF/ArduinoComIF.cpp rename to bsp_hosted/comIF/ArduinoComIF.cpp index 11555f55..047a60ae 100644 --- a/hosted/comIF/ArduinoComIF.cpp +++ b/bsp_hosted/comIF/ArduinoComIF.cpp @@ -1,6 +1,5 @@ -#include "ArduinoComIF.h" -#include "ArduinoCookie.h" - +#include +#include #include #include #include diff --git a/hosted/comIF/ArduinoComIF.h b/bsp_hosted/comIF/ArduinoComIF.h similarity index 100% rename from hosted/comIF/ArduinoComIF.h rename to bsp_hosted/comIF/ArduinoComIF.h diff --git a/hosted/comIF/ArduinoCookie.cpp b/bsp_hosted/comIF/ArduinoCookie.cpp similarity index 83% rename from hosted/comIF/ArduinoCookie.cpp rename to bsp_hosted/comIF/ArduinoCookie.cpp index 7d9a9f3c..bc698720 100644 --- a/hosted/comIF/ArduinoCookie.cpp +++ b/bsp_hosted/comIF/ArduinoCookie.cpp @@ -1,4 +1,4 @@ -#include "ArduinoCookie.h" +#include ArduinoCookie::ArduinoCookie(Protocol_t protocol, uint8_t address, const size_t maxReplySize) : diff --git a/hosted/comIF/ArduinoCookie.h b/bsp_hosted/comIF/ArduinoCookie.h similarity index 100% rename from hosted/comIF/ArduinoCookie.h rename to bsp_hosted/comIF/ArduinoCookie.h diff --git a/hosted/fsfwconfig/FSFWConfig.h b/bsp_hosted/fsfwconfig/FSFWConfig.h similarity index 100% rename from hosted/fsfwconfig/FSFWConfig.h rename to bsp_hosted/fsfwconfig/FSFWConfig.h diff --git a/hosted/fsfwconfig/OBSWConfig.h b/bsp_hosted/fsfwconfig/OBSWConfig.h similarity index 100% rename from hosted/fsfwconfig/OBSWConfig.h rename to bsp_hosted/fsfwconfig/OBSWConfig.h diff --git a/hosted/fsfwconfig/OBSWVersion.h b/bsp_hosted/fsfwconfig/OBSWVersion.h similarity index 100% rename from hosted/fsfwconfig/OBSWVersion.h rename to bsp_hosted/fsfwconfig/OBSWVersion.h diff --git a/hosted/fsfwconfig/events/subsystemIdRanges.h b/bsp_hosted/fsfwconfig/events/subsystemIdRanges.h similarity index 100% rename from hosted/fsfwconfig/events/subsystemIdRanges.h rename to bsp_hosted/fsfwconfig/events/subsystemIdRanges.h diff --git a/hosted/fsfwconfig/fsfwconfig.mk b/bsp_hosted/fsfwconfig/fsfwconfig.mk similarity index 100% rename from hosted/fsfwconfig/fsfwconfig.mk rename to bsp_hosted/fsfwconfig/fsfwconfig.mk diff --git a/hosted/fsfwconfig/ipc/MissionMessageTypes.cpp b/bsp_hosted/fsfwconfig/ipc/MissionMessageTypes.cpp similarity index 75% rename from hosted/fsfwconfig/ipc/MissionMessageTypes.cpp rename to bsp_hosted/fsfwconfig/ipc/MissionMessageTypes.cpp index b91abcd3..36ef1b73 100644 --- a/hosted/fsfwconfig/ipc/MissionMessageTypes.cpp +++ b/bsp_hosted/fsfwconfig/ipc/MissionMessageTypes.cpp @@ -1,5 +1,5 @@ +#include "MissionMessageTypes.h" #include -#include void messagetypes::clearMissionMessage(CommandMessage* message) { switch(message->getMessageType()) { diff --git a/hosted/fsfwconfig/ipc/MissionMessageTypes.h b/bsp_hosted/fsfwconfig/ipc/MissionMessageTypes.h similarity index 100% rename from hosted/fsfwconfig/ipc/MissionMessageTypes.h rename to bsp_hosted/fsfwconfig/ipc/MissionMessageTypes.h diff --git a/hosted/fsfwconfig/returnvalues/classIds.h b/bsp_hosted/fsfwconfig/returnvalues/classIds.h similarity index 100% rename from hosted/fsfwconfig/returnvalues/classIds.h rename to bsp_hosted/fsfwconfig/returnvalues/classIds.h diff --git a/hosted/main.cpp b/bsp_hosted/main.cpp similarity index 95% rename from hosted/main.cpp rename to bsp_hosted/main.cpp index e5ca6d02..50d1e7f2 100644 --- a/hosted/main.cpp +++ b/bsp_hosted/main.cpp @@ -1,7 +1,6 @@ +#include #include #include -#include - #include #ifdef WIN32 diff --git a/fsfw b/fsfw index ca34250e..81c00cd3 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit ca34250e8d74cec8a75bed284bf0ec9252019b65 +Subproject commit 81c00cd3dcdabf57142d488dd348e0cd335f55a8 diff --git a/hosted/boardconfig/print.h b/hosted/boardconfig/print.h deleted file mode 100644 index 8e7e2e5d..00000000 --- a/hosted/boardconfig/print.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef HOSTED_BOARDCONFIG_PRINT_H_ -#define HOSTED_BOARDCONFIG_PRINT_H_ - -#include - -void printChar(const char* character, bool errStream); - -#endif /* HOSTED_BOARDCONFIG_PRINT_H_ */ From 869bc657d9ca779b0ca5de8ccffebf9818e9a109 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 14 Dec 2020 21:57:52 +0100 Subject: [PATCH 020/360] fsfw update --- fsfw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsfw b/fsfw index 81c00cd3..b232a8a2 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 81c00cd3dcdabf57142d488dd348e0cd335f55a8 +Subproject commit b232a8a2919841b331b43c84a7fb2ae80f93186f From dd127fece8bbf071ba68813dc315180127cd957c Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 14 Dec 2020 22:03:57 +0100 Subject: [PATCH 021/360] hosted build working again --- bsp_hosted/InitMission.cpp | 4 --- bsp_hosted/fsfwconfig/FSFWConfig.h | 1 - .../fsfwconfig/objects/systemObjectList.h | 36 +++++++++++++++++++ bsp_hosted/fsfwconfig/tmtc/apid.h | 19 ++++++++++ bsp_hosted/fsfwconfig/tmtc/pusIds.h | 23 ++++++++++++ fsfwconfig/tmtc/tmTcSize.h | 10 ------ mission/core/GenericFactory.cpp | 32 ++++++++--------- mission/devices/MGMHandlerLIS3MDL.h | 2 +- 8 files changed, 93 insertions(+), 34 deletions(-) create mode 100644 bsp_hosted/fsfwconfig/objects/systemObjectList.h create mode 100644 bsp_hosted/fsfwconfig/tmtc/apid.h create mode 100644 bsp_hosted/fsfwconfig/tmtc/pusIds.h delete mode 100644 fsfwconfig/tmtc/tmTcSize.h diff --git a/bsp_hosted/InitMission.cpp b/bsp_hosted/InitMission.cpp index 8bee1b2e..29101d08 100644 --- a/bsp_hosted/InitMission.cpp +++ b/bsp_hosted/InitMission.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -29,9 +28,6 @@ ServiceInterfaceStream sif::error("ERROR", true, false, true); ObjectManagerIF *objectManager = nullptr; -//Initialize Data Pool -DataPool dataPool(nullptr); - void InitMission::initMission() { sif::info << "Building global objects.." << std::endl; /* Instantiate global object manager and also create all objects */ diff --git a/bsp_hosted/fsfwconfig/FSFWConfig.h b/bsp_hosted/fsfwconfig/FSFWConfig.h index ea86152c..3433613c 100644 --- a/bsp_hosted/fsfwconfig/FSFWConfig.h +++ b/bsp_hosted/fsfwconfig/FSFWConfig.h @@ -1,7 +1,6 @@ #ifndef CONFIG_FSFWCONFIG_H_ #define CONFIG_FSFWCONFIG_H_ -#include #include //! Used to determine whether C++ ostreams are used diff --git a/bsp_hosted/fsfwconfig/objects/systemObjectList.h b/bsp_hosted/fsfwconfig/objects/systemObjectList.h new file mode 100644 index 00000000..3b5717fb --- /dev/null +++ b/bsp_hosted/fsfwconfig/objects/systemObjectList.h @@ -0,0 +1,36 @@ +#ifndef HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ +#define HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ + +#include + +// The objects will be instantiated in the ID order +namespace objects { + enum sourceObjects: uint32_t { + /* First Byte 0x50-0x52 reserved for PUS Services **/ + CCSDS_PACKET_DISTRIBUTOR = 0x50000100, + PUS_PACKET_DISTRIBUTOR = 0x50000200, + UDP_BRIDGE = 0x50000300, + UDP_POLLING_TASK = 0x50000400, + + PUS_SERVICE_3 = 0x51000300, + PUS_SERVICE_5 = 0x51000400, + PUS_SERVICE_6 = 0x51000500, + PUS_SERVICE_8 = 0x51000800, + PUS_SERVICE_23 = 0x51002300, + PUS_SERVICE_201 = 0x51020100, + + TIME_STAMPER = 0x52000001, + TM_FUNNEL = 0x52000002, + + /* Test Task */ + + TEST_TASK = 0x42694269, + DUMMY_INTERFACE = 0xCAFECAFE, + DUMMY_HANDLER = 0x4400AFFE, + + /* 0x49 ('I') for Communication Interfaces **/ + ARDUINO_COM_IF = 0x49000001 + }; +} + +#endif /* BSP_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ */ diff --git a/bsp_hosted/fsfwconfig/tmtc/apid.h b/bsp_hosted/fsfwconfig/tmtc/apid.h new file mode 100644 index 00000000..ee2fc7c4 --- /dev/null +++ b/bsp_hosted/fsfwconfig/tmtc/apid.h @@ -0,0 +1,19 @@ +#ifndef FSFWCONFIG_TMTC_APID_H_ +#define FSFWCONFIG_TMTC_APID_H_ + +#include + +/** + * Application Process Definition: entity, uniquely identified by an + * application process ID (APID), capable of generating telemetry source + * packets and receiving telecommand packets + * + * SOURCE APID: 0x73 / 115 / s + * APID is a 11 bit number + */ +namespace apid { + static const uint16_t EIVE_OBSW = 0x65; +} + + +#endif /* FSFWCONFIG_TMTC_APID_H_ */ diff --git a/bsp_hosted/fsfwconfig/tmtc/pusIds.h b/bsp_hosted/fsfwconfig/tmtc/pusIds.h new file mode 100644 index 00000000..a2dd7575 --- /dev/null +++ b/bsp_hosted/fsfwconfig/tmtc/pusIds.h @@ -0,0 +1,23 @@ +#ifndef CONFIG_TMTC_PUSIDS_HPP_ +#define CONFIG_TMTC_PUSIDS_HPP_ + +namespace pus { +enum Ids{ + PUS_SERVICE_1 = 1, + PUS_SERVICE_2 = 2, + PUS_SERVICE_3 = 3, + PUS_SERVICE_3_PSB = 3, + PUS_SERVICE_5 = 5, + PUS_SERVICE_6 = 6, + PUS_SERVICE_8 = 8, + PUS_SERVICE_9 = 9, + PUS_SERVICE_17 = 17, + PUS_SERVICE_19 = 19, + PUS_SERVICE_20 = 20, + PUS_SERVICE_23 = 23, + PUS_SERVICE_200 = 200, + PUS_SERVICE_201 = 201, +}; +}; + +#endif /* CONFIG_TMTC_PUSIDS_HPP_ */ diff --git a/fsfwconfig/tmtc/tmTcSize.h b/fsfwconfig/tmtc/tmTcSize.h deleted file mode 100644 index c3c83d31..00000000 --- a/fsfwconfig/tmtc/tmTcSize.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef FSFWCONFIG_TMTC_TMTCSIZE_H_ -#define FSFWCONFIG_TMTC_TMTCSIZE_H_ - -#include - -namespace tmtcsize { -static const uint32_t MAX_TM_PACKET = 50; -} - -#endif /* FSFWCONFIG_TMTC_TMTCSIZE_H_ */ diff --git a/mission/core/GenericFactory.cpp b/mission/core/GenericFactory.cpp index 5305dc82..be0d65e5 100644 --- a/mission/core/GenericFactory.cpp +++ b/mission/core/GenericFactory.cpp @@ -24,32 +24,28 @@ void ObjectFactory::produceGenericObjects() { /* Framework objects */ new EventManager(objects::EVENT_MANAGER); new HealthTable(objects::HEALTH_TABLE); - new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER, 0, 0, 0); + new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER); new TimeStamper(objects::TIME_STAMPER); { - static constexpr uint8_t NUMBER_OF_POOLS = 5; - const uint16_t element_sizes[NUMBER_OF_POOLS] = {16, 32, 64, 128, 1024}; - const uint16_t n_elements[NUMBER_OF_POOLS] = {100, 50, 25, 15, 5}; - new PoolManager(objects::TC_STORE, element_sizes, - n_elements); + PoolManager::LocalPoolConfig poolCfg = { + {100, 16}, {50, 32}, {25, 64}, {15, 128}, {5, 1024} + }; + new PoolManager(objects::TC_STORE, poolCfg); } { - static constexpr uint8_t NUMBER_OF_POOLS = 5; - const uint16_t element_sizes[NUMBER_OF_POOLS] = {16, 32, 64, 128, 1024}; - const uint16_t n_elements[NUMBER_OF_POOLS] = {100, 50, 25, 15, 5}; - new PoolManager(objects::TM_STORE, element_sizes, - n_elements); + PoolManager::LocalPoolConfig poolCfg = { + {100, 16}, {50, 32}, {25, 64}, {15, 128}, {5, 1024} + }; + new PoolManager(objects::TM_STORE, poolCfg); } { - static constexpr uint8_t NUMBER_OF_POOLS = 6; - const uint16_t element_sizes[NUMBER_OF_POOLS] = {32, 64, 512, - 1024, 2048, 4096}; - const uint16_t n_elements[NUMBER_OF_POOLS] = {200, 100, 50, 25, 15, 5}; - new PoolManager(objects::IPC_STORE, element_sizes, - n_elements); + PoolManager::LocalPoolConfig poolCfg = { + {100, 16}, {50, 32}, {25, 64}, {15, 128}, {5, 1024} + }; + new PoolManager(objects::IPC_STORE, poolCfg); } new CCSDSDistributor(apid::EIVE_OBSW, objects::CCSDS_PACKET_DISTRIBUTOR); @@ -62,7 +58,7 @@ void ObjectFactory::produceGenericObjects() { /* PUS stack */ new Service1TelecommandVerification(objects::PUS_SERVICE_1_VERIFICATION, - apid::EIVE_OBSW, pus::PUS_SERVICE_1, objects::TM_FUNNEL); + apid::EIVE_OBSW, pus::PUS_SERVICE_1, objects::TM_FUNNEL, 20); new Service2DeviceAccess(objects::PUS_SERVICE_2_DEVICE_ACCESS, apid::EIVE_OBSW, pus::PUS_SERVICE_2, 3, 10); new Service5EventReporting(objects::PUS_SERVICE_5_EVENT_REPORTING, diff --git a/mission/devices/MGMHandlerLIS3MDL.h b/mission/devices/MGMHandlerLIS3MDL.h index 0ff4d198..4c06e001 100644 --- a/mission/devices/MGMHandlerLIS3MDL.h +++ b/mission/devices/MGMHandlerLIS3MDL.h @@ -28,7 +28,7 @@ public: static const uint8_t INTERFACE_ID = CLASS_ID::MGM_LIS3MDL; static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MGM_LIS3MDL; //Notifies a command to change the setup parameters - static const Event CHANGE_OF_SETUP_PARAMETER = MAKE_EVENT(0, SEVERITY::LOW); + static const Event CHANGE_OF_SETUP_PARAMETER = MAKE_EVENT(0, severity::LOW); MGMHandlerLIS3MDL(uint32_t objectId, object_id_t deviceCommunication, CookieIF* comCookie); From 77b81cf3952211fd4d446ba6e05ce7310dd62960 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 14 Dec 2020 22:09:18 +0100 Subject: [PATCH 022/360] updated submodules --- fsfw | 2 +- tmtc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fsfw b/fsfw index 113397c6..b232a8a2 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 113397c6c6ae4c46341f4880710e4e4d9b6e7630 +Subproject commit b232a8a2919841b331b43c84a7fb2ae80f93186f diff --git a/tmtc b/tmtc index 3fc71f90..4463efcf 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 3fc71f9094e8fb670942f0c29a9dea0b6e03d17f +Subproject commit 4463efcf7bfd2181a78eff66fca82c335aeea1d1 From 949f6418a083206225a698303484325b303f18c8 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 14 Dec 2020 22:15:07 +0100 Subject: [PATCH 023/360] tmtc update --- tmtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmtc b/tmtc index 2f1c3d5e..4463efcf 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 2f1c3d5eb9c3858d99c4516f4f132425ea1a97b7 +Subproject commit 4463efcf7bfd2181a78eff66fca82c335aeea1d1 From 68d0fa95b0c8af712e4f6a66516ac0a97dbff252 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 14 Dec 2020 22:18:25 +0100 Subject: [PATCH 024/360] indentation --- mission/devices/MGMHandlerLIS3MDL.cpp | 384 +++++++++++++------------- 1 file changed, 192 insertions(+), 192 deletions(-) diff --git a/mission/devices/MGMHandlerLIS3MDL.cpp b/mission/devices/MGMHandlerLIS3MDL.cpp index 77b1a300..50d0ce3c 100644 --- a/mission/devices/MGMHandlerLIS3MDL.cpp +++ b/mission/devices/MGMHandlerLIS3MDL.cpp @@ -3,7 +3,7 @@ MGMHandlerLIS3MDL::MGMHandlerLIS3MDL(object_id_t objectId, object_id_t deviceCommunication, CookieIF* comCookie): - DeviceHandlerBase(objectId, deviceCommunication, comCookie) { + DeviceHandlerBase(objectId, deviceCommunication, comCookie) { #if OBSW_ENHANCED_PRINTOUT == 1 debugDivider = new PeriodicOperationDivider(10); #endif @@ -74,34 +74,34 @@ ReturnValue_t MGMHandlerLIS3MDL::buildTransitionDeviceCommand( } uint8_t MGMHandlerLIS3MDL::readCommand(uint8_t command, bool continuousCom) { - command |= (1 << MGMLIS3MDL::RW_BIT); - if (continuousCom == true) { - command |= (1 << MGMLIS3MDL::MS_BIT); - } - return command; + command |= (1 << MGMLIS3MDL::RW_BIT); + if (continuousCom == true) { + command |= (1 << MGMLIS3MDL::MS_BIT); + } + return command; } uint8_t MGMHandlerLIS3MDL::writeCommand(uint8_t command, bool continuousCom) { - command &= ~(1 << MGMLIS3MDL::RW_BIT); - if (continuousCom == true) { - command |= (1 << MGMLIS3MDL::MS_BIT); - } - return command; + command &= ~(1 << MGMLIS3MDL::RW_BIT); + if (continuousCom == true) { + command |= (1 << MGMLIS3MDL::MS_BIT); + } + return command; } void MGMHandlerLIS3MDL::setupMgm() { - registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; - registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; - registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; - registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; - registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; + registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; + registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; + registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; + registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; + registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; - prepareCtrlRegisterWrite(); + prepareCtrlRegisterWrite(); } ReturnValue_t MGMHandlerLIS3MDL::buildNormalDeviceCommand( - DeviceCommandId_t *id) { + DeviceCommandId_t *id) { // Data/config register will be read in an alternating manner. if(communicationStep == CommunicationStep::DATA) { lastSentCommand = MGMLIS3MDL::READ_CONFIG_AND_DATA; @@ -120,7 +120,7 @@ ReturnValue_t MGMHandlerLIS3MDL::buildNormalDeviceCommand( ReturnValue_t MGMHandlerLIS3MDL::buildCommandFromCommand( DeviceCommandId_t deviceCommand, const uint8_t *commandData, - size_t commandDataLen) { + size_t commandDataLen) { lastSentCommand = deviceCommand; switch(deviceCommand) { case(MGMLIS3MDL::READ_CONFIG_AND_DATA): { @@ -139,24 +139,24 @@ ReturnValue_t MGMHandlerLIS3MDL::buildCommandFromCommand( rawPacketLen = 3; return RETURN_OK; } - case(MGMLIS3MDL::IDENTIFY_DEVICE): { - return identifyDevice(); - } - case(MGMLIS3MDL::TEMP_SENSOR_ENABLE): { - return enableTemperatureSensor(commandData, commandDataLen); - } - case(MGMLIS3MDL::SETUP_MGM): { - setupMgm(); - return HasReturnvaluesIF::RETURN_OK; - } - case(MGMLIS3MDL::ACCURACY_OP_MODE_SET): { - return setOperatingMode(commandData, commandDataLen); - } - default: - lastSentCommand = DeviceHandlerIF::NO_COMMAND; - return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; - } - return HasReturnvaluesIF::RETURN_FAILED; + case(MGMLIS3MDL::IDENTIFY_DEVICE): { + return identifyDevice(); + } + case(MGMLIS3MDL::TEMP_SENSOR_ENABLE): { + return enableTemperatureSensor(commandData, commandDataLen); + } + case(MGMLIS3MDL::SETUP_MGM): { + setupMgm(); + return HasReturnvaluesIF::RETURN_OK; + } + case(MGMLIS3MDL::ACCURACY_OP_MODE_SET): { + return setOperatingMode(commandData, commandDataLen); + } + default: + lastSentCommand = DeviceHandlerIF::NO_COMMAND; + return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + } + return HasReturnvaluesIF::RETURN_FAILED; } ReturnValue_t MGMHandlerLIS3MDL::identifyDevice() { @@ -171,93 +171,93 @@ ReturnValue_t MGMHandlerLIS3MDL::identifyDevice() { } ReturnValue_t MGMHandlerLIS3MDL::scanForReply(const uint8_t *start, - size_t len, DeviceCommandId_t *foundId, size_t *foundLen) { - *foundLen = len; - if (len == MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1) { - *foundLen = len; - *foundId = MGMLIS3MDL::READ_CONFIG_AND_DATA; - // Check validity by checking config registers - if (start[1] != registers[0] or start[2] != registers[1] or - start[3] != registers[2] or start[4] != registers[3] or - start[5] != registers[4]) { - return DeviceHandlerIF::INVALID_DATA; - } + size_t len, DeviceCommandId_t *foundId, size_t *foundLen) { + *foundLen = len; + if (len == MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1) { + *foundLen = len; + *foundId = MGMLIS3MDL::READ_CONFIG_AND_DATA; + // Check validity by checking config registers + if (start[1] != registers[0] or start[2] != registers[1] or + start[3] != registers[2] or start[4] != registers[3] or + start[5] != registers[4]) { + return DeviceHandlerIF::INVALID_DATA; + } if(mode == _MODE_START_UP) { commandExecuted = true; } - } - else if(len == MGMLIS3MDL::TEMPERATURE_REPLY_LEN) { - *foundLen = len; - *foundId = MGMLIS3MDL::READ_TEMPERATURE; - } - else if (len == MGMLIS3MDL::SETUP_REPLY_LEN) { - *foundLen = len; - *foundId = MGMLIS3MDL::SETUP_MGM; - } - else if (len == SINGLE_COMMAND_ANSWER_LEN) { - *foundLen = len; - *foundId = lastSentCommand; - } - else { - return DeviceHandlerIF::INVALID_DATA; - } + } + else if(len == MGMLIS3MDL::TEMPERATURE_REPLY_LEN) { + *foundLen = len; + *foundId = MGMLIS3MDL::READ_TEMPERATURE; + } + else if (len == MGMLIS3MDL::SETUP_REPLY_LEN) { + *foundLen = len; + *foundId = MGMLIS3MDL::SETUP_MGM; + } + else if (len == SINGLE_COMMAND_ANSWER_LEN) { + *foundLen = len; + *foundId = lastSentCommand; + } + else { + return DeviceHandlerIF::INVALID_DATA; + } - // Data with SPI Interface has always this answer - if (start[0] == 0b11111111) { - return RETURN_OK; - } - else { - return DeviceHandlerIF::INVALID_DATA; - } + // Data with SPI Interface has always this answer + if (start[0] == 0b11111111) { + return RETURN_OK; + } + else { + return DeviceHandlerIF::INVALID_DATA; + } } ReturnValue_t MGMHandlerLIS3MDL::interpretDeviceReply(DeviceCommandId_t id, - const uint8_t *packet) { + const uint8_t *packet) { - switch (id) { - case MGMLIS3MDL::IDENTIFY_DEVICE: { - break; - } - case MGMLIS3MDL::SETUP_MGM: { - break; - } - case MGMLIS3MDL::READ_CONFIG_AND_DATA: { - // TODO: Store configuration and sensor values in new local datasets. + switch (id) { + case MGMLIS3MDL::IDENTIFY_DEVICE: { + break; + } + case MGMLIS3MDL::SETUP_MGM: { + break; + } + case MGMLIS3MDL::READ_CONFIG_AND_DATA: { + // TODO: Store configuration and sensor values in new local datasets. - uint8_t scale = getFullScale(registers[2]); - float sensitivityFactor = getSensitivityFactor(scale); + uint8_t scale = getFullScale(registers[2]); + float sensitivityFactor = getSensitivityFactor(scale); - int16_t mgmMeasurementRawX = packet[MGMLIS3MDL::X_HIGHBYTE_IDX] << 8 - | packet[MGMLIS3MDL::X_LOWBYTE_IDX] ; + int16_t mgmMeasurementRawX = packet[MGMLIS3MDL::X_HIGHBYTE_IDX] << 8 + | packet[MGMLIS3MDL::X_LOWBYTE_IDX] ; int16_t mgmMeasurementRawY = packet[MGMLIS3MDL::Y_HIGHBYTE_IDX] << 8 | packet[MGMLIS3MDL::Y_LOWBYTE_IDX] ; int16_t mgmMeasurementRawZ = packet[MGMLIS3MDL::Z_HIGHBYTE_IDX] << 8 | packet[MGMLIS3MDL::Z_LOWBYTE_IDX] ; - // Target value in microtesla - float mgmX = static_cast(mgmMeasurementRawX) * sensitivityFactor - * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; - float mgmY = static_cast(mgmMeasurementRawY) * sensitivityFactor - * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; - float mgmZ = static_cast(mgmMeasurementRawZ) * sensitivityFactor - * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + // Target value in microtesla + float mgmX = static_cast(mgmMeasurementRawX) * sensitivityFactor + * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + float mgmY = static_cast(mgmMeasurementRawY) * sensitivityFactor + * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + float mgmZ = static_cast(mgmMeasurementRawZ) * sensitivityFactor + * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; #if OBSW_ENHANCED_PRINTOUT == 1 - if(debugDivider->checkAndIncrement()) { + if(debugDivider->checkAndIncrement()) { sif::info << "MGMHandlerLIS3: Magnetic field strength in" " microtesla:" << std::endl; // Set terminal to utf-8 if there is an issue with micro printout. sif::info << "X: " << mgmX << " \xC2\xB5T" << std::endl; sif::info << "Y: " << mgmY << " \xC2\xB5T" << std::endl; sif::info << "Z: " << mgmZ << " \xC2\xB5T" << std::endl; - } + } #endif - break; - } + break; + } - case MGMLIS3MDL::READ_TEMPERATURE: { - int16_t tempValueRaw = packet[2] << 8 | packet[1]; + case MGMLIS3MDL::READ_TEMPERATURE: { + int16_t tempValueRaw = packet[2] << 8 | packet[1]; float tempValue = 25.0 + ((static_cast(tempValueRaw)) / 8.0); #if OBSW_ENHANCED_PRINTOUT == 1 if(debugDivider->check()) { @@ -267,131 +267,131 @@ ReturnValue_t MGMHandlerLIS3MDL::interpretDeviceReply(DeviceCommandId_t id, } #endif break; - } + } - default: { - return DeviceHandlerIF::UNKNOW_DEVICE_REPLY; - } + default: { + return DeviceHandlerIF::UNKNOW_DEVICE_REPLY; + } - } - return RETURN_OK; + } + return RETURN_OK; } uint8_t MGMHandlerLIS3MDL::getFullScale(uint8_t ctrlRegister2) { - bool FS0 = false; - bool FS1 = false; - if ((ctrlRegister2 >> 5) == 1) - FS0 = true; - if ((ctrlRegister2 >> 6) == 1) - FS1 = true; - if ((FS0 == true) && (FS1 == true)) - return 16; - else if ((FS0 == false) && (FS1 == true)) - return 12; - else if ((FS0 == true) && (FS1 == false)) - return 8; - else - return 4; + bool FS0 = false; + bool FS1 = false; + if ((ctrlRegister2 >> 5) == 1) + FS0 = true; + if ((ctrlRegister2 >> 6) == 1) + FS1 = true; + if ((FS0 == true) && (FS1 == true)) + return 16; + else if ((FS0 == false) && (FS1 == true)) + return 12; + else if ((FS0 == true) && (FS1 == false)) + return 8; + else + return 4; } float MGMHandlerLIS3MDL::getSensitivityFactor(uint8_t scale) { - return (float) scale / (INT16_MAX); + return (float) scale / (INT16_MAX); } ReturnValue_t MGMHandlerLIS3MDL::enableTemperatureSensor( - const uint8_t *commandData, size_t commandDataLen) { - triggerEvent(CHANGE_OF_SETUP_PARAMETER); - uint32_t size = 2; - commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1); - if (commandDataLen > 1) { - return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; - } - switch (*commandData) { - case (MGMLIS3MDL::ON): - commandBuffer[1] = registers[0] | (1 << 7); - break; + const uint8_t *commandData, size_t commandDataLen) { + triggerEvent(CHANGE_OF_SETUP_PARAMETER); + uint32_t size = 2; + commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1); + if (commandDataLen > 1) { + return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; + } + switch (*commandData) { + case (MGMLIS3MDL::ON): + commandBuffer[1] = registers[0] | (1 << 7); + break; - case (MGMLIS3MDL::OFF): - commandBuffer[1] = registers[0] & ~(1 << 7); - break; + case (MGMLIS3MDL::OFF): + commandBuffer[1] = registers[0] & ~(1 << 7); + break; - default: - return INVALID_COMMAND_PARAMETER; - break; - } - registers[0] = commandBuffer[1]; + default: + return INVALID_COMMAND_PARAMETER; + break; + } + registers[0] = commandBuffer[1]; - rawPacket = commandBuffer; - rawPacketLen = size; + rawPacket = commandBuffer; + rawPacketLen = size; - return RETURN_OK; + return RETURN_OK; } ReturnValue_t MGMHandlerLIS3MDL::setOperatingMode(const uint8_t *commandData, - size_t commandDataLen) { - triggerEvent(CHANGE_OF_SETUP_PARAMETER); - if (commandDataLen != 1) { - return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; - } + size_t commandDataLen) { + triggerEvent(CHANGE_OF_SETUP_PARAMETER); + if (commandDataLen != 1) { + return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; + } - switch (commandData[0]) { - case MGMLIS3MDL::LOW: - registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) & (~(1 << MGMLIS3MDL::OM0)); - registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) & (~(1 << MGMLIS3MDL::OMZ0)); - break; - case MGMLIS3MDL::MEDIUM: - registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) | (1 << MGMLIS3MDL::OM0); - registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) | (1 << MGMLIS3MDL::OMZ0); - break; + switch (commandData[0]) { + case MGMLIS3MDL::LOW: + registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) & (~(1 << MGMLIS3MDL::OM0)); + registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) & (~(1 << MGMLIS3MDL::OMZ0)); + break; + case MGMLIS3MDL::MEDIUM: + registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) | (1 << MGMLIS3MDL::OM0); + registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) | (1 << MGMLIS3MDL::OMZ0); + break; - case MGMLIS3MDL::HIGH: - registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) & (~(1 << MGMLIS3MDL::OM0)); - registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) & (~(1 << MGMLIS3MDL::OMZ0)); - break; + case MGMLIS3MDL::HIGH: + registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) & (~(1 << MGMLIS3MDL::OM0)); + registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) & (~(1 << MGMLIS3MDL::OMZ0)); + break; - case MGMLIS3MDL::ULTRA: - registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) | (1 << MGMLIS3MDL::OM0); - registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) | (1 << MGMLIS3MDL::OMZ0); - break; - default: - break; - } + case MGMLIS3MDL::ULTRA: + registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) | (1 << MGMLIS3MDL::OM0); + registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) | (1 << MGMLIS3MDL::OMZ0); + break; + default: + break; + } - return prepareCtrlRegisterWrite(); + return prepareCtrlRegisterWrite(); } void MGMHandlerLIS3MDL::fillCommandAndReplyMap() { - /* - * Regarding ArduinoBoard: - * Actually SPI answers directly, but as commanding ArduinoBoard the - * communication could be delayed - * SPI always has to be triggered, so there could be no periodic answer of - * the device, the device has to asked with a command, so periodic is zero. - * - * We dont read single registers, we just expect special - * reply from he Readall_MGM - */ - insertInCommandAndReplyMap(MGMLIS3MDL::READ_CONFIG_AND_DATA, 1); - insertInCommandAndReplyMap(MGMLIS3MDL::READ_TEMPERATURE, 1); - insertInCommandAndReplyMap(MGMLIS3MDL::SETUP_MGM, 1); - insertInCommandAndReplyMap(MGMLIS3MDL::IDENTIFY_DEVICE, 1); - insertInCommandAndReplyMap(MGMLIS3MDL::TEMP_SENSOR_ENABLE, 1); - insertInCommandAndReplyMap(MGMLIS3MDL::ACCURACY_OP_MODE_SET, 1); + /* + * Regarding ArduinoBoard: + * Actually SPI answers directly, but as commanding ArduinoBoard the + * communication could be delayed + * SPI always has to be triggered, so there could be no periodic answer of + * the device, the device has to asked with a command, so periodic is zero. + * + * We dont read single registers, we just expect special + * reply from he Readall_MGM + */ + insertInCommandAndReplyMap(MGMLIS3MDL::READ_CONFIG_AND_DATA, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::READ_TEMPERATURE, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::SETUP_MGM, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::IDENTIFY_DEVICE, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::TEMP_SENSOR_ENABLE, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::ACCURACY_OP_MODE_SET, 1); } ReturnValue_t MGMHandlerLIS3MDL::prepareCtrlRegisterWrite() { - commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1, true); + commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1, true); - for (size_t i = 0; i < MGMLIS3MDL::NR_OF_CTRL_REGISTERS; i++) { - commandBuffer[i + 1] = registers[i]; - } - rawPacket = commandBuffer; - rawPacketLen = MGMLIS3MDL::NR_OF_CTRL_REGISTERS + 1; + for (size_t i = 0; i < MGMLIS3MDL::NR_OF_CTRL_REGISTERS; i++) { + commandBuffer[i + 1] = registers[i]; + } + rawPacket = commandBuffer; + rawPacketLen = MGMLIS3MDL::NR_OF_CTRL_REGISTERS + 1; - // We dont have to check if this is working because we just did it - return RETURN_OK; + // We dont have to check if this is working because we just did it + return RETURN_OK; } void MGMHandlerLIS3MDL::setNormalDatapoolEntriesInvalid() { @@ -407,7 +407,7 @@ uint32_t MGMHandlerLIS3MDL::getTransitionDelayMs(Mode_t from, Mode_t to) { } void MGMHandlerLIS3MDL::modeChanged(void) { - internalState = STATE_NONE; + internalState = STATE_NONE; } ReturnValue_t MGMHandlerLIS3MDL::initializeLocalDataPool( From 269b8ee9b8e736eba0c52ec0ec0d24164f336f8e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 14 Dec 2020 22:21:47 +0100 Subject: [PATCH 025/360] again, indentation.. --- mission/devices/MGMHandlerLIS3MDL.cpp | 610 +++++++++++++------------- mission/devices/MGMHandlerLIS3MDL.h | 25 +- 2 files changed, 317 insertions(+), 318 deletions(-) diff --git a/mission/devices/MGMHandlerLIS3MDL.cpp b/mission/devices/MGMHandlerLIS3MDL.cpp index 50d0ce3c..acc6d749 100644 --- a/mission/devices/MGMHandlerLIS3MDL.cpp +++ b/mission/devices/MGMHandlerLIS3MDL.cpp @@ -2,17 +2,17 @@ MGMHandlerLIS3MDL::MGMHandlerLIS3MDL(object_id_t objectId, - object_id_t deviceCommunication, CookieIF* comCookie): - DeviceHandlerBase(objectId, deviceCommunication, comCookie) { + object_id_t deviceCommunication, CookieIF* comCookie): + DeviceHandlerBase(objectId, deviceCommunication, comCookie) { #if OBSW_ENHANCED_PRINTOUT == 1 - debugDivider = new PeriodicOperationDivider(10); + debugDivider = new PeriodicOperationDivider(10); #endif - // Set to default values right away. - registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; - registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; - registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; - registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; - registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; + // Set to default values right away. + registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; + registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; + registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; + registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; + registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; } @@ -21,381 +21,381 @@ MGMHandlerLIS3MDL::~MGMHandlerLIS3MDL() { void MGMHandlerLIS3MDL::doStartUp() { - switch (internalState) { - case STATE_NONE: - internalState = STATE_FIRST_CONTACT; - break; + switch (internalState) { + case STATE_NONE: + internalState = STATE_FIRST_CONTACT; + break; - case STATE_FIRST_CONTACT: - internalState = STATE_SETUP; - break; + case STATE_FIRST_CONTACT: + internalState = STATE_SETUP; + break; - case STATE_SETUP: - internalState = STATE_CHECK_REGISTERS; - break; + case STATE_SETUP: + internalState = STATE_CHECK_REGISTERS; + break; - case STATE_CHECK_REGISTERS: { - // Set up cached registers which will be used to configure the MGM. - if(commandExecuted) { - commandExecuted = false; - setMode(MODE_NORMAL); - } - break; - } - default: - break; - } + case STATE_CHECK_REGISTERS: { + // Set up cached registers which will be used to configure the MGM. + if(commandExecuted) { + commandExecuted = false; + setMode(MODE_NORMAL); + } + break; + } + default: + break; + } } void MGMHandlerLIS3MDL::doShutDown() { - setMode(_MODE_POWER_DOWN); + setMode(_MODE_POWER_DOWN); } ReturnValue_t MGMHandlerLIS3MDL::buildTransitionDeviceCommand( - DeviceCommandId_t *id) { - switch (internalState) { - case STATE_FIRST_CONTACT: - *id = MGMLIS3MDL::IDENTIFY_DEVICE; - break; + DeviceCommandId_t *id) { + switch (internalState) { + case STATE_FIRST_CONTACT: + *id = MGMLIS3MDL::IDENTIFY_DEVICE; + break; - case STATE_SETUP: - *id = MGMLIS3MDL::SETUP_MGM; - break; + case STATE_SETUP: + *id = MGMLIS3MDL::SETUP_MGM; + break; - case STATE_CHECK_REGISTERS: - *id = MGMLIS3MDL::READ_CONFIG_AND_DATA; - break; + case STATE_CHECK_REGISTERS: + *id = MGMLIS3MDL::READ_CONFIG_AND_DATA; + break; - default: - break; - } - return buildCommandFromCommand(*id, NULL, 0); + default: + break; + } + return buildCommandFromCommand(*id, NULL, 0); } uint8_t MGMHandlerLIS3MDL::readCommand(uint8_t command, bool continuousCom) { - command |= (1 << MGMLIS3MDL::RW_BIT); - if (continuousCom == true) { - command |= (1 << MGMLIS3MDL::MS_BIT); - } - return command; + command |= (1 << MGMLIS3MDL::RW_BIT); + if (continuousCom == true) { + command |= (1 << MGMLIS3MDL::MS_BIT); + } + return command; } uint8_t MGMHandlerLIS3MDL::writeCommand(uint8_t command, bool continuousCom) { - command &= ~(1 << MGMLIS3MDL::RW_BIT); - if (continuousCom == true) { - command |= (1 << MGMLIS3MDL::MS_BIT); - } - return command; + command &= ~(1 << MGMLIS3MDL::RW_BIT); + if (continuousCom == true) { + command |= (1 << MGMLIS3MDL::MS_BIT); + } + return command; } void MGMHandlerLIS3MDL::setupMgm() { - registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; - registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; - registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; - registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; - registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; + registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; + registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; + registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; + registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; + registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; - prepareCtrlRegisterWrite(); + prepareCtrlRegisterWrite(); } ReturnValue_t MGMHandlerLIS3MDL::buildNormalDeviceCommand( - DeviceCommandId_t *id) { - // Data/config register will be read in an alternating manner. - if(communicationStep == CommunicationStep::DATA) { - lastSentCommand = MGMLIS3MDL::READ_CONFIG_AND_DATA; - *id = MGMLIS3MDL::READ_CONFIG_AND_DATA; - communicationStep = CommunicationStep::TEMPERATURE; - return buildCommandFromCommand(*id, NULL, 0); - } - else { - lastSentCommand = MGMLIS3MDL::READ_TEMPERATURE; - *id = MGMLIS3MDL::READ_TEMPERATURE; - communicationStep = CommunicationStep::DATA; - return buildCommandFromCommand(*id, NULL, 0); - } + DeviceCommandId_t *id) { + // Data/config register will be read in an alternating manner. + if(communicationStep == CommunicationStep::DATA) { + lastSentCommand = MGMLIS3MDL::READ_CONFIG_AND_DATA; + *id = MGMLIS3MDL::READ_CONFIG_AND_DATA; + communicationStep = CommunicationStep::TEMPERATURE; + return buildCommandFromCommand(*id, NULL, 0); + } + else { + lastSentCommand = MGMLIS3MDL::READ_TEMPERATURE; + *id = MGMLIS3MDL::READ_TEMPERATURE; + communicationStep = CommunicationStep::DATA; + return buildCommandFromCommand(*id, NULL, 0); + } } ReturnValue_t MGMHandlerLIS3MDL::buildCommandFromCommand( - DeviceCommandId_t deviceCommand, const uint8_t *commandData, - size_t commandDataLen) { - lastSentCommand = deviceCommand; - switch(deviceCommand) { - case(MGMLIS3MDL::READ_CONFIG_AND_DATA): { - std::memset(commandBuffer, 0, sizeof(commandBuffer)); - commandBuffer[0] = readCommand(MGMLIS3MDL::CTRL_REG1, true); + DeviceCommandId_t deviceCommand, const uint8_t *commandData, + size_t commandDataLen) { + lastSentCommand = deviceCommand; + switch(deviceCommand) { + case(MGMLIS3MDL::READ_CONFIG_AND_DATA): { + std::memset(commandBuffer, 0, sizeof(commandBuffer)); + commandBuffer[0] = readCommand(MGMLIS3MDL::CTRL_REG1, true); - rawPacket = commandBuffer; - rawPacketLen = MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1; - return RETURN_OK; - } - case(MGMLIS3MDL::READ_TEMPERATURE): { - std::memset(commandBuffer, 0, 3); - commandBuffer[0] = readCommand(MGMLIS3MDL::TEMP_LOWBYTE, true); + rawPacket = commandBuffer; + rawPacketLen = MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1; + return RETURN_OK; + } + case(MGMLIS3MDL::READ_TEMPERATURE): { + std::memset(commandBuffer, 0, 3); + commandBuffer[0] = readCommand(MGMLIS3MDL::TEMP_LOWBYTE, true); - rawPacket = commandBuffer; - rawPacketLen = 3; - return RETURN_OK; - } - case(MGMLIS3MDL::IDENTIFY_DEVICE): { - return identifyDevice(); - } - case(MGMLIS3MDL::TEMP_SENSOR_ENABLE): { - return enableTemperatureSensor(commandData, commandDataLen); - } - case(MGMLIS3MDL::SETUP_MGM): { - setupMgm(); - return HasReturnvaluesIF::RETURN_OK; - } - case(MGMLIS3MDL::ACCURACY_OP_MODE_SET): { - return setOperatingMode(commandData, commandDataLen); - } - default: - lastSentCommand = DeviceHandlerIF::NO_COMMAND; - return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; - } - return HasReturnvaluesIF::RETURN_FAILED; + rawPacket = commandBuffer; + rawPacketLen = 3; + return RETURN_OK; + } + case(MGMLIS3MDL::IDENTIFY_DEVICE): { + return identifyDevice(); + } + case(MGMLIS3MDL::TEMP_SENSOR_ENABLE): { + return enableTemperatureSensor(commandData, commandDataLen); + } + case(MGMLIS3MDL::SETUP_MGM): { + setupMgm(); + return HasReturnvaluesIF::RETURN_OK; + } + case(MGMLIS3MDL::ACCURACY_OP_MODE_SET): { + return setOperatingMode(commandData, commandDataLen); + } + default: + lastSentCommand = DeviceHandlerIF::NO_COMMAND; + return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + } + return HasReturnvaluesIF::RETURN_FAILED; } ReturnValue_t MGMHandlerLIS3MDL::identifyDevice() { - uint32_t size = 2; - commandBuffer[0] = readCommand(MGMLIS3MDL::IDENTIFY_DEVICE_REG_ADDR); - commandBuffer[1] = 0x00; + uint32_t size = 2; + commandBuffer[0] = readCommand(MGMLIS3MDL::IDENTIFY_DEVICE_REG_ADDR); + commandBuffer[1] = 0x00; - rawPacket = commandBuffer; - rawPacketLen = size; + rawPacket = commandBuffer; + rawPacketLen = size; - return RETURN_OK; + return RETURN_OK; } ReturnValue_t MGMHandlerLIS3MDL::scanForReply(const uint8_t *start, - size_t len, DeviceCommandId_t *foundId, size_t *foundLen) { - *foundLen = len; - if (len == MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1) { - *foundLen = len; - *foundId = MGMLIS3MDL::READ_CONFIG_AND_DATA; - // Check validity by checking config registers - if (start[1] != registers[0] or start[2] != registers[1] or - start[3] != registers[2] or start[4] != registers[3] or - start[5] != registers[4]) { - return DeviceHandlerIF::INVALID_DATA; - } - if(mode == _MODE_START_UP) { - commandExecuted = true; - } + size_t len, DeviceCommandId_t *foundId, size_t *foundLen) { + *foundLen = len; + if (len == MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1) { + *foundLen = len; + *foundId = MGMLIS3MDL::READ_CONFIG_AND_DATA; + // Check validity by checking config registers + if (start[1] != registers[0] or start[2] != registers[1] or + start[3] != registers[2] or start[4] != registers[3] or + start[5] != registers[4]) { + return DeviceHandlerIF::INVALID_DATA; + } + if(mode == _MODE_START_UP) { + commandExecuted = true; + } - } - else if(len == MGMLIS3MDL::TEMPERATURE_REPLY_LEN) { - *foundLen = len; - *foundId = MGMLIS3MDL::READ_TEMPERATURE; - } - else if (len == MGMLIS3MDL::SETUP_REPLY_LEN) { - *foundLen = len; - *foundId = MGMLIS3MDL::SETUP_MGM; - } - else if (len == SINGLE_COMMAND_ANSWER_LEN) { - *foundLen = len; - *foundId = lastSentCommand; - } - else { - return DeviceHandlerIF::INVALID_DATA; - } + } + else if(len == MGMLIS3MDL::TEMPERATURE_REPLY_LEN) { + *foundLen = len; + *foundId = MGMLIS3MDL::READ_TEMPERATURE; + } + else if (len == MGMLIS3MDL::SETUP_REPLY_LEN) { + *foundLen = len; + *foundId = MGMLIS3MDL::SETUP_MGM; + } + else if (len == SINGLE_COMMAND_ANSWER_LEN) { + *foundLen = len; + *foundId = lastSentCommand; + } + else { + return DeviceHandlerIF::INVALID_DATA; + } - // Data with SPI Interface has always this answer - if (start[0] == 0b11111111) { - return RETURN_OK; - } - else { - return DeviceHandlerIF::INVALID_DATA; - } + // Data with SPI Interface has always this answer + if (start[0] == 0b11111111) { + return RETURN_OK; + } + else { + return DeviceHandlerIF::INVALID_DATA; + } } ReturnValue_t MGMHandlerLIS3MDL::interpretDeviceReply(DeviceCommandId_t id, - const uint8_t *packet) { + const uint8_t *packet) { - switch (id) { - case MGMLIS3MDL::IDENTIFY_DEVICE: { - break; - } - case MGMLIS3MDL::SETUP_MGM: { - break; - } - case MGMLIS3MDL::READ_CONFIG_AND_DATA: { - // TODO: Store configuration and sensor values in new local datasets. + switch (id) { + case MGMLIS3MDL::IDENTIFY_DEVICE: { + break; + } + case MGMLIS3MDL::SETUP_MGM: { + break; + } + case MGMLIS3MDL::READ_CONFIG_AND_DATA: { + // TODO: Store configuration and sensor values in new local datasets. - uint8_t scale = getFullScale(registers[2]); - float sensitivityFactor = getSensitivityFactor(scale); + uint8_t scale = getFullScale(registers[2]); + float sensitivityFactor = getSensitivityFactor(scale); - int16_t mgmMeasurementRawX = packet[MGMLIS3MDL::X_HIGHBYTE_IDX] << 8 - | packet[MGMLIS3MDL::X_LOWBYTE_IDX] ; - int16_t mgmMeasurementRawY = packet[MGMLIS3MDL::Y_HIGHBYTE_IDX] << 8 - | packet[MGMLIS3MDL::Y_LOWBYTE_IDX] ; - int16_t mgmMeasurementRawZ = packet[MGMLIS3MDL::Z_HIGHBYTE_IDX] << 8 - | packet[MGMLIS3MDL::Z_LOWBYTE_IDX] ; + int16_t mgmMeasurementRawX = packet[MGMLIS3MDL::X_HIGHBYTE_IDX] << 8 + | packet[MGMLIS3MDL::X_LOWBYTE_IDX] ; + int16_t mgmMeasurementRawY = packet[MGMLIS3MDL::Y_HIGHBYTE_IDX] << 8 + | packet[MGMLIS3MDL::Y_LOWBYTE_IDX] ; + int16_t mgmMeasurementRawZ = packet[MGMLIS3MDL::Z_HIGHBYTE_IDX] << 8 + | packet[MGMLIS3MDL::Z_LOWBYTE_IDX] ; - // Target value in microtesla - float mgmX = static_cast(mgmMeasurementRawX) * sensitivityFactor - * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; - float mgmY = static_cast(mgmMeasurementRawY) * sensitivityFactor - * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; - float mgmZ = static_cast(mgmMeasurementRawZ) * sensitivityFactor - * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + // Target value in microtesla + float mgmX = static_cast(mgmMeasurementRawX) * sensitivityFactor + * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + float mgmY = static_cast(mgmMeasurementRawY) * sensitivityFactor + * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + float mgmZ = static_cast(mgmMeasurementRawZ) * sensitivityFactor + * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; #if OBSW_ENHANCED_PRINTOUT == 1 - if(debugDivider->checkAndIncrement()) { - sif::info << "MGMHandlerLIS3: Magnetic field strength in" - " microtesla:" << std::endl; - // Set terminal to utf-8 if there is an issue with micro printout. - sif::info << "X: " << mgmX << " \xC2\xB5T" << std::endl; - sif::info << "Y: " << mgmY << " \xC2\xB5T" << std::endl; - sif::info << "Z: " << mgmZ << " \xC2\xB5T" << std::endl; - } + if(debugDivider->checkAndIncrement()) { + sif::info << "MGMHandlerLIS3: Magnetic field strength in" + " microtesla:" << std::endl; + // Set terminal to utf-8 if there is an issue with micro printout. + sif::info << "X: " << mgmX << " \xC2\xB5T" << std::endl; + sif::info << "Y: " << mgmY << " \xC2\xB5T" << std::endl; + sif::info << "Z: " << mgmZ << " \xC2\xB5T" << std::endl; + } #endif - break; - } + break; + } - case MGMLIS3MDL::READ_TEMPERATURE: { - int16_t tempValueRaw = packet[2] << 8 | packet[1]; - float tempValue = 25.0 + ((static_cast(tempValueRaw)) / 8.0); + case MGMLIS3MDL::READ_TEMPERATURE: { + int16_t tempValueRaw = packet[2] << 8 | packet[1]; + float tempValue = 25.0 + ((static_cast(tempValueRaw)) / 8.0); #if OBSW_ENHANCED_PRINTOUT == 1 - if(debugDivider->check()) { - // Set terminal to utf-8 if there is an issue with micro printout. - sif::info << "MGMHandlerLIS3: Temperature: " << tempValue<< " °C" - << std::endl; - } + if(debugDivider->check()) { + // Set terminal to utf-8 if there is an issue with micro printout. + sif::info << "MGMHandlerLIS3: Temperature: " << tempValue<< " °C" + << std::endl; + } #endif - break; - } + break; + } - default: { - return DeviceHandlerIF::UNKNOW_DEVICE_REPLY; - } + default: { + return DeviceHandlerIF::UNKNOW_DEVICE_REPLY; + } - } - return RETURN_OK; + } + return RETURN_OK; } uint8_t MGMHandlerLIS3MDL::getFullScale(uint8_t ctrlRegister2) { - bool FS0 = false; - bool FS1 = false; - if ((ctrlRegister2 >> 5) == 1) - FS0 = true; - if ((ctrlRegister2 >> 6) == 1) - FS1 = true; - if ((FS0 == true) && (FS1 == true)) - return 16; - else if ((FS0 == false) && (FS1 == true)) - return 12; - else if ((FS0 == true) && (FS1 == false)) - return 8; - else - return 4; + bool FS0 = false; + bool FS1 = false; + if ((ctrlRegister2 >> 5) == 1) + FS0 = true; + if ((ctrlRegister2 >> 6) == 1) + FS1 = true; + if ((FS0 == true) && (FS1 == true)) + return 16; + else if ((FS0 == false) && (FS1 == true)) + return 12; + else if ((FS0 == true) && (FS1 == false)) + return 8; + else + return 4; } float MGMHandlerLIS3MDL::getSensitivityFactor(uint8_t scale) { - return (float) scale / (INT16_MAX); + return (float) scale / (INT16_MAX); } ReturnValue_t MGMHandlerLIS3MDL::enableTemperatureSensor( - const uint8_t *commandData, size_t commandDataLen) { - triggerEvent(CHANGE_OF_SETUP_PARAMETER); - uint32_t size = 2; - commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1); - if (commandDataLen > 1) { - return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; - } - switch (*commandData) { - case (MGMLIS3MDL::ON): - commandBuffer[1] = registers[0] | (1 << 7); - break; + const uint8_t *commandData, size_t commandDataLen) { + triggerEvent(CHANGE_OF_SETUP_PARAMETER); + uint32_t size = 2; + commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1); + if (commandDataLen > 1) { + return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; + } + switch (*commandData) { + case (MGMLIS3MDL::ON): + commandBuffer[1] = registers[0] | (1 << 7); + break; - case (MGMLIS3MDL::OFF): - commandBuffer[1] = registers[0] & ~(1 << 7); - break; + case (MGMLIS3MDL::OFF): + commandBuffer[1] = registers[0] & ~(1 << 7); + break; - default: - return INVALID_COMMAND_PARAMETER; - break; - } - registers[0] = commandBuffer[1]; + default: + return INVALID_COMMAND_PARAMETER; + break; + } + registers[0] = commandBuffer[1]; - rawPacket = commandBuffer; - rawPacketLen = size; + rawPacket = commandBuffer; + rawPacketLen = size; - return RETURN_OK; + return RETURN_OK; } ReturnValue_t MGMHandlerLIS3MDL::setOperatingMode(const uint8_t *commandData, - size_t commandDataLen) { - triggerEvent(CHANGE_OF_SETUP_PARAMETER); - if (commandDataLen != 1) { - return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; - } + size_t commandDataLen) { + triggerEvent(CHANGE_OF_SETUP_PARAMETER); + if (commandDataLen != 1) { + return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; + } - switch (commandData[0]) { - case MGMLIS3MDL::LOW: - registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) & (~(1 << MGMLIS3MDL::OM0)); - registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) & (~(1 << MGMLIS3MDL::OMZ0)); - break; - case MGMLIS3MDL::MEDIUM: - registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) | (1 << MGMLIS3MDL::OM0); - registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) | (1 << MGMLIS3MDL::OMZ0); - break; + switch (commandData[0]) { + case MGMLIS3MDL::LOW: + registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) & (~(1 << MGMLIS3MDL::OM0)); + registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) & (~(1 << MGMLIS3MDL::OMZ0)); + break; + case MGMLIS3MDL::MEDIUM: + registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) | (1 << MGMLIS3MDL::OM0); + registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) | (1 << MGMLIS3MDL::OMZ0); + break; - case MGMLIS3MDL::HIGH: - registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) & (~(1 << MGMLIS3MDL::OM0)); - registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) & (~(1 << MGMLIS3MDL::OMZ0)); - break; + case MGMLIS3MDL::HIGH: + registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) & (~(1 << MGMLIS3MDL::OM0)); + registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) & (~(1 << MGMLIS3MDL::OMZ0)); + break; - case MGMLIS3MDL::ULTRA: - registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) | (1 << MGMLIS3MDL::OM0); - registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) | (1 << MGMLIS3MDL::OMZ0); - break; - default: - break; - } + case MGMLIS3MDL::ULTRA: + registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) | (1 << MGMLIS3MDL::OM0); + registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) | (1 << MGMLIS3MDL::OMZ0); + break; + default: + break; + } - return prepareCtrlRegisterWrite(); + return prepareCtrlRegisterWrite(); } void MGMHandlerLIS3MDL::fillCommandAndReplyMap() { - /* - * Regarding ArduinoBoard: - * Actually SPI answers directly, but as commanding ArduinoBoard the - * communication could be delayed - * SPI always has to be triggered, so there could be no periodic answer of - * the device, the device has to asked with a command, so periodic is zero. - * - * We dont read single registers, we just expect special - * reply from he Readall_MGM - */ - insertInCommandAndReplyMap(MGMLIS3MDL::READ_CONFIG_AND_DATA, 1); - insertInCommandAndReplyMap(MGMLIS3MDL::READ_TEMPERATURE, 1); - insertInCommandAndReplyMap(MGMLIS3MDL::SETUP_MGM, 1); - insertInCommandAndReplyMap(MGMLIS3MDL::IDENTIFY_DEVICE, 1); - insertInCommandAndReplyMap(MGMLIS3MDL::TEMP_SENSOR_ENABLE, 1); - insertInCommandAndReplyMap(MGMLIS3MDL::ACCURACY_OP_MODE_SET, 1); + /* + * Regarding ArduinoBoard: + * Actually SPI answers directly, but as commanding ArduinoBoard the + * communication could be delayed + * SPI always has to be triggered, so there could be no periodic answer of + * the device, the device has to asked with a command, so periodic is zero. + * + * We dont read single registers, we just expect special + * reply from he Readall_MGM + */ + insertInCommandAndReplyMap(MGMLIS3MDL::READ_CONFIG_AND_DATA, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::READ_TEMPERATURE, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::SETUP_MGM, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::IDENTIFY_DEVICE, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::TEMP_SENSOR_ENABLE, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::ACCURACY_OP_MODE_SET, 1); } ReturnValue_t MGMHandlerLIS3MDL::prepareCtrlRegisterWrite() { - commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1, true); + commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1, true); - for (size_t i = 0; i < MGMLIS3MDL::NR_OF_CTRL_REGISTERS; i++) { - commandBuffer[i + 1] = registers[i]; - } - rawPacket = commandBuffer; - rawPacketLen = MGMLIS3MDL::NR_OF_CTRL_REGISTERS + 1; + for (size_t i = 0; i < MGMLIS3MDL::NR_OF_CTRL_REGISTERS; i++) { + commandBuffer[i + 1] = registers[i]; + } + rawPacket = commandBuffer; + rawPacketLen = MGMLIS3MDL::NR_OF_CTRL_REGISTERS + 1; - // We dont have to check if this is working because we just did it - return RETURN_OK; + // We dont have to check if this is working because we just did it + return RETURN_OK; } void MGMHandlerLIS3MDL::setNormalDatapoolEntriesInvalid() { - // TODO: use new distributed datapools here. + // TODO: use new distributed datapools here. } void MGMHandlerLIS3MDL::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { @@ -403,22 +403,22 @@ void MGMHandlerLIS3MDL::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { } uint32_t MGMHandlerLIS3MDL::getTransitionDelayMs(Mode_t from, Mode_t to) { - return 5000; + return 5000; } void MGMHandlerLIS3MDL::modeChanged(void) { - internalState = STATE_NONE; + internalState = STATE_NONE; } ReturnValue_t MGMHandlerLIS3MDL::initializeLocalDataPool( - LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { - localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_X, - new PoolEntry({0.0})); - localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_Y, - new PoolEntry({0.0})); - localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_Z, - new PoolEntry({0.0})); - localDataPoolMap.emplace(MGMLIS3MDL::TEMPERATURE_CELCIUS, - new PoolEntry({0.0})); - return HasReturnvaluesIF::RETURN_OK; + LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_X, + new PoolEntry({0.0})); + localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_Y, + new PoolEntry({0.0})); + localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_Z, + new PoolEntry({0.0})); + localDataPoolMap.emplace(MGMLIS3MDL::TEMPERATURE_CELCIUS, + new PoolEntry({0.0})); + return HasReturnvaluesIF::RETURN_OK; } diff --git a/mission/devices/MGMHandlerLIS3MDL.h b/mission/devices/MGMHandlerLIS3MDL.h index 4c06e001..ff95268c 100644 --- a/mission/devices/MGMHandlerLIS3MDL.h +++ b/mission/devices/MGMHandlerLIS3MDL.h @@ -3,13 +3,12 @@ #include "devicedefinitions/MGMHandlerLIS3Definitions.h" -#include +#include +#include #include #include -#include - /** * @brief Device handler object for the LIS3MDL 3-axis magnetometer * by STMicroeletronics @@ -20,10 +19,10 @@ class MGMHandlerLIS3MDL: public DeviceHandlerBase { public: - enum class CommunicationStep { - DATA, - TEMPERATURE - }; + enum class CommunicationStep { + DATA, + TEMPERATURE + }; static const uint8_t INTERFACE_ID = CLASS_ID::MGM_LIS3MDL; static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MGM_LIS3MDL; @@ -31,7 +30,7 @@ public: static const Event CHANGE_OF_SETUP_PARAMETER = MAKE_EVENT(0, severity::LOW); MGMHandlerLIS3MDL(uint32_t objectId, object_id_t deviceCommunication, - CookieIF* comCookie); + CookieIF* comCookie); virtual ~MGMHandlerLIS3MDL(); protected: @@ -45,18 +44,18 @@ protected: DeviceCommandId_t deviceCommand, const uint8_t *commandData, size_t commandDataLen) override; virtual ReturnValue_t buildTransitionDeviceCommand( - DeviceCommandId_t *id) override; + DeviceCommandId_t *id) override; virtual ReturnValue_t buildNormalDeviceCommand( - DeviceCommandId_t *id) override; + DeviceCommandId_t *id) override; virtual ReturnValue_t scanForReply(const uint8_t *start, size_t len, - DeviceCommandId_t *foundId, size_t *foundLen) override; + DeviceCommandId_t *foundId, size_t *foundLen) override; virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) override; virtual void fillCommandAndReplyMap() override; virtual void modeChanged(void) override; void setNormalDatapoolEntriesInvalid() override; ReturnValue_t initializeLocalDataPool(LocalDataPool &localDataPoolMap, - LocalDataPoolManager &poolManager) override; + LocalDataPoolManager &poolManager) override; private: @@ -164,7 +163,7 @@ private: bool commandExecuted = false; #if OBSW_ENHANCED_PRINTOUT == 1 - PeriodicOperationDivider* debugDivider; + PeriodicOperationDivider* debugDivider; #endif }; From 54c11f65037fd452fb923b215733c0d3ebad4a02 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 14 Dec 2020 22:23:28 +0100 Subject: [PATCH 026/360] formatting --- mission/devices/MGMHandlerLIS3MDL.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/mission/devices/MGMHandlerLIS3MDL.cpp b/mission/devices/MGMHandlerLIS3MDL.cpp index acc6d749..3fa9e9ec 100644 --- a/mission/devices/MGMHandlerLIS3MDL.cpp +++ b/mission/devices/MGMHandlerLIS3MDL.cpp @@ -308,17 +308,16 @@ ReturnValue_t MGMHandlerLIS3MDL::enableTemperatureSensor( return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; } switch (*commandData) { - case (MGMLIS3MDL::ON): - commandBuffer[1] = registers[0] | (1 << 7); - break; - - case (MGMLIS3MDL::OFF): - commandBuffer[1] = registers[0] & ~(1 << 7); - break; - + case (MGMLIS3MDL::ON): { + commandBuffer[1] = registers[0] | (1 << 7); + break; + } + case (MGMLIS3MDL::OFF): { + commandBuffer[1] = registers[0] & ~(1 << 7); + break; + } default: return INVALID_COMMAND_PARAMETER; - break; } registers[0] = commandBuffer[1]; From df992638cca8b75a2db693a34cc1e9ce1637a129 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 14 Dec 2020 22:50:15 +0100 Subject: [PATCH 027/360] stuff stored in local poo lnow --- mission/devices/MGMHandlerLIS3MDL.cpp | 17 +++++++++++++++-- mission/devices/MGMHandlerLIS3MDL.h | 2 +- .../MGMHandlerLIS3Definitions.h | 8 ++++---- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/mission/devices/MGMHandlerLIS3MDL.cpp b/mission/devices/MGMHandlerLIS3MDL.cpp index 3fa9e9ec..1cc83bf8 100644 --- a/mission/devices/MGMHandlerLIS3MDL.cpp +++ b/mission/devices/MGMHandlerLIS3MDL.cpp @@ -3,7 +3,8 @@ MGMHandlerLIS3MDL::MGMHandlerLIS3MDL(object_id_t objectId, object_id_t deviceCommunication, CookieIF* comCookie): - DeviceHandlerBase(objectId, deviceCommunication, comCookie) { + DeviceHandlerBase(objectId, deviceCommunication, comCookie), + dataset(this) { #if OBSW_ENHANCED_PRINTOUT == 1 debugDivider = new PeriodicOperationDivider(10); #endif @@ -253,6 +254,13 @@ ReturnValue_t MGMHandlerLIS3MDL::interpretDeviceReply(DeviceCommandId_t id, sif::info << "Z: " << mgmZ << " \xC2\xB5T" << std::endl; } #endif + ReturnValue_t result = dataset.read(20); + if(result == HasReturnvaluesIF::RETURN_OK) { + dataset.fieldStrengthX = mgmX; + dataset.fieldStrengthY = mgmY; + dataset.fieldStrengthZ = mgmZ; + dataset.commit(20); + } break; } @@ -266,6 +274,11 @@ ReturnValue_t MGMHandlerLIS3MDL::interpretDeviceReply(DeviceCommandId_t id, << std::endl; } #endif + ReturnValue_t result = dataset.read(20); + if(result == HasReturnvaluesIF::RETURN_OK) { + dataset.temperature = tempValue; + dataset.commit(20); + } break; } @@ -371,7 +384,7 @@ void MGMHandlerLIS3MDL::fillCommandAndReplyMap() { * We dont read single registers, we just expect special * reply from he Readall_MGM */ - insertInCommandAndReplyMap(MGMLIS3MDL::READ_CONFIG_AND_DATA, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::READ_CONFIG_AND_DATA, 1, &dataset); insertInCommandAndReplyMap(MGMLIS3MDL::READ_TEMPERATURE, 1); insertInCommandAndReplyMap(MGMLIS3MDL::SETUP_MGM, 1); insertInCommandAndReplyMap(MGMLIS3MDL::IDENTIFY_DEVICE, 1); diff --git a/mission/devices/MGMHandlerLIS3MDL.h b/mission/devices/MGMHandlerLIS3MDL.h index ff95268c..b400daee 100644 --- a/mission/devices/MGMHandlerLIS3MDL.h +++ b/mission/devices/MGMHandlerLIS3MDL.h @@ -18,7 +18,6 @@ */ class MGMHandlerLIS3MDL: public DeviceHandlerBase { public: - enum class CommunicationStep { DATA, TEMPERATURE @@ -59,6 +58,7 @@ protected: private: + MGMLIS3MDL::MgmPrimaryDataset dataset; /*------------------------------------------------------------------------*/ /* Device specific commands and variables */ diff --git a/mission/devices/devicedefinitions/MGMHandlerLIS3Definitions.h b/mission/devices/devicedefinitions/MGMHandlerLIS3Definitions.h index 2518af15..581e46e3 100644 --- a/mission/devices/devicedefinitions/MGMHandlerLIS3Definitions.h +++ b/mission/devices/devicedefinitions/MGMHandlerLIS3Definitions.h @@ -130,7 +130,7 @@ static const uint8_t BDU = 6; //Block data update static const uint8_t FAST_READ = 7; //Fast read enabled = 1 static const uint8_t CTRL_REG5_DEFAULT = 0; -static const uint32_t MGM_DATA_SET_ID = 0; +static const uint32_t MGM_DATA_SET_ID = READ_CONFIG_AND_DATA; enum MgmPoolIds: lp_id_t { FIELD_STRENGTH_X, @@ -147,11 +147,11 @@ public: MgmPrimaryDataset(object_id_t mgmId): StaticLocalDataSet(sid_t(mgmId, MGM_DATA_SET_ID)) {} - lp_var_t angVelocityX = lp_var_t(sid.objectId, + lp_var_t fieldStrengthX = lp_var_t(sid.objectId, FIELD_STRENGTH_X, this); - lp_var_t angVelocityY = lp_var_t(sid.objectId, + lp_var_t fieldStrengthY = lp_var_t(sid.objectId, FIELD_STRENGTH_Y, this); - lp_var_t angVelocityZ = lp_var_t(sid.objectId, + lp_var_t fieldStrengthZ = lp_var_t(sid.objectId, FIELD_STRENGTH_Z, this); lp_var_t temperature = lp_var_t(sid.objectId, TEMPERATURE_CELCIUS, this); From 1757c0fc37cc81d651f28d527ff61a6b2eb9adff Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 14 Dec 2020 22:52:53 +0100 Subject: [PATCH 028/360] updated obsw config --- bsp_hosted/fsfwconfig/OBSWConfig.h | 7 ++++--- fsfwconfig/OBSWConfig.h | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/bsp_hosted/fsfwconfig/OBSWConfig.h b/bsp_hosted/fsfwconfig/OBSWConfig.h index 9e11424b..edfa1bca 100644 --- a/bsp_hosted/fsfwconfig/OBSWConfig.h +++ b/bsp_hosted/fsfwconfig/OBSWConfig.h @@ -6,9 +6,10 @@ #ifndef CONFIG_OBSWCONFIG_H_ #define CONFIG_OBSWCONFIG_H_ -#define ADD_TEST_FOLDER 1 +#define OBSW_ADD_TEST_CODE 0 -// Define not used yet, PUS stack and TMTC tasks are always started -#define ADD_PUS_STACK 1 +// These defines should be disabled for mission code but are useful for +// debugging. +#define OBSW_ENHANCED_PRINTOUT 1 #endif /* CONFIG_OBSWCONFIG_H_ */ diff --git a/fsfwconfig/OBSWConfig.h b/fsfwconfig/OBSWConfig.h index 6d181093..d8784551 100644 --- a/fsfwconfig/OBSWConfig.h +++ b/fsfwconfig/OBSWConfig.h @@ -6,9 +6,10 @@ #ifndef FSFWCONFIG_OBSWCONFIG_H_ #define FSFWCONFIG_OBSWCONFIG_H_ -#define OBSW_ADD_TEST_CODE 0 +#define OBSW_ADD_TEST_CODE 0 -// Define not used yet, PUS stack and TMTC tasks are always started -#define ADD_PUS_STACK 1 +// These defines should be disabled for mission code but are useful for +// debugging. +#define OBSW_ENHANCED_PRINTOUT 1 #endif /* FSFWCONFIG_OBSWCONFIG_H_ */ From 62747e83aa1a3919260022a025835f995a5540ec Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Wed, 16 Dec 2020 10:56:32 +0100 Subject: [PATCH 029/360] working parameter getting and setting of p60dock --- README.md | 8 ++ bsp_linux/comIF/CspComIF.cpp | 17 ++-- mission/devices/P60DockHandler.cpp | 64 ++++++++++++--- .../devicedefinitions/GomSpacePackets.h | 81 ++++++++++--------- tmtc | 2 +- 5 files changed, 119 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index b70e1cd6..f4d5c5f5 100644 --- a/README.md +++ b/README.md @@ -339,4 +339,12 @@ x values: 1,2 or 4 param table x ```` Table 4 lists HK parameters +Changing parameters +First switch to table where parameter shall be changed (here table id is 1) +```` +p60-dock # param mem 1 +p60-dock # param set out_en[0] 1 +p60-dock # param get out_en[0] +GET out_en[0] = 1 +```` diff --git a/bsp_linux/comIF/CspComIF.cpp b/bsp_linux/comIF/CspComIF.cpp index e7616bba..00f11c7e 100644 --- a/bsp_linux/comIF/CspComIF.cpp +++ b/bsp_linux/comIF/CspComIF.cpp @@ -157,13 +157,18 @@ ReturnValue_t CspComIF::cspTransfer(uint8_t cspAddress, uint8_t cspPort, csp_conn_t * conn = csp_connect(CSP_PRIO_HIGH, cspAddress, cspPort, 0, CSP_O_NONE); - querySize = 14; - int receivedBytes = csp_transaction_persistent(conn, timeout_ms, + int result = csp_transaction_persistent(conn, timeout_ms, tmpCmdBuffer, cmdBufferLen, replyBuffer, querySize); - if(receivedBytes != querySize){ - sif::error << "CSP transfer failed to receive all requested bytes " - << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; + if(querySize != 0){ + if(result != querySize){ + sif::error << "CSP transfer failed to receive all requested bytes " + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + } else { + if(result != 1){ + sif::error << "CSP transfer failed" << std::endl; + } } csp_close(conn); diff --git a/mission/devices/P60DockHandler.cpp b/mission/devices/P60DockHandler.cpp index f1950f50..8263165b 100644 --- a/mission/devices/P60DockHandler.cpp +++ b/mission/devices/P60DockHandler.cpp @@ -37,6 +37,50 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( break; } case(PARAM_SET):{ + SetParamMessageUnpacker setParamMessageUnpacker(commandData, + commandDataLen); + uint8_t tableId = setParamMessageUnpacker.getTableId(); + uint16_t address = EndianConverter::convertLittleEndian( + setParamMessageUnpacker.getAddress()); + uint16_t checksum = GOMSPACE::IGNORE_CHECKSUM; + uint16_t seq = 0; + uint16_t total = 0; + /* Reply only comprises the transaction state */ + uint16_t querySize = 1; + const uint8_t* parameterPtr = setParamMessageUnpacker.getParameter(); + uint8_t parameterSize = setParamMessageUnpacker.getParameterSize(); + uint32_t parameter; + parameter = *parameterPtr; + switch(parameterSize) { + case(sizeof(uint16_t)): { + parameter = EndianConverter::convertLittleEndian( + (uint16_t)parameter); + break; + } + case(sizeof(uint32_t)): { + parameter = EndianConverter::convertLittleEndian( + parameter); + break; + } + default: + break; + } + uint16_t payloadlength = EndianConverter::convertLittleEndian( + sizeof(address) + parameterSize); + CspSetParamCommand setParamCmd(querySize, PARAM_SET, tableId, payloadlength, + checksum, seq, total, address, (uint8_t*) ¶meter, + parameterSize); + size_t cspPacketLen = 0; + uint8_t* buffer = cspPacket; + setParamCmd.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), + SerializeIF::Endianness::BIG); + if(cspPacketLen > MAX_PACKET_LEN){ + sif::error << "P60DockHandler: Received invalid set parameter " + "command" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + rawPacket = cspPacket; + rawPacketLen = cspPacketLen; break; } case(PARAM_GET):{ @@ -50,7 +94,7 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( uint16_t checksum = GOMSPACE::IGNORE_CHECKSUM; uint16_t seq = 0; uint16_t total = 0; - uint16_t querySize = getParamMessage.getQuerySize() + uint16_t querySize = getParamMessage.getParameterSize() + CspGetParamCommand::GS_HDR_LENGTH; /* Generate the CSP command to send to the P60 Dock */ CspGetParamCommand getParamCmd(querySize, PARAM_GET, tableId, length, @@ -110,19 +154,19 @@ ReturnValue_t P60DockHandler::interpretDeviceReply(DeviceCommandId_t id, break; } case(PARAM_GET): { - uint16_t payloadLength = *(packet + 2); + // -2 to subtract address size from gomspace parameter reply packet + uint16_t payloadLength = (*(packet + 2) << 8 | *(packet + 3)) - 2; uint8_t tempPayloadBuffer[payloadLength]; CspGetParamReply cspGetParamReply(tempPayloadBuffer, payloadLength); - uint8_t action = cspGetParamReply.getAction(); - uint8_t tableId = cspGetParamReply.getTableId(); - uint16_t length = cspGetParamReply.getLength(); - uint16_t address = cspGetParamReply.getAddress(); size_t size = CspGetParamReply::GS_HDR_LENGTH + payloadLength; cspGetParamReply.deSerialize(&packet, &size, - SerializeIF::Endianness::LITTLE); - ParamReply paramReply(action, tableId, address, length, tempPayloadBuffer, - payloadLength); - handleDeviceTM(¶mReply, id, true, true); + SerializeIF::Endianness::BIG); + uint8_t action = cspGetParamReply.getAction(); + uint8_t tableId = cspGetParamReply.getTableId(); + uint16_t address = cspGetParamReply.getAddress(); + ParamReply paramReply(action, tableId, address, payloadLength, + tempPayloadBuffer); + handleDeviceTM(¶mReply, id, true); break; } default: diff --git a/mission/devices/devicedefinitions/GomSpacePackets.h b/mission/devices/devicedefinitions/GomSpacePackets.h index 025beeb8..4da31b08 100644 --- a/mission/devices/devicedefinitions/GomSpacePackets.h +++ b/mission/devices/devicedefinitions/GomSpacePackets.h @@ -64,13 +64,17 @@ private: */ class CspSetParamCommand : public SerialLinkedListAdapter { public: - CspSetParamCommand(uint8_t action_, uint8_t tableId_, - uint16_t addresslength_, uint16_t checksum_, uint16_t seq_, - uint16_t total_, uint16_t addr_, const uint8_t* parameters_, + + static const uint8_t GS_HDR_LENGTH = 12; + + CspSetParamCommand(uint16_t querySize_, uint8_t action_, uint8_t tableId_, + uint16_t payloadlength_, uint16_t checksum_, uint16_t seq_, + uint16_t total_, uint16_t addr_, const uint8_t* parameter_, uint8_t parameterCount_) : - action(action_), tableId(tableId_), addresslength(addresslength_), checksum( - checksum_), seq(seq_), total(total_), addr(addr_), parameters( - parameters_, parameterCount_) { + querySize(querySize_), action(action_), tableId(tableId_), payloadlength( + payloadlength_), checksum(checksum_), seq(seq_), total( + total_), addr(addr_), parameter(parameter_, + parameterCount_) { setLinks(); } @@ -81,23 +85,24 @@ private: cspPort.setNext(&querySize); querySize.setNext(&action); action.setNext(&tableId); - tableId.setNext(&addresslength); - addresslength.setNext(&checksum); + tableId.setNext(&payloadlength); + payloadlength.setNext(&checksum); checksum.setNext(&seq); - seq.setNext(&addr); - addr.setNext(¶meters); + seq.setNext(&total); + total.setNext(&addr); + addr.setNext(¶meter); } SerializeElement cspPort = GOMSPACE::PARAM_PORT; - /* Only parameters are set. No data will be queried with this command */ - SerializeElement querySize = 0; + /* Only a parameter will be set. No data will be queried with this command */ + SerializeElement querySize; SerializeElement action; SerializeElement tableId; - SerializeElement addresslength; + SerializeElement payloadlength; SerializeElement checksum; SerializeElement seq; SerializeElement total; SerializeElement addr; - SerializeElement> parameters; + SerializeElement> parameter; }; @@ -196,13 +201,17 @@ private: void setLinks() { setStart(&action); action.setNext(&tableId); - seq.setNext(&addr); + tableId.setNext(&length); + length.setNext(&checksum); + checksum.setNext(&seq); + seq.setNext(&total); + total.setNext(&addr); addr.setNext(&payload); } SerializeElement action; SerializeElement tableId; - SerializeElement length; //length of payload data + SerializeElement length; //length of address field + payload data SerializeElement checksum; SerializeElement seq; SerializeElement total; @@ -226,8 +235,9 @@ public: * data will be stored. */ ParamReply(uint8_t action_, uint8_t tableId_, uint16_t addr_, - uint16_t length_, uint8_t* payloadBuffer_, uint8_t payloadBufferSz_) : - payload(payloadBuffer_, payloadBufferSz_) { + uint16_t payloadLength_, uint8_t* payloadBuffer_) : + action(action_), tableId(tableId_), addr(addr_), payloadLength( + payloadLength_), payload(payloadBuffer_, payloadLength) { setLinks(); } @@ -237,14 +247,14 @@ private: setStart(&action); action.setNext(&tableId); tableId.setNext(&addr); - addr.setNext(&length); - length.setNext(&payload); + addr.setNext(&payloadLength); + payloadLength.setNext(&payload); } SerializeElement action; SerializeElement tableId; SerializeElement addr; - SerializeElement length; - SerializeElement> payload; + SerializeElement payloadLength; + SerializeElement> payload; }; @@ -261,8 +271,8 @@ public: SerializeIF::Endianness::BIG); SerializeAdapter::deSerialize(&address, &commandData, &commandDataLen, SerializeIF::Endianness::BIG); - parameterBuffer = commandData; - parameterCount = commandDataLen; + parameter = commandData; + parameterSize = commandDataLen; } uint8_t getTableId() const { @@ -273,12 +283,12 @@ public: return address; } - const uint8_t* getParameters() { - return parameterBuffer; + const uint8_t* getParameter() { + return parameter; } - uint8_t getParameterCount(){ - return parameterCount; + uint8_t getParameterSize(){ + return parameterSize; } @@ -286,10 +296,8 @@ private: SetParamMessageUnpacker(const SetParamMessageUnpacker &message); uint8_t tableId; uint16_t address; - /* Parameter buffer holds the values of the parameters to set while the - * address points to the location of a parameter. */ - const uint8_t * parameterBuffer; - uint8_t parameterCount; + const uint8_t * parameter; + uint8_t parameterSize; }; @@ -306,7 +314,7 @@ public: SerializeIF::Endianness::BIG); SerializeAdapter::deSerialize(&address, &commandData, &commandDataLen, SerializeIF::Endianness::BIG); - SerializeAdapter::deSerialize(&querySize, &commandData, &commandDataLen, + SerializeAdapter::deSerialize(¶meterSize, &commandData, &commandDataLen, SerializeIF::Endianness::BIG); } @@ -318,8 +326,8 @@ public: return address; } - uint8_t getQuerySize(){ - return querySize; + uint8_t getParameterSize(){ + return parameterSize; } @@ -327,7 +335,8 @@ private: GetParamMessageUnpacker(const GetParamMessageUnpacker &message); uint8_t tableId; uint16_t address; //The memory address offset within the table - uint8_t querySize; //defines number of bytes to query + /* The size of the requested value (e.g. temperature is a uint16_t value) */ + uint8_t parameterSize; }; diff --git a/tmtc b/tmtc index 0c0e0595..1bfde844 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 0c0e0595f177b8fe4100902058a10e8d5ad34663 +Subproject commit 1bfde84450f47a028ca831a4dfa8c84cbd4d1fab From b9151fbd6eed292aa6ee2604c0ed154138a726e3 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Wed, 16 Dec 2020 11:02:49 +0100 Subject: [PATCH 030/360] successful change of endian swapping in p60dock param set --- mission/devices/P60DockHandler.cpp | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/mission/devices/P60DockHandler.cpp b/mission/devices/P60DockHandler.cpp index 8263165b..a7f9b820 100644 --- a/mission/devices/P60DockHandler.cpp +++ b/mission/devices/P60DockHandler.cpp @@ -40,8 +40,7 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( SetParamMessageUnpacker setParamMessageUnpacker(commandData, commandDataLen); uint8_t tableId = setParamMessageUnpacker.getTableId(); - uint16_t address = EndianConverter::convertLittleEndian( - setParamMessageUnpacker.getAddress()); + uint16_t address = setParamMessageUnpacker.getAddress(); uint16_t checksum = GOMSPACE::IGNORE_CHECKSUM; uint16_t seq = 0; uint16_t total = 0; @@ -49,26 +48,9 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( uint16_t querySize = 1; const uint8_t* parameterPtr = setParamMessageUnpacker.getParameter(); uint8_t parameterSize = setParamMessageUnpacker.getParameterSize(); - uint32_t parameter; - parameter = *parameterPtr; - switch(parameterSize) { - case(sizeof(uint16_t)): { - parameter = EndianConverter::convertLittleEndian( - (uint16_t)parameter); - break; - } - case(sizeof(uint32_t)): { - parameter = EndianConverter::convertLittleEndian( - parameter); - break; - } - default: - break; - } - uint16_t payloadlength = EndianConverter::convertLittleEndian( - sizeof(address) + parameterSize); + uint16_t payloadlength = sizeof(address) + parameterSize; CspSetParamCommand setParamCmd(querySize, PARAM_SET, tableId, payloadlength, - checksum, seq, total, address, (uint8_t*) ¶meter, + checksum, seq, total, address, parameterPtr, parameterSize); size_t cspPacketLen = 0; uint8_t* buffer = cspPacket; From 3ae7675d7d443868219830fa7040c7ae359ec30c Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 16 Dec 2020 14:05:38 +0100 Subject: [PATCH 031/360] fsfw update --- fsfw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsfw b/fsfw index b232a8a2..74c49e14 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit b232a8a2919841b331b43c84a7fb2ae80f93186f +Subproject commit 74c49e1481a4d40ad37eb6ad3d6404ae9b52629d From 28eb6333f529e4350b7e7314023b710ed5de89df Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Wed, 16 Dec 2020 15:17:10 +0100 Subject: [PATCH 032/360] ping test --- bsp_linux/comIF/CspComIF.cpp | 2 +- mission/devices/P60DockHandler.cpp | 45 ++++++++++-- mission/devices/P60DockHandler.h | 2 + .../devicedefinitions/GomSpacePackets.h | 73 +++++++++++++++++-- 4 files changed, 107 insertions(+), 15 deletions(-) diff --git a/bsp_linux/comIF/CspComIF.cpp b/bsp_linux/comIF/CspComIF.cpp index 00f11c7e..afebeb83 100644 --- a/bsp_linux/comIF/CspComIF.cpp +++ b/bsp_linux/comIF/CspComIF.cpp @@ -86,7 +86,6 @@ ReturnValue_t CspComIF::sendMessage(CookieIF *cookie, SerializeAdapter::deSerialize(&querySize, &sendData, &sendLen, SerializeIF::Endianness::BIG); uint8_t cspAddress = cspCookie->getCspAddress(); - if(cspPort == csp_reserved_ports_e::CSP_PING){ uint32_t timeout = 1000; // ms unsigned int pingSize = 100; // 100 bytes @@ -168,6 +167,7 @@ ReturnValue_t CspComIF::cspTransfer(uint8_t cspAddress, uint8_t cspPort, } else { if(result != 1){ sif::error << "CSP transfer failed" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; } } diff --git a/mission/devices/P60DockHandler.cpp b/mission/devices/P60DockHandler.cpp index a7f9b820..cf584039 100644 --- a/mission/devices/P60DockHandler.cpp +++ b/mission/devices/P60DockHandler.cpp @@ -34,6 +34,22 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( size_t commandDataLen) { switch(deviceCommand) { case(PING): { + PingMessageUnpacker pingMessageUnpacker(commandData, commandDataLen); + const uint8_t* pingData = pingMessageUnpacker.getPingData(); + uint8_t pingDataSz = pingMessageUnpacker.getPingDataSz(); + CspPingCommand cspPingCommand(pingDataSz, pingData); + size_t cspPacketLen = 0; + uint8_t* buffer = cspPacket; + cspPingCommand.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), + SerializeIF::Endianness::BIG); + if(cspPacketLen > MAX_PACKET_LEN){ + sif::error << "P60DockHandler: Received invalid ping message" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + rawPacket = cspPacket; + rawPacketLen = cspPacketLen; + rememberCommandId = PING; break; } case(PARAM_SET):{ @@ -63,16 +79,16 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( } rawPacket = cspPacket; rawPacketLen = cspPacketLen; + rememberRequestedSize = querySize; + rememberCommandId = PARAM_SET; break; } case(PARAM_GET):{ /* Unpack the received action message */ GetParamMessageUnpacker getParamMessage(commandData, commandDataLen); uint8_t tableId = getParamMessage.getTableId(); - uint16_t address = EndianConverter::convertLittleEndian( - getParamMessage.getAddress()); - uint16_t length = EndianConverter::convertLittleEndian( - sizeof(address)); + uint16_t address = getParamMessage.getAddress(); + uint16_t length = sizeof(address); uint16_t checksum = GOMSPACE::IGNORE_CHECKSUM; uint16_t seq = 0; uint16_t total = 0; @@ -113,7 +129,7 @@ ReturnValue_t P60DockHandler::scanForReply(const uint8_t *start, switch(rememberCommandId) { case(PING): *foundId = PING; - *foundLen = rememberRequestedSize; + *foundLen = PING_REPLY_SIZE; rememberCommandId = NONE; break; case(PARAM_GET): { @@ -122,6 +138,12 @@ ReturnValue_t P60DockHandler::scanForReply(const uint8_t *start, rememberCommandId = NONE; break; } + case(PARAM_SET): { + *foundId = PARAM_SET; + *foundLen = rememberRequestedSize; + rememberCommandId = NONE; + break; + } default: return IGNORE_REPLY_DATA; } @@ -132,13 +154,15 @@ ReturnValue_t P60DockHandler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) { switch(id) { case(PING): { - handleDeviceTM((SerializeIF*)packet, id, true, true); + PingReply pingReply(*packet, *(packet + 1)); + handleDeviceTM(&pingReply, id, true, true); break; } case(PARAM_GET): { // -2 to subtract address size from gomspace parameter reply packet uint16_t payloadLength = (*(packet + 2) << 8 | *(packet + 3)) - 2; uint8_t tempPayloadBuffer[payloadLength]; + /* Extract information from received data */ CspGetParamReply cspGetParamReply(tempPayloadBuffer, payloadLength); size_t size = CspGetParamReply::GS_HDR_LENGTH + payloadLength; cspGetParamReply.deSerialize(&packet, &size, @@ -146,11 +170,20 @@ ReturnValue_t P60DockHandler::interpretDeviceReply(DeviceCommandId_t id, uint8_t action = cspGetParamReply.getAction(); uint8_t tableId = cspGetParamReply.getTableId(); uint16_t address = cspGetParamReply.getAddress(); + /* Pack relevant information into a tm reply packet */ ParamReply paramReply(action, tableId, address, payloadLength, tempPayloadBuffer); handleDeviceTM(¶mReply, id, true); break; } + case(PARAM_SET): { + /* When setting a parameter, the p60dock sends back the state of the + * operation */ + if(*packet != PARAM_SET_OK){ + return HasReturnvaluesIF::RETURN_FAILED; + } + break; + } default: break; } diff --git a/mission/devices/P60DockHandler.h b/mission/devices/P60DockHandler.h index abb61ba4..3c4cb3bb 100644 --- a/mission/devices/P60DockHandler.h +++ b/mission/devices/P60DockHandler.h @@ -34,6 +34,8 @@ protected: private: static const uint8_t MAX_PACKET_LEN = 36; + static const uint8_t PARAM_SET_OK = 1; + static const uint8_t PING_REPLY_SIZE = 2; /* Device commands are derived from the rparam.h of the gomspace lib */ static const DeviceCommandId_t PING = 0x1; //!< [EXPORT] : [COMMAND] static const DeviceCommandId_t NONE = 0x2; // Set when no command is pending diff --git a/mission/devices/devicedefinitions/GomSpacePackets.h b/mission/devices/devicedefinitions/GomSpacePackets.h index 4da31b08..88977a86 100644 --- a/mission/devices/devicedefinitions/GomSpacePackets.h +++ b/mission/devices/devicedefinitions/GomSpacePackets.h @@ -6,7 +6,7 @@ #include "fsfw/serialize/SerialLinkedListAdapter.h" namespace GOMSPACE{ - static const uint16_t IGNORE_CHECKSUM = 0xb00b; + static const uint16_t IGNORE_CHECKSUM = 0xbb0; /* CSP port to ping gomspace devices. */ static const uint8_t PING_PORT = 1; static const uint8_t REBOOT_PORT = 4; @@ -16,14 +16,15 @@ namespace GOMSPACE{ /** * @brief A serial linked list adapter implementation to generate ping - * messages for gomspace devices. + * commands for devices supporting the CSP protocol. This command can + * be sent to the CspComIF which will send out the ping request. * * @details A ping request simply sends back the received data provided by the * data buffer. cspPort and querySize are only informations required * by the CspComI and other than the data array not physically * transmitted to the target device. */ -class CspPing : public SerialLinkedListAdapter { +class CspPingCommand : public SerialLinkedListAdapter { public: /** * @brief Constructor @@ -32,16 +33,14 @@ public: * Amounts to the number of bytes send. * @param parameters_ Pointer to data which should be sent to the device. * All data will be sent back by the ping target. - * @param paramterCount_ Number of bytes to send with the ping request. */ - CspPing(uint16_t querySize_, const uint8_t* parameters_, - uint8_t parameterCount_) : - querySize(querySize_), data(parameters_, parameterCount_) { + CspPingCommand(uint16_t querySize_, const uint8_t* parameters_) : + querySize(querySize_), data(parameters_, querySize_) { setLinks(); } private: - CspPing(const CspPing &command); + CspPingCommand(const CspPingCommand &command); void setLinks() { setStart(&cspPort); cspPort.setNext(&querySize); @@ -258,6 +257,28 @@ private: }; +/** + * @brief This class generates telemetry packets containing data from + * CSP get-parameter-replies. + */ +class PingReply : public SerialLinkedListAdapter { +public: + PingReply(uint8_t action_, uint8_t replyTime_) : + action(action_), replyTime(replyTime_) { + setLinks(); + } + +private: + PingReply(const PingReply &reply); + void setLinks() { + setStart(&action); + action.setNext(&replyTime); + } + SerializeElement action; + SerializeElement replyTime; +}; + + /** * @brief This class helps to unpack information from an action messages * to set a parameter in gomspace devices. The action message can be @@ -340,4 +361,40 @@ private: }; +/** + * @brief This class helps to extract the information of a message received + * from an other software component (e.g. the service 8) to generate + * a ping request for gomspace devices. + */ +class PingMessageUnpacker: public SerialLinkedListAdapter { +public: + + PingMessageUnpacker(const uint8_t* commandData, size_t commandDataLen) { + SerializeAdapter::deSerialize(&action, &commandData, &commandDataLen, + SerializeIF::Endianness::BIG); + pingData = commandData; + pingDataSz = commandDataLen; + } + + uint8_t getAction() const { + return action; + } + + const uint8_t* getPingData() { + return pingData; + } + + uint8_t getPingDataSz(){ + return pingDataSz; + } + + +private: + PingMessageUnpacker(const PingMessageUnpacker &message); + uint8_t action; + const uint8_t * pingData; + uint8_t pingDataSz; +}; + + #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEPACKETS_H_ */ From 771adb37431e446f8aebbc75becdfa9c4145a42e Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Thu, 17 Dec 2020 13:26:00 +0100 Subject: [PATCH 033/360] p60 dock handler completed --- bsp_linux/comIF/CspComIF.cpp | 22 +++-- bsp_linux/comIF/CspComIF.h | 10 +- mission/devices/P60DockHandler.cpp | 40 ++++++-- mission/devices/P60DockHandler.h | 2 + .../devicedefinitions/GomSpacePackets.h | 93 ++++++------------- 5 files changed, 91 insertions(+), 76 deletions(-) diff --git a/bsp_linux/comIF/CspComIF.cpp b/bsp_linux/comIF/CspComIF.cpp index afebeb83..77b52c1e 100644 --- a/bsp_linux/comIF/CspComIF.cpp +++ b/bsp_linux/comIF/CspComIF.cpp @@ -86,7 +86,8 @@ ReturnValue_t CspComIF::sendMessage(CookieIF *cookie, SerializeAdapter::deSerialize(&querySize, &sendData, &sendLen, SerializeIF::Endianness::BIG); uint8_t cspAddress = cspCookie->getCspAddress(); - if(cspPort == csp_reserved_ports_e::CSP_PING){ + switch(cspPort) { + case(Ports::CSP_PING): { uint32_t timeout = 1000; // ms unsigned int pingSize = 100; // 100 bytes uint32_t replyTime = csp_ping(cspAddress, timeout, pingSize, @@ -96,11 +97,15 @@ ReturnValue_t CspComIF::sendMessage(CookieIF *cookie, /* Store reply time in reply buffer * */ uint8_t* replyBuffer = cspDeviceMap[cspAddress].data(); memcpy(replyBuffer, &replyTime, sizeof(replyTime)); + replySize = sizeof(replyTime); + break; } - else if(cspPort == csp_reserved_ports_e::CSP_REBOOT){ - csp_reboot(cspCookie->getCspAddress()); + case(Ports::CSP_REBOOT): { + csp_reboot(cspAddress); + break; } - else{ + case(Ports::P60_PORT_GNDWDT_RESET): + case(Ports::P60_PORT_RPARAM): { /* No CSP fixed port was selected. Send data to the specified port and * wait for querySize number of bytes */ result = cspTransfer(cspAddress, cspPort, sendData, sendLen, @@ -108,7 +113,12 @@ ReturnValue_t CspComIF::sendMessage(CookieIF *cookie, if(result != HasReturnvaluesIF::RETURN_OK){ return HasReturnvaluesIF::RETURN_FAILED; } - rememberQuerySize = querySize; + replySize = querySize; + break; + } + default: + sif::error << "CspComIF: Invalid port specified" << std::endl; + break; } return HasReturnvaluesIF::RETURN_OK; } @@ -135,7 +145,7 @@ ReturnValue_t CspComIF::readReceivedMessage(CookieIF *cookie, uint8_t cspAddress = cspCookie->getCspAddress(); *buffer = cspDeviceMap[cspAddress].data(); - *size = rememberQuerySize; + *size = replySize; return HasReturnvaluesIF::RETURN_OK; } diff --git a/bsp_linux/comIF/CspComIF.h b/bsp_linux/comIF/CspComIF.h index 4fb24226..fd4057a8 100644 --- a/bsp_linux/comIF/CspComIF.h +++ b/bsp_linux/comIF/CspComIF.h @@ -46,6 +46,14 @@ private: ReturnValue_t cspTransfer(uint8_t cspAddress, uint8_t cspPort, const uint8_t* cmdBuffer, int cmdBufferLen, uint16_t querySize); + enum Ports { + CSP_PING = 1, + CSP_REBOOT = 4, + P60_PORT_RPARAM = 7, + P60_PORT_GNDWDT_RESET = 9 + }; + + typedef uint8_t node_t; using vectorBuffer = std::vector; using VectorBufferMap = std::unordered_map; @@ -54,7 +62,7 @@ private: /* In this map assigns reply buffers to a CSP device */ VectorBufferMap cspDeviceMap; - uint16_t rememberQuerySize = 0; + uint16_t replySize = 0; /* This is the CSP address of the OBC. */ node_t cspClientAddress = 1; diff --git a/mission/devices/P60DockHandler.cpp b/mission/devices/P60DockHandler.cpp index cf584039..c6cff969 100644 --- a/mission/devices/P60DockHandler.cpp +++ b/mission/devices/P60DockHandler.cpp @@ -34,10 +34,9 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( size_t commandDataLen) { switch(deviceCommand) { case(PING): { - PingMessageUnpacker pingMessageUnpacker(commandData, commandDataLen); - const uint8_t* pingData = pingMessageUnpacker.getPingData(); - uint8_t pingDataSz = pingMessageUnpacker.getPingDataSz(); - CspPingCommand cspPingCommand(pingDataSz, pingData); + const uint8_t* pingData = commandData; + uint8_t pingDataSz = commandDataLen; + CspPingCommand cspPingCommand(pingData, pingDataSz); size_t cspPacketLen = 0; uint8_t* buffer = cspPacket; cspPingCommand.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), @@ -52,6 +51,16 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( rememberCommandId = PING; break; } + case(REBOOT): { + uint8_t cspPort = GOMSPACE::REBOOT_PORT; + uint16_t querySize = 0; + *cspPacket = GOMSPACE::REBOOT_PORT; + *(cspPacket + 1) = querySize; + size_t cspPacketLen = sizeof(cspPort) + sizeof(cspPacketLen); + rawPacket = cspPacket; + rawPacketLen = cspPacketLen; + break; + } case(PARAM_SET):{ SetParamMessageUnpacker setParamMessageUnpacker(commandData, commandDataLen); @@ -112,6 +121,23 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( rememberCommandId = PARAM_GET; break; } + case(GNDWDT_RESET): { + WatchdogResetCommand watchdogResetCommand; + size_t cspPacketLen = 0; + uint8_t* buffer = cspPacket; + watchdogResetCommand.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), + SerializeIF::Endianness::BIG); + if(cspPacketLen > MAX_PACKET_LEN){ + sif::error << "P60DockHandler: Received invalid ground watchdog" + "reset command" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + rawPacket = cspPacket; + rawPacketLen = cspPacketLen; + rememberRequestedSize = 0; // No bytes will be queried with the ground + // watchdog command. + rememberCommandId = GNDWDT_RESET; + } default: break; } @@ -120,8 +146,10 @@ ReturnValue_t P60DockHandler::buildCommandFromCommand( void P60DockHandler::fillCommandAndReplyMap(){ this->insertInCommandAndReplyMap(PING, 3); + this->insertInCommandMap(REBOOT); this->insertInCommandAndReplyMap(PARAM_SET, 3); this->insertInCommandAndReplyMap(PARAM_GET, 3); + this->insertInCommandMap(GNDWDT_RESET); } ReturnValue_t P60DockHandler::scanForReply(const uint8_t *start, @@ -154,8 +182,8 @@ ReturnValue_t P60DockHandler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) { switch(id) { case(PING): { - PingReply pingReply(*packet, *(packet + 1)); - handleDeviceTM(&pingReply, id, true, true); + SerializeElement replyTime = *packet; + handleDeviceTM(&replyTime, id, true); break; } case(PARAM_GET): { diff --git a/mission/devices/P60DockHandler.h b/mission/devices/P60DockHandler.h index 3c4cb3bb..8f3a2f77 100644 --- a/mission/devices/P60DockHandler.h +++ b/mission/devices/P60DockHandler.h @@ -39,6 +39,8 @@ private: /* Device commands are derived from the rparam.h of the gomspace lib */ static const DeviceCommandId_t PING = 0x1; //!< [EXPORT] : [COMMAND] static const DeviceCommandId_t NONE = 0x2; // Set when no command is pending + static const DeviceCommandId_t REBOOT = 0x4; //!< [EXPORT] : [COMMAND] + static const DeviceCommandId_t GNDWDT_RESET = 0x9; //!< [EXPORT] : [COMMAND] static const DeviceCommandId_t PARAM_GET = 0x00; //!< [EXPORT] : [COMMAND] static const DeviceCommandId_t PARAM_SET = 0xFF; //!< [EXPORT] : [COMMAND] diff --git a/mission/devices/devicedefinitions/GomSpacePackets.h b/mission/devices/devicedefinitions/GomSpacePackets.h index 88977a86..e41ea162 100644 --- a/mission/devices/devicedefinitions/GomSpacePackets.h +++ b/mission/devices/devicedefinitions/GomSpacePackets.h @@ -12,8 +12,35 @@ namespace GOMSPACE{ static const uint8_t REBOOT_PORT = 4; /* CSP port of gomspace devices to request or set parameters */ static const uint8_t PARAM_PORT = 7; + static const uint8_t P60_PORT_GNDWDT_RESET = 9; } + +/** + * @brief This class can be used to generated the command for the CspComIF + * to reset the watchdog in a gomspace device. + */ +class WatchdogResetCommand : public SerialLinkedListAdapter { +public: + + WatchdogResetCommand() { + setLinks(); + } + +private: + WatchdogResetCommand(const WatchdogResetCommand &command); + void setLinks() { + setStart(&cspPort); + cspPort.setNext(&querySize); + querySize.setNext(&magic); + } + SerializeElement cspPort = GOMSPACE::P60_PORT_GNDWDT_RESET; + SerializeElement querySize = 1; + /* Sending 0x78 to port 9 of a gomspace device resets the ground watchdog */ + SerializeElement magic = 0x78; +}; + + /** * @brief A serial linked list adapter implementation to generate ping * commands for devices supporting the CSP protocol. This command can @@ -31,11 +58,11 @@ public: * * @param querySize_ The size of bytes replied by the ping request. * Amounts to the number of bytes send. - * @param parameters_ Pointer to data which should be sent to the device. + * @param data_ Pointer to data which should be sent to the device. * All data will be sent back by the ping target. */ - CspPingCommand(uint16_t querySize_, const uint8_t* parameters_) : - querySize(querySize_), data(parameters_, querySize_) { + CspPingCommand(const uint8_t* data_, uint16_t querySize_) : + querySize(querySize_), data(data_, querySize_) { setLinks(); } @@ -256,29 +283,6 @@ private: SerializeElement> payload; }; - -/** - * @brief This class generates telemetry packets containing data from - * CSP get-parameter-replies. - */ -class PingReply : public SerialLinkedListAdapter { -public: - PingReply(uint8_t action_, uint8_t replyTime_) : - action(action_), replyTime(replyTime_) { - setLinks(); - } - -private: - PingReply(const PingReply &reply); - void setLinks() { - setStart(&action); - action.setNext(&replyTime); - } - SerializeElement action; - SerializeElement replyTime; -}; - - /** * @brief This class helps to unpack information from an action messages * to set a parameter in gomspace devices. The action message can be @@ -360,41 +364,4 @@ private: uint8_t parameterSize; }; - -/** - * @brief This class helps to extract the information of a message received - * from an other software component (e.g. the service 8) to generate - * a ping request for gomspace devices. - */ -class PingMessageUnpacker: public SerialLinkedListAdapter { -public: - - PingMessageUnpacker(const uint8_t* commandData, size_t commandDataLen) { - SerializeAdapter::deSerialize(&action, &commandData, &commandDataLen, - SerializeIF::Endianness::BIG); - pingData = commandData; - pingDataSz = commandDataLen; - } - - uint8_t getAction() const { - return action; - } - - const uint8_t* getPingData() { - return pingData; - } - - uint8_t getPingDataSz(){ - return pingDataSz; - } - - -private: - PingMessageUnpacker(const PingMessageUnpacker &message); - uint8_t action; - const uint8_t * pingData; - uint8_t pingDataSz; -}; - - #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEPACKETS_H_ */ From 7b1308342c88820b9263b6f47b3fb7a12f6a80bc Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Thu, 17 Dec 2020 14:19:05 +0100 Subject: [PATCH 034/360] updated tmtc --- tmtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmtc b/tmtc index 1bfde844..345a0252 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 1bfde84450f47a028ca831a4dfa8c84cbd4d1fab +Subproject commit 345a02520ca885065bf6220d48319d2f1c310496 From 37b0249ef7cc22387eaecc77557896d5824a2940 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Thu, 17 Dec 2020 14:27:49 +0100 Subject: [PATCH 035/360] added tmtc --- tmtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmtc b/tmtc index 3fc71f90..345a0252 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 3fc71f9094e8fb670942f0c29a9dea0b6e03d17f +Subproject commit 345a02520ca885065bf6220d48319d2f1c310496 From cbe7ec69c970abd6e4227f75803b1f9b2130ce5e Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Thu, 17 Dec 2020 15:49:11 +0100 Subject: [PATCH 036/360] tmtc p60dock --- tmtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmtc b/tmtc index 345a0252..9342f773 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 345a02520ca885065bf6220d48319d2f1c310496 +Subproject commit 9342f773115856843b167225236b04a061602174 From 8ce6b44c31f70d5279947e88667e4af9852df81a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 17 Dec 2020 17:44:54 +0100 Subject: [PATCH 037/360] fsfw update --- fsfw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsfw b/fsfw index 74c49e14..086cbe1e 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 74c49e1481a4d40ad37eb6ad3d6404ae9b52629d +Subproject commit 086cbe1e3950cf6c904609352408a7fa48cc83ef From 1152e81a774fa022737e5692013b13ecfb03d2bf Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 17 Dec 2020 17:45:42 +0100 Subject: [PATCH 038/360] tmtc update --- tmtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmtc b/tmtc index 4463efcf..345a0252 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 4463efcf7bfd2181a78eff66fca82c335aeea1d1 +Subproject commit 345a02520ca885065bf6220d48319d2f1c310496 From f0f4464ec9054d93945804eee6959b2fa020c7cf Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 17 Dec 2020 17:46:11 +0100 Subject: [PATCH 039/360] removed tmtc submodule, will be replaced --- .gitmodules | 3 --- tmtc | 1 - 2 files changed, 4 deletions(-) delete mode 160000 tmtc diff --git a/.gitmodules b/.gitmodules index 8b5921a8..6d834ef0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "etl"] path = etl url = https://github.com/ETLCPP/etl.git -[submodule "tmtc"] - path = tmtc - url = https://git.ksat-stuttgart.de/Robin.Mueller/tmtc.git [submodule "arduino"] path = arduino url = https://egit.irs.uni-stuttgart.de/eive/eive_arduino_interface.git diff --git a/tmtc b/tmtc deleted file mode 160000 index 345a0252..00000000 --- a/tmtc +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 345a02520ca885065bf6220d48319d2f1c310496 From cc569bdec405426e73d76b5b0a108b7fa06707b9 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 17 Dec 2020 17:47:40 +0100 Subject: [PATCH 040/360] added new tmtc submodule --- .gitmodules | 3 +++ tmtc | 1 + 2 files changed, 4 insertions(+) create mode 160000 tmtc diff --git a/.gitmodules b/.gitmodules index 6d834ef0..dae431d4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "fsfw"] path = fsfw url = https://egit.irs.uni-stuttgart.de/eive/fsfw.git +[submodule "tmtc"] + path = tmtc + url = https://egit.irs.uni-stuttgart.de/eive/eive_tmtc.git diff --git a/tmtc b/tmtc new file mode 160000 index 00000000..1314992e --- /dev/null +++ b/tmtc @@ -0,0 +1 @@ +Subproject commit 1314992e326946ba281ce61846a07261cea37159 From 9613b11f590dd384286ad494fb3124dd625a4d2a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 17 Dec 2020 18:04:04 +0100 Subject: [PATCH 041/360] tmtc update --- tmtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmtc b/tmtc index 1314992e..b0f0b978 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 1314992e326946ba281ce61846a07261cea37159 +Subproject commit b0f0b9788e23360e97e9bdb4fc89473c1e48193d From 3bacafcab79159da1bf4fdebf5dfd69b53a123e2 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 17 Dec 2020 18:04:33 +0100 Subject: [PATCH 042/360] tmtc update --- tmtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmtc b/tmtc index b0f0b978..673a3e8b 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit b0f0b9788e23360e97e9bdb4fc89473c1e48193d +Subproject commit 673a3e8ba47024b940f3a118ac8bcee81a85bc2a From aaf1b1600622a7aa23e18dcad727d3ceaa1c491c Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 17 Dec 2020 18:11:40 +0100 Subject: [PATCH 043/360] tmtc points to new commit --- tmtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmtc b/tmtc index 673a3e8b..75b01009 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 673a3e8ba47024b940f3a118ac8bcee81a85bc2a +Subproject commit 75b01009f104aefe7dd1473f6c071339e67bcb37 From c5790f59b844bf865ad7667cf1a4f67a55b7e5a1 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 17 Dec 2020 18:16:49 +0100 Subject: [PATCH 044/360] tmtc update --- tmtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmtc b/tmtc index 75b01009..46ddd4dd 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 75b01009f104aefe7dd1473f6c071339e67bcb37 +Subproject commit 46ddd4ddb3b8a2214b23636b02443665cbd602f2 From 9c216e1f4257a809307213eb9d22baa9e530d514 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 17 Dec 2020 18:43:27 +0100 Subject: [PATCH 045/360] tmtc update --- tmtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmtc b/tmtc index 46ddd4dd..5e110aab 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 46ddd4ddb3b8a2214b23636b02443665cbd602f2 +Subproject commit 5e110aabff1e9841d242a6b3eb221c1a51002968 From 97e6986fac430f97ba5d99ea1d9ac526e9d5b2d5 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 17 Dec 2020 19:38:09 +0100 Subject: [PATCH 046/360] tmtc update --- fsfwconfig/tmtc/apid.h | 2 +- tmtc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fsfwconfig/tmtc/apid.h b/fsfwconfig/tmtc/apid.h index ee2fc7c4..0799abc3 100644 --- a/fsfwconfig/tmtc/apid.h +++ b/fsfwconfig/tmtc/apid.h @@ -8,7 +8,7 @@ * application process ID (APID), capable of generating telemetry source * packets and receiving telecommand packets * - * SOURCE APID: 0x73 / 115 / s + * EIVE APID: 0x65 / 101 / e * APID is a 11 bit number */ namespace apid { diff --git a/tmtc b/tmtc index 5e110aab..e0c896e6 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 5e110aabff1e9841d242a6b3eb221c1a51002968 +Subproject commit e0c896e62d25286d00599ca57b71d0a3495ed95f From 2fa60a00e7cfe8a8476094390f7c189e6238d214 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 17 Dec 2020 19:38:26 +0100 Subject: [PATCH 047/360] c++ include used --- fsfwconfig/tmtc/apid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsfwconfig/tmtc/apid.h b/fsfwconfig/tmtc/apid.h index 0799abc3..00aabee1 100644 --- a/fsfwconfig/tmtc/apid.h +++ b/fsfwconfig/tmtc/apid.h @@ -1,7 +1,7 @@ #ifndef FSFWCONFIG_TMTC_APID_H_ #define FSFWCONFIG_TMTC_APID_H_ -#include +#include /** * Application Process Definition: entity, uniquely identified by an From a60726e91cf533b84ed18ca0ccf74b1ff68dfc95 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 17 Dec 2020 19:43:20 +0100 Subject: [PATCH 048/360] updated gitignore file --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index f6adc50a..0d0e490d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ _dep .project .cproject __pycache__ + +!misc/eclipse/**/.cproject +!misc/eclipse/**/.project \ No newline at end of file From ad79ea46fdb28772028e489640180f370380405e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 17 Dec 2020 19:45:20 +0100 Subject: [PATCH 049/360] additional include for win compileation --- bsp_hosted/fsfwconfig/FSFWConfig.h | 1 + 1 file changed, 1 insertion(+) diff --git a/bsp_hosted/fsfwconfig/FSFWConfig.h b/bsp_hosted/fsfwconfig/FSFWConfig.h index 3433613c..8c6c754a 100644 --- a/bsp_hosted/fsfwconfig/FSFWConfig.h +++ b/bsp_hosted/fsfwconfig/FSFWConfig.h @@ -2,6 +2,7 @@ #define CONFIG_FSFWCONFIG_H_ #include +#include //! Used to determine whether C++ ostreams are used //! Those can lead to code bloat. From 8a91401c5254d0c24fff5c7e14835e9938ef6fd1 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 17 Dec 2020 19:47:21 +0100 Subject: [PATCH 050/360] deleted linux bsp arduino files --- bsp_linux/comIF/ArduinoComIF.cpp | 324 ------------------------------ bsp_linux/comIF/ArduinoComIF.h | 73 ------- bsp_linux/comIF/ArduinoCookie.cpp | 12 -- bsp_linux/comIF/ArduinoCookie.h | 25 --- 4 files changed, 434 deletions(-) delete mode 100644 bsp_linux/comIF/ArduinoComIF.cpp delete mode 100644 bsp_linux/comIF/ArduinoComIF.h delete mode 100644 bsp_linux/comIF/ArduinoCookie.cpp delete mode 100644 bsp_linux/comIF/ArduinoCookie.h diff --git a/bsp_linux/comIF/ArduinoComIF.cpp b/bsp_linux/comIF/ArduinoComIF.cpp deleted file mode 100644 index ffc59b47..00000000 --- a/bsp_linux/comIF/ArduinoComIF.cpp +++ /dev/null @@ -1,324 +0,0 @@ -#include "ArduinoCookie.h" -#include "ArduinoComIF.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -ArduinoCommInterface::ArduinoCommInterface(object_id_t setObjectId, - const char *serialDevice) : - spiMap(MAX_NUMBER_OF_SPI_DEVICES), rxBuffer( - MAX_PACKET_SIZE * MAX_NUMBER_OF_SPI_DEVICES*10, true), SystemObject(setObjectId) { - initialized = false; - serialPort = ::open("/dev/ttyUSB0", O_RDWR); - - if (serialPort < 0) { - //configuration error - printf("Error %i from open: %s\n", errno, strerror(errno)); - return; - } - - struct termios tty; - memset(&tty, 0, sizeof tty); - - // Read in existing settings, and handle any error - if (tcgetattr(serialPort, &tty) != 0) { - printf("Error %i from tcgetattr: %s\n", errno, strerror(errno)); - return; - } - - tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity - tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication - tty.c_cflag |= CS8; // 8 bits per byte - tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control - tty.c_lflag &= ~ICANON; //Disable Canonical Mode - tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars) - tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed - tty.c_cc[VTIME] = 0; // Non Blocking - tty.c_cc[VMIN] = 0; - - cfsetispeed(&tty, B9600); //Baudrate - - if (tcsetattr(serialPort, TCSANOW, &tty) != 0) { - //printf("Error %i from tcsetattr: %s\n", errno, strerror(errno)); - return; - } - - initialized = true; - -} - -ArduinoCommInterface::~ArduinoCommInterface() { - ::close(serialPort); -} - -ReturnValue_t ArduinoCommInterface::open(Cookie **cookie, uint32_t address, - uint32_t maxReplyLen) { - //This is a hack, will be gone with https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/19 - switch ((address >> 8) & 0xff) { - case 0: - *cookie = new ArduinoCookie(ArduinoCookie::SPI, address, maxReplyLen); - spiMap.insert(address, (ArduinoCookie*) *cookie); //Yes, I *do* know that it is an ArduinoSpiCookie, I just new'd it - break; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t ArduinoCommInterface::reOpen(Cookie *cookie, uint32_t address, - uint32_t maxReplyLen) { - //too lazy right now will be irrelevant with https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/19 - return HasReturnvaluesIF::RETURN_FAILED; -} - -void ArduinoCommInterface::close(Cookie *cookie) { - //too lazy as well, find the correct Map, delete it there, then the cookie... -} - -ReturnValue_t ArduinoCommInterface::sendMessage(Cookie *cookie, uint8_t *data, - uint32_t len) { - ArduinoCookie *arduinoCookie = dynamic_cast(cookie); - if (arduinoCookie == NULL) { - return INVALID_COOKIE_TYPE; - } - - return sendMessage(arduinoCookie->command, arduinoCookie->address, data, - len); -} - -ReturnValue_t ArduinoCommInterface::getSendSuccess(Cookie *cookie) { - return RETURN_OK; -} - -ReturnValue_t ArduinoCommInterface::requestReceiveMessage(Cookie *cookie) { - return RETURN_OK; -} - -ReturnValue_t ArduinoCommInterface::readReceivedMessage(Cookie *cookie, - uint8_t **buffer, uint32_t *size) { - - handleSerialPortRx(); - - ArduinoCookie *arduinoCookie = dynamic_cast(cookie); - if (arduinoCookie == NULL) { - return INVALID_COOKIE_TYPE; - } - - *buffer = arduinoCookie->replyBuffer; - *size = arduinoCookie->receivedDataLen; - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t ArduinoCommInterface::setAddress(Cookie *cookie, - uint32_t address) { - //not implemented - return RETURN_FAILED; -} - -uint32_t ArduinoCommInterface::getAddress(Cookie *cookie) { - //not implemented - return 0; -} - -ReturnValue_t ArduinoCommInterface::setParameter(Cookie *cookie, - uint32_t parameter) { - //not implemented - return RETURN_FAILED; -} - -uint32_t ArduinoCommInterface::getParameter(Cookie *cookie) { - //not implemented - return 0; -} - -ReturnValue_t ArduinoCommInterface::sendMessage(uint8_t command, - uint8_t address, const uint8_t *data, size_t dataLen) { - if (dataLen > UINT16_MAX) { - return TOO_MUCH_DATA; - } - - //being conservative here - uint8_t sendBuffer[(dataLen + 6) * 2 + 2]; - - sendBuffer[0] = DleEncoder::STX; - - uint8_t *currentPosition = sendBuffer + 1; - size_t remainingLen = sizeof(sendBuffer) - 1; - uint32_t encodedLen; - - ReturnValue_t result = DleEncoder::encode(&command, 1, currentPosition, - remainingLen, &encodedLen, false); - if (result != RETURN_OK) { - return result; - } - currentPosition += encodedLen; - remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen - - result = DleEncoder::encode(&address, 1, currentPosition, remainingLen, - &encodedLen, false); - if (result != RETURN_OK) { - return result; - } - currentPosition += encodedLen; - remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen - - uint8_t temporaryBuffer[2]; - - //note to Lukas: yes we _could_ use Serialize here, but for 16 bit it is a bit too much... - temporaryBuffer[0] = dataLen >> 8; //we checked dataLen above - temporaryBuffer[1] = dataLen; - - result = DleEncoder::encode(temporaryBuffer, 2, currentPosition, - remainingLen, &encodedLen, false); - if (result != RETURN_OK) { - return result; - } - currentPosition += encodedLen; - remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen - - //encoding the actual data - result = DleEncoder::encode(data, dataLen, currentPosition, remainingLen, - &encodedLen, false); - if (result != RETURN_OK) { - return result; - } - currentPosition += encodedLen; - remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen - - uint16_t crc = CRC::crc16ccitt(&command, 1); - crc = CRC::crc16ccitt(&address, 1, crc); - //fortunately the length is still there - crc = CRC::crc16ccitt(temporaryBuffer, 2, crc); - crc = CRC::crc16ccitt(data, dataLen, crc); - - temporaryBuffer[0] = crc >> 8; - temporaryBuffer[1] = crc; - - result = DleEncoder::encode(temporaryBuffer, 2, currentPosition, - remainingLen, &encodedLen, false); - if (result != RETURN_OK) { - return result; - } - currentPosition += encodedLen; - remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen - - if (remainingLen > 0) { - *currentPosition = DleEncoder::ETX; - } - remainingLen -= 1; - - encodedLen = sizeof(sendBuffer) - remainingLen; - - ssize_t writtenlen = write(serialPort, sendBuffer, encodedLen); - if (writtenlen < 0) { - //we could try to find out what happened... - return RETURN_FAILED; - } - if (writtenlen != encodedLen) { - //the OS failed us, we do not try to block until everything is written, as - //we can not block the whole system here - return RETURN_FAILED; - } - return RETURN_OK; -} - -void ArduinoCommInterface::handleSerialPortRx() { - uint32_t availableSpace = rxBuffer.availableWriteSpace(); - - uint8_t dataFromSerial[availableSpace]; - - ssize_t bytesRead = read(serialPort, dataFromSerial, - sizeof(dataFromSerial)); - - if (bytesRead < 0) { - return; - } - - rxBuffer.writeData(dataFromSerial, bytesRead); - - uint8_t dataReceivedSoFar[rxBuffer.maxSize()]; - - uint32_t dataLenReceivedSoFar = 0; - - rxBuffer.readData(dataReceivedSoFar, sizeof(dataReceivedSoFar), true, - &dataLenReceivedSoFar); - - //look for STX - size_t firstSTXinRawData = 0; - while ((firstSTXinRawData < dataLenReceivedSoFar) - && (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX)) { - firstSTXinRawData++; - } - - if (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX) { - //there is no STX in our data, throw it away... - rxBuffer.deleteData(dataLenReceivedSoFar); - return; - } - - uint8_t packet[MAX_PACKET_SIZE]; - uint32_t packetLen; - - uint32_t readSize; - - ReturnValue_t result = DleEncoder::decode( - dataReceivedSoFar + firstSTXinRawData, - dataLenReceivedSoFar - firstSTXinRawData, &readSize, packet, - sizeof(packet), &packetLen); - - size_t toDelete = firstSTXinRawData; - if (result == HasReturnvaluesIF::RETURN_OK) { - handlePacket(packet, packetLen); - - //after handling the packet, we can delete it from the raw stream, it has been copied to packet - toDelete += readSize; - } - - //remove Data which was processed - rxBuffer.deleteData(toDelete); -} - -void ArduinoCommInterface::handlePacket(uint8_t *packet, size_t packetLen) { - uint16_t crc = CRC::crc16ccitt(packet, packetLen); - if (crc != 0) { - //CRC error - return; - } - - uint8_t command = packet[0]; - uint8_t address = packet[1]; - - uint16_t size = (packet[2] << 8) + packet[3]; - - if (size != packetLen - 6) { - //Invalid Length - return; - } - - switch (command) { - case ArduinoCookie::SPI: { - ArduinoCookie **itsComplicated; - ReturnValue_t result = spiMap.find(address, &itsComplicated); - if (result != RETURN_OK) { - //we do no know this address - return; - } - ArduinoCookie *theActualCookie = *itsComplicated; - if (packetLen > theActualCookie->maxReplySize + 6) { - packetLen = theActualCookie->maxReplySize + 6; - } - memcpy(theActualCookie->replyBuffer, packet + 4, packetLen - 6); - theActualCookie->receivedDataLen = packetLen - 6; - } - break; - default: - return; - } -} diff --git a/bsp_linux/comIF/ArduinoComIF.h b/bsp_linux/comIF/ArduinoComIF.h deleted file mode 100644 index 9ab166de..00000000 --- a/bsp_linux/comIF/ArduinoComIF.h +++ /dev/null @@ -1,73 +0,0 @@ -//#ifndef MISSION_ARDUINOCOMMINTERFACE_H_ -//#define MISSION_ARDUINOCOMMINTERFACE_H_ -// -//#include -//#include -//#include -//#include -//#include -//#include -// -//#include "../../framework/objectmanager/SystemObject.h" -//#include "ArduinoCookie.h" -// -////Forward declaration, so users don't peek -//class ArduinoCookie; -// -//class ArduinoComIF: public SystemObject, -// public DeviceCommunicationIF { -//public: -// static const uint8_t MAX_NUMBER_OF_SPI_DEVICES = 8; -// static const uint8_t MAX_PACKET_SIZE = 64; -// -// static const uint8_t COMMAND_INVALID = -1; -// static const uint8_t COMMAND_SPI = 1; -// -// ArduinoComIF(object_id_t setObjectId, const char *serialDevice); -// virtual ~ArduinoComIF(); -// -// virtual ReturnValue_t open(Cookie **cookie, uint32_t address, -// uint32_t maxReplyLen); -// -// virtual ReturnValue_t reOpen(Cookie *cookie, uint32_t address, -// uint32_t maxReplyLen); -// -// virtual void close(Cookie *cookie); -// -// //SHOULDDO can data be const? -// virtual ReturnValue_t sendMessage(Cookie *cookie, uint8_t *data, -// uint32_t len); -// -// virtual ReturnValue_t getSendSuccess(Cookie *cookie); -// -// virtual ReturnValue_t requestReceiveMessage(Cookie *cookie); -// -// virtual ReturnValue_t readReceivedMessage(Cookie *cookie, uint8_t **buffer, -// uint32_t *size); -// -// virtual ReturnValue_t setAddress(Cookie *cookie, uint32_t address); -// -// virtual uint32_t getAddress(Cookie *cookie); -// -// virtual ReturnValue_t setParameter(Cookie *cookie, uint32_t parameter); -// -// virtual uint32_t getParameter(Cookie *cookie); -//private: -// //remembering if the initialization in the ctor worked -// //if not, all calls are disabled -// bool initialized; -// int serialPort; -// //used to know where to put the data if a reply is received -// FixedMap spiMap; -// -// SimpleRingBuffer rxBuffer; -// -// ReturnValue_t sendMessage(uint8_t command, uint8_t address, -// const uint8_t *data, size_t dataLen); -// -// void handleSerialPortRx(); -// -// void handlePacket(uint8_t *packet, size_t packetLen); -//}; -// -//#endif /* MISSION_ARDUINOCOMMINTERFACE_H_ */ diff --git a/bsp_linux/comIF/ArduinoCookie.cpp b/bsp_linux/comIF/ArduinoCookie.cpp deleted file mode 100644 index d7e81192..00000000 --- a/bsp_linux/comIF/ArduinoCookie.cpp +++ /dev/null @@ -1,12 +0,0 @@ -//#include -// -//ArduinoCookie::ArduinoCookie(Protocol_t protocol, uint8_t address, -// size_t maxReplySize) : -// command(protocol), address(address), receivedDataLen(0), maxReplySize( -// maxReplySize) { -// replyBuffer = new uint8_t[maxReplySize]; -//} -// -//ArduinoCookie::~ArduinoCookie() { -// delete[] replyBuffer; -//} diff --git a/bsp_linux/comIF/ArduinoCookie.h b/bsp_linux/comIF/ArduinoCookie.h deleted file mode 100644 index 64eed4ad..00000000 --- a/bsp_linux/comIF/ArduinoCookie.h +++ /dev/null @@ -1,25 +0,0 @@ -//#ifndef MISSION_ARDUINO_ARDUINOCOOKIE_H_ -//#define MISSION_ARDUINO_ARDUINOCOOKIE_H_ -// -//#include -// -//#include -//#include -// -//class ArduinoCookie: public Cookie { -//public: -// enum Protocol_t { -// INVALID = 0, SPI = 1 -// }; -// ArduinoCookie(Protocol_t protocol, uint8_t address, size_t maxReplySize); -// virtual ~ArduinoCookie(); -// -// uint8_t command; -// uint8_t address; -// uint8_t *replyBuffer; -// size_t receivedDataLen; -// size_t maxReplySize; -// -//}; -// -//#endif /* MISSION_ARDUINO_ARDUINOCOOKIE_H_ */ From 4f761a4ed0e8b5384e03f6f8cb23eee9ae5120ee Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 17 Dec 2020 19:50:11 +0100 Subject: [PATCH 051/360] added eclipse project and launch files --- misc/eclipse/.cproject | 144 +++++++++++++++++++++++++ misc/eclipse/.project | 27 +++++ misc/eclipse/eive-mingw-debug.launch | 33 ++++++ misc/eclipse/eive-mingw-release.launch | 33 ++++++ 4 files changed, 237 insertions(+) create mode 100644 misc/eclipse/.cproject create mode 100644 misc/eclipse/.project create mode 100644 misc/eclipse/eive-mingw-debug.launch create mode 100644 misc/eclipse/eive-mingw-release.launch diff --git a/misc/eclipse/.cproject b/misc/eclipse/.cproject new file mode 100644 index 00000000..776ea205 --- /dev/null +++ b/misc/eclipse/.cproject @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/misc/eclipse/.project b/misc/eclipse/.project new file mode 100644 index 00000000..906c567f --- /dev/null +++ b/misc/eclipse/.project @@ -0,0 +1,27 @@ + + + eive_obsw + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/misc/eclipse/eive-mingw-debug.launch b/misc/eclipse/eive-mingw-debug.launch new file mode 100644 index 00000000..4ab7b736 --- /dev/null +++ b/misc/eclipse/eive-mingw-debug.launch @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/eclipse/eive-mingw-release.launch b/misc/eclipse/eive-mingw-release.launch new file mode 100644 index 00000000..da2f47a9 --- /dev/null +++ b/misc/eclipse/eive-mingw-release.launch @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 8d951db1696914d9acf3b4ea791ac2bae057c218 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Sun, 20 Dec 2020 13:31:44 +0100 Subject: [PATCH 052/360] issue with makefile --- Makefile | 4 +- bsp_linux/InitMission.cpp | 9 - bsp_linux/comIF/ArduinoComIF.cpp | 324 - bsp_linux/comIF/ArduinoComIF.h | 73 - bsp_linux/comIF/CspComIF.cpp | 66 +- bsp_linux/comIF/CspComIF.h | 12 + bsp_linux/comIF/P60DockComIF.cpp | 170 - bsp_linux/comIF/P60DockComIF.h | 58 - bsp_linux/comIF/cookies/ArduinoCookie.cpp | 12 - bsp_linux/comIF/cookies/ArduinoCookie.h | 25 - bsp_linux/comIF/cookies/P60DockCookie.cpp | 46 - bsp_linux/comIF/cookies/P60DockCookie.h | 51 - fsfwconfig/devices/addresses.h | 1 + fsfwconfig/objects/systemObjectList.h | 5 +- .../PollingSequenceFactory.cpp | 3 + gomspace/gomspace.mk | 22 - gomspace/libgscsp/include/gs/csp/address.h | 65 - gomspace/libgscsp/include/gs/csp/command.h | 25 - gomspace/libgscsp/include/gs/csp/conn.h | 26 - gomspace/libgscsp/include/gs/csp/csp.h | 202 - .../libgscsp/include/gs/csp/drivers/can/can.h | 54 - .../libgscsp/include/gs/csp/drivers/i2c/i2c.h | 29 - .../include/gs/csp/drivers/kiss/kiss.h | 30 - gomspace/libgscsp/include/gs/csp/error.h | 28 - .../include/gs/csp/linux/command_line.h | 24 - gomspace/libgscsp/include/gs/csp/log.h | 27 - gomspace/libgscsp/include/gs/csp/port.h | 111 - gomspace/libgscsp/include/gs/csp/router.h | 36 - gomspace/libgscsp/include/gs/csp/rtable.h | 31 - .../include/gs/csp/service_dispatcher.h | 124 - .../libgscsp/include/gs/csp/service_handler.h | 102 - gomspace/libgscsp/lib/libcsp/CHANGELOG | 113 - gomspace/libgscsp/lib/libcsp/CONTRIBUTORS | 3 - gomspace/libgscsp/lib/libcsp/COPYING | 503 - gomspace/libgscsp/lib/libcsp/INSTALL.rst | 30 - gomspace/libgscsp/lib/libcsp/README.rst | 41 - .../libcsp/bindings/python/libcsp/__init__.py | 6 - gomspace/libgscsp/lib/libcsp/doc/example.rst | 123 - gomspace/libgscsp/lib/libcsp/doc/history.rst | 17 - .../libgscsp/lib/libcsp/doc/interfaces.rst | 95 - gomspace/libgscsp/lib/libcsp/doc/libcsp.rst | 21 - gomspace/libgscsp/lib/libcsp/doc/memory.rst | 28 - gomspace/libgscsp/lib/libcsp/doc/mtu.rst | 19 - .../libgscsp/lib/libcsp/doc/protocolstack.rst | 54 - .../libgscsp/lib/libcsp/doc/structure.rst | 27 - gomspace/libgscsp/lib/libcsp/doc/topology.rst | 26 - .../lib/libcsp/examples/csp_if_fifo.c | 165 - .../lib/libcsp/examples/csp_if_fifo_windows.c | 225 - gomspace/libgscsp/lib/libcsp/examples/kiss.c | 151 - .../python_bindings_example_client.py | 42 - .../python_bindings_example_client_can.py | 30 - .../python_bindings_example_server.py | 72 - .../libgscsp/lib/libcsp/examples/simple.c | 200 - .../libgscsp/lib/libcsp/examples/zmqproxy.c | 82 - .../lib/libcsp/include/csp/arch/csp_clock.h | 60 - .../lib/libcsp/include/csp/arch/csp_malloc.h | 39 - .../lib/libcsp/include/csp/arch/csp_queue.h | 49 - .../libcsp/include/csp/arch/csp_semaphore.h | 109 - .../lib/libcsp/include/csp/arch/csp_system.h | 74 - .../lib/libcsp/include/csp/arch/csp_thread.h | 100 - .../lib/libcsp/include/csp/arch/csp_time.h | 57 - .../include/csp/arch/posix/pthread_queue.h | 118 - .../lib/libcsp/include/csp/crypto/csp_hmac.h | 73 - .../lib/libcsp/include/csp/crypto/csp_sha1.h | 81 - .../lib/libcsp/include/csp/crypto/csp_xtea.h | 52 - .../libgscsp/lib/libcsp/include/csp/csp.h | 545 - .../lib/libcsp/include/csp/csp_buffer.h | 92 - .../libgscsp/lib/libcsp/include/csp/csp_cmp.h | 189 - .../lib/libcsp/include/csp/csp_crc32.h | 63 - .../lib/libcsp/include/csp/csp_debug.h | 150 - .../lib/libcsp/include/csp/csp_endian.h | 170 - .../lib/libcsp/include/csp/csp_error.h | 50 - .../lib/libcsp/include/csp/csp_iflist.h | 56 - .../lib/libcsp/include/csp/csp_interface.h | 54 - .../lib/libcsp/include/csp/csp_platform.h | 56 - .../lib/libcsp/include/csp/csp_rtable.h | 149 - .../lib/libcsp/include/csp/csp_types.h | 235 - .../include/csp/drivers/can_socketcan.h | 22 - .../lib/libcsp/include/csp/drivers/i2c.h | 120 - .../lib/libcsp/include/csp/drivers/usart.h | 107 - .../include/csp/interfaces/csp_if_can.h | 76 - .../include/csp/interfaces/csp_if_i2c.h | 51 - .../include/csp/interfaces/csp_if_kiss.h | 110 - .../libcsp/include/csp/interfaces/csp_if_lo.h | 38 - .../include/csp/interfaces/csp_if_zmqhub.h | 26 - .../lib/libcsp/src/arch/freertos/csp_malloc.c | 33 - .../lib/libcsp/src/arch/freertos/csp_queue.c | 66 - .../libcsp/src/arch/freertos/csp_semaphore.c | 96 - .../lib/libcsp/src/arch/freertos/csp_system.c | 139 - .../lib/libcsp/src/arch/freertos/csp_thread.c | 38 - .../lib/libcsp/src/arch/freertos/csp_time.c | 46 - .../lib/libcsp/src/arch/macosx/csp_malloc.c | 31 - .../lib/libcsp/src/arch/macosx/csp_queue.c | 64 - .../libcsp/src/arch/macosx/csp_semaphore.c | 105 - .../lib/libcsp/src/arch/macosx/csp_system.c | 99 - .../lib/libcsp/src/arch/macosx/csp_thread.c | 31 - .../lib/libcsp/src/arch/macosx/csp_time.c | 65 - .../libcsp/src/arch/macosx/pthread_queue.c | 179 - .../lib/libcsp/src/arch/posix/csp_malloc.c | 31 - .../lib/libcsp/src/arch/posix/csp_queue.c | 64 - .../lib/libcsp/src/arch/posix/csp_semaphore.c | 164 - .../lib/libcsp/src/arch/posix/csp_system.c | 131 - .../lib/libcsp/src/arch/posix/csp_thread.c | 55 - .../lib/libcsp/src/arch/posix/csp_time.c | 54 - .../lib/libcsp/src/arch/posix/pthread_queue.c | 243 - .../lib/libcsp/src/arch/windows/README | 18 - .../lib/libcsp/src/arch/windows/csp_malloc.c | 9 - .../lib/libcsp/src/arch/windows/csp_queue.c | 40 - .../libcsp/src/arch/windows/csp_semaphore.c | 74 - .../lib/libcsp/src/arch/windows/csp_system.c | 60 - .../lib/libcsp/src/arch/windows/csp_thread.c | 11 - .../lib/libcsp/src/arch/windows/csp_time.c | 20 - .../libcsp/src/arch/windows/windows_glue.h | 23 - .../libcsp/src/arch/windows/windows_queue.c | 91 - .../libcsp/src/arch/windows/windows_queue.h | 41 - .../lib/libcsp/src/bindings/python/pycsp.c | 1052 -- .../libgscsp/lib/libcsp/src/crypto/csp_hmac.c | 202 - .../libgscsp/lib/libcsp/src/crypto/csp_sha1.c | 217 - .../libgscsp/lib/libcsp/src/crypto/csp_xtea.c | 134 - gomspace/libgscsp/lib/libcsp/src/csp_bridge.c | 94 - gomspace/libgscsp/lib/libcsp/src/csp_buffer.c | 224 - gomspace/libgscsp/lib/libcsp/src/csp_conn.c | 498 - gomspace/libgscsp/lib/libcsp/src/csp_conn.h | 112 - gomspace/libgscsp/lib/libcsp/src/csp_crc32.c | 140 - gomspace/libgscsp/lib/libcsp/src/csp_debug.c | 133 - gomspace/libgscsp/lib/libcsp/src/csp_dedup.c | 66 - gomspace/libgscsp/lib/libcsp/src/csp_dedup.h | 31 - gomspace/libgscsp/lib/libcsp/src/csp_endian.c | 204 - .../libgscsp/lib/libcsp/src/csp_hex_dump.c | 55 - gomspace/libgscsp/lib/libcsp/src/csp_iflist.c | 100 - gomspace/libgscsp/lib/libcsp/src/csp_io.c | 502 - gomspace/libgscsp/lib/libcsp/src/csp_io.h | 47 - gomspace/libgscsp/lib/libcsp/src/csp_port.c | 105 - gomspace/libgscsp/lib/libcsp/src/csp_port.h | 55 - .../libgscsp/lib/libcsp/src/csp_promisc.c | 82 - .../libgscsp/lib/libcsp/src/csp_promisc.h | 30 - gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c | 149 - gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h | 54 - gomspace/libgscsp/lib/libcsp/src/csp_route.c | 346 - gomspace/libgscsp/lib/libcsp/src/csp_route.h | 24 - .../lib/libcsp/src/csp_service_handler.c | 334 - .../libgscsp/lib/libcsp/src/csp_services.c | 233 - gomspace/libgscsp/lib/libcsp/src/csp_sfp.c | 170 - .../libcsp/src/drivers/can/can_socketcan.c | 201 - .../libcsp/src/drivers/usart/usart_linux.c | 254 - .../libcsp/src/drivers/usart/usart_windows.c | 230 - .../lib/libcsp/src/interfaces/csp_if_can.c | 279 - .../libcsp/src/interfaces/csp_if_can_pbuf.c | 77 - .../libcsp/src/interfaces/csp_if_can_pbuf.h | 31 - .../lib/libcsp/src/interfaces/csp_if_i2c.c | 116 - .../lib/libcsp/src/interfaces/csp_if_kiss.c | 260 - .../lib/libcsp/src/interfaces/csp_if_lo.c | 61 - .../lib/libcsp/src/interfaces/csp_if_zmqhub.c | 165 - .../lib/libcsp/src/rtable/csp_rtable_cidr.c | 233 - .../lib/libcsp/src/rtable/csp_rtable_static.c | 128 - .../lib/libcsp/src/transport/csp_rdp.c | 1102 -- .../lib/libcsp/src/transport/csp_transport.h | 46 - .../lib/libcsp/src/transport/csp_udp.c | 49 - .../libgscsp/lib/libcsp/utils/cfpsplit.py | 52 - .../libgscsp/lib/libcsp/utils/cspsplit.py | 52 - gomspace/libgscsp/lib/libcsp/waf | 170 - gomspace/libgscsp/lib/libcsp/wscript | 346 - .../libgscsp/src/bindings/python/pygscsp.c | 61 - gomspace/libgscsp/src/clock.c | 23 - gomspace/libgscsp/src/commands.c | 652 -- gomspace/libgscsp/src/conn.c | 22 - gomspace/libgscsp/src/csp.c | 91 - gomspace/libgscsp/src/drivers/can/can.c | 108 - gomspace/libgscsp/src/drivers/i2c/i2c.c | 77 - gomspace/libgscsp/src/drivers/kiss/kiss.c | 36 - gomspace/libgscsp/src/error.c | 54 - gomspace/libgscsp/src/freertos/cpu.c | 8 - gomspace/libgscsp/src/linux/command_line.c | 265 - gomspace/libgscsp/src/local.h | 21 - gomspace/libgscsp/src/log.c | 64 - gomspace/libgscsp/src/router.c | 84 - gomspace/libgscsp/src/rtable.c | 69 - gomspace/libgscsp/src/service_dispatcher.c | 213 - gomspace/libgscsp/src/service_handler.c | 86 - gomspace/libgscsp/src/transaction.c | 67 - gomspace/libgscsp/wscript | 104 - gomspace/libp60_client/include/p60.h | 48 - gomspace/libp60_client/include/p60_board.h | 35 - gomspace/libp60_client/include/power_if.h | 62 - gomspace/libp60_client/src/cmd/power_if_cmd.c | 147 - gomspace/libp60_client/src/p60_client.c | 33 - gomspace/libp60_client/src/power_if.c | 91 - gomspace/libp60_client/wscript | 28 - .../include/deprecated/param/param_client.h | 15 - .../include/deprecated/param/param_lock.h | 27 - .../deprecated/param/param_serializer.h | 55 - .../include/deprecated/param/param_string.h | 74 - .../include/deprecated/param/param_types.h | 92 - .../include/deprecated/param/rparam_client.h | 208 - .../include/gs/param/internal/pp/i2c/i2c.h | 42 - .../gs/param/internal/pp/i2c/slave_dispatch.h | 71 - .../gs/param/internal/pp/spi/slave_dispatch.h | 80 - .../include/gs/param/internal/pp/spi/spi.h | 65 - .../include/gs/param/internal/rparam.h | 146 - .../include/gs/param/internal/serialize.h | 29 - .../include/gs/param/internal/table.h | 19 - .../include/gs/param/internal/types.h | 126 - .../include/gs/param/pp/i2c/i2c.h | 60 - .../libparam_client/include/gs/param/pp/pp.h | 214 - .../include/gs/param/pp/spi/spi.h | 29 - .../libparam_client/include/gs/param/rparam.h | 395 - .../include/gs/param/serialize.h | 101 - .../libparam_client/include/gs/param/table.h | 428 - .../libparam_client/include/gs/param/types.h | 272 - .../src/bindings/python/pyparam.c | 1084 -- .../libparam_client/src/pp/cmd/master_cmd.c | 418 - gomspace/libparam_client/src/pp/i2c/i2c.c | 129 - gomspace/libparam_client/src/pp/pp.c | 189 - gomspace/libparam_client/src/pp/spi/spi.c | 91 - .../src/rparam/cmd/cmd_rparam.c | 354 - .../src/rparam/deprecated_rparam.c | 6 - gomspace/libparam_client/src/rparam/query.c | 212 - gomspace/libparam_client/src/rparam/query.h | 110 - gomspace/libparam_client/src/rparam/rparam.c | 474 - gomspace/libparam_client/src/serialize.c | 353 - .../libparam_client/src/serialize_local.h | 9 - gomspace/libparam_client/src/string.c | 589 - gomspace/libparam_client/src/table.c | 393 - gomspace/libparam_client/wscript | 69 - gomspace/libutil/include/conf_util.h | 12 - .../deprecated/gs/gosh/command/command.h | 49 - .../include/deprecated/gs/gosh/gosh/getopt.h | 22 - .../include/deprecated/gs/gosh/util/console.h | 43 - .../include/deprecated/util/color_printf.h | 26 - gomspace/libutil/include/gs/uthash/utarray.h | 231 - gomspace/libutil/include/gs/uthash/uthash.h | 960 -- gomspace/libutil/include/gs/uthash/utlist.h | 757 -- gomspace/libutil/include/gs/uthash/utstring.h | 393 - gomspace/libutil/include/gs/util/base16.h | 90 - gomspace/libutil/include/gs/util/bytebuffer.h | 173 - gomspace/libutil/include/gs/util/byteorder.h | 341 - gomspace/libutil/include/gs/util/check.h | 54 - gomspace/libutil/include/gs/util/clock.h | 88 - gomspace/libutil/include/gs/util/crc32.h | 55 - gomspace/libutil/include/gs/util/crc8.h | 55 - gomspace/libutil/include/gs/util/delay.h | 42 - .../libutil/include/gs/util/drivers/can/can.h | 122 - .../include/gs/util/drivers/gpio/gpio.h | 91 - .../include/gs/util/drivers/i2c/common.h | 88 - .../include/gs/util/drivers/i2c/master.h | 32 - .../include/gs/util/drivers/i2c/slave.h | 79 - .../include/gs/util/drivers/spi/common.h | 66 - .../include/gs/util/drivers/spi/master.h | 95 - .../include/gs/util/drivers/spi/slave.h | 84 - .../include/gs/util/drivers/sys/memory.h | 92 - .../include/gs/util/drivers/watchdog/device.h | 61 - gomspace/libutil/include/gs/util/endian.h | 53 - gomspace/libutil/include/gs/util/error.h | 199 - gomspace/libutil/include/gs/util/fletcher.h | 89 - .../include/gs/util/function_scheduler.h | 79 - .../libutil/include/gs/util/gosh/command.h | 503 - .../libutil/include/gs/util/gosh/console.h | 123 - gomspace/libutil/include/gs/util/hexdump.h | 53 - gomspace/libutil/include/gs/util/linux/argp.h | 40 - .../include/gs/util/linux/command_line.h | 42 - .../include/gs/util/linux/drivers/can/can.h | 29 - .../include/gs/util/linux/drivers/gpio/gpio.h | 146 - .../gs/util/linux/drivers/gpio/gpio_sysfs.h | 91 - .../gs/util/linux/drivers/gpio/gpio_virtual.h | 125 - .../include/gs/util/linux/drivers/i2c/i2c.h | 198 - .../include/gs/util/linux/drivers/spi/spi.h | 175 - .../libutil/include/gs/util/linux/exitcode.h | 40 - .../libutil/include/gs/util/linux/function.h | 49 - gomspace/libutil/include/gs/util/linux/rtc.h | 28 - .../libutil/include/gs/util/linux/signal.h | 40 - .../include/gs/util/linux/sysfs_helper.h | 30 - gomspace/libutil/include/gs/util/log.h | 15 - .../include/gs/util/log/appender/appender.h | 189 - .../include/gs/util/log/appender/console.h | 57 - .../gs/util/log/appender/simple_file.h | 41 - gomspace/libutil/include/gs/util/log/log.h | 853 -- gomspace/libutil/include/gs/util/minmax.h | 67 - gomspace/libutil/include/gs/util/mutex.h | 63 - gomspace/libutil/include/gs/util/pgm.h | 162 - gomspace/libutil/include/gs/util/queue.h | 102 - gomspace/libutil/include/gs/util/rtc.h | 62 - gomspace/libutil/include/gs/util/sem.h | 75 - gomspace/libutil/include/gs/util/stdio.h | 117 - gomspace/libutil/include/gs/util/string.h | 391 - .../libutil/include/gs/util/test/cmocka.h | 136 - .../libutil/include/gs/util/test/command.h | 80 - gomspace/libutil/include/gs/util/test/log.h | 88 - gomspace/libutil/include/gs/util/thread.h | 173 - gomspace/libutil/include/gs/util/time.h | 95 - gomspace/libutil/include/gs/util/timestamp.h | 73 - gomspace/libutil/include/gs/util/types.h | 114 - gomspace/libutil/include/gs/util/unistd.h | 32 - gomspace/libutil/include/gs/util/vmem.h | 194 - .../include/gs/util/watchdog/watchdog.h | 143 - .../include/gs/util/watchdog/watchdog_task.h | 45 - gomspace/libutil/include/gs/util/zip/zip.h | 62 - gomspace/libutil/src/base16.c | 61 - gomspace/libutil/src/bindings/python/pyutil.c | 73 - gomspace/libutil/src/bytebuffer.c | 128 - gomspace/libutil/src/byteorder.c | 323 - gomspace/libutil/src/clock.c | 113 - gomspace/libutil/src/crc32.c | 79 - gomspace/libutil/src/crc8.c | 68 - gomspace/libutil/src/drivers/can/can.c | 6 - gomspace/libutil/src/drivers/i2c/i2c.c | 6 - gomspace/libutil/src/drivers/spi/spi.c | 6 - gomspace/libutil/src/drivers/sys/memory.c | 37 - gomspace/libutil/src/error.c | 106 - gomspace/libutil/src/fletcher.c | 77 - gomspace/libutil/src/function_scheduler.c | 111 - gomspace/libutil/src/gosh/command.c | 754 -- gomspace/libutil/src/gosh/command_local.h | 35 - gomspace/libutil/src/gosh/console.c | 758 -- gomspace/libutil/src/gosh/console_local.h | 10 - gomspace/libutil/src/gosh/default_commands.c | 277 - gomspace/libutil/src/gosh/getopt.c | 55 - gomspace/libutil/src/hexdump.c | 92 - gomspace/libutil/src/linux/argp.c | 34 - gomspace/libutil/src/linux/clock.c | 68 - gomspace/libutil/src/linux/command_line.c | 76 - gomspace/libutil/src/linux/cwd.c | 28 - gomspace/libutil/src/linux/delay.c | 22 - gomspace/libutil/src/linux/drivers/can/can.c | 308 - .../libutil/src/linux/drivers/gpio/gpio.c | 102 - .../src/linux/drivers/gpio/gpio_sysfs.c | 145 - .../src/linux/drivers/gpio/gpio_virtual.c | 171 - gomspace/libutil/src/linux/drivers/i2c/i2c.c | 144 - gomspace/libutil/src/linux/drivers/spi/spi.c | 137 - .../libutil/src/linux/drivers/sys/memory.c | 30 - gomspace/libutil/src/linux/function.c | 41 - gomspace/libutil/src/linux/mutex.c | 59 - gomspace/libutil/src/linux/queue.c | 217 - gomspace/libutil/src/linux/rtc.c | 78 - gomspace/libutil/src/linux/sem.c | 89 - gomspace/libutil/src/linux/signal.c | 38 - gomspace/libutil/src/linux/stdio.c | 36 - gomspace/libutil/src/linux/sysfs_helper.c | 48 - gomspace/libutil/src/linux/thread.c | 89 - gomspace/libutil/src/linux/time.c | 53 - gomspace/libutil/src/lock.c | 30 - gomspace/libutil/src/lock.h | 14 - gomspace/libutil/src/log/appender/console.c | 88 - .../libutil/src/log/appender/simple_file.c | 117 - gomspace/libutil/src/log/commands.c | 392 - gomspace/libutil/src/log/local.h | 27 - gomspace/libutil/src/log/log.c | 705 -- gomspace/libutil/src/rtc.c | 42 - gomspace/libutil/src/stdio.c | 81 - gomspace/libutil/src/string.c | 746 -- gomspace/libutil/src/strtoint.c | 399 - gomspace/libutil/src/test/cmocka.c | 63 - gomspace/libutil/src/test/command.c | 176 - gomspace/libutil/src/test/log.c | 165 - gomspace/libutil/src/time.c | 28 - gomspace/libutil/src/timestamp.c | 61 - gomspace/libutil/src/vmem/commands.c | 123 - gomspace/libutil/src/vmem/vmem.c | 143 - gomspace/libutil/src/watchdog/local.h | 18 - gomspace/libutil/src/watchdog/monitor_task.c | 68 - gomspace/libutil/src/watchdog/watchdog.c | 292 - .../libutil/src/zip/cppcheck-suppress.txt | 5 - .../libutil/src/zip/miniz/LIST_OF_CHANGES | 9429 ----------------- gomspace/libutil/src/zip/miniz/miniz.c | 7572 ------------- gomspace/libutil/src/zip/miniz/miniz.h | 1329 --- gomspace/libutil/src/zip/zip.c | 357 - gomspace/libutil/wscript | 109 - .../include/gs/p60-dock/param/p60dock.h | 47 - .../include/gs/p60-dock/param/p60dock_cal.h | 35 - .../include/gs/p60-dock/param/p60dock_hk.h | 50 - .../include/gs/p60-dock/param/p60dock_param.h | 69 - gomspace/p60-dock_client/src/p60dock_client.c | 147 - gomspace/p60-dock_client/wscript | 34 - .../bindings/python/libcsp/__init__.py | 0 {gomspace/libcsp => libcsp}/doc/example.rst | 0 {gomspace/libcsp => libcsp}/doc/history.rst | 0 .../libcsp => libcsp}/doc/interfaces.rst | 0 {gomspace/libcsp => libcsp}/doc/libcsp.rst | 0 {gomspace/libcsp => libcsp}/doc/memory.rst | 0 {gomspace/libcsp => libcsp}/doc/mtu.rst | 0 .../libcsp => libcsp}/doc/protocolstack.rst | 0 {gomspace/libcsp => libcsp}/doc/structure.rst | 0 {gomspace/libcsp => libcsp}/doc/topology.rst | 0 .../libcsp => libcsp}/examples/csp_if_fifo.c | 0 .../examples/csp_if_fifo_windows.c | 0 {gomspace/libcsp => libcsp}/examples/kiss.c | 0 .../python_bindings_example_client.py | 0 .../python_bindings_example_client_can.py | 0 .../python_bindings_example_server.py | 0 {gomspace/libcsp => libcsp}/examples/simple.c | 0 .../libcsp => libcsp}/examples/zmqproxy.c | 0 .../include/csp/arch/csp_clock.h | 0 .../include/csp/arch/csp_malloc.h | 0 .../include/csp/arch/csp_queue.h | 0 .../include/csp/arch/csp_semaphore.h | 0 .../include/csp/arch/csp_system.h | 0 .../include/csp/arch/csp_thread.h | 0 .../include/csp/arch/csp_time.h | 0 .../include/csp/arch/posix/pthread_queue.h | 0 .../include/csp/crypto/csp_hmac.h | 0 .../include/csp/crypto/csp_sha1.h | 0 .../include/csp/crypto/csp_xtea.h | 0 {gomspace/libcsp => libcsp}/include/csp/csp.h | 0 .../include/csp/csp_autoconfig.h | 0 .../include/csp/csp_buffer.h | 0 .../libcsp => libcsp}/include/csp/csp_cmp.h | 0 .../libcsp => libcsp}/include/csp/csp_crc32.h | 0 .../libcsp => libcsp}/include/csp/csp_debug.h | 0 .../include/csp/csp_endian.h | 0 .../libcsp => libcsp}/include/csp/csp_error.h | 0 .../include/csp/csp_iflist.h | 0 .../include/csp/csp_interface.h | 0 .../include/csp/csp_platform.h | 0 .../include/csp/csp_rtable.h | 0 .../libcsp => libcsp}/include/csp/csp_types.h | 0 .../include/csp/drivers/can_socketcan.h | 0 .../include/csp/drivers/i2c.h | 0 .../include/csp/drivers/usart.h | 0 .../include/csp/interfaces/csp_if_can.h | 0 .../include/csp/interfaces/csp_if_i2c.h | 0 .../include/csp/interfaces/csp_if_kiss.h | 0 .../include/csp/interfaces/csp_if_lo.h | 0 .../include/csp/interfaces/csp_if_zmqhub.h | 0 libcsp/libcsp.mk | 12 + .../src/arch/freertos/csp_malloc.c | 0 .../src/arch/freertos/csp_queue.c | 0 .../src/arch/freertos/csp_semaphore.c | 0 .../src/arch/freertos/csp_system.c | 0 .../src/arch/freertos/csp_thread.c | 0 .../src/arch/freertos/csp_time.c | 0 .../src/arch/macosx/csp_malloc.c | 0 .../src/arch/macosx/csp_queue.c | 0 .../src/arch/macosx/csp_semaphore.c | 0 .../src/arch/macosx/csp_system.c | 0 .../src/arch/macosx/csp_thread.c | 0 .../src/arch/macosx/csp_time.c | 0 .../src/arch/macosx/pthread_queue.c | 0 .../src/arch/posix/csp_malloc.c | 0 .../src/arch/posix/csp_queue.c | 0 .../src/arch/posix/csp_semaphore.c | 0 .../src/arch/posix/csp_system.c | 0 .../src/arch/posix/csp_thread.c | 0 .../src/arch/posix/csp_time.c | 0 .../src/arch/posix/pthread_queue.c | 0 .../libcsp => libcsp}/src/arch/windows/README | 0 .../src/arch/windows/csp_malloc.c | 0 .../src/arch/windows/csp_queue.c | 0 .../src/arch/windows/csp_semaphore.c | 0 .../src/arch/windows/csp_system.c | 0 .../src/arch/windows/csp_thread.c | 0 .../src/arch/windows/csp_time.c | 0 .../src/arch/windows/windows_glue.h | 0 .../src/arch/windows/windows_queue.c | 0 .../src/arch/windows/windows_queue.h | 0 .../src/bindings/python/pycsp.c | 0 .../libcsp => libcsp}/src/crypto/csp_hmac.c | 0 .../libcsp => libcsp}/src/crypto/csp_sha1.c | 0 .../libcsp => libcsp}/src/crypto/csp_xtea.c | 0 {gomspace/libcsp => libcsp}/src/csp_bridge.c | 0 {gomspace/libcsp => libcsp}/src/csp_buffer.c | 0 {gomspace/libcsp => libcsp}/src/csp_conn.c | 0 {gomspace/libcsp => libcsp}/src/csp_conn.h | 0 {gomspace/libcsp => libcsp}/src/csp_crc32.c | 0 {gomspace/libcsp => libcsp}/src/csp_debug.c | 0 {gomspace/libcsp => libcsp}/src/csp_dedup.c | 0 {gomspace/libcsp => libcsp}/src/csp_dedup.h | 0 {gomspace/libcsp => libcsp}/src/csp_endian.c | 0 .../libcsp => libcsp}/src/csp_hex_dump.c | 0 {gomspace/libcsp => libcsp}/src/csp_iflist.c | 0 {gomspace/libcsp => libcsp}/src/csp_io.c | 0 {gomspace/libcsp => libcsp}/src/csp_io.h | 0 {gomspace/libcsp => libcsp}/src/csp_port.c | 0 {gomspace/libcsp => libcsp}/src/csp_port.h | 0 {gomspace/libcsp => libcsp}/src/csp_promisc.c | 0 {gomspace/libcsp => libcsp}/src/csp_promisc.h | 0 {gomspace/libcsp => libcsp}/src/csp_qfifo.c | 0 {gomspace/libcsp => libcsp}/src/csp_qfifo.h | 0 {gomspace/libcsp => libcsp}/src/csp_route.c | 0 {gomspace/libcsp => libcsp}/src/csp_route.h | 0 .../src/csp_service_handler.c | 0 .../libcsp => libcsp}/src/csp_services.c | 0 {gomspace/libcsp => libcsp}/src/csp_sfp.c | 0 .../src/drivers/can/can_socketcan.c | 0 .../src/drivers/usart/usart_linux.c | 0 .../src/drivers/usart/usart_windows.c | 0 .../src/interfaces/csp_if_can.c | 0 .../src/interfaces/csp_if_can_pbuf.c | 0 .../src/interfaces/csp_if_can_pbuf.h | 0 .../src/interfaces/csp_if_i2c.c | 0 .../src/interfaces/csp_if_kiss.c | 0 .../src/interfaces/csp_if_lo.c | 0 .../src/rtable/csp_rtable_cidr.c | 0 .../src/rtable/csp_rtable_static.c | 0 .../libcsp => libcsp}/src/transport/csp_rdp.c | 0 .../src/transport/csp_transport.h | 0 .../libcsp => libcsp}/src/transport/csp_udp.c | 0 {gomspace/libcsp => libcsp}/utils/cfpsplit.py | 0 {gomspace/libcsp => libcsp}/utils/cspsplit.py | 0 mission/core/GenericFactory.cpp | 12 +- mission/devices/GomspaceDeviceHandler.cpp | 323 + mission/devices/GomspaceDeviceHandler.h | 108 + mission/devices/P60DockHandler.cpp | 225 - mission/devices/P60DockHandler.h | 52 - .../devicedefinitions/GomSpacePackets.h | 85 +- .../devicedefinitions/GomspaceDefinitions.h | 24 + .../P60DockHandlerDefinitions.h | 90 - test/testtasks/P60DockTestTask.cpp | 109 - test/testtasks/P60DockTestTask.h | 55 - 507 files changed, 585 insertions(+), 66403 deletions(-) delete mode 100644 bsp_linux/comIF/ArduinoComIF.cpp delete mode 100644 bsp_linux/comIF/ArduinoComIF.h delete mode 100644 bsp_linux/comIF/P60DockComIF.cpp delete mode 100644 bsp_linux/comIF/P60DockComIF.h delete mode 100644 bsp_linux/comIF/cookies/ArduinoCookie.cpp delete mode 100644 bsp_linux/comIF/cookies/ArduinoCookie.h delete mode 100644 bsp_linux/comIF/cookies/P60DockCookie.cpp delete mode 100644 bsp_linux/comIF/cookies/P60DockCookie.h delete mode 100644 gomspace/gomspace.mk delete mode 100644 gomspace/libgscsp/include/gs/csp/address.h delete mode 100644 gomspace/libgscsp/include/gs/csp/command.h delete mode 100644 gomspace/libgscsp/include/gs/csp/conn.h delete mode 100644 gomspace/libgscsp/include/gs/csp/csp.h delete mode 100644 gomspace/libgscsp/include/gs/csp/drivers/can/can.h delete mode 100644 gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h delete mode 100644 gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h delete mode 100644 gomspace/libgscsp/include/gs/csp/error.h delete mode 100644 gomspace/libgscsp/include/gs/csp/linux/command_line.h delete mode 100644 gomspace/libgscsp/include/gs/csp/log.h delete mode 100644 gomspace/libgscsp/include/gs/csp/port.h delete mode 100644 gomspace/libgscsp/include/gs/csp/router.h delete mode 100644 gomspace/libgscsp/include/gs/csp/rtable.h delete mode 100644 gomspace/libgscsp/include/gs/csp/service_dispatcher.h delete mode 100644 gomspace/libgscsp/include/gs/csp/service_handler.h delete mode 100644 gomspace/libgscsp/lib/libcsp/CHANGELOG delete mode 100644 gomspace/libgscsp/lib/libcsp/CONTRIBUTORS delete mode 100644 gomspace/libgscsp/lib/libcsp/COPYING delete mode 100644 gomspace/libgscsp/lib/libcsp/INSTALL.rst delete mode 100644 gomspace/libgscsp/lib/libcsp/README.rst delete mode 100644 gomspace/libgscsp/lib/libcsp/bindings/python/libcsp/__init__.py delete mode 100644 gomspace/libgscsp/lib/libcsp/doc/example.rst delete mode 100644 gomspace/libgscsp/lib/libcsp/doc/history.rst delete mode 100644 gomspace/libgscsp/lib/libcsp/doc/interfaces.rst delete mode 100644 gomspace/libgscsp/lib/libcsp/doc/libcsp.rst delete mode 100644 gomspace/libgscsp/lib/libcsp/doc/memory.rst delete mode 100644 gomspace/libgscsp/lib/libcsp/doc/mtu.rst delete mode 100644 gomspace/libgscsp/lib/libcsp/doc/protocolstack.rst delete mode 100644 gomspace/libgscsp/lib/libcsp/doc/structure.rst delete mode 100644 gomspace/libgscsp/lib/libcsp/doc/topology.rst delete mode 100644 gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo.c delete mode 100644 gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo_windows.c delete mode 100644 gomspace/libgscsp/lib/libcsp/examples/kiss.c delete mode 100644 gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client.py delete mode 100644 gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client_can.py delete mode 100644 gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_server.py delete mode 100644 gomspace/libgscsp/lib/libcsp/examples/simple.c delete mode 100644 gomspace/libgscsp/lib/libcsp/examples/zmqproxy.c delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_clock.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_malloc.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_queue.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_semaphore.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_system.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_thread.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_time.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/arch/posix/pthread_queue.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_hmac.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_sha1.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_xtea.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_buffer.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_cmp.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_crc32.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_debug.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_endian.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_error.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_iflist.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_interface.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_platform.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_rtable.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/csp_types.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/drivers/can_socketcan.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/drivers/i2c.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/drivers/usart.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_can.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_i2c.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_kiss.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_lo.h delete mode 100644 gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_zmqhub.h delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_malloc.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_queue.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_semaphore.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_system.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_thread.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_time.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_malloc.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_queue.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_semaphore.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_system.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_thread.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_time.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/macosx/pthread_queue.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_malloc.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_queue.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_semaphore.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_system.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_thread.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_time.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/posix/pthread_queue.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/README delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_malloc.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_queue.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_semaphore.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_system.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_thread.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_time.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_glue.h delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.h delete mode 100644 gomspace/libgscsp/lib/libcsp/src/bindings/python/pycsp.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/crypto/csp_hmac.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/crypto/csp_sha1.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/crypto/csp_xtea.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_bridge.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_buffer.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_conn.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_conn.h delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_crc32.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_debug.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_dedup.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_dedup.h delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_endian.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_hex_dump.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_iflist.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_io.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_io.h delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_port.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_port.h delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_promisc.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_promisc.h delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_route.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_route.h delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_service_handler.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_services.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/csp_sfp.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/drivers/can/can_socketcan.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_linux.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_windows.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.h delete mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_i2c.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_kiss.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_lo.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_cidr.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_static.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/transport/csp_rdp.c delete mode 100644 gomspace/libgscsp/lib/libcsp/src/transport/csp_transport.h delete mode 100644 gomspace/libgscsp/lib/libcsp/src/transport/csp_udp.c delete mode 100644 gomspace/libgscsp/lib/libcsp/utils/cfpsplit.py delete mode 100644 gomspace/libgscsp/lib/libcsp/utils/cspsplit.py delete mode 100644 gomspace/libgscsp/lib/libcsp/waf delete mode 100644 gomspace/libgscsp/lib/libcsp/wscript delete mode 100644 gomspace/libgscsp/src/bindings/python/pygscsp.c delete mode 100644 gomspace/libgscsp/src/clock.c delete mode 100644 gomspace/libgscsp/src/commands.c delete mode 100644 gomspace/libgscsp/src/conn.c delete mode 100644 gomspace/libgscsp/src/csp.c delete mode 100644 gomspace/libgscsp/src/drivers/can/can.c delete mode 100644 gomspace/libgscsp/src/drivers/i2c/i2c.c delete mode 100644 gomspace/libgscsp/src/drivers/kiss/kiss.c delete mode 100644 gomspace/libgscsp/src/error.c delete mode 100644 gomspace/libgscsp/src/freertos/cpu.c delete mode 100644 gomspace/libgscsp/src/linux/command_line.c delete mode 100644 gomspace/libgscsp/src/local.h delete mode 100644 gomspace/libgscsp/src/log.c delete mode 100644 gomspace/libgscsp/src/router.c delete mode 100644 gomspace/libgscsp/src/rtable.c delete mode 100644 gomspace/libgscsp/src/service_dispatcher.c delete mode 100644 gomspace/libgscsp/src/service_handler.c delete mode 100644 gomspace/libgscsp/src/transaction.c delete mode 100644 gomspace/libgscsp/wscript delete mode 100644 gomspace/libp60_client/include/p60.h delete mode 100644 gomspace/libp60_client/include/p60_board.h delete mode 100644 gomspace/libp60_client/include/power_if.h delete mode 100644 gomspace/libp60_client/src/cmd/power_if_cmd.c delete mode 100644 gomspace/libp60_client/src/p60_client.c delete mode 100644 gomspace/libp60_client/src/power_if.c delete mode 100644 gomspace/libp60_client/wscript delete mode 100644 gomspace/libparam_client/include/deprecated/param/param_client.h delete mode 100644 gomspace/libparam_client/include/deprecated/param/param_lock.h delete mode 100644 gomspace/libparam_client/include/deprecated/param/param_serializer.h delete mode 100644 gomspace/libparam_client/include/deprecated/param/param_string.h delete mode 100644 gomspace/libparam_client/include/deprecated/param/param_types.h delete mode 100644 gomspace/libparam_client/include/deprecated/param/rparam_client.h delete mode 100644 gomspace/libparam_client/include/gs/param/internal/pp/i2c/i2c.h delete mode 100644 gomspace/libparam_client/include/gs/param/internal/pp/i2c/slave_dispatch.h delete mode 100644 gomspace/libparam_client/include/gs/param/internal/pp/spi/slave_dispatch.h delete mode 100644 gomspace/libparam_client/include/gs/param/internal/pp/spi/spi.h delete mode 100644 gomspace/libparam_client/include/gs/param/internal/rparam.h delete mode 100644 gomspace/libparam_client/include/gs/param/internal/serialize.h delete mode 100644 gomspace/libparam_client/include/gs/param/internal/table.h delete mode 100644 gomspace/libparam_client/include/gs/param/internal/types.h delete mode 100644 gomspace/libparam_client/include/gs/param/pp/i2c/i2c.h delete mode 100644 gomspace/libparam_client/include/gs/param/pp/pp.h delete mode 100644 gomspace/libparam_client/include/gs/param/pp/spi/spi.h delete mode 100644 gomspace/libparam_client/include/gs/param/rparam.h delete mode 100644 gomspace/libparam_client/include/gs/param/serialize.h delete mode 100644 gomspace/libparam_client/include/gs/param/table.h delete mode 100644 gomspace/libparam_client/include/gs/param/types.h delete mode 100644 gomspace/libparam_client/src/bindings/python/pyparam.c delete mode 100644 gomspace/libparam_client/src/pp/cmd/master_cmd.c delete mode 100644 gomspace/libparam_client/src/pp/i2c/i2c.c delete mode 100644 gomspace/libparam_client/src/pp/pp.c delete mode 100644 gomspace/libparam_client/src/pp/spi/spi.c delete mode 100644 gomspace/libparam_client/src/rparam/cmd/cmd_rparam.c delete mode 100644 gomspace/libparam_client/src/rparam/deprecated_rparam.c delete mode 100644 gomspace/libparam_client/src/rparam/query.c delete mode 100644 gomspace/libparam_client/src/rparam/query.h delete mode 100644 gomspace/libparam_client/src/rparam/rparam.c delete mode 100644 gomspace/libparam_client/src/serialize.c delete mode 100644 gomspace/libparam_client/src/serialize_local.h delete mode 100644 gomspace/libparam_client/src/string.c delete mode 100644 gomspace/libparam_client/src/table.c delete mode 100644 gomspace/libparam_client/wscript delete mode 100644 gomspace/libutil/include/conf_util.h delete mode 100644 gomspace/libutil/include/deprecated/gs/gosh/command/command.h delete mode 100644 gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h delete mode 100644 gomspace/libutil/include/deprecated/gs/gosh/util/console.h delete mode 100644 gomspace/libutil/include/deprecated/util/color_printf.h delete mode 100644 gomspace/libutil/include/gs/uthash/utarray.h delete mode 100644 gomspace/libutil/include/gs/uthash/uthash.h delete mode 100644 gomspace/libutil/include/gs/uthash/utlist.h delete mode 100644 gomspace/libutil/include/gs/uthash/utstring.h delete mode 100644 gomspace/libutil/include/gs/util/base16.h delete mode 100644 gomspace/libutil/include/gs/util/bytebuffer.h delete mode 100644 gomspace/libutil/include/gs/util/byteorder.h delete mode 100644 gomspace/libutil/include/gs/util/check.h delete mode 100644 gomspace/libutil/include/gs/util/clock.h delete mode 100644 gomspace/libutil/include/gs/util/crc32.h delete mode 100644 gomspace/libutil/include/gs/util/crc8.h delete mode 100644 gomspace/libutil/include/gs/util/delay.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/can/can.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/gpio/gpio.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/i2c/common.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/i2c/master.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/i2c/slave.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/spi/common.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/spi/master.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/spi/slave.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/sys/memory.h delete mode 100644 gomspace/libutil/include/gs/util/drivers/watchdog/device.h delete mode 100644 gomspace/libutil/include/gs/util/endian.h delete mode 100644 gomspace/libutil/include/gs/util/error.h delete mode 100644 gomspace/libutil/include/gs/util/fletcher.h delete mode 100644 gomspace/libutil/include/gs/util/function_scheduler.h delete mode 100644 gomspace/libutil/include/gs/util/gosh/command.h delete mode 100644 gomspace/libutil/include/gs/util/gosh/console.h delete mode 100644 gomspace/libutil/include/gs/util/hexdump.h delete mode 100644 gomspace/libutil/include/gs/util/linux/argp.h delete mode 100644 gomspace/libutil/include/gs/util/linux/command_line.h delete mode 100644 gomspace/libutil/include/gs/util/linux/drivers/can/can.h delete mode 100644 gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h delete mode 100644 gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h delete mode 100644 gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h delete mode 100644 gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h delete mode 100644 gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h delete mode 100644 gomspace/libutil/include/gs/util/linux/exitcode.h delete mode 100644 gomspace/libutil/include/gs/util/linux/function.h delete mode 100644 gomspace/libutil/include/gs/util/linux/rtc.h delete mode 100644 gomspace/libutil/include/gs/util/linux/signal.h delete mode 100644 gomspace/libutil/include/gs/util/linux/sysfs_helper.h delete mode 100644 gomspace/libutil/include/gs/util/log.h delete mode 100644 gomspace/libutil/include/gs/util/log/appender/appender.h delete mode 100644 gomspace/libutil/include/gs/util/log/appender/console.h delete mode 100644 gomspace/libutil/include/gs/util/log/appender/simple_file.h delete mode 100644 gomspace/libutil/include/gs/util/log/log.h delete mode 100644 gomspace/libutil/include/gs/util/minmax.h delete mode 100644 gomspace/libutil/include/gs/util/mutex.h delete mode 100644 gomspace/libutil/include/gs/util/pgm.h delete mode 100644 gomspace/libutil/include/gs/util/queue.h delete mode 100644 gomspace/libutil/include/gs/util/rtc.h delete mode 100644 gomspace/libutil/include/gs/util/sem.h delete mode 100644 gomspace/libutil/include/gs/util/stdio.h delete mode 100644 gomspace/libutil/include/gs/util/string.h delete mode 100644 gomspace/libutil/include/gs/util/test/cmocka.h delete mode 100644 gomspace/libutil/include/gs/util/test/command.h delete mode 100644 gomspace/libutil/include/gs/util/test/log.h delete mode 100644 gomspace/libutil/include/gs/util/thread.h delete mode 100644 gomspace/libutil/include/gs/util/time.h delete mode 100644 gomspace/libutil/include/gs/util/timestamp.h delete mode 100644 gomspace/libutil/include/gs/util/types.h delete mode 100644 gomspace/libutil/include/gs/util/unistd.h delete mode 100644 gomspace/libutil/include/gs/util/vmem.h delete mode 100644 gomspace/libutil/include/gs/util/watchdog/watchdog.h delete mode 100644 gomspace/libutil/include/gs/util/watchdog/watchdog_task.h delete mode 100644 gomspace/libutil/include/gs/util/zip/zip.h delete mode 100644 gomspace/libutil/src/base16.c delete mode 100644 gomspace/libutil/src/bindings/python/pyutil.c delete mode 100644 gomspace/libutil/src/bytebuffer.c delete mode 100644 gomspace/libutil/src/byteorder.c delete mode 100644 gomspace/libutil/src/clock.c delete mode 100644 gomspace/libutil/src/crc32.c delete mode 100644 gomspace/libutil/src/crc8.c delete mode 100644 gomspace/libutil/src/drivers/can/can.c delete mode 100644 gomspace/libutil/src/drivers/i2c/i2c.c delete mode 100644 gomspace/libutil/src/drivers/spi/spi.c delete mode 100644 gomspace/libutil/src/drivers/sys/memory.c delete mode 100644 gomspace/libutil/src/error.c delete mode 100644 gomspace/libutil/src/fletcher.c delete mode 100644 gomspace/libutil/src/function_scheduler.c delete mode 100644 gomspace/libutil/src/gosh/command.c delete mode 100644 gomspace/libutil/src/gosh/command_local.h delete mode 100644 gomspace/libutil/src/gosh/console.c delete mode 100644 gomspace/libutil/src/gosh/console_local.h delete mode 100644 gomspace/libutil/src/gosh/default_commands.c delete mode 100644 gomspace/libutil/src/gosh/getopt.c delete mode 100644 gomspace/libutil/src/hexdump.c delete mode 100644 gomspace/libutil/src/linux/argp.c delete mode 100644 gomspace/libutil/src/linux/clock.c delete mode 100644 gomspace/libutil/src/linux/command_line.c delete mode 100644 gomspace/libutil/src/linux/cwd.c delete mode 100644 gomspace/libutil/src/linux/delay.c delete mode 100644 gomspace/libutil/src/linux/drivers/can/can.c delete mode 100644 gomspace/libutil/src/linux/drivers/gpio/gpio.c delete mode 100644 gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c delete mode 100644 gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c delete mode 100644 gomspace/libutil/src/linux/drivers/i2c/i2c.c delete mode 100644 gomspace/libutil/src/linux/drivers/spi/spi.c delete mode 100644 gomspace/libutil/src/linux/drivers/sys/memory.c delete mode 100644 gomspace/libutil/src/linux/function.c delete mode 100644 gomspace/libutil/src/linux/mutex.c delete mode 100644 gomspace/libutil/src/linux/queue.c delete mode 100644 gomspace/libutil/src/linux/rtc.c delete mode 100644 gomspace/libutil/src/linux/sem.c delete mode 100644 gomspace/libutil/src/linux/signal.c delete mode 100644 gomspace/libutil/src/linux/stdio.c delete mode 100644 gomspace/libutil/src/linux/sysfs_helper.c delete mode 100644 gomspace/libutil/src/linux/thread.c delete mode 100644 gomspace/libutil/src/linux/time.c delete mode 100644 gomspace/libutil/src/lock.c delete mode 100644 gomspace/libutil/src/lock.h delete mode 100644 gomspace/libutil/src/log/appender/console.c delete mode 100644 gomspace/libutil/src/log/appender/simple_file.c delete mode 100644 gomspace/libutil/src/log/commands.c delete mode 100644 gomspace/libutil/src/log/local.h delete mode 100644 gomspace/libutil/src/log/log.c delete mode 100644 gomspace/libutil/src/rtc.c delete mode 100644 gomspace/libutil/src/stdio.c delete mode 100644 gomspace/libutil/src/string.c delete mode 100644 gomspace/libutil/src/strtoint.c delete mode 100644 gomspace/libutil/src/test/cmocka.c delete mode 100644 gomspace/libutil/src/test/command.c delete mode 100644 gomspace/libutil/src/test/log.c delete mode 100644 gomspace/libutil/src/time.c delete mode 100644 gomspace/libutil/src/timestamp.c delete mode 100644 gomspace/libutil/src/vmem/commands.c delete mode 100644 gomspace/libutil/src/vmem/vmem.c delete mode 100644 gomspace/libutil/src/watchdog/local.h delete mode 100644 gomspace/libutil/src/watchdog/monitor_task.c delete mode 100644 gomspace/libutil/src/watchdog/watchdog.c delete mode 100644 gomspace/libutil/src/zip/cppcheck-suppress.txt delete mode 100644 gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES delete mode 100644 gomspace/libutil/src/zip/miniz/miniz.c delete mode 100644 gomspace/libutil/src/zip/miniz/miniz.h delete mode 100644 gomspace/libutil/src/zip/zip.c delete mode 100644 gomspace/libutil/wscript delete mode 100644 gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock.h delete mode 100644 gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_cal.h delete mode 100644 gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h delete mode 100644 gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_param.h delete mode 100644 gomspace/p60-dock_client/src/p60dock_client.c delete mode 100644 gomspace/p60-dock_client/wscript rename {gomspace/libcsp => libcsp}/bindings/python/libcsp/__init__.py (100%) rename {gomspace/libcsp => libcsp}/doc/example.rst (100%) rename {gomspace/libcsp => libcsp}/doc/history.rst (100%) rename {gomspace/libcsp => libcsp}/doc/interfaces.rst (100%) rename {gomspace/libcsp => libcsp}/doc/libcsp.rst (100%) rename {gomspace/libcsp => libcsp}/doc/memory.rst (100%) rename {gomspace/libcsp => libcsp}/doc/mtu.rst (100%) rename {gomspace/libcsp => libcsp}/doc/protocolstack.rst (100%) rename {gomspace/libcsp => libcsp}/doc/structure.rst (100%) rename {gomspace/libcsp => libcsp}/doc/topology.rst (100%) rename {gomspace/libcsp => libcsp}/examples/csp_if_fifo.c (100%) rename {gomspace/libcsp => libcsp}/examples/csp_if_fifo_windows.c (100%) rename {gomspace/libcsp => libcsp}/examples/kiss.c (100%) rename {gomspace/libcsp => libcsp}/examples/python_bindings_example_client.py (100%) rename {gomspace/libcsp => libcsp}/examples/python_bindings_example_client_can.py (100%) rename {gomspace/libcsp => libcsp}/examples/python_bindings_example_server.py (100%) rename {gomspace/libcsp => libcsp}/examples/simple.c (100%) rename {gomspace/libcsp => libcsp}/examples/zmqproxy.c (100%) rename {gomspace/libcsp => libcsp}/include/csp/arch/csp_clock.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/arch/csp_malloc.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/arch/csp_queue.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/arch/csp_semaphore.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/arch/csp_system.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/arch/csp_thread.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/arch/csp_time.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/arch/posix/pthread_queue.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/crypto/csp_hmac.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/crypto/csp_sha1.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/crypto/csp_xtea.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/csp.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/csp_autoconfig.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/csp_buffer.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/csp_cmp.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/csp_crc32.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/csp_debug.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/csp_endian.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/csp_error.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/csp_iflist.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/csp_interface.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/csp_platform.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/csp_rtable.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/csp_types.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/drivers/can_socketcan.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/drivers/i2c.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/drivers/usart.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/interfaces/csp_if_can.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/interfaces/csp_if_i2c.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/interfaces/csp_if_kiss.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/interfaces/csp_if_lo.h (100%) rename {gomspace/libcsp => libcsp}/include/csp/interfaces/csp_if_zmqhub.h (100%) create mode 100644 libcsp/libcsp.mk rename {gomspace/libcsp => libcsp}/src/arch/freertos/csp_malloc.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/freertos/csp_queue.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/freertos/csp_semaphore.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/freertos/csp_system.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/freertos/csp_thread.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/freertos/csp_time.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/macosx/csp_malloc.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/macosx/csp_queue.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/macosx/csp_semaphore.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/macosx/csp_system.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/macosx/csp_thread.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/macosx/csp_time.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/macosx/pthread_queue.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/posix/csp_malloc.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/posix/csp_queue.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/posix/csp_semaphore.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/posix/csp_system.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/posix/csp_thread.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/posix/csp_time.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/posix/pthread_queue.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/windows/README (100%) rename {gomspace/libcsp => libcsp}/src/arch/windows/csp_malloc.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/windows/csp_queue.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/windows/csp_semaphore.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/windows/csp_system.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/windows/csp_thread.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/windows/csp_time.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/windows/windows_glue.h (100%) rename {gomspace/libcsp => libcsp}/src/arch/windows/windows_queue.c (100%) rename {gomspace/libcsp => libcsp}/src/arch/windows/windows_queue.h (100%) rename {gomspace/libcsp => libcsp}/src/bindings/python/pycsp.c (100%) rename {gomspace/libcsp => libcsp}/src/crypto/csp_hmac.c (100%) rename {gomspace/libcsp => libcsp}/src/crypto/csp_sha1.c (100%) rename {gomspace/libcsp => libcsp}/src/crypto/csp_xtea.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_bridge.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_buffer.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_conn.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_conn.h (100%) rename {gomspace/libcsp => libcsp}/src/csp_crc32.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_debug.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_dedup.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_dedup.h (100%) rename {gomspace/libcsp => libcsp}/src/csp_endian.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_hex_dump.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_iflist.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_io.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_io.h (100%) rename {gomspace/libcsp => libcsp}/src/csp_port.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_port.h (100%) rename {gomspace/libcsp => libcsp}/src/csp_promisc.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_promisc.h (100%) rename {gomspace/libcsp => libcsp}/src/csp_qfifo.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_qfifo.h (100%) rename {gomspace/libcsp => libcsp}/src/csp_route.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_route.h (100%) rename {gomspace/libcsp => libcsp}/src/csp_service_handler.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_services.c (100%) rename {gomspace/libcsp => libcsp}/src/csp_sfp.c (100%) rename {gomspace/libcsp => libcsp}/src/drivers/can/can_socketcan.c (100%) rename {gomspace/libcsp => libcsp}/src/drivers/usart/usart_linux.c (100%) rename {gomspace/libcsp => libcsp}/src/drivers/usart/usart_windows.c (100%) rename {gomspace/libcsp => libcsp}/src/interfaces/csp_if_can.c (100%) rename {gomspace/libcsp => libcsp}/src/interfaces/csp_if_can_pbuf.c (100%) rename {gomspace/libcsp => libcsp}/src/interfaces/csp_if_can_pbuf.h (100%) rename {gomspace/libcsp => libcsp}/src/interfaces/csp_if_i2c.c (100%) rename {gomspace/libcsp => libcsp}/src/interfaces/csp_if_kiss.c (100%) rename {gomspace/libcsp => libcsp}/src/interfaces/csp_if_lo.c (100%) rename {gomspace/libcsp => libcsp}/src/rtable/csp_rtable_cidr.c (100%) rename {gomspace/libcsp => libcsp}/src/rtable/csp_rtable_static.c (100%) rename {gomspace/libcsp => libcsp}/src/transport/csp_rdp.c (100%) rename {gomspace/libcsp => libcsp}/src/transport/csp_transport.h (100%) rename {gomspace/libcsp => libcsp}/src/transport/csp_udp.c (100%) rename {gomspace/libcsp => libcsp}/utils/cfpsplit.py (100%) rename {gomspace/libcsp => libcsp}/utils/cspsplit.py (100%) create mode 100644 mission/devices/GomspaceDeviceHandler.cpp create mode 100644 mission/devices/GomspaceDeviceHandler.h delete mode 100644 mission/devices/P60DockHandler.cpp delete mode 100644 mission/devices/P60DockHandler.h create mode 100644 mission/devices/devicedefinitions/GomspaceDefinitions.h delete mode 100644 mission/devices/devicedefinitions/P60DockHandlerDefinitions.h delete mode 100644 test/testtasks/P60DockTestTask.cpp delete mode 100644 test/testtasks/P60DockTestTask.h diff --git a/Makefile b/Makefile index 29eb5856..eaa08f74 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ MISSION_PATH = mission CONFIG_PATH = fsfwconfig TEST_PATH = test UNITTEST_PATH = unittest -GOMSPACE_PATH = gomspace +LIBCSP_PATH = libcsp # Board specific paths BSP_PATH = $(BOARD_FILE_ROOT) @@ -114,7 +114,7 @@ INCLUDES := # Directories where $(directoryname).mk files should be included from SUBDIRS := $(FRAMEWORK_PATH) $(TEST_PATH) $(BSP_PATH) $(UNITTEST_PATH)\ - $(CONFIG_PATH) $(MISSION_PATH) $(GOMSPACE_PATH) + $(CONFIG_PATH) $(MISSION_PATH) $(LIBCSP_PATH) # INCLUDES += framework/test/catch2 # ETL library include. diff --git a/bsp_linux/InitMission.cpp b/bsp_linux/InitMission.cpp index 4be8be72..0243c788 100644 --- a/bsp_linux/InitMission.cpp +++ b/bsp_linux/InitMission.cpp @@ -158,13 +158,6 @@ void InitMission::initTasks(){ // << "failed!" << std::endl; // } - PeriodicTaskIF* P60DockTestTask = - TaskFactory::instance()->createPeriodicTask("P60 Dock", 50, - PeriodicTaskIF::MINIMUM_STACK_SIZE, 1, nullptr); - result = PusLowPrio->addComponent(objects::P60DOCK_TEST_TASK); - if(result!=HasReturnvaluesIF::RETURN_OK){ - sif::error << "Object add component failed" << std::endl; - } #endif //Main thread sleep @@ -185,8 +178,6 @@ void InitMission::initTasks(){ #if ADD_TEST_CODE == 1 // TestTimeslotTask->startTask(); - P60DockTestTask->startTask(); - #endif sif::info << "Tasks started.." << std::endl; } diff --git a/bsp_linux/comIF/ArduinoComIF.cpp b/bsp_linux/comIF/ArduinoComIF.cpp deleted file mode 100644 index 77088a63..00000000 --- a/bsp_linux/comIF/ArduinoComIF.cpp +++ /dev/null @@ -1,324 +0,0 @@ -//#include "cookies/ArduinoCookie.h" -//#include "ArduinoComIF.h" -// -//#include -//#include -//#include -//#include -//#include -//#include -//#include -// -//#include -// -//ArduinoCommInterface::ArduinoCommInterface(object_id_t setObjectId, -// const char *serialDevice) : -// spiMap(MAX_NUMBER_OF_SPI_DEVICES), rxBuffer( -// MAX_PACKET_SIZE * MAX_NUMBER_OF_SPI_DEVICES*10, true), SystemObject(setObjectId) { -// initialized = false; -// serialPort = ::open("/dev/ttyUSB0", O_RDWR); -// -// if (serialPort < 0) { -// //configuration error -// printf("Error %i from open: %s\n", errno, strerror(errno)); -// return; -// } -// -// struct termios tty; -// memset(&tty, 0, sizeof tty); -// -// // Read in existing settings, and handle any error -// if (tcgetattr(serialPort, &tty) != 0) { -// printf("Error %i from tcgetattr: %s\n", errno, strerror(errno)); -// return; -// } -// -// tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity -// tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication -// tty.c_cflag |= CS8; // 8 bits per byte -// tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control -// tty.c_lflag &= ~ICANON; //Disable Canonical Mode -// tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars) -// tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed -// tty.c_cc[VTIME] = 0; // Non Blocking -// tty.c_cc[VMIN] = 0; -// -// cfsetispeed(&tty, B9600); //Baudrate -// -// if (tcsetattr(serialPort, TCSANOW, &tty) != 0) { -// //printf("Error %i from tcsetattr: %s\n", errno, strerror(errno)); -// return; -// } -// -// initialized = true; -// -//} -// -//ArduinoCommInterface::~ArduinoCommInterface() { -// ::close(serialPort); -//} -// -//ReturnValue_t ArduinoCommInterface::open(Cookie **cookie, uint32_t address, -// uint32_t maxReplyLen) { -// //This is a hack, will be gone with https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/19 -// switch ((address >> 8) & 0xff) { -// case 0: -// *cookie = new ArduinoCookie(ArduinoCookie::SPI, address, maxReplyLen); -// spiMap.insert(address, (ArduinoCookie*) *cookie); //Yes, I *do* know that it is an ArduinoSpiCookie, I just new'd it -// break; -// default: -// return HasReturnvaluesIF::RETURN_FAILED; -// } -// return HasReturnvaluesIF::RETURN_OK; -//} -// -//ReturnValue_t ArduinoCommInterface::reOpen(Cookie *cookie, uint32_t address, -// uint32_t maxReplyLen) { -// //too lazy right now will be irrelevant with https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/19 -// return HasReturnvaluesIF::RETURN_FAILED; -//} -// -//void ArduinoCommInterface::close(Cookie *cookie) { -// //too lazy as well, find the correct Map, delete it there, then the cookie... -//} -// -//ReturnValue_t ArduinoCommInterface::sendMessage(Cookie *cookie, uint8_t *data, -// uint32_t len) { -// ArduinoCookie *arduinoCookie = dynamic_cast(cookie); -// if (arduinoCookie == NULL) { -// return INVALID_COOKIE_TYPE; -// } -// -// return sendMessage(arduinoCookie->command, arduinoCookie->address, data, -// len); -//} -// -//ReturnValue_t ArduinoCommInterface::getSendSuccess(Cookie *cookie) { -// return RETURN_OK; -//} -// -//ReturnValue_t ArduinoCommInterface::requestReceiveMessage(Cookie *cookie) { -// return RETURN_OK; -//} -// -//ReturnValue_t ArduinoCommInterface::readReceivedMessage(Cookie *cookie, -// uint8_t **buffer, uint32_t *size) { -// -// handleSerialPortRx(); -// -// ArduinoCookie *arduinoCookie = dynamic_cast(cookie); -// if (arduinoCookie == NULL) { -// return INVALID_COOKIE_TYPE; -// } -// -// *buffer = arduinoCookie->replyBuffer; -// *size = arduinoCookie->receivedDataLen; -// return HasReturnvaluesIF::RETURN_OK; -//} -// -//ReturnValue_t ArduinoCommInterface::setAddress(Cookie *cookie, -// uint32_t address) { -// //not implemented -// return RETURN_FAILED; -//} -// -//uint32_t ArduinoCommInterface::getAddress(Cookie *cookie) { -// //not implemented -// return 0; -//} -// -//ReturnValue_t ArduinoCommInterface::setParameter(Cookie *cookie, -// uint32_t parameter) { -// //not implemented -// return RETURN_FAILED; -//} -// -//uint32_t ArduinoCommInterface::getParameter(Cookie *cookie) { -// //not implemented -// return 0; -//} -// -//ReturnValue_t ArduinoCommInterface::sendMessage(uint8_t command, -// uint8_t address, const uint8_t *data, size_t dataLen) { -// if (dataLen > UINT16_MAX) { -// return TOO_MUCH_DATA; -// } -// -// //being conservative here -// uint8_t sendBuffer[(dataLen + 6) * 2 + 2]; -// -// sendBuffer[0] = DleEncoder::STX; -// -// uint8_t *currentPosition = sendBuffer + 1; -// size_t remainingLen = sizeof(sendBuffer) - 1; -// uint32_t encodedLen; -// -// ReturnValue_t result = DleEncoder::encode(&command, 1, currentPosition, -// remainingLen, &encodedLen, false); -// if (result != RETURN_OK) { -// return result; -// } -// currentPosition += encodedLen; -// remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen -// -// result = DleEncoder::encode(&address, 1, currentPosition, remainingLen, -// &encodedLen, false); -// if (result != RETURN_OK) { -// return result; -// } -// currentPosition += encodedLen; -// remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen -// -// uint8_t temporaryBuffer[2]; -// -// //note to Lukas: yes we _could_ use Serialize here, but for 16 bit it is a bit too much... -// temporaryBuffer[0] = dataLen >> 8; //we checked dataLen above -// temporaryBuffer[1] = dataLen; -// -// result = DleEncoder::encode(temporaryBuffer, 2, currentPosition, -// remainingLen, &encodedLen, false); -// if (result != RETURN_OK) { -// return result; -// } -// currentPosition += encodedLen; -// remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen -// -// //encoding the actual data -// result = DleEncoder::encode(data, dataLen, currentPosition, remainingLen, -// &encodedLen, false); -// if (result != RETURN_OK) { -// return result; -// } -// currentPosition += encodedLen; -// remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen -// -// uint16_t crc = CRC::crc16ccitt(&command, 1); -// crc = CRC::crc16ccitt(&address, 1, crc); -// //fortunately the length is still there -// crc = CRC::crc16ccitt(temporaryBuffer, 2, crc); -// crc = CRC::crc16ccitt(data, dataLen, crc); -// -// temporaryBuffer[0] = crc >> 8; -// temporaryBuffer[1] = crc; -// -// result = DleEncoder::encode(temporaryBuffer, 2, currentPosition, -// remainingLen, &encodedLen, false); -// if (result != RETURN_OK) { -// return result; -// } -// currentPosition += encodedLen; -// remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen -// -// if (remainingLen > 0) { -// *currentPosition = DleEncoder::ETX; -// } -// remainingLen -= 1; -// -// encodedLen = sizeof(sendBuffer) - remainingLen; -// -// ssize_t writtenlen = write(serialPort, sendBuffer, encodedLen); -// if (writtenlen < 0) { -// //we could try to find out what happened... -// return RETURN_FAILED; -// } -// if (writtenlen != encodedLen) { -// //the OS failed us, we do not try to block until everything is written, as -// //we can not block the whole system here -// return RETURN_FAILED; -// } -// return RETURN_OK; -//} -// -//void ArduinoCommInterface::handleSerialPortRx() { -// uint32_t availableSpace = rxBuffer.availableWriteSpace(); -// -// uint8_t dataFromSerial[availableSpace]; -// -// ssize_t bytesRead = read(serialPort, dataFromSerial, -// sizeof(dataFromSerial)); -// -// if (bytesRead < 0) { -// return; -// } -// -// rxBuffer.writeData(dataFromSerial, bytesRead); -// -// uint8_t dataReceivedSoFar[rxBuffer.maxSize()]; -// -// uint32_t dataLenReceivedSoFar = 0; -// -// rxBuffer.readData(dataReceivedSoFar, sizeof(dataReceivedSoFar), true, -// &dataLenReceivedSoFar); -// -// //look for STX -// size_t firstSTXinRawData = 0; -// while ((firstSTXinRawData < dataLenReceivedSoFar) -// && (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX)) { -// firstSTXinRawData++; -// } -// -// if (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX) { -// //there is no STX in our data, throw it away... -// rxBuffer.deleteData(dataLenReceivedSoFar); -// return; -// } -// -// uint8_t packet[MAX_PACKET_SIZE]; -// uint32_t packetLen; -// -// uint32_t readSize; -// -// ReturnValue_t result = DleEncoder::decode( -// dataReceivedSoFar + firstSTXinRawData, -// dataLenReceivedSoFar - firstSTXinRawData, &readSize, packet, -// sizeof(packet), &packetLen); -// -// size_t toDelete = firstSTXinRawData; -// if (result == HasReturnvaluesIF::RETURN_OK) { -// handlePacket(packet, packetLen); -// -// //after handling the packet, we can delete it from the raw stream, it has been copied to packet -// toDelete += readSize; -// } -// -// //remove Data which was processed -// rxBuffer.deleteData(toDelete); -//} -// -//void ArduinoCommInterface::handlePacket(uint8_t *packet, size_t packetLen) { -// uint16_t crc = CRC::crc16ccitt(packet, packetLen); -// if (crc != 0) { -// //CRC error -// return; -// } -// -// uint8_t command = packet[0]; -// uint8_t address = packet[1]; -// -// uint16_t size = (packet[2] << 8) + packet[3]; -// -// if (size != packetLen - 6) { -// //Invalid Length -// return; -// } -// -// switch (command) { -// case ArduinoCookie::SPI: { -// ArduinoCookie **itsComplicated; -// ReturnValue_t result = spiMap.find(address, &itsComplicated); -// if (result != RETURN_OK) { -// //we do no know this address -// return; -// } -// ArduinoCookie *theActualCookie = *itsComplicated; -// if (packetLen > theActualCookie->maxReplySize + 6) { -// packetLen = theActualCookie->maxReplySize + 6; -// } -// memcpy(theActualCookie->replyBuffer, packet + 4, packetLen - 6); -// theActualCookie->receivedDataLen = packetLen - 6; -// } -// break; -// default: -// return; -// } -//} diff --git a/bsp_linux/comIF/ArduinoComIF.h b/bsp_linux/comIF/ArduinoComIF.h deleted file mode 100644 index 9ab166de..00000000 --- a/bsp_linux/comIF/ArduinoComIF.h +++ /dev/null @@ -1,73 +0,0 @@ -//#ifndef MISSION_ARDUINOCOMMINTERFACE_H_ -//#define MISSION_ARDUINOCOMMINTERFACE_H_ -// -//#include -//#include -//#include -//#include -//#include -//#include -// -//#include "../../framework/objectmanager/SystemObject.h" -//#include "ArduinoCookie.h" -// -////Forward declaration, so users don't peek -//class ArduinoCookie; -// -//class ArduinoComIF: public SystemObject, -// public DeviceCommunicationIF { -//public: -// static const uint8_t MAX_NUMBER_OF_SPI_DEVICES = 8; -// static const uint8_t MAX_PACKET_SIZE = 64; -// -// static const uint8_t COMMAND_INVALID = -1; -// static const uint8_t COMMAND_SPI = 1; -// -// ArduinoComIF(object_id_t setObjectId, const char *serialDevice); -// virtual ~ArduinoComIF(); -// -// virtual ReturnValue_t open(Cookie **cookie, uint32_t address, -// uint32_t maxReplyLen); -// -// virtual ReturnValue_t reOpen(Cookie *cookie, uint32_t address, -// uint32_t maxReplyLen); -// -// virtual void close(Cookie *cookie); -// -// //SHOULDDO can data be const? -// virtual ReturnValue_t sendMessage(Cookie *cookie, uint8_t *data, -// uint32_t len); -// -// virtual ReturnValue_t getSendSuccess(Cookie *cookie); -// -// virtual ReturnValue_t requestReceiveMessage(Cookie *cookie); -// -// virtual ReturnValue_t readReceivedMessage(Cookie *cookie, uint8_t **buffer, -// uint32_t *size); -// -// virtual ReturnValue_t setAddress(Cookie *cookie, uint32_t address); -// -// virtual uint32_t getAddress(Cookie *cookie); -// -// virtual ReturnValue_t setParameter(Cookie *cookie, uint32_t parameter); -// -// virtual uint32_t getParameter(Cookie *cookie); -//private: -// //remembering if the initialization in the ctor worked -// //if not, all calls are disabled -// bool initialized; -// int serialPort; -// //used to know where to put the data if a reply is received -// FixedMap spiMap; -// -// SimpleRingBuffer rxBuffer; -// -// ReturnValue_t sendMessage(uint8_t command, uint8_t address, -// const uint8_t *data, size_t dataLen); -// -// void handleSerialPortRx(); -// -// void handlePacket(uint8_t *packet, size_t packetLen); -//}; -// -//#endif /* MISSION_ARDUINOCOMMINTERFACE_H_ */ diff --git a/bsp_linux/comIF/CspComIF.cpp b/bsp_linux/comIF/CspComIF.cpp index 77b52c1e..224ae2d4 100644 --- a/bsp_linux/comIF/CspComIF.cpp +++ b/bsp_linux/comIF/CspComIF.cpp @@ -81,23 +81,28 @@ ReturnValue_t CspComIF::sendMessage(CookieIF *cookie, /* Extract csp port and bytes to query from command buffer */ uint8_t cspPort; uint16_t querySize; - SerializeAdapter::deSerialize(&cspPort, &sendData, &sendLen, - SerializeIF::Endianness::BIG); - SerializeAdapter::deSerialize(&querySize, &sendData, &sendLen, - SerializeIF::Endianness::BIG); +// result = SerializeAdapter::deSerialize(&cspPort, &sendData, +// &sendLen, SerializeIF::Endianness::BIG); +// if(result != HasReturnvaluesIF::RETURN_OK){ +// sif::error << "CspComIF: Failed to deserialize CSP port from command " +// << "buffer" << std::endl; +// return HasReturnvaluesIF::RETURN_FAILED; +// } +// SerializeAdapter::deSerialize(&querySize, &sendData, &sendLen, +// SerializeIF::Endianness::BIG); +// if(result != HasReturnvaluesIF::RETURN_OK){ +// sif::error << "CspComIF: Failed to deserialize querySize from command " +// << "buffer" << std::endl; +// return HasReturnvaluesIF::RETURN_FAILED; +// } + result = getPortAndQuerySize(&sendData, &sendLen, &cspPort, &querySize); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } uint8_t cspAddress = cspCookie->getCspAddress(); switch(cspPort) { case(Ports::CSP_PING): { - uint32_t timeout = 1000; // ms - unsigned int pingSize = 100; // 100 bytes - uint32_t replyTime = csp_ping(cspAddress, timeout, pingSize, - CSP_O_NONE); - sif::info << "Ping address: " << cspAddress << ", reply after " - << replyTime << " ms" << std::endl; - /* Store reply time in reply buffer * */ - uint8_t* replyBuffer = cspDeviceMap[cspAddress].data(); - memcpy(replyBuffer, &replyTime, sizeof(replyTime)); - replySize = sizeof(replyTime); + initiatePingRequest(cspAddress, querySize); break; } case(Ports::CSP_REBOOT): { @@ -153,7 +158,7 @@ ReturnValue_t CspComIF::readReceivedMessage(CookieIF *cookie, ReturnValue_t CspComIF::cspTransfer(uint8_t cspAddress, uint8_t cspPort, const uint8_t* cmdBuffer, int cmdBufferLen, uint16_t querySize) { - uint32_t timeout_ms = 1000; + uint32_t timeout_ms = 500; vectorBufferIter iter = cspDeviceMap.find(cspAddress); if(iter == cspDeviceMap.end()){ sif::error << "CSP device with address " << cspAddress << " no found in" @@ -185,3 +190,34 @@ ReturnValue_t CspComIF::cspTransfer(uint8_t cspAddress, uint8_t cspPort, return HasReturnvaluesIF::RETURN_OK; } + +ReturnValue_t CspComIF::getPortAndQuerySize(const uint8_t** sendData, + size_t* sendLen, uint8_t* cspPort, uint16_t* querySize) { + ReturnValue_t result = SerializeAdapter::deSerialize(cspPort, sendData, + sendLen, SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "CspComIF: Failed to deserialize CSP port from command " + << "buffer" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + SerializeAdapter::deSerialize(querySize, sendData, sendLen, + SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "CspComIF: Failed to deserialize querySize from command " + << "buffer" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void CspComIF::initiatePingRequest(uint8_t cspAddress, uint16_t querySize){ + uint32_t timeout_ms = 500; + uint32_t replyTime = csp_ping(cspAddress, timeout_ms, querySize, + CSP_O_NONE); + sif::info << "Ping address: " << cspAddress << ", reply after " + << replyTime << " ms" << std::endl; + /* Store reply time in reply buffer * */ + uint8_t* replyBuffer = cspDeviceMap[cspAddress].data(); + memcpy(replyBuffer, &replyTime, sizeof(replyTime)); + replySize = sizeof(replyTime); +} diff --git a/bsp_linux/comIF/CspComIF.h b/bsp_linux/comIF/CspComIF.h index fd4057a8..c1a27f19 100644 --- a/bsp_linux/comIF/CspComIF.h +++ b/bsp_linux/comIF/CspComIF.h @@ -69,6 +69,18 @@ private: /* Interface struct for csp protocol stack */ csp_iface_t csp_if; + + /** + * @brief Function to extract the csp port and the query size from the + * command buffer. + */ + ReturnValue_t getPortAndQuerySize(const uint8_t** sendData, size_t* sendLen, + uint8_t* cspPort, uint16_t* querySize); + + /** + * @brief This function initiates the ping request. + */ + void initiatePingRequest(uint8_t cspAddress, uint16_t querySize); }; #endif /* BSP_LINUX_COMIF_COOKIES_CSPCOMIF_H_ */ diff --git a/bsp_linux/comIF/P60DockComIF.cpp b/bsp_linux/comIF/P60DockComIF.cpp deleted file mode 100644 index 07af81e6..00000000 --- a/bsp_linux/comIF/P60DockComIF.cpp +++ /dev/null @@ -1,170 +0,0 @@ -#include "P60DockComIF.h" - -#include -#include -#include -#include -#include - -P60DockComIF::P60DockComIF(object_id_t objectId) : - SystemObject(objectId) { - -} - -P60DockComIF::~P60DockComIF() { -} - -ReturnValue_t P60DockComIF::initializeInterface(CookieIF *cookie) { - if(cookie == nullptr) { - return NULLPOINTER; - } - - P60DockCookie* p60DockCookie = dynamic_cast(cookie); - if(p60DockCookie == nullptr) { - return NULLPOINTER; - } - char* canInterface = p60DockCookie->getCanIf(); - int bitrate = p60DockCookie->getBitrate(); - /* Define the memory to allocate for the CSP stack */ - int buf_count = 10; - int buf_size = 300; - /* Init CSP and CSP buffer system */ - if (csp_init(cspClientAddress) != CSP_ERR_NONE - || csp_buffer_init(buf_count, buf_size) != CSP_ERR_NONE) { - sif::error << "Failed to init CSP\r\n" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - - int promisc = 0; // Set filter mode on - csp_iface_t *csp_if_ptr = &csp_if; - csp_if_ptr = csp_can_socketcan_init(canInterface, bitrate, promisc); - - /* Set default route and start router */ - uint8_t address = CSP_DEFAULT_ROUTE; - uint8_t netmask = 0; - uint8_t mac = CSP_NODE_MAC; - int result = csp_rtable_set(address, netmask, csp_if_ptr, mac); - if(result != CSP_ERR_NONE){ - sif::error << "Failed to add can interface to router table" - << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - - /* Start the route task */ - unsigned int task_stack_size = 500; - unsigned int priority = 0; - result = csp_route_start_task(task_stack_size, priority); - if(result != CSP_ERR_NONE){ - sif::error << "Failed to start csp route task" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t P60DockComIF::sendMessage(CookieIF *cookie, - const uint8_t * sendData, size_t sendLen) { - if(cookie == NULL){ - return HasReturnvaluesIF::RETURN_FAILED; - } - P60DockCookie* p60DockCookie = dynamic_cast (cookie); - if(p60DockCookie == NULL){ - return HasReturnvaluesIF::RETURN_FAILED; - } - - MessageType_t messageType = p60DockCookie->getMessageType(); - - switch(messageType){ - case(P60DockCookie::PING):{ - uint32_t timeout = 1000; // ms - unsigned int pingSize = 100; // 100 bytes - uint8_t p60DockAddress = p60DockCookie->getCspAddress(); - uint32_t replyTime = csp_ping(p60DockAddress, timeout, pingSize, - CSP_O_NONE); - sif::info << "Ping address: " << p60DockAddress << ", reply after " - << replyTime << " ms" << std::endl; - /* Store reply time in reply buffer * */ - memcpy(replyBuffer, &replyTime, sizeof(replyTime)); - break; - } - case(P60DockCookie::REBOOT):{ - csp_reboot(p60DockCookie->getCspAddress()); - break; - } - default: - break; - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t P60DockComIF::getSendSuccess(CookieIF *cookie) { - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t P60DockComIF::requestReceiveMessage(CookieIF *cookie, - size_t requestLen) { - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t P60DockComIF::readReceivedMessage(CookieIF *cookie, - uint8_t** buffer, size_t* size) { - if(cookie == NULL){ - return HasReturnvaluesIF::RETURN_FAILED; - } - P60DockCookie* p60DockCookie = dynamic_cast (cookie); - if(p60DockCookie == NULL){ - return HasReturnvaluesIF::RETURN_FAILED; - } - - MessageType_t messageType = p60DockCookie->getMessageType(); - - switch(messageType){ - case(P60DockCookie::READ_MODULE_CONFIG):{ - uint32_t timeout = 1000; // ms - uint8_t p60dockAddress = p60DockCookie->getCspAddress(); - gs_param_table_instance_t table; - table.rows = (gs_param_table_row_t*)p60dock_config; - table.id = moduleCfgTableNum; - table.row_count = p60dock_config_count; - table.memory_size = P60DOCK_PARAM_SIZE; - table.memory = replyBuffer; - /* Read complete module configuration table from P60 Dock and store data - * in buffer */ - int result = gs_rparam_get_full_table(&table, p60dockAddress, - table.id, GS_RPARAM_MAGIC_CHECKSUM, timeout); - *size = P60DOCK_PARAM_SIZE; - if (result != GS_OK) { - sif::info - << "Failed retrieving module configuration from P60 dock " - << "with error code " << result << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - break; - } - case(P60DockCookie::READ_HK):{ - uint32_t timeout = 1000; // ms - uint8_t p60dockAddress = p60DockCookie->getCspAddress(); - table.rows = (gs_param_table_row_t*)p60dock_hk; - table.id = tmTableNum; - table.row_count = p60dock_hk_count; - table.memory_size = P60DOCK_HK_SIZE; - table.memory = replyBuffer; - /* Read complete module configuration table from P60 Dock and store data - * in buffer */ - int result = gs_rparam_get_full_table(&table, p60dockAddress, - table.id, GS_RPARAM_MAGIC_CHECKSUM, timeout); - *size = P60DOCK_HK_SIZE; - if (result != GS_OK) { - sif::info - << "Failed retrieving telemetry from P60 dock with error " - << "code " << result << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - break; - } - default: - break; - } - return HasReturnvaluesIF::RETURN_OK; -} - diff --git a/bsp_linux/comIF/P60DockComIF.h b/bsp_linux/comIF/P60DockComIF.h deleted file mode 100644 index 3aed2f25..00000000 --- a/bsp_linux/comIF/P60DockComIF.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * P60DockComIF.h - * - * Created on: 01.12.2020 - * Author: jakob - */ - -#ifndef BSP_LINUX_COMIF_P60DOCKCOMIF_H_ -#define BSP_LINUX_COMIF_P60DOCKCOMIF_H_ - -#include -#include -#include - -#include -#include -#include -#include -#include - -/** - * @brief This is the communication interface to the cubesat space protocol - * stack. The physical layer used for this implementation is CAN. - * @author Jakob Meier - */ -class P60DockComIF: public DeviceCommunicationIF, public SystemObject { -public: - static const uint16_t maxReplyLength = 412; - - P60DockComIF(object_id_t objectId); - virtual ~P60DockComIF(); - - ReturnValue_t initializeInterface(CookieIF * cookie) override; - ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t * sendData, - size_t sendLen) override; - ReturnValue_t getSendSuccess(CookieIF *cookie) override; - ReturnValue_t requestReceiveMessage(CookieIF *cookie, - size_t requestLen) override; - ReturnValue_t readReceivedMessage(CookieIF *cookie, - uint8_t **readData, size_t *readLen) override; - -private: - /* This is the CSP address of the OBC. */ - uint8_t cspClientAddress = 1; - /* Interface struct for csp protocol stack */ - csp_iface_t csp_if; - /* Table definitions. According to gomspace software documentation there - * exist four tables each identified by a number*/ - uint8_t moduleCfgTableNum = 1; - uint8_t calibrationParamTableNum = 2; - uint8_t tmTableNum = 4; - /* Replies of P60 dock are written to this buffer */ - uint8_t replyBuffer[P60DockComIF::maxReplyLength]; - gs_param_table_instance_t table; - -}; - -#endif /* BSP_LINUX_COMIF_P60DOCKCOMIF_H_ */ diff --git a/bsp_linux/comIF/cookies/ArduinoCookie.cpp b/bsp_linux/comIF/cookies/ArduinoCookie.cpp deleted file mode 100644 index d7e81192..00000000 --- a/bsp_linux/comIF/cookies/ArduinoCookie.cpp +++ /dev/null @@ -1,12 +0,0 @@ -//#include -// -//ArduinoCookie::ArduinoCookie(Protocol_t protocol, uint8_t address, -// size_t maxReplySize) : -// command(protocol), address(address), receivedDataLen(0), maxReplySize( -// maxReplySize) { -// replyBuffer = new uint8_t[maxReplySize]; -//} -// -//ArduinoCookie::~ArduinoCookie() { -// delete[] replyBuffer; -//} diff --git a/bsp_linux/comIF/cookies/ArduinoCookie.h b/bsp_linux/comIF/cookies/ArduinoCookie.h deleted file mode 100644 index 64eed4ad..00000000 --- a/bsp_linux/comIF/cookies/ArduinoCookie.h +++ /dev/null @@ -1,25 +0,0 @@ -//#ifndef MISSION_ARDUINO_ARDUINOCOOKIE_H_ -//#define MISSION_ARDUINO_ARDUINOCOOKIE_H_ -// -//#include -// -//#include -//#include -// -//class ArduinoCookie: public Cookie { -//public: -// enum Protocol_t { -// INVALID = 0, SPI = 1 -// }; -// ArduinoCookie(Protocol_t protocol, uint8_t address, size_t maxReplySize); -// virtual ~ArduinoCookie(); -// -// uint8_t command; -// uint8_t address; -// uint8_t *replyBuffer; -// size_t receivedDataLen; -// size_t maxReplySize; -// -//}; -// -//#endif /* MISSION_ARDUINO_ARDUINOCOOKIE_H_ */ diff --git a/bsp_linux/comIF/cookies/P60DockCookie.cpp b/bsp_linux/comIF/cookies/P60DockCookie.cpp deleted file mode 100644 index 4f1c87d2..00000000 --- a/bsp_linux/comIF/cookies/P60DockCookie.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "bsp_linux/comIF/cookies/P60DockCookie.h" - - -P60DockCookie::P60DockCookie(uint8_t cspAddress_) : - cspAddress(cspAddress_) { - -} - -P60DockCookie::~P60DockCookie() { -} - -uint8_t P60DockCookie::getCspAddress(){ - return cspAddress; -} - -char* P60DockCookie::getCanIf(){ - return canInterface; -} - -int P60DockCookie::getBitrate(){ - return bitrate; -} - -void P60DockCookie::resetMessageType(){ - nextMessage = MESSAGE_NONE; -} - -void P60DockCookie::setPingMessage(){ - nextMessage = PING; -} - -void P60DockCookie::setRebootMessage(){ - nextMessage = REBOOT; -} - -void P60DockCookie::setReadModuleCfgMessage(){ - nextMessage = READ_MODULE_CONFIG; -} - -void P60DockCookie::setReadHkMessage(){ - nextMessage = READ_HK; -} - -MessageType_t P60DockCookie::getMessageType(){ - return nextMessage; -} diff --git a/bsp_linux/comIF/cookies/P60DockCookie.h b/bsp_linux/comIF/cookies/P60DockCookie.h deleted file mode 100644 index 8d54104c..00000000 --- a/bsp_linux/comIF/cookies/P60DockCookie.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef BSP_LINUX_COMIF_COOKIES_P60DockCookie_H_ -#define BSP_LINUX_COMIF_COOKIES_P60DockCookie_H_ - -#include - -typedef uint32_t MessageType_t; - -/** - * @brief This is the cookie for the communication interface to the cubesat - * space protocol (CSP) implementation of gomspace. The communication - * interface uses CAN as the physical layer. Therefore the cookie also - * holds the CAN instance to use. - * @author Jakob Meier - */ -class P60DockCookie: public CookieIF { -public: - /** - * Constructor for the CSP cookie - * @param cspAddress_ The CSP address of the target device. - */ - P60DockCookie(uint8_t cspAddress_); - virtual ~P60DockCookie(); - - uint8_t getCspAddress(); - char* getCanIf(); - int getBitrate(); - void setPingMessage(); - void setRebootMessage(); - void setReadModuleCfgMessage(); - void setReadHkMessage(); - MessageType_t getMessageType(); - void resetMessageType(); - - /* Message type defines the type of the next data transfer between the - * CSP device and the OBC. */ - static const MessageType_t MESSAGE_NONE = 0x0; - static const MessageType_t PING = 0x1; - static const MessageType_t REBOOT = 0x4; - static const MessageType_t READ_MODULE_CONFIG = 0x71; - static const MessageType_t READ_HK = 0x74; - - -private: - - char canInterface[5] = "can0"; - uint8_t cspAddress; - int bitrate = 1000; - MessageType_t nextMessage = MESSAGE_NONE; -}; - -#endif /* BSP_LINUX_COMIF_COOKIES_P60DockCookie_H_ */ diff --git a/fsfwconfig/devices/addresses.h b/fsfwconfig/devices/addresses.h index 210881e6..0884d4c5 100644 --- a/fsfwconfig/devices/addresses.h +++ b/fsfwconfig/devices/addresses.h @@ -24,6 +24,7 @@ namespace addresses { /* Addresses of devices supporting the CSP protocol */ enum cspAddresses: uint8_t { P60DOCK = 4, + PDU1 = 3, /* PDU2 occupies X4 slot of P60Dock */ PDU2 = 6 }; diff --git a/fsfwconfig/objects/systemObjectList.h b/fsfwconfig/objects/systemObjectList.h index 52b62db1..c58473cf 100644 --- a/fsfwconfig/objects/systemObjectList.h +++ b/fsfwconfig/objects/systemObjectList.h @@ -31,10 +31,11 @@ namespace objects { /* 0x49 ('I') for Communication Interfaces **/ ARDUINO_COM_IF = 0x49000001, - P60_DOCK_COM_IF = 0x49000002, + CSP_COM_IF = 0x49000002, /* 0x44 ('D') for device handlers */ - P60DOCK_HANDLER = 0x44000001 + P60DOCK_HANDLER = 0x44000001, + PDU2_HANDLER = 0x44000002 }; } diff --git a/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp b/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp index 6370efa5..b038e0fb 100644 --- a/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp +++ b/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp @@ -34,10 +34,13 @@ ReturnValue_t pst::gomspacePstInit(FixedTimeslotTaskIF *thisSequence){ thisSequence->addSlot(objects::P60DOCK_HANDLER, length * 0, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::P60DOCK_HANDLER, length * 0.25, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::P60DOCK_HANDLER, length * 0.5, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::P60DOCK_HANDLER, length * 0.75, DeviceHandlerIF::GET_READ); diff --git a/gomspace/gomspace.mk b/gomspace/gomspace.mk deleted file mode 100644 index 8a781ac8..00000000 --- a/gomspace/gomspace.mk +++ /dev/null @@ -1,22 +0,0 @@ -CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/drivers/can/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/interfaces/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/rtable/csp_rtable_cidr.c) -CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/crypto/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/arch/posix/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/transport/*.c) -CSRC += $(wildcard $(CURRENTPATH)/p60-dock_client/src/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libutil/src/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libutil/src/linux/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libparam_client/src/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libparam_client/src/rparam/*.c) - -INCLUDES += $(CURRENTPATH)/libcsp/include -INCLUDES += $(CURRENTPATH)/libcsp/include/csp/crypto -INCLUDES += $(CURRENTPATH)/libcsp -INCLUDES += $(CURRENTPATH)/p60-dock_client/include/gs/p60-dock/param -INCLUDES += $(CURRENTPATH)/libparam_client/include -INCLUDES += $(CURRENTPATH)/libparam_client/include/deprecated -INCLUDES += $(CURRENTPATH)/libp60_client/include -INCLUDES += $(CURRENTPATH)/libutil/include -INCLUDES += $(CURRENTPATH)/libgscsp/include \ No newline at end of file diff --git a/gomspace/libgscsp/include/gs/csp/address.h b/gomspace/libgscsp/include/gs/csp/address.h deleted file mode 100644 index 9d6e701c..00000000 --- a/gomspace/libgscsp/include/gs/csp/address.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_ADDRESS_H -#define LIBGSCSP_INCLUDE_GS_CSP_ADDRESS_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Default CSP addresses for nodes in the satellite - often changed for each project. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Default address for OBC (On Board Computer). - Example: a3200-sdk. -*/ -#define GS_CSP_ADDR_OBC 1 -/** - Power supply. - Example: nano-power. -*/ -#define GS_CSP_ADDR_EPS 2 -/** - Payload address. -*/ -#define GS_CSP_ADDR_PAYLOAD_3 3 -/** - Default address for ADCS. - Example: a3200-adcs. -*/ -#define GS_CSP_ADDR_ADCS 4 -/** - Default address for radio. - Example: nanocom-ax. -*/ -#define GS_CSP_ADDR_NANOCOM 5 -/** - Payload address. -*/ -#define GS_CSP_ADDR_PAYLOAD_6 6 -/** - Battery pack. - Example: nano-power-bpx. -*/ -#define GS_CSP_ADDR_BPX 7 -/** - Payload address. -*/ -#define GS_CSP_ADDR_PAYLOAD_8 8 -/** - Reaction wheels. - Example: gsw-600. -*/ -#define GS_CSP_ADDR_GSW600 9 -/** - Antenna module. - Example: ant2150. -*/ -#define GS_CSP_ADDR_ANT2150 10 - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/command.h b/gomspace/libgscsp/include/gs/csp/command.h deleted file mode 100644 index 79d518db..00000000 --- a/gomspace/libgscsp/include/gs/csp/command.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_COMMAND_H -#define LIBGSCSP_INCLUDE_GS_CSP_COMMAND_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - CSP commands. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Register CSP commands. - @return_gs_error_t -*/ -gs_error_t gs_csp_register_commands(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/conn.h b/gomspace/libgscsp/include/gs/csp/conn.h deleted file mode 100644 index c8bd755e..00000000 --- a/gomspace/libgscsp/include/gs/csp/conn.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_CONN_H -#define LIBGSCSP_INCLUDE_GS_CSP_CONN_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Extensions to standard libcsp connection interface. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Return number of open connections. - - @return number of open connections. -*/ -size_t gs_csp_conn_get_open(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/csp.h b/gomspace/libgscsp/include/gs/csp/csp.h deleted file mode 100644 index 6268bced..00000000 --- a/gomspace/libgscsp/include/gs/csp/csp.h +++ /dev/null @@ -1,202 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_CSP_H -#define LIBGSCSP_INCLUDE_GS_CSP_CSP_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Extensions to standard libcsp. -*/ - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Default CSP timeout (mS). - - Default timeout value for communicating with a satellite, based on round-trip time of approximately 500 mS. -*/ -#define GS_CSP_TIMEOUT 3000 - -/** - Check if address is a valid CSP adddress. - @param[in] address CSP address to verify - @return \a true if address is valid. -*/ -bool gs_csp_is_address_valid(uint8_t address); - -/** - gscsp and csp configuration. -*/ -typedef struct { - /** - Forward CSP logs to GomSpace log (libutil). - */ - bool use_gs_log; - - /** - Use command line options. - Configure interfaces specified on the command line. - @note Only supported on Linux - ignored on platforms without command line options. - */ - bool use_command_line_options; - - /** - Size of a CSP buffer (in bytes). - @see csp_buffer_init(). - */ - size_t csp_buffer_size; - /** - Number of CSP buffers to allocate. - @see csp_buffer_init(). - */ - size_t csp_buffers; - - /** - CSP address of the system - */ - uint8_t address; - /** - Host name, returned by the #CSP_CMP_IDENT request. - @note String must remain valid as long as the application is running. - */ - const char *hostname; - /** - Model, returned by the #CSP_CMP_IDENT request. - @note String must remain valid as long as the application is running. - */ - const char *model; - /** - Revision, returned by the #CSP_CMP_IDENT request - @note String must remain valid as long as the application is running. - */ - const char *revision; - -} gs_csp_conf_t; - -/** - Get default CSP configuration for server systems. - @param[in] conf user supplied configuration struct. -*/ -void gs_csp_conf_get_defaults_server(gs_csp_conf_t * conf); - -/** - Get default CSP configuration for embedded systems. - @param[in] conf user supplied configuration struct. -*/ -void gs_csp_conf_get_defaults_embedded(gs_csp_conf_t * conf); - -/** - Initialize CSP. - - Wraps initialization of libcsp, by calling following functions - - hooks CSP log system into GomSpace log system. - - initializes CSP buffers by calling csp_buffer_init() - - initializes CSP by calling csp_init() - - configure interfaces specificed on command line - - configure routing table specificed on command line, or default if only one interface is present. - - @param[in] conf configuration. - @return_gs_error_t -*/ -gs_error_t gs_csp_init(const gs_csp_conf_t * conf); - -/** - Perform an entire request/reply transaction, - - Copies both input buffer and reply to output buffer. - Also makes the connection and closes it again - Differ from 'csp_transaction()' by limiting input buffer size when input length is unknown - - @param[in] prio CSP Prio - @param[in] dest CSP Dest - @param[in] port CSP Port - @param[in] timeout timeout in ms - @param[in] tx_buf pointer to outgoing data buffer - @param[in] tx_len length of request to send - @param[out] rx_buf pointer to incoming data buffer - @param[in] rx_max_len length of expected reply (input buffer size) - @param[out] rx_len pointer to length of reply - @param[in] opts connection options. - @return GS_ERROR_OVERFLOW when input length larger than buffer - it still updates rx_buf - @return GS_ERROR_IO when 'csp_send()' or 'csp_read()' fails - @return GS_ERROR_ALLOC when 'csp_get_buffer()' fails - @return_gs_error_t - */ -gs_error_t gs_csp_transaction2(uint8_t prio, - uint8_t dest, - uint8_t port, - uint32_t timeout, - const void * tx_buf, - size_t tx_len, - void * rx_buf, - size_t rx_max_len, - size_t * rx_len, - uint32_t opts); - -/** - Perform an entire request/reply transaction, - - @param[in] prio CSP Prio - @param[in] dest CSP Dest - @param[in] port CSP Port - @param[in] timeout timeout in ms - @param[in] tx_buf pointer to outgoing data buffer - @param[in] tx_len length of request to send - @param[out] rx_buf pointer to incoming data buffer - @param[in] rx_max_len length of expected reply (input buffer size) - @param[out] rx_len pointer to length of reply - @return GS_ERROR_OVERFLOW when input length larger than buffer - it still updates rx_buf - @return GS_ERROR_IO when 'csp_send()' or 'csp_read()' fails - @return GS_ERROR_ALLOC when 'csp_get_buffer()' fails - @return_gs_error_t - @see gs_csp_transaction2() -*/ -static inline gs_error_t gs_csp_transaction(uint8_t prio, - uint8_t dest, - uint8_t port, - uint32_t timeout, - const void * tx_buf, - size_t tx_len, - void * rx_buf, - size_t rx_max_len, - size_t * rx_len) -{ - return gs_csp_transaction2(prio, dest, port, timeout, tx_buf, tx_len, rx_buf, rx_max_len, rx_len, 0); -} - -/** - Use an existing connection to perform a transaction. - - This is only possible if the next packet is on the same port and destination! - Differ from 'csp_transaction_persistent()' by limiting input buffer size when input length is unknown - - @param[in] conn pointer to connection structure - @param[in] timeout timeout in ms - @param[in] tx_buf pointer to outgoing data buffer - @param[in] tx_len length of request to send - @param[out] rx_buf pointer to incoming data buffer - @param[in] rx_max_len length of expected reply (input buffer size) - @param[out] rx_len pointer to length of reply - @return GS_ERROR_OVERFLOW when input length larger than buffer - it still updates rx_buf - @return GS_ERROR_IO when 'csp_send()' or 'csp_read()' fails - @return GS_ERROR_ALLOC when 'csp_get_buffer()' fails - @return_gs_error_t - */ -gs_error_t gs_csp_transaction_persistent(csp_conn_t * conn, - uint32_t timeout, - const void * tx_buf, - size_t tx_len, - void * rx_buf, - size_t rx_max_len, - size_t * rx_len); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/drivers/can/can.h b/gomspace/libgscsp/include/gs/csp/drivers/can/can.h deleted file mode 100644 index 453dabde..00000000 --- a/gomspace/libgscsp/include/gs/csp/drivers/can/can.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_CAN_CAN_H -#define LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_CAN_CAN_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - GomSpace CAN API for CSP. -*/ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Default CAN interface name. -*/ -#define GS_CSP_CAN_DEFAULT_IF_NAME "CAN" - -/** - Initialize CSP for CAN device. - - @param[in] device CAN device - @param[in] csp_addr CSP address. - @param[in] mtu MTU, normally CSP_CAN_MTU. - @param[in] name name of CSP interface, if NULL #GS_CSP_CAN_DEFAULT_IF_NAME will be used. - @param[in] set_default_route if \a true, the device will be set as default route. - @param[out] csp_if the added CSP interface. - @return #GS_ERROR_EXIST if device already exists. - @return_gs_error_t -*/ -gs_error_t gs_csp_can_init2(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, bool set_default_route, csp_iface_t ** csp_if); - -/** - Initialize CSP for CAN device. - - @param[in] device CAN device - @param[in] csp_addr CSP address. - @param[in] mtu MTU, normally CSP_CAN_MTU. - @param[in] name name of CSP interface, if NULL #GS_CSP_CAN_DEFAULT_IF_NAME will be used. - @param[out] csp_if the added CSP interface. - @return #GS_ERROR_EXIST if device already exists. - @return_gs_error_t - @see gs_csp_can_init2() -*/ -gs_error_t gs_csp_can_init(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, csp_iface_t ** csp_if); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h b/gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h deleted file mode 100644 index 4b6204f1..00000000 --- a/gomspace/libgscsp/include/gs/csp/drivers/i2c/i2c.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_I2C_I2C_H -#define LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_I2C_I2C_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - GomSpace I2C API for CSP. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Initialize CSP for I2C device. - @note I2C device must be initialized allready with the same I2C address as the CSP address. - - @param[in] device I2C device. - @param[in] csp_addr CSP address. - @return_gs_error_t -*/ -gs_error_t gs_csp_i2c_init(uint8_t device, uint8_t csp_addr); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h b/gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h deleted file mode 100644 index cb098fce..00000000 --- a/gomspace/libgscsp/include/gs/csp/drivers/kiss/kiss.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_KISS_KISS_H -#define LIBGSCSP_INCLUDE_GS_CSP_DRIVERS_KISS_KISS_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -/** - @file - - GomSpace KISS API for CSP. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Initialize CSP for KISS device. - @note KISS/UART device must be initialized all ready. - - @param[in] device KISS/UART device. - @return_gs_error_t -*/ -gs_error_t gs_csp_kiss_init(uint8_t device); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/error.h b/gomspace/libgscsp/include/gs/csp/error.h deleted file mode 100644 index 8de40787..00000000 --- a/gomspace/libgscsp/include/gs/csp/error.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_ERROR_H -#define LIBGSCSP_INCLUDE_GS_CSP_ERROR_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Converting CSP error codes to #gs_error_t -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Convert CSP error. - - @param[in] csp_error CSP error - @return GS error code representing the CSP error. -*/ -gs_error_t gs_csp_error(int csp_error); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/linux/command_line.h b/gomspace/libgscsp/include/gs/csp/linux/command_line.h deleted file mode 100644 index e416eda5..00000000 --- a/gomspace/libgscsp/include/gs/csp/linux/command_line.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef GS_CSP_LINUX_COMMAND_LINE_H -#define GS_CSP_LINUX_COMMAND_LINE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Command line support. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Command line options. -*/ -extern const struct argp_child gs_csp_command_line_options; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/log.h b/gomspace/libgscsp/include/gs/csp/log.h deleted file mode 100644 index 91360cc0..00000000 --- a/gomspace/libgscsp/include/gs/csp/log.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_LOG_H -#define LIBGSCSP_INCLUDE_GS_CSP_LOG_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - CSP log hook. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Hook into CSP log system. - All CSP logs will be logged through Log (libutil). - - @return_gs_error_t -*/ -gs_error_t gs_csp_log_init(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/port.h b/gomspace/libgscsp/include/gs/csp/port.h deleted file mode 100644 index 29fa32e4..00000000 --- a/gomspace/libgscsp/include/gs/csp/port.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_PORT_H -#define LIBGSCSP_INCLUDE_GS_CSP_PORT_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Port definitions for standard CSP and GomSpace services. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Port definitions for standard CSP and GomSpace services. -*/ -typedef enum { - /** - CSP Management Protocol - standard CSP service. - */ - GS_CSP_CMP = CSP_CMP, // 0 - /** - Ping - standard CSP service. - */ - GS_CSP_PING = CSP_PING, // 1 - /** - Show process status - standard CSP service. - */ - GS_CSP_PS = CSP_PS, // 2 - /** - Show memory free - standard CSP service. - */ - GS_CSP_MEM_FREE = CSP_MEMFREE, // 3 - GS_CSP_MEMFREE = GS_CSP_MEM_FREE, - /** - Reboot/reset request - standard CSP service. - */ - GS_CSP_REBOOT = CSP_REBOOT, // 4 - /** - Show number of free CSP buffers - standard CSP service. - */ - GS_CSP_BUF_FREE = CSP_BUF_FREE, // 5 - /** - Show uptime (time since last reset) - standard CSP service. - */ - GS_CSP_UPTIME = CSP_UPTIME, // 6 - /** - Parameter service (libparam) - */ - GS_CSP_PORT_RPARAM = 7, - /** - File Transfer Service (libftp) - */ - GS_CSP_PORT_FTP = 9, - /** - Remote log service (liblog) - */ - GS_CSP_PORT_RLOG = 11, - /** - Remote GOSH service (librgosh) - */ - GS_CSP_PORT_RGOSH = 12, - /** - AIS command port (libais). - */ - GS_CSP_PORT_AIS = 13, - /** - ADS-B command port (libadsb). - */ - GS_CSP_PORT_ADSB = 14, - - /** - GomSpace Sensor Bus (libgssb). - */ - GS_CSP_PORT_GSSB = 16, - /** - Flight Planner (libfp). - */ - GS_CSP_PORT_FP = 18, - /** - ADCS (libadcs). - */ - GS_CSP_PORT_ADCS = 20, - /** - House Keeping (libhk). - */ - GS_CSP_PORT_HK = 21, - /** - G(omSpace) script service (libgosh) - */ - GS_CSP_PORT_GSCRIPT = 22, - /** - Remote shell (libgosh). - Executes shell commands (linux server only). - Requires CSP_O_RDP. - */ - GS_CSP_PORT_REMOTE_SHELL = 27, - /** - House keeping beacon port (libhk). - Default port for sending beacons from satellite to ground (configurable). - */ - GS_CSP_PORT_HK_BEACON = 30, - -} gs_csp_port_t; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/router.h b/gomspace/libgscsp/include/gs/csp/router.h deleted file mode 100644 index dae8990a..00000000 --- a/gomspace/libgscsp/include/gs/csp/router.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_ROUTER_H -#define LIBGSCSP_INCLUDE_GS_CSP_ROUTER_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - CSP router task, with support for stopping/terminating router task. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Start CSP router (task/thread). - @param[in] stack_size stack size in bytes, minimum 300 bytes. - @param[in] priority task priority, normally GS_THREAD_PRIORITY_HIGH. - @return_gs_error_t -*/ -gs_error_t gs_csp_router_task_start(size_t stack_size, gs_thread_priority_t priority); - -/** - Stop CSP router task (for testing). - - Signal stop to the router and waits for it to terminate (join). - @note Join is performed, which may hang forever if the router doesn't respond to the stop request. - @return_gs_error_t -*/ -gs_error_t gs_csp_router_task_stop(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/rtable.h b/gomspace/libgscsp/include/gs/csp/rtable.h deleted file mode 100644 index 511b7bc2..00000000 --- a/gomspace/libgscsp/include/gs/csp/rtable.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef GS_CSP_RTABLE_H -#define GS_CSP_RTABLE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - CSP routing table support. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Load routing table. - Extension to csp_rtable_load(). - - @param[in] rtable string containing the routing table to set/load. - @param[in] set_default_route if \a true, sets a default route if no routing table specified and only one interface configured. - @param[in] use_command_line_option if \a true (and command line supported), use command line options to configure routing. - @return_gs_error_t -*/ -gs_error_t gs_csp_rtable_load(const char * rtable, bool set_default_route, bool use_command_line_option); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/service_dispatcher.h b/gomspace/libgscsp/include/gs/csp/service_dispatcher.h deleted file mode 100644 index e80ef66d..00000000 --- a/gomspace/libgscsp/include/gs/csp/service_dispatcher.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_SERVICE_DISPATCHER_H -#define LIBGSCSP_INCLUDE_GS_CSP_SERVICE_DISPATCHER_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - CSP Service Dispatcher. - - The dispatcher is a task/thread, listening on a configured number of ports and forwards the the incoming connection - to a configured CSP service handler. - The dispatcher touches a software watchdog for every handled connection. -*/ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - CSP service dispatcher configuration. -*/ -typedef struct { - /** - Name of dispatcher. - */ - const char * name; - /** - Array of service handlers - index'ed by CSP port number. - */ - const gs_csp_service_handler_t * handler_array; - /** - Array size of \a handler_array. - */ - unsigned int handler_array_size; - /** - Bind to any unbound ports (CSP_ANY). - Only one task/dispatcher can bind to any ports. This can be used to log unexpected incoming connections. - */ - bool bind_any; - /** - Disable watchdog. - The watchdog is created with a fixed timeout of 20 seconds. - */ - bool disable_watchdog; - /** - CSP connection backlog. - If 0 (zero), the backlog is set to 10. - */ - size_t listen_backlog; - /** - Callback after timeout or processsed connection. - The return value is the next timeout in milli seconds. - Return UINT32_MAX to use default timeout. - */ - unsigned int (*callback)(void); - /** - Socket options. - */ - uint32_t socket_options; -} gs_csp_service_dispatcher_conf_t; - -/** - Basic CSP service handlers. - - Can be used to configure handlers for all basic CSP services. -*/ -#define GS_CSP_BASIC_SERVICE_HANDLERS \ - [GS_CSP_CMP] = gs_csp_cmp_service_handler, \ - [GS_CSP_PING] = gs_csp_ping_service_handler, \ - [GS_CSP_PS] = gs_csp_ps_service_handler, \ - [GS_CSP_MEMFREE] = gs_csp_mem_free_service_handler, \ - [GS_CSP_REBOOT] = gs_csp_reboot_service_handler, \ - [GS_CSP_BUF_FREE] = gs_csp_buf_free_service_handler, \ - [GS_CSP_UPTIME] = gs_csp_uptime_service_handler - -/** - Service dispatcher handle. - @see gs_csp_service_dispatcher_create(), gs_csp_service_dispatcher_close() -*/ -typedef struct gs_csp_service_dispatcher * gs_csp_service_dispatcher_t; - -/** - Create service dispatcher (task/thread). - - @param[in] conf configuration - must remain valid as long as the dispatcher is running. - @param[in] stack_size thread stack size. - @param[in] priority thread priority. - @param[out] return_handle created dispatcher - use NULL if not used. - @return_gs_error_t -*/ -gs_error_t gs_csp_service_dispatcher_create(const gs_csp_service_dispatcher_conf_t * conf, - size_t stack_size, - gs_thread_priority_t priority, - gs_csp_service_dispatcher_t * return_handle); - -/** - Wake up service dispatcher. - - This will cause the disapther to wake up (from listing for new connections), and invoke the configured \a callback function, - before listing for new connections. - - @param[in] handle dispatcher. - @return_gs_error_t -*/ -gs_error_t gs_csp_service_dispatcher_wake_up(gs_csp_service_dispatcher_t handle); - -/** - Destroy/close service dispatcher (for testing). - - Signal stop to the dispatcher and waits for it to terminate (join). - - @note Join is performed, which may hang forever if the dispatcher doesn't respond to the stop request. - @param[in] handle dispatcher. - @return_gs_error_t -*/ -gs_error_t gs_csp_service_dispatcher_destroy(gs_csp_service_dispatcher_t handle); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/include/gs/csp/service_handler.h b/gomspace/libgscsp/include/gs/csp/service_handler.h deleted file mode 100644 index 52479129..00000000 --- a/gomspace/libgscsp/include/gs/csp/service_handler.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef LIBGSCSP_INCLUDE_GS_CSP_SERVICE_HANDLER_H -#define LIBGSCSP_INCLUDE_GS_CSP_SERVICE_HANDLER_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - CSP Service handler. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - CSP Service handler. - - It is the handler's responsibility to process all pakcets on the connection and close the connection when done - even if a failure - is returned. - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -typedef gs_error_t (*gs_csp_service_handler_t)(csp_conn_t * conn); - -/** - Service handler for CSP Management Protocol. - - Invokes standard libcsp service handler. - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -gs_error_t gs_csp_cmp_service_handler(csp_conn_t * conn); - -/** - Service handler for ping. - - Invokes standard libcsp service handler. - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -gs_error_t gs_csp_ping_service_handler(csp_conn_t * conn); - -/** - Service handler for getting process list. - - Invokes standard libcsp service handler. - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -gs_error_t gs_csp_ps_service_handler(csp_conn_t * conn); - -/** - Service handler for getting memory free. - - Invokes GomSpace handler, which doesn't use malloc() to determine \a free memory. - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -gs_error_t gs_csp_mem_free_service_handler(csp_conn_t * conn); - - -/** - Service handler for reboot (reset) of node. - - Invokes standard libcsp service handler. - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -gs_error_t gs_csp_reboot_service_handler(csp_conn_t * conn); - -/** - Service handler for getting free CSP buffers. - - Invokes standard libcsp service handler. - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -gs_error_t gs_csp_buf_free_service_handler(csp_conn_t * conn); - -/** - Service handler for getting uptime (in seconds). - - Invokes GomSpace handler (works on Linux). - - @param[in] conn incoming connection. - @return_gs_error_t -*/ -gs_error_t gs_csp_uptime_service_handler(csp_conn_t * conn); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/lib/libcsp/CHANGELOG b/gomspace/libgscsp/lib/libcsp/CHANGELOG deleted file mode 100644 index a4945716..00000000 --- a/gomspace/libgscsp/lib/libcsp/CHANGELOG +++ /dev/null @@ -1,113 +0,0 @@ -libcsp 1.4, 07-05-2015 ----------------------- -- new: General rtable interface with support for STATIC or CIDR format -- new: CIDR (classless interdomain routing) route table format with netmasks -- new: Bridge capability -- new: Added routing table (de)serialization functions for load/save -- new: Automatic packet deduplication using CRC32 (compile time option) -- new: Autogenerated python bindings using ctypesgen -- new: Task-less operation with router invocation from external scheduler function -- api: Refactor route_if_add to csp_iflist_add -- api: Refactor route_set and friends to rtable_set -- api: Refactor csp_fifo_qos to csp_qfifo -- api: Added defined to be backwards compatible with 1.x -- interfaces: Drop packets on LOOP interface not for own address (blackhole) -- interfaces: New ZMQHUB interface (using zeroMQ over TCP) -- other: Increase stack size from 250 to 1100 for csp_can_rx_task -- other: Cleanup in csp_route.c -- other: Show incoming interface name in debug message -- other: Remove newlines from debug calls -- improvement: Reduce debug hook function complexity with valist passing -- fix: csp_sleep_ms did not work - -libcsp 1.3, 07-05-2015 ----------------------- -- new: Split long process lists into multiple packets -- new: Added posix csp_clock.h -- new: cmp clock functions (requires that you provide csp_clock.h implementation) -- new: Added SFP (Small fragmentation protocol) for larger data chunks -- fix: csp_if_fifo example -- fix: NULL char at the end of rps -- doc: Updated mtu documentation -- other: Tested with FreeRTOS 8.0 -- other: Added disable-stlib option to build only object files - -libcsp 1.2, 25-10-2013 ----------------------- -- Feature release -- New: CMP service for peek and poke of memory -- New: CMP interface statistics struct is now packed -- New: Faster O(1) buffer system with reference counting and automatic alignment -- New: Thread safe KISS driver with support for multiple interfaces -- New: CSP interface struct now holds an opaque pointer to driver handle -- New: removed TXBUF from KISS driver entirely to minimize stack usage, added TX lock instead -- New: Pre-calculated CRC table .romem or PROGMEM on __avr__ -- New: Added buffer overflow protection to KISS interface -- New: Allow posting null pointers on conn RX queues -- New: Lower memory usage on AVR8 -- New: csp_route_save and csp_route_load functions -- New: option --disable-verbose to disable filenames and linenumber on debug -- Protocol: KISS uses csp_crc32 instead of it own embedded crc32 -- Improvement: Use buffer clone function to copy promisc packets -- Bugfix: Fix pointer size (32/16bit) in cmp_peek/poke -- Bugfix: Issue with double free in KISS fixed -- Bugfix: Change rdp_send timeout from packet to connection timeout to make sending task block longer -- Bugfix: Fix conn pool leak when using security check and discarding new packets -- Bugfix: Add packet too short check for CRC32 -- Bugfix: Accept CRC32 responses from nodes without CRC support -- Bugfix: Ensure csp_ping works for packets > 256 bytes -- Bugfix: Cleanup printf inside ISR functions -- Bugfix: Do not add forwarded packets to promisc queue twice -- Bugfix: Fix return value bug of csp_buffer_get when out of buffers -- Bugfix: Always post null pointer with lowest priority, not highest -- Bugfix: Add check on debug level before calling do_csp_debug, fixes #35 -- Other: Export csp/arch include files -- Other: Remove the use of bool type from csp_debug -- Other: Moved csp debug functions to csp_debug.h instead of csp.h -- Other: Ensure assignment of id happens using the uint32_t .ext value of the union, quenches warning - -libcsp 1.1, 24-08-2012 ----------------------- -- Feature release -- Defacto stable since Feb 2012 -- New: I2C interface -- New: KISS interface -- New: USART drivers for Linux, Mac and Windows -- New: Windows/MinGW support -- New: MacOSX support -- New: Interface register function -- New: Interface search function -- New: CMP service for remote route updating -- New: CMP service for interface statistics -- Improvement: Better QoS support -- Improvement: Send RDP control messages with high priority -- Improvement: WAF distcheck now works -- Improvement: Automatic endian discovery -- Improvement: Accept packets with CRC32 checksum if compiled without CRC32 support -- Improvement: Do not wake the router task if RDP is not enabled -- Improvement: Save 102 bytes of RAM by packing route entries -- Cleanup: Simplify CAN configuration -- Cleanup: Move architecture specific code to src/arch -- Bugfix: CSP_MEMFREE gives wrong answer on freertos AVR due to truncation -- Bugfix: Fixed wrong 64-bit size_t in csp_service_handler -- Bugfix: Fixed problem in csp_if_kiss when out of buffers -- Bigfix: Handle bus-off CAN IRQ for AT90CAN128 - -libcsp 1.0.1, 30-10-2011 ------------------------- -- Hotfix release -- Bugfix: missing extern in csp_if_lo.h - -libcsp 1.0, 24-10-2011 ----------------------- -- First official release -- New: CSP 32-bit header 1.0 -- Features: Network Router with promiscous mode, broadcast and QoS -- Features: Connection-oriented transport protocol w. flow-control -- Features: Connection-less "UDP" like transport -- Features: Encryption, Authentication and message check -- Features: Loopback interface -- Features: Python Bindings -- Features: CAN interface w. drivers for several chips -- Features: CSP-services (ping, reboot, uptime, memfree, buffree, ident) - diff --git a/gomspace/libgscsp/lib/libcsp/CONTRIBUTORS b/gomspace/libgscsp/lib/libcsp/CONTRIBUTORS deleted file mode 100644 index 97240f60..00000000 --- a/gomspace/libgscsp/lib/libcsp/CONTRIBUTORS +++ /dev/null @@ -1,3 +0,0 @@ -Jeppe Ledet-Pedersen -Johan De Claville Christiansen -Dan Erik Holmstrøm diff --git a/gomspace/libgscsp/lib/libcsp/COPYING b/gomspace/libgscsp/lib/libcsp/COPYING deleted file mode 100644 index 54c619ad..00000000 --- a/gomspace/libgscsp/lib/libcsp/COPYING +++ /dev/null @@ -1,503 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - diff --git a/gomspace/libgscsp/lib/libcsp/INSTALL.rst b/gomspace/libgscsp/lib/libcsp/INSTALL.rst deleted file mode 100644 index e68a46ed..00000000 --- a/gomspace/libgscsp/lib/libcsp/INSTALL.rst +++ /dev/null @@ -1,30 +0,0 @@ -How to install LibCSP -===================== - -CSP uses the `waf` build system (http://code.google.com/p/waf/). In order to -compile CSP, you first need to configure the toolchain, what operating system -to compile for, the location of required libraries and whether to enable -certain optional features. - -To configure CSP to build with the AVR32 toolchain for FreeRTOS and output -the compiled libcsp.a and header files to the install directory, issue: - -.. code-block:: bash - - ./waf configure --toolchain=avr32- --with-os=freertos --prefix=install - -When compiling for FreeRTOS, the path to the FreeRTOS header files must be -specified with `--with-freertos=PATH.` - -A number of optional features can be enabled by from the configure script. -Support for XTEA encryption can e.g. be enabled with `--enable-xtea`. Run -`./waf configure --help` to list the available configure options. - -The CAN drivers can be enabled by appending the configure option `--with-driver-can=CHIP`, -where CHIP is one of 'socketcan', 'at91sam7a1', 'at91sam7a3' or 'at90can128'. - -To build and copy the library to the location specified with --prefix, use: - -.. code-block:: bash - - ./waf build install diff --git a/gomspace/libgscsp/lib/libcsp/README.rst b/gomspace/libgscsp/lib/libcsp/README.rst deleted file mode 100644 index c8aff3d8..00000000 --- a/gomspace/libgscsp/lib/libcsp/README.rst +++ /dev/null @@ -1,41 +0,0 @@ -The Cubesat Space Protocol -========================== - -Cubesat Space Protocol (CSP) is a small protocol stack written in C. CSP is designed to ease communication between distributed embedded systems in smaller networks, such as Cubesats. The design follows the TCP/IP model and includes a transport protocol, a routing protocol and several MAC-layer interfaces. The core of libcsp includes a router, a socket buffer pool and a connection oriented socket API. - -The protocol is based on a 32-bit header containing both transport and network-layer information. Its implementation is designed for, but not limited to, embedded systems such as the 8-bit AVR microprocessor and the 32-bit ARM and AVR from Atmel. The implementation is written in GNU C and is currently ported to run on FreeRTOS or POSIX operating systems such as Linux. - -The idea is to give sub-system developers of cubesats the same features of a TCP/IP stack, but without adding the huge overhead of the IP header. The small footprint and simple implementation allows a small 8-bit system with less than 4 kB of RAM to be fully connected on the network. This allows all subsystems to provide their services on the same network level, without any master node required. Using a service oriented architecture has several advantages compared to the traditional mater/slave topology used on many cubesats. - - * Standardised network protocol: All subsystems can communicate with eachother - * Service loose coupling: Services maintain a relationship that minimizes dependencies between subsystems - * Service abstraction: Beyond descriptions in the service contract, services hide logic from the outside world - * Service reusability: Logic is divided into services with the intention of promoting reuse. - * Service autonomy: Services have control over the logic they encapsulate. - * Service Redundancy: Easily add redundant services to the bus - * Reduces single point of failure: The complexity is moved from a single master node to several well defines services on the network - -The implementation of LibCSP is written with simplicity in mind, but it's compile time configuration allows it to have some rather advanced features as well: - -Features --------- - - * Thread safe Socket API - * Router task with Quality of Services - * Connection-oriented operation (RFC 908 and 1151). - * Connection-less operation (similar to UDP) - * ICMP-like requests such as ping and buffer status. - * Loopback interface - * Very Small Footprint 48 kB code and less that 1kB ram required on ARM - * Zero-copy buffer and queue system - * Modular network interface system - * Modular OS interface, ported to FreeRTOS, windows (cygwin) and Linux - * Broadcast traffic - * Promiscuous mode - * Encrypted packets with XTEA in CTR mode - * Truncated HMAC-SHA1 Authentication (RFC 2104) - -LGPL Software license ---------------------- -The source code is available under an LGPL 2.1 license. See COPYING for the license text. - diff --git a/gomspace/libgscsp/lib/libcsp/bindings/python/libcsp/__init__.py b/gomspace/libgscsp/lib/libcsp/bindings/python/libcsp/__init__.py deleted file mode 100644 index 39de36b5..00000000 --- a/gomspace/libgscsp/lib/libcsp/bindings/python/libcsp/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -import sys - -if sys.version_info >= (3, 0): - from libcsp_py3 import * -else: - from libcsp_py2 import * diff --git a/gomspace/libgscsp/lib/libcsp/doc/example.rst b/gomspace/libgscsp/lib/libcsp/doc/example.rst deleted file mode 100644 index b82a055e..00000000 --- a/gomspace/libgscsp/lib/libcsp/doc/example.rst +++ /dev/null @@ -1,123 +0,0 @@ -Client and server example -========================= - -The following examples show the initialization of the protocol stack and examples of client/server code. - -Initialization Sequence ------------------------ - -This code initializes the CSP buffer system, device drivers and router core. The example uses the CAN interface function csp_can_tx but the initialization is similar for other interfaces. The loopback interface does not require any explicit initialization. - -.. code-block:: c - - #include - #include - - /* CAN configuration struct for SocketCAN interface "can0" */ - struct csp_can_config can_conf = {.ifc = "can0"}; - - /* Init buffer system with 10 packets of maximum 320 bytes each */ - csp_buffer_init(10, 320); - - /* Init CSP with address 1 */ - csp_init(1); - - /* Init the CAN interface with hardware filtering */ - csp_can_init(CSP_CAN_MASKED, &can_conf) - - /* Setup default route to CAN interface */ - csp_route_set(CSP_DEFAULT_ROUTE, &csp_can_tx, CSP_HOST_MAC); - - /* Start router task with 500 word stack, OS task priority 1 */ - csp_route_start_task(500, 1); - -Server ------- - -This example shows how to create a server task that listens for incoming connections. CSP should be initialized before starting this task. Note the use of `csp_service_handler()` as the default branch in the port switch case. The service handler will automatically reply to ICMP-like requests, such as pings and buffer status requests. - -.. code-block:: c - - void csp_task(void *parameters) { - /* Create socket without any socket options */ - csp_socket_t *sock = csp_socket(CSP_SO_NONE); - - /* Bind all ports to socket */ - csp_bind(sock, CSP_ANY); - - /* Create 10 connections backlog queue */ - csp_listen(sock, 10); - - /* Pointer to current connection and packet */ - csp_conn_t *conn; - csp_packet_t *packet; - - /* Process incoming connections */ - while (1) { - /* Wait for connection, 10000 ms timeout */ - if ((conn = csp_accept(sock, 10000)) == NULL) - continue; - - /* Read packets. Timout is 1000 ms */ - while ((packet = csp_read(conn, 1000)) != NULL) { - switch (csp_conn_dport(conn)) { - case MY_PORT: - /* Process packet here */ - default: - /* Let the service handler reply pings, buffer use, etc. */ - csp_service_handler(conn, packet); - break; - } - } - - /* Close current connection, and handle next */ - csp_close(conn); - } - } - -Client ------- - -This example shows how to allocate a packet buffer, connect to another host and send the packet. CSP should be initialized before calling this function. RDP, XTEA, HMAC and CRC checksums can be enabled per connection, by setting the connection option to a bitwise OR of any combination of `CSP_O_RDP`, `CSP_O_XTEA`, `CSP_O_HMAC` and `CSP_O_CRC`. - -.. code-block:: c - - int send_packet(void) { - - /* Get packet buffer for data */ - csp_packet_t *packet = csp_buffer_get(data_size); - if (packet == NULL) { - /* Could not get buffer element */ - printf("Failed to get buffer element\\n"); - return -1; - } - - /* Connect to host HOST, port PORT with regular UDP-like protocol and 1000 ms timeout */ - csp_conn_t *conn = csp_connect(CSP_PRIO_NORM, HOST, PORT, 1000, CSP_O_NONE); - if (conn == NULL) { - /* Connect failed */ - printf("Connection failed\\n"); - /* Remember to free packet buffer */ - csp_buffer_free(packet); - return -1; - } - - /* Copy message to packet */ - char *msg = "HELLO"; - strcpy(packet->data, msg); - - /* Set packet length */ - packet->length = strlen(msg); - - /* Send packet */ - if (!csp_send(conn, packet, 1000)) { - /* Send failed */ - printf("Send failed\\n"); - csp_buffer_free(packet); - } - - /* Close connection */ - csp_close(conn); - - return 0 - } diff --git a/gomspace/libgscsp/lib/libcsp/doc/history.rst b/gomspace/libgscsp/lib/libcsp/doc/history.rst deleted file mode 100644 index ad064873..00000000 --- a/gomspace/libgscsp/lib/libcsp/doc/history.rst +++ /dev/null @@ -1,17 +0,0 @@ -History -======= - -The idea was developed by a group of students from Aalborg University in 2008. In 2009 the main developer started working for GomSpace, and CSP became integrated into the GomSpace products. The protocol is based on a 32-bit header containing both transport, network and MAC-layer information. It's implementation is designed for, but not limited to, embedded systems such as the 8-bit AVR microprocessor and the 32-bit ARM and AVR from Atmel. The implementation is written in C and is currently ported to run on FreeRTOS and POSIX and pthreads based operating systems like Linux and BSD. The three letter acronym CSP was originally an abbreviation for CAN Space Protocol because the first MAC-layer driver was written for CAN-bus. Now the physical layer has extended to include spacelink, I2C and RS232, the name was therefore extended to the more general CubeSat Space Protocol without changing the abbreviation. - -Satellites using CSP --------------------- - -This is the known list of satellites or organisations that uses CSP. - - * GomSpace GATOSS GOMX-1 - * AAUSAT-3 - * EgyCubeSat - * EuroLuna - * NUTS - * Hawaiian Space Flight Laboratory - * GomSpace GOMX-3 diff --git a/gomspace/libgscsp/lib/libcsp/doc/interfaces.rst b/gomspace/libgscsp/lib/libcsp/doc/interfaces.rst deleted file mode 100644 index 5a80325c..00000000 --- a/gomspace/libgscsp/lib/libcsp/doc/interfaces.rst +++ /dev/null @@ -1,95 +0,0 @@ -CSP Interfaces -============== - -This is an example of how to implement a new layer-2 interface in CSP. The example is going to show how to create a `csp_if_fifo`, using a set of [named pipes](http://en.wikipedia.org/wiki/Named_pipe). The complete interface example code can be found in `examples/fifo.c`. For an example of a fragmenting interface, see the CAN interface in `src/interfaces/csp_if_can.c`. - -CSP interfaces are declared in a `csp_iface_t` structure, which sets the interface nexthop function and name. A maximum transmission unit can also be set, which forces CSP to drop outgoing packets above a certain size. The fifo interface is defined as: - -.. code-block:: c - - #include - #include - - csp_iface_t csp_if_fifo = { - .name = "fifo", - .nexthop = csp_fifo_tx, - .mtu = BUF_SIZE, - }; - -Outgoing traffic ----------------- - -The nexthop function takes a pointer to a CSP packet and a timeout as parameters. All outgoing packets that are routed to the interface are passed to this function: - -.. code-block:: c - - int csp_fifo_tx(csp_packet_t *packet, uint32_t timeout) { - write(tx_channel, &packet->length, packet->length + sizeof(uint32_t) + sizeof(uint16_t)); - csp_buffer_free(packet); - return 1; - } - -In the fifo interface, we simply transmit the header, length field and data using a write to the fifo. CSP does not dictate the wire format, so other interfaces may decide to e.g. ignore the length field if the physical layer provides start/stop flags. - -_Important notice: If the transmission succeeds, the interface must free the packet and return 1. If transmission fails, the nexthop function should return 0 and not free the packet, to allow retransmissions by the caller._ - -Incoming traffic ----------------- - -The interface also needs to receive incoming packets and pass it to the CSP protocol stack. In the fifo interface, this is handled by a thread that blocks on the incoming fifo and waits for packets: - -.. code-block:: c - - void * fifo_rx(void * parameters) { - csp_packet_t *buf = csp_buffer_get(BUF_SIZE); - /* Wait for packet on fifo */ - while (read(rx_channel, &buf->length, BUF_SIZE) > 0) { - csp_qfifo_write(buf, &csp_if_fifo, NULL); - buf = csp_buffer_get(BUF_SIZE); - } - } - -A new CSP buffer is preallocated with csp_buffer_get(). When data is received, the packet is passed to CSP using `csp_qfifo_write()` and a new buffer is allocated for the next packet. In addition to the received packet, `csp_qfifo_write()` takes two additional arguments: - -.. code-block:: c - - void csp_qfifo_write(csp_packet_t *packet, csp_iface_t *interface, CSP_BASE_TYPE *pxTaskWoken); - -The calling interface must be passed in `interface` to avoid routing loops. Furthermore, `pxTaskWoken` must be set to a non-NULL value if the packet is received in an interrupt service routine. If the packet is received in task context, NULL must be passed. 'pxTaskWoken' only applies to FreeRTOS systems, and POSIX system should always set the value to NULL. - -`csp_qfifo_write` will either accept the packet or free the packet buffer, so the interface must never free the packet after passing it to CSP. - -Initialization --------------- - -In order to initialize the interface, and make it available to the router, use the following function found in `csp/csp_interface.h`: - -.. code-block:: c - - csp_route_add_if(&csp_if_fifo); - -This actually happens automatically if you try to call `csp_route_add()` with an interface that is unknown to the router. This may however be removed in the future, in order to ensure that all interfaces are initialised before configuring the routing table. The reason is, that some products released in the future may ship with an empty routing table, which is then configured by a routing protocol rather than a static configuration. - -In order to setup a manual static route, use the following example where the default route is set to the fifo interface: - -.. code-block:: c - - csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_fifo, CSP_NODE_MAC); - -All outgoing traffic except loopback, is now passed to the fifo interface's nexthop function. - -Building the example --------------------- - -The fifo examples can be compiled with: - -.. code-block:: bash - - % gcc csp_if_fifo.c -o csp_if_fifo -I/include -L/build -lcsp -lpthread -lrt - -The two named pipes are created with: - -.. code-block:: bash - - % mkfifo server_to_client client_to_server - diff --git a/gomspace/libgscsp/lib/libcsp/doc/libcsp.rst b/gomspace/libgscsp/lib/libcsp/doc/libcsp.rst deleted file mode 100644 index f866015f..00000000 --- a/gomspace/libgscsp/lib/libcsp/doc/libcsp.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. CSP Documentation master file. - -.. _libcsp: - -********************** -CubeSat Space Protocol -********************** - -.. toctree:: - :maxdepth: 3 - - ../README - history - structure - interfaces - memory - protocolstack - topology - mtu - example - diff --git a/gomspace/libgscsp/lib/libcsp/doc/memory.rst b/gomspace/libgscsp/lib/libcsp/doc/memory.rst deleted file mode 100644 index 4e38d711..00000000 --- a/gomspace/libgscsp/lib/libcsp/doc/memory.rst +++ /dev/null @@ -1,28 +0,0 @@ -How CSP uses memory -=================== - -CSP has been written for small microprocessor systems. The way memory is handled is therefore a tradeoff between the amount used and the code efficiency. This section tries to give some answers to what the memory is used for and how it it used. The primary memory blocks in use by CSP is: - - * Routing table - * Ports table - * Connection table - * Buffer pool - * Interface list - -Tables ------- -The reason for using tables for the routes, ports and connections is speed. When a new packet arrives the core of CSP needs to do a quick lookup in the connection so see if it can find an existing connection to which the packet matches. If this is not found, it will take a lookup in the ports table to see if there are any applications listening on the incoming port number. Another argument of using tables are pre-allocation. The linker will reserve an area of the memory for which the routes and connections can be stored. This avoid an expensive `malloc()` call during initialization of CSP, and practically costs zero CPU instructions. The downside of using tables are the wasted memory used by unallocated ports and connections. For the routing table the argumentation is the same, pre-allocation is better than calling `malloc()`. - -Buffer Pool ------------ - -The buffer handling system can be compiled for either static allocation or a one-time dynamic allocation of the main memory block. After this, the buffer system is entirely self-contained. All allocated elements are of the same size, so the buffer size must be chosen to be able to handle the maximum possible packet length. The buffer pool uses a queue to store pointers to free buffer elements. First of all, this gives a very quick method to get the next free element since the dequeue is an O(1) operation. Furthermore, since the queue is a protected operating system primitive, it can be accessed from both task-context and interrupt-context. The `csp_buffer_get` version is for task-context and `csp_buffer_get_isr` is for interrupt-context. Using fixed size buffer elements that are preallocated is again a question of speed and safety. - - -A basic concept of the buffer system is called Zero-Copy. This means that from userspace to the kernel-driver, the buffer is never copied from one buffer to another. This is a big deal for a small microprocessor, where a call to `memcpy()` can be very expensive. In practice when data is inserted into a packet, it is shifted a certain number of bytes in order to allow for a packet header to be prepended at the lower layers. This also means that there is a strict contract between the layers, which data can be modified and where. The buffer object is normally casted to a `csp_packet_t`, but when its given to an interface on the MAC layer it's casted to a `csp_i2c_frame_t` for example. - -Interface list --------------- - -The interface list is a simple single-ended linked list of references to the interface specification structures. These structures are static const and allocated by the linker. The pointer to this data is inserted into the list one time during setup of the interface. Each entry in the routing table has a direct pointer to the interface element, thereby avoiding list lookup, but the list is needed in order for the dynamic route configuration to know which interfaces are available. - diff --git a/gomspace/libgscsp/lib/libcsp/doc/mtu.rst b/gomspace/libgscsp/lib/libcsp/doc/mtu.rst deleted file mode 100644 index 27753300..00000000 --- a/gomspace/libgscsp/lib/libcsp/doc/mtu.rst +++ /dev/null @@ -1,19 +0,0 @@ -Maximum Transfer Unit -===================== - -There are two things limiting the MTU of CSP. - - 1. The pre-allocated buffer pool’s allocation size - 2. The link layer protocol. - -So let’s assume that you have made a protocol called KISS with a MTU of 256. The 256 is the total amount of data that you can put into the CSP-packet. However, you need to take the overhead of the link layer into account. Typically this could consist of a length field and/or a start/stop flag. So the actual frame size on the link layer would for example be 256 bytes of data + 2 bytes sync flag + 2 bytes length field. - -This requires a buffer allocation of at lest 256 + 2 + 2. However, the CSP packet itself has some reserved bytes in the beginning of the packet (which you can see in csp.h) - so the recommended buffer allocation size is MAX MTU + 16 bytes. In this case the max MTU would be 256. - -If you try to pass data which is longer than the MTU, the chance is that you will also make a buffer overflow in the CSP buffer pool. However, lets assume that you have two interfaces one with an MTU of 200 bytes and another with an MTU of 100 bytes. In this case you might successfully transfer 150 bytes over the first interface, but the packet will be rejected once it comes to the second interface. - -If you want to increase your MTU of a specific link layer, it is up to the link layer protocol to implement its own fragmentation protocol. A good example is CAN-bus which only allows a frame size of 8 bytes. libcsp have a small protocol for this called the “CAN fragmentation protocol" or CFP for short. This allows data of much larger size to be transferred over the CAN bus. - -Okay, but what if you want to transfer 1000 bytes, and the network maximum MTU is 256? Well, since CSP does not include streaming sockets, only packet’s. Somebody will have to split that data up into chunks. It might be that you application have special knowledge about the datatype you are transmitting, and that it makes sense to split the 1000 byte content into 10 chunks of 100 byte status messages. This, application layer delimitation might be good if you have a situation with packet loss, because your receiver could still make good usage of the partially delivered chunks. - -But, what if you just want 1000 bytes transmitted, and you don’t care about the fragmentation unit, and also don’t want the hassle of writing the fragmentation code yourself? - In this case, libcsp now features a new (still experimental) feature called SFP (small fragmentation protocol) designed to work on the application layer. For this purpose you will not use csp_send and csp_recv, but csp_sfp_send and csp_sfp_recv. This will split your data into chunks of a certain size, enumerate them and transfer over a given connection. If a chunk is missing the SFP client will abort the reception, because SFP does not provide retransmission. If you wish to also have retransmission and orderly delivery you will have to open an RDP connection and send your SFP message to that connection. diff --git a/gomspace/libgscsp/lib/libcsp/doc/protocolstack.rst b/gomspace/libgscsp/lib/libcsp/doc/protocolstack.rst deleted file mode 100644 index 365aabbe..00000000 --- a/gomspace/libgscsp/lib/libcsp/doc/protocolstack.rst +++ /dev/null @@ -1,54 +0,0 @@ -The Protocol Stack -================== - -The CSP protocol stack includes functionality on all layers of the TCP/IP model: - -Layer 1: Drivers ----------------- - -Lib CSP is not designed for any specific processor or hardware peripheral, but yet these drivers are required in order to work. The intention of LibCSP is not to provide CAN, I2C or UART drivers for all platforms, however some drivers has been included for some platforms. If you do not find your platform supported, it is quite simple to add a driver that conforms to the CSP interfaces. For example the I2C driver just requires three functions: `init`, `send` and `recv`. For good stability and performance interrupt driven drivers are preferred in favor of polled drivers. Where applicable also DMA usage is recommended. - -Layer 2: MAC interfaces ------------------------ - -CSP has interfaces for I2C, CAN, RS232 (KISS) and Loopback. The layer 2 protocol software defines a frame-format that is suitable for the media. CSP can be easily extended with implementations for even more links. For example a radio-link and IP-networks. The file `csp_interface.h` declares the rx and tx functions needed in order to define a network interface in CSP. During initialisation of CSP each interface will be inserted into a linked list of interfaces that is available to the router. In cases where link-layer addresses are required, such as I2C, the routing table supports specifying next-hop link-layer address directly. This avoids the need to implement an address resolution protocol to translate CSP addresses to I2C addresses. - -Layer 3: Network Router ------------------------ - -The router core is the backbone of the CSP implementation. The router works by looking at a 32-bit CSP header which contains the delivery and source address together with port numbers for the connection. Each router supports both local delivery and forwarding of frames to another destination. Frames will never exit the router on the same interface that they arrives at, this concept is called split horizon, and helps prevent routing loops. - -The main purpose of the router is to accept incoming packets and deliver them to the right message queue. Therefore, in order to listen on a port-number on the network, a task must create a socket and call the accept() call. This will make the task block and wait for incoming traffic, just like a web-server or similar. When an incoming connection is opened, the task is woken. Depending on the task-priority, the task can even preempt another task and start execution immediately. - -There is no routing protocol for automatic route discovery, all routing tables are pre-programmed into the subsystems. The table itself contains a separate route to each of the possible 32 nodes in the network and the additional default route. This means that the overall topology must be decided before putting sub-systems together, as explained in the `topology.md` file. However CSP has an extension on port zero CMP (CSP management protocol), which allows for over-the-network routing table configuration. This has the advantage that default routes could be changed if for example the primary radio fails, and the secondary should be used instead. - -Layer 4: Transport Layer ------------------------- - -LibCSP implements two different Transport Layer protocols, they are called UDP (unreliable datagram protocol) and RDP (reliable datagram protocol). The name UDP has not been chosen to be an exact replica of the UDP (user datagram protocol) known from the TCP/IP model, but they have certain similarities. - -The most important thing to notice is that CSP is entirely a datagram service. There is no stream based service like TCP. A datagram is defined a block of data with a specified size and structure. This block enters the transport layer as a single datagram and exits the transport layer in the other end as a single datagram. CSP preserves this structure all the way to the physical layer for I2C, KISS and Loopback interfaces are used. The CAN-bus interface has to fragment the datagram into CAN-frames of 8 bytes, however only a fully completed datagram will arrive at the receiver. - -UDP -^^^ - -UDP uses a simple transmission model without implicit hand-shaking dialogues for guaranteeing reliability, ordering, or data integrity. Thus, UDP provides an unreliable service and datagrams may arrive out of order, appear duplicated, or go missing without notice. UDP assumes that error checking and correction is either not necessary or performed in the application, avoiding the overhead of such processing at the network interface level. Time-sensitive applications often use UDP because dropping packets is preferable to waiting for delayed packets, which may not be an option in a real-time system. - -UDP is very practical to implement request/reply based communication where a single packet forms the request and a single packet forms the reply. In this case a typical request and wait protocol is used between the client and server, which will simply return an error if a reply is not received within a specified time limit. An error would normally lead to a retransmission of the request from the user or operator which sent the request. - -While UDP is very simple, it also has some limitations. Normally a human in the loop is a good thing when operating the satellite over UDP. But when it comes to larger file transfers, the human becomes the bottleneck. When a high-speed file transfer is initiated data acknowledgment should be done automatically in order to speed up the transfer. This is where the RDP protocol can help. - -RDP -^^^ -CSP provides a transport layer extension called RDP (reliable datagram protocol) which is an implementation of RFC908 and RFC1151. RDP provides a few additional features: - - * Three-way handshake - * Flow Control - * Data-buffering - * Packet re-ordering - * Retransmission - * Windowing - * Extended Acknowledgment - -For more information on this, please refer to RFC908. - diff --git a/gomspace/libgscsp/lib/libcsp/doc/structure.rst b/gomspace/libgscsp/lib/libcsp/doc/structure.rst deleted file mode 100644 index 4c9b515c..00000000 --- a/gomspace/libgscsp/lib/libcsp/doc/structure.rst +++ /dev/null @@ -1,27 +0,0 @@ -Structure -========= -The Cubesat Space Protocol library is structured as shown in the following table: - -============================= ========================================================================= -**Folder** **Description** -============================= ========================================================================= -libcsp/include/csp Main include files -libcsp/include/csp/arch Architecture include files -libcsp/include/csp/interfaces Interface include files -libcsp/include/csp/drivers Drivers include files -libcsp/src Main modules for CSP: io, router, connections, services -libcsp/src/interfaces Interface modules for CAN, I2C, KISS, LOOP and ZMQHUB -libcsp/src/drivers/can Driver for CAN -libcsp/src/drivers/usart Driver for USART -libcsp/src/arch/freertos FreeRTOS architecture module -libcsp/src/arch/macosx Mac OS X architecture module -libcsp/src/arch/posix Posix architecture module -libcsp/src/arch/windows Windows architecture module -libcsp/src/rtable Routing table module -libcsp/transport Transport module, UDP and RDP -libcsp/crypto Crypto module -libcsp/utils Utilities -libcsp/bindings/python Python wrapper for libcsp -libcsp/examples CSP examples (source code) -libasf/doc The doc folder contains the source code for this documentation -============================= ========================================================================= diff --git a/gomspace/libgscsp/lib/libcsp/doc/topology.rst b/gomspace/libgscsp/lib/libcsp/doc/topology.rst deleted file mode 100644 index e629c29e..00000000 --- a/gomspace/libgscsp/lib/libcsp/doc/topology.rst +++ /dev/null @@ -1,26 +0,0 @@ -Network Topology -================ - -CSP uses a network oriented terminology similar to what is known from the Internet and the TCP/IP model. A CSP network can be configured for several different topologies. The most common topology is to create two segments, one for the Satellite and one for the Ground-Station. - -.. code-block:: none - - I2C BUS - _______________________________ - / | | | \ - +---+ +---+ +---+ +---+ +---+ - |OBC| |COM| |EPS| |PL1| |PL2| Nodes 0 - 7 (Space segment) - +---+ +---+ +---+ +---+ +---+ - ^ - | Radio - v - +---+ +----+ - |TNC| ------- | PC | Nodes 8 - 15 (Ground segment) - +---+ USB +----+ - - Node 9 Node 10 - -The address range, from 0 to 15, has been segmented into two equal size segments. This allows for easy routing in the network. All addresses starting with binary 1 is on the ground-segment, and all addresses starting with 0 is on the space segment. From CSP v1.0 the address space has been increased to 32 addresses, 0 to 31. But for legacy purposes, the old 0 to 15 is still used in most products. - -The network is configured using static routes initialised at boot-up of each sub-system. This means that the basic routing table must be assigned compile-time of each subsystem. However each node supports assigning an individual route to every single node in the network and can be changed run-time. This means that the network topology can be easily reconfigured after startup. - diff --git a/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo.c b/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo.c deleted file mode 100644 index 136fc3aa..00000000 --- a/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo.c +++ /dev/null @@ -1,165 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#define TYPE_SERVER 1 -#define TYPE_CLIENT 2 -#define PORT 10 -#define BUF_SIZE 250 - -pthread_t rx_thread; -int rx_channel, tx_channel; - -int csp_fifo_tx(csp_iface_t *ifc, csp_packet_t *packet, uint32_t timeout); - -csp_iface_t csp_if_fifo = { - .name = "fifo", - .nexthop = csp_fifo_tx, - .mtu = BUF_SIZE, -}; - -int csp_fifo_tx(csp_iface_t *ifc, csp_packet_t *packet, uint32_t timeout) { - /* Write packet to fifo */ - if (write(tx_channel, &packet->length, packet->length + sizeof(uint32_t) + sizeof(uint16_t)) < 0) - printf("Failed to write frame\r\n"); - csp_buffer_free(packet); - return CSP_ERR_NONE; -} - -void * fifo_rx(void * parameters) { - csp_packet_t *buf = csp_buffer_get(BUF_SIZE); - /* Wait for packet on fifo */ - while (read(rx_channel, &buf->length, BUF_SIZE) > 0) { - csp_qfifo_write(buf, &csp_if_fifo, NULL); - buf = csp_buffer_get(BUF_SIZE); - } - - return NULL; -} - -int main(int argc, char **argv) { - - int me, other, type; - const char *message = "Testing CSP"; - const char *rx_channel_name; - const char *tx_channel_name; - csp_socket_t *sock; - csp_conn_t *conn; - csp_packet_t *packet; - - /* Run as either server or client */ - if (argc != 2) { - printf("usage: %s \r\n", argv[0]); - return -1; - } - - /* Set type */ - if (strcmp(argv[1], "server") == 0) { - me = 1; - other = 2; - tx_channel_name = "server_to_client"; - rx_channel_name = "client_to_server"; - type = TYPE_SERVER; - } else if (strcmp(argv[1], "client") == 0) { - me = 2; - other = 1; - tx_channel_name = "client_to_server"; - rx_channel_name = "server_to_client"; - type = TYPE_CLIENT; - } else { - printf("Invalid type. Must be either 'server' or 'client'\r\n"); - return -1; - } - - /* Init CSP and CSP buffer system */ - if (csp_init(me) != CSP_ERR_NONE || csp_buffer_init(10, 300) != CSP_ERR_NONE) { - printf("Failed to init CSP\r\n"); - return -1; - } - - tx_channel = open(tx_channel_name, O_RDWR); - if (tx_channel < 0) { - printf("Failed to open TX channel\r\n"); - return -1; - } - - rx_channel = open(rx_channel_name, O_RDWR); - if (rx_channel < 0) { - printf("Failed to open RX channel\r\n"); - return -1; - } - - /* Start fifo RX task */ - pthread_create(&rx_thread, NULL, fifo_rx, NULL); - - /* Set default route and start router */ - csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_fifo, CSP_NODE_MAC); - csp_route_start_task(0, 0); - - /* Create socket and listen for incoming connections */ - if (type == TYPE_SERVER) { - sock = csp_socket(CSP_SO_NONE); - csp_bind(sock, PORT); - csp_listen(sock, 5); - } - - /* Super loop */ - while (1) { - if (type == TYPE_SERVER) { - /* Process incoming packet */ - conn = csp_accept(sock, 1000); - if (conn) { - packet = csp_read(conn, 0); - if (packet) - printf("Received: %s\r\n", packet->data); - csp_buffer_free(packet); - csp_close(conn); - } - } else { - /* Send a new packet */ - packet = csp_buffer_get(strlen(message)); - if (packet) { - strcpy((char *) packet->data, message); - packet->length = strlen(message); - - conn = csp_connect(CSP_PRIO_NORM, other, PORT, 1000, CSP_O_NONE); - printf("Sending: %s\r\n", message); - if (!conn || !csp_send(conn, packet, 1000)) - return -1; - csp_close(conn); - } - sleep(1); - } - } - - close(rx_channel); - close(tx_channel); - - return 0; -} diff --git a/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo_windows.c b/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo_windows.c deleted file mode 100644 index 5b360709..00000000 --- a/gomspace/libgscsp/lib/libcsp/examples/csp_if_fifo_windows.c +++ /dev/null @@ -1,225 +0,0 @@ -#include -#include -#include -#include -#include -#undef interface - -#include -#include - -#define PIPE_BUFSIZE 1024 - -#define TYPE_SERVER 1 -#define TYPE_CLIENT 2 -#define PORT 10 -#define BUF_SIZE 250 - - -static LPCTSTR pipeName = TEXT("\\\\.\\pipe\\CSP_Pipe"); - -static HANDLE pipe = INVALID_HANDLE_VALUE; - -unsigned WINAPI fifo_rx(void *); -unsigned WINAPI pipe_listener(void *); - -void printError(void); - -int csp_fifo_tx(csp_packet_t *packet, uint32_t timeout); - -csp_iface_t csp_if_fifo = { - .name = "fifo", - .nexthop = csp_fifo_tx, - .mtu = BUF_SIZE, -}; - -int csp_fifo_tx(csp_packet_t *packet, uint32_t timeout) { - printf("csp_fifo_tx tid: %lu\n", GetCurrentThreadId()); - DWORD expectedSent = packet->length + sizeof(uint32_t) + sizeof(uint16_t); - DWORD actualSent; - /* Write packet to fifo */ - if( !WriteFile(pipe, &packet->length, expectedSent, &actualSent, NULL) - || actualSent != expectedSent ) { - printError(); - } - - csp_buffer_free(packet); - return CSP_ERR_NONE; -} - - -int main(int argc, char *argv[]) { - int me, other, type; - char *message = "Testing CSP"; - csp_socket_t *sock = NULL; - csp_conn_t *conn = NULL; - csp_packet_t *packet = NULL; - - /* Run as either server or client */ - if (argc != 2) { - printf("usage: server \r\n"); - return -1; - } - - /* Set type */ - if (strcmp(argv[1], "server") == 0) { - me = 1; - other = 2; - type = TYPE_SERVER; - } else if (strcmp(argv[1], "client") == 0) { - me = 2; - other = 1; - type = TYPE_CLIENT; - } else { - printf("Invalid type. Must be either 'server' or 'client'\r\n"); - return -1; - } - - /* Init CSP and CSP buffer system */ - if (csp_init(me) != CSP_ERR_NONE || csp_buffer_init(10, 300) != CSP_ERR_NONE) { - printf("Failed to init CSP\r\n"); - return -1; - } - - if( type == TYPE_SERVER ) { - _beginthreadex(NULL, 0, pipe_listener, NULL, 0, 0); - } else { - pipe = CreateFile( - pipeName, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - OPEN_EXISTING, - 0, - NULL); - if( pipe == INVALID_HANDLE_VALUE ) { - printError(); - return -1; - } - } - - /* Set default route and start router */ - csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_fifo, CSP_NODE_MAC); - csp_route_start_task(0, 0); - - /* Create socket and listen for incoming connections */ - if (type == TYPE_SERVER) { - sock = csp_socket(CSP_SO_NONE); - csp_bind(sock, PORT); - csp_listen(sock, 5); - } - - /* Super loop */ - while (1) { - if (type == TYPE_SERVER) { - /* Process incoming packet */ - conn = csp_accept(sock, 1000); - if (conn) { - packet = csp_read(conn, 0); - if (packet) - printf("Received: %s\r\n", packet->data); - csp_buffer_free(packet); - csp_close(conn); - } - } else { - /* Send a new packet */ - packet = csp_buffer_get(strlen(message)); - if (packet) { - strcpy((char *) packet->data, message); - packet->length = strlen(message); - - conn = csp_connect(CSP_PRIO_NORM, other, PORT, 1000, CSP_O_NONE); - printf("Sending: %s\r\n", message); - if (!conn || !csp_send(conn, packet, 1000)) - return -1; - csp_close(conn); - Sleep(1000); - } - } - } - - return 0; -} - -void printError(void) { - LPTSTR messageBuffer = NULL; - DWORD errorCode = GetLastError(); - DWORD formatMessageRet; - formatMessageRet = FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - errorCode, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&messageBuffer, - 0, - NULL); - - if( !formatMessageRet ) { - wprintf(L"FormatMessage error, code: %lu\n", GetLastError()); - return; - } - - printf("%s\n", messageBuffer); - LocalFree(messageBuffer); -} - -unsigned WINAPI pipe_listener(void *parameters) { - while(1) { - HANDLE pipe = CreateNamedPipe( - pipeName, - PIPE_ACCESS_DUPLEX, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, - PIPE_BUFSIZE, - PIPE_BUFSIZE, - 0, - NULL); - BOOL clientConnected; - if( pipe == INVALID_HANDLE_VALUE ) { - printf("Error creating named pipe. Code %lu\n", GetLastError()); - return -1; - } - - // True if client connects *after* server called ConnectNamedPipe - // or *between* CreateNamedPipe and ConnectNamedPipe - clientConnected = - ConnectNamedPipe(pipe, NULL) ? TRUE : GetLastError()==ERROR_PIPE_CONNECTED; - printf("Client connected!\n"); - - if( !clientConnected ) { - printf("Failure while listening for clients. Code %lu\n", GetLastError()); - CloseHandle(pipe); - return -1; - } - printf("Create client thread\n"); - _beginthreadex(NULL, 0, fifo_rx, (PVOID)pipe, 0, 0); - } - - return 0; -} - -unsigned WINAPI fifo_rx(void *handle) { - printf("fifo_rx tid: %lu\n", GetCurrentThreadId()); - HANDLE pipe = (HANDLE) handle; - csp_packet_t *buf = csp_buffer_get(BUF_SIZE); - DWORD bytesRead; - BOOL readSuccess; - - while(1) { - readSuccess = - ReadFile(pipe, &buf->length, BUF_SIZE, &bytesRead, NULL); - if( !readSuccess || bytesRead == 0 ) { - csp_buffer_free(buf); - printError(); - break; - } - csp_qfifo_write(buf, &csp_if_fifo, NULL); - buf = csp_buffer_get(BUF_SIZE); - } - printf("Closing pipe to client\n"); - CloseHandle(pipe); - - return 0; -} diff --git a/gomspace/libgscsp/lib/libcsp/examples/kiss.c b/gomspace/libgscsp/lib/libcsp/examples/kiss.c deleted file mode 100644 index c95eb2aa..00000000 --- a/gomspace/libgscsp/lib/libcsp/examples/kiss.c +++ /dev/null @@ -1,151 +0,0 @@ -/** - * Build this example on linux with: - * ./waf configure --enable-examples --enable-if-kiss --with-driver-usart=linux --enable-crc32 clean build - */ - -#include -#include -#include - -#include -#include - -#define PORT 10 -#define MY_ADDRESS 1 - -#define SERVER_TIDX 0 -#define CLIENT_TIDX 1 -#define USART_HANDLE 0 - -CSP_DEFINE_TASK(task_server) { - int running = 1; - csp_socket_t *socket = csp_socket(CSP_SO_NONE); - csp_conn_t *conn; - csp_packet_t *packet; - csp_packet_t *response; - - response = csp_buffer_get(sizeof(csp_packet_t) + 2); - if( response == NULL ) { - fprintf(stderr, "Could not allocate memory for response packet!\n"); - return CSP_TASK_RETURN; - } - response->data[0] = 'O'; - response->data[1] = 'K'; - response->length = 2; - - csp_bind(socket, CSP_ANY); - csp_listen(socket, 5); - - printf("Server task started\r\n"); - - while(running) { - if( (conn = csp_accept(socket, 10000)) == NULL ) { - continue; - } - - while( (packet = csp_read(conn, 100)) != NULL ) { - switch( csp_conn_dport(conn) ) { - case PORT: - if( packet->data[0] == 'q' ) - running = 0; - csp_buffer_free(packet); - csp_send(conn, response, 1000); - break; - default: - csp_service_handler(conn, packet); - break; - } - } - - csp_close(conn); - } - - csp_buffer_free(response); - - return CSP_TASK_RETURN; -} - -CSP_DEFINE_TASK(task_client) { - - char outbuf = 'q'; - char inbuf[3] = {0}; - int pingResult; - - for(int i = 50; i <= 200; i+= 50) { - pingResult = csp_ping(MY_ADDRESS, 1000, 100, CSP_O_NONE); - printf("Ping with payload of %d bytes, took %d ms\n", i, pingResult); - csp_sleep_ms(1000); - } - csp_ps(MY_ADDRESS, 1000); - csp_sleep_ms(1000); - csp_memfree(MY_ADDRESS, 1000); - csp_sleep_ms(1000); - csp_buf_free(MY_ADDRESS, 1000); - csp_sleep_ms(1000); - csp_uptime(MY_ADDRESS, 1000); - csp_sleep_ms(1000); - - csp_transaction(0, MY_ADDRESS, PORT, 1000, &outbuf, 1, inbuf, 2); - printf("Quit response from server: %s\n", inbuf); - - return CSP_TASK_RETURN; -} - -int main(int argc, char **argv) { - csp_debug_toggle_level(CSP_PACKET); - csp_debug_toggle_level(CSP_INFO); - - csp_buffer_init(10, 300); - csp_init(MY_ADDRESS); - - struct usart_conf conf; - -#if defined(CSP_WINDOWS) - conf.device = argc != 2 ? "COM4" : argv[1]; - conf.baudrate = CBR_9600; - conf.databits = 8; - conf.paritysetting = NOPARITY; - conf.stopbits = ONESTOPBIT; - conf.checkparity = FALSE; -#elif defined(CSP_POSIX) - conf.device = argc != 2 ? "/dev/ttyUSB0" : argv[1]; - conf.baudrate = 500000; -#elif defined(CSP_MACOSX) - conf.device = argc != 2 ? "/dev/tty.usbserial-FTSM9EGE" : argv[1]; - conf.baudrate = 115200; -#endif - - /* Run USART init */ - usart_init(&conf); - - /* Setup CSP interface */ - static csp_iface_t csp_if_kiss; - static csp_kiss_handle_t csp_kiss_driver; - csp_kiss_init(&csp_if_kiss, &csp_kiss_driver, usart_putc, usart_insert, "KISS"); - - /* Setup callback from USART RX to KISS RS */ - void my_usart_rx(uint8_t * buf, int len, void * pxTaskWoken) { - csp_kiss_rx(&csp_if_kiss, buf, len, pxTaskWoken); - } - usart_set_callback(my_usart_rx); - - csp_route_set(MY_ADDRESS, &csp_if_kiss, CSP_NODE_MAC); - csp_route_start_task(0, 0); - - csp_conn_print_table(); - csp_route_print_table(); - csp_route_print_interfaces(); - - csp_thread_handle_t handle_server; - csp_thread_create(task_server, "SERVER", 1000, NULL, 0, &handle_server); - csp_thread_handle_t handle_client; - csp_thread_create(task_client, "CLIENT", 1000, NULL, 0, &handle_client); - - /* Wait for program to terminate (ctrl + c) */ - while(1) { - csp_sleep_ms(1000000); - } - - return 0; - -} diff --git a/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client.py b/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client.py deleted file mode 100644 index 123ce36e..00000000 --- a/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/python - -# libcsp must be build with at least these options to run this example client: -# ./waf distclean configure build --enable-bindings --enable-crc32 --enable-rdp --enable-if-zmq --with-driver-usart=linux --enable-if-kiss --enable-xtea --enable-if-can --enable-can-socketcan --enable-hmac --enable-examples - -# Can be run from root of libcsp like this: -# LD_LIBRARY_PATH=build PYTHONPATH=bindings/python:build python examples/python_bindings_example_client.py -# - -import os -import time -import libcsp as csp - - -if __name__ == "__main__": - - csp.buffer_init(10, 300) - csp.init(28) - csp.zmqhub_init(28, "localhost") - csp.rtable_set(27, 5, "ZMQHUB") - csp.route_start_task() - - ## allow router task startup - time.sleep(1) - - ## cmp_ident - (rc, host, model, rev, date, time) = csp.cmp_ident(27) - if rc == csp.CSP_ERR_NONE: - print (host, model, rev, date, time) - else: - print ("error in cmp_ident, rc=%i" % (rc)) - - ## transaction - outbuf = bytearray().fromhex('01') - inbuf = bytearray(1) - print ("using csp_transaction to send a single byte") - if csp.transaction(0, 27, 10, 1000, outbuf, inbuf) < 1: - print ("csp_transaction failed") - else: - print ("got reply, data=" + ''.join('{:02x}'.format(x) for x in inbuf)) - - diff --git a/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client_can.py b/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client_can.py deleted file mode 100644 index ec796572..00000000 --- a/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_client_can.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/python - -# libcsp must be build with at least these options to run this example client: -# ./waf distclean configure build --enable-bindings --enable-crc32 --enable-rdp --enable-if-zmq --with-driver-usart=linux --enable-if-kiss --enable-xtea --enable-if-can --enable-can-socketcan --enable-hmac --enable-examples - -# Can be run from root of libcsp like this: -# LD_LIBRARY_PATH=build PYTHONPATH=bindings/python:build python examples/python_bindings_example_client.py -# - -import os -import time -import libcsp as csp - - -if __name__ == "__main__": - - csp.buffer_init(10, 300) - csp.init(28) - csp.can_socketcan_init("can0") - csp.rtable_set(4, 5, "CAN") - csp.route_start_task() - - ## allow router task startup - time.sleep(1) - - - node = 4 - if csp.ping(node) < 0: - print ("Unable to ping node %d"%(node)) - diff --git a/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_server.py b/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_server.py deleted file mode 100644 index 3cf3f5da..00000000 --- a/gomspace/libgscsp/lib/libcsp/examples/python_bindings_example_server.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/python - -# libcsp must be build with at least these options to run this example server: -# ./waf distclean configure build --enable-bindings --enable-crc32 --enable-rdp --enable-if-zmq --with-driver-usart=linux --enable-if-kiss --enable-xtea --enable-if-can --enable-can-socketcan --enable-hmac --enable-examples - -# Can be run from root of libcsp like this: -# LD_LIBRARY_PATH=build PYTHONPATH=bindings/python:build python examples/python_bindings_example_server.py -# - -import os -import time -import sys -import libcsp as csp -import subprocess - -if __name__ == "__main__": - - # start a zmqproxy to transport messages to and from the client - zmqp = subprocess.Popen('build/zmqproxy') - - # init csp - csp.buffer_init(10, 300) - csp.init(27) - csp.zmqhub_init(27, "localhost") - csp.rtable_set(28, 5, "ZMQHUB") - csp.route_start_task() - - # set identity - csp.set_hostname("test_service") - csp.set_model("bindings") - csp.set_revision("1.2.3") - - # and read it back - print (csp.get_hostname()) - print (csp.get_model()) - print (csp.get_revision()) - - # start listening for packets... - sock = csp.socket() - csp.bind(sock, csp.CSP_ANY) - csp.listen(sock) - while True: - conn = csp.accept(sock) - if not conn: - continue - - print ("connection: source=%i:%i, dest=%i:%i" % (csp.conn_src(conn), - csp.conn_sport(conn), - csp.conn_dst(conn), - csp.conn_dport(conn))) - - while True: - packet = csp.read(conn) - if not packet: - break - - if csp.conn_dport(conn) == 10: - data = bytearray(csp.packet_get_data(packet)) - length = csp.packet_get_length(packet) - print ("got packet, len=" + str(length) + ", data=" + ''.join('{:02x}'.format(x) for x in data)) - - data[0] = data[0] + 1 - reply_packet = csp.buffer_get(1) - if reply_packet: - csp.packet_set_data(reply_packet, data) - csp.sendto_reply(packet, reply_packet, csp.CSP_O_NONE) - - csp.buffer_free(packet) - else: - csp.service_handler(conn, packet) - csp.close(conn) - diff --git a/gomspace/libgscsp/lib/libcsp/examples/simple.c b/gomspace/libgscsp/lib/libcsp/examples/simple.c deleted file mode 100644 index b996f8c1..00000000 --- a/gomspace/libgscsp/lib/libcsp/examples/simple.c +++ /dev/null @@ -1,200 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include - -#include - -/* Using un-exported header file. - * This is allowed since we are still in libcsp */ -#include - -/** Example defines */ -#define MY_ADDRESS 1 // Address of local CSP node -#define MY_PORT 10 // Port to send test traffic to - -CSP_DEFINE_TASK(task_server) { - - /* Create socket without any socket options */ - csp_socket_t *sock = csp_socket(CSP_SO_NONE); - - /* Bind all ports to socket */ - csp_bind(sock, CSP_ANY); - - /* Create 10 connections backlog queue */ - csp_listen(sock, 10); - - /* Pointer to current connection and packet */ - csp_conn_t *conn; - csp_packet_t *packet; - - /* Process incoming connections */ - while (1) { - - /* Wait for connection, 10000 ms timeout */ - if ((conn = csp_accept(sock, 10000)) == NULL) - continue; - - /* Read packets. Timout is 100 ms */ - while ((packet = csp_read(conn, 100)) != NULL) { - switch (csp_conn_dport(conn)) { - case MY_PORT: - /* Process packet here */ - printf("Packet received on MY_PORT: %s\r\n", (char *) packet->data); - csp_buffer_free(packet); - break; - - default: - /* Let the service handler reply pings, buffer use, etc. */ - csp_service_handler(conn, packet); - break; - } - } - - /* Close current connection, and handle next */ - csp_close(conn); - - } - - return CSP_TASK_RETURN; - -} - -CSP_DEFINE_TASK(task_client) { - - csp_packet_t * packet; - csp_conn_t * conn; - - while (1) { - - /** - * Try ping - */ - - csp_sleep_ms(1000); - - int result = csp_ping(MY_ADDRESS, 100, 100, CSP_O_NONE); - printf("Ping result %d [ms]\r\n", result); - - csp_sleep_ms(1000); - - /** - * Try data packet to server - */ - - /* Get packet buffer for data */ - packet = csp_buffer_get(100); - if (packet == NULL) { - /* Could not get buffer element */ - printf("Failed to get buffer element\n"); - return CSP_TASK_RETURN; - } - - /* Connect to host HOST, port PORT with regular UDP-like protocol and 1000 ms timeout */ - conn = csp_connect(CSP_PRIO_NORM, MY_ADDRESS, MY_PORT, 1000, CSP_O_NONE); - if (conn == NULL) { - /* Connect failed */ - printf("Connection failed\n"); - /* Remember to free packet buffer */ - csp_buffer_free(packet); - return CSP_TASK_RETURN; - } - - /* Copy dummy data to packet */ - const char *msg = "Hello World"; - strcpy((char *) packet->data, msg); - - /* Set packet length */ - packet->length = strlen(msg); - - /* Send packet */ - if (!csp_send(conn, packet, 1000)) { - /* Send failed */ - printf("Send failed\n"); - csp_buffer_free(packet); - } - - /* Close connection */ - csp_close(conn); - - } - - return CSP_TASK_RETURN; -} - -int main(int argc, char * argv[]) { - - /** - * Initialise CSP, - * No physical interfaces are initialised in this example, - * so only the loopback interface is registered. - */ - - /* Init buffer system with 10 packets of maximum 300 bytes each */ - printf("Initialising CSP\r\n"); - csp_buffer_init(5, 300); - - /* Init CSP with address MY_ADDRESS */ - csp_init(MY_ADDRESS); - - /* Start router task with 500 word stack, OS task priority 1 */ - csp_route_start_task(500, 1); - - /* Enable debug output from CSP */ - if ((argc > 1) && (strcmp(argv[1], "-v") == 0)) { - printf("Debug enabed\r\n"); - csp_debug_toggle_level(3); - csp_debug_toggle_level(4); - - printf("Conn table\r\n"); - csp_conn_print_table(); - - printf("Route table\r\n"); - csp_route_print_table(); - - printf("Interfaces\r\n"); - csp_route_print_interfaces(); - - } - - /** - * Initialise example threads, using pthreads. - */ - - /* Server */ - printf("Starting Server task\r\n"); - csp_thread_handle_t handle_server; - csp_thread_create(task_server, "SERVER", 1000, NULL, 0, &handle_server); - - /* Client */ - printf("Starting Client task\r\n"); - csp_thread_handle_t handle_client; - csp_thread_create(task_client, "SERVER", 1000, NULL, 0, &handle_client); - - /* Wait for execution to end (ctrl+c) */ - while(1) { - csp_sleep_ms(100000); - } - - return 0; - -} diff --git a/gomspace/libgscsp/lib/libcsp/examples/zmqproxy.c b/gomspace/libgscsp/lib/libcsp/examples/zmqproxy.c deleted file mode 100644 index 5e259579..00000000 --- a/gomspace/libgscsp/lib/libcsp/examples/zmqproxy.c +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -static void * task_capture(void *ctx) { - - /* Subscriber (RX) */ - void *subscriber = zmq_socket(ctx, ZMQ_SUB); - assert(zmq_connect(subscriber, "tcp://localhost:7000") == 0); - assert(zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, "", 0) == 0); - - while (1) { - zmq_msg_t msg; - zmq_msg_init_size(&msg, 1024); - - /* Receive data */ - if (zmq_msg_recv(&msg, subscriber, 0) < 0) { - zmq_msg_close(&msg); - csp_log_error("ZMQ: %s\r\n", zmq_strerror(zmq_errno())); - continue; - } - - int datalen = zmq_msg_size(&msg); - if (datalen < 5) { - csp_log_warn("ZMQ: Too short datalen: %u\r\n", datalen); - while(zmq_msg_recv(&msg, subscriber, ZMQ_NOBLOCK) > 0) - zmq_msg_close(&msg); - continue; - } - - /* Create new csp packet */ - csp_packet_t * packet = malloc(1024); - if (packet == NULL) { - zmq_msg_close(&msg); - continue; - } - - /* Copy the data from zmq to csp */ - char * satidptr = ((char *) &packet->id) - 1; - memcpy(satidptr, zmq_msg_data(&msg), datalen); - packet->length = datalen - 4 - 1; - - printf("Input: Src %u, Dst %u, Dport %u, Sport %u, Pri %u, Flags 0x%02X, Size %"PRIu16"\r\n", - packet->id.src, packet->id.dst, packet->id.dport, - packet->id.sport, packet->id.pri, packet->id.flags, packet->length); - - free(packet); - zmq_msg_close(&msg); - } -} - -int main(int argc, char ** argv) { - - /** - * ZMQ PROXY - */ - void * ctx = zmq_ctx_new(); - assert(ctx); - - void *frontend = zmq_socket(ctx, ZMQ_XSUB); - assert(frontend); - assert(zmq_bind (frontend, "tcp://*:6000") == 0); - - void *backend = zmq_socket(ctx, ZMQ_XPUB); - assert(backend); - assert(zmq_bind(backend, "tcp://*:7000") == 0); - - pthread_t capworker; - pthread_create(&capworker, NULL, task_capture, ctx); - - printf("Starting ZMQproxy\r\n"); - zmq_proxy(frontend, backend, NULL); - - printf("Closing ZMQproxy\r\n"); - zmq_ctx_destroy(ctx); - return 0; - -} diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_clock.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_clock.h deleted file mode 100644 index 3c19c887..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_clock.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_CLOCK_H_ -#define _CSP_CLOCK_H_ - -/** - @file - - Clock API. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/** - Cross-platform timestamp. -*/ -typedef struct { - //! Seconds - uint32_t tv_sec; - //! Nano-seconds. - uint32_t tv_nsec; -} csp_timestamp_t; - -/** - Get time - must be implemented by the user. -*/ -__attribute__((weak)) extern void clock_get_time(csp_timestamp_t * time); - -/** - Set time - must be implemented by the user. -*/ -__attribute__((weak)) extern void clock_set_time(csp_timestamp_t * time); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_CLOCK_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_malloc.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_malloc.h deleted file mode 100644 index 12602d1b..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_malloc.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_MALLOC_H_ -#define _CSP_MALLOC_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -void * csp_malloc(size_t size); -void csp_free(void * ptr); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_MALLOC_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_queue.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_queue.h deleted file mode 100644 index 3156c05e..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_queue.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_QUEUE_H_ -#define _CSP_QUEUE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#define CSP_QUEUE_FULL 0 -#define CSP_QUEUE_ERROR 0 -#define CSP_QUEUE_OK 1 -typedef void * csp_queue_handle_t; - -#include -#include - -csp_queue_handle_t csp_queue_create(int length, size_t item_size); -void csp_queue_remove(csp_queue_handle_t queue); -int csp_queue_enqueue(csp_queue_handle_t handle, void *value, uint32_t timeout); -int csp_queue_enqueue_isr(csp_queue_handle_t handle, void * value, CSP_BASE_TYPE * task_woken); -int csp_queue_dequeue(csp_queue_handle_t handle, void *buf, uint32_t timeout); -int csp_queue_dequeue_isr(csp_queue_handle_t handle, void * buf, CSP_BASE_TYPE * task_woken); -int csp_queue_size(csp_queue_handle_t handle); -int csp_queue_size_isr(csp_queue_handle_t handle); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_QUEUE_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_semaphore.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_semaphore.h deleted file mode 100644 index c8068da2..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_semaphore.h +++ /dev/null @@ -1,109 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_SEMAPHORE_H_ -#define _CSP_SEMAPHORE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include - -/* POSIX interface */ -#if defined(CSP_POSIX) - -#include -#include - -#define CSP_SEMAPHORE_OK 1 -#define CSP_SEMAPHORE_ERROR 2 -#define CSP_MUTEX_OK CSP_SEMAPHORE_OK -#define CSP_MUTEX_ERROR CSP_SEMAPHORE_ERROR - -typedef sem_t csp_bin_sem_handle_t; -typedef pthread_mutex_t csp_mutex_t; - -#endif // CSP_POSIX - -/* MAC OS X interface */ -#if defined(CSP_MACOSX) - -#include -#include "posix/pthread_queue.h" - -#define CSP_SEMAPHORE_OK PTHREAD_QUEUE_OK -#define CSP_SEMAPHORE_ERROR PTHREAD_QUEUE_EMPTY -#define CSP_MUTEX_OK CSP_SEMAPHORE_OK -#define CSP_MUTEX_ERROR CSP_SEMAPHORE_ERROR - -typedef pthread_queue_t * csp_bin_sem_handle_t; -typedef pthread_queue_t * csp_mutex_t; - -#endif // CSP_MACOSX - -#if defined(CSP_WINDOWS) - -#include -#undef interface - -#define CSP_SEMAPHORE_OK 1 -#define CSP_SEMAPHORE_ERROR 2 -#define CSP_MUTEX_OK CSP_SEMAPHORE_OK -#define CSP_MUTEX_ERROR CSP_SEMAPHORE_ERROR - -typedef HANDLE csp_bin_sem_handle_t; -typedef HANDLE csp_mutex_t; - -#endif - -/* FreeRTOS interface */ -#if defined(CSP_FREERTOS) - -#include -#include - -#define CSP_SEMAPHORE_OK pdPASS -#define CSP_SEMAPHORE_ERROR pdFAIL -#define CSP_MUTEX_OK CSP_SEMAPHORE_OK -#define CSP_MUTEX_ERROR CSP_SEMAPHORE_ERROR - -typedef xSemaphoreHandle csp_bin_sem_handle_t; -typedef xSemaphoreHandle csp_mutex_t; - -#endif // CSP_FREERTOS - -int csp_mutex_create(csp_mutex_t * mutex); -int csp_mutex_remove(csp_mutex_t * mutex); -int csp_mutex_lock(csp_mutex_t * mutex, uint32_t timeout); -int csp_mutex_unlock(csp_mutex_t * mutex); -int csp_bin_sem_create(csp_bin_sem_handle_t * sem); -int csp_bin_sem_remove(csp_bin_sem_handle_t * sem); -int csp_bin_sem_wait(csp_bin_sem_handle_t * sem, uint32_t timeout); -int csp_bin_sem_post(csp_bin_sem_handle_t * sem); -int csp_bin_sem_post_isr(csp_bin_sem_handle_t * sem, CSP_BASE_TYPE * task_woken); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_SEMAPHORE_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_system.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_system.h deleted file mode 100644 index c6c0e5af..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_system.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_SYSTEM_H_ -#define _CSP_SYSTEM_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#define COLOR_MASK_COLOR 0x0F -#define COLOR_MASK_MODIFIER 0xF0 - -typedef enum { - /* Colors */ - COLOR_RESET = 0xF0, - COLOR_BLACK = 0x01, - COLOR_RED = 0x02, - COLOR_GREEN = 0x03, - COLOR_YELLOW = 0x04, - COLOR_BLUE = 0x05, - COLOR_MAGENTA = 0x06, - COLOR_CYAN = 0x07, - COLOR_WHITE = 0x08, - /* Modifiers */ - COLOR_NORMAL = 0x0F, - COLOR_BOLD = 0x10, - COLOR_UNDERLINE = 0x20, - COLOR_BLINK = 0x30, - COLOR_HIDE = 0x40, -} csp_color_t; - -/** - * Writes out a task list into a pre-allocate buffer, - * use csp_sys_tasklist_size to get sizeof buffer to allocate - * @param out pointer to output buffer - * @return - */ -int csp_sys_tasklist(char * out); - -/** - * @return Size of tasklist buffer to allocate for the csp_sys_tasklist call - */ -int csp_sys_tasklist_size(void); - -uint32_t csp_sys_memfree(void); -int csp_sys_reboot(void); -int csp_sys_shutdown(void); -void csp_sys_set_color(csp_color_t color); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_SYSTEM_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_thread.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_thread.h deleted file mode 100644 index 3c6ea171..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_thread.h +++ /dev/null @@ -1,100 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_THREAD_H_ -#define _CSP_THREAD_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/* POSIX interface */ -#if defined(CSP_POSIX) || defined(CSP_MACOSX) - -#include -#include - -#define csp_thread_exit() pthread_exit(NULL) - -typedef pthread_t csp_thread_handle_t; -typedef void * csp_thread_return_t; - -#define CSP_DEFINE_TASK(task_name) csp_thread_return_t task_name(void * param) -#define CSP_TASK_RETURN NULL - -#define csp_sleep_ms(time_ms) usleep(time_ms * 1000); - -#endif // CSP_POSIX - -/* Windows interface */ -#if defined(CSP_WINDOWS) - -#include -#undef interface -#include - -#define csp_thread_exit() _endthreadex(0) - -typedef HANDLE csp_thread_handle_t; -typedef unsigned int csp_thread_return_t; - -#define CSP_DEFINE_TASK(task_name) csp_thread_return_t __attribute__((stdcall)) task_name(void * param) -#define CSP_TASK_RETURN 0 - -#define csp_sleep_ms(time_ms) Sleep(time_ms); - -#endif // CSP_WINDOWS - -/* FreeRTOS interface */ -#if defined(CSP_FREERTOS) - -#include -#include - -#if INCLUDE_vTaskDelete -#define csp_thread_exit() vTaskDelete(NULL) -#else -#define csp_thread_exit() -#endif - -typedef xTaskHandle csp_thread_handle_t; -typedef void csp_thread_return_t; - -#define CSP_DEFINE_TASK(task_name) csp_thread_return_t task_name(void * param) -#define CSP_TASK_RETURN - -#define csp_sleep_ms(time_ms) vTaskDelay(time_ms / portTICK_RATE_MS); - -#endif // CSP_FREERTOS - -#ifndef CSP_WINDOWS -int csp_thread_create(csp_thread_return_t (* routine)(void *), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle); -#else -int csp_thread_create(csp_thread_return_t (* routine)(void *)__attribute__((stdcall)), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle); -#endif - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_THREAD_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_time.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_time.h deleted file mode 100644 index aa72ab8f..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/arch/csp_time.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_TIME_H_ -#define _CSP_TIME_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/* Blackfin/x86 on Linux */ -#if defined(CSP_POSIX) - -#include -#include -#include - -#endif // CSP_POSIX - -/* AVR/ARM on FreeRTOS */ -#if defined(CSP_FREERTOS) - -#include -#include - -#endif // CSP_FREERTOS - -uint32_t csp_get_ms(void); -uint32_t csp_get_ms_isr(void); -uint32_t csp_get_s(void); -uint32_t csp_get_s_isr(void); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_TIME_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/arch/posix/pthread_queue.h b/gomspace/libgscsp/lib/libcsp/include/csp/arch/posix/pthread_queue.h deleted file mode 100644 index 44ef596e..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/arch/posix/pthread_queue.h +++ /dev/null @@ -1,118 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _PTHREAD_QUEUE_H_ -#define _PTHREAD_QUEUE_H_ - -/** - @file - - Queue implemented using pthread locks and conds. - - Inspired by c-pthread-queue by Matthew Dickinson: http://code.google.com/p/c-pthread-queue/ -*/ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -#include - -/** - Queue error codes. - @{ -*/ -/** - General error code - something went wrong. -*/ -#define PTHREAD_QUEUE_ERROR CSP_QUEUE_ERROR -/** - Queue is empty - cannot extract element. -*/ -#define PTHREAD_QUEUE_EMPTY CSP_QUEUE_ERROR -/** - Queue is full - cannot insert element. -*/ -#define PTHREAD_QUEUE_FULL CSP_QUEUE_ERROR -/** - Ok - no error. -*/ -#define PTHREAD_QUEUE_OK CSP_QUEUE_OK -/** @{ */ - -/** - Queue handle. -*/ -typedef struct pthread_queue_s { - //! Memory area. - void * buffer; - //! Memory size. - int size; - //! Item/element size. - int item_size; - //! Items/elements in queue. - int items; - //! Insert point. - int in; - //! Extract point. - int out; - //! Lock. - pthread_mutex_t mutex; - //! Wait because queue is full (insert). - pthread_cond_t cond_full; - //! Wait because queue is empty (extract). - pthread_cond_t cond_empty; -} pthread_queue_t; - -/** - Create queue. -*/ -pthread_queue_t * pthread_queue_create(int length, size_t item_size); - -/** - Delete queue. -*/ -void pthread_queue_delete(pthread_queue_t * q); - -/** - Enqueue/insert element. -*/ -int pthread_queue_enqueue(pthread_queue_t * queue, void * value, uint32_t timeout); - -/** - Dequeue/extract element. -*/ -int pthread_queue_dequeue(pthread_queue_t * queue, void * buf, uint32_t timeout); - -/** - Return number of elements in the queue. -*/ -int pthread_queue_items(pthread_queue_t * queue); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _PTHREAD_QUEUE_H_ - diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_hmac.h b/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_hmac.h deleted file mode 100644 index 8c3f5d6a..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_hmac.h +++ /dev/null @@ -1,73 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_HMAC_H_ -#define _CSP_HMAC_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define CSP_HMAC_LENGTH 4 - -/** - * Append HMAC to packet - * @param packet Pointer to packet - * @param include_header use header in hmac calculation (this will not modify the flags field) - * @return 0 on success, negative on failure - */ -int csp_hmac_append(csp_packet_t * packet, bool include_header); - -/** - * Verify HMAC of packet - * @param packet Pointer to packet - * @param include_header use header in hmac calculation (this will not modify the flags field) - * @return 0 on success, negative on failure - */ -int csp_hmac_verify(csp_packet_t * packet, bool include_header); - -/** - * Calculate HMAC on buffer - * - * This function is used by append/verify but cal also be called separately. - * @param key HMAC key - * @param keylen HMAC key length - * @param data pointer to data - * @param datalen lehgth of data - * @param hmac output HMAC calculation (CSP_HMAC_LENGTH) - * @return 0 on success, negative on failure - */ -int csp_hmac_memory(const uint8_t * key, uint32_t keylen, const uint8_t * data, uint32_t datalen, uint8_t * hmac); - -/** - * Save a copy of the key string for use by the append/verify functions - * @param key HMAC key - * @param keylen HMAC key length - * @return Always returns 0 - */ -int csp_hmac_set_key(char * key, uint32_t keylen); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_HMAC_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_sha1.h b/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_sha1.h deleted file mode 100644 index aa7e7a0d..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_sha1.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_SHA1_H_ -#define _CSP_SHA1_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* The SHA1 block and message digest size in bytes */ -#define SHA1_BLOCKSIZE 64 -#define SHA1_DIGESTSIZE 20 - -/** - SHA1 state structure -*/ -typedef struct { - //! Internal SHA1 state. - uint64_t length; - //! Internal SHA1 state. - uint32_t state[5]; - //! Internal SHA1 state. - uint32_t curlen; - //! Internal SHA1 state. - uint8_t buf[SHA1_BLOCKSIZE]; -} csp_sha1_state; - -/** - * Initialize the hash state - * @param sha1 The hash state you wish to initialize - */ -void csp_sha1_init(csp_sha1_state * sha1); - -/** - * Process a block of memory though the hash - * @param sha1 The hash state - * @param in The data to hash - * @param inlen The length of the data (octets) - */ -void csp_sha1_process(csp_sha1_state * sha1, const uint8_t * in, uint32_t inlen); - -/** - * Terminate the hash to get the digest - * @param sha1 The hash state - * @param out [out] The destination of the hash (20 bytes) - */ -void csp_sha1_done(csp_sha1_state * sha1, uint8_t * out); - -/** - * Calculate SHA1 hash of block of memory. - * @param msg Pointer to message buffer - * @param len Length of message - * @param sha1 Pointer to SHA1 output buffer. Must be 20 bytes or more! - */ -void csp_sha1_memory(const uint8_t * msg, uint32_t len, uint8_t * hash); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_SHA1_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_xtea.h b/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_xtea.h deleted file mode 100644 index f740b8d5..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/crypto/csp_xtea.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_XTEA_H_ -#define _CSP_XTEA_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define CSP_XTEA_IV_LENGTH 8 - -/** - * XTEA encrypt byte array - * @param plain Pointer to plain text - * @param len Length of plain text - * @param iv Initialization vector - */ -int csp_xtea_encrypt(uint8_t * plain, const uint32_t len, uint32_t iv[2]); - -/** - * Decrypt XTEA encrypted byte array - * @param cipher Pointer to cipher text - * @param len Length of plain text - * @param iv Initialization vector - */ -int csp_xtea_decrypt(uint8_t * cipher, const uint32_t len, uint32_t iv[2]); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_XTEA_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp.h deleted file mode 100644 index 6962195b..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/csp.h +++ /dev/null @@ -1,545 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_H_ -#define _CSP_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Includes */ -#include - -#include - -/* CSP includes */ -#include "csp_types.h" -#include "csp_platform.h" -#include "csp_error.h" -#include "csp_debug.h" -#include "csp_buffer.h" -#include "csp_rtable.h" -#include "csp_iflist.h" - -/** csp_init - * Start up the can-space protocol - * @param my_node_address The CSP node address - */ -int csp_init(uint8_t my_node_address); - -/** csp_set_address - * Set the systems own address - * @param addr The new address of the system - */ -void csp_set_address(uint8_t addr); - -/** csp_get_address - * Get the systems own address - * @return The current address of the system - */ -uint8_t csp_get_address(void); - -/** csp_set_hostname - * Set subsystem hostname. - * This function takes a pointer to a string, which should remain static - * @param hostname Hostname to set - */ -void csp_set_hostname(const char *hostname); - -/** csp_get_hostname - * Get current subsystem hostname. - * @return Pointer to char array with current hostname. - */ -const char *csp_get_hostname(void); - -/** csp_set_model - * Set subsystem model name. - * This function takes a pointer to a string, which should remain static - * @param model Model name to set - */ -void csp_set_model(const char *model); - -/** csp_get_model - * Get current model name. - * @return Pointer to char array with current model name. - */ -const char *csp_get_model(void); - -/** csp_set_revision - * Set subsystem revision. This can be used to override the CMP revision field. - * This function takes a pointer to a string, which should remain static - * @param revision Revision name to set - */ -void csp_set_revision(const char *revision); - -/** csp_get_revision - * Get subsystem revision. - * @return Pointer to char array with software revision. - */ -const char *csp_get_revision(void); - -/** csp_socket - * Create CSP socket endpoint - * @param opts Socket options - * @return Pointer to socket on success, NULL on failure - */ -csp_socket_t *csp_socket(uint32_t opts); - -/** - * Wait for a new connection on a socket created by csp_socket - * @param socket Socket to accept connections on - * @param timeout use CSP_MAX_DELAY for infinite timeout - * @return Return pointer to csp_conn_t or NULL if timeout was reached - */ -csp_conn_t *csp_accept(csp_socket_t *socket, uint32_t timeout); - -/** - * Read data from a connection - * This fuction uses the RX queue of a connection to receive a packet - * If no packet is available and a timeout has been specified - * The call will block. - * Do NOT call this from ISR - * @param conn pointer to connection - * @param timeout timeout in ms, use CSP_MAX_DELAY for infinite blocking time - * @return Returns pointer to csp_packet_t, which you MUST free yourself, either by calling csp_buffer_free() or reusing the buffer for a new csp_send. - */ -csp_packet_t *csp_read(csp_conn_t *conn, uint32_t timeout); - -/** - * Send a packet on an already established connection - * @param conn pointer to connection - * @param packet pointer to packet, - * @param timeout a timeout to wait for TX to complete. NOTE: not all underlying drivers supports flow-control. - * @return returns 1 if successful and 0 otherwise. you MUST free the frame yourself if the transmission was not successful. - */ -int csp_send(csp_conn_t *conn, csp_packet_t *packet, uint32_t timeout); - -/** - * Send a packet on an already established connection, and change the default priority of the connection - * - * @note When using this function, the priority of the connection will change. If you need to change it back - * use another call to csp_send_prio, or ensure that all packets sent on a given connection is using send_prio call. - * - * @param prio csp priority - * @param conn pointer to connection - * @param packet pointer to packet, - * @param timeout a timeout to wait for TX to complete. NOTE: not all underlying drivers supports flow-control. - * @return returns 1 if successful and 0 otherwise. you MUST free the frame yourself if the transmission was not successful. - */ -int csp_send_prio(uint8_t prio, csp_conn_t *conn, csp_packet_t *packet, uint32_t timeout); - -/** - * Perform an entire request/reply transaction - * Copies both input buffer and reply to output buffeer. - * Also makes the connection and closes it again - * @param prio CSP Prio - * @param dest CSP Dest - * @param port CSP Port - * @param timeout timeout in ms - * @param outbuf pointer to outgoing data buffer - * @param outlen length of request to send - * @param inbuf pointer to incoming data buffer - * @param inlen length of expected reply, -1 for unknown size (note inbuf MUST be large enough) - * @return Return 1 or reply size if successful, 0 if error or incoming length does not match or -1 if timeout was reached - */ -int csp_transaction(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, void *outbuf, int outlen, void *inbuf, int inlen); - -/** - * Perform an entire request/reply transaction - * Copies both input buffer and reply to output buffeer. - * Also makes the connection and closes it again - * @param prio CSP Prio - * @param dest CSP Dest - * @param port CSP Port - * @param timeout timeout in ms - * @param outbuf pointer to outgoing data buffer - * @param outlen length of request to send - * @param inbuf pointer to incoming data buffer - * @param inlen length of expected reply, -1 for unknown size (note inbuf MUST be large enough) - * @param opts Connection options. - * @return Return 1 or reply size if successful, 0 if error or incoming length does not match or -1 if timeout was reached - */ -int csp_transaction2(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, void *outbuf, int outlen, void *inbuf, int inlen, uint32_t opts); - -/** - * Use an existing connection to perform a transaction, - * This is only possible if the next packet is on the same port and destination! - * @param conn pointer to connection structure - * @param timeout timeout in ms - * @param outbuf pointer to outgoing data buffer - * @param outlen length of request to send - * @param inbuf pointer to incoming data buffer - * @param inlen length of expected reply, -1 for unknown size (note inbuf MUST be large enough) - * @return - */ -int csp_transaction_persistent(csp_conn_t *conn, uint32_t timeout, void *outbuf, int outlen, void *inbuf, int inlen); - -/** - * Read data from a connection-less server socket - * This fuction uses the socket directly to receive a frame - * If no packet is available and a timeout has been specified the call will block. - * Do NOT call this from ISR - * @return Returns pointer to csp_packet_t, which you MUST free yourself, either by calling csp_buffer_free() or reusing the buffer for a new csp_send. - */ -csp_packet_t *csp_recvfrom(csp_socket_t *socket, uint32_t timeout); - -/** - * Send a packet without previously opening a connection - * @param prio CSP_PRIO_x - * @param dest destination node - * @param dport destination port - * @param src_port source port - * @param opts CSP_O_x - * @param packet pointer to packet - * @param timeout timeout used by interfaces with blocking send - * @return -1 if error (you must free packet), 0 if OK (you must discard pointer) - */ -int csp_sendto(uint8_t prio, uint8_t dest, uint8_t dport, uint8_t src_port, uint32_t opts, csp_packet_t *packet, uint32_t timeout); - -/** - * Send a packet as a direct reply to the source of an incoming packet, - * but still without holding an entire connection - * @param request_packet pointer to packet to reply to - * @param reply_packet actual reply data - * @param opts CSP_O_x - * @param timeout timeout used by interfaces with blocking send - * @return -1 if error (you must free packet), 0 if OK (you must discard pointer) - */ -int csp_sendto_reply(csp_packet_t * request_packet, csp_packet_t * reply_packet, uint32_t opts, uint32_t timeout); - -/** csp_connect - * Used to establish outgoing connections - * This function searches the port table for free slots and finds an unused - * connection from the connection pool - * There is no handshake in the CSP protocol - * @param prio Connection priority. - * @param dest Destination address. - * @param dport Destination port. - * @param timeout Timeout in ms. - * @param opts Connection options. - * @return a pointer to a new connection or NULL - */ -csp_conn_t *csp_connect(uint8_t prio, uint8_t dest, uint8_t dport, uint32_t timeout, uint32_t opts); - -/** csp_close - * Closes a given connection and frees buffers used. - * @param conn pointer to connection structure - * @return CSP_ERR_NONE if connection was closed. Otherwise, an err code is returned. - */ -int csp_close(csp_conn_t *conn); - -/** - * @param conn pointer to connection structure - * @return destination port of an incoming connection - */ -int csp_conn_dport(csp_conn_t *conn); - -/** - * @param conn pointer to connection structure - * @return source port of an incoming connection - */ -int csp_conn_sport(csp_conn_t *conn); - -/** - * @param conn pointer to connection structure - * @return destination address of an incoming connection - */ -int csp_conn_dst(csp_conn_t *conn); - -/** - * @param conn pointer to connection structure - * @return source address of an incoming connection - */ -int csp_conn_src(csp_conn_t *conn); - -/** - * @param conn pointer to connection structure - * @return flags field of an incoming connection - */ -int csp_conn_flags(csp_conn_t *conn); - -/** - * Set socket to listen for incoming connections - * @param socket Socket to enable listening on - * @param conn_queue_length Lenght of backlog connection queue - * @return 0 on success, -1 on error. - */ -int csp_listen(csp_socket_t *socket, size_t conn_queue_length); - -/** - * Bind port to socket - * @param socket Socket to bind port to - * @param port Port number to bind - * @return 0 on success, -1 on error. - */ -int csp_bind(csp_socket_t *socket, uint8_t port); - -/** - * Start the router task. - * @param task_stack_size The number of portStackType to allocate. This only affects FreeRTOS systems. - * @param priority The OS task priority of the router - */ -int csp_route_start_task(unsigned int task_stack_size, unsigned int priority); - -/** - * Call the router worker function manually (without the router task) - * This must be run inside a loop or called periodically for the csp router to work. - * Use this function instead of calling and starting the router task. - * @param timeout max blocking time - * @return -1 if no packet was processed, 0 otherwise - */ -int csp_route_work(uint32_t timeout); - -/** - * Start the bridge task. - * @param task_stack_size The number of portStackType to allocate. This only affects FreeRTOS systems. - * @param priority The OS task priority of the router - * @param _if_a pointer to first side - * @param _if_b pointer to second side - * @return CSP_ERR type - */ -int csp_bridge_start(unsigned int task_stack_size, unsigned int task_priority, csp_iface_t * _if_a, csp_iface_t * _if_b); - -/** - * Enable promiscuous mode packet queue - * This function is used to enable promiscuous mode for the router. - * If enabled, a copy of all incoming packets are placed in a queue - * that can be read with csp_promisc_get(). Not all interface drivers - * support promiscuous mode. - * - * @param buf_size Size of buffer for incoming packets - */ -int csp_promisc_enable(unsigned int buf_size); - -/** - * Disable promiscuous mode. - * If the queue was initialised prior to this, it can be re-enabled - * by calling promisc_enable(0) - */ -void csp_promisc_disable(void); - -/** - * Get packet from promiscuous mode packet queue - * Returns the first packet from the promiscuous mode packet queue. - * The queue is FIFO, so the returned packet is the oldest one - * in the queue. - * - * @param timeout Timeout in ms to wait for a new packet - */ -csp_packet_t *csp_promisc_read(uint32_t timeout); - -/** - * Send multiple packets using the simple fragmentation protocol - * CSP will add total size and offset to all packets - * This can be read by the client using the csp_sfp_recv, if the CSP_FFRAG flag is set - * @param conn pointer to connection - * @param data pointer to data to send - * @param totalsize size of data to send - * @param mtu maximum transfer unit - * @param timeout timeout in ms to wait for csp_send() - * @return 0 if OK, -1 if ERR - */ -int csp_sfp_send(csp_conn_t * conn, const void * data, int totalsize, int mtu, uint32_t timeout); - -/** - * Same as csp_sfp_send but with option to supply your own memcpy function. - * This is usefull if you wish to send data stored in flash memory or another location - * @param conn pointer to connection - * @param data pointer to data to send - * @param totalsize size of data to send - * @param mtu maximum transfer unit - * @param timeout timeout in ms to wait for csp_send() - * @param memcpyfcn, pointer to memcpy function - * @return 0 if OK, -1 if ERR - */ -int csp_sfp_send_own_memcpy(csp_conn_t * conn, const void * data, int totalsize, int mtu, uint32_t timeout, void * (*memcpyfcn)(void *, const void *, size_t)); - -/** - * This is the counterpart to the csp_sfp_send function - * @param conn pointer to active conn, on which you expect to receive sfp packed data - * @param dataout pointer to NULL pointer, whill be overwritten with malloc pointer - * @param datasize actual size of received data - * @param timeout timeout in ms to wait for csp_recv() - * @return 0 if OK, -1 if ERR - */ -int csp_sfp_recv(csp_conn_t * conn, void ** dataout, int * datasize, uint32_t timeout); - -/** - * This is the counterpart to the csp_sfp_send function - * @param conn pointer to active conn, on which you expect to receive sfp packed data - * @param dataout pointer to NULL pointer, whill be overwritten with malloc pointer - * @param datasize actual size of received data - * @param timeout timeout in ms to wait for csp_recv() - * @param first_packet This is a pointer to the first SFP packet (previously received with csp_read) - * @return 0 if OK, -1 if ERR - */ -int csp_sfp_recv_fp(csp_conn_t * conn, void ** dataout, int * datasize, uint32_t timeout, csp_packet_t * first_packet); - -/** - * If the given packet is a service-request (that is uses one of the csp service ports) - * it will be handled according to the CSP service handler. - * This function will either use the packet buffer or delete it, - * so this function is typically called in the last "default" clause of - * a switch/case statement in a csp_listener task. - * In order to listen to csp service ports, bind your listener to the CSP_ANY port. - * This function may only be called from task context. - * @param conn Pointer to the new connection - * @param packet Pointer to the first packet, obtained by using csp_read() - */ -void csp_service_handler(csp_conn_t *conn, csp_packet_t *packet); - -/** - * Send a single ping/echo packet - * @param node node id - * @param timeout timeout in ms - * @param size size of packet to transmit - * @param conn_options csp connection options - * @return >0 = Echo time in ms, -1 = ERR - */ -int csp_ping(uint8_t node, uint32_t timeout, unsigned int size, uint8_t conn_options); - -/** - * Send a single ping/echo packet without waiting for reply - * @param node node id - */ -void csp_ping_noreply(uint8_t node); - -/** - * Request process list. - * @note This is only available for FreeRTOS systems - * @param node node id - * @param timeout timeout in ms - */ -void csp_ps(uint8_t node, uint32_t timeout); - -/** - * Request amount of free memory - * @param node node id - * @param timeout timeout in ms - */ -void csp_memfree(uint8_t node, uint32_t timeout); - -/** - * Request number of free buffer elements - * @param node node id - * @param timeout timeout in ms - */ -void csp_buf_free(uint8_t node, uint32_t timeout); - -/** - * Reboot subsystem - * @param node node id - */ -void csp_reboot(uint8_t node); - -/** - * Shutdown subsystem - * @param node node id - */ -void csp_shutdown(uint8_t node); - -/** - * Request subsystem uptime - * @param node node id - * @param timeout timeout in ms - */ -void csp_uptime(uint8_t node, uint32_t timeout); - -/** - * Set RDP options - * @param window_size Window size - * @param conn_timeout_ms Connection timeout in ms - * @param packet_timeout_ms Packet timeout in ms - * @param delayed_acks Enable/disable delayed acknowledgements - * @param ack_timeout Acknowledgement timeout when delayed ACKs is enabled - * @param ack_delay_count Send acknowledgement for every ack_delay_count packets - */ -void csp_rdp_set_opt(unsigned int window_size, unsigned int conn_timeout_ms, - unsigned int packet_timeout_ms, unsigned int delayed_acks, - unsigned int ack_timeout, unsigned int ack_delay_count); - -/** - * Get RDP options - * @param window_size Window size - * @param conn_timeout_ms Connection timeout in ms - * @param packet_timeout_ms Packet timeout in ms - * @param delayed_acks Enable/disable delayed acknowledgements - * @param ack_timeout Acknowledgement timeout when delayed ACKs is enabled - * @param ack_delay_count Send acknowledgement for every ack_delay_count packets - */ -void csp_rdp_get_opt(unsigned int *window_size, unsigned int *conn_timeout_ms, - unsigned int *packet_timeout_ms, unsigned int *delayed_acks, - unsigned int *ack_timeout, unsigned int *ack_delay_count); - -/** - * Set XTEA key - * @param key Pointer to key array - * @param keylen Length of key - * @return 0 if key was successfully set, -1 otherwise - */ -int csp_xtea_set_key(char *key, uint32_t keylen); - -/** - * Set HMAC key - * @param key Pointer to key array - * @param keylen Length of key - * @return 0 if key was successfully set, -1 otherwise - */ -int csp_hmac_set_key(char *key, uint32_t keylen); - -/** - * Print connection table - */ -void csp_conn_print_table(void); -int csp_conn_print_table_str(char * str_buf, int str_size); - -/** - * Print buffer usage table - */ -void csp_buffer_print_table(void); - -/** - * Hex dump to stdout - */ -void csp_hex_dump(const char *desc, void *addr, int len); - -#ifdef __AVR__ -typedef uint32_t csp_memptr_t; -#else -typedef void * csp_memptr_t; -#endif - -typedef csp_memptr_t (*csp_memcpy_fnc_t)(csp_memptr_t, const csp_memptr_t, size_t); -void csp_cmp_set_memcpy(csp_memcpy_fnc_t fnc); - -/** - * Set csp_debug hook function - * @param f Hook function - */ -#include -typedef void (*csp_debug_hook_func_t)(csp_debug_level_t level, const char *format, va_list args); -void csp_debug_hook_set(csp_debug_hook_func_t f); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_buffer.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_buffer.h deleted file mode 100644 index 9ed6df77..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/csp_buffer.h +++ /dev/null @@ -1,92 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_BUFFER_H_ -#define _CSP_BUFFER_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Start the buffer handling system - * You must specify the number for buffers and the size. All buffers are fixed - * size so you must specify the size of your largest buffer. - * - * @param count Number of buffers to allocate - * @param size Buffer size in bytes. - * - * @return CSP_ERR_NONE if malloc() succeeded, CSP_ERR message otherwise. - */ -int csp_buffer_init(int count, int size); - -/** - * Get a reference to a free buffer. This function can only be called - * from task context. - * - * @param size Specify what data-size you will put in the buffer - * @return pointer to a free csp_packet_t or NULL if out of memory - */ -void * csp_buffer_get(size_t size); - -/** - * Get a reference to a free buffer. This function can only be called - * from interrupt context. - * - * @param buf_size Specify what data-size you will put in the buffer - * @return pointer to a free csp_packet_t or NULL if out of memory - */ -void * csp_buffer_get_isr(size_t buf_size); - -/** - * Free a buffer after use. - * @param packet pointer to memory area, must be acquired by csp_buffer_get(). - */ -void csp_buffer_free(void *packet); - -/** - * Free a buffer after use in ISR context. - * @param packet pointer to memory area, must be acquired by csp_buffer_get(). - */ -void csp_buffer_free_isr(void *packet); - -/** - * Clone an existing packet and increase/decrease cloned packet size. - * @param buffer Existing buffer to clone. - */ -void * csp_buffer_clone(void *buffer); - -/** - * Return how many buffers that are currently free. - * @return number of free buffers - */ -int csp_buffer_remaining(void); - -/** - * Return the size of the CSP buffers - * @return size of CSP buffers - */ -int csp_buffer_size(void); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* _CSP_BUFFER_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_cmp.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_cmp.h deleted file mode 100644 index 114a8eab..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/csp_cmp.h +++ /dev/null @@ -1,189 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_CMP_H_ -#define _CSP_CMP_H_ - -/** - @file - CSP management protocol (CMP). -*/ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -/** - CMP type. - @{ -*/ -/** - CMP request. -*/ -#define CSP_CMP_REQUEST 0x00 -/** - CMP reply. -*/ -#define CSP_CMP_REPLY 0xff -/**@}*/ - -/** - CMP requests. - @{ -*/ -/** - CMP request codes. -*/ -/** - Request identification, compile time, revision, name. -*/ -#define CSP_CMP_IDENT 1 -/** - Set/configure routing. -*/ -#define CSP_CMP_ROUTE_SET 2 -/** - Request interface statistics. -*/ -#define CSP_CMP_IF_STATS 3 -/** - Peek/read data from memory. -*/ -#define CSP_CMP_PEEK 4 -/** - Poke/write data from memory. -*/ -#define CSP_CMP_POKE 5 -/** - Get/set clock. -*/ -#define CSP_CMP_CLOCK 6 -/**@}*/ - -/** - CMP identification - max revision length. -*/ -#define CSP_CMP_IDENT_REV_LEN 20 -/** - CMP identification - max date length. -*/ -#define CSP_CMP_IDENT_DATE_LEN 12 -/** - CMP identification - max time length. -*/ -#define CSP_CMP_IDENT_TIME_LEN 9 - -/** - CMP interface statistics - max interface name length. -*/ -#define CSP_CMP_ROUTE_IFACE_LEN 11 - -/** - CMP peek/read memeory - max read length. -*/ -#define CSP_CMP_PEEK_MAX_LEN 200 - -/** - CMP poke/write memeory - max write length. -*/ -#define CSP_CMP_POKE_MAX_LEN 200 - -/** - CSP management protocol description. -*/ -struct csp_cmp_message { - //! CMP request type. - uint8_t type; - //! CMP request code. - uint8_t code; - union { - struct { - char hostname[CSP_HOSTNAME_LEN]; - char model[CSP_MODEL_LEN]; - char revision[CSP_CMP_IDENT_REV_LEN]; - char date[CSP_CMP_IDENT_DATE_LEN]; - char time[CSP_CMP_IDENT_TIME_LEN]; - } ident; - struct { - uint8_t dest_node; - uint8_t next_hop_mac; - char interface[CSP_CMP_ROUTE_IFACE_LEN]; - } route_set; - struct __attribute__((__packed__)) { - char interface[CSP_CMP_ROUTE_IFACE_LEN]; - uint32_t tx; - uint32_t rx; - uint32_t tx_error; - uint32_t rx_error; - uint32_t drop; - uint32_t autherr; - uint32_t frame; - uint32_t txbytes; - uint32_t rxbytes; - uint32_t irq; - } if_stats; - struct { - uint32_t addr; - uint8_t len; - char data[CSP_CMP_PEEK_MAX_LEN]; - } peek; - struct { - uint32_t addr; - uint8_t len; - char data[CSP_CMP_POKE_MAX_LEN]; - } poke; - csp_timestamp_t clock; - }; -} __attribute__ ((packed)); - -/** - Macro for calculating size of management message. -*/ -#define CMP_SIZE(_memb) (sizeof(((struct csp_cmp_message *)0)->_memb) + sizeof(uint8_t) + sizeof(uint8_t)) - -/** - Generic send management message request. -*/ -int csp_cmp(uint8_t node, uint32_t timeout, uint8_t code, int membsize, struct csp_cmp_message *msg); - -/** - Macro for defining management handling function. -*/ -#define CMP_MESSAGE(_code, _memb) \ -static inline int csp_cmp_##_memb(uint8_t node, uint32_t timeout, struct csp_cmp_message *msg) { \ - return csp_cmp(node, timeout, _code, CMP_SIZE(_memb), msg); \ -} - -CMP_MESSAGE(CSP_CMP_IDENT, ident) -CMP_MESSAGE(CSP_CMP_ROUTE_SET, route_set) -CMP_MESSAGE(CSP_CMP_IF_STATS, if_stats) -CMP_MESSAGE(CSP_CMP_PEEK, peek) -CMP_MESSAGE(CSP_CMP_POKE, poke) -CMP_MESSAGE(CSP_CMP_CLOCK, clock) - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_CMP_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_crc32.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_crc32.h deleted file mode 100644 index a474eaf8..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/csp_crc32.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_CRC32_H_ -#define _CSP_CRC32_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Generate precomputed CRC32 table - */ -void csp_crc32_gentab(void); - -/** - * Append CRC32 checksum to packet - * @param packet Packet to append checksum - * @param include_header use header in calculation (this will not modify the flags field) - * @return 0 on success, -1 on error - */ -int csp_crc32_append(csp_packet_t * packet, bool include_header); - -/** - * Verify CRC32 checksum on packet - * @param packet Packet to verify - * @param include_header use header in calculation (this will not modify the flags field) - * @return 0 if checksum is valid, -1 otherwise - */ -int csp_crc32_verify(csp_packet_t * packet, bool include_header); - -/** - * Calculate checksum for a given memory area - * @param data pointer to memory - * @param length length of memory to do checksum on - * @return return uint32_t checksum - */ -uint32_t csp_crc32_memory(const uint8_t * data, uint32_t length); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* _CSP_CRC32_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_debug.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_debug.h deleted file mode 100644 index 64429d49..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/csp_debug.h +++ /dev/null @@ -1,150 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_DEBUG_H_ -#define _CSP_DEBUG_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** Debug levels */ -typedef enum { - CSP_ERROR = 0, - CSP_WARN = 1, - CSP_INFO = 2, - CSP_BUFFER = 3, - CSP_PACKET = 4, - CSP_PROTOCOL = 5, - CSP_LOCK = 6, -} csp_debug_level_t; - -/* Extract filename component from path */ -#define BASENAME(_file) ((strrchr(_file, '/') ? : (strrchr(_file, '\\') ? : _file)) + 1) - -/* Implement csp_assert_fail_action to override default failure action */ -extern void __attribute__((weak)) csp_assert_fail_action(const char *assertion, const char *file, int line); - -#ifndef NDEBUG - #define csp_assert(exp) \ - do { \ - if (!(exp)) { \ - const char *assertion = #exp; \ - const char *file = BASENAME(__FILE__); \ - int line = __LINE__; \ - printf("\E[1;31m[%02" PRIu8 "] Assertion \'%s\' failed in %s:%d\E[0m\r\n", \ - csp_get_address(), assertion, file, line); \ - if (csp_assert_fail_action) \ - csp_assert_fail_action(assertion, file, line); \ - } \ - } while (0) -#else - #define csp_assert(...) do {} while (0) -#endif - -#ifdef __AVR__ - #include - #include - #define CONSTSTR(data) PSTR(data) - #undef printf - #undef sscanf - #undef scanf - #undef sprintf - #undef snprintf - #define printf(s, ...) printf_P(PSTR(s), ## __VA_ARGS__) - #define sscanf(buf, s, ...) sscanf_P(buf, PSTR(s), ## __VA_ARGS__) - #define scanf(s, ...) scanf_P(PSTR(s), ## __VA_ARGS__) - #define sprintf(buf, s, ...) sprintf_P(buf, PSTR(s), ## __VA_ARGS__) - #define snprintf(buf, size, s, ...) snprintf_P(buf, size, PSTR(s), ## __VA_ARGS__) -#else - #define CONSTSTR(data) data -#endif - -#ifdef CSP_DEBUG - #define csp_debug(level, format, ...) do { do_csp_debug(level, CONSTSTR(format), ##__VA_ARGS__); } while(0) -#else - #define csp_debug(...) do {} while (0) -#endif - -#ifdef CSP_LOG_LEVEL_ERROR - #define csp_log_error(format, ...) csp_debug(CSP_ERROR, format, ##__VA_ARGS__) -#else - #define csp_log_error(...) do {} while (0) -#endif - -#ifdef CSP_LOG_LEVEL_WARN - #define csp_log_warn(format, ...) csp_debug(CSP_WARN, format, ##__VA_ARGS__) -#else - #define csp_log_warn(...) do {} while (0) -#endif - -#ifdef CSP_LOG_LEVEL_INFO - #define csp_log_info(format, ...) csp_debug(CSP_INFO, format, ##__VA_ARGS__) -#else - #define csp_log_info(...) do {} while (0) -#endif - -#ifdef CSP_LOG_LEVEL_DEBUG - #define csp_log_buffer(format, ...) csp_debug(CSP_BUFFER, format, ##__VA_ARGS__) - #define csp_log_packet(format, ...) csp_debug(CSP_PACKET, format, ##__VA_ARGS__) - #define csp_log_protocol(format, ...) csp_debug(CSP_PROTOCOL, format, ##__VA_ARGS__) - #define csp_log_lock(format, ...) csp_debug(CSP_LOCK, format, ##__VA_ARGS__) -#else - #define csp_log_buffer(...) do {} while (0) - #define csp_log_packet(...) do {} while (0) - #define csp_log_protocol(...) do {} while (0) - #define csp_log_lock(...) do {} while (0) -#endif - -/** - * This function should not be used directly, use csp_log_() macro instead - * @param level - * @param format - */ -void do_csp_debug(csp_debug_level_t level, const char *format, ...); - -/** - * Toggle debug level on/off - * @param level Level to toggle - */ -void csp_debug_toggle_level(csp_debug_level_t level); - -/** - * Set debug level - * @param level Level to set - * @param value New level value - */ -void csp_debug_set_level(csp_debug_level_t level, bool value); - -/** - * Get current debug level value - * @param level Level value to get - * @return Level value - */ -int csp_debug_get_level(csp_debug_level_t level); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_DEBUG_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_endian.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_endian.h deleted file mode 100644 index e63a73c2..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/csp_endian.h +++ /dev/null @@ -1,170 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_ENDIAN_H_ -#define _CSP_ENDIAN_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/** - * Convert 16-bit integer from host byte order to network byte order - * @param h16 Host byte order 16-bit integer - */ -uint16_t csp_hton16(uint16_t h16); - -/** - * Convert 16-bit integer from host byte order to host byte order - * @param n16 Network byte order 16-bit integer - */ -uint16_t csp_ntoh16(uint16_t n16); - -/** - * Convert 32-bit integer from host byte order to network byte order - * @param h32 Host byte order 32-bit integer - */ -uint32_t csp_hton32(uint32_t h32); - -/** - * Convert 32-bit integer from host byte order to host byte order - * @param n32 Network byte order 32-bit integer - */ -uint32_t csp_ntoh32(uint32_t n32); - -/** - * Convert 64-bit integer from host byte order to network byte order - * @param h64 Host byte order 64-bit integer - */ -uint64_t csp_hton64(uint64_t h64); - -/** - * Convert 64-bit integer from host byte order to host byte order - * @param n64 Network byte order 64-bit integer - */ -uint64_t csp_ntoh64(uint64_t n64); - -/** - * Convert 16-bit integer from host byte order to big endian byte order - * @param h16 Host byte order 16-bit integer - */ -uint16_t csp_htobe16(uint16_t h16); - -/** - * Convert 16-bit integer from host byte order to little endian byte order - * @param h16 Host byte order 16-bit integer - */ -uint16_t csp_htole16(uint16_t h16); - -/** - * Convert 16-bit integer from big endian byte order to little endian byte order - * @param be16 Big endian byte order 16-bit integer - */ -uint16_t csp_betoh16(uint16_t be16); - -/** - * Convert 16-bit integer from little endian byte order to host byte order - * @param le16 Little endian byte order 16-bit integer - */ -uint16_t csp_letoh16(uint16_t le16); - -/** - * Convert 32-bit integer from host byte order to big endian byte order - * @param h32 Host byte order 32-bit integer - */ -uint32_t csp_htobe32(uint32_t h32); - -/** - * Convert 32-bit integer from little endian byte order to host byte order - * @param h32 Host byte order 32-bit integer - */ -uint32_t csp_htole32(uint32_t h32); - -/** - * Convert 32-bit integer from big endian byte order to host byte order - * @param be32 Big endian byte order 32-bit integer - */ -uint32_t csp_betoh32(uint32_t be32); - -/** - * Convert 32-bit integer from little endian byte order to host byte order - * @param le32 Little endian byte order 32-bit integer - */ -uint32_t csp_letoh32(uint32_t le32); - -/** - * Convert 64-bit integer from host byte order to big endian byte order - * @param h64 Host byte order 64-bit integer - */ -uint64_t csp_htobe64(uint64_t h64); - -/** - * Convert 64-bit integer from host byte order to little endian byte order - * @param h64 Host byte order 64-bit integer - */ -uint64_t csp_htole64(uint64_t h64); - -/** - * Convert 64-bit integer from big endian byte order to host byte order - * @param be64 Big endian byte order 64-bit integer - */ -uint64_t csp_betoh64(uint64_t be64); - -/** - * Convert 64-bit integer from little endian byte order to host byte order - * @param le64 Little endian byte order 64-bit integer - */ -uint64_t csp_letoh64(uint64_t le64); - -/** - * Convert float from host to network byte order - * @param f Float in host order - * @return Float in network order - */ -float csp_htonflt(float f); - -/** - * Convert float from network to host byte order - * @param f Float in network order - * @return Float in host order - */ -float csp_ntohflt(float f); - -/** - * Convert double from host to network byte order - * @param d Double in host order - * @return Double in network order - */ -double csp_htondbl(double d); - -/** - * Convert double from network to host order - * @param d Double in network order - * @return Double in host order - */ -double csp_ntohdbl(double d); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_ENDIAN_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_error.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_error.h deleted file mode 100644 index 31866607..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/csp_error.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_ERROR_H_ -#define _CSP_ERROR_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#define CSP_ERR_NONE 0 /* No error */ -#define CSP_ERR_NOMEM -1 /* Not enough memory */ -#define CSP_ERR_INVAL -2 /* Invalid argument */ -#define CSP_ERR_TIMEDOUT -3 /* Operation timed out */ -#define CSP_ERR_USED -4 /* Resource already in use */ -#define CSP_ERR_NOTSUP -5 /* Operation not supported */ -#define CSP_ERR_BUSY -6 /* Device or resource busy */ -#define CSP_ERR_ALREADY -7 /* Connection already in progress */ -#define CSP_ERR_RESET -8 /* Connection reset */ -#define CSP_ERR_NOBUFS -9 /* No more buffer space available */ -#define CSP_ERR_TX -10 /* Transmission failed */ -#define CSP_ERR_DRIVER -11 /* Error in driver layer */ -#define CSP_ERR_AGAIN -12 /* Resource temporarily unavailable */ - -#define CSP_ERR_HMAC -100 /* HMAC failed */ -#define CSP_ERR_XTEA -101 /* XTEA failed */ -#define CSP_ERR_CRC32 -102 /* CRC32 failed */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_ERROR_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_iflist.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_iflist.h deleted file mode 100644 index 55875657..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/csp_iflist.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef CSP_IFLIST_H_ -#define CSP_IFLIST_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Add interface to list - * @param ifc Pointer to interface to add - */ -void csp_iflist_add(csp_iface_t *ifc); - -/** - * Lookup interface by name - * @param name String with interface name - * @return Pointer to interface or NULL if not found - */ -csp_iface_t * csp_iflist_get_by_name(const char *name); - -/** - * Print list of interfaces to stdout - */ -void csp_iflist_print(void); - -/** - * Return list of registered interfaces. - */ -csp_iface_t * csp_iflist_get(void); - -#ifdef __cplusplus -} -#endif -#endif /* CSP_IFLIST_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_interface.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_interface.h deleted file mode 100644 index 8f04bee3..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/csp_interface.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_INTERFACE_H_ -#define _CSP_INTERFACE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/** - * Inputs a new packet into the system - * This function is called from interface drivers ISR to route and accept packets. - * But it can also be called from a task, provided that the pxTaskWoken parameter is NULL! - * - * EXTREMELY IMPORTANT: - * pxTaskWoken arg must ALWAYS be NULL if called from task, - * and ALWAYS be NON NULL if called from ISR! - * If this condition is met, this call is completely thread-safe - * - * This function is fire and forget, it returns void, meaning - * that a packet will always be either accepted or dropped - * so the memory will always be freed. - * - * @param packet A pointer to the incoming packet - * @param interface A pointer to the incoming interface TX function. - * @param pxTaskWoken This must be a pointer a valid variable if called from ISR or NULL otherwise! - */ -void csp_qfifo_write(csp_packet_t *packet, csp_iface_t *interface, CSP_BASE_TYPE *pxTaskWoken); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_INTERFACE_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_platform.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_platform.h deleted file mode 100644 index b33292e9..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/csp_platform.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_PLATFORM_H_ -#define _CSP_PLATFORM_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* Set OS */ -#if defined(CSP_POSIX) || defined(CSP_WINDOWS) || defined(CSP_MACOSX) - #define CSP_BASE_TYPE int - #define CSP_MAX_DELAY (UINT32_MAX) - #define CSP_INFINITY (UINT32_MAX) - #define CSP_DEFINE_CRITICAL(lock) static csp_bin_sem_handle_t lock - #define CSP_INIT_CRITICAL(lock) ({(csp_bin_sem_create(&lock) == CSP_SEMAPHORE_OK) ? CSP_ERR_NONE : CSP_ERR_NOMEM;}) - #define CSP_ENTER_CRITICAL(lock) do { csp_bin_sem_wait(&lock, CSP_MAX_DELAY); } while(0) - #define CSP_EXIT_CRITICAL(lock) do { csp_bin_sem_post(&lock); } while(0) -#elif defined(CSP_FREERTOS) - #include "FreeRTOS.h" - #define CSP_BASE_TYPE portBASE_TYPE - #define CSP_MAX_DELAY portMAX_DELAY - #define CSP_INFINITY portMAX_DELAY - #define CSP_DEFINE_CRITICAL(lock) - #define CSP_INIT_CRITICAL(lock) ({CSP_ERR_NONE;}) - #define CSP_ENTER_CRITICAL(lock) do { portENTER_CRITICAL(); } while (0) - #define CSP_EXIT_CRITICAL(lock) do { portEXIT_CRITICAL(); } while (0) -#else - #error "OS must be either CSP_POSIX, CSP_MACOSX, CSP_FREERTOS OR CSP_WINDOWS" -#endif - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_PLATFORM_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_rtable.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_rtable.h deleted file mode 100644 index 34cd18e2..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/csp_rtable.h +++ /dev/null @@ -1,149 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef CSP_RTABLE_H_ -#define CSP_RTABLE_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define CSP_NODE_MAC 0xFF -#define CSP_ROUTE_COUNT (CSP_ID_HOST_MAX + 2) -#define CSP_ROUTE_TABLE_SIZE 5 * CSP_ROUTE_COUNT - -/** - * Find outgoing interface in routing table - * @param id Destination node - * @return pointer to outgoing interface or NULL - */ -csp_iface_t * csp_rtable_find_iface(uint8_t id); - -/** - * Find MAC address associated with node - * @param id Destination node - * @return MAC address - */ -uint8_t csp_rtable_find_mac(uint8_t id); - -/** - * Setup routing entry - * @param node Host - * @param mask Number of bits in netmask - * @param ifc Interface - * @param mac MAC address - * @return CSP error type - */ -int csp_rtable_set(uint8_t node, uint8_t mask, csp_iface_t *ifc, uint8_t mac); - -/** - * Print routing table to stdout - */ -void csp_rtable_print(void); - - -/** - * Load the routing table from a buffer - * (deprecated, please use new csp_rtable_load) - * - * Warning: - * The table will be RAW from memory and contains direct pointers, not interface names. - * Therefore it's very important that a saved routing table is deleted after a firmware update - * - * @param route_table_in pointer to routing table buffer - */ -void csp_route_table_load(uint8_t route_table_in[CSP_ROUTE_TABLE_SIZE]); - -/** - * Save the routing table to a buffer - * (deprecated, please use new csp_rtable_save) - * - * Warning: - * The table will be RAW from memory and contains direct pointers, not interface names. - * Therefore it's very important that a saved routing table is deleted after a firmware update - * - * @param route_table_out pointer to routing table buffer - */ -void csp_route_table_save(uint8_t route_table_out[CSP_ROUTE_TABLE_SIZE]); - -/** - * Save routing table as a string to a buffer, which can be parsed - * again by csp_rtable_load. - * @param buffer pointer to buffer - * @param maxlen length of buffer - * @return length of saved string - */ -int csp_rtable_save(char * buffer, int maxlen); - -/** - * Load routing table from a string in the format - * %u/%u %s %u - * - Address - * - Netmask - * - Ifname - * - Mac Address (this field is optional) - * An example routing string is "0/0 I2C, 8/2 KISS" - * The string must be \0 null terminated - * @param buffer Pointer to string - */ -void csp_rtable_load(const char * buffer); - -/** - * Check string for valid routing table - * @param buffer Pointer to string - * @return number of valid entries found - */ -int csp_rtable_check(const char * buffer); - -/** - * Clear routing table: - * This could be done before load to ensure an entire clean table is loaded. - */ -void csp_rtable_clear(void); - -/** - * Setup routing entry to single node - * (deprecated, please use csp_rtable_set) - * - * @param node Host - * @param ifc Interface - * @param mac MAC address - * @return CSP error type - */ -#define csp_route_set(node, ifc, mac) csp_rtable_set(node, CSP_ID_HOST_SIZE, ifc, mac) - -/** - * Print routing table - * (deprecated, please use csp_rtable_print) - */ -#define csp_route_print_table() csp_rtable_print(); - -/** - * Print list of interfaces - * (deprecated, please use csp_iflist_print) - */ -#define csp_route_print_interfaces() csp_iflist_print(); - -#ifdef __cplusplus -} -#endif -#endif /* CSP_RTABLE_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/csp_types.h b/gomspace/libgscsp/lib/libcsp/include/csp/csp_types.h deleted file mode 100644 index a9cc28cd..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/csp_types.h +++ /dev/null @@ -1,235 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef CSP_TYPES_H_ -#define CSP_TYPES_H_ - -#include -#include // -> CSP_HAVE_X defines -#ifdef CSP_HAVE_STDBOOL_H -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Make bool for compilers without stdbool.h */ -#ifndef CSP_HAVE_STDBOOL_H -#define bool int -#define false 0 -#define true !false -#endif - -/** - * RESERVED PORTS (SERVICES) - */ - -enum csp_reserved_ports_e { - CSP_CMP = 0, - CSP_PING = 1, - CSP_PS = 2, - CSP_MEMFREE = 3, - CSP_REBOOT = 4, - CSP_BUF_FREE = 5, - CSP_UPTIME = 6, - CSP_ANY = (CSP_MAX_BIND_PORT + 1), - CSP_PROMISC = (CSP_MAX_BIND_PORT + 2) -}; - -typedef enum { - CSP_PRIO_CRITICAL = 0, - CSP_PRIO_HIGH = 1, - CSP_PRIO_NORM = 2, - CSP_PRIO_LOW = 3, -} csp_prio_t; - -#define CSP_PRIORITIES (1 << CSP_ID_PRIO_SIZE) - -#ifdef CSP_USE_QOS -#define CSP_RX_QUEUE_LENGTH (CSP_CONN_QUEUE_LENGTH / CSP_PRIORITIES) -#define CSP_ROUTE_FIFOS CSP_PRIORITIES -#define CSP_RX_QUEUES CSP_PRIORITIES -#else -#define CSP_RX_QUEUE_LENGTH CSP_CONN_QUEUE_LENGTH -#define CSP_ROUTE_FIFOS 1 -#define CSP_RX_QUEUES 1 -#endif - -/** Size of bit-fields in CSP header */ -#define CSP_ID_PRIO_SIZE 2 -#define CSP_ID_HOST_SIZE 5 -#define CSP_ID_PORT_SIZE 6 -#define CSP_ID_FLAGS_SIZE 8 - -#define CSP_HEADER_BITS (CSP_ID_PRIO_SIZE + 2 * CSP_ID_HOST_SIZE + 2 * CSP_ID_PORT_SIZE + CSP_ID_FLAGS_SIZE) -#define CSP_HEADER_LENGTH (CSP_HEADER_BITS / 8) - -#if CSP_HEADER_BITS != 32 && __GNUC__ -#error "Header length must be 32 bits" -#endif - -/** Highest number to be entered in field */ -#define CSP_ID_PRIO_MAX ((1 << (CSP_ID_PRIO_SIZE)) - 1) -#define CSP_ID_HOST_MAX ((1 << (CSP_ID_HOST_SIZE)) - 1) -#define CSP_ID_PORT_MAX ((1 << (CSP_ID_PORT_SIZE)) - 1) -#define CSP_ID_FLAGS_MAX ((1 << (CSP_ID_FLAGS_SIZE)) - 1) - -/** Identifier field masks */ -#define CSP_ID_PRIO_MASK ((uint32_t) CSP_ID_PRIO_MAX << (CSP_ID_FLAGS_SIZE + 2 * CSP_ID_PORT_SIZE + 2 * CSP_ID_HOST_SIZE)) -#define CSP_ID_SRC_MASK ((uint32_t) CSP_ID_HOST_MAX << (CSP_ID_FLAGS_SIZE + 2 * CSP_ID_PORT_SIZE + 1 * CSP_ID_HOST_SIZE)) -#define CSP_ID_DST_MASK ((uint32_t) CSP_ID_HOST_MAX << (CSP_ID_FLAGS_SIZE + 2 * CSP_ID_PORT_SIZE)) -#define CSP_ID_DPORT_MASK ((uint32_t) CSP_ID_PORT_MAX << (CSP_ID_FLAGS_SIZE + 1 * CSP_ID_PORT_SIZE)) -#define CSP_ID_SPORT_MASK ((uint32_t) CSP_ID_PORT_MAX << (CSP_ID_FLAGS_SIZE)) -#define CSP_ID_FLAGS_MASK ((uint32_t) CSP_ID_FLAGS_MAX << (0)) - -#define CSP_ID_CONN_MASK (CSP_ID_SRC_MASK | CSP_ID_DST_MASK | CSP_ID_DPORT_MASK | CSP_ID_SPORT_MASK) - -/** - CSP identifier. -*/ -typedef union { - //! Entire identifier. - uint32_t ext; - //! Individual fields. - struct __attribute__((__packed__)) { -#if defined(CSP_BIG_ENDIAN) && !defined(CSP_LITTLE_ENDIAN) - unsigned int pri : CSP_ID_PRIO_SIZE; - unsigned int src : CSP_ID_HOST_SIZE; - unsigned int dst : CSP_ID_HOST_SIZE; - unsigned int dport : CSP_ID_PORT_SIZE; - unsigned int sport : CSP_ID_PORT_SIZE; - unsigned int flags : CSP_ID_FLAGS_SIZE; -#elif defined(CSP_LITTLE_ENDIAN) && !defined(CSP_BIG_ENDIAN) - unsigned int flags : CSP_ID_FLAGS_SIZE; - unsigned int sport : CSP_ID_PORT_SIZE; - unsigned int dport : CSP_ID_PORT_SIZE; - unsigned int dst : CSP_ID_HOST_SIZE; - unsigned int src : CSP_ID_HOST_SIZE; - unsigned int pri : CSP_ID_PRIO_SIZE; -#else -#error "Must define one of CSP_BIG_ENDIAN or CSP_LITTLE_ENDIAN in csp_platform.h" -#endif - }; -} csp_id_t; - -/** Broadcast address */ -#define CSP_BROADCAST_ADDR CSP_ID_HOST_MAX - -/** Default routing address */ -#define CSP_DEFAULT_ROUTE (CSP_ID_HOST_MAX + 1) - -/** CSP Flags */ -#define CSP_FRES1 0x80 // Reserved for future use -#define CSP_FRES2 0x40 // Reserved for future use -#define CSP_FRES3 0x20 // Reserved for future use -#define CSP_FFRAG 0x10 // Use fragmentation -#define CSP_FHMAC 0x08 // Use HMAC verification -#define CSP_FXTEA 0x04 // Use XTEA encryption -#define CSP_FRDP 0x02 // Use RDP protocol -#define CSP_FCRC32 0x01 // Use CRC32 checksum - -/** CSP Socket options */ -#define CSP_SO_NONE 0x0000 // No socket options -#define CSP_SO_RDPREQ 0x0001 // Require RDP -#define CSP_SO_RDPPROHIB 0x0002 // Prohibit RDP -#define CSP_SO_HMACREQ 0x0004 // Require HMAC -#define CSP_SO_HMACPROHIB 0x0008 // Prohibit HMAC -#define CSP_SO_XTEAREQ 0x0010 // Require XTEA -#define CSP_SO_XTEAPROHIB 0x0020 // Prohibit HMAC -#define CSP_SO_CRC32REQ 0x0040 // Require CRC32 -#define CSP_SO_CRC32PROHIB 0x0080 // Prohibit CRC32 -#define CSP_SO_CONN_LESS 0x0100 // Enable Connection Less mode -#define CSP_SO_INTERNAL_LISTEN 0x1000 // Internal flag: listen called on socket - -/** CSP Connect options */ -#define CSP_O_NONE CSP_SO_NONE // No connection options -#define CSP_O_RDP CSP_SO_RDPREQ // Enable RDP -#define CSP_O_NORDP CSP_SO_RDPPROHIB // Disable RDP -#define CSP_O_HMAC CSP_SO_HMACREQ // Enable HMAC -#define CSP_O_NOHMAC CSP_SO_HMACPROHIB // Disable HMAC -#define CSP_O_XTEA CSP_SO_XTEAREQ // Enable XTEA -#define CSP_O_NOXTEA CSP_SO_XTEAPROHIB // Disable XTEA -#define CSP_O_CRC32 CSP_SO_CRC32REQ // Enable CRC32 -#define CSP_O_NOCRC32 CSP_SO_CRC32PROHIB // Disable CRC32 - -/** - * CSP PACKET STRUCTURE - * Note: This structure is constructed to fit - * with all interface frame types in order to - * have buffer reuse - */ -typedef struct __attribute__((__packed__)) { - uint8_t padding[CSP_PADDING_BYTES]; /**< Interface dependent padding */ - uint16_t length; /**< Length field must be just before CSP ID */ - csp_id_t id; /**< CSP id must be just before data */ - union { - uint8_t data[0]; /**< This just points to the rest of the buffer, without a size indication. */ - uint16_t data16[0]; /**< The data 16 and 32 types makes it easy to reference an integer (properly aligned) */ - uint32_t data32[0]; /**< without the compiler warning about strict aliasing rules. */ - }; -} csp_packet_t; - -/** Interface TX function */ -struct csp_iface_s; -typedef int (*nexthop_t)(struct csp_iface_s * interface, csp_packet_t *packet, uint32_t timeout); - -/** Interface struct */ -typedef struct csp_iface_s { - const char *name; /**< Interface name (keep below 10 bytes) */ - void * driver; /**< Pointer to interface handler structure */ - nexthop_t nexthop; /**< Next hop function */ - uint16_t mtu; /**< Maximum Transmission Unit of interface */ - uint8_t split_horizon_off; /**< Disable the route-loop prevention on if */ - uint32_t tx; /**< Successfully transmitted packets */ - uint32_t rx; /**< Successfully received packets */ - uint32_t tx_error; /**< Transmit errors */ - uint32_t rx_error; /**< Receive errors */ - uint32_t drop; /**< Dropped packets */ - uint32_t autherr; /**< Authentication errors */ - uint32_t frame; /**< Frame format errors */ - uint32_t txbytes; /**< Transmitted bytes */ - uint32_t rxbytes; /**< Received bytes */ - uint32_t irq; /**< Interrupts */ - struct csp_iface_s *next; /**< Next interface */ -} csp_iface_t; - -/** - * This define must be equal to the size of the packet overhead in csp_packet_t. - * It is used in csp_buffer_get() to check the allocated buffer size against - * the required buffer size. - */ -#define CSP_BUFFER_PACKET_OVERHEAD (sizeof(csp_packet_t) - sizeof(((csp_packet_t *)0)->data)) - -/** Forward declaration of socket and connection structures */ -typedef struct csp_conn_s csp_socket_t; -typedef struct csp_conn_s csp_conn_t; - -#define CSP_HOSTNAME_LEN 20 -#define CSP_MODEL_LEN 30 - -/* CSP_REBOOT magic values */ -#define CSP_REBOOT_MAGIC 0x80078007 -#define CSP_REBOOT_SHUTDOWN_MAGIC 0xD1E5529A - -#ifdef __cplusplus -} -#endif -#endif /* CSP_TYPES_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/drivers/can_socketcan.h b/gomspace/libgscsp/lib/libcsp/include/csp/drivers/can_socketcan.h deleted file mode 100644 index 0963b414..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/drivers/can_socketcan.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * can_socketcan.h - * - * Created on: Feb 6, 2017 - * Author: johan - */ - -#ifndef LIB_CSP_INCLUDE_CSP_DRIVERS_CAN_SOCKETCAN_H_ -#define LIB_CSP_INCLUDE_CSP_DRIVERS_CAN_SOCKETCAN_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -csp_iface_t * csp_can_socketcan_init(const char * ifc, int bitrate, int promisc); - -#ifdef __cplusplus -} -#endif -#endif /* LIB_CSP_INCLUDE_CSP_DRIVERS_CAN_SOCKETCAN_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/drivers/i2c.h b/gomspace/libgscsp/lib/libcsp/include/csp/drivers/i2c.h deleted file mode 100644 index 3cf605ee..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/drivers/i2c.h +++ /dev/null @@ -1,120 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/** - * @file - * Common I2C interface, - * This file is derived from the Gomspace I2C driver, - * - */ - -#ifndef I2C_H_ -#define I2C_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * The return value of the driver is a bit strange, - * It should return E_NO_ERR if successfull and the value is -1 - */ -#define E_NO_ERR -1 - -/** - * Maximum transfer length on I2C - */ -#define I2C_MTU 256 - -/** - I2C device modes - @{ -*/ -/** - I2C Master mode. -*/ -#define I2C_MASTER 0 -/** - I2C Slave mode. -*/ -#define I2C_SLAVE 1 -/**@}*/ - -/** - Data structure for I2C frames. - This structs fits on top of #csp_packet_t, removing the need for copying data. -*/ -typedef struct __attribute__((packed)) i2c_frame_s { - //! Not used by CSP - uint8_t padding; - //! Not used by CSP - cleared before Tx - uint8_t retries; - //! Not used by CSP - uint32_t reserved; - //! Destination address - uint8_t dest; - //! Not used by CSP - cleared before Tx - uint8_t len_rx; - //! Length of \a data part - uint16_t len; - //! CSP data - uint8_t data[I2C_MTU]; -} i2c_frame_t; - -/** - Callback for receiving data. - - @param[in] frame received I2C frame - @param[out] pxTaskWoken can be set, if context switch is required due to received data. -*/ -typedef void (*i2c_callback_t) (i2c_frame_t * frame, void * pxTaskWoken); - -/** - Initialise the I2C driver - - Functions is called by csp_i2c_init(). - - @param handle Which I2C bus (if more than one exists) - @param mode I2C device mode. Must be either I2C_MASTER or I2C_SLAVE - @param addr Own slave address - @param speed Bus speed in kbps - @param queue_len_tx Length of transmit queue - @param queue_len_rx Length of receive queue - @param callback If this value is set, the driver will call this function instead of using an RX queue - @return Error code -*/ -int i2c_init(int handle, int mode, uint8_t addr, uint16_t speed, int queue_len_tx, int queue_len_rx, i2c_callback_t callback); - -/** - User I2C transmit function. - - Called by CSP, when sending message over I2C. - - @param handle Handle to the device - @param frame Pointer to I2C frame - @param timeout Ticks to wait - @return Error code -*/ -int i2c_send(int handle, i2c_frame_t * frame, uint16_t timeout); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/drivers/usart.h b/gomspace/libgscsp/lib/libcsp/include/csp/drivers/usart.h deleted file mode 100644 index d2da8448..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/drivers/usart.h +++ /dev/null @@ -1,107 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/** - * @file - * Common USART interface, - * This file is derived from the Gomspace USART driver, - * the main difference is the assumption that only one USART will be present on a PC - */ - -#ifndef USART_H_ -#define USART_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Usart configuration, to be used with the usart_init call. -*/ -struct usart_conf { - //! USART device. - const char *device; - //! bits per second. - uint32_t baudrate; - //! Number of data bits. - uint8_t databits; - //! Number of stop bits. - uint8_t stopbits; - //! Parity setting. - uint8_t paritysetting; - //! Enable parity checking (Windows only). - uint8_t checkparity; -}; - -/** - Initialise UART with the usart_conf data structure - @param[in] conf full configuration structure -*/ -void usart_init(struct usart_conf *conf); - -/** - In order to catch incoming chars use the callback. - Only one callback per interface. - @param[in] handle usart[0,1,2,3] - @param[in] callback function pointer -*/ -typedef void (*usart_callback_t) (uint8_t *buf, int len, void *pxTaskWoken); - -/** - Set callback for receiving data. -*/ -void usart_set_callback(usart_callback_t callback); - -/** - Insert a character to the RX buffer of a usart - - @param[in] c character to insert - @param[out] pxTaskWoken can be set, if context switch is required due to received data. -*/ -void usart_insert(char c, void *pxTaskWoken); - -/** - Polling putchar (stdin). - - @param[in] c Character to transmit -*/ -void usart_putc(char c); - -/** - Send char buffer on UART (stdout). - - @param[in] buf Pointer to data - @param[in] len Length of data -*/ -void usart_putstr(char *buf, int len); - -/** - Buffered getchar (stdin). - - @return Character received -*/ -char usart_getc(void); - -#ifdef __cplusplus -} -#endif -#endif /* USART_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_can.h b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_can.h deleted file mode 100644 index 229671f2..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_can.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_IF_CAN_H_ -#define _CSP_IF_CAN_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include -#include - -/* CAN header macros */ -#define CFP_HOST_SIZE 5 -#define CFP_TYPE_SIZE 1 -#define CFP_REMAIN_SIZE 8 -#define CFP_ID_SIZE 10 - -/* Macros for extracting header fields */ -#define CFP_FIELD(id,rsiz,fsiz) ((uint32_t)((uint32_t)((id) >> (rsiz)) & (uint32_t)((1 << (fsiz)) - 1))) -#define CFP_SRC(id) CFP_FIELD(id, CFP_HOST_SIZE + CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE, CFP_HOST_SIZE) -#define CFP_DST(id) CFP_FIELD(id, CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE, CFP_HOST_SIZE) -#define CFP_TYPE(id) CFP_FIELD(id, CFP_REMAIN_SIZE + CFP_ID_SIZE, CFP_TYPE_SIZE) -#define CFP_REMAIN(id) CFP_FIELD(id, CFP_ID_SIZE, CFP_REMAIN_SIZE) -#define CFP_ID(id) CFP_FIELD(id, 0, CFP_ID_SIZE) - -/* Macros for building CFP headers */ -#define CFP_MAKE_FIELD(id,fsiz,rsiz) ((uint32_t)(((id) & (uint32_t)((uint32_t)(1 << (fsiz)) - 1)) << (rsiz))) -#define CFP_MAKE_SRC(id) CFP_MAKE_FIELD(id, CFP_HOST_SIZE, CFP_HOST_SIZE + CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE) -#define CFP_MAKE_DST(id) CFP_MAKE_FIELD(id, CFP_HOST_SIZE, CFP_TYPE_SIZE + CFP_REMAIN_SIZE + CFP_ID_SIZE) -#define CFP_MAKE_TYPE(id) CFP_MAKE_FIELD(id, CFP_TYPE_SIZE, CFP_REMAIN_SIZE + CFP_ID_SIZE) -#define CFP_MAKE_REMAIN(id) CFP_MAKE_FIELD(id, CFP_REMAIN_SIZE, CFP_ID_SIZE) -#define CFP_MAKE_ID(id) CFP_MAKE_FIELD(id, CFP_ID_SIZE, 0) - -/* Mask to uniquely separate connections */ -#define CFP_ID_CONN_MASK (CFP_MAKE_SRC((uint32_t)(1 << CFP_HOST_SIZE) - 1) | \ - CFP_MAKE_DST((uint32_t)(1 << CFP_HOST_SIZE) - 1) | \ - CFP_MAKE_ID((uint32_t)(1 << CFP_ID_SIZE) - 1)) - -/** - Default Maximum Transmission Unit (MTU) for CSP over CAN. - Maximum value is 2042 bytes. -*/ -#define CSP_CAN_MTU 256 - -int csp_can_rx(csp_iface_t *interface, uint32_t id, const uint8_t * data, uint8_t dlc, CSP_BASE_TYPE *task_woken); -int csp_can_tx(csp_iface_t *interface, csp_packet_t *packet, uint32_t timeout); - -/* Must be implemented by the driver */ -int csp_can_tx_frame(csp_iface_t *interface, uint32_t id, const uint8_t * data, uint8_t dlc); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* _CSP_IF_CAN_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_i2c.h b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_i2c.h deleted file mode 100644 index c2169843..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_i2c.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_IF_I2C_H_ -#define _CSP_IF_I2C_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include -#include -#include - -extern csp_iface_t csp_if_i2c; - -/** - * Capture I2C RX events for CSP - * @param opt_addr local i2c address - * @param handle which i2c device to use - * @param speed interface speed in kHz (normally 100 or 400) - * @return csp_error.h code - */ -int csp_i2c_init(uint8_t opt_addr, int handle, int speed); - -void csp_i2c_rx(i2c_frame_t * frame, void * pxTaskWoken); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* _CSP_IF_I2C_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_kiss.h b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_kiss.h deleted file mode 100644 index f164cad1..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_kiss.h +++ /dev/null @@ -1,110 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_IF_KISS_H_ -#define _CSP_IF_KISS_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include -#include - -/** - * The KISS interface relies on the USART callback in order to parse incoming - * messaged from the serial interface. The USART callback however does not - * support passing the handle number of the responding USART, so you need to implement - * a USART callback for each handle and then call kiss_rx subsequently. - * - * In order to initialize the KISS interface. Fist call kiss_init() and then - * setup your usart to call csp_kiss_rx when new data is available. - * - * When a byte is not a part of a kiss packet, it will be returned to your - * usart driver using the usart_insert funtion that you provide. - * - * @param csp_iface pointer to interface - * @param buf pointer to incoming data - * @param len length of incoming data - * @param pxTaskWoken NULL if task context, pointer to variable if ISR - */ -void csp_kiss_rx(csp_iface_t * interface, uint8_t *buf, int len, void *pxTaskWoken); - -/** - * The putc function is used by the kiss interface to send - * a string of data to the serial port. This function must - * be implemented by the user, and passed to the kiss - * interface through the kiss_init function. - * @param buf byte to push - */ -typedef void (*csp_kiss_putc_f)(char buf); - -/** - * The characters not accepted by the kiss interface, are discarded - * using this function, which must be implemented by the user - * and passed through the kiss_init function. - * - * This reject function is typically used to display ASCII strings - * sent over the serial port, which are not in KISS format. Such as - * debugging information. - * - * @param c rejected character - * @param pxTaskWoken NULL if task context, pointer to variable if ISR - */ -typedef void (*csp_kiss_discard_f)(char c, void *pxTaskWoken); - -typedef enum { - KISS_MODE_NOT_STARTED, - KISS_MODE_STARTED, - KISS_MODE_ESCAPED, - KISS_MODE_SKIP_FRAME, -} kiss_mode_e; - -/** - * This structure should be statically allocated by the user - * and passed to the kiss interface during the init function - * no member information should be changed - */ -typedef struct csp_kiss_handle_s { - //! Put character on usart (tx). - csp_kiss_putc_f kiss_putc; - //! Discard - not KISS data (rx). - csp_kiss_discard_f kiss_discard; - //! Internal KISS state. - unsigned int rx_length; - //! Internal KISS state. - kiss_mode_e rx_mode; - //! Internal KISS state. - unsigned int rx_first; - //! Not used. - volatile unsigned char *rx_cbuf; - //! Internal KISS state. - csp_packet_t * rx_packet; -} csp_kiss_handle_t; - -void csp_kiss_init(csp_iface_t * csp_iface, csp_kiss_handle_t * csp_kiss_handle, csp_kiss_putc_f kiss_putc_f, csp_kiss_discard_f kiss_discard_f, const char * name); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* _CSP_IF_KISS_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_lo.h b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_lo.h deleted file mode 100644 index 793c45ac..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_lo.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_IF_LO_H_ -#define _CSP_IF_LO_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* CSP includes */ -#include -#include - -extern csp_iface_t csp_if_lo; - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_IF_LO_H_ diff --git a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_zmqhub.h b/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_zmqhub.h deleted file mode 100644 index f9ab43bf..00000000 --- a/gomspace/libgscsp/lib/libcsp/include/csp/interfaces/csp_if_zmqhub.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef CSP_IF_ZMQHUB_H_ -#define CSP_IF_ZMQHUB_H_ - -#include - -extern csp_iface_t csp_if_zmqhub; - -/** - * Setup ZMQ interface - * @param addr only receive messages matching this address (255 means all) - * @param host Pointer to string containing zmqproxy host - * @return CSP_ERR - */ -int csp_zmqhub_init(uint8_t addr, const char * host); - -/** - * Setup ZMQ interface - * @param addr only receive messages matching this address (255 means all) - * @param publisher_endpoint Pointer to string containing zmqproxy publisher endpoint - * @param subscriber_endpoint Pointer to string containing zmqproxy subscriber endpoint - * @return CSP_ERR - */ -int csp_zmqhub_init_w_endpoints(uint8_t addr, const char * publisher_url, - const char * subscriber_url); - -#endif /* CSP_IF_ZMQHUB_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_malloc.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_malloc.c deleted file mode 100644 index 97e5c8f4..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_malloc.c +++ /dev/null @@ -1,33 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include - -/* FreeRTOS includes */ -#include - -void * csp_malloc(size_t size) { - return pvPortMalloc(size); -} - -void csp_free(void *ptr) { - vPortFree(ptr); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_queue.c deleted file mode 100644 index 44efd0eb..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_queue.c +++ /dev/null @@ -1,66 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include - -/* FreeRTOS includes */ -#include -#include - -/* CSP includes */ -#include - -#include - -csp_queue_handle_t csp_queue_create(int length, size_t item_size) { - return xQueueCreate(length, item_size); -} - -void csp_queue_remove(csp_queue_handle_t queue) { - vQueueDelete(queue); -} - -int csp_queue_enqueue(csp_queue_handle_t handle, void * value, uint32_t timeout) { - if (timeout != CSP_MAX_DELAY) - timeout = timeout / portTICK_RATE_MS; - return xQueueSendToBack(handle, value, timeout); -} - -int csp_queue_enqueue_isr(csp_queue_handle_t handle, void * value, CSP_BASE_TYPE * task_woken) { - return xQueueSendToBackFromISR(handle, value, task_woken); -} - -int csp_queue_dequeue(csp_queue_handle_t handle, void * buf, uint32_t timeout) { - if (timeout != CSP_MAX_DELAY) - timeout = timeout / portTICK_RATE_MS; - return xQueueReceive(handle, buf, timeout); -} - -int csp_queue_dequeue_isr(csp_queue_handle_t handle, void * buf, CSP_BASE_TYPE * task_woken) { - return xQueueReceiveFromISR(handle, buf, task_woken); -} - -int csp_queue_size(csp_queue_handle_t handle) { - return uxQueueMessagesWaiting(handle); -} - -int csp_queue_size_isr(csp_queue_handle_t handle) { - return uxQueueMessagesWaitingFromISR(handle); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_semaphore.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_semaphore.c deleted file mode 100644 index b91757e5..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_semaphore.c +++ /dev/null @@ -1,96 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include - -/* FreeRTOS includes */ -#include -#include - -/* CSP includes */ -#include - -#include -#include -#include - -int csp_mutex_create(csp_mutex_t * mutex) { - *mutex = xSemaphoreCreateMutex(); - if (*mutex) { - return CSP_SEMAPHORE_OK; - } else { - return CSP_SEMAPHORE_ERROR; - } -} - -int csp_mutex_remove(csp_mutex_t * mutex) { - return csp_bin_sem_remove(mutex); -} - -int csp_mutex_lock(csp_mutex_t * mutex, uint32_t timeout) { - return csp_bin_sem_wait(mutex, timeout); -} - -int csp_mutex_unlock(csp_mutex_t * mutex) { - return csp_bin_sem_post(mutex); -} - -int csp_bin_sem_create(csp_bin_sem_handle_t * sem) { - vSemaphoreCreateBinary(*sem); - return CSP_SEMAPHORE_OK; -} - -int csp_bin_sem_remove(csp_bin_sem_handle_t * sem) { - if ((sem != NULL) && (*sem != NULL)) { - csp_queue_remove(*sem); - } - return CSP_SEMAPHORE_OK; -} - -int csp_bin_sem_wait(csp_bin_sem_handle_t * sem, uint32_t timeout) { - csp_log_lock("Wait: %p", sem); - if (timeout != CSP_MAX_DELAY) - timeout = timeout / portTICK_RATE_MS; - if (xSemaphoreTake(*sem, timeout) == pdPASS) { - return CSP_SEMAPHORE_OK; - } else { - return CSP_SEMAPHORE_ERROR; - } -} - -int csp_bin_sem_post(csp_bin_sem_handle_t * sem) { - csp_log_lock("Post: %p", sem); - if (xSemaphoreGive(*sem) == pdPASS) { - return CSP_SEMAPHORE_OK; - } else { - return CSP_SEMAPHORE_ERROR; - } -} - -int csp_bin_sem_post_isr(csp_bin_sem_handle_t * sem, CSP_BASE_TYPE * task_woken) { - csp_log_lock("Post: %p", sem); - if (xSemaphoreGiveFromISR(*sem, task_woken) == pdPASS) { - return CSP_SEMAPHORE_OK; - } else { - return CSP_SEMAPHORE_ERROR; - } -} - diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_system.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_system.c deleted file mode 100644 index a81c84b4..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_system.c +++ /dev/null @@ -1,139 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include - -#include -#include - -#include - -int csp_sys_tasklist(char * out) { -#if (tskKERNEL_VERSION_MAJOR < 8) - vTaskList((signed portCHAR *) out); -#else - vTaskList(out); -#endif - return CSP_ERR_NONE; -} - -int csp_sys_tasklist_size(void) { - return 40 * uxTaskGetNumberOfTasks(); -} - -uint32_t csp_sys_memfree(void) { - - uint32_t total = 0, max = UINT32_MAX, size; - void * pmem; - - /* If size_t is less than 32 bits, start with 10 KiB */ - size = sizeof(uint32_t) > sizeof(size_t) ? 10000 : 1000000; - - while (1) { - pmem = pvPortMalloc(size + total); - if (pmem == NULL) { - max = size + total; - size = size / 2; - } else { - total += size; - if (total + size >= max) - size = size / 2; - vPortFree(pmem); - } - if (size < 32) break; - } - - return total; -} - -int csp_sys_reboot(void) { - - extern void __attribute__((weak)) cpu_set_reset_cause(unsigned int); - if (cpu_set_reset_cause) - cpu_set_reset_cause(1); - - extern void __attribute__((weak)) cpu_reset(void); - if (cpu_reset) { - cpu_reset(); - while (1); - } - - csp_log_error("Failed to reboot"); - - return CSP_ERR_INVAL; -} - -int csp_sys_shutdown(void) { - - extern void __attribute__((weak)) cpu_shutdown(void); - if (cpu_shutdown) { - cpu_shutdown(); - while (1); - } - - csp_log_error("Failed to shutdown"); - - return CSP_ERR_INVAL; -} - -void csp_sys_set_color(csp_color_t color) { - - unsigned int color_code, modifier_code; - switch (color & COLOR_MASK_COLOR) { - case COLOR_BLACK: - color_code = 30; break; - case COLOR_RED: - color_code = 31; break; - case COLOR_GREEN: - color_code = 32; break; - case COLOR_YELLOW: - color_code = 33; break; - case COLOR_BLUE: - color_code = 34; break; - case COLOR_MAGENTA: - color_code = 35; break; - case COLOR_CYAN: - color_code = 36; break; - case COLOR_WHITE: - color_code = 37; break; - case COLOR_RESET: - default: - color_code = 0; break; - } - - switch (color & COLOR_MASK_MODIFIER) { - case COLOR_BOLD: - modifier_code = 1; break; - case COLOR_UNDERLINE: - modifier_code = 2; break; - case COLOR_BLINK: - modifier_code = 3; break; - case COLOR_HIDE: - modifier_code = 4; break; - case COLOR_NORMAL: - default: - modifier_code = 0; break; - } - - printf("\033[%u;%um", modifier_code, color_code); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_thread.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_thread.c deleted file mode 100644 index af8296cd..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_thread.c +++ /dev/null @@ -1,38 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include - -/* CSP includes */ -#include - -#include - -int csp_thread_create(csp_thread_return_t (* routine)(void *), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle) { -#if (tskKERNEL_VERSION_MAJOR >= 8) - portBASE_TYPE ret = xTaskCreate(routine, thread_name, stack_depth, parameters, priority, handle); -#else - portBASE_TYPE ret = xTaskCreate(routine, (signed char *) thread_name, stack_depth, parameters, priority, handle); -#endif - if (ret != pdTRUE) - return CSP_ERR_NOMEM; - return CSP_ERR_NONE; -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_time.c b/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_time.c deleted file mode 100644 index fd54a8cb..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/freertos/csp_time.c +++ /dev/null @@ -1,46 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include - -/* FreeRTOS includes */ -#include -#include - -/* CSP includes */ -#include - -#include - -uint32_t csp_get_ms(void) { - return (uint32_t)(xTaskGetTickCount() * (1000/configTICK_RATE_HZ)); -} - -uint32_t csp_get_ms_isr(void) { - return (uint32_t)(xTaskGetTickCountFromISR() * (1000/configTICK_RATE_HZ)); -} - -uint32_t csp_get_s(void) { - return (uint32_t)(xTaskGetTickCount()/configTICK_RATE_HZ); -} - -uint32_t csp_get_s_isr(void) { - return (uint32_t)(xTaskGetTickCountFromISR()/configTICK_RATE_HZ); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_malloc.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_malloc.c deleted file mode 100644 index 95bb8cc7..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_malloc.c +++ /dev/null @@ -1,31 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include - -void * csp_malloc(size_t size) { - return malloc(size); -} - -void csp_free(void *ptr) { - free(ptr); -} - diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_queue.c deleted file mode 100644 index a2fb1b4f..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_queue.c +++ /dev/null @@ -1,64 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include - -/* CSP includes */ -#include - -#include -#include - - -csp_queue_handle_t csp_queue_create(int length, size_t item_size) { - return pthread_queue_create(length, item_size); -} - -void csp_queue_remove(csp_queue_handle_t queue) { - return pthread_queue_delete(queue); -} - -int csp_queue_enqueue(csp_queue_handle_t handle, void *value, uint32_t timeout) { - return pthread_queue_enqueue(handle, value, timeout); -} - -int csp_queue_enqueue_isr(csp_queue_handle_t handle, void * value, CSP_BASE_TYPE * task_woken) { - if (task_woken != NULL) - *task_woken = 0; - return csp_queue_enqueue(handle, value, 0); -} - -int csp_queue_dequeue(csp_queue_handle_t handle, void *buf, uint32_t timeout) { - return pthread_queue_dequeue(handle, buf, timeout); -} - -int csp_queue_dequeue_isr(csp_queue_handle_t handle, void *buf, CSP_BASE_TYPE * task_woken) { - *task_woken = 0; - return csp_queue_dequeue(handle, buf, 0); -} - -int csp_queue_size(csp_queue_handle_t handle) { - return pthread_queue_items(handle); -} - -int csp_queue_size_isr(csp_queue_handle_t handle) { - return pthread_queue_items(handle); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_semaphore.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_semaphore.c deleted file mode 100644 index 915447f3..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_semaphore.c +++ /dev/null @@ -1,105 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* CSP includes */ -#include - -#include - -int csp_mutex_create(csp_mutex_t * mutex) { - csp_log_lock("Mutex init: %p", mutex); - *mutex = pthread_queue_create(1, sizeof(int)); - if (mutex) { - int dummy = 0; - pthread_queue_enqueue(*mutex, &dummy, 0); - return CSP_SEMAPHORE_OK; - } else { - return CSP_SEMAPHORE_ERROR; - } -} - -int csp_mutex_remove(csp_mutex_t * mutex) { - pthread_queue_delete(*mutex); - return CSP_SEMAPHORE_OK; -} - -int csp_mutex_lock(csp_mutex_t * mutex, uint32_t timeout) { - - int ret; - csp_log_lock("Wait: %p timeout %"PRIu32, mutex, timeout); - - if (timeout == CSP_INFINITY) { - /* TODO: fix this to be infinite */ - int dummy = 0; - if (pthread_queue_dequeue(*mutex, &dummy, timeout) == PTHREAD_QUEUE_OK) - ret = CSP_MUTEX_OK; - else - ret = CSP_MUTEX_ERROR; - } else { - int dummy = 0; - if (pthread_queue_dequeue(*mutex, &dummy, timeout) == PTHREAD_QUEUE_OK) - ret = CSP_MUTEX_OK; - else - ret = CSP_MUTEX_ERROR; - } - - return ret == CSP_MUTEX_ERROR ? CSP_SEMAPHORE_ERROR : CSP_SEMAPHORE_OK; -} - -int csp_mutex_unlock(csp_mutex_t * mutex) { - int dummy = 0; - if (pthread_queue_enqueue(*mutex, &dummy, 0) == PTHREAD_QUEUE_OK) { - return CSP_SEMAPHORE_OK; - } else { - return CSP_SEMAPHORE_ERROR; - } -} - -int csp_bin_sem_create(csp_bin_sem_handle_t * sem) { - return csp_mutex_create(sem); -} - -int csp_bin_sem_remove(csp_bin_sem_handle_t * sem) { - return csp_mutex_remove(sem); -} - -int csp_bin_sem_wait(csp_bin_sem_handle_t * sem, uint32_t timeout) { - return csp_mutex_lock(sem, timeout); -} - -int csp_bin_sem_post(csp_bin_sem_handle_t * sem) { - return csp_mutex_unlock(sem); -} - -int csp_bin_sem_post_isr(csp_bin_sem_handle_t * sem, CSP_BASE_TYPE * task_woken) { - return csp_mutex_unlock(sem); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_system.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_system.c deleted file mode 100644 index 834cb210..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_system.c +++ /dev/null @@ -1,99 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include - -#include -#include - -#include - -int csp_sys_tasklist(char * out) { - strcpy(out, "Tasklist not available on OSX"); - return CSP_ERR_NONE; -} - -int csp_sys_tasklist_size(void) { - return 100; -} - -uint32_t csp_sys_memfree(void) { - /* TODO: Fix memory free on OSX */ - uint32_t total = 0; - return total; -} - -int csp_sys_reboot(void) { - /* TODO: Fix reboot on OSX */ - csp_log_error("Failed to reboot"); - - return CSP_ERR_INVAL; -} - -int csp_sys_shutdown(void) { - /* TODO: Fix shutdown on OSX */ - csp_log_error("Failed to shutdown"); - - return CSP_ERR_INVAL; -} - -void csp_sys_set_color(csp_color_t color) { - - unsigned int color_code, modifier_code; - switch (color & COLOR_MASK_COLOR) { - case COLOR_BLACK: - color_code = 30; break; - case COLOR_RED: - color_code = 31; break; - case COLOR_GREEN: - color_code = 32; break; - case COLOR_YELLOW: - color_code = 33; break; - case COLOR_BLUE: - color_code = 34; break; - case COLOR_MAGENTA: - color_code = 35; break; - case COLOR_CYAN: - color_code = 36; break; - case COLOR_WHITE: - color_code = 37; break; - case COLOR_RESET: - default: - color_code = 0; break; - } - - switch (color & COLOR_MASK_MODIFIER) { - case COLOR_BOLD: - modifier_code = 1; break; - case COLOR_UNDERLINE: - modifier_code = 2; break; - case COLOR_BLINK: - modifier_code = 3; break; - case COLOR_HIDE: - modifier_code = 4; break; - case COLOR_NORMAL: - default: - modifier_code = 0; break; - } - - printf("\033[%u;%um", modifier_code, color_code); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_thread.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_thread.c deleted file mode 100644 index ed64856a..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_thread.c +++ /dev/null @@ -1,31 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include - -/* CSP includes */ -#include - -#include - -int csp_thread_create(csp_thread_return_t (* routine)(void *), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle) { - return pthread_create(handle, NULL, routine, parameters); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_time.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_time.c deleted file mode 100644 index a53f27e6..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/csp_time.c +++ /dev/null @@ -1,65 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include - -/* CSP includes */ -#include - -#include - -uint32_t csp_get_ms(void) { - struct timespec ts; - - clock_serv_t cclock; - mach_timespec_t mts; - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); - clock_get_time(cclock, &mts); - mach_port_deallocate(mach_task_self(), cclock); - ts.tv_sec = mts.tv_sec; - ts.tv_nsec = mts.tv_nsec; - - return (uint32_t)(ts.tv_sec*1000+ts.tv_nsec/1000000); -} - -uint32_t csp_get_ms_isr(void) { - return csp_get_ms(); -} - -uint32_t csp_get_s(void) { - struct timespec ts; - - clock_serv_t cclock; - mach_timespec_t mts; - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); - clock_get_time(cclock, &mts); - mach_port_deallocate(mach_task_self(), cclock); - ts.tv_sec = mts.tv_sec; - ts.tv_nsec = mts.tv_nsec; - - return (uint32_t)ts.tv_sec; -} - -uint32_t csp_get_s_isr(void) { - return csp_get_s(); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/pthread_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/macosx/pthread_queue.c deleted file mode 100644 index c4ac8c1d..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/macosx/pthread_queue.c +++ /dev/null @@ -1,179 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* -Inspired by c-pthread-queue by Matthew Dickinson -http://code.google.com/p/c-pthread-queue/ -*/ - -#include -#include -#include -#include -#include -#include -#include - -/* CSP includes */ -#include - -pthread_queue_t * pthread_queue_create(int length, size_t item_size) { - - pthread_queue_t * q = malloc(sizeof(pthread_queue_t)); - - if (q != NULL) { - q->buffer = malloc(length*item_size); - if (q->buffer != NULL) { - q->size = length; - q->item_size = item_size; - q->items = 0; - q->in = 0; - q->out = 0; - if (pthread_mutex_init(&(q->mutex), NULL) || pthread_cond_init(&(q->cond_full), NULL) || pthread_cond_init(&(q->cond_empty), NULL)) { - free(q->buffer); - free(q); - q = NULL; - } - } else { - free(q); - q = NULL; - } - } - - return q; - -} - -void pthread_queue_delete(pthread_queue_t * q) { - - if (q == NULL) - return; - - free(q->buffer); - free(q); - - return; - -} - -int pthread_queue_enqueue(pthread_queue_t * queue, void * value, uint32_t timeout) { - - int ret; - - /* Calculate timeout */ - struct timespec ts; - - clock_serv_t cclock; - mach_timespec_t mts; - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); - clock_get_time(cclock, &mts); - mach_port_deallocate(mach_task_self(), cclock); - ts.tv_sec = mts.tv_sec; - ts.tv_nsec = mts.tv_nsec; - - uint32_t sec = timeout / 1000; - uint32_t nsec = (timeout - 1000 * sec) * 1000000; - - ts.tv_sec += sec; - - if (ts.tv_nsec + nsec > 1000000000) - ts.tv_sec++; - - ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; - - /* Get queue lock */ - pthread_mutex_lock(&(queue->mutex)); - while (queue->items == queue->size) { - ret = pthread_cond_timedwait(&(queue->cond_full), &(queue->mutex), &ts); - if (ret != 0) { - pthread_mutex_unlock(&(queue->mutex)); - return PTHREAD_QUEUE_FULL; - } - } - - /* Coby object from input buffer */ - memcpy(queue->buffer+(queue->in * queue->item_size), value, queue->item_size); - queue->items++; - queue->in = (queue->in + 1) % queue->size; - pthread_mutex_unlock(&(queue->mutex)); - - /* Nofify blocked threads */ - pthread_cond_broadcast(&(queue->cond_empty)); - - return PTHREAD_QUEUE_OK; - -} - -int pthread_queue_dequeue(pthread_queue_t * queue, void * buf, uint32_t timeout) { - - int ret; - - /* Calculate timeout */ - struct timespec ts; - clock_serv_t cclock; - mach_timespec_t mts; - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); - clock_get_time(cclock, &mts); - mach_port_deallocate(mach_task_self(), cclock); - ts.tv_sec = mts.tv_sec; - ts.tv_nsec = mts.tv_nsec; - - uint32_t sec = timeout / 1000; - uint32_t nsec = (timeout - 1000 * sec) * 1000000; - - ts.tv_sec += sec; - - if (ts.tv_nsec + nsec > 1000000000) - ts.tv_sec++; - - ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; - - /* Get queue lock */ - pthread_mutex_lock(&(queue->mutex)); - while (queue->items == 0) { - ret = pthread_cond_timedwait(&(queue->cond_empty), &(queue->mutex), &ts); - if (ret != 0) { - pthread_mutex_unlock(&(queue->mutex)); - return PTHREAD_QUEUE_EMPTY; - } - } - - /* Coby object to output buffer */ - memcpy(buf, queue->buffer+(queue->out * queue->item_size), queue->item_size); - queue->items--; - queue->out = (queue->out + 1) % queue->size; - pthread_mutex_unlock(&(queue->mutex)); - - /* Nofify blocked threads */ - pthread_cond_broadcast(&(queue->cond_full)); - - return PTHREAD_QUEUE_OK; - -} - -int pthread_queue_items(pthread_queue_t * queue) { - - pthread_mutex_lock(&(queue->mutex)); - int items = queue->items; - pthread_mutex_unlock(&(queue->mutex)); - - return items; - -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_malloc.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_malloc.c deleted file mode 100644 index 95bb8cc7..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_malloc.c +++ /dev/null @@ -1,31 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include - -void * csp_malloc(size_t size) { - return malloc(size); -} - -void csp_free(void *ptr) { - free(ptr); -} - diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_queue.c deleted file mode 100644 index a2fb1b4f..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_queue.c +++ /dev/null @@ -1,64 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include - -/* CSP includes */ -#include - -#include -#include - - -csp_queue_handle_t csp_queue_create(int length, size_t item_size) { - return pthread_queue_create(length, item_size); -} - -void csp_queue_remove(csp_queue_handle_t queue) { - return pthread_queue_delete(queue); -} - -int csp_queue_enqueue(csp_queue_handle_t handle, void *value, uint32_t timeout) { - return pthread_queue_enqueue(handle, value, timeout); -} - -int csp_queue_enqueue_isr(csp_queue_handle_t handle, void * value, CSP_BASE_TYPE * task_woken) { - if (task_woken != NULL) - *task_woken = 0; - return csp_queue_enqueue(handle, value, 0); -} - -int csp_queue_dequeue(csp_queue_handle_t handle, void *buf, uint32_t timeout) { - return pthread_queue_dequeue(handle, buf, timeout); -} - -int csp_queue_dequeue_isr(csp_queue_handle_t handle, void *buf, CSP_BASE_TYPE * task_woken) { - *task_woken = 0; - return csp_queue_dequeue(handle, buf, 0); -} - -int csp_queue_size(csp_queue_handle_t handle) { - return pthread_queue_items(handle); -} - -int csp_queue_size_isr(csp_queue_handle_t handle) { - return pthread_queue_items(handle); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_semaphore.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_semaphore.c deleted file mode 100644 index 6829dec2..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_semaphore.c +++ /dev/null @@ -1,164 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* CSP includes */ -#include - -#include - -int csp_mutex_create(csp_mutex_t * mutex) { - csp_log_lock("Mutex init: %p", mutex); - if (pthread_mutex_init(mutex, NULL) == 0) { - return CSP_SEMAPHORE_OK; - } else { - return CSP_SEMAPHORE_ERROR; - } -} - -int csp_mutex_remove(csp_mutex_t * mutex) { - if (pthread_mutex_destroy(mutex) == 0) { - return CSP_SEMAPHORE_OK; - } else { - return CSP_SEMAPHORE_ERROR; - } -} - -int csp_mutex_lock(csp_mutex_t * mutex, uint32_t timeout) { - - int ret; - struct timespec ts; - uint32_t sec, nsec; - - csp_log_lock("Wait: %p timeout %"PRIu32, mutex, timeout); - - if (timeout == CSP_INFINITY) { - ret = pthread_mutex_lock(mutex); - } else { - if (clock_gettime(CLOCK_REALTIME, &ts)) - return CSP_SEMAPHORE_ERROR; - - sec = timeout / 1000; - nsec = (timeout - 1000 * sec) * 1000000; - - ts.tv_sec += sec; - - if (ts.tv_nsec + nsec >= 1000000000) - ts.tv_sec++; - - ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; - - ret = pthread_mutex_timedlock(mutex, &ts); - } - - if (ret != 0) - return CSP_SEMAPHORE_ERROR; - - return CSP_SEMAPHORE_OK; -} - -int csp_mutex_unlock(csp_mutex_t * mutex) { - if (pthread_mutex_unlock(mutex) == 0) { - return CSP_SEMAPHORE_OK; - } else { - return CSP_SEMAPHORE_ERROR; - } -} - -int csp_bin_sem_create(csp_bin_sem_handle_t * sem) { - csp_log_lock("Semaphore init: %p", sem); - if (sem_init(sem, 0, 1) == 0) { - return CSP_SEMAPHORE_OK; - } else { - return CSP_SEMAPHORE_ERROR; - } -} - -int csp_bin_sem_remove(csp_bin_sem_handle_t * sem) { - if (sem_destroy(sem) == 0) - return CSP_SEMAPHORE_OK; - else - return CSP_SEMAPHORE_ERROR; -} - -int csp_bin_sem_wait(csp_bin_sem_handle_t * sem, uint32_t timeout) { - - int ret; - struct timespec ts; - uint32_t sec, nsec; - - csp_log_lock("Wait: %p timeout %"PRIu32, sem, timeout); - - if (timeout == CSP_INFINITY) { - ret = sem_wait(sem); - } else { - if (clock_gettime(CLOCK_REALTIME, &ts)) - return CSP_SEMAPHORE_ERROR; - - sec = timeout / 1000; - nsec = (timeout - 1000 * sec) * 1000000; - - ts.tv_sec += sec; - - if (ts.tv_nsec + nsec >= 1000000000) - ts.tv_sec++; - - ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; - - ret = sem_timedwait(sem, &ts); - } - - if (ret != 0) - return CSP_SEMAPHORE_ERROR; - - return CSP_SEMAPHORE_OK; -} - -int csp_bin_sem_post(csp_bin_sem_handle_t * sem) { - CSP_BASE_TYPE dummy = 0; - return csp_bin_sem_post_isr(sem, &dummy); -} - -int csp_bin_sem_post_isr(csp_bin_sem_handle_t * sem, CSP_BASE_TYPE * task_woken) { - csp_log_lock("Post: %p", sem); - *task_woken = 0; - - int value; - sem_getvalue(sem, &value); - if (value > 0) - return CSP_SEMAPHORE_OK; - - if (sem_post(sem) == 0) { - return CSP_SEMAPHORE_OK; - } else { - return CSP_SEMAPHORE_ERROR; - } -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_system.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_system.c deleted file mode 100644 index 6c882c7c..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_system.c +++ /dev/null @@ -1,131 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -int csp_sys_tasklist(char * out) { - strcpy(out, "Tasklist not available on POSIX"); - return CSP_ERR_NONE; -} - -int csp_sys_tasklist_size(void) { - return 100; -} - -uint32_t csp_sys_memfree(void) { - uint32_t total = 0; - struct sysinfo info; - sysinfo(&info); - total = info.freeram * info.mem_unit; - return total; -} - -int csp_sys_reboot(void) { -#ifdef CSP_USE_INIT_SHUTDOWN - /* Let init(1) handle the reboot */ - int ret = system("reboot"); - (void) ret; /* Silence warning */ -#else - int magic = LINUX_REBOOT_CMD_RESTART; - - /* Sync filesystem before reboot */ - sync(); - reboot(magic); -#endif - - /* If reboot(2) returns, it is an error */ - csp_log_error("Failed to reboot: %s", strerror(errno)); - - return CSP_ERR_INVAL; -} - -int csp_sys_shutdown(void) { -#ifdef CSP_USE_INIT_SHUTDOWN - /* Let init(1) handle the shutdown */ - int ret = system("halt"); - (void) ret; /* Silence warning */ -#else - int magic = LINUX_REBOOT_CMD_HALT; - - /* Sync filesystem before reboot */ - sync(); - reboot(magic); -#endif - - /* If reboot(2) returns, it is an error */ - csp_log_error("Failed to shutdown: %s", strerror(errno)); - - return CSP_ERR_INVAL; -} - -void csp_sys_set_color(csp_color_t color) { - - unsigned int color_code, modifier_code; - switch (color & COLOR_MASK_COLOR) { - case COLOR_BLACK: - color_code = 30; break; - case COLOR_RED: - color_code = 31; break; - case COLOR_GREEN: - color_code = 32; break; - case COLOR_YELLOW: - color_code = 33; break; - case COLOR_BLUE: - color_code = 34; break; - case COLOR_MAGENTA: - color_code = 35; break; - case COLOR_CYAN: - color_code = 36; break; - case COLOR_WHITE: - color_code = 37; break; - case COLOR_RESET: - default: - color_code = 0; break; - } - - switch (color & COLOR_MASK_MODIFIER) { - case COLOR_BOLD: - modifier_code = 1; break; - case COLOR_UNDERLINE: - modifier_code = 2; break; - case COLOR_BLINK: - modifier_code = 3; break; - case COLOR_HIDE: - modifier_code = 4; break; - case COLOR_NORMAL: - default: - modifier_code = 0; break; - } - - printf("\033[%u;%um", modifier_code, color_code); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_thread.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_thread.c deleted file mode 100644 index 3277d35d..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_thread.c +++ /dev/null @@ -1,55 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include - -/* CSP includes */ -#include - -#include - -int csp_thread_create(csp_thread_return_t (* routine)(void *), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle) { - pthread_attr_t attributes, *attr_ref; - int return_code; - - if( pthread_attr_init(&attributes) == 0 ) - { - unsigned int stack_size = PTHREAD_STACK_MIN;// use at least one memory page - - while(stack_size < stack_depth)// must reach at least the provided size - { - stack_size += PTHREAD_STACK_MIN;// keep memory page boundary (some systems may fail otherwise)) - } - attr_ref = &attributes; - - pthread_attr_setdetachstate(attr_ref, PTHREAD_CREATE_DETACHED);// do not waste memory on each call - pthread_attr_setstacksize(attr_ref, stack_size); - } - else - { - attr_ref = NULL; - } - return_code = pthread_create(handle, attr_ref, routine, parameters); - if( attr_ref != NULL ) pthread_attr_destroy(attr_ref); - - return return_code; -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_time.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_time.c deleted file mode 100644 index c9677443..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/posix/csp_time.c +++ /dev/null @@ -1,54 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include - -/* CSP includes */ -#include - -#include - -uint32_t csp_get_ms(void) { - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) - return (uint32_t)(ts.tv_sec*1000+ts.tv_nsec/1000000); - else - return 0; -} - -uint32_t csp_get_ms_isr(void) { - return csp_get_ms(); -} - -uint32_t csp_get_s(void) { - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) - return (uint32_t)ts.tv_sec; - else - return 0; -} - -uint32_t csp_get_s_isr(void) { - return csp_get_s(); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/posix/pthread_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/posix/pthread_queue.c deleted file mode 100644 index e8b6d4ab..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/posix/pthread_queue.c +++ /dev/null @@ -1,243 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* -Inspired by c-pthread-queue by Matthew Dickinson -http://code.google.com/p/c-pthread-queue/ -*/ - -#include -#include -#include -#include -#include -#include -#include - -/* CSP includes */ -#include - -static inline int get_deadline(struct timespec *ts, uint32_t timeout_ms) -{ - int ret = clock_gettime(CLOCK_MONOTONIC, ts); - - if (ret < 0) { - return ret; - } - - uint32_t sec = timeout_ms / 1000; - uint32_t nsec = (timeout_ms - 1000 * sec) * 1000000; - - ts->tv_sec += sec; - - if (ts->tv_nsec + nsec >= 1000000000) { - ts->tv_sec++; - } - - ts->tv_nsec = (ts->tv_nsec + nsec) % 1000000000; - - return ret; -} - -static inline int init_cond_clock_monotonic(pthread_cond_t * cond) -{ - - int ret; - pthread_condattr_t attr; - - pthread_condattr_init(&attr); - ret = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); - - if (ret == 0) { - ret = pthread_cond_init(cond, &attr); - } - - pthread_condattr_destroy(&attr); - return ret; - -} - -pthread_queue_t * pthread_queue_create(int length, size_t item_size) { - - pthread_queue_t * q = malloc(sizeof(pthread_queue_t)); - - if (q != NULL) { - q->buffer = malloc(length*item_size); - if (q->buffer != NULL) { - q->size = length; - q->item_size = item_size; - q->items = 0; - q->in = 0; - q->out = 0; - if (pthread_mutex_init(&(q->mutex), NULL) || init_cond_clock_monotonic(&(q->cond_full)) || init_cond_clock_monotonic(&(q->cond_empty))) { - free(q->buffer); - free(q); - q = NULL; - } - } else { - free(q); - q = NULL; - } - } - - return q; - -} - -void pthread_queue_delete(pthread_queue_t * q) { - - if (q == NULL) - return; - - free(q->buffer); - free(q); - - return; - -} - - -static inline int wait_slot_available(pthread_queue_t * queue, struct timespec *ts) { - - int ret; - - while (queue->items == queue->size) { - - if (ts != NULL) { - ret = pthread_cond_timedwait(&(queue->cond_full), &(queue->mutex), ts); - } else { - ret = pthread_cond_wait(&(queue->cond_full), &(queue->mutex)); - } - - if (ret != 0 && errno != EINTR) { - return PTHREAD_QUEUE_FULL; //Timeout - } - } - - return PTHREAD_QUEUE_OK; - -} - -int pthread_queue_enqueue(pthread_queue_t * queue, void * value, uint32_t timeout) { - - int ret; - struct timespec ts; - struct timespec *pts = NULL; - - /* Calculate timeout */ - if (timeout != CSP_MAX_DELAY) { - if (get_deadline(&ts, timeout) != 0) { - return PTHREAD_QUEUE_ERROR; - } - pts = &ts; - } else { - pts = NULL; - } - - /* Get queue lock */ - pthread_mutex_lock(&(queue->mutex)); - - ret = wait_slot_available(queue, pts); - if (ret == PTHREAD_QUEUE_OK) { - /* Copy object from input buffer */ - memcpy(queue->buffer+(queue->in * queue->item_size), value, queue->item_size); - queue->items++; - queue->in = (queue->in + 1) % queue->size; - } - - pthread_mutex_unlock(&(queue->mutex)); - - if (ret == PTHREAD_QUEUE_OK) { - /* Nofify blocked threads */ - pthread_cond_broadcast(&(queue->cond_empty)); - } - - return ret; - -} - -static inline int wait_item_available(pthread_queue_t * queue, struct timespec *ts) { - - int ret; - - while (queue->items == 0) { - - if (ts != NULL) { - ret = pthread_cond_timedwait(&(queue->cond_empty), &(queue->mutex), ts); - } else { - ret = pthread_cond_wait(&(queue->cond_empty), &(queue->mutex)); - } - - if (ret != 0 && errno != EINTR) { - return PTHREAD_QUEUE_EMPTY; //Timeout - } - } - - return PTHREAD_QUEUE_OK; - -} - -int pthread_queue_dequeue(pthread_queue_t * queue, void * buf, uint32_t timeout) { - - int ret; - struct timespec ts; - struct timespec *pts; - - /* Calculate timeout */ - if (timeout != CSP_MAX_DELAY) { - if (get_deadline(&ts, timeout) != 0) { - return PTHREAD_QUEUE_ERROR; - } - pts = &ts; - } else { - pts = NULL; - } - - /* Get queue lock */ - pthread_mutex_lock(&(queue->mutex)); - - ret = wait_item_available(queue, pts); - if (ret == PTHREAD_QUEUE_OK) { - /* Coby object to output buffer */ - memcpy(buf, queue->buffer+(queue->out * queue->item_size), queue->item_size); - queue->items--; - queue->out = (queue->out + 1) % queue->size; - } - - pthread_mutex_unlock(&(queue->mutex)); - - if (ret == PTHREAD_QUEUE_OK) { - /* Nofify blocked threads */ - pthread_cond_broadcast(&(queue->cond_full)); - } - - return ret; - -} - -int pthread_queue_items(pthread_queue_t * queue) { - - pthread_mutex_lock(&(queue->mutex)); - int items = queue->items; - pthread_mutex_unlock(&(queue->mutex)); - - return items; - -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/README b/gomspace/libgscsp/lib/libcsp/src/arch/windows/README deleted file mode 100644 index b97ce7f5..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/windows/README +++ /dev/null @@ -1,18 +0,0 @@ -This directory contains files specific to the windows port of libcsp. - -To compile and create a static library, execute: - - python waf configure --with-os=windows build - -from the root of this project. Note python must be in PATH. - -The build requirements are: - * Windows Vista SP1 - * A recent version of MinGW _or_ MinGW-w64 - * Windows API headers - * cPython 2.5 or newer - -What provides the Windows API headers depends on the development environment: -Using MinGW: Headers provided by w32api package. windows_glue.h header is needed because these headers do not declare condition variables. -Using MinGW-w64: Headers should be available in the default configuration. You may have to compile the distribution from source. windows_glue.h should not be needed. - diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_malloc.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_malloc.c deleted file mode 100644 index 4b301e49..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_malloc.c +++ /dev/null @@ -1,9 +0,0 @@ -#include - -void * csp_malloc(size_t size) { - return malloc(size); -} - -void csp_free(void * ptr) { - free(ptr); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_queue.c deleted file mode 100644 index 177f8fa9..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_queue.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include -#include -#include "windows_queue.h" - -csp_queue_handle_t csp_queue_create(int length, size_t item_size) { - return windows_queue_create(length, item_size); -} - -void csp_queue_remove(csp_queue_handle_t queue) { - windows_queue_delete(queue); -} - -int csp_queue_enqueue(csp_queue_handle_t handle, void *value, uint32_t timeout) { - return windows_queue_enqueue(handle, value, timeout); -} - -int csp_queue_enqueue_isr(csp_queue_handle_t handle, void * value, CSP_BASE_TYPE * task_woken) { - if( task_woken != NULL ) - *task_woken = 0; - return windows_queue_enqueue(handle, value, 0); -} - -int csp_queue_dequeue(csp_queue_handle_t handle, void *buf, uint32_t timeout) { - return windows_queue_dequeue(handle, buf, timeout); -} - -int csp_queue_dequeue_isr(csp_queue_handle_t handle, void * buf, CSP_BASE_TYPE * task_woken) { - if( task_woken != NULL ) - *task_woken = 0; - return windows_queue_dequeue(handle, buf, 0); -} - -int csp_queue_size(csp_queue_handle_t handle) { - return windows_queue_items(handle); -} - -int csp_queue_size_isr(csp_queue_handle_t handle) { - return windows_queue_items(handle); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_semaphore.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_semaphore.c deleted file mode 100644 index aa69251e..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_semaphore.c +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include -#include - -int csp_mutex_create(csp_mutex_t * mutex) { - HANDLE mutexHandle = CreateMutex(NULL, FALSE, FALSE); - if( mutexHandle == NULL ) { - return CSP_MUTEX_ERROR; - } - *mutex = mutexHandle; - return CSP_MUTEX_OK; -} - -int csp_mutex_remove(csp_mutex_t * mutex) { - if( !CloseHandle(*mutex) ) { - return CSP_MUTEX_ERROR; - } - return CSP_MUTEX_OK; -} - -int csp_mutex_lock(csp_mutex_t * mutex, uint32_t timeout) { - if(WaitForSingleObject(*mutex, timeout) == WAIT_OBJECT_0) { - return CSP_MUTEX_OK; - } - return CSP_MUTEX_ERROR; - -} - -int csp_mutex_unlock(csp_mutex_t * mutex) { - if( !ReleaseMutex(*mutex) ) { - return CSP_MUTEX_ERROR; - } - return CSP_MUTEX_OK; -} - -int csp_bin_sem_create(csp_bin_sem_handle_t * sem) { - HANDLE semHandle = CreateSemaphore(NULL, 1, 1, NULL); - if( semHandle == NULL ) { - return CSP_SEMAPHORE_ERROR; - } - *sem = semHandle; - return CSP_SEMAPHORE_OK; -} - -int csp_bin_sem_remove(csp_bin_sem_handle_t * sem) { - if( !CloseHandle(*sem) ) { - return CSP_SEMAPHORE_ERROR; - } - return CSP_SEMAPHORE_OK; -} - -int csp_bin_sem_wait(csp_bin_sem_handle_t * sem, uint32_t timeout) { - if( WaitForSingleObject(*sem, timeout) == WAIT_OBJECT_0 ) { - return CSP_SEMAPHORE_OK; - } - return CSP_SEMAPHORE_ERROR; - -} - -int csp_bin_sem_post(csp_bin_sem_handle_t * sem) { - if( !ReleaseSemaphore(*sem, 1, NULL) ) { - return CSP_SEMAPHORE_ERROR; - } - return CSP_SEMAPHORE_OK; -} - -int csp_bin_sem_post_isr(csp_bin_sem_handle_t * sem, CSP_BASE_TYPE * task_woken) { - if( task_woken != NULL ) { - *task_woken = 0; - } - return csp_bin_sem_post(sem); -} - - diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_system.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_system.c deleted file mode 100644 index 262c2052..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_system.c +++ /dev/null @@ -1,60 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include - -#include -#include - -#include - -int csp_sys_tasklist(char * out) { - strcpy(out, "Tasklist not available on Windows"); - return CSP_ERR_NONE; -} - -uint32_t csp_sys_memfree(void) { - MEMORYSTATUSEX statex; - statex.dwLength = sizeof(statex); - GlobalMemoryStatusEx(&statex); - DWORDLONG freePhysicalMem = statex.ullAvailPhys; - size_t total = (size_t) freePhysicalMem; - return (uint32_t)total; -} - -int csp_sys_reboot(void) { - /* TODO: Fix reboot on Windows */ - csp_log_error("Failed to reboot"); - - return CSP_ERR_INVAL; -} - -int csp_sys_shutdown(void) { - /* TODO: Fix shutdown on Windows */ - csp_log_error("Failed to shutdown"); - - return CSP_ERR_INVAL; -} - -void csp_sys_set_color(csp_color_t color) { - /* TODO: Add Windows color output here */ -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_thread.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_thread.c deleted file mode 100644 index ef46a948..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_thread.c +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include -#include - -int csp_thread_create(csp_thread_return_t (* routine)(void *)__attribute__((stdcall)), const char * const thread_name, unsigned short stack_depth, void * parameters, unsigned int priority, csp_thread_handle_t * handle) { - HANDLE taskHandle = (HANDLE) _beginthreadex(NULL, stack_depth, routine, parameters, 0, 0); - if( taskHandle == 0 ) - return CSP_ERR_NOMEM; // Failure - *handle = taskHandle; - return CSP_ERR_NONE; -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_time.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_time.c deleted file mode 100644 index 618292ab..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/windows/csp_time.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -#include - -uint32_t csp_get_ms(void) { - return (uint32_t)GetTickCount(); -} - -uint32_t csp_get_ms_isr(void) { - return csp_get_ms(); -} - -uint32_t csp_get_s(void) { - uint32_t time_ms = csp_get_ms(); - return time_ms/1000; -} - -uint32_t csp_get_s_isr(void) { - return csp_get_s(); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_glue.h b/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_glue.h deleted file mode 100644 index 6e0cf6db..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_glue.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef WINDOWS_GLUE_H -#define WINDOWS_GLUE_H - -#include -#undef interface - -#if (_WIN32_WINNT >= 0x0600) - -#define RTL_CONDITION_VARIABLE_INIT 0 -#define RTL_CONDITION_VARIABLE_LOCKMODE_SHARED 1 -#define CONDITION_VARIABLE_INIT RTL_CONDITION_VARIABLE_INIT -#define CONDITION_VARIABLE_LOCKMODE_SHARED RTL_CONDITION_VARIABLE_LOCKMODE_SHARED - -typedef PVOID RTL_CONDITION_VARIABLE; -typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE; - -WINBASEAPI VOID WINAPI InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable); -WINBASEAPI WINBOOL WINAPI SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable, PCRITICAL_SECTION CriticalSection, DWORD dwMilliseconds); -WINBASEAPI VOID WINAPI WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable); -WINBASEAPI VOID WINAPI WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable); - -#endif // _WIN#"_WINNT -#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.c b/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.c deleted file mode 100644 index aa337dc8..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.c +++ /dev/null @@ -1,91 +0,0 @@ -#include "windows_queue.h" -#include "windows_glue.h" -#include - -static int queueFull(windows_queue_t * queue) { - return queue->items == queue->size; -} - -static int queueEmpty(windows_queue_t * queue) { - return queue->items == 0; -} - -windows_queue_t * windows_queue_create(int length, size_t item_size) { - windows_queue_t *queue = (windows_queue_t*)malloc(sizeof(windows_queue_t)); - if(queue == NULL) - goto queue_malloc_failed; - - queue->buffer = malloc(length*item_size); - if(queue->buffer == NULL) - goto buffer_malloc_failed; - - queue->size = length; - queue->item_size = item_size; - queue->items = 0; - queue->head_idx = 0; - - InitializeCriticalSection(&(queue->mutex)); - InitializeConditionVariable(&(queue->cond_full)); - InitializeConditionVariable(&(queue->cond_empty)); - goto queue_init_success; - -buffer_malloc_failed: - free(queue); - queue = NULL; -queue_malloc_failed: -queue_init_success: - return queue; -} - -void windows_queue_delete(windows_queue_t * q) { - if(q==NULL) return; - DeleteCriticalSection(&(q->mutex)); - free(q->buffer); - free(q); -} - -int windows_queue_enqueue(windows_queue_t * queue, void * value, int timeout) { - int offset; - EnterCriticalSection(&(queue->mutex)); - while(queueFull(queue)) { - int ret = SleepConditionVariableCS(&(queue->cond_full), &(queue->mutex), timeout); - if( !ret ) { - LeaveCriticalSection(&(queue->mutex)); - return ret == WAIT_TIMEOUT ? WINDOWS_QUEUE_FULL : WINDOWS_QUEUE_ERROR; - } - } - offset = ((queue->head_idx+queue->items) % queue->size) * queue->item_size; - memcpy((unsigned char*)queue->buffer + offset, value, queue->item_size); - queue->items++; - - LeaveCriticalSection(&(queue->mutex)); - WakeAllConditionVariable(&(queue->cond_empty)); - return WINDOWS_QUEUE_OK; -} - -int windows_queue_dequeue(windows_queue_t * queue, void * buf, int timeout) { - EnterCriticalSection(&(queue->mutex)); - while(queueEmpty(queue)) { - int ret = SleepConditionVariableCS(&(queue->cond_empty), &(queue->mutex), timeout); - if( !ret ) { - LeaveCriticalSection(&(queue->mutex)); - return ret == WAIT_TIMEOUT ? WINDOWS_QUEUE_EMPTY : WINDOWS_QUEUE_ERROR; - } - } - memcpy(buf, (unsigned char*)queue->buffer+(queue->head_idx%queue->size*queue->item_size), queue->item_size); - queue->items--; - queue->head_idx = (queue->head_idx + 1) % queue->size; - - LeaveCriticalSection(&(queue->mutex)); - WakeAllConditionVariable(&(queue->cond_full)); - return WINDOWS_QUEUE_OK; -} - -int windows_queue_items(windows_queue_t * queue) { - int items; - EnterCriticalSection(&(queue->mutex)); - items = queue->items; - LeaveCriticalSection(&(queue->mutex)); - - return items; -} diff --git a/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.h b/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.h deleted file mode 100644 index e6bc5423..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/arch/windows/windows_queue.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _WINDOWS_QUEUE_H_ -#define _WINDOWS_QUEUE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include "windows_glue.h" -#undef interface - -#include - -#define WINDOWS_QUEUE_ERROR CSP_QUEUE_ERROR -#define WINDOWS_QUEUE_EMPTY CSP_QUEUE_ERROR -#define WINDOWS_QUEUE_FULL CSP_QUEUE_ERROR -#define WINDOWS_QUEUE_OK CSP_QUEUE_OK - -typedef struct windows_queue_s { - void * buffer; - int size; - int item_size; - int items; - int head_idx; - CRITICAL_SECTION mutex; - CONDITION_VARIABLE cond_full; - CONDITION_VARIABLE cond_empty; -} windows_queue_t; - -windows_queue_t * windows_queue_create(int length, size_t item_size); -void windows_queue_delete(windows_queue_t * q); -int windows_queue_enqueue(windows_queue_t * queue, void * value, int timeout); -int windows_queue_dequeue(windows_queue_t * queue, void * buf, int timeout); -int windows_queue_items(windows_queue_t * queue); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _WINDOWS_QUEUE_H_ - diff --git a/gomspace/libgscsp/lib/libcsp/src/bindings/python/pycsp.c b/gomspace/libgscsp/lib/libcsp/src/bindings/python/pycsp.c deleted file mode 100644 index f1009d1a..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/bindings/python/pycsp.c +++ /dev/null @@ -1,1052 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if PY_MAJOR_VERSION == 3 -#define IS_PY3 -#endif - -static int is_capsule_of_type(PyObject* capsule, const char* expected_type) { - const char* capsule_name = PyCapsule_GetName(capsule); - if (strcmp(capsule_name, expected_type) != 0) { - PyErr_Format( - PyExc_TypeError, - "capsule contains unexpected type, expected=%s, got=%s", - expected_type, capsule_name); // TypeError is thrown - return 0; - } - return 1; -} - -/** - * csp/csp.h - */ - -/* - * void csp_service_handler(csp_conn_t *conn, csp_packet_t *packet); - */ -static PyObject* pycsp_service_handler(PyObject *self, PyObject *args) { - PyObject* conn_capsule; - PyObject* packet_capsule; - if (!PyArg_ParseTuple(args, "OO", &conn_capsule, &packet_capsule)) { - return NULL; // TypeError is thrown - } - - if (!is_capsule_of_type(conn_capsule, "csp_conn_t") || - !is_capsule_of_type(packet_capsule, "csp_packet_t")) { - return NULL; // TypeError is thrown - } - - csp_service_handler( - (csp_conn_t*)PyCapsule_GetPointer(conn_capsule, "csp_conn_t"), - (csp_packet_t*)PyCapsule_GetPointer(packet_capsule, "csp_packet_t")); - - Py_RETURN_NONE; -} - -/* - * int csp_init(uint8_t my_node_address); - */ -static PyObject* pycsp_init(PyObject *self, PyObject *args) { - uint8_t my_node_address; - if (!PyArg_ParseTuple(args, "b", &my_node_address)) { - return NULL; // TypeError is thrown - } - - return Py_BuildValue("i", csp_init(my_node_address)); -} - -/* - * void csp_set_hostname(const char *hostname); - */ -static PyObject* pycsp_set_hostname(PyObject *self, PyObject *args) { - char* hostname; - if (!PyArg_ParseTuple(args, "s", &hostname)) { - return NULL; // TypeError is thrown - } - - csp_set_hostname(hostname); - Py_RETURN_NONE; -} - -/* - * const char *csp_get_hostname(void); - */ -static PyObject* pycsp_get_hostname(PyObject *self, PyObject *args) { - return Py_BuildValue("s", csp_get_hostname()); -} - -/* - * void csp_set_model(const char *model); - */ -static PyObject* pycsp_set_model(PyObject *self, PyObject *args) { - char* model; - if (!PyArg_ParseTuple(args, "s", &model)) { - return NULL; // TypeError is thrown - } - - csp_set_model(model); - Py_RETURN_NONE; -} - -/* - * const char *csp_get_model(void); - */ -static PyObject* pycsp_get_model(PyObject *self, PyObject *args) { - return Py_BuildValue("s", csp_get_model()); -} - -/* - * void csp_set_revision(const char *revision); - */ -static PyObject* pycsp_set_revision(PyObject *self, PyObject *args) { - char* revision; - if (!PyArg_ParseTuple(args, "s", &revision)) { - return NULL; // TypeError is thrown - } - - csp_set_revision(revision); - Py_RETURN_NONE; -} - -/* - * const char *csp_get_revision(void); - */ -static PyObject* pycsp_get_revision(PyObject *self, PyObject *args) { - return Py_BuildValue("s", csp_get_revision()); -} - -/* - * csp_socket_t *csp_socket(uint32_t opts); - */ -static PyObject* pycsp_socket(PyObject *self, PyObject *args) { - uint32_t opts = CSP_SO_NONE; - if (!PyArg_ParseTuple(args, "|I", &opts)) { - return NULL; // TypeError is thrown - } - - return PyCapsule_New(csp_socket(opts), "csp_socket_t", NULL); -} - -/* - * csp_conn_t *csp_accept(csp_socket_t *socket, uint32_t timeout); - */ -static PyObject* pycsp_accept(PyObject *self, PyObject *args) { - PyObject* socket_capsule; - uint32_t timeout = 500; - if (!PyArg_ParseTuple(args, "O|I", &socket_capsule, &timeout)) { - return NULL; // TypeError is thrown - } - - if (!is_capsule_of_type(socket_capsule, "csp_socket_t")) { - return NULL; // TypeError is thrown - } - - void* socket = PyCapsule_GetPointer(socket_capsule, "csp_socket_t"); - csp_conn_t* conn = csp_accept((csp_socket_t*)socket, timeout); - if (conn == NULL) { - Py_RETURN_NONE; // because a capsule cannot contain a NULL-pointer - } - - return PyCapsule_New(conn, "csp_conn_t", NULL); -} - -/* - * csp_packet_t *csp_read(csp_conn_t *conn, uint32_t timeout); - */ -static PyObject* pycsp_read(PyObject *self, PyObject *args) { - PyObject* conn_capsule; - uint32_t timeout = 500; - if (!PyArg_ParseTuple(args, "O|I", &conn_capsule, &timeout)) { - return NULL; // TypeError is thrown - } - - if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { - return NULL; // TypeError is thrown - } - - void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); - csp_packet_t* packet = csp_read((csp_conn_t*)conn, timeout); - if (packet == NULL) { - Py_RETURN_NONE; // because capsule cannot contain a NULL-pointer - } - - return PyCapsule_New(packet, "csp_packet_t", NULL); -} - -/* -* int csp_send(csp_conn_t * conn, csp_packet_t * packet, uint32_t timeout) -*/ -static PyObject* pycsp_send(PyObject *self, PyObject *args) { - PyObject* conn_capsule; - PyObject* packet_capsule; - uint32_t timeout = 500; - if (!PyArg_ParseTuple(args, "OO|I", &conn_capsule, &packet_capsule, &timeout)) { - return NULL; // TypeError is thrown - } - - if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { - return NULL; // TypeError is thrown - } - - void* packet = PyCapsule_GetPointer(packet_capsule, "csp_packet_t"); - if (packet == NULL) { - Py_RETURN_NONE; - } - - void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); - - int result = csp_send(conn, packet, timeout); - - return Py_BuildValue("i", result); -} - -/* - * int csp_transaction(uint8_t prio, uint8_t dest, uint8_t port, - * uint32_t timeout, void *outbuf, int outlen, - * void *inbuf, int inlen); - */ -static PyObject* pycsp_transaction(PyObject *self, PyObject *args) { - uint8_t prio; - uint8_t dest; - uint8_t port; - uint32_t timeout; - Py_buffer inbuf; - Py_buffer outbuf; - if (!PyArg_ParseTuple(args, "bbbIw*w*", &prio, &dest, &port, &timeout, &outbuf, &inbuf)) { - return NULL; // TypeError is thrown - } - - int result = csp_transaction(prio, dest, port, timeout, - outbuf.buf, outbuf.len, - inbuf.buf, inbuf.len); - - return Py_BuildValue("i", result); -} - -/* int csp_sendto(uint8_t prio, uint8_t dest, uint8_t dport, uint8_t src_port, uint32_t opts, csp_packet_t *packet, uint32_t timeout); */ -static PyObject* pycsp_sendto(PyObject *self, PyObject *args) { - uint8_t prio; - uint8_t dest; - uint8_t dport; - uint8_t src_port; - uint32_t opts; - PyObject* packet_capsule; - uint32_t timeout; - if (!PyArg_ParseTuple(args, "bbbbIOI", &prio, &dest, &dport, &src_port, &opts, &packet_capsule, &timeout)) { - Py_RETURN_NONE; - } - - void* packet = PyCapsule_GetPointer(packet_capsule, "csp_packet_t"); - if (packet == NULL) { - Py_RETURN_NONE; - } - - return Py_BuildValue("i", csp_sendto(prio, - dest, - dport, - src_port, - opts, - (csp_packet_t*)packet, - timeout)); -} - - -/* - * int csp_sendto_reply(csp_packet_t * request_packet, - * csp_packet_t * reply_packet, - * uint32_t opts, uint32_t timeout); - */ -static PyObject* pycsp_sendto_reply(PyObject *self, PyObject *args) { - PyObject* request_packet_capsule; - PyObject* reply_packet_capsule; - uint32_t opts = CSP_O_NONE; - uint32_t timeout = 500; - if (!PyArg_ParseTuple(args, "OO|II", &request_packet_capsule, &reply_packet_capsule, &opts, &timeout)) { - return NULL; // TypeError is thrown - } - - if (!is_capsule_of_type(request_packet_capsule, "csp_packet_t") || - !is_capsule_of_type(reply_packet_capsule, "csp_packet_t")) { - return NULL; // TypeError is thrown - } - - void* request_packet = PyCapsule_GetPointer(request_packet_capsule, "csp_packet_t"); - void* reply_packet = PyCapsule_GetPointer(reply_packet_capsule, "csp_packet_t"); - - return Py_BuildValue("i", csp_sendto_reply((csp_packet_t*)request_packet, - (csp_packet_t*)reply_packet, - opts, - timeout)); -} - -/* - * csp_conn_t *csp_connect(uint8_t prio, uint8_t dest, uint8_t dport, uint32_t timeout, uint32_t opts); - */ -static PyObject* pycsp_connect(PyObject *self, PyObject *args) { - uint8_t prio; - uint8_t dest; - uint8_t dport; - uint32_t timeout; - uint32_t opts; - if (!PyArg_ParseTuple(args, "bbbII", &prio, &dest, &dport, &timeout, &opts)) { - return NULL; // TypeError is thrown - } - - csp_conn_t *conn = csp_connect(prio, dest, dport, timeout,opts); - - return PyCapsule_New(conn, "csp_conn_t", NULL); -} - -/* - * int csp_close(csp_conn_t *conn); - */ -static PyObject* pycsp_close(PyObject *self, PyObject *conn_capsule) { - if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { - return NULL; // TypeError is thrown - } - - void *conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); - return Py_BuildValue("i", csp_close((csp_conn_t*)conn)); -} - -/* - * int csp_conn_dport(csp_conn_t *conn); - */ -static PyObject* pycsp_conn_dport(PyObject *self, PyObject *conn_capsule) { - if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { - return NULL; // TypeError is thrown - } - - void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); - return Py_BuildValue("i", csp_conn_dport((csp_conn_t*)conn)); -} - -/* - * int csp_conn_sport(csp_conn_t *conn); - */ -static PyObject* pycsp_conn_sport(PyObject *self, PyObject *conn_capsule) { - if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { - return NULL; // TypeError is thrown - } - - void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); - return Py_BuildValue("i", csp_conn_sport((csp_conn_t*)conn)); -} - -/* int csp_conn_dst(csp_conn_t *conn); */ -static PyObject* pycsp_conn_dst(PyObject *self, PyObject *conn_capsule) { - if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { - return NULL; // TypeError is thrown - } - - void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); - return Py_BuildValue("i", csp_conn_dst((csp_conn_t*)conn)); -} - -/* - * int csp_conn_src(csp_conn_t *conn); - */ -static PyObject* pycsp_conn_src(PyObject *self, PyObject *conn_capsule) { - if (!is_capsule_of_type(conn_capsule, "csp_conn_t")) { - return NULL; // TypeError is thrown - } - - void* conn = PyCapsule_GetPointer(conn_capsule, "csp_conn_t"); - return Py_BuildValue("i", csp_conn_src((csp_conn_t*)conn)); -} - -/* int csp_listen(csp_socket_t *socket, size_t conn_queue_length); */ -static PyObject* pycsp_listen(PyObject *self, PyObject *args) { - PyObject* socket_capsule; - size_t conn_queue_len = 10; - if (!PyArg_ParseTuple(args, "O|n", &socket_capsule, &conn_queue_len)) { - return NULL; // TypeError is thrown - } - - if (!is_capsule_of_type(socket_capsule, "csp_socket_t")) { - return NULL; // TypeError is thrown - } - - void* sock = PyCapsule_GetPointer(socket_capsule, "csp_socket_t"); - return Py_BuildValue("i", csp_listen((csp_socket_t*)sock, conn_queue_len)); -} - -/* int csp_bind(csp_socket_t *socket, uint8_t port); */ -static PyObject* pycsp_bind(PyObject *self, PyObject *args) { - PyObject* socket_capsule; - uint8_t port; - if (!PyArg_ParseTuple(args, "Ob", &socket_capsule, &port)) { - return NULL; // TypeError is thrown - } - - if (!is_capsule_of_type(socket_capsule, "csp_socket_t")) { - return NULL; // TypeError is thrown - } - - void* sock = PyCapsule_GetPointer(socket_capsule, "csp_socket_t"); - return Py_BuildValue("i", csp_bind((csp_socket_t*)sock, port)); -} - -/* int csp_route_start_task(unsigned int task_stack_size, unsigned int priority); */ -static PyObject* pycsp_route_start_task(PyObject *self, PyObject *args) { - unsigned int priority = CSP_PRIO_NORM; - if (!PyArg_ParseTuple(args, "|I", &priority)) { - return NULL; // TypeError is thrown - } - - return Py_BuildValue("i", csp_route_start_task(0, priority)); -} - -/* - * int csp_ping(uint8_t node, uint32_t timeout, - * unsigned int size, uint8_t conn_options); - */ -static PyObject* pycsp_ping(PyObject *self, PyObject *args) { - uint8_t node; - uint32_t timeout = 500; - unsigned int size = 100; - uint8_t conn_options = CSP_O_NONE; - if (!PyArg_ParseTuple(args, "b|IIb", &node, &timeout, &size, &conn_options)) { - return NULL; // TypeError is thrown - } - - return Py_BuildValue("i", csp_ping(node, timeout, size, conn_options)); -} - -/* - * void csp_reboot(uint8_t node); - */ -static PyObject* pycsp_reboot(PyObject *self, PyObject *args) { - uint8_t node; - if (!PyArg_ParseTuple(args, "b", &node)) { - return NULL; // TypeError is thrown - } - - csp_reboot(node); - Py_RETURN_NONE; -} - -/* - * void csp_shutdown(uint8_t node); - */ -static PyObject* pycsp_shutdown(PyObject *self, PyObject *args) { - uint8_t node; - if (!PyArg_ParseTuple(args, "b", &node)) { - return NULL; // TypeError is thrown - } - - csp_shutdown(node); - Py_RETURN_NONE; -} - -/* - * void csp_rdp_set_opt(unsigned int window_size, - * unsigned int conn_timeout_ms, - * unsigned int packet_timeout_ms, - * unsigned int delayed_acks, - * unsigned int ack_timeout, - * unsigned int ack_delay_count); - */ -static PyObject* pycsp_rdp_set_opt(PyObject *self, PyObject *args) { - unsigned int window_size; - unsigned int conn_timeout_ms; - unsigned int packet_timeout_ms; - unsigned int delayed_acks; - unsigned int ack_timeout; - unsigned int ack_delay_count; - if (!PyArg_ParseTuple(args, "IIIIII", &window_size, &conn_timeout_ms, - &packet_timeout_ms, &delayed_acks, - &ack_timeout, &ack_delay_count)) { - return NULL; // TypeError is thrown - } -#ifdef CSP_USE_RDP - csp_rdp_set_opt(window_size, conn_timeout_ms, packet_timeout_ms, - delayed_acks, ack_timeout, ack_delay_count); -#endif - Py_RETURN_NONE; -} - -/* - * void csp_rdp_get_opt(unsigned int *window_size, - * unsigned int *conn_timeout_ms, - * unsigned int *packet_timeout_ms, - * unsigned int *delayed_acks, - * unsigned int *ack_timeout, - * unsigned int *ack_delay_count); - */ -static PyObject* pycsp_rdp_get_opt(PyObject *self, PyObject *args) { - - unsigned int window_size = 0; - unsigned int conn_timeout_ms = 0; - unsigned int packet_timeout_ms = 0; - unsigned int delayed_acks = 0; - unsigned int ack_timeout = 0; - unsigned int ack_delay_count = 0; -#ifdef CSP_USE_RDP - csp_rdp_get_opt(&window_size, - &conn_timeout_ms, - &packet_timeout_ms, - &delayed_acks, - &ack_timeout, - &ack_delay_count); -#endif - return Py_BuildValue("IIIIII", - window_size, - conn_timeout_ms, - packet_timeout_ms, - delayed_acks, - ack_timeout, - ack_delay_count); -} - - -/* - * - * int csp_xtea_set_key(char *key, uint32_t keylen); - */ -static PyObject* pycsp_xtea_set_key(PyObject *self, PyObject *args) { - char* key; - uint32_t keylen; - if (!PyArg_ParseTuple(args, "si", &key, &keylen)) { - return NULL; // TypeError is thrown - } - return Py_BuildValue("i", csp_xtea_set_key(key, keylen)); -} -/** - * csp/csp_rtable.h - */ - -/* - * int csp_rtable_set(uint8_t node, uint8_t mask, - * csp_iface_t *ifc, uint8_t mac); - */ -static PyObject* pycsp_rtable_set(PyObject *self, PyObject *args) { - uint8_t node; - uint8_t mask; - char* interface_name; - uint8_t mac = CSP_NODE_MAC; - if (!PyArg_ParseTuple(args, "bbs|b", &node, &mask, &interface_name, &mac)) { - return NULL; // TypeError is thrown - } - - return Py_BuildValue("i", csp_rtable_set(node, - mask, - csp_iflist_get_by_name(interface_name), - mac)); -} - -/* - * void csp_rtable_clear(void); - */ -static PyObject* pycsp_rtable_clear(PyObject *self, PyObject *args) { - csp_rtable_clear(); - Py_RETURN_NONE; -} - -/* -* int csp_rtable_check(const char * buffer) -*/ -static PyObject* pycsp_rtable_check(PyObject *self, PyObject *args) { - char* buffer; - if (!PyArg_ParseTuple(args, "s", &buffer)) { - return NULL; // TypeError is thrown - } - - return Py_BuildValue("i", csp_rtable_check(buffer)); -} - -/* -* void csp_rtable_load(const char * buffer) -*/ -static PyObject* pycsp_rtable_load(PyObject *self, PyObject *args) { - char* buffer; - if (!PyArg_ParseTuple(args, "s", &buffer)) { - return NULL; // TypeError is thrown - } - - csp_rtable_load(buffer); - Py_RETURN_NONE; -} - -/** - * csp/csp_buffer.h - */ - -/* - * int csp_buffer_init(int count, int size); - */ -static PyObject* pycsp_buffer_init(PyObject *self, PyObject *args) { - int count; - int size; - if (!PyArg_ParseTuple(args, "ii", &count, &size)) { - return NULL; // TypeError is thrown - } - - return Py_BuildValue("i", csp_buffer_init(count, size)); -} - -/* - * void * csp_buffer_get(size_t size); - */ -static PyObject* pycsp_buffer_get(PyObject *self, PyObject *args) { - size_t size; - if (!PyArg_ParseTuple(args, "n", &size)) { - return NULL; // TypeError is thrown - } - - void* packet = csp_buffer_get(size); - if (packet == NULL) { - Py_RETURN_NONE; - } - - return PyCapsule_New(packet, "csp_packet_t", NULL); -} -/* - * void csp_buffer_free(void *packet); - */ -static PyObject* pycsp_buffer_free(PyObject *self, PyObject *args) { - PyObject* packet_capsule; - if (!PyArg_ParseTuple(args, "O", &packet_capsule)) { - return NULL; // TypeError is thrown - } - - - if (!is_capsule_of_type(packet_capsule, "csp_packet_t")) { - return NULL; // TypeError is thrown - } - - csp_buffer_free(PyCapsule_GetPointer(packet_capsule, "csp_packet_t")); - Py_RETURN_NONE; -} - -/* - * int csp_buffer_remaining(void); - */ -static PyObject* pycsp_buffer_remaining(PyObject *self, PyObject *args) { - return Py_BuildValue("i", csp_buffer_remaining()); -} - -/** - * csp/csp_cmp.h - */ - -/* - * static inline int csp_cmp_ident(uint8_t node, uint32_t timeout, - * struct csp_cmp_message *msg) - */ -static PyObject* pycsp_cmp_ident(PyObject *self, PyObject *args) { - uint8_t node; - uint32_t timeout = 500; - if (!PyArg_ParseTuple(args, "b|i", &node, &timeout)) { - return NULL; // TypeError is thrown - } - - struct csp_cmp_message msg; - int rc = csp_cmp_ident(node, timeout, &msg); - return Py_BuildValue("isssss", - rc, - msg.ident.hostname, - msg.ident.model, - msg.ident.revision, - msg.ident.date, - msg.ident.time); -} - -/* - * static inline int csp_cmp_route_set(uint8_t node, uint32_t timeout, - * struct csp_cmp_message *msg) - */ -static PyObject* pycsp_cmp_route_set(PyObject *self, PyObject *args) { - uint8_t node; - uint32_t timeout = 500; - uint8_t addr; - uint8_t mac; - char* ifstr; - if (!PyArg_ParseTuple(args, "bibbs", &node, &timeout, &addr, &mac, &ifstr)) { - return NULL; // TypeError is thrown - } - - struct csp_cmp_message msg; - msg.route_set.dest_node = addr; - msg.route_set.next_hop_mac = mac; - strncpy(msg.route_set.interface, ifstr, CSP_CMP_ROUTE_IFACE_LEN); - int rc = csp_cmp_route_set(node, timeout, &msg); - return Py_BuildValue("i", - rc); -} - -/* static inline int pycsp_cmp_peek(uint8_t node, uint32_t timeout, struct csp_cmp_message *msg); */ -static PyObject* pycsp_cmp_peek(PyObject *self, PyObject *args) { - uint8_t node; - uint32_t timeout; - uint8_t len; - uint32_t addr; - Py_buffer outbuf; - - if (!PyArg_ParseTuple(args, "biibw*", &node, &timeout, &addr, &len, &outbuf)) { - Py_RETURN_NONE; - } - - if (len > CSP_CMP_PEEK_MAX_LEN) { - len = CSP_CMP_PEEK_MAX_LEN; - } - struct csp_cmp_message msg; - msg.peek.addr = csp_hton32(addr); - msg.peek.len = len; - int rc = csp_cmp_peek(node, timeout, &msg); - if (rc != CSP_ERR_NONE) { - Py_RETURN_NONE; - } - memcpy(outbuf.buf, msg.peek.data, len); - outbuf.len = len; - - return Py_BuildValue("i", rc); -} - -/* static inline int pycsp_cmp_poke(uint8_t node, uint32_t timeout, struct csp_cmp_message *msg); */ -static PyObject* pycsp_cmp_poke(PyObject *self, PyObject *args) { - uint8_t node; - uint32_t timeout; - uint8_t len; - uint32_t addr; - Py_buffer inbuf; - - if (!PyArg_ParseTuple(args, "biibw*", &node, &timeout, &addr, &len, &inbuf)) { - Py_RETURN_NONE; - } - - if (len > CSP_CMP_POKE_MAX_LEN) { - len = CSP_CMP_POKE_MAX_LEN; - } - struct csp_cmp_message msg; - msg.poke.addr = csp_hton32(addr); - msg.poke.len = len; - memcpy(msg.poke.data, inbuf.buf, len); - int rc = csp_cmp_poke(node, timeout, &msg); - if (rc != CSP_ERR_NONE) { - Py_RETURN_NONE; - } - - return Py_BuildValue("i", rc); -} - -/* static inline int csp_cmp_clock(uint8_t node, uint32_t timeout, struct csp_cmp_message *msg); */ -static PyObject* pycsp_cmp_clock(PyObject *self, PyObject *args) { - uint8_t node; - uint32_t timeout; - uint32_t sec; - uint32_t nsec; - if (!PyArg_ParseTuple(args, "bIII", &node, &timeout, &sec, &nsec)) { - Py_RETURN_NONE; - } - - struct csp_cmp_message msg; - msg.clock.tv_sec = csp_hton32(sec); - msg.clock.tv_nsec = csp_hton32(nsec); - return Py_BuildValue("i", csp_cmp_clock(node, timeout, &msg)); -} - -/** - * csp/interfaces/csp_if_zmqhub.h - */ - -/* - * int csp_zmqhub_init(char addr, char * host); - */ -static PyObject* pycsp_zmqhub_init(PyObject *self, PyObject *args) { - char addr; - char* host; - if (!PyArg_ParseTuple(args, "bs", &addr, &host)) { - return NULL; // TypeError is thrown - } - - return Py_BuildValue("i", csp_zmqhub_init(addr, host)); -} - -/** - * csp/drivers/can_socketcan.h - */ - -/* - * csp_iface_t * csp_can_socketcan_init(const char * ifc, int bitrate, int promisc); - */ -static PyObject* pycsp_can_socketcan_init(PyObject *self, PyObject *args) -{ - char* ifc; - int bitrate = 1000000; - int promisc = 0; - - if (!PyArg_ParseTuple(args, "s|ii", &ifc, &bitrate, &promisc)) - { - return NULL; - } - - csp_can_socketcan_init(ifc, bitrate, promisc); - Py_RETURN_NONE; -} - - -/** - * csp/interfaces/csp_if_kiss.h - */ - -/* - * int csp_kiss_init(char addr, char * host); - */ -static PyObject* pycsp_kiss_init(PyObject *self, PyObject *args) { - char* device; - uint32_t baudrate = 500000; - uint32_t mtu = 512; - const char* if_name = "KISS"; - if (!PyArg_ParseTuple(args, "s|IIs", &device, &baudrate, &mtu, &if_name)) { - return NULL; // TypeError is thrown - } - - static csp_iface_t csp_if_kiss; - static csp_kiss_handle_t csp_kiss_driver; - csp_if_kiss.mtu = (uint16_t) mtu; - struct usart_conf conf = {.device = device, .baudrate = baudrate}; - csp_kiss_init(&csp_if_kiss, &csp_kiss_driver, usart_putc, usart_insert, if_name); - usart_init(&conf); - - void my_usart_rx(uint8_t * buf, int len, void * pxTaskWoken) { - csp_kiss_rx(&csp_if_kiss, buf, len, pxTaskWoken); - } - usart_set_callback(my_usart_rx); - - Py_RETURN_NONE; -} - -/** - * Helpers - accessing csp_packet_t members - */ -static PyObject* pycsp_packet_set_data(PyObject *self, PyObject *args) { - PyObject* packet_capsule; - Py_buffer data; - if (!PyArg_ParseTuple(args, "Ow*", &packet_capsule, &data)) { - return NULL; // TypeError is thrown - } - - if (!is_capsule_of_type(packet_capsule, "csp_packet_t")) { - return NULL; // TypeError is thrown - } - - csp_packet_t* packet = PyCapsule_GetPointer(packet_capsule, "csp_packet_t"); - - memcpy((char *)packet->data, data.buf, data.len); - packet->length = data.len; - - Py_RETURN_NONE; -} -static PyObject* pycsp_packet_get_data(PyObject *self, PyObject *packet_capsule) { - if (!is_capsule_of_type(packet_capsule, "csp_packet_t")) { - return NULL; // TypeError is thrown - } - - csp_packet_t* packet = PyCapsule_GetPointer(packet_capsule, "csp_packet_t"); -#ifdef IS_PY3 - return Py_BuildValue("y#", packet->data, packet->length); -#else - return Py_BuildValue("s#", packet->data, packet->length); -#endif -} - -static PyObject* pycsp_packet_get_length(PyObject *self, PyObject *packet_capsule) { - if (!is_capsule_of_type(packet_capsule, "csp_packet_t")) { - return NULL; // TypeError is thrown - } - - csp_packet_t* packet = PyCapsule_GetPointer(packet_capsule, "csp_packet_t"); - return Py_BuildValue("H", packet->length); -} - -static PyMethodDef methods[] = { - - /* csp/csp.h */ - {"service_handler", pycsp_service_handler, METH_VARARGS, ""}, - {"init", pycsp_init, METH_VARARGS, ""}, - {"set_hostname", pycsp_set_hostname, METH_VARARGS, ""}, - {"get_hostname", pycsp_get_hostname, METH_NOARGS, ""}, - {"set_model", pycsp_set_model, METH_VARARGS, ""}, - {"get_model", pycsp_get_model, METH_NOARGS, ""}, - {"set_revision", pycsp_set_revision, METH_VARARGS, ""}, - {"get_revision", pycsp_get_revision, METH_NOARGS, ""}, - {"socket", pycsp_socket, METH_VARARGS, ""}, - {"accept", pycsp_accept, METH_VARARGS, ""}, - {"read", pycsp_read, METH_VARARGS, ""}, - {"send", pycsp_send, METH_VARARGS, ""}, - {"transaction", pycsp_transaction, METH_VARARGS, ""}, - {"sendto_reply", pycsp_sendto_reply, METH_VARARGS, ""}, - {"sendto", pycsp_sendto, METH_VARARGS, ""}, - {"connect", pycsp_connect, METH_VARARGS, ""}, - {"close", pycsp_close, METH_O, ""}, - {"conn_dport", pycsp_conn_dport, METH_O, ""}, - {"conn_sport", pycsp_conn_sport, METH_O, ""}, - {"conn_dst", pycsp_conn_dst, METH_O, ""}, - {"conn_src", pycsp_conn_src, METH_O, ""}, - {"listen", pycsp_listen, METH_VARARGS, ""}, - {"bind", pycsp_bind, METH_VARARGS, ""}, - {"route_start_task", pycsp_route_start_task, METH_VARARGS, ""}, - {"ping", pycsp_ping, METH_VARARGS, ""}, - {"reboot", pycsp_reboot, METH_VARARGS, ""}, - {"shutdown", pycsp_shutdown, METH_VARARGS, ""}, - {"rdp_set_opt", pycsp_rdp_set_opt, METH_VARARGS, ""}, - {"rdp_get_opt", pycsp_rdp_get_opt, METH_NOARGS, ""}, - {"xtea_set_key", pycsp_xtea_set_key, METH_VARARGS, ""}, - - /* csp/csp_rtable.h */ - {"rtable_set", pycsp_rtable_set, METH_VARARGS, ""}, - {"rtable_clear", pycsp_rtable_clear, METH_NOARGS, ""}, - {"rtable_check", pycsp_rtable_check, METH_VARARGS, ""}, - {"rtable_load", pycsp_rtable_load, METH_VARARGS, ""}, - - /* csp/csp_buffer.h */ - {"buffer_init", pycsp_buffer_init, METH_VARARGS, ""}, - {"buffer_free", pycsp_buffer_free, METH_VARARGS, ""}, - {"buffer_get", pycsp_buffer_get, METH_VARARGS, ""}, - {"buffer_remaining", pycsp_buffer_remaining, METH_NOARGS, ""}, - - /* csp/csp_cmp.h */ - {"cmp_ident", pycsp_cmp_ident, METH_VARARGS, ""}, - {"cmp_route_set", pycsp_cmp_route_set, METH_VARARGS, ""}, - {"cmp_peek", pycsp_cmp_peek, METH_VARARGS, ""}, - {"cmp_poke", pycsp_cmp_poke, METH_VARARGS, ""}, - {"cmp_clock", pycsp_cmp_clock, METH_VARARGS, ""}, - - - /* csp/interfaces/csp_if_zmqhub.h */ - {"zmqhub_init", pycsp_zmqhub_init, METH_VARARGS, ""}, - {"kiss_init", pycsp_kiss_init, METH_VARARGS, ""}, - - /* csp/drivers/can_socketcan.h */ - {"can_socketcan_init", pycsp_can_socketcan_init, METH_VARARGS, ""}, - - /* helpers */ - {"packet_get_length", pycsp_packet_get_length, METH_O, ""}, - {"packet_get_data", pycsp_packet_get_data, METH_O, ""}, - {"packet_set_data", pycsp_packet_set_data, METH_VARARGS, ""}, - - /* sentinel */ - {NULL, NULL, 0, NULL} -}; - -#ifdef IS_PY3 -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "libcsp_py3", - NULL, - -1, - methods, - NULL, - NULL, - NULL, - NULL -}; -#endif - -#ifdef IS_PY3 -PyMODINIT_FUNC PyInit_libcsp_py3(void) { -#else - PyMODINIT_FUNC initlibcsp_py2(void) { -#endif - - PyObject* m; - -#ifdef IS_PY3 - m = PyModule_Create(&moduledef); -#else - m = Py_InitModule("libcsp_py2", methods); -#endif - /** - * csp/csp_types.h - */ - - /* RESERVED PORTS */ - PyModule_AddIntConstant(m, "CSP_CMP", CSP_CMP); - PyModule_AddIntConstant(m, "CSP_PING", CSP_PING); - PyModule_AddIntConstant(m, "CSP_PS", CSP_PS); - PyModule_AddIntConstant(m, "CSP_MEMFREE", CSP_MEMFREE); - PyModule_AddIntConstant(m, "CSP_REBOOT", CSP_REBOOT); - PyModule_AddIntConstant(m, "CSP_BUF_FREE", CSP_BUF_FREE); - PyModule_AddIntConstant(m, "CSP_UPTIME", CSP_UPTIME); - PyModule_AddIntConstant(m, "CSP_ANY", CSP_MAX_BIND_PORT + 1); - PyModule_AddIntConstant(m, "CSP_PROMISC", CSP_MAX_BIND_PORT + 2); - - /* PRIORITIES */ - PyModule_AddIntConstant(m, "CSP_PRIO_CRITICAL", CSP_PRIO_CRITICAL); - PyModule_AddIntConstant(m, "CSP_PRIO_HIGH", CSP_PRIO_HIGH); - PyModule_AddIntConstant(m, "CSP_PRIO_NORM", CSP_PRIO_NORM); - PyModule_AddIntConstant(m, "CSP_PRIO_LOW", CSP_PRIO_LOW); - - /* FLAGS */ - PyModule_AddIntConstant(m, "CSP_FFRAG", CSP_FFRAG); - PyModule_AddIntConstant(m, "CSP_FHMAC", CSP_FHMAC); - PyModule_AddIntConstant(m, "CSP_FXTEA", CSP_FXTEA); - PyModule_AddIntConstant(m, "CSP_FRDP", CSP_FRDP); - PyModule_AddIntConstant(m, "CSP_FCRC32", CSP_FCRC32); - - /* SOCKET OPTIONS */ - PyModule_AddIntConstant(m, "CSP_SO_NONE", CSP_SO_NONE); - PyModule_AddIntConstant(m, "CSP_SO_RDPREQ", CSP_SO_RDPREQ); - PyModule_AddIntConstant(m, "CSP_SO_RDPPROHIB", CSP_SO_RDPPROHIB); - PyModule_AddIntConstant(m, "CSP_SO_HMACREQ", CSP_SO_HMACREQ); - PyModule_AddIntConstant(m, "CSP_SO_HMACPROHIB", CSP_SO_HMACPROHIB); - PyModule_AddIntConstant(m, "CSP_SO_XTEAREQ", CSP_SO_XTEAREQ); - PyModule_AddIntConstant(m, "CSP_SO_XTEAPROHIB", CSP_SO_XTEAPROHIB); - PyModule_AddIntConstant(m, "CSP_SO_CRC32REQ", CSP_SO_CRC32REQ); - PyModule_AddIntConstant(m, "CSP_SO_CRC32PROHIB", CSP_SO_CRC32PROHIB); - PyModule_AddIntConstant(m, "CSP_SO_CONN_LESS", CSP_SO_CONN_LESS); - - /* CONNECT OPTIONS */ - PyModule_AddIntConstant(m, "CSP_O_NONE", CSP_O_NONE); - PyModule_AddIntConstant(m, "CSP_O_RDP", CSP_O_RDP); - PyModule_AddIntConstant(m, "CSP_O_NORDP", CSP_O_NORDP); - PyModule_AddIntConstant(m, "CSP_O_HMAC", CSP_O_HMAC); - PyModule_AddIntConstant(m, "CSP_O_NOHMAC", CSP_O_NOHMAC); - PyModule_AddIntConstant(m, "CSP_O_XTEA", CSP_O_XTEA); - PyModule_AddIntConstant(m, "CSP_O_NOXTEA", CSP_O_NOXTEA); - PyModule_AddIntConstant(m, "CSP_O_CRC32", CSP_O_CRC32); - PyModule_AddIntConstant(m, "CSP_O_NOCRC32", CSP_O_NOCRC32); - - - /** - * csp/csp_error.h - */ - - PyModule_AddIntConstant(m, "CSP_ERR_NONE", CSP_ERR_NONE); - PyModule_AddIntConstant(m, "CSP_ERR_NOMEM", CSP_ERR_NOMEM); - PyModule_AddIntConstant(m, "CSP_ERR_INVAL", CSP_ERR_INVAL); - PyModule_AddIntConstant(m, "CSP_ERR_TIMEDOUT", CSP_ERR_TIMEDOUT); - PyModule_AddIntConstant(m, "CSP_ERR_USED", CSP_ERR_USED); - PyModule_AddIntConstant(m, "CSP_ERR_NOTSUP", CSP_ERR_NOTSUP); - PyModule_AddIntConstant(m, "CSP_ERR_BUSY", CSP_ERR_BUSY); - PyModule_AddIntConstant(m, "CSP_ERR_ALREADY", CSP_ERR_ALREADY); - PyModule_AddIntConstant(m, "CSP_ERR_RESET", CSP_ERR_RESET); - PyModule_AddIntConstant(m, "CSP_ERR_NOBUFS", CSP_ERR_NOBUFS); - PyModule_AddIntConstant(m, "CSP_ERR_TX", CSP_ERR_TX); - PyModule_AddIntConstant(m, "CSP_ERR_DRIVER", CSP_ERR_DRIVER); - PyModule_AddIntConstant(m, "CSP_ERR_AGAIN", CSP_ERR_AGAIN); - PyModule_AddIntConstant(m, "CSP_ERR_HMAC", CSP_ERR_HMAC); - PyModule_AddIntConstant(m, "CSP_ERR_XTEA", CSP_ERR_XTEA); - PyModule_AddIntConstant(m, "CSP_ERR_CRC32", CSP_ERR_CRC32); - - /** - * csp/rtable.h - */ - PyModule_AddIntConstant(m, "CSP_NODE_MAC", CSP_NODE_MAC); - -#ifdef IS_PY3 - return m; -#endif - } - diff --git a/gomspace/libgscsp/lib/libcsp/src/crypto/csp_hmac.c b/gomspace/libgscsp/lib/libcsp/src/crypto/csp_hmac.c deleted file mode 100644 index ae7fbb00..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/crypto/csp_hmac.c +++ /dev/null @@ -1,202 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* Hash-based Message Authentication Code - based on code from libtom.org */ - -#include -#include -#include - -/* CSP includes */ -#include - -#include -#include - -#ifdef CSP_USE_HMAC - -#define HMAC_KEY_LENGTH 16 - -/* HMAC key */ -static uint8_t csp_hmac_key[HMAC_KEY_LENGTH]; - -/* HMAC state structure */ -typedef struct { - csp_sha1_state md; - uint8_t key[SHA1_BLOCKSIZE]; -} hmac_state; - -static int csp_hmac_init(hmac_state * hmac, const uint8_t * key, uint32_t keylen) { - uint32_t i; - uint8_t buf[SHA1_BLOCKSIZE]; - - /* NULL pointer and key check */ - if (!hmac || !key || keylen < 1) - return CSP_ERR_INVAL; - - /* Make sure we have a large enough key */ - if(keylen > SHA1_BLOCKSIZE) { - csp_sha1_memory(key, keylen, hmac->key); - if(SHA1_DIGESTSIZE < SHA1_BLOCKSIZE) - memset((hmac->key) + SHA1_DIGESTSIZE, 0, (size_t)(SHA1_BLOCKSIZE - SHA1_DIGESTSIZE)); - } else { - memcpy(hmac->key, key, (size_t)keylen); - if(keylen < SHA1_BLOCKSIZE) - memset((hmac->key) + keylen, 0, (size_t)(SHA1_BLOCKSIZE - keylen)); - } - - /* Create the initial vector */ - for(i = 0; i < SHA1_BLOCKSIZE; i++) - buf[i] = hmac->key[i] ^ 0x36; - - /* Prepend to the hash data */ - csp_sha1_init(&hmac->md); - csp_sha1_process(&hmac->md, buf, SHA1_BLOCKSIZE); - - return CSP_ERR_NONE; -} - -static int csp_hmac_process(hmac_state * hmac, const uint8_t * in, uint32_t inlen) { - - /* NULL pointer check */ - if (!hmac || !in) - return CSP_ERR_INVAL; - - /* Process data */ - csp_sha1_process(&hmac->md, in, inlen); - - return CSP_ERR_NONE; -} - -static int csp_hmac_done(hmac_state * hmac, uint8_t * out) { - - uint32_t i; - uint8_t buf[SHA1_BLOCKSIZE]; - uint8_t isha[SHA1_DIGESTSIZE]; - - if (!hmac || !out) - return CSP_ERR_INVAL; - - /* Get the hash of the first HMAC vector plus the data */ - csp_sha1_done(&hmac->md, isha); - - /* Create the second HMAC vector vector */ - for(i = 0; i < SHA1_BLOCKSIZE; i++) - buf[i] = hmac->key[i] ^ 0x5C; - - /* Now calculate the outer hash */ - csp_sha1_init(&hmac->md); - csp_sha1_process(&hmac->md, buf, SHA1_BLOCKSIZE); - csp_sha1_process(&hmac->md, isha, SHA1_DIGESTSIZE); - csp_sha1_done(&hmac->md, buf); - - /* Copy to output */ - for (i = 0; i < SHA1_DIGESTSIZE; i++) - out[i] = buf[i]; - - return CSP_ERR_NONE; -} - -int csp_hmac_memory(const uint8_t * key, uint32_t keylen, const uint8_t * data, uint32_t datalen, uint8_t * hmac) { - hmac_state state; - - /* NULL pointer check */ - if (!key || !data || !hmac) - return CSP_ERR_INVAL; - - /* Init HMAC state */ - if (csp_hmac_init(&state, key, keylen) != 0) - return CSP_ERR_INVAL; - - /* Process data */ - if (csp_hmac_process(&state, data, datalen) != 0) - return CSP_ERR_INVAL; - - /* Output HMAC */ - if (csp_hmac_done(&state, hmac) != 0) - return CSP_ERR_INVAL; - - return CSP_ERR_NONE; -} - -int csp_hmac_set_key(char * key, uint32_t keylen) { - - /* Use SHA1 as KDF */ - uint8_t hash[SHA1_DIGESTSIZE]; - csp_sha1_memory((uint8_t *)key, keylen, hash); - - /* Copy key */ - memcpy(csp_hmac_key, hash, HMAC_KEY_LENGTH); - - return CSP_ERR_NONE; - -} - -int csp_hmac_append(csp_packet_t * packet, bool include_header) { - - /* NULL pointer check */ - if (packet == NULL) - return CSP_ERR_INVAL; - - uint8_t hmac[SHA1_DIGESTSIZE]; - - /* Calculate HMAC */ - if (include_header) { - csp_hmac_memory(csp_hmac_key, HMAC_KEY_LENGTH, (uint8_t *) &packet->id, packet->length + sizeof(packet->id), hmac); - } else { - csp_hmac_memory(csp_hmac_key, HMAC_KEY_LENGTH, packet->data, packet->length, hmac); - } - - /* Truncate hash and copy to packet */ - memcpy(&packet->data[packet->length], hmac, CSP_HMAC_LENGTH); - packet->length += CSP_HMAC_LENGTH; - - return CSP_ERR_NONE; - -} - -int csp_hmac_verify(csp_packet_t * packet, bool include_header) { - - /* NULL pointer check */ - if (packet == NULL) - return CSP_ERR_INVAL; - - uint8_t hmac[SHA1_DIGESTSIZE]; - - /* Calculate HMAC */ - if (include_header) { - csp_hmac_memory(csp_hmac_key, HMAC_KEY_LENGTH, (uint8_t *) &packet->id, packet->length + sizeof(packet->id) - CSP_HMAC_LENGTH, hmac); - } else { - csp_hmac_memory(csp_hmac_key, HMAC_KEY_LENGTH, packet->data, packet->length - CSP_HMAC_LENGTH, hmac); - } - - /* Compare calculated HMAC with packet header */ - if (memcmp(&packet->data[packet->length] - CSP_HMAC_LENGTH, hmac, CSP_HMAC_LENGTH) != 0) { - /* HMAC failed */ - return CSP_ERR_HMAC; - } else { - /* Strip HMAC */ - packet->length -= CSP_HMAC_LENGTH; - return CSP_ERR_NONE; - } - -} - -#endif // CSP_USE_HMAC diff --git a/gomspace/libgscsp/lib/libcsp/src/crypto/csp_sha1.c b/gomspace/libgscsp/lib/libcsp/src/crypto/csp_sha1.c deleted file mode 100644 index 6c3920e9..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/crypto/csp_sha1.c +++ /dev/null @@ -1,217 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* Code originally from Python's SHA1 Module, who based it on libtom.org */ - -#include -#include - -/* CSP includes */ -#include - -#include - -#if defined(CSP_USE_HMAC) || defined(CSP_USE_XTEA) - -/* Rotate left macro */ -#define ROL(x,y) (((x) << (y)) | ((x) >> (32-y))) - -/* Endian Neutral macros that work on all platforms */ -#define STORE32H(x, y) do { (y)[0] = (uint8_t)(((x) >> 24) & 0xff); \ - (y)[1] = (uint8_t)(((x) >> 16) & 0xff); \ - (y)[2] = (uint8_t)(((x) >> 8) & 0xff); \ - (y)[3] = (uint8_t)(((x) >> 0) & 0xff); } while (0) - -#define LOAD32H(x, y) do { (x) = ((uint32_t)((y)[0] & 0xff) << 24) | \ - ((uint32_t)((y)[1] & 0xff) << 16) | \ - ((uint32_t)((y)[2] & 0xff) << 8) | \ - ((uint32_t)((y)[3] & 0xff) << 0); } while (0) - -#define STORE64H(x, y) do { (y)[0] = (uint8_t)(((x) >> 56) & 0xff); \ - (y)[1] = (uint8_t)(((x) >> 48) & 0xff); \ - (y)[2] = (uint8_t)(((x) >> 40) & 0xff); \ - (y)[3] = (uint8_t)(((x) >> 32) & 0xff); \ - (y)[4] = (uint8_t)(((x) >> 24) & 0xff); \ - (y)[5] = (uint8_t)(((x) >> 16) & 0xff); \ - (y)[6] = (uint8_t)(((x) >> 8) & 0xff); \ - (y)[7] = (uint8_t)(((x) >> 0) & 0xff); } while (0) - -#define MIN(x, y) (((x) < (y)) ? (x) : (y)) - -/* SHA1 macros */ -#define F0(x,y,z) (z ^ (x & (y ^ z))) -#define F1(x,y,z) (x ^ y ^ z) -#define F2(x,y,z) ((x & y) | (z & (x | y))) -#define F3(x,y,z) (x ^ y ^ z) - -#define FF_0(a, b, c, d, e, i) do {e = (ROL(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROL(b, 30);} while (0) -#define FF_1(a, b, c, d, e, i) do {e = (ROL(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROL(b, 30);} while (0) -#define FF_2(a, b, c, d, e, i) do {e = (ROL(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROL(b, 30);} while (0) -#define FF_3(a, b, c, d, e, i) do {e = (ROL(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROL(b, 30);} while (0) - -static void csp_sha1_compress(csp_sha1_state * sha1, const uint8_t * buf) { - - uint32_t a, b, c, d, e, W[80], i; - - /* Copy the state into 512-bits into W[0..15] */ - for (i = 0; i < 16; i++) - LOAD32H(W[i], buf + (4*i)); - - /* Copy state */ - a = sha1->state[0]; - b = sha1->state[1]; - c = sha1->state[2]; - d = sha1->state[3]; - e = sha1->state[4]; - - /* Expand it */ - for (i = 16; i < 80; i++) - W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1); - - /* Compress */ - i = 0; - - /* Round one */ - for (; i < 20;) { - FF_0(a, b, c, d, e, i++); - FF_0(e, a, b, c, d, i++); - FF_0(d, e, a, b, c, i++); - FF_0(c, d, e, a, b, i++); - FF_0(b, c, d, e, a, i++); - } - - /* Round two */ - for (; i < 40;) { - FF_1(a, b, c, d, e, i++); - FF_1(e, a, b, c, d, i++); - FF_1(d, e, a, b, c, i++); - FF_1(c, d, e, a, b, i++); - FF_1(b, c, d, e, a, i++); - } - - /* Round three */ - for (; i < 60;) { - FF_2(a, b, c, d, e, i++); - FF_2(e, a, b, c, d, i++); - FF_2(d, e, a, b, c, i++); - FF_2(c, d, e, a, b, i++); - FF_2(b, c, d, e, a, i++); - } - - /* Round four */ - for (; i < 80;) { - FF_3(a, b, c, d, e, i++); - FF_3(e, a, b, c, d, i++); - FF_3(d, e, a, b, c, i++); - FF_3(c, d, e, a, b, i++); - FF_3(b, c, d, e, a, i++); - } - - /* Store */ - sha1->state[0] += a; - sha1->state[1] += b; - sha1->state[2] += c; - sha1->state[3] += d; - sha1->state[4] += e; - -} - -void csp_sha1_init(csp_sha1_state * sha1) { - - sha1->state[0] = 0x67452301UL; - sha1->state[1] = 0xefcdab89UL; - sha1->state[2] = 0x98badcfeUL; - sha1->state[3] = 0x10325476UL; - sha1->state[4] = 0xc3d2e1f0UL; - sha1->curlen = 0; - sha1->length = 0; - -} - -void csp_sha1_process(csp_sha1_state * sha1, const uint8_t * in, uint32_t inlen) { - - uint32_t n; - while (inlen > 0) { - if (sha1->curlen == 0 && inlen >= SHA1_BLOCKSIZE) { - csp_sha1_compress(sha1, in); - sha1->length += SHA1_BLOCKSIZE * 8; - in += SHA1_BLOCKSIZE; - inlen -= SHA1_BLOCKSIZE; - } else { - n = MIN(inlen, (SHA1_BLOCKSIZE - sha1->curlen)); - memcpy(sha1->buf + sha1->curlen, in, (size_t)n); - sha1->curlen += n; - in += n; - inlen -= n; - if (sha1->curlen == SHA1_BLOCKSIZE) { - csp_sha1_compress(sha1, sha1->buf); - sha1->length += 8*SHA1_BLOCKSIZE; - sha1->curlen = 0; - } - } - } - -} - -void csp_sha1_done(csp_sha1_state * sha1, uint8_t * out) { - - uint32_t i; - - /* Increase the length of the message */ - sha1->length += sha1->curlen * 8; - - /* Append the '1' bit */ - sha1->buf[sha1->curlen++] = 0x80; - - /* If the length is currently above 56 bytes we append zeros - * then compress. Then we can fall back to padding zeros and length - * encoding like normal. - */ - if (sha1->curlen > 56) { - while (sha1->curlen < 64) - sha1->buf[sha1->curlen++] = 0; - csp_sha1_compress(sha1, sha1->buf); - sha1->curlen = 0; - } - - /* Pad up to 56 bytes of zeroes */ - while (sha1->curlen < 56) - sha1->buf[sha1->curlen++] = 0; - - /* Store length */ - STORE64H(sha1->length, sha1->buf + 56); - csp_sha1_compress(sha1, sha1->buf); - - /* Copy output */ - for (i = 0; i < 5; i++) - STORE32H(sha1->state[i], out + (4 * i)); - -} - -void csp_sha1_memory(const uint8_t * msg, uint32_t len, uint8_t * hash) { - - csp_sha1_state md; - csp_sha1_init(&md); - csp_sha1_process(&md, msg, len); - csp_sha1_done(&md, hash); - -} - -#endif // CSP_USE_HMAC diff --git a/gomspace/libgscsp/lib/libcsp/src/crypto/csp_xtea.c b/gomspace/libgscsp/lib/libcsp/src/crypto/csp_xtea.c deleted file mode 100644 index 718824d1..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/crypto/csp_xtea.c +++ /dev/null @@ -1,134 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* Simple implementation of XTEA in CTR mode */ - -#include -#include - -/* CSP includes */ -#include -#include -#include -#include - -#ifdef CSP_USE_XTEA - -#define XTEA_BLOCKSIZE 8 -#define XTEA_ROUNDS 32 -#define XTEA_KEY_LENGTH 16 - -/* XTEA key */ -static uint32_t csp_xtea_key[XTEA_KEY_LENGTH/sizeof(uint32_t)] __attribute__ ((aligned(sizeof(uint32_t)))); - -#define STORE32L(x, y) do { (y)[3] = (uint8_t)(((x) >> 24) & 0xff); \ - (y)[2] = (uint8_t)(((x) >> 16) & 0xff); \ - (y)[1] = (uint8_t)(((x) >> 8) & 0xff); \ - (y)[0] = (uint8_t)(((x) >> 0) & 0xff); } while (0) - -#define LOAD32L(x, y) do { (x) = ((uint32_t)((y)[3] & 0xff) << 24) | \ - ((uint32_t)((y)[2] & 0xff) << 16) | \ - ((uint32_t)((y)[1] & 0xff) << 8) | \ - ((uint32_t)((y)[0] & 0xff) << 0); } while (0) - -/* This function takes 64 bits of data in block and the 128 bits key in key */ -static inline void csp_xtea_encrypt_block(uint8_t *block, uint8_t const *key) { - - uint32_t i, v0, v1, delta = 0x9E3779B9, sum = 0, k[4]; - - LOAD32L(k[0], &key[0]); - LOAD32L(k[1], &key[4]); - LOAD32L(k[2], &key[8]); - LOAD32L(k[3], &key[12]); - - LOAD32L(v0, &block[0]); - LOAD32L(v1, &block[4]); - - for (i = 0; i < XTEA_ROUNDS; i++) { - v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]); - sum += delta; - v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum >> 11) & 3]); - } - - STORE32L(v0, &block[0]); - STORE32L(v1, &block[4]); - -} - -static inline void csp_xtea_xor_byte(uint8_t * dst, uint8_t * src, uint32_t len) { - - unsigned int i; - for (i = 0; i < len; i++) - dst[i] ^= src[i]; - -} - -int csp_xtea_set_key(char * key, uint32_t keylen) { - - /* Use SHA1 as KDF */ - uint8_t hash[SHA1_DIGESTSIZE]; - csp_sha1_memory((uint8_t *)key, keylen, hash); - - /* Copy key */ - memcpy(csp_xtea_key, hash, XTEA_KEY_LENGTH); - - return CSP_ERR_NONE; - -} - -int csp_xtea_encrypt(uint8_t * plain, const uint32_t len, uint32_t iv[2]) { - - unsigned int i; - uint32_t stream[2]; - - uint32_t blocks = (len + XTEA_BLOCKSIZE - 1)/ XTEA_BLOCKSIZE; - uint32_t remain; - - /* Initialize stream */ - stream[0] = csp_htobe32(iv[0]); - stream[1] = csp_htobe32(iv[1]); - - for (i = 0; i < blocks; i++) { - /* Create stream */ - csp_xtea_encrypt_block((uint8_t *)stream, (uint8_t *)csp_xtea_key); - - /* Calculate remaining bytes */ - remain = len - i * XTEA_BLOCKSIZE; - - /* XOR plain text with stream to generate cipher text */ - csp_xtea_xor_byte(&plain[len - remain], (uint8_t *)stream, remain < XTEA_BLOCKSIZE ? remain : XTEA_BLOCKSIZE); - - /* Increment counter */ - stream[0] = csp_htobe32(iv[0]); - stream[1] = csp_htobe32(iv[1]++); - } - - return CSP_ERR_NONE; - -} - -int csp_xtea_decrypt(uint8_t * cipher, const uint32_t len, uint32_t iv[2]) { - - /* Since we use counter mode, we can reuse the encryption function */ - return csp_xtea_encrypt(cipher, len, iv); - -} - -#endif // CSP_USE_XTEA diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_bridge.c b/gomspace/libgscsp/lib/libcsp/src/csp_bridge.c deleted file mode 100644 index 1c579a9f..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_bridge.c +++ /dev/null @@ -1,94 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include "csp_route.h" -#include "csp_qfifo.h" -#include "csp_io.h" -#include "csp_promisc.h" - -static csp_iface_t* if_a = NULL; -static csp_iface_t* if_b = NULL; - -static CSP_DEFINE_TASK(csp_bridge) { - - csp_qfifo_t input; - csp_packet_t * packet; - - /* Here there be bridging */ - while (1) { - - /* Get next packet to route */ - if (csp_qfifo_read(&input) != CSP_ERR_NONE) - continue; - - packet = input.packet; - - csp_log_packet("Input: Src %u, Dst %u, Dport %u, Sport %u, Pri %u, Flags 0x%02X, Size %"PRIu16, - packet->id.src, packet->id.dst, packet->id.dport, - packet->id.sport, packet->id.pri, packet->id.flags, packet->length); - - /* Here there be promiscuous mode */ -#ifdef CSP_USE_PROMISC - csp_promisc_add(packet); -#endif - - /* Find the opposing interface */ - csp_iface_t * ifout; - if (input.interface == if_a) { - ifout = if_b; - } else { - ifout = if_a; - } - - /* Send to the interface directly, no hassle */ - if (csp_send_direct(packet->id, packet, ifout, 0) != CSP_ERR_NONE) { - csp_log_warn("Router failed to send"); - csp_buffer_free(packet); - } - - /* Next message, please */ - continue; - - } - - return CSP_TASK_RETURN; - -} - -int csp_bridge_start(unsigned int task_stack_size, unsigned int task_priority, csp_iface_t * _if_a, csp_iface_t * _if_b) { - - /* Set static references to A/B side of bridge */ - if_a = _if_a; - if_b = _if_b; - - static csp_thread_handle_t handle; - int ret = csp_thread_create(csp_bridge, "BRIDGE", task_stack_size, NULL, task_priority, &handle); - - if (ret != 0) { - csp_log_error("Failed to start task"); - return CSP_ERR_NOMEM; - } - - return CSP_ERR_NONE; - -} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_buffer.c b/gomspace/libgscsp/lib/libcsp/src/csp_buffer.c deleted file mode 100644 index 8947f337..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_buffer.c +++ /dev/null @@ -1,224 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include - -/* CSP includes */ -#include -#include -#include -#include -#include - -#ifndef CSP_BUFFER_ALIGN -#define CSP_BUFFER_ALIGN (sizeof(int *)) -#endif - -typedef struct csp_skbf_s { - unsigned int refcount; - void * skbf_addr; - char skbf_data[]; -} csp_skbf_t; - -static csp_queue_handle_t csp_buffers; -static char * csp_buffer_pool; -static unsigned int count, size; - -CSP_DEFINE_CRITICAL(csp_critical_lock); - -int csp_buffer_init(int buf_count, int buf_size) { - - unsigned int i; - csp_skbf_t * buf; - - count = buf_count; - size = buf_size + CSP_BUFFER_PACKET_OVERHEAD; - unsigned int skbfsize = (sizeof(csp_skbf_t) + size); - skbfsize = CSP_BUFFER_ALIGN * ((skbfsize + CSP_BUFFER_ALIGN - 1) / CSP_BUFFER_ALIGN); - unsigned int poolsize = count * skbfsize; - - csp_buffer_pool = csp_malloc(poolsize); - if (csp_buffer_pool == NULL) - goto fail_malloc; - - csp_buffers = csp_queue_create(count, sizeof(void *)); - if (!csp_buffers) - goto fail_queue; - - if (CSP_INIT_CRITICAL(csp_critical_lock) != CSP_ERR_NONE) - goto fail_critical; - - memset(csp_buffer_pool, 0, poolsize); - - for (i = 0; i < count; i++) { - - /* We have already taken care of pointer alignment since - * skbfsize is an integer multiple of sizeof(int *) - * but the explicit cast to a void * is still necessary - * to tell the compiler so. - */ - buf = (void *) &csp_buffer_pool[i * skbfsize]; - buf->refcount = 0; - buf->skbf_addr = buf; - - csp_queue_enqueue(csp_buffers, &buf, 0); - - } - - return CSP_ERR_NONE; - -fail_critical: - csp_queue_remove(csp_buffers); -fail_queue: - csp_free(csp_buffer_pool); -fail_malloc: - return CSP_ERR_NOMEM; - -} - -void *csp_buffer_get_isr(size_t buf_size) { - - csp_skbf_t * buffer = NULL; - CSP_BASE_TYPE task_woken = 0; - - if (buf_size + CSP_BUFFER_PACKET_OVERHEAD > size) - return NULL; - - csp_queue_dequeue_isr(csp_buffers, &buffer, &task_woken); - if (buffer == NULL) - return NULL; - - if (buffer != buffer->skbf_addr) - return NULL; - - buffer->refcount++; - return buffer->skbf_data; - -} - -void *csp_buffer_get(size_t buf_size) { - - csp_skbf_t * buffer = NULL; - - if (buf_size + CSP_BUFFER_PACKET_OVERHEAD > size) { - csp_log_error("Attempt to allocate too large block %u", buf_size); - return NULL; - } - - csp_queue_dequeue(csp_buffers, &buffer, 0); - if (buffer == NULL) { - csp_log_error("Out of buffers"); - return NULL; - } - - csp_log_buffer("GET: %p %p", buffer, buffer->skbf_addr); - - if (buffer != buffer->skbf_addr) { - csp_log_error("Corrupt CSP buffer"); - return NULL; - } - - buffer->refcount++; - return buffer->skbf_data; -} - -void csp_buffer_free_isr(void *packet) { - CSP_BASE_TYPE task_woken = 0; - if (!packet) - return; - - csp_skbf_t * buf = packet - sizeof(csp_skbf_t); - - if (((uintptr_t) buf % CSP_BUFFER_ALIGN) > 0) - return; - - if (buf->skbf_addr != buf) - return; - - if (buf->refcount == 0) { - return; - } else if (buf->refcount > 1) { - buf->refcount--; - return; - } else { - buf->refcount = 0; - csp_queue_enqueue_isr(csp_buffers, &buf, &task_woken); - } - -} - -void csp_buffer_free(void *packet) { - if (!packet) { - csp_log_error("Attempt to free null pointer"); - return; - } - - csp_skbf_t * buf = packet - sizeof(csp_skbf_t); - - if (((uintptr_t) buf % CSP_BUFFER_ALIGN) > 0) { - csp_log_error("FREE: Unaligned CSP buffer pointer %p", packet); - return; - } - - if (buf->skbf_addr != buf) { - csp_log_error("FREE: Invalid CSP buffer pointer %p", packet); - return; - } - - if (buf->refcount == 0) { - csp_log_error("FREE: Buffer already free %p", buf); - return; - } else if (buf->refcount > 1) { - buf->refcount--; - csp_log_error("FREE: Buffer %p in use by %u users", buf, buf->refcount); - return; - } else { - buf->refcount = 0; - csp_log_buffer("FREE: %p", buf); - csp_queue_enqueue(csp_buffers, &buf, 0); - } - -} - -void *csp_buffer_clone(void *buffer) { - - csp_packet_t *packet = (csp_packet_t *) buffer; - - if (!packet) - return NULL; - - csp_packet_t *clone = csp_buffer_get(packet->length); - - if (clone) - memcpy(clone, packet, size); - - return clone; - -} - -int csp_buffer_remaining(void) { - return csp_queue_size(csp_buffers); -} - -int csp_buffer_size(void) { - return size; -} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_conn.c b/gomspace/libgscsp/lib/libcsp/src/csp_conn.c deleted file mode 100644 index 7daa569d..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_conn.c +++ /dev/null @@ -1,498 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include - -/* CSP includes */ -#include -#include - -#include -#include -#include -#include -#include - -#include "csp_conn.h" -#include "transport/csp_transport.h" - -/* Static connection pool */ -static csp_conn_t arr_conn[CSP_CONN_MAX]; - -/* Connection pool lock */ -static csp_bin_sem_handle_t conn_lock; - -/* Source port */ -static uint8_t sport; - -/* Source port lock */ -static csp_bin_sem_handle_t sport_lock; - -void csp_conn_check_timeouts(void) { -#ifdef CSP_USE_RDP - int i; - for (i = 0; i < CSP_CONN_MAX; i++) - if (arr_conn[i].state == CONN_OPEN) - if (arr_conn[i].idin.flags & CSP_FRDP) - csp_rdp_check_timeouts(&arr_conn[i]); -#endif -} - -int csp_conn_get_rxq(int prio) { - -#ifdef CSP_USE_QOS - return prio; -#else - return 0; -#endif - -} - -int csp_conn_lock(csp_conn_t * conn, uint32_t timeout) { - - if (csp_mutex_lock(&conn->lock, timeout) != CSP_MUTEX_OK) - return CSP_ERR_TIMEDOUT; - - return CSP_ERR_NONE; - -} - -int csp_conn_unlock(csp_conn_t * conn) { - - csp_mutex_unlock(&conn->lock); - - return CSP_ERR_NONE; - -} - -int csp_conn_enqueue_packet(csp_conn_t * conn, csp_packet_t * packet) { - - if (!conn) - return CSP_ERR_INVAL; - - int rxq; - if (packet != NULL) { - rxq = csp_conn_get_rxq(packet->id.pri); - } else { - rxq = CSP_RX_QUEUES - 1; - } - - if (csp_queue_enqueue(conn->rx_queue[rxq], &packet, 0) != CSP_QUEUE_OK) { - csp_log_error("RX queue %p full with %u items", conn->rx_queue[rxq], csp_queue_size(conn->rx_queue[rxq])); - return CSP_ERR_NOMEM; - } - -#ifdef CSP_USE_QOS - int event = 0; - if (csp_queue_enqueue(conn->rx_event, &event, 0) != CSP_QUEUE_OK) { - csp_log_error("QOS event queue full"); - return CSP_ERR_NOMEM; - } -#endif - - return CSP_ERR_NONE; -} - -int csp_conn_init(void) { - - /* Initialize source port */ - srand(csp_get_ms()); - sport = (rand() % (CSP_ID_PORT_MAX - CSP_MAX_BIND_PORT)) + (CSP_MAX_BIND_PORT + 1); - - if (csp_bin_sem_create(&sport_lock) != CSP_SEMAPHORE_OK) { - csp_log_error("No more memory for sport semaphore"); - return CSP_ERR_NOMEM; - } - - int i, prio; - for (i = 0; i < CSP_CONN_MAX; i++) { - for (prio = 0; prio < CSP_RX_QUEUES; prio++) - arr_conn[i].rx_queue[prio] = csp_queue_create(CSP_RX_QUEUE_LENGTH, sizeof(csp_packet_t *)); - -#ifdef CSP_USE_QOS - arr_conn[i].rx_event = csp_queue_create(CSP_CONN_QUEUE_LENGTH, sizeof(int)); -#endif - arr_conn[i].state = CONN_CLOSED; - - if (csp_mutex_create(&arr_conn[i].lock) != CSP_MUTEX_OK) { - csp_log_error("Failed to create connection lock"); - return CSP_ERR_NOMEM; - } - -#ifdef CSP_USE_RDP - if (csp_rdp_allocate(&arr_conn[i]) != CSP_ERR_NONE) { - csp_log_error("Failed to create queues for RDP in csp_conn_init"); - return CSP_ERR_NOMEM; - } -#endif - } - - if (csp_bin_sem_create(&conn_lock) != CSP_SEMAPHORE_OK) { - csp_log_error("No more memory for conn semaphore"); - return CSP_ERR_NOMEM; - } - - return CSP_ERR_NONE; - -} - -csp_conn_t * csp_conn_find(uint32_t id, uint32_t mask) { - - /* Search for matching connection */ - int i; - csp_conn_t * conn; - id = (id & mask); - for (i = 0; i < CSP_CONN_MAX; i++) { - conn = &arr_conn[i]; - if ((conn->state != CONN_CLOSED) && (conn->type == CONN_CLIENT) && ((conn->idin.ext & mask) == id)) - return conn; - } - - return NULL; - -} - -static int csp_conn_flush_rx_queue(csp_conn_t * conn) { - - csp_packet_t * packet; - - int prio; - - /* Flush packet queues */ - for (prio = 0; prio < CSP_RX_QUEUES; prio++) { - while (csp_queue_dequeue(conn->rx_queue[prio], &packet, 0) == CSP_QUEUE_OK) - if (packet != NULL) - csp_buffer_free(packet); - } - - /* Flush event queue */ -#ifdef CSP_USE_QOS - int event; - while (csp_queue_dequeue(conn->rx_event, &event, 0) == CSP_QUEUE_OK); -#endif - - return CSP_ERR_NONE; - -} - -csp_conn_t * csp_conn_allocate(csp_conn_type_t type) { - - int i, j; - static uint8_t csp_conn_last_given = 0; - csp_conn_t * conn; - - if (csp_bin_sem_wait(&conn_lock, 100) != CSP_SEMAPHORE_OK) { - csp_log_error("Failed to lock conn array"); - return NULL; - } - - /* Search for free connection */ - i = csp_conn_last_given; - i = (i + 1) % CSP_CONN_MAX; - - for (j = 0; j < CSP_CONN_MAX; j++) { - conn = &arr_conn[i]; - if (conn->state == CONN_CLOSED) - break; - i = (i + 1) % CSP_CONN_MAX; - } - - if (conn->state == CONN_OPEN) { - csp_log_error("No more free connections"); - csp_bin_sem_post(&conn_lock); - return NULL; - } - - conn->idin.ext = 0; - conn->idout.ext = 0; - conn->socket = NULL; - conn->timestamp = 0; - conn->type = type; - conn->state = CONN_OPEN; - - csp_conn_last_given = i; - csp_bin_sem_post(&conn_lock); - - return conn; - -} - -csp_conn_t * csp_conn_new(csp_id_t idin, csp_id_t idout) { - - /* Allocate connection structure */ - csp_conn_t * conn = csp_conn_allocate(CONN_CLIENT); - - if (conn) { - /* No lock is needed here, because nobody else * - * has a reference to this connection yet. */ - conn->idin.ext = idin.ext; - conn->idout.ext = idout.ext; - conn->timestamp = csp_get_ms(); - - /* Ensure connection queue is empty */ - csp_conn_flush_rx_queue(conn); - } - - return conn; - -} - -int csp_close(csp_conn_t * conn) { - - if (conn == NULL) { - csp_log_error("NULL Pointer given to csp_close"); - return CSP_ERR_INVAL; - } - - if (conn->state == CONN_CLOSED) { - csp_log_protocol("Conn already closed"); - return CSP_ERR_NONE; - } - -#ifdef CSP_USE_RDP - /* Ensure RDP knows this connection is closing */ - if (conn->idin.flags & CSP_FRDP || conn->idout.flags & CSP_FRDP) - if (csp_rdp_close(conn) == CSP_ERR_AGAIN) - return CSP_ERR_NONE; -#endif - - /* Lock connection array while closing connection */ - if (csp_bin_sem_wait(&conn_lock, 100) != CSP_SEMAPHORE_OK) { - csp_log_error("Failed to lock conn array"); - return CSP_ERR_TIMEDOUT; - } - - /* Set to closed */ - conn->state = CONN_CLOSED; - - /* Ensure connection queue is empty */ - csp_conn_flush_rx_queue(conn); - - if (conn->socket && (conn->type == CONN_SERVER) && (conn->opts & (CSP_SO_CONN_LESS | CSP_SO_INTERNAL_LISTEN))) { - csp_queue_remove(conn->socket); - conn->socket = NULL; - } - - /* Reset RDP state */ -#ifdef CSP_USE_RDP - if (conn->idin.flags & CSP_FRDP) - csp_rdp_flush_all(conn); -#endif - - /* Unlock connection array */ - csp_bin_sem_post(&conn_lock); - - return CSP_ERR_NONE; -} - -csp_conn_t * csp_connect(uint8_t prio, uint8_t dest, uint8_t dport, uint32_t timeout, uint32_t opts) { - - /* Force options on all connections */ - opts |= CSP_CONNECTION_SO; - - /* Generate identifier */ - csp_id_t incoming_id, outgoing_id; - incoming_id.pri = prio; - incoming_id.dst = csp_get_address(); - incoming_id.src = dest; - incoming_id.sport = dport; - incoming_id.flags = 0; - outgoing_id.pri = prio; - outgoing_id.dst = dest; - outgoing_id.src = csp_get_address(); - outgoing_id.dport = dport; - outgoing_id.flags = 0; - - /* Set connection options */ - if (opts & CSP_O_NOCRC32) { - opts &= ~CSP_O_CRC32; - } - - if (opts & CSP_O_RDP) { -#ifdef CSP_USE_RDP - incoming_id.flags |= CSP_FRDP; - outgoing_id.flags |= CSP_FRDP; -#else - csp_log_error("Attempt to create RDP connection, but CSP was compiled without RDP support"); - return NULL; -#endif - } - - if (opts & CSP_O_HMAC) { -#ifdef CSP_USE_HMAC - outgoing_id.flags |= CSP_FHMAC; - incoming_id.flags |= CSP_FHMAC; -#else - csp_log_error("Attempt to create HMAC authenticated connection, but CSP was compiled without HMAC support"); - return NULL; -#endif - } - - if (opts & CSP_O_XTEA) { -#ifdef CSP_USE_XTEA - outgoing_id.flags |= CSP_FXTEA; - incoming_id.flags |= CSP_FXTEA; -#else - csp_log_error("Attempt to create XTEA encrypted connection, but CSP was compiled without XTEA support"); - return NULL; -#endif - } - - if (opts & CSP_O_CRC32) { -#ifdef CSP_USE_CRC32 - outgoing_id.flags |= CSP_FCRC32; - incoming_id.flags |= CSP_FCRC32; -#else - csp_log_error("Attempt to create CRC32 validated connection, but CSP was compiled without CRC32 support"); - return NULL; -#endif - } - - /* Find an unused ephemeral port */ - csp_conn_t * conn = NULL; - - /* Wait for sport lock - note that csp_conn_new(..) is called inside the lock! */ - if (csp_bin_sem_wait(&sport_lock, 1000) != CSP_SEMAPHORE_OK) - return NULL; - - const uint8_t start = sport; - while (++sport != start) { - if (sport > CSP_ID_PORT_MAX) - sport = CSP_MAX_BIND_PORT + 1; - - outgoing_id.sport = sport; - incoming_id.dport = sport; - - /* Match on destination port of _incoming_ identifier */ - if (csp_conn_find(incoming_id.ext, CSP_ID_DPORT_MASK) == NULL) { - /* Break - we found an unused ephemeral port - allocate connection while locked to mark port in use */ - conn = csp_conn_new(incoming_id, outgoing_id); - break; - } - } - - /* Post sport lock */ - csp_bin_sem_post(&sport_lock); - - if (conn == NULL) - return NULL; - - /* Set connection options */ - conn->opts = opts; - -#ifdef CSP_USE_RDP - /* Call Transport Layer connect */ - if (outgoing_id.flags & CSP_FRDP) { - /* If the transport layer has failed to connect - * deallocate connection structure again and return NULL */ - if (csp_rdp_connect(conn, timeout) != CSP_ERR_NONE) { - csp_close(conn); - return NULL; - } - } -#endif - - /* We have a successful connection */ - return conn; - -} - -inline int csp_conn_dport(csp_conn_t * conn) { - - return conn->idin.dport; - -} - -inline int csp_conn_sport(csp_conn_t * conn) { - - return conn->idin.sport; - -} - -inline int csp_conn_dst(csp_conn_t * conn) { - - return conn->idin.dst; - -} - -inline int csp_conn_src(csp_conn_t * conn) { - - return conn->idin.src; - -} - -inline int csp_conn_flags(csp_conn_t * conn) { - - return conn->idin.flags; - -} - -#ifdef CSP_DEBUG -void csp_conn_print_table(void) { - - int i; - csp_conn_t * conn; - - for (i = 0; i < CSP_CONN_MAX; i++) { - conn = &arr_conn[i]; - printf("[%02u %p] S:%u, %u -> %u, %u -> %u, sock: %p\r\n", - i, conn, conn->state, conn->idin.src, conn->idin.dst, - conn->idin.dport, conn->idin.sport, conn->socket); -#ifdef CSP_USE_RDP - if (conn->idin.flags & CSP_FRDP) - csp_rdp_conn_print(conn); -#endif - } -} - -int csp_conn_print_table_str(char * str_buf, int str_size) { - - int i, start = 0; - csp_conn_t * conn; - char buf[100]; - - /* Display up to 10 connections */ - if (CSP_CONN_MAX - 10 > 0) - start = CSP_CONN_MAX - 10; - - for (i = start; i < CSP_CONN_MAX; i++) { - conn = &arr_conn[i]; - snprintf(buf, sizeof(buf), "[%02u %p] S:%u, %u -> %u, %u -> %u, sock: %p\n", - i, conn, conn->state, conn->idin.src, conn->idin.dst, - conn->idin.dport, conn->idin.sport, conn->socket); - - strncat(str_buf, buf, str_size); - if ((str_size -= strlen(buf)) <= 0) - break; - } - - return CSP_ERR_NONE; -} -#endif - -const csp_conn_t * csp_conn_get_array(size_t * size) -{ - *size = CSP_CONN_MAX; - return arr_conn; -} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_conn.h b/gomspace/libgscsp/lib/libcsp/src/csp_conn.h deleted file mode 100644 index 3fa0ff52..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_conn.h +++ /dev/null @@ -1,112 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_CONN_H_ -#define _CSP_CONN_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include - -#include -#include - -/** @brief Connection states */ -typedef enum { - CONN_CLOSED = 0, - CONN_OPEN = 1, -} csp_conn_state_t; - -/** @brief Connection types */ -typedef enum { - CONN_CLIENT = 0, - CONN_SERVER = 1, -} csp_conn_type_t; - -typedef enum { - RDP_CLOSED = 0, - RDP_SYN_SENT, - RDP_SYN_RCVD, - RDP_OPEN, - RDP_CLOSE_WAIT, -} csp_rdp_state_t; - -/** @brief RDP Connection header - * @note Do not try to pack this struct, the posix sem handle will stop working */ -typedef struct { - csp_rdp_state_t state; /**< Connection state */ - uint16_t snd_nxt; /**< The sequence number of the next segment that is to be sent */ - uint16_t snd_una; /**< The sequence number of the oldest unacknowledged segment */ - uint16_t snd_iss; /**< The initial send sequence number */ - uint16_t rcv_cur; /**< The sequence number of the last segment received correctly and in sequence */ - uint16_t rcv_irs; /**< The initial receive sequence number */ - uint16_t rcv_lsa; /**< The last sequence number acknowledged by the receiver */ - uint32_t window_size; - uint32_t conn_timeout; - uint32_t packet_timeout; - uint32_t delayed_acks; - uint32_t ack_timeout; - uint32_t ack_delay_count; - uint32_t ack_timestamp; - csp_bin_sem_handle_t tx_wait; - csp_queue_handle_t tx_queue; - csp_queue_handle_t rx_queue; -} csp_rdp_t; - -/** @brief Connection struct */ -struct csp_conn_s { - csp_conn_type_t type; /* Connection type (CONN_CLIENT or CONN_SERVER) */ - csp_conn_state_t state; /* Connection state (CONN_OPEN or CONN_CLOSED) */ - csp_mutex_t lock; /* Connection structure lock */ - csp_id_t idin; /* Identifier received */ - csp_id_t idout; /* Identifier transmitted */ -#ifdef CSP_USE_QOS - csp_queue_handle_t rx_event; /* Event queue for RX packets */ -#endif - csp_queue_handle_t rx_queue[CSP_RX_QUEUES]; /* Queue for RX packets */ - csp_queue_handle_t socket; /* Socket to be "woken" when first packet is ready */ - uint32_t timestamp; /* Time the connection was opened */ - uint32_t opts; /* Connection or socket options */ -#ifdef CSP_USE_RDP - csp_rdp_t rdp; /* RDP state */ -#endif -}; - -int csp_conn_lock(csp_conn_t * conn, uint32_t timeout); -int csp_conn_unlock(csp_conn_t * conn); -int csp_conn_enqueue_packet(csp_conn_t * conn, csp_packet_t * packet); -int csp_conn_init(void); -csp_conn_t * csp_conn_allocate(csp_conn_type_t type); -csp_conn_t * csp_conn_find(uint32_t id, uint32_t mask); -csp_conn_t * csp_conn_new(csp_id_t idin, csp_id_t idout); -void csp_conn_check_timeouts(void); -int csp_conn_get_rxq(int prio); - -const csp_conn_t * csp_conn_get_array(size_t * size); // for test purposes only! - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_CONN_H_ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_crc32.c b/gomspace/libgscsp/lib/libcsp/src/csp_crc32.c deleted file mode 100644 index 8bf2145f..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_crc32.c +++ /dev/null @@ -1,140 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include - -#include -#include - -#include - -#ifdef CSP_USE_CRC32 - -#ifdef __AVR__ -#include -static const uint32_t crc_tab[256] PROGMEM = { -#else -static const uint32_t crc_tab[256] = { -#endif - 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, - 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, - 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, - 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, - 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, - 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, - 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, - 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, - 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, - 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, - 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, - 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, - 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, - 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, - 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, - 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, - 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, - 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, - 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, - 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, - 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, - 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, - 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, - 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, - 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, - 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, - 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, - 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, - 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, - 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, - 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, - 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 }; - -uint32_t csp_crc32_memory(const uint8_t * data, uint32_t length) { - uint32_t crc; - - crc = 0xFFFFFFFF; - while (length--) -#ifdef __AVR__ - crc = pgm_read_dword(&crc_tab[(crc ^ *data++) & 0xFFL]) ^ (crc >> 8); -#else - crc = crc_tab[(crc ^ *data++) & 0xFFL] ^ (crc >> 8); -#endif - - return (crc ^ 0xFFFFFFFF); -} - -int csp_crc32_append(csp_packet_t * packet, bool include_header) { - - uint32_t crc; - - /* NULL pointer check */ - if (packet == NULL) - return CSP_ERR_INVAL; - - /* Calculate CRC32, convert to network byte order */ - if (include_header) { - crc = csp_crc32_memory((uint8_t *) &packet->id, packet->length + sizeof(packet->id)); - } else { - crc = csp_crc32_memory(packet->data, packet->length); - } - crc = csp_hton32(crc); - - /* Copy checksum to packet */ - memcpy(&packet->data[packet->length], &crc, sizeof(uint32_t)); - packet->length += sizeof(uint32_t); - - return CSP_ERR_NONE; - -} - -int csp_crc32_verify(csp_packet_t * packet, bool include_header) { - - uint32_t crc; - - /* NULL pointer check */ - if (packet == NULL) - return CSP_ERR_INVAL; - - if (packet->length < sizeof(uint32_t)) - return CSP_ERR_INVAL; - - /* Calculate CRC32, convert to network byte order */ - if (include_header) { - crc = csp_crc32_memory((uint8_t *) &packet->id, packet->length + sizeof(packet->id) - sizeof(uint32_t)); - } else { - crc = csp_crc32_memory(packet->data, packet->length - sizeof(uint32_t)); - } - crc = csp_hton32(crc); - - /* Compare calculated checksum with packet header */ - if (memcmp(&packet->data[packet->length] - sizeof(uint32_t), &crc, sizeof(uint32_t)) != 0) { - /* CRC32 failed */ - return CSP_ERR_INVAL; - } else { - /* Strip CRC32 */ - packet->length -= sizeof(uint32_t); - return CSP_ERR_NONE; - } - -} - -#endif // CSP_USE_CRC32 diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_debug.c b/gomspace/libgscsp/lib/libcsp/src/csp_debug.c deleted file mode 100644 index 2e710cb3..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_debug.c +++ /dev/null @@ -1,133 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include - -#ifdef __AVR__ -#include -#endif - -/* CSP includes */ -#include - -#include - -/* Custom debug function */ -csp_debug_hook_func_t csp_debug_hook_func = NULL; - -/* Debug levels */ -static bool csp_debug_level_enabled[] = { - [CSP_ERROR] = true, - [CSP_WARN] = true, - [CSP_INFO] = false, - [CSP_BUFFER] = false, - [CSP_PACKET] = false, - [CSP_PROTOCOL] = false, - [CSP_LOCK] = false, -}; - -/* Some compilers do not support weak symbols, so this function - * can be used instead to set a custom debug hook */ -void csp_debug_hook_set(csp_debug_hook_func_t f) -{ - csp_debug_hook_func = f; -} - -void do_csp_debug(csp_debug_level_t level, const char *format, ...) -{ - int color = COLOR_RESET; - va_list args; - - /* Don't print anything if log level is disabled */ - if (level > CSP_LOCK || !csp_debug_level_enabled[level]) - return; - - switch(level) { - case CSP_INFO: - color = COLOR_GREEN | COLOR_BOLD; - break; - case CSP_ERROR: - color = COLOR_RED | COLOR_BOLD; - break; - case CSP_WARN: - color = COLOR_YELLOW | COLOR_BOLD; - break; - case CSP_BUFFER: - color = COLOR_MAGENTA; - break; - case CSP_PACKET: - color = COLOR_GREEN; - break; - case CSP_PROTOCOL: - color = COLOR_BLUE; - break; - case CSP_LOCK: - color = COLOR_CYAN; - break; - default: - return; - } - - va_start(args, format); - - /* If csp_debug_hook symbol is defined, pass on the message. - * Otherwise, just print with pretty colors ... */ - if (csp_debug_hook_func) { - csp_debug_hook_func(level, format, args); - } else { - csp_sys_set_color(color); -#ifdef __AVR__ - vfprintf_P(stdout, format, args); -#else - vprintf(format, args); -#endif - printf("\r\n"); - csp_sys_set_color(COLOR_RESET); - } - - va_end(args); -} - -void csp_debug_set_level(csp_debug_level_t level, bool value) -{ - if (level > CSP_LOCK) - return; - csp_debug_level_enabled[level] = value; -} - -int csp_debug_get_level(csp_debug_level_t level) -{ - if (level > CSP_LOCK) - return 0; - return csp_debug_level_enabled[level]; -} - -void csp_debug_toggle_level(csp_debug_level_t level) -{ - if (level > CSP_LOCK) { - printf("Max level is 6\r\n"); - return; - } - csp_debug_level_enabled[level] = (csp_debug_level_enabled[level]) ? false : true; - printf("Level %u: value %u\r\n", level, csp_debug_level_enabled[level]); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_dedup.c b/gomspace/libgscsp/lib/libcsp/src/csp_dedup.c deleted file mode 100644 index d263c7a4..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_dedup.c +++ /dev/null @@ -1,66 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include - -#include -#include -#include - -#include "csp_dedup.h" - -/* Check the last CSP_DEDUP_COUNT packets for duplicates */ -#define CSP_DEDUP_COUNT 16 - -/* Only consider packet a duplicate if received under CSP_DEDUP_WINDOW_MS ago */ -#define CSP_DEDUP_WINDOW_MS 1000 - -/* Store packet CRC's in a ringbuffer */ -static uint32_t csp_dedup_array[CSP_DEDUP_COUNT] = {}; -static uint32_t csp_dedup_timestamp[CSP_DEDUP_COUNT] = {}; -static int csp_dedup_in = 0; - -bool csp_dedup_is_duplicate(csp_packet_t *packet) -{ - /* Calculate CRC32 for packet */ - uint32_t crc = csp_crc32_memory((const uint8_t *) &packet->id, packet->length + sizeof(packet->id)); - - /* Check if we have received this packet before */ - for (int i = 0; i < CSP_DEDUP_COUNT; i++) { - - /* Check for match */ - if (crc == csp_dedup_array[i]) { - - /* Check the timestamp */ - if (csp_get_ms() < csp_dedup_timestamp[i] + CSP_DEDUP_WINDOW_MS) - return true; - } - } - - /* If not, insert packet into duplicate list */ - csp_dedup_array[csp_dedup_in] = crc; - csp_dedup_timestamp[csp_dedup_in] = csp_get_ms(); - csp_dedup_in = (csp_dedup_in + 1) % CSP_DEDUP_COUNT; - - return false; -} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_dedup.h b/gomspace/libgscsp/lib/libcsp/src/csp_dedup.h deleted file mode 100644 index 75a3f124..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_dedup.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef CSP_DEDUP_H_ -#define CSP_DEDUP_H_ - -/** - * Check for a duplicate packet - * @param packet pointer to packet - * @return false if not a duplicate, true if duplicate - */ -bool csp_dedup_is_duplicate(csp_packet_t *packet); - -#endif /* CSP_DEDUP_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_endian.c b/gomspace/libgscsp/lib/libcsp/src/csp_endian.c deleted file mode 100644 index 6d0ef226..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_endian.c +++ /dev/null @@ -1,204 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include - -/* CSP includes */ -#include -#include - -/* Convert 16-bit number from host byte order to network byte order */ -inline uint16_t __attribute__ ((__const__)) csp_hton16(uint16_t h16) { -#ifdef CSP_BIG_ENDIAN - return h16; -#else - return (((h16 & 0xff00) >> 8) | - ((h16 & 0x00ff) << 8)); -#endif -} - -/* Convert 16-bit number from network byte order to host byte order */ -inline uint16_t __attribute__ ((__const__)) csp_ntoh16(uint16_t n16) { - return csp_hton16(n16); -} - -/* Convert 32-bit number from host byte order to network byte order */ -inline uint32_t __attribute__ ((__const__)) csp_hton32(uint32_t h32) { -#ifdef CSP_BIG_ENDIAN - return h32; -#else - return (((h32 & 0xff000000) >> 24) | - ((h32 & 0x000000ff) << 24) | - ((h32 & 0x0000ff00) << 8) | - ((h32 & 0x00ff0000) >> 8)); -#endif -} - -/* Convert 32-bit number from network byte order to host byte order */ -inline uint32_t __attribute__ ((__const__)) csp_ntoh32(uint32_t n32) { - return csp_hton32(n32); -} - -/* Convert 64-bit number from host byte order to network byte order */ -inline uint64_t __attribute__ ((__const__)) csp_hton64(uint64_t h64) { -#ifdef CSP_BIG_ENDIAN - return h64; -#else - return (((h64 & 0xff00000000000000LL) >> 56) | - ((h64 & 0x00000000000000ffLL) << 56) | - ((h64 & 0x00ff000000000000LL) >> 40) | - ((h64 & 0x000000000000ff00LL) << 40) | - ((h64 & 0x0000ff0000000000LL) >> 24) | - ((h64 & 0x0000000000ff0000LL) << 24) | - ((h64 & 0x000000ff00000000LL) >> 8) | - ((h64 & 0x00000000ff000000LL) << 8)); -#endif -} - -/* Convert 64-bit number from host byte order to network byte order */ -inline uint64_t __attribute__ ((__const__)) csp_ntoh64(uint64_t n64) { - return csp_hton64(n64); -} - -/* Convert 16-bit number from host byte order to big endian byte order */ -inline uint16_t __attribute__ ((__const__)) csp_htobe16(uint16_t h16) { - return csp_hton16(h16); -} - -/* Convert 16-bit number from host byte order to little endian byte order */ -inline uint16_t __attribute__ ((__const__)) csp_htole16(uint16_t h16) { -#ifdef CSP_LITTLE_ENDIAN - return h16; -#else - return (((h16 & 0xff00) >> 8) | - ((h16 & 0x00ff) << 8)); -#endif -} - -/* Convert 16-bit number from big endian byte order to little endian byte order */ -inline uint16_t __attribute__ ((__const__)) csp_betoh16(uint16_t be16) { - return csp_ntoh16(be16); -} - -/* Convert 16-bit number from little endian byte order to host byte order */ -inline uint16_t __attribute__ ((__const__)) csp_letoh16(uint16_t le16) { - return csp_htole16(le16); -} - -/* Convert 32-bit number from host byte order to big endian byte order */ -inline uint32_t __attribute__ ((__const__)) csp_htobe32(uint32_t h32) { - return csp_hton32(h32); -} - -/* Convert 32-bit number from little endian byte order to host byte order */ -inline uint32_t __attribute__ ((__const__)) csp_htole32(uint32_t h32) { -#ifdef CSP_LITTLE_ENDIAN - return h32; -#else - return (((h32 & 0xff000000) >> 24) | - ((h32 & 0x000000ff) << 24) | - ((h32 & 0x0000ff00) << 8) | - ((h32 & 0x00ff0000) >> 8)); -#endif -} - -/* Convert 32-bit number from big endian byte order to host byte order */ -inline uint32_t __attribute__ ((__const__)) csp_betoh32(uint32_t be32) { - return csp_ntoh32(be32); -} - -/* Convert 32-bit number from little endian byte order to host byte order */ -inline uint32_t __attribute__ ((__const__)) csp_letoh32(uint32_t le32) { - return csp_htole32(le32); -} - -/* Convert 64-bit number from host byte order to big endian byte order */ -inline uint64_t __attribute__ ((__const__)) csp_htobe64(uint64_t h64) { - return csp_hton64(h64); -} - -/* Convert 64-bit number from host byte order to little endian byte order */ -inline uint64_t __attribute__ ((__const__)) csp_htole64(uint64_t h64) { -#ifdef CSP_LITTLE_ENDIAN - return h64; -#else - return (((h64 & 0xff00000000000000LL) >> 56) | - ((h64 & 0x00000000000000ffLL) << 56) | - ((h64 & 0x00ff000000000000LL) >> 40) | - ((h64 & 0x000000000000ff00LL) << 40) | - ((h64 & 0x0000ff0000000000LL) >> 24) | - ((h64 & 0x0000000000ff0000LL) << 24) | - ((h64 & 0x000000ff00000000LL) >> 8) | - ((h64 & 0x00000000ff000000LL) << 8)); -#endif -} - -/* Convert 64-bit number from big endian byte order to host byte order */ -inline uint64_t __attribute__ ((__const__)) csp_betoh64(uint64_t be64) { - return csp_ntoh64(be64); -} - -/* Convert 64-bit number from little endian byte order to host byte order */ -inline uint64_t __attribute__ ((__const__)) csp_letoh64(uint64_t le64) { - return csp_htole64(le64); -} - - -/* Convert float from host byte order to network byte order */ -inline float __attribute__ ((__const__)) csp_htonflt(float f) { -#ifdef CSP_BIG_ENDIAN - return f; -#else - union v { - float f; - uint32_t i; - }; - union v val; - val.f = f; - val.i = csp_hton32(val.i); - return val.f; -#endif -} - -/* Convert float from host byte order to network byte order */ -inline float __attribute__ ((__const__)) csp_ntohflt(float f) { - return csp_htonflt(f); -} - -/* Convert double from host byte order to network byte order */ -inline double __attribute__ ((__const__)) csp_htondbl(double d) { -#ifdef CSP_BIG_ENDIAN - return d; -#else - union v { - double d; - uint64_t i; - }; - union v val; - val.d = d; - val.i = csp_hton64(val.i); - return val.d; -#endif -} - -/* Convert float from host byte order to network byte order */ -inline double __attribute__ ((__const__)) csp_ntohdbl(double d) { - return csp_htondbl(d); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_hex_dump.c b/gomspace/libgscsp/lib/libcsp/src/csp_hex_dump.c deleted file mode 100644 index af0a2660..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_hex_dump.c +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include - -void csp_hex_dump (const char *desc, void *addr, int len) -{ - int i; - unsigned char buff[17]; - unsigned char *pc = (unsigned char*)addr; - - // Output description if given. - if (desc != NULL) - printf ("%s:\r\n", desc); - - if (len == 0) { - printf(" ZERO LENGTH\r\n"); - return; - } - if (len < 0) { - printf(" NEGATIVE LENGTH: %i\r\n",len); - return; - } - - // Process every byte in the data. - for (i = 0; i < len; i++) { - // Multiple of 16 means new line (with line offset). - - if ((i % 16) == 0) { - // Just don't print ASCII for the zeroth line. - if (i != 0) - printf (" %s\r\n", buff); - - // Output the offset. - printf (" %p ", addr + i); - } - - // Now the hex code for the specific character. - printf (" %02x", pc[i]); - - // And store a printable ASCII character for later. - if ((pc[i] < 0x20) || (pc[i] > 0x7e)) - buff[i % 16] = '.'; - else - buff[i % 16] = pc[i]; - buff[(i % 16) + 1] = '\0'; - } - - // Pad out last line if not exactly 16 characters. - while ((i % 16) != 0) { - printf (" "); - i++; - } - - // And print the final ASCII bit. - printf (" %s\r\n", buff); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_iflist.c b/gomspace/libgscsp/lib/libcsp/src/csp_iflist.c deleted file mode 100644 index 2bfef422..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_iflist.c +++ /dev/null @@ -1,100 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include - -/* Interfaces are stored in a linked list*/ -static csp_iface_t * interfaces = NULL; - -csp_iface_t * csp_iflist_get_by_name(const char *name) { - csp_iface_t *ifc = interfaces; - while(ifc) { - if (strncmp(ifc->name, name, 10) == 0) - break; - ifc = ifc->next; - } - return ifc; -} - -void csp_iflist_add(csp_iface_t *ifc) { - - /* Add interface to pool */ - if (interfaces == NULL) { - /* This is the first interface to be added */ - interfaces = ifc; - ifc->next = NULL; - } else { - /* One or more interfaces were already added */ - csp_iface_t * i = interfaces; - while (i != ifc && i->next) - i = i->next; - - /* Insert interface last if not already in pool */ - if (i != ifc && i->next == NULL) { - i->next = ifc; - ifc->next = NULL; - } - } - -} - -csp_iface_t * csp_iflist_get(void) -{ - return interfaces; -} - -#ifdef CSP_DEBUG -static int csp_bytesize(char *buf, int len, unsigned long int n) { - char postfix; - double size; - - if (n >= 1048576) { - size = n/1048576.0; - postfix = 'M'; - } else if (n >= 1024) { - size = n/1024.; - postfix = 'K'; - } else { - size = n; - postfix = 'B'; - } - - return snprintf(buf, len, "%.1f%c", size, postfix); -} - -void csp_iflist_print(void) { - csp_iface_t * i = interfaces; - char txbuf[25], rxbuf[25]; - - while (i) { - csp_bytesize(txbuf, 25, i->txbytes); - csp_bytesize(rxbuf, 25, i->rxbytes); - printf("%-5s tx: %05"PRIu32" rx: %05"PRIu32" txe: %05"PRIu32" rxe: %05"PRIu32"\r\n" - " drop: %05"PRIu32" autherr: %05"PRIu32 " frame: %05"PRIu32"\r\n" - " txb: %"PRIu32" (%s) rxb: %"PRIu32" (%s)\r\n\r\n", - i->name, i->tx, i->rx, i->tx_error, i->rx_error, i->drop, - i->autherr, i->frame, i->txbytes, txbuf, i->rxbytes, rxbuf); - i = i->next; - } - -} -#endif - diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_io.c b/gomspace/libgscsp/lib/libcsp/src/csp_io.c deleted file mode 100644 index 3d7f614a..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_io.c +++ /dev/null @@ -1,502 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include - -/* CSP includes */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "csp_io.h" -#include "csp_port.h" -#include "csp_conn.h" -#include "csp_route.h" -#include "csp_promisc.h" -#include "csp_qfifo.h" -#include "transport/csp_transport.h" - -/** CSP address of this node */ -static uint8_t csp_my_address; - -/* Hostname, model and build revision */ -static const char *csp_hostname = NULL; -static const char *csp_model = NULL; -static const char *csp_revision = GIT_REV; - -#ifdef CSP_USE_PROMISC -extern csp_queue_handle_t csp_promisc_queue; -#endif - -void csp_set_address(uint8_t addr) -{ - csp_my_address = addr; -} - -uint8_t csp_get_address(void) -{ - return csp_my_address; -} - -void csp_set_hostname(const char *hostname) -{ - csp_hostname = hostname; -} - -const char *csp_get_hostname(void) -{ - return csp_hostname; -} - -void csp_set_model(const char *model) -{ - csp_model = model; -} - -const char *csp_get_model(void) -{ - return csp_model; -} - -void csp_set_revision(const char *revision) -{ - csp_revision = revision; -} - -const char *csp_get_revision(void) -{ - return csp_revision; -} - -int csp_init(unsigned char address) { - - int ret; - - /* Initialize CSP */ - csp_set_address(address); - - ret = csp_conn_init(); - if (ret != CSP_ERR_NONE) - return ret; - - ret = csp_port_init(); - if (ret != CSP_ERR_NONE) - return ret; - - ret = csp_qfifo_init(); - if (ret != CSP_ERR_NONE) - return ret; - - /* Loopback */ - csp_iflist_add(&csp_if_lo); - - /* Register loopback route */ - csp_route_set(csp_get_address(), &csp_if_lo, CSP_NODE_MAC); - - /* Also register loopback as default, until user redefines default route */ - csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_lo, CSP_NODE_MAC); - - return CSP_ERR_NONE; - -} - -csp_socket_t * csp_socket(uint32_t opts) { - - /* Validate socket options */ -#ifndef CSP_USE_RDP - if (opts & CSP_SO_RDPREQ) { - csp_log_error("Attempt to create socket that requires RDP, but CSP was compiled without RDP support"); - return NULL; - } -#endif - -#ifndef CSP_USE_XTEA - if (opts & CSP_SO_XTEAREQ) { - csp_log_error("Attempt to create socket that requires XTEA, but CSP was compiled without XTEA support"); - return NULL; - } -#endif - -#ifndef CSP_USE_HMAC - if (opts & CSP_SO_HMACREQ) { - csp_log_error("Attempt to create socket that requires HMAC, but CSP was compiled without HMAC support"); - return NULL; - } -#endif - -#ifndef CSP_USE_CRC32 - if (opts & CSP_SO_CRC32REQ) { - csp_log_error("Attempt to create socket that requires CRC32, but CSP was compiled without CRC32 support"); - return NULL; - } -#endif - - /* Drop packet if reserved flags are set */ - if (opts & ~(CSP_SO_RDPREQ | CSP_SO_XTEAREQ | CSP_SO_HMACREQ | CSP_SO_CRC32REQ | CSP_SO_CONN_LESS)) { - csp_log_error("Invalid socket option"); - return NULL; - } - - /* Use CSP buffers instead? */ - csp_socket_t * sock = csp_conn_allocate(CONN_SERVER); - if (sock == NULL) - return NULL; - - /* If connectionless, init the queue to a pre-defined size - * if not, the user must init the queue using csp_listen */ - if (opts & CSP_SO_CONN_LESS) { - sock->socket = csp_queue_create(CSP_CONN_QUEUE_LENGTH, sizeof(csp_packet_t *)); - if (sock->socket == NULL) { - csp_close(sock); - return NULL; - } - } else { - sock->socket = NULL; - } - sock->opts = opts; - - return sock; - -} - -csp_conn_t * csp_accept(csp_socket_t * sock, uint32_t timeout) { - - if (sock == NULL) - return NULL; - - if (sock->socket == NULL) - return NULL; - - csp_conn_t * conn; - if (csp_queue_dequeue(sock->socket, &conn, timeout) == CSP_QUEUE_OK) - return conn; - - return NULL; - -} - -csp_packet_t * csp_read(csp_conn_t * conn, uint32_t timeout) { - - csp_packet_t * packet = NULL; - - if (conn == NULL || conn->state != CONN_OPEN) - return NULL; - -#ifdef CSP_USE_QOS - int prio, event; - if (csp_queue_dequeue(conn->rx_event, &event, timeout) != CSP_QUEUE_OK) - return NULL; - - for (prio = 0; prio < CSP_RX_QUEUES; prio++) - if (csp_queue_dequeue(conn->rx_queue[prio], &packet, 0) == CSP_QUEUE_OK) - break; -#else - if (csp_queue_dequeue(conn->rx_queue[0], &packet, timeout) != CSP_QUEUE_OK) - return NULL; -#endif - -#ifdef CSP_USE_RDP - /* Packet read could trigger ACK transmission */ - if (conn->idin.flags & CSP_FRDP && conn->rdp.delayed_acks) - csp_rdp_check_ack(conn); - -#endif - - return packet; - -} - -int csp_send_direct(csp_id_t idout, csp_packet_t * packet, csp_iface_t * ifout, uint32_t timeout) { - - if (packet == NULL) { - csp_log_error("csp_send_direct called with NULL packet"); - goto err; - } - - if ((ifout == NULL) || (ifout->nexthop == NULL)) { - csp_log_error("No route to host: %#08x", idout.ext); - goto err; - } - - csp_log_packet("OUT: S %u, D %u, Dp %u, Sp %u, Pr %u, Fl 0x%02X, Sz %u VIA: %s", - idout.src, idout.dst, idout.dport, idout.sport, idout.pri, idout.flags, packet->length, ifout->name); - - /* Copy identifier to packet (before crc, xtea and hmac) */ - packet->id.ext = idout.ext; - -#ifdef CSP_USE_PROMISC - /* Loopback traffic is added to promisc queue by the router */ - if (idout.dst != csp_get_address() && idout.src == csp_get_address()) { - packet->id.ext = idout.ext; - csp_promisc_add(packet); - } -#endif - - /* Only encrypt packets from the current node */ - if (idout.src == csp_get_address()) { - /* Append HMAC */ - if (idout.flags & CSP_FHMAC) { -#ifdef CSP_USE_HMAC - /* Calculate and add HMAC (does not include header for backwards compatability with csp1.x) */ - if (csp_hmac_append(packet, false) != 0) { - /* HMAC append failed */ - csp_log_warn("HMAC append failed!"); - goto tx_err; - } -#else - csp_log_warn("Attempt to send packet with HMAC, but CSP was compiled without HMAC support. Discarding packet"); - goto tx_err; -#endif - } - - /* Append CRC32 */ - if (idout.flags & CSP_FCRC32) { -#ifdef CSP_USE_CRC32 - /* Calculate and add CRC32 (does not include header for backwards compatability with csp1.x) */ - if (csp_crc32_append(packet, false) != 0) { - /* CRC32 append failed */ - csp_log_warn("CRC32 append failed!"); - goto tx_err; - } -#else - csp_log_warn("Attempt to send packet with CRC32, but CSP was compiled without CRC32 support. Sending without CRC32r"); - idout.flags &= ~(CSP_FCRC32); -#endif - } - - if (idout.flags & CSP_FXTEA) { -#ifdef CSP_USE_XTEA - /* Create nonce */ - uint32_t nonce, nonce_n; - nonce = (uint32_t)rand(); - nonce_n = csp_hton32(nonce); - memcpy(&packet->data[packet->length], &nonce_n, sizeof(nonce_n)); - - /* Create initialization vector */ - uint32_t iv[2] = {nonce, 1}; - - /* Encrypt data */ - if (csp_xtea_encrypt(packet->data, packet->length, iv) != 0) { - /* Encryption failed */ - csp_log_warn("Encryption failed! Discarding packet"); - goto tx_err; - } - - packet->length += sizeof(nonce_n); -#else - csp_log_warn("Attempt to send XTEA encrypted packet, but CSP was compiled without XTEA support. Discarding packet"); - goto tx_err; -#endif - } - } - - /* Store length before passing to interface */ - uint16_t bytes = packet->length; - uint16_t mtu = ifout->mtu; - - if (mtu > 0 && bytes > mtu) - goto tx_err; - - if ((*ifout->nexthop)(ifout, packet, timeout) != CSP_ERR_NONE) - goto tx_err; - - ifout->tx++; - ifout->txbytes += bytes; - return CSP_ERR_NONE; - -tx_err: - ifout->tx_error++; -err: - return CSP_ERR_TX; - -} - -int csp_send(csp_conn_t * conn, csp_packet_t * packet, uint32_t timeout) { - - int ret; - - if ((conn == NULL) || (packet == NULL) || (conn->state != CONN_OPEN)) { - csp_log_error("Invalid call to csp_send"); - return 0; - } - -#ifdef CSP_USE_RDP - if (conn->idout.flags & CSP_FRDP) { - if (csp_rdp_send(conn, packet, timeout) != CSP_ERR_NONE) { - csp_iface_t * ifout = csp_rtable_find_iface(conn->idout.dst); - if (ifout != NULL) - ifout->tx_error++; - csp_log_warn("RDP send failed!"); - return 0; - } - } -#endif - - csp_iface_t * ifout = csp_rtable_find_iface(conn->idout.dst); - ret = csp_send_direct(conn->idout, packet, ifout, timeout); - - return (ret == CSP_ERR_NONE) ? 1 : 0; - -} - -int csp_send_prio(uint8_t prio, csp_conn_t * conn, csp_packet_t * packet, uint32_t timeout) { - conn->idout.pri = prio; - return csp_send(conn, packet, timeout); -} - -int csp_transaction_persistent(csp_conn_t * conn, uint32_t timeout, void * outbuf, int outlen, void * inbuf, int inlen) { - - int size = (inlen > outlen) ? inlen : outlen; - csp_packet_t * packet = csp_buffer_get(size); - if (packet == NULL) - return 0; - - /* Copy the request */ - if (outlen > 0 && outbuf != NULL) - memcpy(packet->data, outbuf, outlen); - packet->length = outlen; - - if (!csp_send(conn, packet, timeout)) { - csp_buffer_free(packet); - return 0; - } - - /* If no reply is expected, return now */ - if (inlen == 0) - return 1; - - packet = csp_read(conn, timeout); - if (packet == NULL) - return 0; - - if ((inlen != -1) && ((int)packet->length != inlen)) { - csp_log_error("Reply length %u expected %u", packet->length, inlen); - csp_buffer_free(packet); - return 0; - } - - memcpy(inbuf, packet->data, packet->length); - int length = packet->length; - csp_buffer_free(packet); - return length; - -} - -int csp_transaction(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, void * outbuf, int outlen, void * inbuf, int inlen) { - return csp_transaction2(prio, dest, port, timeout, outbuf, outlen, inbuf, inlen, 0); -} - -int csp_transaction2(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, void * outbuf, int outlen, void * inbuf, int inlen, uint32_t opts) { - - csp_conn_t * conn = csp_connect(prio, dest, port, 0, opts); - if (conn == NULL) - return 0; - - int status = csp_transaction_persistent(conn, timeout, outbuf, outlen, inbuf, inlen); - - csp_close(conn); - - return status; - -} - -csp_packet_t * csp_recvfrom(csp_socket_t * socket, uint32_t timeout) { - - if ((socket == NULL) || (!(socket->opts & CSP_SO_CONN_LESS))) - return NULL; - - csp_packet_t * packet = NULL; - csp_queue_dequeue(socket->socket, &packet, timeout); - - return packet; - -} - -int csp_sendto(uint8_t prio, uint8_t dest, uint8_t dport, uint8_t src_port, uint32_t opts, csp_packet_t * packet, uint32_t timeout) { - - packet->id.flags = 0; - - if (opts & CSP_O_RDP) { - csp_log_error("Attempt to create RDP packet on connection-less socket"); - return CSP_ERR_INVAL; - } - - if (opts & CSP_O_HMAC) { -#ifdef CSP_USE_HMAC - packet->id.flags |= CSP_FHMAC; -#else - csp_log_error("Attempt to create HMAC authenticated packet, but CSP was compiled without HMAC support"); - return CSP_ERR_NOTSUP; -#endif - } - - if (opts & CSP_O_XTEA) { -#ifdef CSP_USE_XTEA - packet->id.flags |= CSP_FXTEA; -#else - csp_log_error("Attempt to create XTEA encrypted packet, but CSP was compiled without XTEA support"); - return CSP_ERR_NOTSUP; -#endif - } - - if (opts & CSP_O_CRC32) { -#ifdef CSP_USE_CRC32 - packet->id.flags |= CSP_FCRC32; -#else - csp_log_error("Attempt to create CRC32 validated packet, but CSP was compiled without CRC32 support"); - return CSP_ERR_NOTSUP; -#endif - } - - packet->id.dst = dest; - packet->id.dport = dport; - packet->id.src = csp_get_address(); - packet->id.sport = src_port; - packet->id.pri = prio; - - csp_iface_t * ifout = csp_rtable_find_iface(dest); - if (csp_send_direct(packet->id, packet, ifout, timeout) != CSP_ERR_NONE) - return CSP_ERR_NOTSUP; - - return CSP_ERR_NONE; - -} - -int csp_sendto_reply(csp_packet_t * request_packet, csp_packet_t * reply_packet, uint32_t opts, uint32_t timeout) { - if (request_packet == NULL) - return CSP_ERR_INVAL; - - return csp_sendto(request_packet->id.pri, request_packet->id.src, request_packet->id.sport, request_packet->id.dport, opts, reply_packet, timeout); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_io.h b/gomspace/libgscsp/lib/libcsp/src/csp_io.h deleted file mode 100644 index 6ea8dfec..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_io.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_IO_H_ -#define _CSP_IO_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include - -/** - * Function to transmit a frame without an existing connection structure. - * This function is used for stateless transmissions - * @param idout 32bit CSP identifier - * @param packet pointer to packet, - * @param ifout pointer to output interface - * @param timeout a timeout to wait for TX to complete. NOTE: not all underlying drivers supports flow-control. - * @return returns 1 if successful and 0 otherwise. you MUST free the frame yourself if the transmission was not successful. - */ -int csp_send_direct(csp_id_t idout, csp_packet_t * packet, csp_iface_t * ifout, uint32_t timeout); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_IO_H_ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_port.c b/gomspace/libgscsp/lib/libcsp/src/csp_port.c deleted file mode 100644 index 2a4ac2a9..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_port.c +++ /dev/null @@ -1,105 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include - -/* CSP includes */ -#include -#include - -#include -#include -#include - -#include "csp_port.h" -#include "csp_conn.h" - -/* Allocation of ports */ -static csp_port_t ports[CSP_MAX_BIND_PORT + 2]; - -csp_socket_t * csp_port_get_socket(unsigned int port) { - - csp_socket_t * ret = NULL; - - if (port >= CSP_ANY) - return NULL; - - /* Match dport to socket or local "catch all" port number */ - if (ports[port].state == PORT_OPEN) - ret = ports[port].socket; - else if (ports[CSP_ANY].state == PORT_OPEN) - ret = ports[CSP_ANY].socket; - - return ret; - -} - -int csp_port_init(void) { - - memset(ports, PORT_CLOSED, sizeof(csp_port_t) * (CSP_MAX_BIND_PORT + 2)); - - return CSP_ERR_NONE; - -} - -int csp_listen(csp_socket_t * socket, size_t conn_queue_length) { - - if (socket == NULL) - return CSP_ERR_INVAL; - - socket->socket = csp_queue_create(conn_queue_length, sizeof(csp_conn_t *)); - if (socket->socket == NULL) - return CSP_ERR_NOMEM; - - socket->opts |= CSP_SO_INTERNAL_LISTEN; - - return CSP_ERR_NONE; - -} - -int csp_bind(csp_socket_t * socket, uint8_t port) { - - if (socket == NULL) - return CSP_ERR_INVAL; - - if (port > CSP_ANY) { - csp_log_error("Only ports from 0-%u (and CSP_ANY for default) are available for incoming ports", CSP_ANY); - return CSP_ERR_INVAL; - } - - /* Check if port number is valid */ - if (ports[port].state != PORT_CLOSED) { - csp_log_error("Port %d is already in use", port); - return CSP_ERR_USED; - } - - csp_log_info("Binding socket %p to port %u", socket, port); - - /* Save listener */ - ports[port].socket = socket; - ports[port].state = PORT_OPEN; - - return CSP_ERR_NONE; - -} - - diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_port.h b/gomspace/libgscsp/lib/libcsp/src/csp_port.h deleted file mode 100644 index d2ec06e9..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_port.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_PORT_H_ -#define _CSP_PORT_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include - -/** @brief Port states */ -typedef enum { - PORT_CLOSED = 0, - PORT_OPEN = 1, -} csp_port_state_t; - -/** @brief Port struct */ -typedef struct { - csp_port_state_t state; // Port state - csp_socket_t * socket; // New connections are added to this socket's conn queue -} csp_port_t; - -/** - * Init ports array - */ -int csp_port_init(void); - -csp_socket_t * csp_port_get_socket(unsigned int dport); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif // _CSP_PORT_H_ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_promisc.c b/gomspace/libgscsp/lib/libcsp/src/csp_promisc.c deleted file mode 100644 index 5f156c33..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_promisc.c +++ /dev/null @@ -1,82 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include - -#ifdef CSP_USE_PROMISC - -static csp_queue_handle_t csp_promisc_queue = NULL; -static int csp_promisc_enabled = 0; - -int csp_promisc_enable(unsigned int buf_size) { - - /* If queue already initialised */ - if (csp_promisc_queue != NULL) { - csp_promisc_enabled = 1; - return CSP_ERR_NONE; - } - - /* Create packet queue */ - csp_promisc_queue = csp_queue_create(buf_size, sizeof(csp_packet_t *)); - - if (csp_promisc_queue == NULL) - return CSP_ERR_INVAL; - - csp_promisc_enabled = 1; - return CSP_ERR_NONE; - -} - -void csp_promisc_disable(void) { - csp_promisc_enabled = 0; -} - -csp_packet_t * csp_promisc_read(uint32_t timeout) { - - if (csp_promisc_queue == NULL) - return NULL; - - csp_packet_t * packet = NULL; - csp_queue_dequeue(csp_promisc_queue, &packet, timeout); - - return packet; - -} - -void csp_promisc_add(csp_packet_t * packet) { - - if (csp_promisc_enabled == 0) - return; - - if (csp_promisc_queue != NULL) { - /* Make a copy of the message and queue it to the promiscuous task */ - csp_packet_t *packet_copy = csp_buffer_clone(packet); - if (packet_copy != NULL) { - if (csp_queue_enqueue(csp_promisc_queue, &packet_copy, 0) != CSP_QUEUE_OK) { - csp_log_error("Promiscuous mode input queue full"); - csp_buffer_free(packet_copy); - } - } - } - -} - -#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_promisc.h b/gomspace/libgscsp/lib/libcsp/src/csp_promisc.h deleted file mode 100644 index be62edda..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_promisc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 Gomspace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef CSP_PROMISC_H_ -#define CSP_PROMISC_H_ - -/** - * Add packet to promiscuous mode packet queue - * @param packet Packet to add to the queue - */ -void csp_promisc_add(csp_packet_t * packet); - -#endif /* CSP_PROMISC_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c b/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c deleted file mode 100644 index 9329b2ca..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.c +++ /dev/null @@ -1,149 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include "csp_qfifo.h" - -static csp_queue_handle_t qfifo[CSP_ROUTE_FIFOS]; -#ifdef CSP_USE_QOS -static csp_queue_handle_t qfifo_events; -#endif - -int csp_qfifo_init(void) { - int prio; - - /* Create router fifos for each priority */ - for (prio = 0; prio < CSP_ROUTE_FIFOS; prio++) { - if (qfifo[prio] == NULL) { - qfifo[prio] = csp_queue_create(CSP_FIFO_INPUT, sizeof(csp_qfifo_t)); - if (!qfifo[prio]) - return CSP_ERR_NOMEM; - } - } - -#ifdef CSP_USE_QOS - /* Create QoS fifo notification queue */ - qfifo_events = csp_queue_create(CSP_FIFO_INPUT, sizeof(int)); - if (!qfifo_events) - return CSP_ERR_NOMEM; -#endif - - return CSP_ERR_NONE; - -} - -int csp_qfifo_read(csp_qfifo_t * input) { - -#ifdef CSP_USE_QOS - int prio, found, event; - - /* Wait for packet in any queue */ - if (csp_queue_dequeue(qfifo_events, &event, FIFO_TIMEOUT) != CSP_QUEUE_OK) - return CSP_ERR_TIMEDOUT; - - /* Find packet with highest priority */ - found = 0; - for (prio = 0; prio < CSP_ROUTE_FIFOS; prio++) { - if (csp_queue_dequeue(qfifo[prio], input, 0) == CSP_QUEUE_OK) { - found = 1; - break; - } - } - - if (!found) { - csp_log_warn("Spurious wakeup: No packet found"); - return CSP_ERR_TIMEDOUT; - } -#else - if (csp_queue_dequeue(qfifo[0], input, FIFO_TIMEOUT) != CSP_QUEUE_OK) - return CSP_ERR_TIMEDOUT; -#endif - - return CSP_ERR_NONE; - -} - -void csp_qfifo_write(csp_packet_t * packet, csp_iface_t * interface, CSP_BASE_TYPE * pxTaskWoken) { - - int result; - - if (packet == NULL) { - if (pxTaskWoken == NULL) { // Only do logging in non-ISR context - csp_log_warn("csp_new packet called with NULL packet"); - } - return; - } else if (interface == NULL) { - if (pxTaskWoken == NULL) { // Only do logging in non-ISR context - csp_log_warn("csp_new packet called with NULL interface"); - } - if (pxTaskWoken == NULL) - csp_buffer_free(packet); - else - csp_buffer_free_isr(packet); - return; - } - - csp_qfifo_t queue_element; - queue_element.interface = interface; - queue_element.packet = packet; - -#ifdef CSP_USE_QOS - int fifo = packet->id.pri; -#else - int fifo = 0; -#endif - - if (pxTaskWoken == NULL) - result = csp_queue_enqueue(qfifo[fifo], &queue_element, 0); - else - result = csp_queue_enqueue_isr(qfifo[fifo], &queue_element, pxTaskWoken); - -#ifdef CSP_USE_QOS - static int event = 0; - - if (result == CSP_QUEUE_OK) { - if (pxTaskWoken == NULL) - csp_queue_enqueue(qfifo_events, &event, 0); - else - csp_queue_enqueue_isr(qfifo_events, &event, pxTaskWoken); - } -#endif - - if (result != CSP_QUEUE_OK) { - if (pxTaskWoken == NULL) { // Only do logging in non-ISR context - csp_log_warn("ERROR: Routing input FIFO is FULL. Dropping packet."); - } - interface->drop++; - if (pxTaskWoken == NULL) - csp_buffer_free(packet); - else - csp_buffer_free_isr(packet); - } - -} - -void csp_qfifo_wake_up(void) { - csp_qfifo_t queue_element; - queue_element.interface = NULL; - queue_element.packet = NULL; - csp_queue_enqueue(qfifo[0], &queue_element, 0); -} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h b/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h deleted file mode 100644 index 2910c48d..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_qfifo.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef CSP_QFIFO_H_ -#define CSP_QFIFO_H_ - -#ifdef CSP_USE_RDP -#define FIFO_TIMEOUT 100 //! If RDP is enabled, the router needs to awake some times to check timeouts -#else -#define FIFO_TIMEOUT CSP_MAX_DELAY //! If no RDP, the router can sleep untill data arrives -#endif - -/** - * Init FIFO/QOS queues - * @return CSP_ERR type - */ -int csp_qfifo_init(void); - -typedef struct { - csp_iface_t * interface; - csp_packet_t * packet; -} csp_qfifo_t; - -/** - * Read next packet from router input queue - * @param input pointer to router queue item element - * @return CSP_ERR type - */ -int csp_qfifo_read(csp_qfifo_t * input); - -/** - * Wake up any task (e.g. router) waiting on messages. - * For testing. - */ -void csp_qfifo_wake_up(void); - -#endif /* CSP_QFIFO_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_route.c b/gomspace/libgscsp/lib/libcsp/src/csp_route.c deleted file mode 100644 index bc843577..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_route.c +++ /dev/null @@ -1,346 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include - -/* CSP includes */ -#include -#include -#include - -#include -#include - -#include -#include - -#include "csp_port.h" -#include "csp_conn.h" -#include "csp_io.h" -#include "csp_promisc.h" -#include "csp_qfifo.h" -#include "csp_dedup.h" -#include "transport/csp_transport.h" - -/** - * Check supported packet options - * @param interface pointer to incoming interface - * @param packet pointer to packet - * @return CSP_ERR_NONE is all options are supported, CSP_ERR_NOTSUP if not - */ -static int csp_route_check_options(csp_iface_t *interface, csp_packet_t *packet) -{ -#ifndef CSP_USE_XTEA - /* Drop XTEA packets */ - if (packet->id.flags & CSP_FXTEA) { - csp_log_error("Received XTEA encrypted packet, but CSP was compiled without XTEA support. Discarding packet"); - interface->autherr++; - return CSP_ERR_NOTSUP; - } -#endif - -#ifndef CSP_USE_HMAC - /* Drop HMAC packets */ - if (packet->id.flags & CSP_FHMAC) { - csp_log_error("Received packet with HMAC, but CSP was compiled without HMAC support. Discarding packet"); - interface->autherr++; - return CSP_ERR_NOTSUP; - } -#endif - -#ifndef CSP_USE_RDP - /* Drop RDP packets */ - if (packet->id.flags & CSP_FRDP) { - csp_log_error("Received RDP packet, but CSP was compiled without RDP support. Discarding packet"); - interface->rx_error++; - return CSP_ERR_NOTSUP; - } -#endif - return CSP_ERR_NONE; -} - -/** - * Helper function to decrypt, check auth and CRC32 - * @param security_opts either socket_opts or conn_opts - * @param interface pointer to incoming interface - * @param packet pointer to packet - * @return -1 Missing feature, -2 XTEA error, -3 CRC error, -4 HMAC error, 0 = OK. - */ -static int csp_route_security_check(uint32_t security_opts, csp_iface_t * interface, csp_packet_t * packet) { - -#ifdef CSP_USE_XTEA - /* XTEA encrypted packet */ - if (packet->id.flags & CSP_FXTEA) { - /* Read nonce */ - uint32_t nonce; - memcpy(&nonce, &packet->data[packet->length - sizeof(nonce)], sizeof(nonce)); - nonce = csp_ntoh32(nonce); - packet->length -= sizeof(nonce); - - /* Create initialization vector */ - uint32_t iv[2] = {nonce, 1}; - - /* Decrypt data */ - if (csp_xtea_decrypt(packet->data, packet->length, iv) != 0) { - /* Decryption failed */ - csp_log_error("Decryption failed! Discarding packet"); - interface->autherr++; - return CSP_ERR_XTEA; - } - } else if (security_opts & CSP_SO_XTEAREQ) { - csp_log_warn("Received packet without XTEA encryption. Discarding packet"); - interface->autherr++; - return CSP_ERR_XTEA; - } -#endif - - /* CRC32 verified packet */ - if (packet->id.flags & CSP_FCRC32) { -#ifdef CSP_USE_CRC32 - if (packet->length < 4) - csp_log_error("Too short packet for CRC32, %u", packet->length); - /* Verify CRC32 (does not include header for backwards compatability with csp1.x) */ - if (csp_crc32_verify(packet, false) != 0) { - /* Checksum failed */ - csp_log_error("CRC32 verification error! Discarding packet"); - interface->rx_error++; - return CSP_ERR_CRC32; - } - } else if (security_opts & CSP_SO_CRC32REQ) { - csp_log_warn("Received packet without CRC32. Accepting packet"); -#else - /* Strip CRC32 field and accept the packet */ - csp_log_warn("Received packet with CRC32, but CSP was compiled without CRC32 support. Accepting packet"); - packet->length -= sizeof(uint32_t); -#endif - } - -#ifdef CSP_USE_HMAC - /* HMAC authenticated packet */ - if (packet->id.flags & CSP_FHMAC) { - /* Verify HMAC (does not include header for backwards compatability with csp1.x) */ - if (csp_hmac_verify(packet, false) != 0) { - /* HMAC failed */ - csp_log_error("HMAC verification error! Discarding packet"); - interface->autherr++; - return CSP_ERR_HMAC; - } - } else if (security_opts & CSP_SO_HMACREQ) { - csp_log_warn("Received packet without HMAC. Discarding packet"); - interface->autherr++; - return CSP_ERR_HMAC; - } -#endif - -#ifdef CSP_USE_RDP - /* RDP packet */ - if (!(packet->id.flags & CSP_FRDP)) { - if (security_opts & CSP_SO_RDPREQ) { - csp_log_warn("Received packet without RDP header. Discarding packet"); - interface->rx_error++; - return CSP_ERR_INVAL; - } - } -#endif - - return CSP_ERR_NONE; - -} - -int csp_route_work(uint32_t timeout) { - - csp_qfifo_t input; - csp_packet_t * packet; - csp_conn_t * conn; - csp_socket_t * socket; - -#ifdef CSP_USE_RDP - /* Check connection timeouts (currently only for RDP) */ - csp_conn_check_timeouts(); -#endif - - /* Get next packet to route */ - if (csp_qfifo_read(&input) != CSP_ERR_NONE) - return -1; - - packet = input.packet; - if (!packet) - return -1; - - csp_log_packet("INP: S %u, D %u, Dp %u, Sp %u, Pr %u, Fl 0x%02X, Sz %"PRIu16" VIA: %s", - packet->id.src, packet->id.dst, packet->id.dport, - packet->id.sport, packet->id.pri, packet->id.flags, packet->length, input.interface->name); - - /* Here there be promiscuous mode */ -#ifdef CSP_USE_PROMISC - csp_promisc_add(packet); -#endif - -#ifdef CSP_USE_DEDUP - /* Check for duplicates */ - if (csp_dedup_is_duplicate(packet)) { - /* Discard packet */ - csp_log_packet("Duplicate packet discarded"); - input.interface->drop++; - csp_buffer_free(packet); - return 0; - } -#endif - - /* Now we count the message (since its deduplicated) */ - input.interface->rx++; - input.interface->rxbytes += packet->length; - - /* If the message is not to me, route the message to the correct interface */ - if ((packet->id.dst != csp_get_address()) && (packet->id.dst != CSP_BROADCAST_ADDR)) { - - /* Find the destination interface */ - csp_iface_t * dstif = csp_rtable_find_iface(packet->id.dst); - - /* If the message resolves to the input interface, don't loop it back out */ - if ((dstif == NULL) || ((dstif == input.interface) && (input.interface->split_horizon_off == 0))) { - csp_buffer_free(packet); - return 0; - } - - /* Otherwise, actually send the message */ - if (csp_send_direct(packet->id, packet, dstif, 0) != CSP_ERR_NONE) { - csp_log_warn("Router failed to send"); - csp_buffer_free(packet); - } - - /* Next message, please */ - return 0; - } - - /* Discard packets with unsupported options */ - if (csp_route_check_options(input.interface, packet) != CSP_ERR_NONE) { - csp_buffer_free(packet); - return 0; - } - - /* The message is to me, search for incoming socket */ - socket = csp_port_get_socket(packet->id.dport); - - /* If the socket is connection-less, deliver now */ - if (socket && (socket->opts & CSP_SO_CONN_LESS)) { - if (csp_route_security_check(socket->opts, input.interface, packet) < 0) { - csp_buffer_free(packet); - return 0; - } - if (csp_queue_enqueue(socket->socket, &packet, 0) != CSP_QUEUE_OK) { - csp_log_error("Conn-less socket queue full"); - csp_buffer_free(packet); - return 0; - } - return 0; - } - - /* Search for an existing connection */ - conn = csp_conn_find(packet->id.ext, CSP_ID_CONN_MASK); - - /* If this is an incoming packet on a new connection */ - if (conn == NULL) { - - /* Reject packet if no matching socket is found */ - if (!socket) { - csp_buffer_free(packet); - return 0; - } - - /* Run security check on incoming packet */ - if (csp_route_security_check(socket->opts, input.interface, packet) < 0) { - csp_buffer_free(packet); - return 0; - } - - /* New incoming connection accepted */ - csp_id_t idout; - idout.pri = packet->id.pri; - idout.src = csp_get_address(); - - idout.dst = packet->id.src; - idout.dport = packet->id.sport; - idout.sport = packet->id.dport; - idout.flags = packet->id.flags; - - /* Create connection */ - conn = csp_conn_new(packet->id, idout); - - if (!conn) { - csp_log_error("No more connections available"); - csp_buffer_free(packet); - return 0; - } - - /* Store the socket queue and options */ - conn->socket = socket->socket; - conn->opts = socket->opts; - - /* Packet to existing connection */ - } else { - - /* Run security check on incoming packet */ - if (csp_route_security_check(conn->opts, input.interface, packet) < 0) { - csp_buffer_free(packet); - return 0; - } - - } - -#ifdef CSP_USE_RDP - /* Pass packet to RDP module */ - if (packet->id.flags & CSP_FRDP) { - csp_rdp_new_packet(conn, packet); - return 0; - } -#endif - - /* Pass packet to UDP module */ - csp_udp_new_packet(conn, packet); - return 0; -} - -static CSP_DEFINE_TASK(csp_task_router) { - - /* Here there be routing */ - while (1) { - csp_route_work(FIFO_TIMEOUT); - } - - return CSP_TASK_RETURN; - -} - -int csp_route_start_task(unsigned int task_stack_size, unsigned int priority) { - - static csp_thread_handle_t handle_router; - int ret = csp_thread_create(csp_task_router, "RTE", task_stack_size, NULL, priority, &handle_router); - - if (ret != 0) { - csp_log_error("Failed to start router task"); - return CSP_ERR_NOMEM; - } - - return CSP_ERR_NONE; - -} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_route.h b/gomspace/libgscsp/lib/libcsp/src/csp_route.h deleted file mode 100644 index 2a20f49f..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_route.h +++ /dev/null @@ -1,24 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_ROUTE_H_ -#define _CSP_ROUTE_H_ - -#endif // _CSP_ROUTE_H_ diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_service_handler.c b/gomspace/libgscsp/lib/libcsp/src/csp_service_handler.c deleted file mode 100644 index 0090afc1..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_service_handler.c +++ /dev/null @@ -1,334 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include - -/* CSP includes */ -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "csp_route.h" - -#define CSP_RPS_MTU 196 - -/** - * The CSP CMP mempy function is used to, override the function used to - * read/write memory by peek and poke. - */ -#ifdef __AVR__ -static uint32_t wrap_32bit_memcpy(uint32_t to, const uint32_t from, size_t size) { - return (uint32_t) (uintptr_t) memcpy((void *) (uintptr_t) to, (const void *) (uintptr_t) from, size); -} -static csp_memcpy_fnc_t csp_cmp_memcpy_fnc = wrap_32bit_memcpy; -#else -static csp_memcpy_fnc_t csp_cmp_memcpy_fnc = (csp_memcpy_fnc_t) memcpy; -#endif - - -void csp_cmp_set_memcpy(csp_memcpy_fnc_t fnc) { - csp_cmp_memcpy_fnc = fnc; -} - -static int do_cmp_ident(struct csp_cmp_message *cmp) { - - /* Copy revision */ - strncpy(cmp->ident.revision, csp_get_revision(), CSP_CMP_IDENT_REV_LEN); - cmp->ident.revision[CSP_CMP_IDENT_REV_LEN - 1] = '\0'; - - /* Copy compilation date */ - strncpy(cmp->ident.date, __DATE__, CSP_CMP_IDENT_DATE_LEN); - cmp->ident.date[CSP_CMP_IDENT_DATE_LEN - 1] = '\0'; - - /* Copy compilation time */ - strncpy(cmp->ident.time, __TIME__, CSP_CMP_IDENT_TIME_LEN); - cmp->ident.time[CSP_CMP_IDENT_TIME_LEN - 1] = '\0'; - - /* Copy hostname */ - strncpy(cmp->ident.hostname, csp_get_hostname(), CSP_HOSTNAME_LEN); - cmp->ident.hostname[CSP_HOSTNAME_LEN - 1] = '\0'; - - /* Copy model name */ - strncpy(cmp->ident.model, csp_get_model(), CSP_MODEL_LEN); - cmp->ident.model[CSP_MODEL_LEN - 1] = '\0'; - - return CSP_ERR_NONE; - -} - -static int do_cmp_route_set(struct csp_cmp_message *cmp) { - - csp_iface_t *ifc = csp_iflist_get_by_name(cmp->route_set.interface); - if (ifc == NULL) - return CSP_ERR_INVAL; - - if (csp_route_set(cmp->route_set.dest_node, ifc, cmp->route_set.next_hop_mac) != CSP_ERR_NONE) - return CSP_ERR_INVAL; - - return CSP_ERR_NONE; - -} - -static int do_cmp_if_stats(struct csp_cmp_message *cmp) { - - csp_iface_t *ifc = csp_iflist_get_by_name(cmp->if_stats.interface); - if (ifc == NULL) - return CSP_ERR_INVAL; - - cmp->if_stats.tx = csp_hton32(ifc->tx); - cmp->if_stats.rx = csp_hton32(ifc->rx); - cmp->if_stats.tx_error = csp_hton32(ifc->tx_error); - cmp->if_stats.rx_error = csp_hton32(ifc->rx_error); - cmp->if_stats.drop = csp_hton32(ifc->drop); - cmp->if_stats.autherr = csp_hton32(ifc->autherr); - cmp->if_stats.frame = csp_hton32(ifc->frame); - cmp->if_stats.txbytes = csp_hton32(ifc->txbytes); - cmp->if_stats.rxbytes = csp_hton32(ifc->rxbytes); - cmp->if_stats.irq = csp_hton32(ifc->irq); - - return CSP_ERR_NONE; -} - -static int do_cmp_peek(struct csp_cmp_message *cmp) { - - cmp->peek.addr = csp_hton32(cmp->peek.addr); - if (cmp->peek.len > CSP_CMP_PEEK_MAX_LEN) - return CSP_ERR_INVAL; - - /* Dangerous, you better know what you are doing */ - csp_cmp_memcpy_fnc((csp_memptr_t) (uintptr_t) cmp->peek.data, (csp_memptr_t) (unsigned long) cmp->peek.addr, cmp->peek.len); - - return CSP_ERR_NONE; - -} - -static int do_cmp_poke(struct csp_cmp_message *cmp) { - - cmp->poke.addr = csp_hton32(cmp->poke.addr); - if (cmp->poke.len > CSP_CMP_POKE_MAX_LEN) - return CSP_ERR_INVAL; - - /* Extremely dangerous, you better know what you are doing */ - csp_cmp_memcpy_fnc((csp_memptr_t) (unsigned long) cmp->poke.addr, (csp_memptr_t) (uintptr_t) cmp->poke.data, cmp->poke.len); - - return CSP_ERR_NONE; - -} - -static int do_cmp_clock(struct csp_cmp_message *cmp) { - - cmp->clock.tv_sec = csp_ntoh32(cmp->clock.tv_sec); - cmp->clock.tv_nsec = csp_ntoh32(cmp->clock.tv_nsec); - - if ((cmp->clock.tv_sec != 0) && (clock_set_time != NULL)) { - clock_set_time(&cmp->clock); - } - - if (clock_get_time != NULL) { - clock_get_time(&cmp->clock); - } - - cmp->clock.tv_sec = csp_hton32(cmp->clock.tv_sec); - cmp->clock.tv_nsec = csp_hton32(cmp->clock.tv_nsec); - return CSP_ERR_NONE; - -} - -/* CSP Management Protocol handler */ -static int csp_cmp_handler(csp_conn_t * conn, csp_packet_t * packet) { - - int ret = CSP_ERR_INVAL; - struct csp_cmp_message * cmp = (struct csp_cmp_message *) packet->data; - - /* Ignore everything but requests */ - if (cmp->type != CSP_CMP_REQUEST) - return ret; - - switch (cmp->code) { - case CSP_CMP_IDENT: - ret = do_cmp_ident(cmp); - packet->length = CMP_SIZE(ident); - break; - - case CSP_CMP_ROUTE_SET: - ret = do_cmp_route_set(cmp); - packet->length = CMP_SIZE(route_set); - break; - - case CSP_CMP_IF_STATS: - ret = do_cmp_if_stats(cmp); - packet->length = CMP_SIZE(if_stats); - break; - - case CSP_CMP_PEEK: - ret = do_cmp_peek(cmp); - break; - - case CSP_CMP_POKE: - ret = do_cmp_poke(cmp); - break; - - case CSP_CMP_CLOCK: - ret = do_cmp_clock(cmp); - break; - - default: - ret = CSP_ERR_INVAL; - break; - } - - cmp->type = CSP_CMP_REPLY; - - return ret; -} - -void csp_service_handler(csp_conn_t * conn, csp_packet_t * packet) { - - switch (csp_conn_dport(conn)) { - - case CSP_CMP: - /* Pass to CMP handler */ - if (csp_cmp_handler(conn, packet) != CSP_ERR_NONE) { - csp_buffer_free(packet); - return; - } - break; - - case CSP_PING: - /* A ping means, just echo the packet, so no changes */ - csp_log_info("SERVICE: Ping received"); - break; - - case CSP_PS: { - /* Sanity check on request */ - if ((packet->length != 1) || (packet->data[0] != 0x55)) { - /* Sanity check failed */ - csp_buffer_free(packet); - /* Clear the packet, it has been freed */ - packet = NULL; - break; - } - /* Start by allocating just the right amount of memory */ - int task_list_size = csp_sys_tasklist_size(); - char * pslist = csp_malloc(task_list_size); - /* Check for malloc fail */ - if (pslist == NULL) { - /* Send out the data */ - strcpy((char *)packet->data, "Not enough memory"); - packet->length = strlen((char *)packet->data); - /* Break and let the default handling send packet */ - break; - } - - /* Retrieve the tasklist */ - csp_sys_tasklist(pslist); - int pslen = strnlen(pslist, task_list_size); - - /* Split the potentially very long string into packets */ - int i = 0; - while(i < pslen) { - - /* Allocate packet buffer, if need be */ - if (packet == NULL) - packet = csp_buffer_get(CSP_RPS_MTU); - if (packet == NULL) - break; - - /* Calculate length, either full MTU or the remainder */ - packet->length = (pslen - i > CSP_RPS_MTU) ? CSP_RPS_MTU : (pslen - i); - - /* Send out the data */ - memcpy(packet->data, &pslist[i], packet->length); - i += packet->length; - if (!csp_send(conn, packet, 0)) - csp_buffer_free(packet); - - /* Clear the packet reference when sent */ - packet = NULL; - - } - csp_free(pslist); - break; - } - - case CSP_MEMFREE: { - uint32_t total = csp_sys_memfree(); - - total = csp_hton32(total); - memcpy(packet->data, &total, sizeof(total)); - packet->length = sizeof(total); - - break; - } - - case CSP_REBOOT: { - uint32_t magic_word; - memcpy(&magic_word, packet->data, sizeof(magic_word)); - - magic_word = csp_ntoh32(magic_word); - - /* If the magic word is valid, reboot */ - if (magic_word == CSP_REBOOT_MAGIC) { - csp_sys_reboot(); - } else if (magic_word == CSP_REBOOT_SHUTDOWN_MAGIC) { - csp_sys_shutdown(); - } - - - - csp_buffer_free(packet); - return; - } - - case CSP_BUF_FREE: { - uint32_t size = csp_buffer_remaining(); - size = csp_hton32(size); - memcpy(packet->data, &size, sizeof(size)); - packet->length = sizeof(size); - break; - } - - case CSP_UPTIME: { - uint32_t time = csp_get_s(); - time = csp_hton32(time); - memcpy(packet->data, &time, sizeof(time)); - packet->length = sizeof(time); - break; - } - - default: - csp_buffer_free(packet); - return; - } - - if (packet != NULL) { - if (!csp_send(conn, packet, 0)) - csp_buffer_free(packet); - } - -} diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_services.c b/gomspace/libgscsp/lib/libcsp/src/csp_services.c deleted file mode 100644 index 5392cb82..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_services.c +++ /dev/null @@ -1,233 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include - -/* CSP includes */ -#include -#include -#include - -#include - -int csp_ping(uint8_t node, uint32_t timeout, unsigned int size, uint8_t conn_options) { - - unsigned int i; - uint32_t start, time, status = 0; - - /* Counter */ - start = csp_get_ms(); - - /* Open connection */ - csp_conn_t * conn = csp_connect(CSP_PRIO_NORM, node, CSP_PING, timeout, conn_options); - if (conn == NULL) - return -1; - - /* Prepare data */ - csp_packet_t * packet; - packet = csp_buffer_get(size); - if (packet == NULL) - goto out; - - /* Set data to increasing numbers */ - packet->length = size; - for (i = 0; i < size; i++) - packet->data[i] = i; - - /* Try to send frame */ - if (!csp_send(conn, packet, 0)) - goto out; - - /* Read incoming frame */ - packet = csp_read(conn, timeout); - if (packet == NULL) - goto out; - - /* Ensure that the data was actually echoed */ - for (i = 0; i < size; i++) - if (packet->data[i] != i % (0xff + 1)) - goto out; - - status = 1; - -out: - /* Clean up */ - if (packet != NULL) - csp_buffer_free(packet); - csp_close(conn); - - /* We have a reply */ - time = (csp_get_ms() - start); - - if (status) { - return time; - } else { - return -1; - } - -} - -void csp_ping_noreply(uint8_t node) { - - /* Prepare data */ - csp_packet_t * packet; - packet = csp_buffer_get(1); - - /* Check malloc */ - if (packet == NULL) - return; - - /* Open connection */ - csp_conn_t * conn = csp_connect(CSP_PRIO_NORM, node, CSP_PING, 0, 0); - if (conn == NULL) { - csp_buffer_free(packet); - return; - } - - packet->data[0] = 0x55; - packet->length = 1; - - printf("Ping ignore reply node %u.\r\n", (unsigned int) node); - - /* Try to send frame */ - if (!csp_send(conn, packet, 0)) - csp_buffer_free(packet); - - csp_close(conn); - -} - -void csp_reboot(uint8_t node) { - uint32_t magic_word = csp_hton32(CSP_REBOOT_MAGIC); - csp_transaction(CSP_PRIO_NORM, node, CSP_REBOOT, 0, &magic_word, sizeof(magic_word), NULL, 0); -} - -void csp_shutdown(uint8_t node) { - uint32_t magic_word = csp_hton32(CSP_REBOOT_SHUTDOWN_MAGIC); - csp_transaction(CSP_PRIO_NORM, node, CSP_REBOOT, 0, &magic_word, sizeof(magic_word), NULL, 0); -} - -void csp_ps(uint8_t node, uint32_t timeout) { - - /* Open connection */ - csp_conn_t * conn = csp_connect(CSP_PRIO_NORM, node, CSP_PS, 0, 0); - if (conn == NULL) - return; - - /* Prepare data */ - csp_packet_t * packet; - packet = csp_buffer_get(95); - - /* Check malloc */ - if (packet == NULL) - goto out; - - packet->data[0] = 0x55; - packet->length = 1; - - printf("PS node %u: \r\n", (unsigned int) node); - - /* Try to send frame */ - if (!csp_send(conn, packet, 0)) - goto out; - - while(1) { - - /* Read incoming frame */ - packet = csp_read(conn, timeout); - if (packet == NULL) - break; - - /* We have a reply, add our own NULL char */ - packet->data[packet->length] = 0; - printf("%s", packet->data); - - /* Each packet from csp_read must to be freed by user */ - csp_buffer_free(packet); - } - - printf("\r\n"); - - /* Clean up */ -out: - if (packet != NULL) - csp_buffer_free(packet); - csp_close(conn); - -} - -void csp_memfree(uint8_t node, uint32_t timeout) { - - uint32_t memfree; - - int status = csp_transaction(CSP_PRIO_NORM, node, CSP_MEMFREE, timeout, NULL, 0, &memfree, sizeof(memfree)); - if (status == 0) { - printf("Network error\r\n"); - return; - } - - /* Convert from network to host order */ - memfree = csp_ntoh32(memfree); - - printf("Free Memory at node %u is %"PRIu32" bytes\r\n", (unsigned int) node, memfree); - -} - -void csp_buf_free(uint8_t node, uint32_t timeout) { - - uint32_t size = 0; - - int status = csp_transaction(CSP_PRIO_NORM, node, CSP_BUF_FREE, timeout, NULL, 0, &size, sizeof(size)); - if (status == 0) { - printf("Network error\r\n"); - return; - } - size = csp_ntoh32(size); - printf("Free buffers at node %u is %"PRIu32"\r\n", (unsigned int) node, size); - -} - -void csp_uptime(uint8_t node, uint32_t timeout) { - - uint32_t uptime = 0; - - int status = csp_transaction(CSP_PRIO_NORM, node, CSP_UPTIME, timeout, NULL, 0, &uptime, sizeof(uptime)); - if (status == 0) { - printf("Network error\r\n"); - return; - } - uptime = csp_ntoh32(uptime); - printf("Uptime of node %u is %"PRIu32" s\r\n", (unsigned int) node, uptime); - -} - -int csp_cmp(uint8_t node, uint32_t timeout, uint8_t code, int membsize, struct csp_cmp_message * msg) { - msg->type = CSP_CMP_REQUEST; - msg->code = code; - int status = csp_transaction(CSP_PRIO_NORM, node, CSP_CMP, timeout, msg, membsize, msg, membsize); - if (status == 0) - return CSP_ERR_TIMEDOUT; - - return CSP_ERR_NONE; -} - diff --git a/gomspace/libgscsp/lib/libcsp/src/csp_sfp.c b/gomspace/libgscsp/lib/libcsp/src/csp_sfp.c deleted file mode 100644 index 96ef36e1..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/csp_sfp.c +++ /dev/null @@ -1,170 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include -#include -#include "csp_conn.h" - -typedef struct __attribute__((__packed__)) { - uint32_t offset; - uint32_t totalsize; -} sfp_header_t; - -/** - * SFP Headers: - * The following functions are helper functions that handles the extra SFP - * information that needs to be appended to all data packets. - */ -static sfp_header_t * csp_sfp_header_add(csp_packet_t * packet) { - sfp_header_t * header = (sfp_header_t *) &packet->data[packet->length]; - packet->length += sizeof(sfp_header_t); - memset(header, 0, sizeof(sfp_header_t)); - return header; -} - -static sfp_header_t * csp_sfp_header_remove(csp_packet_t * packet) { - sfp_header_t * header = (sfp_header_t *) &packet->data[packet->length-sizeof(sfp_header_t)]; - packet->length -= sizeof(sfp_header_t); - return header; -} - -int csp_sfp_send_own_memcpy(csp_conn_t * conn, const void * data, int totalsize, int mtu, uint32_t timeout, void * (*memcpyfcn)(void *, const void *, size_t)) { - - int count = 0; - while(count < totalsize) { - - /* Allocate packet */ - csp_packet_t * packet = csp_buffer_get(mtu); - if (packet == NULL) - return -1; - - /* Calculate sending size */ - int size = totalsize - count; - if (size > mtu) - size = mtu; - - /* Print debug */ - csp_debug(CSP_PROTOCOL, "Sending SFP at %x size %u", data + count, size); - - /* Copy data */ - (*memcpyfcn)(packet->data, data + count, size); - packet->length = size; - - /* Set fragment flag */ - conn->idout.flags |= CSP_FFRAG; - - /* Add SFP header */ - sfp_header_t * sfp_header = csp_sfp_header_add(packet); - sfp_header->totalsize = csp_hton32(totalsize); - sfp_header->offset = csp_hton32(count); - - /* Send data */ - if (!csp_send(conn, packet, timeout)) { - csp_buffer_free(packet); - return -1; - } - - /* Increment count */ - count += size; - - } - - return 0; - -} - -int csp_sfp_send(csp_conn_t * conn, const void * data, int totalsize, int mtu, uint32_t timeout) { - return csp_sfp_send_own_memcpy(conn, data, totalsize, mtu, timeout, &memcpy); -} - -int csp_sfp_recv_fp(csp_conn_t * conn, void ** dataout, int * datasize, uint32_t timeout, csp_packet_t * first_packet) { - - unsigned int last_byte = 0; - - *dataout = NULL; /* Allow caller to assume csp_free() can always be called when dataout is non-NULL */ - - /* Get first packet from user, or from connection */ - csp_packet_t * packet = NULL; - if (first_packet == NULL) { - packet = csp_read(conn, timeout); - if (packet == NULL) - return -1; - } else { - packet = first_packet; - } - - do { - - /* Check that SFP header is present */ - if ((packet->id.flags & CSP_FFRAG) == 0) { - csp_debug(CSP_ERROR, "Missing SFP header"); - csp_buffer_free(packet); - return -1; - } - - /* Read SFP header */ - sfp_header_t * sfp_header = csp_sfp_header_remove(packet); - sfp_header->offset = csp_ntoh32(sfp_header->offset); - sfp_header->totalsize = csp_ntoh32(sfp_header->totalsize); - - csp_debug(CSP_PROTOCOL, "SFP fragment %u/%u", sfp_header->offset + packet->length, sfp_header->totalsize); - - if (sfp_header->offset > last_byte + 1) { - csp_debug(CSP_ERROR, "SFP missing %u bytes", sfp_header->offset - last_byte); - csp_buffer_free(packet); - return -1; - } else { - last_byte = sfp_header->offset + packet->length; - } - - /* Allocate memory */ - if (*dataout == NULL) - *dataout = csp_malloc(sfp_header->totalsize); - if (*dataout == NULL) { - csp_debug(CSP_ERROR, "No dyn-memory for SFP fragment"); - csp_buffer_free(packet); - return -1; - } - - /* Copy data to output */ - *datasize = sfp_header->totalsize; - memcpy(*dataout + sfp_header->offset, packet->data, packet->length); - - if (sfp_header->offset + packet->length >= sfp_header->totalsize) { - csp_debug(CSP_PROTOCOL, "SFP complete"); - csp_buffer_free(packet); - return 0; - } else { - csp_buffer_free(packet); - } - - } while((packet = csp_read(conn, timeout)) != NULL); - - return -1; - -} - -int csp_sfp_recv(csp_conn_t * conn, void ** dataout, int * datasize, uint32_t timeout) { - return csp_sfp_recv_fp(conn, dataout, datasize, timeout, NULL); -} - diff --git a/gomspace/libgscsp/lib/libcsp/src/drivers/can/can_socketcan.c b/gomspace/libgscsp/lib/libcsp/src/drivers/can/can_socketcan.c deleted file mode 100644 index 7d12f184..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/drivers/can/can_socketcan.c +++ /dev/null @@ -1,201 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* SocketCAN driver */ -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#ifdef CSP_HAVE_LIBSOCKETCAN -#include -#endif - -static struct can_socketcan_s { - int socket; - csp_iface_t interface; -} socketcan[1] = { - { - .interface = { - .name = "CAN", - .nexthop = csp_can_tx, - .mtu = CSP_CAN_MTU, - .driver = &socketcan[0], - }, - }, -}; - -static void * socketcan_rx_thread(void * parameters) -{ - struct can_frame frame; - int nbytes; - - while (1) { - /* Read CAN frame */ - nbytes = read(socketcan[0].socket, &frame, sizeof(frame)); - if (nbytes < 0) { - csp_log_error("read: %s", strerror(errno)); - continue; - } - - if (nbytes != sizeof(frame)) { - csp_log_warn("Read incomplete CAN frame"); - continue; - } - - /* Frame type */ - if (frame.can_id & (CAN_ERR_FLAG | CAN_RTR_FLAG) || !(frame.can_id & CAN_EFF_FLAG)) { - /* Drop error and remote frames */ - csp_log_warn("Discarding ERR/RTR/SFF frame"); - continue; - } - - /* Strip flags */ - frame.can_id &= CAN_EFF_MASK; - - /* Call RX callbacsp_can_rx_frameck */ - csp_can_rx(&socketcan[0].interface, frame.can_id, frame.data, frame.can_dlc, NULL); - } - - /* We should never reach this point */ - pthread_exit(NULL); -} - - -int csp_can_tx_frame(csp_iface_t *interface, uint32_t id, const uint8_t * data, uint8_t dlc) -{ - struct can_frame frame; - int i, tries = 0; - memset(&frame, 0, sizeof(frame)); - if (dlc > 8) - return -1; - - /* Copy identifier */ - frame.can_id = id | CAN_EFF_FLAG; - - /* Copy data to frame */ - for (i = 0; i < dlc; i++) - frame.data[i] = data[i]; - - /* Set DLC */ - frame.can_dlc = dlc; - - /* Send frame */ - while (write(socketcan[0].socket, &frame, sizeof(frame)) != sizeof(frame)) { - if (++tries < 1000 && errno == ENOBUFS) { - /* Wait 10 ms and try again */ - usleep(10000); - } else { - csp_log_error("write: %s", strerror(errno)); - break; - } - } - - return 0; -} - -csp_iface_t * csp_can_socketcan_init(const char * ifc, int bitrate, int promisc) -{ - struct ifreq ifr; - struct sockaddr_can addr; - pthread_t rx_thread; - - printf("Init can interface %s\n", ifc); - -#ifdef CSP_HAVE_LIBSOCKETCAN - /* Set interface up */ - if (bitrate > 0) { - can_do_stop(ifc); - can_set_bitrate(ifc, bitrate); - can_set_restart_ms(ifc, 100); - can_do_start(ifc); - } -#endif - - /* Create socket */ - if ((socketcan[0].socket = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { - csp_log_error("socket: %s", strerror(errno)); - return NULL; - } - - /* Locate interface */ - strncpy(ifr.ifr_name, ifc, IFNAMSIZ - 1); - if (ioctl(socketcan[0].socket, SIOCGIFINDEX, &ifr) < 0) { - csp_log_error("ioctl: %s", strerror(errno)); - return NULL; - } - memset(&addr, 0, sizeof(addr)); - /* Bind the socket to CAN interface */ - addr.can_family = AF_CAN; - addr.can_ifindex = ifr.ifr_ifindex; - if (bind(socketcan[0].socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - csp_log_error("bind: %s", strerror(errno)); - return NULL; - } - - /* Set filter mode */ - if (promisc == 0) { - - struct can_filter filter; - filter.can_id = CFP_MAKE_DST(csp_get_address()); - filter.can_mask = CFP_MAKE_DST((1 << CFP_HOST_SIZE) - 1); - - if (setsockopt(socketcan[0].socket, SOL_CAN_RAW, CAN_RAW_FILTER, &filter, sizeof(filter)) < 0) { - csp_log_error("setsockopt: %s", strerror(errno)); - return NULL; - } - - } - - /* Create receive thread */ - if (pthread_create(&rx_thread, NULL, socketcan_rx_thread, NULL) != 0) { - csp_log_error("pthread_create: %s", strerror(errno)); - return NULL; - } - - csp_iflist_add(&socketcan[0].interface); - - return &socketcan[0].interface; -} diff --git a/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_linux.c b/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_linux.c deleted file mode 100644 index c4ceeb27..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_linux.c +++ /dev/null @@ -1,254 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -int fd; -usart_callback_t usart_callback = NULL; - -static void *serial_rx_thread(void *vptr_args); - -int getbaud(int ifd) { - struct termios termAttr; - int inputSpeed = -1; - speed_t baudRate; - tcgetattr(ifd, &termAttr); - /* Get the input speed. */ - baudRate = cfgetispeed(&termAttr); - switch (baudRate) { - case B0: - inputSpeed = 0; - break; - case B50: - inputSpeed = 50; - break; - case B110: - inputSpeed = 110; - break; - case B134: - inputSpeed = 134; - break; - case B150: - inputSpeed = 150; - break; - case B200: - inputSpeed = 200; - break; - case B300: - inputSpeed = 300; - break; - case B600: - inputSpeed = 600; - break; - case B1200: - inputSpeed = 1200; - break; - case B1800: - inputSpeed = 1800; - break; - case B2400: - inputSpeed = 2400; - break; - case B4800: - inputSpeed = 4800; - break; - case B9600: - inputSpeed = 9600; - break; - case B19200: - inputSpeed = 19200; - break; - case B38400: - inputSpeed = 38400; - break; - case B57600: - inputSpeed = 57600; - break; - case B115200: - inputSpeed = 115200; - break; - case B230400: - inputSpeed = 230400; - break; -#ifndef CSP_MACOSX - case B460800: - inputSpeed = 460800; - break; - case B500000: - inputSpeed = 500000; - break; - case B576000: - inputSpeed = 576000; - break; - case B921600: - inputSpeed = 921600; - break; - case B1000000: - inputSpeed = 1000000; - break; - case B1152000: - inputSpeed = 1152000; - break; - case B1500000: - inputSpeed = 1500000; - break; - case B2000000: - inputSpeed = 2000000; - break; - case B2500000: - inputSpeed = 2500000; - break; - case B3000000: - inputSpeed = 3000000; - break; - case B3500000: - inputSpeed = 3500000; - break; - case B4000000: - inputSpeed = 4000000; - break; -#endif - } - - return inputSpeed; - -} - -void usart_init(struct usart_conf * conf) { - - struct termios options; - pthread_t rx_thread; - - fd = open(conf->device, O_RDWR | O_NOCTTY | O_NONBLOCK); - - if (fd < 0) { - printf("Failed to open %s: %s\r\n", conf->device, strerror(errno)); - return; - } - - int brate = 0; - switch(conf->baudrate) { - case 4800: brate=B4800; break; - case 9600: brate=B9600; break; - case 19200: brate=B19200; break; - case 38400: brate=B38400; break; - case 57600: brate=B57600; break; - case 115200: brate=B115200; break; - case 230400: brate=B230400; break; -#ifndef CSP_MACOSX - case 460800: brate=B460800; break; - case 500000: brate=B500000; break; - case 576000: brate=B576000; break; - case 921600: brate=B921600; break; - case 1000000: brate=B1000000; break; - case 1152000: brate=B1152000; break; - case 1500000: brate=B1500000; break; - case 2000000: brate=B2000000; break; - case 2500000: brate=B2500000; break; - case 3000000: brate=B3000000; break; - case 3500000: brate=B3500000; break; - case 4000000: brate=B4000000; break; -#endif - default: - printf("Unsupported baudrate requested, defaulting to 500000, requested baudrate=%u\n", conf->baudrate); - brate=B500000; - break; - } - - tcgetattr(fd, &options); - cfsetispeed(&options, brate); - cfsetospeed(&options, brate); - options.c_cflag |= (CLOCAL | CREAD); - options.c_cflag &= ~PARENB; - options.c_cflag &= ~CSTOPB; - options.c_cflag &= ~CSIZE; - options.c_cflag |= CS8; - options.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); - options.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | PARMRK | INPCK | ISTRIP | IXON); - options.c_oflag &= ~(OCRNL | ONLCR | ONLRET | ONOCR | OFILL | OPOST); - options.c_cc[VTIME] = 0; - options.c_cc[VMIN] = 1; - tcsetattr(fd, TCSANOW, &options); - if (tcgetattr(fd, &options) == -1) - perror("error setting options"); - fcntl(fd, F_SETFL, 0); - - /* Flush old transmissions */ - if (tcflush(fd, TCIOFLUSH) == -1) - printf("Error flushing serial port - %s(%d).\n", strerror(errno), errno); - - if (pthread_create(&rx_thread, NULL, serial_rx_thread, NULL) != 0) - return; - -} - -void usart_set_callback(usart_callback_t callback) { - usart_callback = callback; -} - -void usart_insert(char c, void * pxTaskWoken) { - printf("%c", c); -} - -void usart_putstr(char * buf, int len) { - if (write(fd, buf, len) != len) - return; -} - -void usart_putc(char c) { - if (write(fd, &c, 1) != 1) - return; -} - -char usart_getc(void) { - char c; - if (read(fd, &c, 1) != 1) return 0; - return c; -} - -static void *serial_rx_thread(void *vptr_args) { - unsigned int length; - uint8_t * cbuf = malloc(100000); - - // Receive loop - while (1) { - length = read(fd, cbuf, 300); - if (length <= 0) { - perror("Error: "); - exit(1); - } - if (usart_callback) - usart_callback(cbuf, length, NULL); - } - return NULL; -} diff --git a/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_windows.c b/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_windows.c deleted file mode 100644 index 91ffe87d..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/drivers/usart/usart_windows.c +++ /dev/null @@ -1,230 +0,0 @@ -#include -#include -#include - -#include -#include - -static HANDLE portHandle = INVALID_HANDLE_VALUE; -static HANDLE rxThread = INVALID_HANDLE_VALUE; -static CRITICAL_SECTION txSection; -static LONG isListening = 0; -static usart_callback_t usart_callback = NULL; - -static void prvSendData(char *buf, int bufsz); -static int prvTryOpenPort(const char* intf); -static int prvTryConfigurePort(const struct usart_conf*); -static int prvTrySetPortTimeouts(void); -static const char* prvParityToStr(BYTE paritySetting); - -#ifdef CSP_DEBUG -static void prvPrintError(void) { - char *messageBuffer = NULL; - DWORD errorCode = GetLastError(); - DWORD formatMessageRet; - formatMessageRet = FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - errorCode, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (char*)&messageBuffer, - 0, - NULL); - - if( !formatMessageRet ) { - csp_log_error("FormatMessage error, code: %lu", GetLastError()); - return; - } - csp_log_error("%s", messageBuffer); - LocalFree(messageBuffer); -} -#endif - -#ifdef CSP_DEBUG -#define printError() prvPrintError() -#else -#define printError() do {} while(0) -#endif - -static int prvTryOpenPort(const char *intf) { - portHandle = CreateFileA( - intf, - GENERIC_READ|GENERIC_WRITE, - 0, - NULL, - OPEN_EXISTING, - 0, - NULL); - - if( portHandle == INVALID_HANDLE_VALUE ) { - DWORD errorCode = GetLastError(); - if( errorCode == ERROR_FILE_NOT_FOUND ) { - csp_log_error("Could not open serial port, because it didn't exist!"); - } - else - csp_log_error("Failure opening serial port! Code: %lu", errorCode); - return 1; - } - return 0; -} - -static int prvTryConfigurePort(const struct usart_conf * conf) { - DCB portSettings = {0}; - portSettings.DCBlength = sizeof(DCB); - if(!GetCommState(portHandle, &portSettings) ) { - csp_log_error("Could not get default settings for open COM port! Code: %lu", GetLastError()); - return -1; - } - portSettings.BaudRate = conf->baudrate; - portSettings.Parity = conf->paritysetting; - portSettings.StopBits = conf->stopbits; - portSettings.fParity = conf->checkparity; - portSettings.fBinary = TRUE; - portSettings.ByteSize = conf->databits; - if( !SetCommState(portHandle, &portSettings) ) { - csp_log_error("Error when setting COM port settings! Code:%lu", GetLastError()); - return 1; - } - - GetCommState(portHandle, &portSettings); - - csp_log_info("Port: %s, Baudrate: %lu, Data bits: %d, Stop bits: %d, Parity: %s", - conf->device, conf->baudrate, conf->databits, conf->stopbits, prvParityToStr(conf->paritysetting)); - return 0; -} - -static const char* prvParityToStr(BYTE paritySetting) { - static const char *parityStr[] = { - "None", - "Odd", - "Even", - "N/A" - }; - char const *resultStr = NULL; - - switch(paritySetting) { - case NOPARITY: - resultStr = parityStr[0]; - break; - case ODDPARITY: - resultStr = parityStr[1]; - break; - case EVENPARITY: - resultStr = parityStr[2]; - break; - default: - resultStr = parityStr[3]; - }; - return resultStr; -} - -static int prvTrySetPortTimeouts(void) { - COMMTIMEOUTS timeouts = {0}; - - if( !GetCommTimeouts(portHandle, &timeouts) ) { - csp_log_error("Error gettings current timeout settings"); - return 1; - } - - timeouts.ReadIntervalTimeout = 5; - timeouts.ReadTotalTimeoutMultiplier = 1; - timeouts.ReadTotalTimeoutConstant = 5; - timeouts.WriteTotalTimeoutMultiplier = 1; - timeouts.WriteTotalTimeoutConstant = 5; - - if(!SetCommTimeouts(portHandle, &timeouts)) { - csp_log_error("Error setting timeouts!"); - return 1; - } - - return 0; -} - -unsigned WINAPI prvRxTask(void* params) { - DWORD bytesRead; - DWORD eventStatus; - uint8_t recvBuffer[24]; - SetCommMask(portHandle, EV_RXCHAR); - - while(isListening) { - WaitCommEvent(portHandle, &eventStatus, NULL); - if( !(eventStatus & EV_RXCHAR) ) { - continue; - } - if( !ReadFile(portHandle, recvBuffer, 24, &bytesRead, NULL)) { - csp_log_warn("Error receiving data! Code: %lu", GetLastError()); - continue; - } - if( usart_callback != NULL ) - usart_callback(recvBuffer, (size_t)bytesRead, NULL); - } - return 0; -} - -static void prvSendData(char *buf, int bufsz) { - DWORD bytesTotal = 0; - DWORD bytesActual; - if( !WriteFile(portHandle, buf, bufsz-bytesTotal, &bytesActual, NULL) ) { - csp_log_error("Could not write data. Code: %lu", GetLastError()); - return; - } - if( !FlushFileBuffers(portHandle) ) { - csp_log_warn("Could not flush write buffer. Code: %lu", GetLastError()); - } -} - -void usart_shutdown(void) { - InterlockedExchange(&isListening, 0); - CloseHandle(portHandle); - portHandle = INVALID_HANDLE_VALUE; - if( rxThread != INVALID_HANDLE_VALUE ) { - WaitForSingleObject(rxThread, INFINITE); - rxThread = INVALID_HANDLE_VALUE; - } - DeleteCriticalSection(&txSection); -} - -void usart_listen(void) { - InterlockedExchange(&isListening, 1); - rxThread = (HANDLE)_beginthreadex(NULL, 0, &prvRxTask, NULL, 0, NULL); -} - -void usart_putstr(char* buf, int bufsz) { - EnterCriticalSection(&txSection); - prvSendData(buf, bufsz); - LeaveCriticalSection(&txSection); -} - -void usart_insert(char c, void *pxTaskWoken) { - /* redirect debug output to stdout */ - printf("%c", c); -} - -void usart_set_callback(usart_callback_t callback) { - usart_callback = callback; -} - -void usart_init(struct usart_conf * conf) { - if( prvTryOpenPort(conf->device) ) { - printError(); - return; - } - - if( prvTryConfigurePort(conf) ) { - printError(); - return; - } - - if( prvTrySetPortTimeouts() ) { - printError(); - return; - } - - InitializeCriticalSection(&txSection); - - /* Start receiver thread */ - usart_listen(); -} - - diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can.c deleted file mode 100644 index 5add8334..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can.c +++ /dev/null @@ -1,279 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* CAN frames contains at most 8 bytes of data, so in order to transmit CSP - * packets larger than this, a fragmentation protocol is required. The CAN - * Fragmentation Protocol (CFP) header is designed to match the 29 bit CAN - * identifier. - * - * The CAN identifier is divided in these fields: - * src: 5 bits - * dst: 5 bits - * type: 1 bit - * remain: 8 bits - * identifier: 10 bits - * - * Source and Destination addresses must match the CSP packet. The type field - * is used to distinguish the first and subsequent frames in a fragmented CSP - * packet. Type is BEGIN (0) for the first fragment and MORE (1) for all other - * fragments. Remain indicates number of remaining fragments, and must be - * decremented by one for each fragment sent. The identifier field serves the - * same purpose as in the Internet Protocol, and should be an auto incrementing - * integer to uniquely separate sessions. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "csp_if_can_pbuf.h" - -/* CFP Frame Types */ -enum cfp_frame_t { - CFP_BEGIN = 0, - CFP_MORE = 1 -}; - -int csp_can_rx(csp_iface_t *interface, uint32_t id, const uint8_t *data, uint8_t dlc, CSP_BASE_TYPE *task_woken) -{ - csp_can_pbuf_element_t *buf; - uint8_t offset; - - /* Random packet loss */ -#if 0 - int random = rand(); - if (random < RAND_MAX * 0.00005) { - csp_log_warn("Dropping frame"); - return; - } -#endif - - /* Bind incoming frame to a packet buffer */ - buf = csp_can_pbuf_find(id, CFP_ID_CONN_MASK); - - /* Check returned buffer */ - if (buf == NULL) { - if (CFP_TYPE(id) == CFP_BEGIN) { - buf = csp_can_pbuf_new(id, task_woken); - if (buf == NULL) { - //csp_log_warn("No available packet buffer for CAN"); - interface->rx_error++; - return CSP_ERR_NOMEM; - } - } else { - //csp_log_warn("Out of order id 0x%X remain %u", CFP_ID(id), CFP_REMAIN(id)); - interface->frame++; - return CSP_ERR_INVAL; - } - } - - /* Reset frame data offset */ - offset = 0; - - switch (CFP_TYPE(id)) { - - case CFP_BEGIN: - - /* Discard packet if DLC is less than CSP id + CSP length fields */ - if (dlc < sizeof(csp_id_t) + sizeof(uint16_t)) { - //csp_log_warn("Short BEGIN frame received"); - interface->frame++; - csp_can_pbuf_free(buf, task_woken); - break; - } - - /* Check for incomplete frame */ - if (buf->packet != NULL) { - /* Reuse the buffer */ - //csp_log_warn("Incomplete frame"); - interface->frame++; - } else { - /* Allocate memory for frame */ - if (task_woken == NULL) { - buf->packet = csp_buffer_get(interface->mtu); - } else { - buf->packet = csp_buffer_get_isr(interface->mtu); - } - if (buf->packet == NULL) { - //csp_log_error("Failed to get buffer for CSP_BEGIN packet"); - interface->frame++; - csp_can_pbuf_free(buf, task_woken); - break; - } - } - - /* Copy CSP identifier and length*/ - memcpy(&(buf->packet->id), data, sizeof(csp_id_t)); - buf->packet->id.ext = csp_ntoh32(buf->packet->id.ext); - memcpy(&(buf->packet->length), data + sizeof(csp_id_t), sizeof(uint16_t)); - buf->packet->length = csp_ntoh16(buf->packet->length); - - /* Reset RX count */ - buf->rx_count = 0; - - /* Set offset to prevent CSP header from being copied to CSP data */ - offset = sizeof(csp_id_t) + sizeof(uint16_t); - - /* Set remain field - increment to include begin packet */ - buf->remain = CFP_REMAIN(id) + 1; - - /* FALLTHROUGH */ - - case CFP_MORE: - - /* Check 'remain' field match */ - if (CFP_REMAIN(id) != buf->remain - 1) { - //csp_log_error("CAN frame lost in CSP packet"); - csp_can_pbuf_free(buf, task_woken); - interface->frame++; - break; - } - - /* Decrement remaining frames */ - buf->remain--; - - /* Check for overflow */ - if ((buf->rx_count + dlc - offset) > buf->packet->length) { - //csp_log_error("RX buffer overflow"); - interface->frame++; - csp_can_pbuf_free(buf, task_woken); - break; - } - - /* Copy dlc bytes into buffer */ - memcpy(&buf->packet->data[buf->rx_count], data + offset, dlc - offset); - buf->rx_count += dlc - offset; - - /* Check if more data is expected */ - if (buf->rx_count != buf->packet->length) - break; - - /* Data is available */ - csp_qfifo_write(buf->packet, interface, task_woken); - - /* Drop packet buffer reference */ - buf->packet = NULL; - - /* Free packet buffer */ - csp_can_pbuf_free(buf, task_woken); - - break; - - default: - //csp_log_warn("Received unknown CFP message type"); - csp_can_pbuf_free(buf, task_woken); - break; - - } - - return CSP_ERR_NONE; -} - -int csp_can_tx(csp_iface_t *interface, csp_packet_t *packet, uint32_t timeout) -{ - - /* CFP Identification number */ - static volatile int csp_can_frame_id = 0; - - /* Get local copy of the static frameid */ - int ident = csp_can_frame_id++; - - uint16_t tx_count; - uint8_t bytes, overhead, avail, dest; - uint8_t frame_buf[8]; - - /* Calculate overhead */ - overhead = sizeof(csp_id_t) + sizeof(uint16_t); - - /* Insert destination node mac address into the CFP destination field */ - dest = csp_rtable_find_mac(packet->id.dst); - if (dest == CSP_NODE_MAC) - dest = packet->id.dst; - - /* Create CAN identifier */ - uint32_t id = 0; - id |= CFP_MAKE_SRC(packet->id.src); - id |= CFP_MAKE_DST(dest); - id |= CFP_MAKE_ID(ident); - id |= CFP_MAKE_TYPE(CFP_BEGIN); - id |= CFP_MAKE_REMAIN((packet->length + overhead - 1) / 8); - - /* Calculate first frame data bytes */ - avail = 8 - overhead; - bytes = (packet->length <= avail) ? packet->length : avail; - - /* Copy CSP headers and data */ - uint32_t csp_id_be = csp_hton32(packet->id.ext); - uint16_t csp_length_be = csp_hton16(packet->length); - - memcpy(frame_buf, &csp_id_be, sizeof(csp_id_be)); - memcpy(frame_buf + sizeof(csp_id_be), &csp_length_be, sizeof(csp_length_be)); - memcpy(frame_buf + overhead, packet->data, bytes); - - /* Increment tx counter */ - tx_count = bytes; - - /* Send first frame */ - if (csp_can_tx_frame(interface, id, frame_buf, overhead + bytes)) { - //csp_log_warn("Failed to send CAN frame in csp_tx_can"); - interface->tx_error++; - return CSP_ERR_DRIVER; - } - - /* Send next frames if not complete */ - while (tx_count < packet->length) { - /* Calculate frame data bytes */ - bytes = (packet->length - tx_count >= 8) ? 8 : packet->length - tx_count; - - /* Prepare identifier */ - id = 0; - id |= CFP_MAKE_SRC(packet->id.src); - id |= CFP_MAKE_DST(dest); - id |= CFP_MAKE_ID(ident); - id |= CFP_MAKE_TYPE(CFP_MORE); - id |= CFP_MAKE_REMAIN((packet->length - tx_count - bytes + 7) / 8); - - /* Increment tx counter */ - tx_count += bytes; - - /* Send frame */ - if (csp_can_tx_frame(interface, id, packet->data + tx_count - bytes, bytes)) { - //csp_log_warn("Failed to send CAN frame in Tx callback"); - interface->tx_error++; - return CSP_ERR_DRIVER; - } - } - - csp_buffer_free(packet); - - return CSP_ERR_NONE; -} diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.c deleted file mode 100644 index 65f18de9..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * csp_if_can_pbuf.c - * - * Created on: Feb 3, 2017 - * Author: johan - */ - -#include -#include "csp_if_can_pbuf.h" - -/* Number of packet buffer elements */ -#define PBUF_ELEMENTS CSP_CONN_MAX - -/* Buffer element timeout in ms */ -#define PBUF_TIMEOUT_MS 1000 - -static csp_can_pbuf_element_t csp_can_pbuf[PBUF_ELEMENTS] = {}; - -int csp_can_pbuf_free(csp_can_pbuf_element_t *buf, CSP_BASE_TYPE *task_woken) -{ - /* Free CSP packet */ - if (buf->packet != NULL) { - if (task_woken == NULL) { - csp_buffer_free(buf->packet); - } else { - csp_buffer_free_isr(buf->packet); - } - } - - /* Mark buffer element free */ - buf->packet = NULL; - buf->rx_count = 0; - buf->cfpid = 0; - buf->last_used = 0; - buf->remain = 0; - buf->state = BUF_FREE; - - return CSP_ERR_NONE; -} - -csp_can_pbuf_element_t *csp_can_pbuf_new(uint32_t id, CSP_BASE_TYPE *task_woken) -{ - uint32_t now = csp_get_ms(); - - for (int i = 0; i < PBUF_ELEMENTS; i++) { - - /* Perform cleanup in used pbufs */ - if (csp_can_pbuf[i].state == BUF_USED) { - if (now - csp_can_pbuf[i].last_used > PBUF_TIMEOUT_MS) - csp_can_pbuf_free(&csp_can_pbuf[i], task_woken); - } - - if (csp_can_pbuf[i].state == BUF_FREE) { - csp_can_pbuf[i].state = BUF_USED; - csp_can_pbuf[i].cfpid = id; - csp_can_pbuf[i].remain = 0; - csp_can_pbuf[i].last_used = now; - return &csp_can_pbuf[i]; - } - - } - - return NULL; - -} - -csp_can_pbuf_element_t *csp_can_pbuf_find(uint32_t id, uint32_t mask) -{ - for (int i = 0; i < PBUF_ELEMENTS; i++) { - if ((csp_can_pbuf[i].state == BUF_USED) && ((csp_can_pbuf[i].cfpid & mask) == (id & mask))) { - csp_can_pbuf[i].last_used = csp_get_ms(); - return &csp_can_pbuf[i]; - } - } - return NULL; -} - diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.h b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.h deleted file mode 100644 index 3e71c26c..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_can_pbuf.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * csp_if_can_pbuf.h - * - * Created on: Feb 3, 2017 - * Author: johan - */ - -#ifndef LIB_CSP_SRC_INTERFACES_CSP_IF_CAN_PBUF_H_ -#define LIB_CSP_SRC_INTERFACES_CSP_IF_CAN_PBUF_H_ - -/* Packet buffers */ -typedef enum { - BUF_FREE = 0, /* Buffer element free */ - BUF_USED = 1, /* Buffer element used */ -} csp_can_pbuf_state_t; - -typedef struct { - uint16_t rx_count; /* Received bytes */ - uint32_t remain; /* Remaining packets */ - uint32_t cfpid; /* Connection CFP identification number */ - csp_packet_t *packet; /* Pointer to packet buffer */ - csp_can_pbuf_state_t state; /* Element state */ - uint32_t last_used; /* Timestamp in ms for last use of buffer */ -} csp_can_pbuf_element_t; - -int csp_can_pbuf_free(csp_can_pbuf_element_t *buf, CSP_BASE_TYPE *task_woken); -csp_can_pbuf_element_t *csp_can_pbuf_new(uint32_t id, CSP_BASE_TYPE *task_woken); -csp_can_pbuf_element_t *csp_can_pbuf_find(uint32_t id, uint32_t mask); -void csp_can_pbuf_cleanup(CSP_BASE_TYPE *task_woken); - -#endif /* LIB_CSP_SRC_INTERFACES_CSP_IF_CAN_PBUF_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_i2c.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_i2c.c deleted file mode 100644 index c5d105df..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_i2c.c +++ /dev/null @@ -1,116 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include - -#include -#include -#include -#include -#include -#include - -static int csp_i2c_handle = 0; - -int csp_i2c_tx(csp_iface_t * interface, csp_packet_t * packet, uint32_t timeout) { - - /* Cast the CSP packet buffer into an i2c frame */ - i2c_frame_t * frame = (i2c_frame_t *) packet; - - /* Insert destination node into the i2c destination field */ - if (csp_rtable_find_mac(packet->id.dst) == CSP_NODE_MAC) { - frame->dest = packet->id.dst; - } else { - frame->dest = csp_rtable_find_mac(packet->id.dst); - } - - /* Save the outgoing id in the buffer */ - packet->id.ext = csp_hton32(packet->id.ext); - - /* Add the CSP header to the I2C length field */ - frame->len += sizeof(packet->id); - frame->len_rx = 0; - - /* Some I2C drivers support X number of retries - * CSP don't care about this. If it doesn't work the first - * time, don'y use time on it. - */ - frame->retries = 0; - - /* enqueue the frame */ - if (i2c_send(csp_i2c_handle, frame, timeout) != E_NO_ERR) - return CSP_ERR_DRIVER; - - return CSP_ERR_NONE; - -} - -/** - * When a frame is received, cast it to a csp_packet - * and send it directly to the CSP new packet function. - * Context: ISR only - * @param frame - */ -void csp_i2c_rx(i2c_frame_t * frame, void * pxTaskWoken) { - - static csp_packet_t * packet; - - /* Validate input */ - if (frame == NULL) - return; - - if ((frame->len < 4) || (frame->len > I2C_MTU)) { - csp_if_i2c.frame++; - csp_buffer_free_isr(frame); - return; - } - - /* Strip the CSP header off the length field before converting to CSP packet */ - frame->len -= sizeof(csp_id_t); - - /* Convert the packet from network to host order */ - packet = (csp_packet_t *) frame; - packet->id.ext = csp_ntoh32(packet->id.ext); - - /* Receive the packet in CSP */ - csp_qfifo_write(packet, &csp_if_i2c, pxTaskWoken); - -} - -int csp_i2c_init(uint8_t addr, int handle, int speed) { - - /* Create i2c_handle */ - csp_i2c_handle = handle; - if (i2c_init(csp_i2c_handle, I2C_MASTER, addr, speed, 10, 10, csp_i2c_rx) != E_NO_ERR) - return CSP_ERR_DRIVER; - - /* Register interface */ - csp_iflist_add(&csp_if_i2c); - - return CSP_ERR_NONE; - -} - -/** Interface definition */ -csp_iface_t csp_if_i2c = { - .name = "I2C", - .nexthop = csp_i2c_tx, -}; diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_kiss.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_kiss.c deleted file mode 100644 index fe5707f6..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_kiss.c +++ /dev/null @@ -1,260 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define KISS_MTU 256 - -#define FEND 0xC0 -#define FESC 0xDB -#define TFEND 0xDC -#define TFESC 0xDD - -#define TNC_DATA 0x00 -#define TNC_SET_HARDWARE 0x06 -#define TNC_RETURN 0xFF - -static int kiss_lock_init = 0; -static csp_bin_sem_handle_t kiss_lock; - -/* Send a CSP packet over the KISS RS232 protocol */ -static int csp_kiss_tx(csp_iface_t * interface, csp_packet_t * packet, uint32_t timeout) { - - if (interface == NULL || interface->driver == NULL) - return CSP_ERR_DRIVER; - - /* Add CRC32 checksum */ - csp_crc32_append(packet, false); - - /* Save the outgoing id in the buffer */ - packet->id.ext = csp_hton32(packet->id.ext); - packet->length += sizeof(packet->id.ext); - - /* Lock */ - csp_bin_sem_wait(&kiss_lock, 1000); - - /* Transmit data */ - csp_kiss_handle_t * driver = interface->driver; - driver->kiss_putc(FEND); - driver->kiss_putc(TNC_DATA); - for (unsigned int i = 0; i < packet->length; i++) { - if (((unsigned char *) &packet->id.ext)[i] == FEND) { - ((unsigned char *) &packet->id.ext)[i] = TFEND; - driver->kiss_putc(FESC); - } else if (((unsigned char *) &packet->id.ext)[i] == FESC) { - ((unsigned char *) &packet->id.ext)[i] = TFESC; - driver->kiss_putc(FESC); - } - driver->kiss_putc(((unsigned char *) &packet->id.ext)[i]); - } - driver->kiss_putc(FEND); - - /* Free data */ - csp_buffer_free(packet); - - /* Unlock */ - csp_bin_sem_post(&kiss_lock); - - return CSP_ERR_NONE; -} - -/** - * When a frame is received, decode the kiss-stuff - * and eventually send it directly to the CSP new packet function. - */ -void csp_kiss_rx(csp_iface_t * interface, uint8_t * buf, int len, void * pxTaskWoken) { - - /* Driver handle */ - csp_kiss_handle_t * driver = interface->driver; - - while (len--) { - - /* Input */ - unsigned char inputbyte = *buf++; - - /* If packet was too long */ - if (driver->rx_length > interface->mtu) { - //csp_log_warn("KISS RX overflow"); - interface->rx_error++; - driver->rx_mode = KISS_MODE_NOT_STARTED; - driver->rx_length = 0; - } - - switch (driver->rx_mode) { - - case KISS_MODE_NOT_STARTED: - - /* Send normal chars back to usart driver */ - if (inputbyte != FEND) { - if (driver->kiss_discard != NULL) - driver->kiss_discard(inputbyte, pxTaskWoken); - break; - } - - /* Try to allocate new buffer */ - if (driver->rx_packet == NULL) { - if (pxTaskWoken == NULL) { - driver->rx_packet = csp_buffer_get(interface->mtu); - } else { - driver->rx_packet = csp_buffer_get_isr(interface->mtu); - } - } - - /* If no more memory, skip frame */ - if (driver->rx_packet == NULL) { - driver->rx_mode = KISS_MODE_SKIP_FRAME; - break; - } - - /* Start transfer */ - driver->rx_length = 0; - driver->rx_mode = KISS_MODE_STARTED; - driver->rx_first = 1; - break; - - case KISS_MODE_STARTED: - - /* Escape char */ - if (inputbyte == FESC) { - driver->rx_mode = KISS_MODE_ESCAPED; - break; - } - - /* End Char */ - if (inputbyte == FEND) { - - /* Accept message */ - if (driver->rx_length > 0) { - - /* Check for valid length */ - if (driver->rx_length < CSP_HEADER_LENGTH + sizeof(uint32_t)) { - //csp_log_warn("KISS short frame skipped, len: %u", driver->rx_length); - interface->rx_error++; - driver->rx_mode = KISS_MODE_NOT_STARTED; - break; - } - - /* Count received frame */ - interface->frame++; - - /* The CSP packet length is without the header */ - driver->rx_packet->length = driver->rx_length - CSP_HEADER_LENGTH; - - /* Convert the packet from network to host order */ - driver->rx_packet->id.ext = csp_ntoh32(driver->rx_packet->id.ext); - - /* Validate CRC */ - if (csp_crc32_verify(driver->rx_packet, false) != CSP_ERR_NONE) { - //csp_log_warn("KISS invalid crc frame skipped, len: %u", driver->rx_packet->length); - interface->rx_error++; - driver->rx_mode = KISS_MODE_NOT_STARTED; - break; - } - - /* Send back into CSP, notice calling from task so last argument must be NULL! */ - csp_qfifo_write(driver->rx_packet, interface, pxTaskWoken); - driver->rx_packet = NULL; - driver->rx_mode = KISS_MODE_NOT_STARTED; - break; - - } - - /* Break after the end char */ - break; - } - - /* Skip the first char after FEND which is TNC_DATA (0x00) */ - if (driver->rx_first) { - driver->rx_first = 0; - break; - } - - /* Valid data char */ - ((char *) &driver->rx_packet->id.ext)[driver->rx_length++] = inputbyte; - - break; - - case KISS_MODE_ESCAPED: - - /* Escaped escape char */ - if (inputbyte == TFESC) - ((char *) &driver->rx_packet->id.ext)[driver->rx_length++] = FESC; - - /* Escaped fend char */ - if (inputbyte == TFEND) - ((char *) &driver->rx_packet->id.ext)[driver->rx_length++] = FEND; - - /* Go back to started mode */ - driver->rx_mode = KISS_MODE_STARTED; - break; - - case KISS_MODE_SKIP_FRAME: - - /* Just wait for end char */ - if (inputbyte == FEND) - driver->rx_mode = KISS_MODE_NOT_STARTED; - - break; - - } - - } - -} - -void csp_kiss_init(csp_iface_t * csp_iface, csp_kiss_handle_t * csp_kiss_handle, csp_kiss_putc_f kiss_putc_f, csp_kiss_discard_f kiss_discard_f, const char * name) { - - /* Init lock only once */ - if (kiss_lock_init == 0) { - csp_bin_sem_create(&kiss_lock); - kiss_lock_init = 1; - } - - /* Register device handle as member of interface */ - csp_iface->driver = csp_kiss_handle; - csp_kiss_handle->kiss_discard = kiss_discard_f; - csp_kiss_handle->kiss_putc = kiss_putc_f; - csp_kiss_handle->rx_packet = NULL; - csp_kiss_handle->rx_mode = KISS_MODE_NOT_STARTED; - - /* Set default MTU if not given */ - if (csp_iface->mtu == 0) { - csp_iface->mtu = KISS_MTU; - } - - /* Setup other mandatories */ - csp_iface->nexthop = csp_kiss_tx; - csp_iface->name = name; - - /* Regsiter interface */ - csp_iflist_add(csp_iface); - -} diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_lo.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_lo.c deleted file mode 100644 index f3e81b15..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_lo.c +++ /dev/null @@ -1,61 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* CSP includes */ -#include -#include -#include -#include - -#include -#include - -#include "../csp_route.h" - -/** - * Loopback interface transmit function - * @param packet Packet to transmit - * @param timeout Timout in ms - * @return 1 if packet was successfully transmitted, 0 on error - */ -static int csp_lo_tx(csp_iface_t * interface, csp_packet_t * packet, uint32_t timeout) { - - /* Drop packet silently if not destined for us. This allows - * blackhole routing addresses by setting their nexthop to - * the loopback interface. - */ - if (packet->id.dst != csp_get_address()) { - /* Consume and drop packet */ - csp_buffer_free(packet); - return CSP_ERR_NONE; - } - - /* Send back into CSP, notice calling from task so last argument must be NULL! */ - csp_qfifo_write(packet, &csp_if_lo, NULL); - - return CSP_ERR_NONE; - -} - -/* Interface definition */ -csp_iface_t csp_if_lo = { - .name = "LOOP", - .nexthop = csp_lo_tx, -}; diff --git a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c b/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c deleted file mode 100644 index 5292663b..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/interfaces/csp_if_zmqhub.c +++ /dev/null @@ -1,165 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include - -/* CSP includes */ -#include -#include -#include -#include -#include -#include - -/* ZMQ */ -#include - -static void * context; -static void * publisher; -static void * subscriber; -static csp_bin_sem_handle_t tx_wait; - -/** - * Interface transmit function - * @param packet Packet to transmit - * @param timeout Timeout in ms - * @return 1 if packet was successfully transmitted, 0 on error - */ -int csp_zmqhub_tx(csp_iface_t * interface, csp_packet_t * packet, uint32_t timeout) { - - /* Send envelope */ - uint8_t dest = csp_rtable_find_mac(packet->id.dst); - if (dest == CSP_NODE_MAC) - dest = packet->id.dst; - - uint16_t length = packet->length; - uint8_t * destptr = ((uint8_t *) &packet->id) - sizeof(dest); - memcpy(destptr, &dest, sizeof(dest)); - csp_bin_sem_wait(&tx_wait, CSP_INFINITY); /* Using ZMQ in thread safe manner*/ - int result = zmq_send(publisher, destptr, length + sizeof(packet->id) + sizeof(dest), 0); - csp_bin_sem_post(&tx_wait); /* Release tx semaphore */ - if (result < 0) - csp_log_error("ZMQ send error: %u %s\r\n", result, strerror(result)); - - csp_buffer_free(packet); - - return CSP_ERR_NONE; - -} - -CSP_DEFINE_TASK(csp_zmqhub_task) { - - while(1) { - zmq_msg_t msg; - assert(zmq_msg_init_size(&msg, 1024) == 0); - - /* Receive data */ - if (zmq_msg_recv(&msg, subscriber, 0) < 0) { - zmq_msg_close(&msg); - csp_log_error("ZMQ: %s", zmq_strerror(zmq_errno())); - continue; - } - - int datalen = zmq_msg_size(&msg); - if (datalen < 5) { - csp_log_warn("ZMQ: Too short datalen: %u", datalen); - while(zmq_msg_recv(&msg, subscriber, ZMQ_NOBLOCK) > 0) - zmq_msg_close(&msg); - continue; - } - - /* Create new csp packet */ - csp_packet_t * packet = csp_buffer_get(256); - if (packet == NULL) { - zmq_msg_close(&msg); - continue; - } - - /* Copy the data from zmq to csp */ - uint8_t * destptr = ((uint8_t *) &packet->id) - sizeof(*destptr); - memcpy(destptr, zmq_msg_data(&msg), datalen); - packet->length = datalen - sizeof(packet->id) - sizeof(*destptr); - - /* Queue up packet to router */ - csp_qfifo_write(packet, &csp_if_zmqhub, NULL); - - zmq_msg_close(&msg); - } - - return CSP_TASK_RETURN; - -} - -int csp_zmqhub_init(uint8_t addr, const char * host) { - char url_pub[100]; - char url_sub[100]; - - sprintf(url_pub, "tcp://%s:6000", host); - sprintf(url_sub, "tcp://%s:7000", host); - - return csp_zmqhub_init_w_endpoints(addr, url_pub, url_sub); -} - -int csp_zmqhub_init_w_endpoints(uint8_t addr, const char * publisher_endpoint, - const char * subscriber_endpoint) { - - context = zmq_ctx_new(); - assert(context); - - csp_log_info("INIT ZMQ with addr %u to servers %s / %s\r\n", - addr, publisher_endpoint, subscriber_endpoint); - - /* Publisher (TX) */ - publisher = zmq_socket(context, ZMQ_PUB); - assert(publisher); - assert(zmq_connect(publisher, publisher_endpoint) == 0); - - /* Subscriber (RX) */ - subscriber = zmq_socket(context, ZMQ_SUB); - assert(subscriber); - assert(zmq_connect(subscriber, subscriber_endpoint) == 0); - - if (addr == CSP_NODE_MAC) { // == 255 - assert(zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, NULL, 0) == 0); - } else { - assert(zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, &addr, 1) == 0); - } - /* ZMQ isn't thread safe, so we add a binary semaphore to wait on for tx */ - if (csp_bin_sem_create(&tx_wait) != CSP_SEMAPHORE_OK) { - csp_log_error("Failed to initialize semaphore in csp_zmqhub_init_w_endpoints"); - return CSP_ERR_NOMEM; - } - /* Start RX thread */ - static csp_thread_handle_t handle_subscriber; - int ret = csp_thread_create(csp_zmqhub_task, "ZMQ", 20000, NULL, 0, &handle_subscriber); - csp_log_info("Task start %d\r\n", ret); - - /* Register interface */ - csp_iflist_add(&csp_if_zmqhub); - - return CSP_ERR_NONE; - -} - -/* Interface definition */ -csp_iface_t csp_if_zmqhub = { - .name = "ZMQHUB", - .nexthop = csp_zmqhub_tx, -}; diff --git a/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_cidr.c b/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_cidr.c deleted file mode 100644 index 5758dc3c..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_cidr.c +++ /dev/null @@ -1,233 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include -#include -#include - -/* Local typedef for routing table */ -typedef struct __attribute__((__packed__)) csp_rtable_s { - uint8_t address; - uint8_t netmask; - uint8_t mac; - csp_iface_t * interface; - struct csp_rtable_s * next; -} csp_rtable_t; - -/* Routing entries are stored in a linked list*/ -static csp_rtable_t * rtable = NULL; - -static csp_rtable_t * csp_rtable_find(uint8_t addr, uint8_t netmask, uint8_t exact) { - - /* Remember best result */ - csp_rtable_t * best_result = NULL; - uint8_t best_result_mask = 0; - - /* Start search */ - csp_rtable_t * i = rtable; - while(i) { - - /* Look for exact match */ - if (i->address == addr && i->netmask == netmask) { - best_result = i; - break; - } - - /* Try a CIDR netmask match */ - if (!exact) { - uint8_t hostbits = (1 << (CSP_ID_HOST_SIZE - i->netmask)) - 1; - uint8_t netbits = ~hostbits; - //printf("Netbits %x Hostbits %x\r\n", netbits, hostbits); - - /* Match network addresses */ - uint8_t net_a = i->address & netbits; - uint8_t net_b = addr & netbits; - //printf("A: %hhx, B: %hhx\r\n", net_a, net_b); - - /* We have a match */ - if (net_a == net_b) { - if (i->netmask >= best_result_mask) { - //printf("Match best result %u %u\r\n", best_result_mask, i->netmask); - best_result = i; - best_result_mask = i->netmask; - } - } - - } - - i = i->next; - - } - -#if 0 - if (best_result) - csp_debug(CSP_PACKET, "Using routing entry: %u/%u dev %s m:%u\r\n", best_result->address, best_result->netmask, best_result->interface->name, best_result->mac); -#endif - - return best_result; - -} - -void csp_rtable_clear(void) { - for (csp_rtable_t * i = rtable; (i);) { - void * freeme = i; - i = i->next; - csp_free(freeme); - } - rtable = NULL; - - /* Set loopback up again */ - csp_rtable_set(csp_get_address(), CSP_ID_HOST_SIZE, &csp_if_lo, CSP_NODE_MAC); - -} - -static int csp_rtable_parse(const char * buffer, int dry_run) { - - int valid_entries = 0; - - /* Copy string before running strtok */ - char * str = alloca(strlen(buffer) + 1); - memcpy(str, buffer, strlen(buffer) + 1); - - /* Get first token */ - str = strtok(str, ","); - - while ((str) && (strlen(str) > 1)) { - int address = 0, netmask = 0, mac = 255; - char name[10] = {}; - if (sscanf(str, "%u/%u %s %u", &address, &netmask, name, &mac) != 4) { - if (sscanf(str, "%u/%u %s", &address, &netmask, name) != 3) { - csp_log_error("Parse error %s", str); - return -1; - } - } - //printf("Parsed %u/%u %u %s\r\n", address, netmask, mac, name); - csp_iface_t * ifc = csp_iflist_get_by_name(name); - if (ifc) { - if (dry_run == 0) - csp_rtable_set(address, netmask, ifc, mac); - } else { - csp_log_error("Unknown interface %s", name); - return -1; - } - valid_entries++; - str = strtok(NULL, ","); - } - - return valid_entries; -} - -void csp_rtable_load(const char * buffer) { - csp_rtable_parse(buffer, 0); -} - -int csp_rtable_check(const char * buffer) { - return csp_rtable_parse(buffer, 1); -} - -int csp_rtable_save(char * buffer, int maxlen) { - int len = 0; - for (csp_rtable_t * i = rtable; (i); i = i->next) { - if (i->mac != CSP_NODE_MAC) { - len += snprintf(buffer + len, maxlen - len, "%u/%u %s %u, ", i->address, i->netmask, i->interface->name, i->mac); - } else { - len += snprintf(buffer + len, maxlen - len, "%u/%u %s, ", i->address, i->netmask, i->interface->name); - } - } - return len; -} - -csp_iface_t * csp_rtable_find_iface(uint8_t id) { - csp_rtable_t * entry = csp_rtable_find(id, CSP_ID_HOST_SIZE, 0); - if (entry == NULL) - return NULL; - return entry->interface; -} - -uint8_t csp_rtable_find_mac(uint8_t id) { - csp_rtable_t * entry = csp_rtable_find(id, CSP_ID_HOST_SIZE, 0); - if (entry == NULL) - return 255; - return entry->mac; -} - -int csp_rtable_set(uint8_t _address, uint8_t _netmask, csp_iface_t *ifc, uint8_t mac) { - - if (ifc == NULL) - return CSP_ERR_INVAL; - - /* Set default route in the old way */ - int address, netmask; - if (_address == CSP_DEFAULT_ROUTE) { - netmask = 0; - address = 0; - } else { - netmask = _netmask; - address = _address; - } - - /* Fist see if the entry exists */ - csp_rtable_t * entry = csp_rtable_find(address, netmask, 1); - - /* If not, create a new one */ - if (!entry) { - entry = csp_malloc(sizeof(csp_rtable_t)); - if (entry == NULL) - return CSP_ERR_NOMEM; - - entry->next = NULL; - /* Add entry to linked-list */ - if (rtable == NULL) { - /* This is the first interface to be added */ - rtable = entry; - } else { - /* One or more interfaces were already added */ - csp_rtable_t * i = rtable; - while (i->next) - i = i->next; - i->next = entry; - } - } - - /* Fill in the data */ - entry->address = address; - entry->netmask = netmask; - entry->interface = ifc; - entry->mac = mac; - - return CSP_ERR_NONE; -} - -#ifdef CSP_DEBUG -void csp_rtable_print(void) { - - for (csp_rtable_t * i = rtable; (i); i = i->next) { - if (i->mac == 255) { - printf("%u/%u %s\r\n", i->address, i->netmask, i->interface->name); - } else { - printf("%u/%u %s %u\r\n", i->address, i->netmask, i->interface->name, i->mac); - } - } - -} -#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_static.c b/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_static.c deleted file mode 100644 index ea993027..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/rtable/csp_rtable_static.c +++ /dev/null @@ -1,128 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include - -/* Local typedef for routing table */ -typedef struct __attribute__((__packed__)) csp_rtable_s { - csp_iface_t * interface; - uint8_t mac; -} csp_rtable_t; - -/* Static storage context for routing table */ -static csp_rtable_t routes[CSP_ROUTE_COUNT] = {}; - -/** - * Find entry in static routing table - * This is done by table lookup with fallback to the default route - * The reason why the csp_rtable_t struct is not returned directly - * is that we wish to hide the storage format, mainly because of - * the alternative routing table storage (cidr). - * @param id Node - * @return pointer to found routing entry - */ -static csp_rtable_t * csp_rtable_find(uint8_t id) { - - if (routes[id].interface != NULL) { - return &routes[id]; - } else if (routes[CSP_DEFAULT_ROUTE].interface != NULL) { - return &routes[CSP_DEFAULT_ROUTE]; - } - return NULL; - -} - -csp_iface_t * csp_rtable_find_iface(uint8_t id) { - csp_rtable_t * route = csp_rtable_find(id); - if (route == NULL) - return NULL; - return route->interface; -} - -uint8_t csp_rtable_find_mac(uint8_t id) { - csp_rtable_t * route = csp_rtable_find(id); - if (route == NULL) - return 255; - return route->mac; -} - -void csp_rtable_clear(void) { - memset(routes, 0, sizeof(routes[0]) * CSP_ROUTE_COUNT); -} - -void csp_route_table_load(uint8_t route_table_in[CSP_ROUTE_TABLE_SIZE]) { - memcpy(routes, route_table_in, sizeof(routes[0]) * CSP_ROUTE_COUNT); -} - -void csp_route_table_save(uint8_t route_table_out[CSP_ROUTE_TABLE_SIZE]) { - memcpy(route_table_out, routes, sizeof(routes[0]) * CSP_ROUTE_COUNT); -} - -int csp_rtable_set(uint8_t node, uint8_t mask, csp_iface_t *ifc, uint8_t mac) { - - /* Don't add nothing */ - if (ifc == NULL) - return CSP_ERR_INVAL; - - /** - * Check if the interface has been added. - * - * NOTE: For future implementations, interfaces should call - * csp_route_add_if in its csp_if__init function, instead - * of registering at first route_set, in order to make the interface - * available to network based (CMP) route configuration. - */ - csp_iflist_add(ifc); - - /* Set route */ - if (node <= CSP_DEFAULT_ROUTE) { - routes[node].interface = ifc; - routes[node].mac = mac; - } else { - csp_log_error("Failed to set route: invalid node id %u", node); - return CSP_ERR_INVAL; - } - - return CSP_ERR_NONE; - -} - -void csp_rtable_load(const char * buffer) { -} - -int csp_rtable_check(const char * buffer) { - return -1; -} - -#ifdef CSP_DEBUG -void csp_rtable_print(void) { - int i; - printf("Node Interface Address\r\n"); - for (i = 0; i < CSP_DEFAULT_ROUTE; i++) - if (routes[i].interface != NULL) - printf("%4u %-9s %u\r\n", i, - routes[i].interface->name, - routes[i].mac == CSP_NODE_MAC ? i : routes[i].mac); - printf(" * %-9s %u\r\n", routes[CSP_DEFAULT_ROUTE].interface->name, routes[CSP_DEFAULT_ROUTE].mac); - -} -#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/transport/csp_rdp.c b/gomspace/libgscsp/lib/libcsp/src/transport/csp_rdp.c deleted file mode 100644 index e19968e2..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/transport/csp_rdp.c +++ /dev/null @@ -1,1102 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* - * This is a implementation of the seq/ack handling taken from the Reliable Datagram Protocol (RDP) - * For more information read RFC 908/1151. The implementation has been extended to include support for - * delayed acknowledgments, to improve performance over half-duplex links. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include "../csp_port.h" -#include "../csp_conn.h" -#include "../csp_io.h" -#include "csp_transport.h" - -#ifdef CSP_USE_RDP - -#define RDP_SYN 0x01 -#define RDP_ACK 0x02 -#define RDP_EAK 0x04 -#define RDP_RST 0x08 - -static uint32_t csp_rdp_window_size = 4; -static uint32_t csp_rdp_conn_timeout = 10000; -static uint32_t csp_rdp_packet_timeout = 1000; -static uint32_t csp_rdp_delayed_acks = 1; -static uint32_t csp_rdp_ack_timeout = 1000 / 4; -static uint32_t csp_rdp_ack_delay_count = 4 / 2; - -/* Used for queue calls */ -static CSP_BASE_TYPE pdTrue = 1; - -typedef struct __attribute__((__packed__)) { - /* The timestamp is placed in the padding bytes */ - uint8_t padding[CSP_PADDING_BYTES - 2 * sizeof(uint32_t)]; - uint32_t quarantine; // EACK quarantine period - uint32_t timestamp; // Time the message was sent - uint16_t length; // Length field must be just before CSP ID - csp_id_t id; // CSP id must be just before data - uint8_t data[]; // This just points to the rest of the buffer, without a size indication. -} rdp_packet_t; - -typedef struct __attribute__((__packed__)) { - union __attribute__((__packed__)) { - uint8_t flags; - struct __attribute__((__packed__)) { -#if defined(CSP_BIG_ENDIAN) && !defined(CSP_LITTLE_ENDIAN) - unsigned int res : 4; - unsigned int syn : 1; - unsigned int ack : 1; - unsigned int eak : 1; - unsigned int rst : 1; -#elif defined(CSP_LITTLE_ENDIAN) && !defined(CSP_BIG_ENDIAN) - unsigned int rst : 1; - unsigned int eak : 1; - unsigned int ack : 1; - unsigned int syn : 1; - unsigned int res : 4; -#else - #error "Must define one of CSP_BIG_ENDIAN or CSP_LITTLE_ENDIAN in csp_platform.h" -#endif - }; - }; - uint16_t seq_nr; - uint16_t ack_nr; -} rdp_header_t; - -/** - * RDP Headers: - * The following functions are helper functions that handles the extra RDP - * information that needs to be appended to all data packets. - */ -static rdp_header_t * csp_rdp_header_add(csp_packet_t * packet) { - rdp_header_t * header = (rdp_header_t *) &packet->data[packet->length]; - packet->length += sizeof(rdp_header_t); - memset(header, 0, sizeof(rdp_header_t)); - return header; -} - -static rdp_header_t * csp_rdp_header_remove(csp_packet_t * packet) { - rdp_header_t * header = (rdp_header_t *) &packet->data[packet->length-sizeof(rdp_header_t)]; - packet->length -= sizeof(rdp_header_t); - return header; -} - -static rdp_header_t * csp_rdp_header_ref(csp_packet_t * packet) { - rdp_header_t * header = (rdp_header_t *) &packet->data[packet->length-sizeof(rdp_header_t)]; - return header; -} - -/* Functions for comparing wrapping sequence numbers and timestamps */ - -/* Return 1 if seq is between start and end (both inclusive) */ -static inline int csp_rdp_seq_between(uint16_t seq, uint16_t start, uint16_t end) { - return (uint16_t)(end - start) >= (uint16_t)(seq - start); -} - -/* Return 1 if seq is before cmp */ -static inline int csp_rdp_seq_before(uint16_t seq, uint16_t cmp) { - return (int16_t)(seq - cmp) < 0; -} - -/* Return 1 if seq is after cmp */ -static inline int csp_rdp_seq_after(uint16_t seq, uint16_t cmp) { - return csp_rdp_seq_before(cmp, seq); -} - -/* Return 1 if time is between start and end (both inclusive) */ -static inline int csp_rdp_time_between(uint32_t time, uint32_t start, uint32_t end) { - return (uint32_t)(end - start) >= (uint32_t)(time - start); -} - -/* Return 1 if time is before cmp */ -static inline int csp_rdp_time_before(uint32_t time, uint32_t cmp) { - return (int32_t)(time - cmp) < 0; -} - -/* Return 1 if time is after cmp */ -static inline int csp_rdp_time_after(uint32_t time, uint32_t cmp) { - return csp_rdp_time_before(cmp, time); -} - -/** - * CONTROL MESSAGES - * The following function is used to send empty messages, - * with ACK, SYN or RST flag. - */ -static int csp_rdp_send_cmp(csp_conn_t * conn, csp_packet_t * packet, int flags, int seq_nr, int ack_nr) { - - csp_id_t idout; - - /* Generate message */ - if (!packet) { - packet = csp_buffer_get(20); - if (!packet) - return CSP_ERR_NOMEM; - packet->length = 0; - } - - /* Add RDP header */ - rdp_header_t * header = csp_rdp_header_add(packet); - header->seq_nr = csp_hton16(seq_nr); - header->ack_nr = csp_hton16(ack_nr); - header->ack = (flags & RDP_ACK) ? 1 : 0; - header->eak = (flags & RDP_EAK) ? 1 : 0; - header->syn = (flags & RDP_SYN) ? 1 : 0; - header->rst = (flags & RDP_RST) ? 1 : 0; - - /* Send copy to tx_queue, before sending packet to IF */ - if (flags & RDP_SYN) { - rdp_packet_t * rdp_packet = csp_buffer_clone(packet); - if (rdp_packet == NULL) return CSP_ERR_NOMEM; - rdp_packet->timestamp = csp_get_ms(); - if (csp_queue_enqueue(conn->rdp.tx_queue, &rdp_packet, 0) != CSP_QUEUE_OK) - csp_buffer_free(rdp_packet); - } - - /* Send control messages with high priority */ - idout = conn->idout; - idout.pri = conn->idout.pri < CSP_PRIO_HIGH ? conn->idout.pri : CSP_PRIO_HIGH; - - /* Send packet to IF */ - csp_iface_t * ifout = csp_rtable_find_iface(idout.dst); - if (csp_send_direct(idout, packet, ifout, 0) != CSP_ERR_NONE) { - csp_log_error("INTERFACE ERROR: not possible to send"); - csp_buffer_free(packet); - return CSP_ERR_BUSY; - } - - /* Update last ACK time stamp */ - if (flags & RDP_ACK) { - conn->rdp.rcv_lsa = ack_nr; - conn->rdp.ack_timestamp = csp_get_ms(); - } - - return CSP_ERR_NONE; - -} - -/** - * EXTENDED ACKNOWLEDGEMENTS - * The following function sends an extended ACK packet - */ -static int csp_rdp_send_eack(csp_conn_t * conn) { - - /* Allocate message */ - csp_packet_t * packet_eack = csp_buffer_get(100); - if (packet_eack == NULL) return CSP_ERR_NOMEM; - packet_eack->length = 0; - - /* Loop through RX queue */ - int i, count; - csp_packet_t * packet; - count = csp_queue_size(conn->rdp.rx_queue); - for (i = 0; i < count; i++) { - - if (csp_queue_dequeue_isr(conn->rdp.rx_queue, &packet, &pdTrue) != CSP_QUEUE_OK) { - csp_log_error("Cannot dequeue from rx_queue in queue deliver"); - break; - } - - /* Add seq nr to EACK packet */ - rdp_header_t * header = csp_rdp_header_ref(packet); - packet_eack->data16[packet_eack->length/sizeof(uint16_t)] = csp_hton16(header->seq_nr); - packet_eack->length += sizeof(uint16_t); - csp_log_protocol("Added EACK nr %u", header->seq_nr); - - /* Requeue */ - csp_queue_enqueue_isr(conn->rdp.rx_queue, &packet, &pdTrue); - - } - - return csp_rdp_send_cmp(conn, packet_eack, RDP_ACK | RDP_EAK, conn->rdp.snd_nxt, conn->rdp.rcv_cur); - -} - - -/** - * SYN Packet - * The following function sends a SYN packet - */ -static int csp_rdp_send_syn(csp_conn_t * conn) { - - /* Allocate message */ - csp_packet_t * packet = csp_buffer_get(100); - if (packet == NULL) return CSP_ERR_NOMEM; - - /* Generate contents */ - packet->data32[0] = csp_hton32(csp_rdp_window_size); - packet->data32[1] = csp_hton32(csp_rdp_conn_timeout); - packet->data32[2] = csp_hton32(csp_rdp_packet_timeout); - packet->data32[3] = csp_hton32(csp_rdp_delayed_acks); - packet->data32[4] = csp_hton32(csp_rdp_ack_timeout); - packet->data32[5] = csp_hton32(csp_rdp_ack_delay_count); - packet->length = 6 * sizeof(uint32_t); - - return csp_rdp_send_cmp(conn, packet, RDP_SYN, conn->rdp.snd_iss, 0); - -} - -static inline int csp_rdp_receive_data(csp_conn_t * conn, csp_packet_t * packet) { - - /* Remove RDP header before passing to userspace */ - csp_rdp_header_remove(packet); - - /* Enqueue data */ - if (csp_conn_enqueue_packet(conn, packet) < 0) { - csp_log_warn("Conn RX buffer full"); - return CSP_ERR_NOBUFS; - } - - return CSP_ERR_NONE; - -} - -static inline void csp_rdp_rx_queue_flush(csp_conn_t * conn) { - - /* Loop through RX queue */ - int i, count; - csp_packet_t * packet; - -front: - count = csp_queue_size(conn->rdp.rx_queue); - for (i = 0; i < count; i++) { - - if (csp_queue_dequeue_isr(conn->rdp.rx_queue, &packet, &pdTrue) != CSP_QUEUE_OK) { - csp_log_error("Cannot dequeue from rx_queue in queue deliver"); - break; - } - - rdp_header_t * header = csp_rdp_header_ref(packet); - csp_log_protocol("RX Queue deliver matching Element, seq %u", header->seq_nr); - - /* If the matching packet was found: */ - if (header->seq_nr == (uint16_t)(conn->rdp.rcv_cur + 1)) { - csp_log_protocol("Deliver seq %u", header->seq_nr); - csp_rdp_receive_data(conn, packet); - conn->rdp.rcv_cur++; - /* Loop from first element again */ - goto front; - - /* Otherwise, requeue */ - } else { - csp_queue_enqueue_isr(conn->rdp.rx_queue, &packet, &pdTrue); - } - - } - -} - -static inline bool csp_rdp_seq_in_rx_queue(csp_conn_t * conn, uint16_t seq_nr) { - - /* Loop through RX queue */ - int i, count; - rdp_packet_t * packet; - count = csp_queue_size(conn->rdp.rx_queue); - for (i = 0; i < count; i++) { - - if (csp_queue_dequeue_isr(conn->rdp.rx_queue, &packet, &pdTrue) != CSP_QUEUE_OK) { - csp_log_error("Cannot dequeue from rx_queue in queue exists"); - break; - } - - csp_queue_enqueue_isr(conn->rdp.rx_queue, &packet, &pdTrue); - - rdp_header_t * header = csp_rdp_header_ref((csp_packet_t *) packet); - csp_log_protocol("RX Queue exists matching Element, seq %u", header->seq_nr); - - /* If the matching packet was found, deliver */ - if (header->seq_nr == seq_nr) { - csp_log_protocol("We have a match"); - return true; - } - - } - - return false; - -} - -static inline int csp_rdp_rx_queue_add(csp_conn_t * conn, csp_packet_t * packet, uint16_t seq_nr) { - - if (csp_rdp_seq_in_rx_queue(conn, seq_nr)) - return CSP_QUEUE_ERROR; - return csp_queue_enqueue_isr(conn->rdp.rx_queue, &packet, &pdTrue); - -} - -static void csp_rdp_flush_eack(csp_conn_t * conn, csp_packet_t * eack_packet) { - - /* Loop through TX queue */ - int i, j, count; - rdp_packet_t * packet; - count = csp_queue_size(conn->rdp.tx_queue); - for (i = 0; i < count; i++) { - - if (csp_queue_dequeue(conn->rdp.tx_queue, &packet, 0) != CSP_QUEUE_OK) { - csp_log_error("Cannot dequeue from tx_queue in flush EACK"); - break; - } - - rdp_header_t * header = csp_rdp_header_ref((csp_packet_t *) packet); - csp_log_protocol("EACK compare element, time %u, seq %u", packet->timestamp, csp_ntoh16(header->seq_nr)); - - /* Look for this element in EACKs */ - int match = 0; - for (j = 0; j < (int)((eack_packet->length - sizeof(rdp_header_t)) / sizeof(uint16_t)); j++) { - if (csp_ntoh16(eack_packet->data16[j]) == csp_ntoh16(header->seq_nr)) - match = 1; - - /* Enable this if you want EACK's to trigger retransmission */ - if (csp_ntoh16(eack_packet->data16[j]) > csp_ntoh16(header->seq_nr)) { - uint32_t time_now = csp_get_ms(); - if (csp_rdp_time_after(time_now, packet->quarantine)) { - packet->timestamp = time_now - conn->rdp.packet_timeout - 1; - packet->quarantine = time_now + conn->rdp.packet_timeout / 2; - } - } - } - - if (match == 0) { - /* If not found, put back on tx queue */ - csp_queue_enqueue(conn->rdp.tx_queue, &packet, 0); - } else { - /* Found, free */ - csp_log_protocol("TX Element %u freed", csp_ntoh16(header->seq_nr)); - csp_buffer_free(packet); - } - - } - -} - -static inline bool csp_rdp_should_ack(csp_conn_t * conn) { - - /* If delayed ACKs are not used, always ACK */ - if (!conn->rdp.delayed_acks) { - return true; - } - - /* ACK if time since last ACK is greater than ACK timeout */ - uint32_t time_now = csp_get_ms(); - if (csp_rdp_time_after(time_now, conn->rdp.ack_timestamp + conn->rdp.ack_timeout)) - return true; - - /* ACK if number of unacknowledged packets is greater than delay count */ - if (csp_rdp_seq_after(conn->rdp.rcv_cur, conn->rdp.rcv_lsa + conn->rdp.ack_delay_count)) - return true; - - return false; - -} - -void csp_rdp_flush_all(csp_conn_t * conn) { - - if ((conn == NULL) || conn->rdp.tx_queue == NULL) { - csp_log_error("Null pointer passed to rdp flush all"); - return; - } - - rdp_packet_t * packet; - - /* Empty TX queue */ - while (csp_queue_dequeue_isr(conn->rdp.tx_queue, &packet, &pdTrue) == CSP_QUEUE_OK) { - if (packet != NULL) { - csp_log_protocol("RDP %p: Flush TX Element, time %u, seq %u", conn, packet->timestamp, csp_ntoh16(csp_rdp_header_ref((csp_packet_t *) packet)->seq_nr)); - csp_buffer_free(packet); - } - } - - /* Empty RX queue */ - while (csp_queue_dequeue_isr(conn->rdp.rx_queue, &packet, &pdTrue) == CSP_QUEUE_OK) { - if (packet != NULL) { - csp_log_protocol("RDP %p: Flush RX Element, time %u, seq %u", conn, packet->timestamp, csp_ntoh16(csp_rdp_header_ref((csp_packet_t *) packet)->seq_nr)); - csp_buffer_free(packet); - } - } - -} - - -int csp_rdp_check_ack(csp_conn_t * conn) { - - /* Check all RX queues for spare capacity */ - int prio, avail = 1; - for (prio = 0; prio < CSP_RX_QUEUES; prio++) { - if (CSP_RX_QUEUE_LENGTH - csp_queue_size(conn->rx_queue[prio]) <= 2 * (int32_t)conn->rdp.window_size) { - avail = 0; - break; - } - } - - /* If more space available, only send after ack timeout or immediately if delay_acks is zero */ - if (avail && csp_rdp_should_ack(conn)) - csp_rdp_send_cmp(conn, NULL, RDP_ACK, conn->rdp.snd_nxt, conn->rdp.rcv_cur); - - return CSP_ERR_NONE; - -} - -static inline bool csp_rdp_is_conn_ready_for_tx(csp_conn_t * conn) -{ - // Check Tx window (messages waiting for acks) - if (csp_rdp_seq_after(conn->rdp.snd_nxt, conn->rdp.snd_una + conn->rdp.window_size - 1)) { - return false; - } - return true; -} - -/** - * This function must be called with regular intervals for the - * RDP protocol to work as expected. This takes care of closing - * stale connections and retransmitting traffic. A good place to - * call this function is from the CSP router task. - */ -void csp_rdp_check_timeouts(csp_conn_t * conn) { - - rdp_packet_t * packet; - - /** - * CONNECTION TIMEOUT: - * Check that connection has not timed out inside the network stack - * */ - uint32_t time_now = csp_get_ms(); - if (conn->socket != NULL) { - if (csp_rdp_time_after(time_now, conn->timestamp + conn->rdp.conn_timeout)) { - csp_log_warn("RDP %p: Found a lost connection (now: %u, ts: %u, to: %u), closing now", - conn, time_now, conn->timestamp, conn->rdp.conn_timeout); - csp_close(conn); - return; - } - } - - /** - * CLOSE-WAIT TIMEOUT: - * After waiting a while in CLOSE-WAIT, the connection should be closed. - */ - if (conn->rdp.state == RDP_CLOSE_WAIT) { - if (csp_rdp_time_after(time_now, conn->timestamp + conn->rdp.conn_timeout)) { - csp_log_protocol("RDP %p: CLOSE_WAIT timeout", conn); - csp_close(conn); - } - return; - } - - /** - * MESSAGE TIMEOUT: - * Check each outgoing message for TX timeout - */ - int i, count; - count = csp_queue_size(conn->rdp.tx_queue); - for (i = 0; i < count; i++) { - - if ((csp_queue_dequeue_isr(conn->rdp.tx_queue, &packet, &pdTrue) != CSP_QUEUE_OK) || packet == NULL) { - csp_log_warn("Cannot dequeue from tx_queue in check timeout"); - break; - } - - /* Get header */ - rdp_header_t * header = csp_rdp_header_ref((csp_packet_t *) packet); - - /* If acked, do not retransmit */ - if (csp_rdp_seq_before(csp_ntoh16(header->seq_nr), conn->rdp.snd_una)) { - csp_log_protocol("TX Element Free, time %u, seq %u, una %u", packet->timestamp, csp_ntoh16(header->seq_nr), conn->rdp.snd_una); - csp_buffer_free(packet); - continue; - } - - /* Check timestamp and retransmit if needed */ - if (csp_rdp_time_after(time_now, packet->timestamp + conn->rdp.packet_timeout)) { - csp_log_protocol("TX Element timed out, retransmitting seq %u", csp_ntoh16(header->seq_nr)); - - /* Update to latest outgoing ACK */ - header->ack_nr = csp_hton16(conn->rdp.rcv_cur); - - /* Send copy to tx_queue */ - packet->timestamp = csp_get_ms(); - csp_packet_t * new_packet = csp_buffer_clone(packet); - csp_iface_t * ifout = csp_rtable_find_iface(conn->idout.dst); - if (csp_send_direct(conn->idout, new_packet, ifout, 0) != CSP_ERR_NONE) { - csp_log_warn("Retransmission failed"); - csp_buffer_free(new_packet); - } - - } - - /* Requeue the TX element */ - csp_queue_enqueue_isr(conn->rdp.tx_queue, &packet, &pdTrue); - - } - - /** - * ACK TIMEOUT: - * Check ACK timeouts, if we have unacknowledged segments - */ - if (conn->rdp.delayed_acks) { - csp_rdp_check_ack(conn); - } - - /* Wake user task if connection is open and additional Tx can be done */ - if ((conn->rdp.state == RDP_OPEN) && csp_rdp_is_conn_ready_for_tx(conn)) { - csp_log_protocol("RDP %p: Wake Tx task (check timeouts)", conn); - csp_bin_sem_post(&conn->rdp.tx_wait); - } -} - -void csp_rdp_new_packet(csp_conn_t * conn, csp_packet_t * packet) { - - /* Get RX header and convert to host byte-order */ - rdp_header_t * rx_header = csp_rdp_header_ref(packet); - rx_header->ack_nr = csp_ntoh16(rx_header->ack_nr); - rx_header->seq_nr = csp_ntoh16(rx_header->seq_nr); - - csp_log_protocol("RDP %p: Received in S %u: syn %u, ack %u, eack %u, " - "rst %u, seq_nr %5u, ack_nr %5u, packet_len %u (%u)", - conn, conn->rdp.state, rx_header->syn, rx_header->ack, rx_header->eak, - rx_header->rst, rx_header->seq_nr, rx_header->ack_nr, - packet->length, packet->length - sizeof(rdp_header_t)); - - /* If a RESET was received. */ - if (rx_header->rst) { - - if (rx_header->ack) { - /* Store current ack'ed sequence number */ - conn->rdp.snd_una = rx_header->ack_nr + 1; - } - - if (conn->rdp.state == RDP_CLOSE_WAIT || conn->rdp.state == RDP_CLOSED) { - csp_log_protocol("RDP %p: RST received in CLOSE_WAIT or CLOSED. Now closing connection", conn); - goto discard_close; - } else { - csp_log_protocol("RDP %p: Got RESET in state %u", conn, conn->rdp.state); - - if (rx_header->seq_nr == (uint16_t)(conn->rdp.rcv_cur + 1)) { - csp_log_protocol("RDP %p: RESET in sequence, no more data incoming, reply with RESET", conn); - conn->rdp.state = RDP_CLOSE_WAIT; - conn->timestamp = csp_get_ms(); - csp_rdp_send_cmp(conn, NULL, RDP_ACK | RDP_RST, conn->rdp.snd_nxt, conn->rdp.rcv_cur); - goto discard_close; - } else { - csp_log_protocol("RDP %p: RESET out of sequence, keep connection open", conn); - goto discard_open; - } - } - } - - /* The BIG FAT switch (state-machine) */ - switch(conn->rdp.state) { - - /** - * STATE == CLOSED - */ - case RDP_CLOSED: { - - /* No SYN flag set while in closed. Inform by sending back RST */ - if (!rx_header->syn) { - csp_log_protocol("Not SYN received in CLOSED state. Discarding packet"); - csp_rdp_send_cmp(conn, NULL, RDP_RST, conn->rdp.snd_nxt, conn->rdp.rcv_cur); - goto discard_close; - } - - csp_log_protocol("RDP: SYN-Received"); - - /* Setup TX seq. */ - conn->rdp.snd_iss = (uint16_t)rand(); - conn->rdp.snd_nxt = conn->rdp.snd_iss + 1; - conn->rdp.snd_una = conn->rdp.snd_iss; - - /* Store RX seq. */ - conn->rdp.rcv_cur = rx_header->seq_nr; - conn->rdp.rcv_irs = rx_header->seq_nr; - conn->rdp.rcv_lsa = rx_header->seq_nr; - - /* Store RDP options */ - conn->rdp.window_size = csp_ntoh32(packet->data32[0]); - conn->rdp.conn_timeout = csp_ntoh32(packet->data32[1]); - conn->rdp.packet_timeout = csp_ntoh32(packet->data32[2]); - conn->rdp.delayed_acks = csp_ntoh32(packet->data32[3]); - conn->rdp.ack_timeout = csp_ntoh32(packet->data32[4]); - conn->rdp.ack_delay_count = csp_ntoh32(packet->data32[5]); - csp_log_protocol("RDP: Window Size %u, conn timeout %u, packet timeout %u", - conn->rdp.window_size, conn->rdp.conn_timeout, conn->rdp.packet_timeout); - csp_log_protocol("RDP: Delayed acks: %u, ack timeout %u, ack each %u packet", - conn->rdp.delayed_acks, conn->rdp.ack_timeout, conn->rdp.ack_delay_count); - - /* Connection accepted */ - conn->rdp.state = RDP_SYN_RCVD; - - /* Send SYN/ACK */ - csp_rdp_send_cmp(conn, NULL, RDP_ACK | RDP_SYN, conn->rdp.snd_iss, conn->rdp.rcv_irs); - - goto discard_open; - - } - break; - - /** - * STATE == SYN-SENT - */ - case RDP_SYN_SENT: { - - /* First check SYN/ACK */ - if (rx_header->syn && rx_header->ack) { - - conn->rdp.rcv_cur = rx_header->seq_nr; - conn->rdp.rcv_irs = rx_header->seq_nr; - conn->rdp.rcv_lsa = rx_header->seq_nr - 1; - conn->rdp.snd_una = rx_header->ack_nr + 1; - conn->rdp.ack_timestamp = csp_get_ms(); - conn->rdp.state = RDP_OPEN; - - csp_log_protocol("RDP: NP: Connection OPEN"); - - /* Send ACK */ - csp_rdp_send_cmp(conn, NULL, RDP_ACK, conn->rdp.snd_nxt, conn->rdp.rcv_cur); - - /* Wake TX task */ - csp_log_protocol("RDP %p: Wake Tx task (ack)", conn); - csp_bin_sem_post(&conn->rdp.tx_wait); - - goto discard_open; - } - - /* If there was no SYN in the reply, our SYN message hit an already open connection - * This is handled by sending a RST. - * Normally this would be followed up by a new connection attempt, however - * we don't have a method for signaling this to the user space. - */ - if (rx_header->ack) { - csp_log_error("Half-open connection found, sending RST"); - csp_rdp_send_cmp(conn, NULL, RDP_RST, conn->rdp.snd_nxt, conn->rdp.rcv_cur); - csp_log_protocol("RDP %p: Wake Tx task (rst)", conn); - csp_bin_sem_post(&conn->rdp.tx_wait); - - goto discard_open; - } - - /* Otherwise we have an invalid command, such as a SYN reply to a SYN command, - * indicating simultaneous connections, which is not possible in the way CSP - * reserves some ports for server and some for clients. - */ - csp_log_error("Invalid reply to SYN request"); - goto discard_close; - - } - break; - - /** - * STATE == OPEN - */ - case RDP_SYN_RCVD: - case RDP_OPEN: - { - - /* SYN or !ACK is invalid */ - if (rx_header->syn || !rx_header->ack) { - if (rx_header->seq_nr != conn->rdp.rcv_irs) { - csp_log_error("Invalid SYN or no ACK, resetting!"); - goto discard_close; - } else { - csp_log_protocol("Ignoring duplicate SYN packet!"); - goto discard_open; - } - } - - /* Check sequence number */ - if (!csp_rdp_seq_between(rx_header->seq_nr, conn->rdp.rcv_cur + 1, conn->rdp.rcv_cur + conn->rdp.window_size * 2)) { - csp_log_protocol("Invalid sequence number! %"PRIu16" not between %"PRIu16" and %"PRIu16, - rx_header->seq_nr, conn->rdp.rcv_cur + 1, conn->rdp.rcv_cur + 1 + conn->rdp.window_size * 2); - /* If duplicate SYN received, send another SYN/ACK */ - if (conn->rdp.state == RDP_SYN_RCVD) - csp_rdp_send_cmp(conn, NULL, RDP_ACK | RDP_SYN, conn->rdp.snd_iss, conn->rdp.rcv_irs); - /* If duplicate data packet received, send EACK back */ - if (conn->rdp.state == RDP_OPEN) - csp_rdp_send_eack(conn); - - goto discard_open; - } - - /* Check ACK number */ - if (!csp_rdp_seq_between(rx_header->ack_nr, conn->rdp.snd_una - 1 - (conn->rdp.window_size * 2), conn->rdp.snd_nxt - 1)) { - csp_log_error("Invalid ACK number! %u not between %u and %u", - rx_header->ack_nr, conn->rdp.snd_una - 1 - (conn->rdp.window_size * 2), conn->rdp.snd_nxt - 1); - goto discard_open; - } - - /* Check SYN_RCVD ACK */ - if (conn->rdp.state == RDP_SYN_RCVD) { - if (rx_header->ack_nr != conn->rdp.snd_iss) { - csp_log_error("SYN-RCVD: Wrong ACK number"); - goto discard_close; - } - csp_log_protocol("RDP: NC: Connection OPEN"); - conn->rdp.state = RDP_OPEN; - - /* If a socket is set, this message is the first in a new connection - * so the connection must be queued to the socket. */ - if (conn->socket != NULL) { - - /* Try queueing */ - if (csp_queue_enqueue(conn->socket, &conn, 0) == CSP_QUEUE_FULL) { - csp_log_error("ERROR socket cannot accept more connections"); - goto discard_close; - } - - /* Ensure that this connection will not be posted to this socket again - * and remember that the connection handle has been passed to userspace - * by setting the socket = NULL */ - conn->socket = NULL; - } - - } - - /* Store current ack'ed sequence number */ - conn->rdp.snd_una = rx_header->ack_nr + 1; - - /* We have an EACK */ - if (rx_header->eak) { - if (packet->length > sizeof(rdp_header_t)) - csp_rdp_flush_eack(conn, packet); - goto discard_open; - } - - /* If no data, return here */ - if (packet->length <= sizeof(rdp_header_t)) - goto discard_open; - - /* If message is not in sequence, send EACK and store packet */ - if (rx_header->seq_nr != (uint16_t)(conn->rdp.rcv_cur + 1)) { - if (csp_rdp_rx_queue_add(conn, packet, rx_header->seq_nr) != CSP_QUEUE_OK) { - csp_log_protocol("Duplicate sequence number"); - csp_rdp_check_ack(conn); - goto discard_open; - } - csp_rdp_send_eack(conn); - goto accepted_open; - } - - /* Store sequence number before stripping RDP header */ - uint16_t seq_nr = rx_header->seq_nr; - - /* Receive data */ - if (csp_rdp_receive_data(conn, packet) != CSP_ERR_NONE) - goto discard_open; - - /* Update last received packet */ - conn->rdp.rcv_cur = seq_nr; - - /* Only ACK the message if there is room for a full window in the RX buffer. - * Unacknowledged segments are ACKed by csp_rdp_check_timeouts when the buffer is - * no longer full. */ - csp_rdp_check_ack(conn); - - /* Flush RX queue */ - csp_rdp_rx_queue_flush(conn); - - goto accepted_open; - - } - break; - - case RDP_CLOSE_WAIT: - - /* Ignore SYN or !ACK */ - if (rx_header->syn || !rx_header->ack) { - csp_log_protocol("Invalid SYN or no ACK in CLOSE-WAIT"); - goto discard_open; - } - - /* Check ACK number */ - if (!csp_rdp_seq_between(rx_header->ack_nr, conn->rdp.snd_una - 1 - (conn->rdp.window_size * 2), conn->rdp.snd_nxt - 1)) { - csp_log_error("Invalid ACK number! %u not between %u and %u", - rx_header->ack_nr, conn->rdp.snd_una - 1 - (conn->rdp.window_size * 2), conn->rdp.snd_nxt - 1); - goto discard_open; - } - - /* Store current ack'ed sequence number */ - conn->rdp.snd_una = rx_header->ack_nr + 1; - - /* Send back a reset */ - csp_rdp_send_cmp(conn, NULL, RDP_ACK | RDP_RST, conn->rdp.snd_nxt, conn->rdp.rcv_cur); - - goto discard_open; - - default: - csp_log_error("RDP: ERROR default state!"); - goto discard_close; - } - -discard_close: - /* If user-space has received the connection handle, wake it up, - * by sending a NULL pointer, user-space should close connection */ - if (conn->socket == NULL) { - csp_log_protocol("RDP %p: Waiting for userspace to close", conn); - csp_conn_enqueue_packet(conn, NULL); - } else { - csp_close(conn); - } - -discard_open: - csp_buffer_free(packet); -accepted_open: - return; - -} - -int csp_rdp_connect(csp_conn_t * conn, uint32_t timeout) { - - int retry = 1; - - conn->rdp.window_size = csp_rdp_window_size; - conn->rdp.conn_timeout = csp_rdp_conn_timeout; - conn->rdp.packet_timeout = csp_rdp_packet_timeout; - conn->rdp.delayed_acks = csp_rdp_delayed_acks; - conn->rdp.ack_timeout = csp_rdp_ack_timeout; - conn->rdp.ack_delay_count = csp_rdp_ack_delay_count; - conn->rdp.ack_timestamp = csp_get_ms(); - -retry: - csp_log_protocol("RDP %p: Active connect, conn state %u", conn, conn->rdp.state); - - if (conn->rdp.state == RDP_OPEN) { - csp_log_error("RDP %p: Connection already open", conn); - return CSP_ERR_ALREADY; - } - - /* Randomize ISS */ - conn->rdp.snd_iss = (uint16_t)rand(); - - conn->rdp.snd_nxt = conn->rdp.snd_iss + 1; - conn->rdp.snd_una = conn->rdp.snd_iss; - - csp_log_protocol("RDP %p: AC: Sending SYN", conn); - - /* Ensure semaphore is busy, so router task can release it */ - csp_bin_sem_wait(&conn->rdp.tx_wait, 0); - - /* Send SYN message */ - conn->rdp.state = RDP_SYN_SENT; - if (csp_rdp_send_syn(conn) != CSP_ERR_NONE) - goto error; - - /* Wait for router task to release semaphore */ - csp_log_protocol("RDP %p: AC: Waiting for SYN/ACK reply...", conn); - int result = csp_bin_sem_wait(&conn->rdp.tx_wait, conn->rdp.conn_timeout); - - if (result == CSP_SEMAPHORE_OK) { - if (conn->rdp.state == RDP_OPEN) { - csp_log_protocol("RDP %p: AC: Connection OPEN", conn); - return CSP_ERR_NONE; - } else if(conn->rdp.state == RDP_SYN_SENT) { - if (retry) { - csp_log_warn("RDP %p: Half-open connection detected, RST sent, now retrying", conn); - csp_rdp_flush_all(conn); - retry = 0; - goto retry; - } else { - csp_log_error("RDP %p: Connection stayed half-open, even after RST and retry!", conn); - goto error; - } - } - } else { - csp_log_protocol("RDP %p: AC: Connection Failed", conn); - goto error; - } - -error: - conn->rdp.state = RDP_CLOSE_WAIT; - return CSP_ERR_TIMEDOUT; - -} - -int csp_rdp_send(csp_conn_t * conn, csp_packet_t * packet, uint32_t timeout) { - - if (conn->rdp.state != RDP_OPEN) { - csp_log_error("RDP: ERROR cannot send, connection reset"); - return CSP_ERR_RESET; - } - - while ((conn->rdp.state == RDP_OPEN) && (csp_rdp_is_conn_ready_for_tx(conn) == false)) { - csp_log_protocol("RDP %p: Waiting for window update before sending seq %u", conn, conn->rdp.snd_nxt); - if ((csp_bin_sem_wait(&conn->rdp.tx_wait, conn->rdp.conn_timeout)) != CSP_SEMAPHORE_OK) { - csp_log_error("RDP %p: Timeout during send", conn); - return CSP_ERR_TIMEDOUT; - } - } - - if (conn->rdp.state != RDP_OPEN) { - csp_log_error("RDP: ERROR cannot send, connection reset"); - return CSP_ERR_RESET; - } - - /* Add RDP header */ - rdp_header_t * tx_header = csp_rdp_header_add(packet); - tx_header->ack_nr = csp_hton16(conn->rdp.rcv_cur); - tx_header->seq_nr = csp_hton16(conn->rdp.snd_nxt); - tx_header->ack = 1; - - /* Send copy to tx_queue */ - rdp_packet_t * rdp_packet = csp_buffer_clone(packet); - if (rdp_packet == NULL) { - csp_log_error("Failed to allocate packet buffer"); - return CSP_ERR_NOMEM; - } - - rdp_packet->timestamp = csp_get_ms(); - rdp_packet->quarantine = 0; - if (csp_queue_enqueue(conn->rdp.tx_queue, &rdp_packet, 0) != CSP_QUEUE_OK) { - csp_log_error("No more space in RDP retransmit queue"); - csp_buffer_free(rdp_packet); - return CSP_ERR_NOBUFS; - } - - csp_log_protocol("RDP: Sending in S %u: syn %u, ack %u, eack %u, " - "rst %u, seq_nr %5u, ack_nr %5u, packet_len %u (%u)", - conn->rdp.state, tx_header->syn, tx_header->ack, tx_header->eak, - tx_header->rst, csp_ntoh16(tx_header->seq_nr), csp_ntoh16(tx_header->ack_nr), - packet->length, packet->length - sizeof(rdp_header_t)); - - conn->rdp.snd_nxt++; - return CSP_ERR_NONE; - -} - -int csp_rdp_allocate(csp_conn_t * conn) { - - csp_log_protocol("RDP: Creating RDP queues for conn %p", conn); - - /* Set initial state */ - conn->rdp.state = RDP_CLOSED; - conn->rdp.conn_timeout = csp_rdp_conn_timeout; - conn->rdp.packet_timeout = csp_rdp_packet_timeout; - - /* Create a binary semaphore to wait on for tasks */ - if (csp_bin_sem_create(&conn->rdp.tx_wait) != CSP_SEMAPHORE_OK) { - csp_log_error("Failed to initialize semaphore"); - return CSP_ERR_NOMEM; - } - - /* Create TX queue */ - conn->rdp.tx_queue = csp_queue_create(CSP_RDP_MAX_WINDOW, sizeof(csp_packet_t *)); - if (conn->rdp.tx_queue == NULL) { - csp_log_error("Failed to create TX queue for conn"); - csp_bin_sem_remove(&conn->rdp.tx_wait); - return CSP_ERR_NOMEM; - } - - /* Create RX queue */ - conn->rdp.rx_queue = csp_queue_create(CSP_RDP_MAX_WINDOW * 2, sizeof(csp_packet_t *)); - if (conn->rdp.rx_queue == NULL) { - csp_log_error("Failed to create RX queue for conn"); - csp_bin_sem_remove(&conn->rdp.tx_wait); - csp_queue_remove(conn->rdp.tx_queue); - return CSP_ERR_NOMEM; - } - - return CSP_ERR_NONE; - -} - -/** - * @note This function may only be called from csp_close, and is therefore - * without any checks for null pointers. - */ -int csp_rdp_close(csp_conn_t * conn) { - - if (conn->rdp.state == RDP_CLOSED) - return CSP_ERR_NONE; - - /* If message is open, send reset */ - if (conn->rdp.state != RDP_CLOSE_WAIT) { - conn->rdp.state = RDP_CLOSE_WAIT; - conn->timestamp = csp_get_ms(); - csp_rdp_send_cmp(conn, NULL, RDP_ACK | RDP_RST, conn->rdp.snd_nxt, conn->rdp.rcv_cur); - csp_log_protocol("RDP %p: Close, sent RST", conn); - csp_bin_sem_post(&conn->rdp.tx_wait); // wake up any pendng Tx - return CSP_ERR_AGAIN; - } - - csp_log_protocol("RDP %p: Close in CLOSE_WAIT, now closing", conn); - conn->rdp.state = RDP_CLOSED; - return CSP_ERR_NONE; - -} - -/** - * RDP Set socket options - * Controls important parameters of the RDP protocol. - * These settings will be applied to all new outgoing connections. - * The settings are global, so be sure no other task are conflicting with your settings. - */ -void csp_rdp_set_opt(unsigned int window_size, unsigned int conn_timeout_ms, - unsigned int packet_timeout_ms, unsigned int delayed_acks, - unsigned int ack_timeout, unsigned int ack_delay_count) { - csp_rdp_window_size = window_size; - csp_rdp_conn_timeout = conn_timeout_ms; - csp_rdp_packet_timeout = packet_timeout_ms; - csp_rdp_delayed_acks = delayed_acks; - csp_rdp_ack_timeout = ack_timeout; - csp_rdp_ack_delay_count = ack_delay_count; -} - -void csp_rdp_get_opt(unsigned int * window_size, unsigned int * conn_timeout_ms, - unsigned int * packet_timeout_ms, unsigned int * delayed_acks, - unsigned int * ack_timeout, unsigned int * ack_delay_count) { - - if (window_size) - *window_size = csp_rdp_window_size; - if (conn_timeout_ms) - *conn_timeout_ms = csp_rdp_conn_timeout; - if (packet_timeout_ms) - *packet_timeout_ms = csp_rdp_packet_timeout; - if (delayed_acks) - *delayed_acks = csp_rdp_delayed_acks; - if (ack_timeout) - *ack_timeout = csp_rdp_ack_timeout; - if (ack_delay_count) - *ack_delay_count = csp_rdp_ack_delay_count; -} - -#ifdef CSP_DEBUG -void csp_rdp_conn_print(csp_conn_t * conn) { - - if (conn == NULL) - return; - - printf("\tRDP: State %"PRIu16", rcv %"PRIu16", snd %"PRIu16", win %"PRIu32"\r\n", - conn->rdp.state, conn->rdp.rcv_cur, conn->rdp.snd_una, conn->rdp.window_size); - -} -#endif - -#endif diff --git a/gomspace/libgscsp/lib/libcsp/src/transport/csp_transport.h b/gomspace/libgscsp/lib/libcsp/src/transport/csp_transport.h deleted file mode 100644 index 7fcda3dc..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/transport/csp_transport.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _CSP_TRANSPORT_H_ -#define _CSP_TRANSPORT_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/** ARRIVING SEGMENT */ -void csp_udp_new_packet(csp_conn_t * conn, csp_packet_t * packet); -void csp_rdp_new_packet(csp_conn_t * conn, csp_packet_t * packet); - -/** RDP: USER REQUESTS */ -int csp_rdp_connect(csp_conn_t * conn, uint32_t timeout); -int csp_rdp_allocate(csp_conn_t * conn); -int csp_rdp_close(csp_conn_t * conn); -void csp_rdp_conn_print(csp_conn_t * conn); -int csp_rdp_send(csp_conn_t * conn, csp_packet_t * packet, uint32_t timeout); -int csp_rdp_check_ack(csp_conn_t * conn); -void csp_rdp_check_timeouts(csp_conn_t * conn); -void csp_rdp_flush_all(csp_conn_t * conn); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* _CSP_TRANSPORT_H_ */ diff --git a/gomspace/libgscsp/lib/libcsp/src/transport/csp_udp.c b/gomspace/libgscsp/lib/libcsp/src/transport/csp_udp.c deleted file mode 100644 index 61732703..00000000 --- a/gomspace/libgscsp/lib/libcsp/src/transport/csp_udp.c +++ /dev/null @@ -1,49 +0,0 @@ -/* -Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include "../csp_port.h" -#include "../csp_conn.h" -#include "csp_transport.h" - -void csp_udp_new_packet(csp_conn_t * conn, csp_packet_t * packet) { - - /* Enqueue */ - if (csp_conn_enqueue_packet(conn, packet) < 0) { - csp_log_error("Connection buffer queue full!"); - csp_buffer_free(packet); - return; - } - - /* Try to queue up the new connection pointer */ - if (conn->socket != NULL) { - if (csp_queue_enqueue(conn->socket, &conn, 0) != CSP_QUEUE_OK) { - csp_log_warn("Warning socket connection queue full"); - csp_close(conn); - return; - } - - /* Ensure that this connection will not be posted to this socket again */ - conn->socket = NULL; - } - -} - diff --git a/gomspace/libgscsp/lib/libcsp/utils/cfpsplit.py b/gomspace/libgscsp/lib/libcsp/utils/cfpsplit.py deleted file mode 100644 index 9a350e3e..00000000 --- a/gomspace/libgscsp/lib/libcsp/utils/cfpsplit.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python - -# Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -# Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -# Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -# Split CFP header in protocol fields - -import sys - -def usage(): - print("usage: cfpsplit.py HEADER") - -def main(): - try: - hdr = sys.argv[1] - except: - usage() - sys.exit(-1) - - try: - hdrhex = int(hdr, 16) - except: - print("HEADER must be in hexadecimal format") - sys.exit(-1) - - if hdrhex > 0x1fffffff: - print("HEADER is not a valid CFP header") - sys.exit(-1) - - print("Source: {0}".format((hdrhex >> 24) & 0x1f)) - print("Destination: {0}".format((hdrhex >> 19) & 0x1f)) - print("Type: {0}".format("MORE" if ((hdrhex >> 18) & 0x01) else "BEGIN")) - print("Remain: {0}".format((hdrhex >> 10) & 0xff)) - print("Identifier: {0}".format((hdrhex >> 0) & 0x3ff)) - -if __name__ == "__main__": - main() diff --git a/gomspace/libgscsp/lib/libcsp/utils/cspsplit.py b/gomspace/libgscsp/lib/libcsp/utils/cspsplit.py deleted file mode 100644 index f4ed942f..00000000 --- a/gomspace/libgscsp/lib/libcsp/utils/cspsplit.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python - -# Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -# Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -# Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -# Split CSP header in protocol fields - -import sys - -def usage(): - print("usage: cspsplit.py HEADER") - -def main(): - try: - hdr = sys.argv[1] - except: - usage() - sys.exit(-1) - - try: - hdrhex = int(hdr, 16) - except: - print("HEADER must be in hexadecimal format") - sys.exit(-1) - - print("Priotity: {0}".format((hdrhex >> 30) & 0x03)) - print("Source: {0}".format((hdrhex >> 25) & 0x1f)) - print("Destination: {0}".format((hdrhex >> 20) & 0x1f)) - print("Destination port: {0}".format((hdrhex >> 14) & 0x3f)) - print("Source port: {0}".format((hdrhex >> 8) & 0x3f)) - print("HMAC: {0}".format("Yes" if ((hdrhex >> 3) & 0x01) else "No")) - print("XTEA: {0}".format("Yes" if ((hdrhex >> 2) & 0x01) else "No")) - print("RDP: {0}".format("Yes" if ((hdrhex >> 1) & 0x01) else "No")) - print("CRC32: {0}".format("Yes" if ((hdrhex >> 0) & 0x01) else "No")) - -if __name__ == "__main__": - main() diff --git a/gomspace/libgscsp/lib/libcsp/waf b/gomspace/libgscsp/lib/libcsp/waf deleted file mode 100644 index 4b322f1a..00000000 --- a/gomspace/libgscsp/lib/libcsp/waf +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env python -# encoding: ISO8859-1 -# Thomas Nagy, 2005-2016 - -""" -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. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 AUTHOR 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. -""" - -import os, sys, inspect - -VERSION="1.8.19" -REVISION="b1fc8f7baef51bd2db4c2971909a568d" -GIT="22213cd8abbd141bda40667f7ca2a48f2d6ad785" -INSTALL='' -C1='#5' -C2='#/' -C3='#,' -cwd = os.getcwd() -join = os.path.join - - -WAF='waf' -def b(x): - return x -if sys.hexversion>0x300000f: - WAF='waf3' - def b(x): - return x.encode() - -def err(m): - print(('\033[91mError: %s\033[0m' % m)) - sys.exit(1) - -def unpack_wafdir(dir, src): - f = open(src,'rb') - c = 'corrupt archive (%d)' - while 1: - line = f.readline() - if not line: err('run waf-light from a folder containing waflib') - if line == b('#==>\n'): - txt = f.readline() - if not txt: err(c % 1) - if f.readline() != b('#<==\n'): err(c % 2) - break - if not txt: err(c % 3) - txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r')).replace(b(C3), b('\x00')) - - import shutil, tarfile - try: shutil.rmtree(dir) - except OSError: pass - try: - for x in ('Tools', 'extras'): - os.makedirs(join(dir, 'waflib', x)) - except OSError: - err("Cannot unpack waf lib into %s\nMove waf in a writable directory" % dir) - - os.chdir(dir) - tmp = 't.bz2' - t = open(tmp,'wb') - try: t.write(txt) - finally: t.close() - - try: - t = tarfile.open(tmp) - except: - try: - os.system('bunzip2 t.bz2') - t = tarfile.open('t') - tmp = 't' - except: - os.chdir(cwd) - try: shutil.rmtree(dir) - except OSError: pass - err("Waf cannot be unpacked, check that bzip2 support is present") - - try: - for x in t: t.extract(x) - finally: - t.close() - - for x in ('Tools', 'extras'): - os.chmod(join('waflib',x), 493) - - if sys.hexversion<0x300000f: - sys.path = [join(dir, 'waflib')] + sys.path - import fixpy2 - fixpy2.fixdir(dir) - - os.remove(tmp) - os.chdir(cwd) - - try: dir = unicode(dir, 'mbcs') - except: pass - try: - from ctypes import windll - windll.kernel32.SetFileAttributesW(dir, 2) - except: - pass - -def test(dir): - try: - os.stat(join(dir, 'waflib')) - return os.path.abspath(dir) - except OSError: - pass - -def find_lib(): - src = os.path.abspath(inspect.getfile(inspect.getmodule(err))) - base, name = os.path.split(src) - - #devs use $WAFDIR - w=test(os.environ.get('WAFDIR', '')) - if w: return w - - #waf-light - if name.endswith('waf-light'): - w = test(base) - if w: return w - err('waf-light requires waflib -> export WAFDIR=/folder') - - dirname = '%s-%s-%s' % (WAF, VERSION, REVISION) - for i in (INSTALL,'/usr','/usr/local','/opt'): - w = test(i + '/lib/' + dirname) - if w: return w - - #waf-local - dir = join(base, (sys.platform != 'win32' and '.' or '') + dirname) - w = test(dir) - if w: return w - - #unpack - unpack_wafdir(dir, src) - return dir - -wafdir = find_lib() -sys.path.insert(0, wafdir) - -if __name__ == '__main__': - - from waflib import Scripting - Scripting.waf_entry_point(cwd, VERSION, wafdir) - -#==> -#BZh91AY&SYmEõKQ#/ÿÿÿ°#,Óÿÿÿÿÿÿÿÿÿÿÿ„ Y Â#%H4#,`(bÜrû}Ñ#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,ÕÓ­ul]ZåÍë}i{l4­´ï±®í_pÝlkLϱ÷dzvúݺ{¾]òxì¾ó¥Ô´©…Rúøq楯½¯y\ÃÛe… h«Ì÷g¡éEm.Ç»u­w¦×ºÔë]2]ôõyk=·{»º¼å·[ž®×™½×ywÞ@=ggÅíkWe÷œ}}À}ìowÕãNzî#,#,#,è#, yì#,x->€è#,ûØÜ<¼À*©©{¸WLåÜû·a¦ƒOl¥Ø5nûÛ§FƒËÊ#,·m6Ð ØÑÛPP½ºu(QBª#5 JJöeGc@#,¤’ P6bªîàïA—nâûîׯZ>ÝÃãH½ž'»{´½íp#/ÍKØÔvPÊZ6îîûÞtÃjÒ>©·Þ·£¾{šûzèÓÝl›»_7Zíôìíëéß}ÙÛ¡¦MZûÚõlíζˮ83oM<€k=bWGÓªU¤Ž rz5O{½ÏyÞå뽇 ôz#/o3ÕPKh—F;ÛÝæ·Ûl5­#5ªvê½Ù¦‡¯f­î{©%žöëÕŽÚ»sg¼RÃË’î}¹Ÿ}ÞÐ#/#//·ZÅ"õîiµÍÀŸç@[ßsÇ­·®Øèì^s +ŽÞ€>û½îBqŸ*ÓKïxÓG5_/»=ÝÐ=ª£¾Ü'Ø}Â>9¶¦¶ë¯½÷e…åÏ6íëžÝÓmõvuÛnúåëÎãï{›E³{«·6·u.#/Ýö»ÎÛêï·îNî»^FM>ŽO}¤ÓˆßX¥­áÍL|R¡ZÛu.9ñ.÷;ìí«/nûÝÞÛ¯7rúçµj;<è¼ßF¾ù¹¾öogƒŸnžïj½zÛ|`uï¾uòú-íèúy=gÔ#, J=°#@˜S{0)ÚRO½Ôó5^‡¯^ñN²>·3îeÝÖk|½ÚðöP•Ü§;{¸Š‰ïUíØ)¨+×Kßw^|#,=Üu #,=ïŸ^—|ívõÞ§Ãv¾Ÿqw{ß]8¾ŽtÓz#¸§í×HÛ˜×@ÓÄåÎÙì^vÛlÒÈλ÷¼zÞ‹›g¾|å6ÝÛÀ%W ¢ëî»ïW×ݶûêx};ìßešô>æ&¾Ž{o=—Þ}î»{¶oŸkÛÝÞ:Þ{}»‡ÛkL}½>û>ya—Û½¾vòÛÀÖŠï°£®šqM_^/…ó:è5í„éx_-ê»IÚžÛíïynOµ@}o³+LUS¯4ºŸZ:û=àuîžæî­a+ïW{ëS¥¾ofw[{½ï\î7Ïvò_|î÷\VŠ€:Õ/±¡Û̳ÏnR„+Åw¨Ñ†#/×_wÑãÛ@mg #,#,ùíÜ:;¶5èkGv»sÉ®Wß"}½Àt@õïxõõèÞê“6ù·wuÏN×Vvû¤½­Îíº‹F’HÍÎ.î‰õ‡Sy½çUr^ßN/FϧÝîO®·Ð¦çq«^;N!ßyNû¬·£à´Ä“NŽí¸{›ovŒkwV¾]ÜÚÛv™òzÉ÷ßskí´ÙNÛ®Ûo6¾÷ÏSæo‡#|w M @#,É Ó#/ ™iODžˆ¥=CjA‰‘êx JhD@„Äi2hÔj6™Sð£D4òÓ'¨#,#,#,4#,#,A!! A¢bh' Sòh ž©6Dõ='©é6 Ð7©#,#,#,#,#,'ªQI4j<ši‰¤ôSf”ôÑ=OHz@#/#,Ш#,3I¡ #,#,#,#,$ˆ#, i0M#,§¡¦‰¦"{I“I‚O$z4Ð#,#,#,#,j"#, Ñ #5™é=SCÑ<©ížò‡Šzž§ê˜€ Ð#,È×ý+m«ÿîbcú†Ö¹µ¹uÉ~ÆÛS°“)#5=¶®º3&ª-5³åV­WêêmV¾Èþ#òþ'—òüµû #Îo{ÉÃMòÎg5ÌÇœ¦o9­Ì¦ç.înç9£šs-Ïð´èJ}B-~¨Z¯¦ÛRªßkæÈD&Tƒ%ŠªÆ(°xT)U\óâãóÏEÓ<š7^øIË̶ëXI³&>rµŒÕÞVª«L*ØiH ?#/ÕõŠ7ÀR ÀYeË©jÒµZ*Ú1µm#,-ÕB¨IX(¤È‚ ‚¡!„[*E±#,|à…R‚ Õ F±V«m¯¿kjµL‚@¡ ı™¦ &D4c6™QSR%Œ‰%(ÒŠm¤¨EL’X XMSQT”DJ “4M”-”ÆJÌ £I,hM0¥F’)6"ÑJmIJZS"Ô@ %–’#5’`˜2’)lQm“T#/A”²¢–&¥()%Ò‰Yš‹F¢´«iU©I6¢dÌ™4lUZ•¬f˜fÌÓ6¤±šm°KM±5-M2jadS$š djF•¤ÖB*M&ƒL’ZH-¦±’²h˜!`£3M1šlb`•4°HA˜†31#/†I‘(‰(l›R@‘KŠÉ¡’#2‘„–f–)2A´˜c%4–ÒTZ#/¦5*ECI†Š4Òl(’Q&È¥±1Pl™M¢’e¤2’&ƒF”ŒÉRŠ)™6ÈT2(–E’BH…6"ÒX5 ¨…"J*5D”…3b $Ô–)1H‰”Œd™3Fa-™S ØJ‚ˆ‰!*M‰ ’M%`Ä”–,³0lÚ#M#FÂJ!e$ ¤Í‘)š¥›,¥Ë0É¥’ji”h#/¥ŠK264ed&bIZ––HXCeA¦Ì Æ£f‘±†SKS[M†!3H¢ÌDjL”š@ÓIK-,©QQD‚Š#/‚&$Ȉ’”Æ4 #$4ÌP¢!•3-¤EaJ¤!”©&B”…6’ÒQl‘¬i&I% E’šÈ¶F̆LцÉ&Ê“L¦¢1Ë*™¥1 P©“DTѳSb“(²2bJE*I!e2,Ji‚´¤É²’f&É£&B¡¤`B5$Ë)YI†ÐY6J@“!%“(ÈE3A’2™HË0–’•Mš*6‹BeÈ”‘ÔbØÒLÖE#/&60’FTi#/*%k,˜Q¬eš™"f‹&–DJÅ,€5JJ2ŒÒ5µ6Ûh(¶0IS@´”ÊHÑb™)’cI£l–”³F˜¤Ìe3K*M”±jdcal’#5›(ÊFhÓe¯Úmv4…•¤¤%J2SX«EbÑQ²IšTDÓ%KAQ°Š’V¦"†Æ–!™e) RF³*Ô&Ú,Šk&Cc)–•E¡bd¦5-*c$&,32•Y£e”#k*ER©X¦Ê$²£)µdÔˆÖɦVD©5 [%YYJSL+f(i‘5£KMD–’%ƱXÕ3h¶ÛH3`±ªÂF¤Ñ¶Æѱ²Qª3LÄ5E!¨4jÅQ°ÍHmbY0¢5³Rhe1%‚h±„5(”Ú–Äm$šÆ5!b´’šµ³VÓA,#ei6F&³l‰3)©¥#5I–Õ6¢–’”Ô²¤¶š¦ÒZ¦˜“²¦Rɶ–m¦ÌZ4f¶k32I¬±¡›¤ÛKYRSJ(ˆ C5J4‰ŒQ°b„- 3–ѵ$JME2š£iI¥FLš#/%0ŠE,¨ŠAieH€i¢˜)’e6hbÄ„¤TZ,É b•š’ÀclË3K1š`©¨™Ñ2FLlBÌK!I´lI¤£&h4‹2‹S2TÅ4Rma3`Ñ#5TXÌ1S6 RÉBlE†54Ú3 3h¨±±±F„hÆÉ©¡"“aK-“$¤¦L¦Á’Ø…3R‰2I²ÒˆJ¨²Ô™¢6”ÒlÆÒei+Ä#”dfM”“BTš“)FÌÓj[,Ø´”³I²lbTQfŠJfdÑ©–´Œ”¥¢ÁH‘›$FY‘1¢Òš#@ÖY6Jhbb&“I F¢5BTmmˆ­1¤ÃI2ÄÊ &‘h¦•É K#5¥e$š *5“0²ie24´›mIkhЙfÚ‚H´–ÅA£ ,#/›R”JQliIš¨Ù&k2*H’£I"Ë*ÔƆMEc&&VJˆ¦”¡Q¥%4ET±*Je)FÛ`µ$Qd£dª0Ê6Kd¤Ô›j”ÑIEJjµ&ÅCI3d†RTXiH‹- ””ÆhÁ´˜#5‰3BÁª”FÈÊV&#JKEhƲEd„6%`Š1”¶#h¬¤”T€h1E& “V”ZST¦Òj-±¬VÍ1Y-f¢©š’‹Å(#(1³B$¡4l”Á£VÄm‹hØÒšÖHe¢#5Æ&¢Ñ­6Ë6£h´TZÆI5©fÍÒÊĪ1h³,UMIHÛ(Ë)DÒFÊÅ`’Æ’Ù-d¢Ô–±I´¦eM¢Â‘QIF‹kT­´ŒeCI¢$©”Z66† ÒZ[$ÛIŒÉl‚›%Eµ$¶ŠÑ­‹FÛhÚ¡K&ÖÄZ¦¥e´J2ŠbFÒL`©lMšlT‘²È¨ ™‰1$™I2$¡jM±fV¦?‹çý5üKý&¼ |ü©ŒRžÜÐZdI‹©±‡þå©-Iû²Ò/E¹±ò»´–^ï|¿¦¿¤ë×ô£Æ°Tԥƪ?ðÖã,Sý^‰b¨ O¦ò¢ób¬M4ºd7%‚•Ä3³m´5T;%ëvþ>zãyg÷îÐÿƒÌ³'ù£Ÿ,¯uc/eÕLŠYÝ]ÈZ1±, òt–u÷ë-²'«êÆÚe)‰QéjoÎQmå¦Ðn¥ØГfN½1j—qÈqÖ=c,„Â’¦6Ýr¸6=)`ó¨S‚¢5Š¨ªìÃKJÈÒ|9ëW®Y×[#¿Êní·ei”-M(¥@Ñ ¸_ñQ eRËFƶh&«ìºòO9Q ‰¸‘6Y6?óÀÝ€4Í5ȤU5vZ±ËQ­îX?ùhÿÀ¦ãaRµ^Ô›2Æ*Šžê2ØÁdX¿ë¹aßÝZ3#,©Ñ#57ªAOS(C (`)UAÒ¼®—é­u›ërÖæå‹òöêÞKŠež f>ÐD¹Ó§‘&²–9©%C™E¤¹æ%Š¿žªùOUòmº˜šƒ@ìQ†EÇÛ{zY]J4}]¢­0n(i¥JÂn@rpeË’nºìNºéŠƒ}K[ËÎÿlàUŠ ,D¬ÐÑ(Fí¶R·-"‚¿MTFzè­UiŽ´ÿÚz`™`ÿ¦ˆÎ™O-Li6ÂJ°¹@`@hÔ¨OÐVâ<çÕ€˜Ú˜Dã™{Œ’àq¶Ü`Cò“U}Ã]¿l]~>îÙ›ˆ­Vpò…§†o‘;J0Û)¨ãjåýeNôÕ8TãLhµÅ©j¶0æCfB(t\´Ã·µö% v3IêåS—ʉf´0 ÷09!àá­ñÁ±´µºÎš‰™Ú†{¦’z XZ%l²ÜÝ(ÂOa"ÚO– ½:Þ>×åŠ0ö@¨ÎÚÑfÉPe‰J#5WïÉ—RcäÝ¿£ZÁ6–‘»GÕ"_ºø7Ýv›$£#}þ»_zîF: ãe.¶W7"^*®P‹ÿ‰¥ð$cós´WŽLŽVÚiþÎУ²?.ãä]u6Š1£^9™dÞ5Ë–Æ«ù)¨Óï84mëwßêü¯ ™þº¾ïó{_Kâíå¹£UÝ\XŒQd$Äa–“Þ뻩 (hdS£C"¬éÊŒ&/º_†W x«¦¬oW“ñ{ÑJ_7*#5¾óáy›â¸ÌWíMu­»4 ‰"1SJBÌV·b·cX²júOöÅòW#kðº„"ȆùkÁ‡ÏPÐ?íV"0ãKŸEÓlØþz'<• "1Ò¶³d< ™!µõwë¼®mÔß9u#Es”H²sª›»Œ…¦õAu¢–•­Bz’ZÅŽ£”ÈP‚wQ&šÒ›³äšêP¨¬¢ÚTD×¾ï˜XùíÏIà•½raißÝv‘’dªFÓÊÊ90Õ L"ÈòªKv‰ÑÄ®áçˆ6ÊÃm-8ÂÉ2ÔQ¶Ùìᦻ`¶"§#5ôºœûªŒÀ(ò@Þø%€.ê}UÁ b‡dtAí²—ðŒ´Ö3Úá·0÷"+„úÇitˈ!cûœøÏE0Œ«“ꆀáÇ6¿v¹ÎÞ,MP—“$XŠ‚Œb‚ ÝT‚}åuÒV …H±CZ*SHuÅqf?áNåyaðÚ»™:¡¨ã…ufÿ/jiÉÐ80jN §Hï¯Öo/žø9`Î>®¿/,šÁ)Bµ)ÍA¿:—+«v#W*ƒÆ|™u ²&7½DjBQN84ÛüÕK°™&d¦«ý#5*mÏí¯gÓ|¸ÕÍŸQNoø (|‹¡Ù(ÅsÛ_á|¼»ðÄV'rï¾I3Æm¼c+¯-ÍIŸEMT}[×@0ØÏÂŽì$‰hJº¯ZÅX¿|ê*—º&dìFŽÚmÄŽÈŽ0¡üGʯg™kú‰;¼e ÷›¤x Á×ÇœønãoîqØàäñÕOì´÷¿.w’ô‡ž˜7p’3Œ¶=æF¶÷¿½P'ãûµ†HùOÀÌhËhÕq¦{æ2°oïüÒ¿„ѯ%BÒ„–¨¯:?_ÛëñͺC—öGÊŠo‡®.W’wD+:Äy/²"]žòæO{{õ•X*Rpª‘ëkq*(øV1)"­¯MëÝ´ò‹ýfŠì†˜­PcMïôå1­AÄ«pÒ¤V=§Aç=ÓFÐì¾ì¿n.ØÜ=oeŽH!aÝ$™hNü|dm«]-üÑ”ÈLÛ@áò:<¥—¤!iõ—o »h-ˆHAWã‰ûs2±ÃpTªj¹î]¬ð«³ƒ-öN˜H”Š#5Ft—æ¸>ªµ¨;ùÖ”ú?ÝŒv3ÜÜ¥D#PübžÐÓ®ÏZ:Ö4@Iî¥*h­=(<—Ü+Ã4—|õ#5ÇÅþŸšµB—_xá Ÿ>Ä4¯]ÀG§H­Ñ Œ|]#5b"«£.xù›ã•#/.SθÊîta¦aæ”ÚØ”†•7lDݶØ1Õmð¿þü,8HÑ“èºr.ÿ›>y#/‘A;÷Éí âo͘«HjEá¤Aƒhlù½W—â(¥ôvÝë\—évê0‚1:éeˆ9Jö0¯¢ÑG’·I”Ü•óåþÕéçþ§[Oïï¼û6±º{0)º¡J‰jUª×’ÒÙ.éaðg¸müÌAÖg­@I#5ÇBÞ‰¼`ÑG¡àaé-†{_#/™[á%Îs¶­OÏ>Ñ»5²F3Ù1õ «8 9ºùý71ÝF¿m€§zä¦(§-|4°²øbÌdj~.£áøQ’ʤX€Š=_©žoŽxpîð§çÌU5øøïWìýÊ,饌„{‰#ŒÖ³Õ'‘Tiç¯<P8°)‰:YßmMî£b‰w@ ‚Á@a”ãƒÓŒ=x³Õ¥dÀ}øëy”Ð+MuÞøb…#5nê3›°èM6~ŠR-äœÙ¡‡Žó\æòx@ëpÔ8\Ê6ir¢t{î¦P¤ª¡AFšòh„»ÜäSC°¡ã1ºb™RüŽÓ`^©š;4õªâÍl)W»µZ›ívE€Àe³CÌL¢ˆ²šèóª¤;&#/F‘Ò§»t^yyÊxq¦.K•ö3¸ë·á˜ËÌèQIŒ:d$Z¨g§7‹ ”†B©É=0JŠBJq¢}öÉé†>4ßi¶DÛ%RR„Ç’Â"[àCþõçoqE1×íàä‚ØáÚ{~Yƒ>«ÉökZ™;xZoÚ¤Lhø‰êÂ×VRŠÄ9³HÉ`œMuôÆÅxë²7cÌOrJD2ÇÓ: uÁv˜ôOîrÊêe“¦DeÿØ$Ï:3Îw׈X© *B²‹Ÿ,žöJø¾â¡œð½Úõˆ^ï0s‡wÒ‚åÓX‹F¶;¢ûn^Ÿß‡Ž›\ÍÈT#5p€Lt"Ý3ÃtíÝé8§Ç§„ÊóÑšMÀ¨§ƒHœ(£1ÅBP0ŒA¢Äßøºj¯f¯†§…Ó»}s[Õ{C©Ý}ÿ>Ï7M/e«å-o‘Œîe‡#5#5Ö¼ ¤dSRª{^{÷ê}i›ƒ¤#,$ ¡NjG÷G5íIÉOµÇÔ?Ë–ç§WègLäãóg]EÇòü*Ô;Þþù» ðzþ¨/o/b‘œwÒA«^?%g%ÛÓê÷ªzn©÷|ö.?#×}$éäüq=^E¤nñí¥¤Ö ìFcïv–f¦¶,ù#/³,ðgîg›œ!³¾#5~Š«ªPžâiå:: Ðš:䲦‰ïQi±WýÐÊ9ªÃÝkdUWk¢™B#/IMvýõgØøé(:0Ì"ðp8®H±/Fý“à@ô:Jæg‘ÿºÃª Uüבä¢e;tÊ™á‡óúÎ3†ÙöÛ¹ðÐC~ÛÍêÜôzM,„ÂçöÂÁT®œw6—j†)Ú!¥kûçövñ|­Cï£ÒPðˆ—.QËËÀGòB|‚rÆ=*D2•þ,Ñ®wÀ ÊÈßà›3•ÏÏÒìâý©ÕÈá´J?JwHMÂSÖ¥ÒXTñj,‡)< Ó'iÆ~ÈØG÷u>’wºÒ9×w5‘¬ú¹Lf8ë$„¿Z‹LÅfã4ž.çÒœLVsR÷¼`ÆY ALjg½)ÀÅ“BÏj~oJ“4„³}vZZÉU):èg {·£uü8P¹¨x󘳜ï³leüÊ:o]éùÙìÞÍÄîß<ï{ÔǽY/”?3Çðé5œÝà_µÊÐÓ1)4º:mË¿–šCuŒ›¥»¥ Ì „(b1#»/4ÜÂc-Å;Ä2Ž…Ç£«1T]†ÆcFzÏf¼ñ…YÕ#5FmUSZ6I»+dU½^¶S#/›4ãßO ËD=ô[¡©ÝqŒ1ùÚÕ¶UOÛÖ±Zä~ë3"Y·þ‚c|4oZ–0åÁËú]y‚üQ›‡ÛQâûÿFÃãó뼟#/6#/ùAA“Á©zø`e°¶÷¢—TT•˜,„UQ²–PûzÝkLCh¢%jV•MP-R‰¦˜.ð€èÔdNdƒMÙdJ¿•ù¢ç;­Ži]š\òQ?†8ÁUòØ–†Å#/ yJŸµRN5ûZ+H÷5úZ:||jînÖá¹½h§ÂqÖŽÌìëÙ˜ÕaÚtèI«Ý#¶Û‘‘§&ZƒÄ‹#Œå Ñß÷CÙmÃ)ã.#/„6G®it¬„/½iô®µP-§¥Ž¶›~òâZ0ú:¿~®J+JmÇM}î/sÚ»±¸´^i@ÁÑñ©Ç%”ÈCÊAòÍThÝ°Ñû|Æ‹Ç[4¨wpUüÜϧ‡ýú#稺…f¾\bÊÏLc‰Ñç¯B°Vü8éqæ÷ë²^©À€¡ Æ&[>¼Üµk6ª«Ž˜ñãl<ø9^K#/ÎÌSm/××;)ÂøtýVÖE×,×iýëþÖw-#5õÄ4&á7ÂߺutßÅdwçi#/>÷ÅZÙ~ŸÓ™¡©]w«DÚñ¥ï¨û|œ»}>˜ê®#uŸ¤†òñ´ÎÉáMgYYRóªó«TY¼q‰f¤Üбœ*qoj å›®¥ñ“f+­?Éæg—mº‡Ký¸Ç&Lã·C}W$3Ó«·4àe)„Þ«­býŒÕ“|×Æ©Ú²ÂÐ>u?……#/$î‡Ìã–æÂçŽi¤[Sß¹åÔ‰¦Ì“æƒïù¯|Ó #/‰é®Sw?„ëë›Ù{œùFÃÂ.Ó_Y$ŒøFïl;timâøv¬¨CÛÇO”+)ŽÐ~:*‰ºx­d!žÆ4W'߶Q1üÖðoØ„÷IëúÂfOÏËz6½Š²k.&Ü‚õwsŠð$D981…2â®Í»±í´øåsÊ#¬ŽOn6ÖØ›*3לÊ[LÖhùW’"¹#1˜|α#,TªME‹ºMqéªoävs6¸]–/œqŽ\ø<$öAó©C}¾%è•©LÑÉáSéM$ÔV9Ÿl{§šzk;öO~)tW¦\¹kר›¥§Uo‰˜–¬LÏ|^Ó‘s›¥žsÙe¶»¹ÖÎÝ›ìanÊ‘ üj‘@z•A6‹ßøý¼†ö´3Ž°¬·‚W{x‘a$ý++o}ÝZ¢@þ¨³e]Ò¡ºà•3¹äúT?Ù…S¨ÛU5ºÚaŽãnæ~ØbPI𥠮Ž¿/;#5ä‘ú ¦ÞªR“9ØK8ǣü¼9·Ùѽ(ÃKhœ-¡ºGsÂ(Ùk8Aqj wÇ”„Uü° s¢Ç“ÏŒÚãî‰Uy_¡'·~Â+Ž~ÕXgÔÒ]©I•â#/Lx¢ùBw3Â>gGè•B²BÇq×]!©¨w]ßçÏœ]vÆg›ëNßM4ô¾À§aBú9æsÒ5xöí¨£ÞsµG ’†Y¡Y†µ£$ÔÃîz´”¹@¾ì3š^Gt—+Î%y ݽ,Ù|ÛõR¡T¼$¥¼´IëCî—ÁYÛ;gX²$…MëÄäóÇC ÿ‰§Ù¢ªvgÑdKÍ9oI×V³…™ëÅ]ŸJÌvsȵ¤ŒPRÑ®¶Œa“¿÷3QÙ¬C Œ>©½–Bû÷ìÙ0´·¥òTUBšˆEeƒµ¶([¡(ùhí†G„\ìÙII“Þª‹K®D+²QÃášÀ«YÍÑæf®_m#/žìt};ôx#¡ZÍÎÖ·øÆ>cÿ8K|MPÓÃýPññå’ŒDÂd!,›I¶KƒÊæƒeN–ÇMÑbˆdÜ]‡ç;ê>¢ÉUò!¾yzwîgÓãòç¿ÐªPÛî[Õ@ðú?š@“L$NLjÿU­£¤PX´[7åä³ev4ú®P©iÏ›iyÐI'iq v†Êyº#/z¬¨¤8è‡Zõjòú¾›ž½¦Æ†þ Éîæwñz{&|I¾ÝZáÐX‰˜¼DÛFì Þy‰ÉT,cšÉ˜@#,˜`>únãùªfk­ÚøX~8Â~%·e“¨ócº¨šÝäÝÿ<ÿ¦æÒÛ Uí·i€Û À‰G’oŽ ÿ_;#/¿[´²Da©wà¨Õ  "Å‹>gΤÇÙµ]'•neÂfqU Å‘©z='U.aš6|½¥v•…O…¼¹süÓ¤QîüåÜÉšo$ !ãñU³,ÉU«}Z#W`åÕu”8Ò0HÈE[„^ÛÜ`//«]º#/tP^(ƒ–¸–wQná…·„VÍ%Ît’bƒ(ÚÌÌám˜Ìݽp“L'o˜“ 5û'ìs¥µË/”ô›Œ@ V„ÈM^%€æ-©ÞîbæaµÃÝ—«©bíð‡¢›ú~øûþâ€cþÕ À¬-Á§ø°t‰š„¯£PŽ#51U·Oìï,…P‡Â&£ïöw̯m¸âÇø?èòb®uYƒ©ëµ®Ê9•TñÏ?ŸM,ýxÁª·ögß ÌÚ¡¯F΃›ãӮݷXG÷ÂíÈÑU^ekuþß'TI²A¦Hk+Í~Fî!I—vsõ×^Å€ã€ÎQçs@õM=¸ä˜#/¤fÿ»¦ÙÕQL"žSL+Ü¡KSiÆÔ£ú sOǃ:…NVʹ”SsAßPT%B'ú? ˜u'.BÝÝ®³é©±ËPõŽÐh`¡¯1ŠÕ¾¤´¥æã@vü©õh7)ÝwÎyî*³Þ‘Á­I$5!ÝÂe‘óÌr&šmïC³C(¸³W&HLÁRÊý’iÚB­YàÓ{­ØNlÍ¡3¡†’)G¡5ç4nÛ@Û;Þ7覧þÊÍ‘‚)¾œuËÌÃVfeš5IDðç”jß„!@¿h¤ŠG4hf6D™X9FF)èÄ»ÝünZC†ÄDKßm£IúüyüÕ¶aÓÒå»4ÁAÀŲ¥Âñ?†¥´¦g² ýX<Ä ÂZ3°áÊÞ´IÊc#/ŸHªc?Œ‹œXXÌúéíåv‘ïìÏðŽ[Ù ¼»Œî*뉣êQÖ°ÆŸ{wN4‰Fè·ÀLdIAÛƒ´ˆŽší3¨×[”˜B¿wE fì°²‡Œ„©8÷p€»VCùô ¦§±#5÷L5i8.^£TéiݬòÇ40öþ\Î×s¶©ì\løîlÿ‹=ÄlêŸp·¯vöµ®M#/µ>ÇùòúàW§{ßl½3㢂̶WTô™ÈÀ×xTs+•¸S´ÀÚ{¥EP¹§~n^&¶þÅPï¦Ê.XZ9™IÑ®¿¥=SF™9ˆg!8ïyùþ—W¡4`˜üÔytÅ1î˜×ó©7,»/+i'}‰†nß”Ùðþî©“–Ðû†¤lï°#Ö:§¬>sñèÒòš§˜ÊÛl;BÞ`–§iùŸ•dŒVÁFú8Úq”ªtyG6¿Ÿ5#/+žÆúo¡E{fð÷w »¬ppÍ(”&d¥ïqÓ­|ŸÃf¸•‚áºÒIÀçË¿1œ åU‹c¿v¨Ø餑&`q|kŒLþ 5XQpùàâj‹‡Ü23(!°Èò¦íæËî–;¤„Aë|»¿Âö¢ãY#5mÜJä:Å!Ó·³¡ñ¦øïûkM³çV1»è¢ÊÇ“’&”˜«aÌ/†'Þóžk¦ùòԉ½ž*ŸNu½ÁD½L‚Á3´‰´µèJß?‡Ðg<á@dCDžÃ#5j3xÚX‹TiˆÒnÀ£:2.î\µÆ ¶Öƒi¤šQccyHà,ÇlÑa%Btš“0úæ?œq§¤ôÌü.£C¿ÿ`‘BÄ=uìç"1vŒ•€‹ ´‡Ðb*póÜÕe…6oçü¿ÈÌÌ¡™´!³¡!&[3F a6?>¹6LÕâå\¢•AuØÍ·¬.ÓªúR|ân [#5 hŒ;2ÌJAÈôSÄ£6.²ì³fÂJf”óêZ%•+æ|bôcÊN¶G.ä¢Óg]w$¯Çû93ÆÙéó?³ÄÉî®Ý5×J7*Wk˜²jrï•¡ ªÑÎ{ÈoóÆ;‹ÓXýZš„ww´Ù·¾ ØnÚ3‹óÄ@ûƒâ\ëÇHfÅ]†ZdjÊ!“â¼v¹5n>OsÔ5›_FjÂÿE[Å7sn×(Dð˜¤Úã¿ã©Û²f}‹ˆo(}Ë¥é/o¢ùÝ3MÔ#/*ô\˜ÒÛS‚c"ðµ]tÇe¢°üL(Dvó5èyÓCêÒeòó´Ky£lÎú!ÂÅ8–Ud˜ùî–Ià ‡0¹6ä`‹œ½B˜àB[‰CÕeØ©xìú\ªN¯ŸXÄ?Ÿ~öŒZWÞxßV8gŒâE/ptv6À¨¿1+Í- ÜKu—–™‡ÂÁ!+²5D7­KaA³Ù¦qšd·Žˆ=3`¢QSO›ú»ÓîŒýËñbYuvL 7´Æ` þ_Ïò3”‘ldÚZ¯®Ü+ÔCä–|’ó9©Ï»ÀªóÞùò{ê}2%\z¸m‘oM[ ‡þjÞ=Ì4å¾q0öÁH¦Y²aµ8B󺻼ó4æ¯;‘˜’,i•¦JH,Š£µ¾XÐLèÖ¿o?Gßœ=úr8üžLÔËe%0Š(5aH­RšÄPÁŒ+š>­{±­¢jED¥EAa zêVå —%YbTÂ}~Zâç 9‹×;® Š´< 9ÅFŸ*ŒP¢“’Oö~º+fcÈÇW%Ÿ®ƒ’莚ù¦‚0þ²HXºÐf¸0íf¼d­ø×Êú£Ç<wòÍT¿uH6\‰²E…0i©¥Ìà]äÉ*ê‚ÐÖD\LÄÀ‚l`Mü6W›ôñŶ•u=&0á‡t……"|"n¾½¨Æ¸‡L™×MoãùvÈ=Eóç'8H£¿ÈSÏ·©¢Œ–!#NÌí^ ýó†Z«¬i[<.ž6P*‰#5¥«7eP¹òƒS†¶ÙßÐ7bPžG®æˆŽRÖŸù2TÆ4`œ@×8jLL¦ŒF“K"áfƒµ™­ ‹å™›#5`g©¡œæÊ-TbB¢Â®¸ÜÑß]Mt:›´Ë®ñ^6ú-ËJöh?­‘¬ù¤1Š¢¶à¨%¢ó0ÝáÑ")œ…" G¿J.ëϯé‘úw½yŽüˆSªICQÄ(`a kï5¼UÉ4[5-Q¤aÉ‹#/XEÂV\ !<î­r×ÉnÍ⯄VêVÉ­š–½Q½é­°åBê£hD‡‹F{Ip×kN:µóŠW9HU’غ¯«U¥.àHªo>µ]Vâ"/z(•~©r#5°«+j¾O AÜÀÎÆîK]›ÈcÙ«×ûj¯v={[vëƒdIÑàj=qÞFRUxoÍ¥Ÿñp UswØU+nnÈ:.öÐÍôz¡êÓÓ–e~ƒ<P¶1öÊ1gMÛ7*â_'‚Ï0úº½ÀJÅ7(’Ù#5™H0Q’車£WË2¬úr«û³Õ“u˜­¨”»ŒªÜ¹hÂÊ) OƒnšÜt¾²I [º_Ž™Ù¿]A8âòVT‡ãP[úÜÔ“™NËù¿Å›¿»qž|tKƒê¹Î[ãðŸyVàWí­÷Íø6††Ná¡—´MŠ<·u,Ư âLÁ³:FßU¦hÞ‡1ü;HÆ‘Œ @ dJ•¦ÛÏ/5Ûòë±±^¸j-ñ/F‚d‹"ÂÈÐ ’ RE—‹¢¢²˜H4›I#/ I³.Îaϳš=u:Äj¢úc³ùô­5¾VR…k/’IÇú¬îvýÞ¼ñÇsÆc«üË©’è#ÒsD»OGÍøM‹F)ÅâH„cpÎ"MUöo¿WáÈu¡uG¾#–œ)˜{žSªd>?«ðr¨dÇr6&foÙ²j[!¬×J­!bSB»%ÖMk6{fþïp#/¶2ѲÞgZwéÊ/ê80n\„9PÁ$ï=®˜Xu,[À&ŽÅŠ­iêŸ ý§/ôËRdOʪ)È(dµûÓ.Z¤ØÆ(Q…E·T(0QµÔϵ’–L·:+wÚŒ‘gwÕ9¼†!ÇJ¯éiKËÈéÛ¥þ²ÙøÔÔs“Äf¨î¼ÜûN~¾\¤Èn€˜6ó$”Á<>)Î.±X‘! ö£&}÷·¿búŽŽ ð’þ2 ×z’lŽëì² ¬v×LT¢‰d$ŒyD}^ò—¶ßgöÎøNÑŒRèuÆ–8ÖT¤ˆ¡Ý®q/òÄ}–þ/)$·´Ø^sfõlÀ‡÷*ŒÛräÊ´‘¢Ì‹ÝU,^;æ\ÓæMt0se#5kã,6EUPq'=q#Ÿ^ºá§D>±à¡lÎF•¾)NB„xSqF†£ü* Y‚$/#/2·™&½¡¿ÙóŸòàû Àܲda=®ÄÝ­,ÕÂ\&ãf*ÑõÈZëÚjô¾½!ÊóŒ×;¤1î9TÆuCBs U.¢¢$ÚŒrÛ\ÚHµÍ¹­ÜÚÝ-¦iÌ÷n½öºDSU<*ì¨.;ð`X&Écñâ¤àèŽfÖ¡“ ¸n‰d©LNk”Ëë8ÇHQ¨rö>ÓÚzÂeâªhS30gÐcÕó`L#š~m!ô·#Íí#Ç/¿ÊFÝTŸoÇÝï]ýltËQ~×PÌbæiŽ«ê±­ #/„¬Q÷þõm¨ã¤ÿaëÑÕÚ-;ݾ´ÇêÞíÒŒ[ÓC%ߊãÊÉIŠ¼ÔÝåå«çÖjÖ<êyuåB?j§«`Áœ?Á½ÆhW,¿ëh¯ÖŽ2Îÿ>rã#íåoû«"å'RúÎôï ïPxÅ—²W–Ç+Û“Ë©­iÈ"#]“¼ 1û³BF]ÍãÈŒ²Ä½4†Ÿ=9üxOÏsÂzú_ìû;áDUãâÓ}><ûáË/1¤ÊÞ2n­ÿG&iŸ×LCk¸bÔƒ¨Òuüß«/5µÓÖ֓*“Ì:rëìÙ•·¯¡_ÑÄñ^+Ëùëûª•Òó]ÐZ!ê>Ì£Ù*6mçõ¿ðÍôcÙð>N¾+ú÷~Þ>ï·òųæ3öf_ž:Í´™Ø½gDøK;¹#5ì¡ ×‰E¦Qx Õ4{hyOçfßñì²Eʼnb|•ãŸ®_'¯AC9<Õ9³zt¢“FB”Ó–¨P!õ×­¿õL²k;±ù×Óöwé·•¶ ¾Ü#5ÇiéöY÷ÂŽÁ5‰V¡GW3à«Éa1¦”4Ü åÞQcziÉIP%4QhÕ¨%B¾ïßF¿Ä*†ÚhÿÒªB-ôÁä‡IWïü¿Nš¹™™‚–X0; ]ËÂâùsWŠùÿ{wëßÈsœ¡™ÄÜ"Ä[ø¶‰A™!!…Bb3âv´Lµ%“øÊæLHfÊ–%Iùf&’Ò£kúÿŽvÝlQY\Üvq0Ι ’ Þ&¹1 ¬=Å°ÝÖ^[-ŸÌÄ? MÃnzM¦v¶‰e4.Z)M!t¿}^Mzߣϻæù1ãDF"whª #52’ØO€b¢‘S†‚&H'{÷_ôLô®ÖxŽA‡N+Qó¡Ù ÈdD>žŸ{ý]L‡v0ŽQ£ˆ0›$3~ër½¿¿®¶¿B½EXŒ°ÚŒx¾gáb™d¿é«Hu¢„dY¼#5gEkò«Öõ·K^Í]J½ImóÑ\ˆ%%„Qñ.?äùÜúS¡Vª%´ÉlÞ"–eHhÀ¦#5[*‚‰àù]Ã11þCHOÑŸ0xjgüø/¦$(—ãoð³¿%Œ_ù#5»U0}q–_ùé§ï^™?3üììÙ:¦Ú [4À6?¸ ž³S»Lë[ž13£ŒN´?á½$y×%’1@z‰»qÁ„ ÓÎö ¥mú"Õz_ ΢׸n"=°áxM *¨èÎ3 뚣IU+«ÏN_F,Ýø#âI@ÿ·*"Ãû.N§#5è’‘P‰CdìQŒ.ð±q.CÛÒçúBkÝ…gâÖbkßùØdE=l|öDU)I÷0¤ý JÃõ´#·Mj°šëjú†Þâ–füÝuý‚å£W¨ê·/ÆÅ$㇮¥‰ƒCá?‹òÕÓåÛë>Tbß-ß»Ëñ§®¿¹Ú¸sÇž>8[Â%hæïÏïŸyù*ýÿMý"MÅy—JûŸNm…>‰Ö¿*™Ë匩E¬ÄÆi|ÿXçËgáÍa×vö1•t‡=¦ŽÏßH‡:ƒo­–ƒ˜–Rô<5áî{-ºÚG"j  Q‚¯•þ³&jçû(áÐ*ú°»#,ÀJo¹|ezmûf~áàµÅê¾?Ãþœ)í†ÌýúÓõé ¬»”M¹õÂ''ßÝV7q™°¹,RveS»wð28É/œVÄídîð$/@T\cLï¡îª´3cv¾»-E±Ø£L>ÝÀ4#,Ô%ñ3#5Oóô=Q[MW9ÙetŽ˜Æ=cñõ_[*[åØ´å§ÍEÍœÕÁ²Ï¥¯è—zµd ¦ã¯‘a¤ÃB#5LÜý445è>K·ñW*–¤ßYÜz¡=„¥ÆRLÜíã?Äܲ\*™wÂyÿ~ïÂ|ŒÎ¬ÜN& ^Û ?.¹©ÝT8#/ZÅ5ý­{ò€¤êÍÄ…¤c‘°o0€ÛNÂsüþ ›:Òß9t û „"uúO|ÈU¼&;éì·ïl}ðèÞIÈ~³ù¡Þš“°G-²DǯŠ‘,îìïå ßÜñ‹ýoÒÈo½Îc|ÈÑÙHxžG¤¯ÔDy¤!&B1d8ÐÁüóù Wð_¶?uŽÙ“fñ!’*„ùO@‰Ö˜|‡+N/•©ù?ºuôgYèÏn¥›y^9ÌœûS:gwi‡³ƒóDáIM~‰ˆÓ4ÑŠ »LFÚŸµè{!V4 A2IbçBÉpVl­à#ƒýYà.½Üât’‡cšH’LJ·×~µ ¦ÿüÁØòû»Õz0:* #5|ÀK‰¥TR#,Ý TDDEWåîñ† ÝÔîöLoÏ—M‰þeaüµúå”Ò%'ô©_ããÖ\Zñn2Sh2PÉ,ƒ ÎAÀ1¥ €ÒŒ]îoFƒåÖi31-´t¡1ûzŠÉøÓÔ¿ŸÍ³fîùfïû{{¸×êòâÇÛê>th|´tÜ»XöÝg»KzÿuÞÝGÈqü·Þsé#/xT{sÝ ìÀÛ3Gš¹ÆšðÆ/çPïêî?^½tiÇöíʼrÕÕùgÝQŸ£uÖBáUüèòá»~Tr«Žò¿úOœ¦~—½CÈ·x¹éþ8÷OMµ­³ –¼wkrùãWÔó‡DÍøÆ_)À§ÃuŸ^ýÞxú—ͧwÞDá¶ÍÝÍŸ<÷Ó»ö–†ˆözsËŸ²Û=méòñ5™°;²õz4ž\ú5žž^-mÓø7¯ùü~}7VGãi²f¶ÆœףɻÅ#/íæ×+%BÜ{bÚqóöž9N+ôÐŽ:àÞ‚¹í,9Ç?§fãÃg=÷í|ÝóÏú©–ª³Å»«–È×#/¯J¯ÌGFÎjàu~~=vû²l?¥0†zJäOtªå§Vy×l«4S\‘,‚ñZºö´Ipç=%Ò>^û.ðSž]Z·U³´UÒ:k²;9ÿ]1‚öâÜÕߤƎ|vø¡nj·gmJÊy çÝ—IÍ®Ìô°ù\ÀÆ2+ׯ‰#5U¨<8œ„äŠãô<¡÷üpm~òÝ:ê~Eüæë|°¸Ù·Ô´éJÝCø‘?wŲîû´úyüv–CŒ2ݳD'år.gmQ+õao.]¬ãÍeû=WUZeB+ÏÒ¦ÞZ¡#5•kôòvPÑþØÜ©ºþQÉ®S†Ùuü¾&¶7Ó3û¿ >¡´Iëæìüg™ïª’ѽSIŒ‹ÍR¯ß$£¹ÿMx~O6{‹!׿?ÎyÈß- ®+òÃdž_vÛ:¬È'ªÿò=Ê¢ï€AáPe Êß^»óÚlËuîŽßoš>ä¿n«—×áåáJbíÑüÌšÚÛ£þ÷×ðÚÕŸ»gËüý¸òÕ›B‘\çýœz*Ñ‘õzÆ¿W51ø/U[dXhÆݹ»gWó=™9µYgº€^ÞY÷}’¸³O]Ó/n¸{kÓÏÏüvëøº+¶ÉæMrôádÜ„ÿZK×\6¹þ8éjË“qpGtK³”×°Ž3öfÙ¶a²È—ú|ÿÎË~læmÙºOy·ý¿ËwÃäïúáXo?[ïæÛ|ñÏÓMB-Ñ^Ÿ]>&æª>ÚDò¼Ä(ŽøhðúwsþZ¿IºPØòÅè¢FFU!dÔú9Þå—ÒS“åáqC°H¤"œ‹L$⟎Ï_Å *l‰¦>@E ÃZ˜¶25˜fÚG˜—Ùòi÷ž ß»´«Ÿ´éê×óùù_ËÁ—¯òù~z÷öè#ð9‡œèòô°spšìúX¿oë­¼ñì;Ïô÷ño¯òþãfoš­Ñlí¯WEÞê›CTÚ|ú_Ó~˳s+\û~_x~;tÆ~£Iaæ&Ü^–¾7Í«/=f8|ÛEW.¾vÕ®ÉðÒ|ìº'ëÓi¿ðêÌS|²·•Rzì¹Û»låøرuû+êZtš§­­Pg•±JüíP9¡[ÈVË1qB T/;WRØž•¼/“Ý©tåÇTë²™^—Ç®œÞîeJKNWõf»–TäSsv'k»òÉ)Ês³—Ù Q¸ÂÜÍÍ)ÙýÜcÆy#E’I'!i!¹Ž¢Zƒ9/ÜÛ?#/^k#5óíõ ²¾>­_˜Ãâáâê¥;žÀÝ*kMê”;þ‘:ª'¶S©¨f‰Å<)ñí„>8Âœrìçß„1ds…óÂhœ!rÐ˦~߬rl}÷5ŠÕ½¹µwTb©<èäPÈØíÁõvDN¢Ô½ãvïŠ~¾UÞ±Þ·!žZ‡ŒüÒPéZ\ZgW ËDK¢’áBQx 3d¸YfHg¿ˆ—äöYp¸hâ×a-³Òf*•ùËrϯ˜ªÉ™l¶üÓ›™½[;âh÷üòÕauÀ‹bq&„ÑÆ%£–É„zV€Ë1 V­„±}2+†ó I–ºW k-ìÞ{ÿfë„'¦o›}†üµ=uÛ9c{bgîצ^cf·×mv·8›ôBP”+çšP[ÂiÃËMùõ>(c“9§HJíYŠ¿ÙàW§=‡ùK¼`¾—üÔ²y»5íÝÍò|•V¤r]:’®—vw×Ê—Ùëëü§GÃ/¨Ú#“tð5/ÓêÙ#/p<ël{ƒîŠ²Iÿ_/d¾Œºnå‹Ó¶žÉF Ùy!ÝÓ4"«ÎÞ6Ý}F8#/ÛôÇÕÓîóú¨cê4™G¼26©tÈÔsyJ\³Ó×Q`š„ùd`Žï>p#ûIȃU^^J¾Š¾©…×ê­õ.EwË»/¢ÜÕøý$¾ŸËWõ­a\q´ZŒÌ¹‘²¶ä%`Ïž*;GªAºÖÇuöÃta­¬¤°ŽƒšVŠ•$Ç´Cc†E„‚ª(8Ü#5*"ªjDÚF 6ΞšÛ[k[‰Ò `ÒŽ ÈLXµ‚V“a¦HhÄYSI¤ÝU X–š’¤0­Ò#@ÝÓ¶–k¨¨,›Ä06…ûóüY‹Ã8h Ô$m÷E¡=ø§M§X¾îóÈÞ³!¹À‚ŸìuòX~Õ1©&~˜­Zj]'åþáhkQ˜XÁàñغ9ˆˆ¢13S²%”R(Èùªæº t{¢t/9h#08Ž$ø™”ˆŽJ:QFk1}KIPc 0i`QV‹† M@„4í Dé Aà<Èwoì‡fIˆ”xS-ÇÔgoþl,î)~½ÿŸt»gÒ·Ÿ1‡ôëÂËóQ¨ñ/4W¥hÑÙÓ?¾«9¶Y¤æül¦Zµ%û½CÌ·þŸÉæÍ÷a_#/úz~Ó®ŒDÕ‹u~½-2üÔß]Ÿ%Ë<ãÙâ{n¹w;åmxû'š”ÓæýóÌ=ÇÏiäÐ1¯¥¬i5B·”}#5>fÅ®>ãÉÕêý_ƒÿ…^­ZýišöBB°ãÊ DÒ8%k½ÿw÷­?AfoºwqáÓ×¢}Y?¦ú‘³ñ…Ñþ’iIå)B1x×^@Àäêñã?åÛáO%>ÿ?㪥Íá4N=ßÜùÏ/ÉguÉ~>w祑ùkêøºÿºþ®þš»ïüìݸÝû«ü5zë(¨–‡î¤à}†spçGÁÊ|¢®õ?È~Aˆøo{Í8VšÏHm0ÿaÌcb!…hô22Ã!I¥n0KJÑÊØ¥ß%IH Ó@ÓHÁ˜2¬)#,i³ÜuF Ó¦$©Z¹LÚ›&ÈÉ®Ýôó^šö÷ÀÄŽ˜–™SÍ)jŠ€ÄÀr7h(UX¥¡`È£¡ÚHŒ*V&šefeX6<+-iNþüF„<Ç+Ú“{†º†Í„f#/² £IºàEƒ©‰‘AÆÚN…iÑÅv“yåN=Q˜R2ŠŠ9‰Á£DI°n€ÄB° ›pcK J ¸‘Š)"Éó†%ºæ¡¶„¦ˆ2)@lƃ2#/e&:EÕ‘'(<)‘LRÛŠX›-7օ̤«J#5%F#50¬ (älRÍ>7³Mi¡²ˆ‚Æ—s6„B§ˆ‘îÀÇ⢷f“ /öZU™¨¨V¦œ®Â jPï‚ÀÇX`- ed ?@¡ÐóÈQ§Â'Ѹ˜.j.DÝÊGºìqrº¡hs#/ü¸1”>=j0}'t’Pƒ»¼0ïsòM¬8…Ù#/¤$Ò¾«š0,ô.e‹/³ùÕå¹óš~hsÌÀ7ïQÉá8m5_:ˆñô{þdã·ltþTmg"éø•vS“Rìi— ²v÷I¢n7]#/CŒŠThb¬ƒÖ0£«ÊI¯DðZª^1¢ìfe!™i?Ï#8þ^[©50î!Ý5ô;ÖÿŒýÓôø›£<(.™£ÉÄ#äv;³)™ ·¢€¸ÄÐ|oà¨2{»ÙËþ\þûn¼XôÆ–TµMå Ú­EUµ6Ç?ðíS§Qá×±ÿfhèïÜTU¼Â[wBëµÛ¤/ÑÜž¼âBBåWÙ&Ž/^ša6¼yõ›¶MšºR—±FåºjnþHÉ$·o½•«hqØÏ#/<Ú”%­èµµ£&¯­¢r¶ý;_É56„UòȇÐVç1Ê'}˜}CŽnLé €ø •DÛÿ®±¦Ú¤ld„q‘!¨—ðb¶?Ó—MìÒ60¬Î8;"Ê·LÐ!ÅO7³éÕôztÝów—ÎõøOþ¿¦_DÉ‹cꀠˆTH(¤QŒèkš°ôÉ(VôMÁëLê ]Æ‚^©†1‘¡¥aÃ[ÌÃTu¢šùè] ÒÞà†r‚Ì2Æ¢Iæ¥f˜äq|(£x8V‘Šã3ƒˆ]»” Ò*0be¨°#5¾§¡è‘MÊx›X0¯g½«Èâ­–êŽÞÚÁgáó1@¼aå°Ù²=°¬h´;_ÞFC4FµÝ£*%ié†'äeCÑK9ntlV ‰ž™’Æ‘à:iëC9ª*‡·§iâ3‹b4‚ƒPK³5¾j&JQ@z+F ,#Q6ʵ´kï`bäJ.×^Î )iÄêvº‘rŒ‰6Q¨k0wçc+z;EA³¾hk ·ÄZ4”!÷îõ5M)Ž4ܦˆæšÑ ¦ŸüŸéž&ÿï?}éçʪ½Ñú;úéC£êÊÈô÷S^_kwž3^c¿ÏýÞrìº*>äV¿¿ˆü)úØmâËÎI ‘tÒHÜØêluÚ~&|f7¡TΘ77lÓ€ãDc#5çDŒx»S &´21· 1›l£'bF–åÖ“qÄB2š‹õ’,Ter¢Ö9q¼UºöT²ÀÐœj¸¹¦²dÄ…”9¨´SLŽÄËÌ…’™A ZaϬ|C;öÒ®½-j†‹´ªÁôÞŒ¥¤e]Jß1§×@l*œâCr¦[‚Çã9¼P@™è… àtДC0]#áŒfØûÓ³AqC­I*V÷Á“&sbÓ-Œ^,\ņÊy¹`tœZiAȤ ‚ŠGb“vHƈé”OR¿ºkYþkÓ¿©wóõä½üÅïŸïTGò†ÿgÇ«Ûë{ç1J6OøÅ)ÕãWj¶63sr²Ž„Z™ÓÀ˜0É©4NX°#I(9NÆÉ‹³»ÌlßGqªVdþ¸»­ÚcºLåpr¦v‰ˆa”G›Q#5šÐ&àð¼Ó‹0œ‹Ô„¿L¤—ô#fÌýí£#/êüj̳˜ ë;d3ÄÐãž,X« n¹bŒI”ÈòQ”pÔ.6ó²ÇâA±£a©¼l±·#f*U¼Ã2ÊeÃs]×›ËÍçW]9wP$$¡°`ÁÝšÙbЧ…ÂÍV¾þMw+^ïæÂ" 7¾+š±]š](Ò†‘ÔÀ¤Š¥R —mdÓ×GóÕ¤ÆúÿtD˜(4 x8)#5Ó°ã —È’4û5ÄlËŒH™˜¡#/§ao|›!ŽñBiNb™Ì!8˜‘±—#/’ÎoàDJÃö°Þ[áË€™%À‰Uº;åœ3˜aŒ/Í8kÒ fA#/¨í;æ~doa™]7›8:›ÙÉ°Ê`”ÂBLìívP¾|l¬kåóñx ¶Ð“ZôãÍ©u4„¯fù}’Ê]¤6ªºÉ²¡°,™&M+ˆwònÁµÛ#/à ƒˆ8,·äF Á‚÷r7Q¸J-âœÎ-“vmk­tQ6v5#5',ˆÇjŽÚÔÃv+zâ΃®©à+GÉcvs¦ÁÒ´ÝXÎÐqšW/€š!³X:XÆ1–¨qïìºÍfÙÂn¹ª\†¥HÕÐkƒ… µ‘Æ»\ëÙœL‹O¹®psnÝÔç\“..L“Òª™Zµ–ç%'frf“€ODHåaô;ôì÷Ž#/bûõL^…vîóØ\“#/ç<ÓLEç¥Æ#ÀŠ5x^éö'>7®±å->6ÚW¤òßoÌùëµôSƒ-¹ò~ÂÄoƒFqRæ2>De^ÌF/K©± ·}`²ÿÔsD!ô!à˜ÎÉŠÄç£ÿÉ&û|¾=mêw%²êOçÀõ¹£~k¿ †§µæesQ»?"ë0òJ»ˆØ+Uny\(·˜›qUF̳ÁSl¨·ï©ÆËês¶Œ]$„¥:dsu§‡å%ýš÷̧_#5sûL†3Ï‹{7Ó›fïÇ|2SDï錙49õÐèõi[ã>•&™0™2@×ÄrC’™wì®ï·ñÞfŸË™ŠÖYmsD¨ìz;A‡ËÃÍõ:vYÁ—Ášˆ˜1bð°]2ÔøÈCæDv!ÌRoñèqb|¥)iÅpg“¾«ŒÓ'šZlÿ¯GL·Û#/{Oíq„g=ùo¥‹X[èÃ¥¬@c«‡‹„CY·2Kdu£é}ÞˆêýÕk·;9Œ5[þ½§\A|+/éwÇè£b $Ú-2 exìÁ2f*Ÿ)ŽÑ—-üqÈØ2ô’½²\3°bB„b`•E£ú¦àoêf/\dÄ#/$]‘ ÉPq©A;HÁˆ¸;€Å3i»ø˜ô3žÏµ®³¾@˜)à‰DËùÛœsª¡àLï”þ¦íTãÑ¢¯´Ò©H©‘¤Jœ“ð&á=Så^;Üy¹…3«€’ƒÔž…K¿‘Ó#/ù²ôa¼#¶ßJ(¿¤ð©'ŽôZen· Zoí¢£Ü²[¹ƒ^o(5úÅd÷o]§h=Oh’G·&{¥ü#5dýZ…ðúgHÑzëºìCZ$V¢ð¼fS%¦Ã{i› n˧ª(“ ½‚0GË«ãšßÀ™)'¿|YÀôxÇhv¤™‚!Ƽ1ç׌ìÏsFÍ[HÜÑý½œuh劥ûÅÄxŽZ_)éúD©iœ¦jL<¹ ÖyÌc†Ì¯E¦²OóON4Z”ãæ&NFÛèÀ»C¹ÀeÑË5Üß$?ääS¯?ÜD3ÊŽ¦ÿN6ø¯³ v‡«.å:¼èÆ!€Hßã<ˆ]27|jƒ$Ó‘î¨0ÜÎTé$=Ì“,aÇgG>ãôDÞ‰á@'û.'Øøñ£_%æš·‡ ýUgn=-šåMŠroš^bZk£œÓI«&˜t:pé²2¬-{n»}nû10ÙÕcb(€–æº_FÕ±í£+ÅV›-÷´[}ʲ³PíŠÌ©¥ λ‰¡ÜëÂG‘Üv¨¨3^Í1'bøŸ˜ö/M˜ùöÑ„níevè›;ôJª®åÖ)l¹Ê—qµ‹w–‘¸Ìv]έ–j–f»ãÄ;ÿåQ_'.=”Ó‹÷¹”+Ãçå³ßá~ÃÝ‘œj°Òaß‹ˆg—Œ÷ÊXÆßXl´#5¬ya(\CÒv»±Å¿w¶í3Þqf2N"^JHç—æÊØ!þûÖ‡ø¬¦ìîË‚ÞSØà‰¹'*…Î {æç\•¥Ùq#/3”Ó†_gÀ’P—]ê<¸˜þ_Ê篵äúÞø¯Yï§:pùÁ"&¯-P&Ð5*¦÷¨Z¦–¼øL‰Ê™¶á™€ÚET4 Ë©:G¶ºXØ_sBÆ;2וZ~gÑqwF¸GFãÎ"[1”jjáuIý&™çà®V÷Ú›zC¿‡lg* ®¤]ƒ Û]jP‘Pí-Ç~Â#/Sa£â›[ëf<òÒ‹àrª9–b’ÐÐvÍzg¦­°¯\ë|õéQ’ h!ý^MÜmûcÎËÛ¸‹.Hn%ÓV3û—¬O¤ñNc3ßi{=Ûæ¿ÉÕ¬{ÙÛ|Á6ÓR„ÐâZôoÍcž.±ìÎäi.Ù(Ûa–U%ÎE;Å·¾aÐQŸ&Ò-FL4aØW*µ$MÚVÀƒ ¦!ÉæIˆ9Gתªúã§bDÝdÀ:Þ¤¥-WjjWÈè^6ôìUðäéÝ;§·KWñ×UvQ¬·.¡„*àóJ#,Ü‘$†s\’8¨±Ê'ø {ǧéÌ¿=sœ.ƒø/奊8<³W”¾=¦Z8l`ï;1)qŸZ·zΨœ{¹ÕQƒÂ‘ÌN'â{#,ï“ß®FâÄ›nØÑhùÇ;mñ1Mé²÷#œËŽ™q(¸VU qCáêÂ%I<ŽÎÍ™4s¶äH“°‡¿œË51€–$1¾È'lLq½-wqVaé¢4í&n½2/½¸œù§Go\ïµ\²t“÷—%øó¶ ìÖÉù*£ß2Š‡ðÜ÷ÎL$mð,¨‚<#5ëÆS2Ê[Áïs}ÌË¡¾Ïûï¬ Añ×R&9ðrD·,Ö(ƒKÉ賨Ê!L½FªFv³¦Â²P!f¾òynÌi&•îëaÁF,Î=x)“Re¦Þ¹=5"^#?#eóO•Ç-½eÀQ€~²,Äx-¸Lª ôÈlgW‡ÕHþÃ×—ÎÌ£}Š°˜ÜˆI n±hš{a¢ÐŒ¹ØšTéyV驵ú0ÞåèúÂÃýaãþvD^fÝßü~îMQN„ÉAÝWG~ïÕóÎÝŽÍQæ3]Ÿ)û#/»lÒîô\ñ|Þÿ•ùöH—ç.Øõ×f|`éøkÌhd7ˆ}g­gXVÖX%AE¯ÊŽÎV≟ £}ï õ/A ±ˆFõsÅÕY~’‰aG6âq¬¶©ªð;ŽÝJ*8…ê¦9íûüBºÊ—7o¿zí<œ}*ÏÉ´Q¦m¢ŽqI«ò8í8ZTD„¿ËúÁ¶[CNÒVF·¥üÅܳk%E^VÏ4Ä[w \3:“ñ¦jüRk)rP௼m9©¢Ûáe7ßÆ«ÌKpWW>ê]4÷‚ÂvÝ2YósÆuJ*rºO$¯œpí´Àž®zµÞÿ¯ñÝðßoÂý¸³°±ÛƼv'®’ŒfÊ”œ¾#ñ·H¾™ýUèi_Âëì}ØÅH¹÷D²ÌøÆšêãc1óI=ÝR¿™ùƒYSeY8=ùóXlY$®­]œ|•t”xJÍeÄ´N ÌŽ<Äckº\y!ý³ú<’2×–°ÓTNzw“^ÙPRiˆK»?…¡79ƒÞÏó{kõYX~›Æêãºmª³á'ámYªÂ™ðŒo€ˆ‘ "í¿ì®…e5,¶·½[—ÊP±µyo,­ž/ m±ë4ßH"$!LÚ&tŠWsW•èf5ð5fH‰l*;Ú®LOt3dcu r®‚#5a ô‰I<%Ç(G¦Uöø¶êªÚê.x—‰ô®Ô’—Òqðƒûf=b¹oG*0'ÍŒÄe{ÃË,bDŠDîÝÚ) ¼òB=‹¾Qe…£ÃG9l5až¼üÕ«¼s*+ó§¤ÊËçÎ̉{æàöþJâîÁìEiˆ‰díÊ£²Ço c[¥¾ —÷>ˆ6h_TvtÞ¿/>JÚ1†û"•Už5(÷ónšÜ2â*KCz×_[¡bú–QA]#èºfqiׇžUyNOS©çžq• ˆ7¹¡u×ø'Ò#5Ñy$ü rdòç53„å®äûÁÞúv{’ÜÉ-q¾1©4L“tpºo¢ß6YÍÏu¿"˜Ë2óWçØΪ9½VBâ§cÆ[Ù#5U;elóÌaWê[Sk\òVôËd.¯‡§§ÏaÌn5Ä“ß$‹Åó5j‡wǺ¬&6ßKxª®kk7q×î…ƒÓ¶d"õäö¬`|¯H²E°§ˆ©3êäÎ÷=k}ZǾéàŒ3÷NµŒóóßïX^XŽžÑ\Ü$Ξ‡Hi%ÙF裣ü|«<ãD U1Ÿœ{uÎ?o!¸Õü7t¯+Ô¿hÜôñkÓq3Wùbbüó-Æêxš…D:hvUƒÄ:s¿ãÄ÷?jZQ¸ŸG=y{ðîºâºã8­òúÏo~$èF øó'·7à 4³Ç ßWÇžkÏni’´9ùêÿ5Á£#5ªÆC¯5ò9çm±¡h3?¥lMAòÄصÜ`[U5¾<Ãœ¹[Unü±>Ü3bÑg\#uNI{®ýü秢Ïw>ÅñÛÓëY7ÎàNƒ‹•ënåçu6Lþ55Ê…vYª nª¨GF±®9Ú©¢Õ†’)¡¢.žÍ<9秊ãZ”YîôyBÇÙã™yj¬µÅrOíÎpe{#ç³êùé°ž•b\ãàA<`STO­ùžÙJ÷YŒL.g´šƒBV•Ae®ÜU‰®¸bU2²Õno’Š¯]`ªD{ÜTõ‹©wjuûD…4ð<梺âcŸ.ç”´}O>k¾úJb~÷n9ðFI럿›ŸOÎ#YÇB*4/9ž2ÿWö^“¬my$œýL{7½D°Œ.É¢98‘}ÑÇ—Æú#à¯:HóÑû®™Jk‡a›”#/û¥ÀòÍó‚¡/wéñã»]3¨mWQUpÕͦý÷™d”¢ÚE¨Ó^£sñ¤Ÿš¼ìÇÃzš0EüþŸ-ü+÷aöï­M‘kÕÝ¢›!Jë7YOß+O++^´A— ¬Úõ& SØžQ#/Ô2ÑG¯#5BAÓhêwlÍ*ìN§n-z×!å>+­5S¨§]S5Oš¶À°Õt#5ÚîTt>ڸϺSŽP×…ÇÚêz>7ñŸ4î·©ž"úxí0µÝ¯æ çzºÐXnß9~]ëVƒîÓro.˜iÇG¥\\\¨$y«…ȼÒAðwÉ2Š‡ TÜ‹´ N“çW4f²F¼Ù¿WÛéJÉå–Ëéﺙaf¯ñZF–Å zº±™$?CÀÍYײÖÌeÅùw$ ¾|µ<.‰_£æa«ŸÂ¹ãXGãF¾dªàx!ç+xóÔë#5B:&adΓ RÞª« hR#5DMüíÚhDc7,O=P®Ã1¿e0¥Ó|›e’ɇUlêÞžøü"¸í^UàPÔ›¿z¸nŒŸ¿=c&÷Ë—ÅM%çß”;º>^X­Ðß4}ÕÅsIñÚ¹¦¼§G{Õ"B×Åå¶o.ZµcJÅš&±š·Bd[× }άù!#5¬¯”%›šPËÍVŠo¡çòWA-«\c#,¶½1ˆD^æü¡§½‹ë¢Šny–„z_„NÛn/¹vÕÔtÞåÏw~ørÎkš$Îcy»ãªcüoÍ`]]¾~.÷ᄦ¯Å–2±†£äãÔøO­›ÄÕ×oÄ£52©Ãö¿âøò¦9ß#/ùÁ€KôŸ·ßÇÕ%½æyÜŸZ×Ãàð<â’¾ªeˆšƒB;s†ò‰n¼i[%§uÕ‘Ððœu¯DzÙÔÔ D]S1áËà ë +FËa  àìÖ#Ç1ú騃4uá2#/óÍôÍw¸@kS.‹s²Ïžwµ¥W‘Ct­p/Yk²Í—xGb;¬;«Ž.;EÇ´wΡ¦;a”'/[Ê© µÝÜ·Bvð«Ç‘(cÛ|7㟨]õæ¦bÖ‰C§d¦™YTc<7WÓ‹éÙUw=Zë0¼ÐǶþþknDqqZ7ÆPlÅR¨jsÕÃTõÕ¿Iï,ù³e šäÆÄ5ª1f÷nM<šÌ¢YdÍèIŒÂŠ³u˜žµ[\­gW…nïƒóV$QÍî>Õ¥÷ž¼TÕÉbåL/éˆb0›é׈֟ŽO³á÷]Mzà™î©²¼nKÒ¿Ôý»ôéÓªéËäܼ äy†—ÃÓW‡ˆAüFŸ.#5{ç®/~ä »ÈúÉmqoG:7—Rì<áá:ߣ2µcÚAuÒ^ºNš°!§CÚŠ\Œ³Ä€ C EÂ|HY9(îKÊ¿%ç#/'ýF/;Ìúj>`Ë_d¥º¨G’2/®^•Ûó‚úÄÈáÞ3—ò›=‘úðóÛÍŽÚ®üëÉtåìùl5J»ÎúúöÉãP?ßïHK×Øá×3¥œO2³ÝY<…òáT LâÊcÙø¡þï1. ËáѤü#/¿kUò„ž—š’ÞAøÄ ÑÈ’ÀÕG½ÉÖšèdÌ·éÅš–»âá3 ø£j±ˆ-1†7ÄŠÑh†K•BÚÕåqy§®ÆOG|`xO Qb(D£ª´\ÿd,¦ò XˆWõÔliï½2뉷íOØ•írqIÍzÎWÖ»,©õãD´Žö‡V·Å¶ûzþ³¦¦ÊÄoƒ]¹9ZbÔNŽoqÚäÂQç·l‘¨¹Ñ‘;¦Ó}óëUC‡Ôܧä -:úÕcó‰TsV씣§C¢Ñøm…dî«„œGlç*:¸IÊyH~Ž|,ðŠé†=Ð?‡n,OŠˆGv‚È–• vHø=Þ’1¾x3!>*Ý»L¡¾¡«µÞl™72éR šÁo¦(§LbåÖÿ5~CµâNá·w©{Eöº.“ƒH^:ì;Š™Žæ’tˆB—zéš³Þäç<&ÉTcKÚ#/vÙGÜPf¯e¿®f|ßÄzm$Ð爄rÿ{Žpr>ËISÀyYCdÅ5)œcÑ‹Æ<ÇxdÖ›Œæíû‘qˆ[¸)’RÔ'¢çË1È?¬·2¨é¬r”T·göl8ÈǤm›É0Ï–<ùËìf&&qÐà˜Ì¯…6e„œ34ëÑ7m+Ó‡ËrRÁ ï³}Pë.dž?g@ºÍ^,嫶cŒŠ:M:ÿ¦ëîÛÕ#,pöÿin-camvÙÒ™¦›ËŽ!hèÅJ¼3m׆Š„¿oŽñ~³›oA1 [Fy]}Œ¹gÒ1ÙS®Šïô;¤ÜI“vÑÂQßæƆ–ú#/»Ôü~¥î5Ù„°ƒÀ»TDJv®Þ_,pcÛê~Nö©ŸÚŽt×ô"ww__§n‚4N-uF:µWø½Úâñ½|~gû†÷bkKÀ#³¹ÐC»–¢— ât£ùÿJàú”äpðx})–) A.ç¢È„t3ïQ¨ÔðP„ó©uÔô,óÂ~;[Mc5)hº,ý§ñoš«nŸÌI|\!ë#h¹,ý§Ç¨V47£Á‹èõíôFãÎ<ý›Q¾9êNs_»)Áëìlîs+[-Ö¼¼3×li2ÂÚ6ý¦ÌJ:nW)C©øý>{­îñ´°ûå®R\¬Ù­3Dɾd7¥µ¿F?H¼\Zœ Hï\ uï?5–Ud!z!Ò˜µI§ëñhµN±#/$Û˜„†tÈöaùáqä³l1¶VÂèd¿¨í‘>¯ûÅCŠ0J¤‘Dm"¯§ò«‰˜+&Ö-X(¥Ìöf†#% !D è1È&çâæH+†›ÂP¦iÑQc7¡`«; sÅJm¥bÑ ØÒUòÖ­U"ª¥ƒÆù@1,>*«q“—pÝÛ¹‹'ª§jWµZ´R»4?ÆXlàFÒH‡Nì/ÈFT†¼ü‘…­é y›œlWƒ#/ïù2ÍÎ_Db´0©Ïí=ÚßKE*ªì<¾éýYT‘VqHTA|ÒÛÿeeÛF\P…äOô³7(Y~^êš½òøÃFº|Ý×[Mh­(÷¸Púö7fî„¿Çôzf{!P¦ÑLí1Ê”9C„5ð9ø›CS¾ÏUÞ|‚¿.fŽwûÎ1ü×Á¿'ÚÝÄgs¬ÏÁ+M-¹=Zqµ®îéjm}êŽ~ÊDŠkÐÃÌR$þI¼ ÓJ¯P|Ñ÷÷™úBm&2Q´û@°”ûÎ’ü¤;¬dØæR'ð~÷òUtˆb›ìDÂI«s’vCÙ¥JEP ÜhQû„c6AäQOê«žó‰6з='ïdXùÎYø}öíöýéo•n~ª3}é¡éS*ïBÒéìÒÖ˜r¿{o³Æì=ž›tÎúͶÅÁa#/J*#4«àWÁ¤¶0ˆS×F—q˜ß‡J6HGÚmÖ…ÏðÇ•Îè=#ÝÅ€V†Æ{‡y¢`‚wð©_“(Ìtñ³‚“b¸ò¬G¯•rÓX|Ulão,þï;²g„ðãxa»D,°ç#5¯¿JÏ>GòwG#îÜ$Ѓ-#,xÍ1w@P¾[wöp øIðúüÿé¬M=SÍRMÝ¡Aô¦à¼~q×Å1¦8D7‰àCœõÿVKÊmðí¡Õ¼N̓íªaì*R¡hÈlW¦f®ñ“QF¥á=Ú¦9Ë.wì:†3t)I†gRó ¢F¨ÝpÀцVÞL®Mvúa5#ª ?3ëιîTÖ‚q‘‚±BR‰½Ì7tñ©)–˜ÒâàmÀG(eA0€ï ¡Ãyßg üåµDŽß”_’ÕY*k~²+Q_Š©ê®*KNýæïN÷JË=L™õ û4¾q×RhíÝK«nf=`{ºàNV5ÊätÏr~]Oø•#@ªtFö«CãP È4 &“"Ó¢{t×H†wüìê¤ÚâòÏaÙPøÞ7vÊ[JŽª/y]‡T˜M¢8áÍL„ Ÿ-1¹×>ƒ“çêžêh°fÑk­bR‚MdR‹sðÓš§Ãmex:×#/µ¦^ž‘,…ðíòó„‘¢Aè{îÆ%ëdõ‚„ÍyóЪ] WžþÒYñ0kNRÉâ¯F9Wdo‡aKÑ|X"´ ‚2CÉ”¬PQìM ~‚«ã™´×a#5bÃï‰I#5Wc§ÁŽj9Åe¼¥÷[n cVÀù‚ßËñÔtÎSr‘72A¹‚Þ‰Ÿ²!t~¡®» ÄT%I³iL©±¾Y-Ù³t£tiq\;’Ño®âçN¹ÇNØ/+#/äÊzñ¥ÕTR8 )#/#/ˆ_#/—#/z—óÞÐ1/g§g–sºÐÔƒž(£ lâ%£·¾ÚsÄÚðuš…pIë—Y GA6Êx=ÌWà#«" Ô;MNü]ìàß‘¬;Ì|K4È!²/Ÿ@ä”CËC´µWW|3bÑ–Šóë­ˆ71žÍ|1€ýË6©–¡¦c.«æÌ<5oŽ OÀCI»fÎÙ÷Ï;¾#)Åa,~~X›Œ3q¨ÝvÀXÀgj3+ÅÕœŠñÑ;Îs’ˆ1âsÆO¥u¶ãÃÁ'Gø·NBæåˆË¬ŽG?£½ÂšßQ˜Á,]ôÀÄXL§I„þØ,¢uH§|i¸8††J(M¥ƒ˜–æ}«ž²ÄwÎÎûAº»˜/Wl#/s•3•GJ+Mã Ù %L¡œ\hå©LU2åkïÍlgß&ji±ÃXòLšPõÏiè÷ñVq!ÖÇüìo8s +#/ZלLVN‹<ðÇEÞH­¦Y(A¦\.{jÙŽWšNvµÝinæJÓŒÈ)«‰º6øÝtÔ5vjvãBg¢$ÐÔ #/#/—`’° 3ßvUo¯#5f›ÞväTšÙ9aï féÃ,}k¶¬ÚÖ©e&†r­ƒnx…¬R0!¡¹àÓØhŒ,í¬f]³>†|f´Ã±òÜ}ÜæÝ/7M¾ãAª•ò)(c5iE¤‹Ic#5m9øëòò9ʉ”xm4Ül4j†A8ÐÀ–MùûAÂ#5hÓ·«Ò·p³à&ºVî Õ&’¸E&‡©u¨<"Jl =>M|ØúÜ4"Rüås¾z§ï´þÈH?WúXRÏ.ï„O.Zè MP0ÿ¼…¿ÝJaÜ"ŠÍ6»._‘»o/<«1•*I ŸßüßÕãaʪTz¡ú”3þ¥6ï;M©ÅX}c! ¿ D&†aùº¸¿ók›V~tÓ¬ ¾0ø|eƒ„\gn$„¡›#5˜q’È:3þcÃ|½I&ŽD?fró¬Öºd9 BMtÃÜ¿u«-ÔÇ}8A^ZO÷¦£¿Ãã ð`x¡C†QõˆV-@‘Fè‹€);‘ Hb…˜{˜¢cÙˆ_c…9E’Ý#,ƒZÙI¥€Ø @ÓEL0î*"¯àï½Å.%%°R ÈçzG1”×éiEJ”Iá¨D*ΖÍ­‚í3<6f"È,²`‘¡Rè`Á…ÈSuï‚&g·X@’'ô q(&æ52ëI|]îëúóìóc‹/c—3³|šÿ!³Ù¹ì<²†"³ãöüfDÿ—Ë]q?ãÝlú6¿½%ýÏÊ[ûá…ÒÈ’Ä#/^!¸j 9q‰öŸ—ó®LŒý±=ŸMüÕðó¨(¸òéa‰épRjMŽTZ˜XxŒÌÁª™e1âcHIŠ~(´É{^£œÄz-#5ë?èÕGJ‹(9¸ÖÞˆ¶ˆ?£–r¨gCiŒõ¶>.sÎ`Œ¥é?äQ¦;#Ýçλ´ŒÌcr®·w’ŒyÖÝÉo Þiî«“VÈ,Ñ;mGJïlò) ]Ú,x3˜»AûÇ##/%iˆß!’aÇÀñ«Hl…uÎ#58 sV¢;Ê8–P±‘7(•¼hšèWÆPa)‹—/zU#/Ù;Æhê¨Õe#5OöÝïÊå3Å¡ ùü5!ä#¡ÄFŽíoÕ¿eCö[Ü:12µº ýp:Dì>F͇ðš(wQ–ëgaÌü(0Å¡{zƒ¼Õ+«ÂBCõð0óÎÇQ‰Eø®jøu×n#/,YÑ $dŒ‰^æõO39:Ñi¦¨©H¬PYET,í·¦³ q˜<ç3¹5wæm³GµÕºÖ&â’ð#/3p²»V`îƒ “IŒ¨$ˆ#5ñ*€¤Ý*”P!*¡Y_ŒA®D´Ýéó×õŽ}´#/B<»XÔ”î Â"B(T{#/Õ‘Œyõ†#/Pyög® 0ìÁ[’F pÎ8Ûmymp΢»H]!º ¶ƒÃ?9r':”"‚ÛMP:1H¸7 †Ó0´Nl`;(ÊΆ´qÌ£PKD}|ŽßUµÆ&>ul*ºŒ4¤TÛ¬à¡%Ýq­Äk^ø80 <'¬OH<,u³#ÛÊ)µ¹³·<ÎÄO}FÆpW|´yÓëÞdLÈó¼¬dd¨ªNÝÎéD8¦3¥ë#‘¶!ΉÎ4E„€gÒE8T„#5¢«­%WWMµí‘çö7UŒB¤ „D N<èdPF-©KfP‰"GÏ꯷/+Hå5I—té¡D–•¡/TÑÇ·€ˆmGšNG•t×¼ÈuJn1-Ȫ”%•É•37yzI ,jzüS&|YóÚNj…ÕOªê!äÑåR—(ÏŒ«òó¨s1ß>+#ÔÁ€‰Hˆ Õ\^âÞ¦„*pEëÎN>>ôŠ#L(ô1Œ#(.UÔ¸O{ɹÓ5D¢VÂ% ¡R] (׬Øó^Y¦O sУS7Å›`–C‘wÈ¢*ᩈØwÅ„NÖq°V4Ï=¬9ÚP’ ôa=J˜JúèC#,õÑAˆH=ùaఠȼHÐ}›=QÕ‚ )¨ÉÁ†tâæEÚékag=LÑ+¸ ÀMä¾ÂÞÃ)€Dˆ©Nï$[—”$!!&A… ¶àûº#xK"¸æÍú,M°¨Ïƒ3rçÑr4&z8éëJ VÉ›XXž­ºã#[•€`¢Z;Õ#5„dñÖótSO+k¸s!u~H£óíWZuË' e*:*ôÂ#5·ùÅóCr 2'o h(:¹ôÎϲ`L™²ÀwÝ@ ‚‡,7–÷ákW*ã/Ü-SÛÓKUB¼ÀZ#5±SB†Ò6é¾ÿ$çW(ŠÁ¹M‚Î%éCËÌùð8éÄÎ/ƒ:ì¢f‹ºêgÕæR‘þ<Ú#/1³Thõzõ½Ž…Ê®©ÑÉelUdà‹ÝÝßœB’“D¢H$ mTK=hŠA0i*zšëMË[ufr­7 63PA™ã“Ý9² N®ú-ŽX󹌊t;‡T±ñöÙPË1ømÝó³2RH(£XxM‚üŠ(”–!2ÉJöœ9ƒ7>®SXøžÎÛäc$õÆÅT#èær•8"p«ºÜyK}³ÊÛhŠG4!…Ä'–˜Ë)Õ)d °ÏÖùtó-vEØ…ª…[â÷ÙrCÙÛq[¤aÒ¸2.¦Ë8¨#/…(Ê6 mžJöU÷ùKf»QÂLï¸:kÁ’ȳö‹>‡~N•\&µÍ¿2BV~c‘˜ÛË7¯­¥ùãnü¦#/½­¸›üæÉŒy¢“ÄCØœ›4 øF¬ŠDA†'¥iT¦„Ù6¿èº8|#52Å"šê),(5#)Pö¢p ô9QòHmšt¯‡Çú,ë‘\tváv–‰ÛG.K} vCŽÞEâ«ÜÎŽ1£d4>?P=ˆ¾¶•M!5H«©Sà÷»Ñ|zë¹ÃÆÊ~x!Ë£»4­7ãíŸF'é’qŸ0ƒêìÎt,#Ñ÷¶ØðÖ[†A1,Xwl¥áý#5›ƒ{Ø‹KK9l£‡wÜ·#,ÝëÁ™¹!×I'D:u”ó!zÐÖs,ëÃ×ykåälö;ºÃ@#5L«qž½ÅZE µÅÙÍø̬#/¡uò‡;²)ÄCnûôõuÀófµ´5W´ˆó~£áÆç"&à±Î9Õ)Ò#ØA„-3aüFðÃ@J2ˆ÷}šyÃÁÎB;Zv`äYÔƒ¨­‘m„”ÒÅ£Öº©,É%)š1D5$:±0ðlT¥ªL—¨Øš57ˆq•‚¨=š%$7š#,zˆÞÛ˜“õÄ4—õzm‡SêS‹ß†t;ûùËJ,Á¯ìâuBuR!¿"¶Tï‘Iȃߣ5~#y5‡–$!¹t$à‡cò¯C™òlzEu]Åu&fr²Ëò^»j`…KJ ÐE#,Èôò–‘Ñ6z~ç ­œ›¾M‰:êƒÛ A2›ÉAÇÏNí»vlÃ1vkB>ÖÜ€–£–œ¾êسµÍp?tL“7‰1Æ÷2>9¢X’˜Öã+s¯:Å€°x~ÏϘdcDú>þXüœvÌ~ÿB¨e’¨o{l¾P3Š\yÑEºzC~à”äUdM"aùi¸K£š—ý¬ÌÁÓ(ò£ËËSû&R–iâf챇ùmåëÇÙÐÌâOt ½<#5VûZ:ï•»»\œXJ”ùžääÄÚ%o|©¾~À&b º“A+¸«: @Ï#50‹Y™ƒæ3­»ztÿa/da1A_âýã¤?Ô‘!!Êa/à ¨ù¾ÞtÙ]a¡¶&»e‘‚x@=æI®ûXt›õ ÂÌQBòüׂ“áeuÒ¯ÇÊ¥³éñÐ>Úôbý³Óm¹EoõÖOê•ÝÓwYmuwþ®'.pQ̆!3só÷œ»sñð»„#u1¥ygW[Ç#ùØsaI þ$¤¤(HŒ‘B¤?£%6¥ L¥þOyaýŸíÂ1÷úZ¨DoH˜j/½Øúañ|bB/ç‚P2w3ä£ur¡ ¡Ã¦;ÁqÓHq³äKD¥–•[Ž8V¾Þ±«˜öYŸ¤›~•ØÛGÔî#5šÖ2y_–Šçö~eÙÒõóÿÔÒïÞuø™†‹]fW—x€ Œ/®éîý÷ôá}•?ƒ30_¾}R«6-bj¬y‹;#/’`o§~VíÖ‡(uD×Y_s Îj&8Úc_¿yŽÌèfø¢e¡®G4·‡ÊŠ$Ôzj¯Îø1rVaD£ìkZWGó¾-·çg2mjˆ•Š¸gÕë}agæ+ª%ž®Þ³ê6açãwï1­rN–›Ns˜5311Pú`ŽKt¤yº¸æ!èóËÇwoëÅ‘`NÌ1/ú(KôÄkøÞ*²>²Š$>@ªˆ«ù~1[Þ+óÿ9RqXÌ°Ìr…§#,&éùúµs¹¥Cõ¢R"é&H<ìLjñã·¯œ‘º{ú(Ø».qÑAãºÉÂû¿Ñöc?‰.îöhD d(ù|mû7óê#/@OÖÈmLoO`•^.Þ²]ép0ÕÒûttð†WGš)xt áy(kÈóaöÙwu+°uÀ-‘³jß®Ï(ñ¿‡šÞÑ:l ^ÔuyãÉ¢Ë`Y-ŸAßêÜm z5ÄìØy½òT‹à禇˫çÑ¥"ß— ÌÁ'á9´äiÏ#5¡–´ÖÎÎÃ|©›fÇ"ÎÞ¸] ¶1z¬ë1[ĺ•|ý®®Z µ¤Ó’"kmõY‡lkø=xû|÷¾DYe-bBfGC\¦"ËÉ.}yfnûýÍÞ½ÿ5“Ïœûvúc1#,…† £E˜b"®P»–æ>!#ÚÞ³Ïí9NgÅ®¦ÓLOpÞ¶f`ý ¢'ÞÆã‹eå3šÒæÙh õæ„€’„)9⬣u4œ9À¯ãßsª"➺_ÂMÿÙåöÞ7Öÿ‡5ö¸ÒùLÃ.ì©"¸H¤{áÕup”æU“g†:¶z8]›½™˜}‡ßš2Ûª!Œ·@¼Ç3‰<“Nf?¿œi•A¨àÅ^½# ¼õ©ÉÛ<ï^Å¥ÎÞhmöÞ-4î¼3#,¬ßÕ½#/ÒüNªÞ,ÿW?]®É߈!Vâ šæ ‹¼Ãáà=PÌI êEš­/l×À’0iQýñ¿é–õû³”´wÕ""ª‡JæþöâB™PKE¿yŸžùçµæßþ¹®>Ó'#5|#/y²‹ð—;ÇÓb·sŸ*Ž/›öΠC÷xëƒñŒ’ýo‡×.^NÊ”:2t¸7·ä¸õ²OĆ!8KÁÛ’¥r„¥i‰(<öA³aNbìñ®SòþëÊw5Ú/ã¬Ow•Ë<‘0üÞ„z*Û/1IÊNyàÛõ¥w4Oª¡Ë^]¼/ ©/„»úÚðLz Ð M–óPÐòF×ù$sžHDŽO\°OQv¾/Úáªuñ\̉zà}Ûð‡˜ƒåÔ“¯Í¶N§Ž'¬âÇzžñ&]›ÇG:ñÄq£®ë~|Á83M0Ŷ-^\{uïŽñ×z+îs>ÛˆMgÙUùb6vLtOt*dƒdtºŠóõæèj·C‰~ÈyRãÈX¯~Lw$êéjãΫJÏœf.(ó|v5|cw1†”YùÝ%;ó‹;vÖ{ç]ëSª0¥“¨{ý#5™O~ªìù–aÁSúÞFÒº}“#5 SSa:›; bî4Í‘ÓM0–vñ®•8èL±ßðu_z<ÍQCØYª-™_¢eœö“"¡Ï¯# §ÒðÄ*‚Òð6¦yI¼GTWUñöò¬·/dzI#;~÷?N€ÀXó‰gíÖ©‹åðÃ2ô´ª3·kÓÀ…˜¹­1Ý›è›W®Ã¿.’ýQµlUŸõ}à«¢àu#ù6‘oÖé”ùÃZ¤î|üeyš¹áŒ|ÓÃ?u#/äˆyÌž0yÉ e²Á©}?6ÃöKžk›öò6^÷Ò$d›žÓ¬ú¡¬õ}lªŸAd0­•÷)¹eÓš*ŽñbfŽ\=~]H3ÑËÁGY'œ{l;üÅ8,J»Åž¤c.ê`ó—gÃG©½êÁ„çƒ÷¿ö«3õqà[Ci30öÔŠFª^;ÎlËškF½µíáøíwX56ZËY}.ˆsŸœušÿVÌŒsç9§wÃWi&yZ_ycé'-ê0ñÛÏ̽%êí¤uàÏAž«¬t?whlŸl?CUÀÓôÙl™ s¨#Ê·š¬§dÐRé.)NÈøõ}­¦r“öGüi©Ÿo‡6#¥Å)CýW_™ègß. ì,O/óD(-_ZÉA*9ìæZÜŠpÔìñ‚­þQàÌçÛeÁ×$n9µw;­-k1æ#/Ò·ÃùÐåÅÄ1èSñû2}j—Ç07ß?†ïŸmKó¢Iîìì‘lÝKpû‰Ä—æçÓÃÁÝú¹µømÛ¿Jç‚©£Fú%ü²ú3Ÿ)m5S0W–‚k(êN>vZ´9J =–âT*õ;ñRƒþkÀÍ á–¦·R^4ÞpÑðóï#5~§zHßÚžØ$ÇO¾p÷|œ-a{#õâaöýPt΢‘j+Vß3¯ZmY·EÛHÂDÚÛ´Bò…ñ¦dBi]×k%ôKÊ~âfQxô & Û´P“Å1¥8ƒÑGâ ´Å$¿äjêÅ‹ò‘à%ÄÎ{‡“éj£øYB®DÂ^Äi/¦ê8Ä0(O¬DãÔ,|–-‹$ʽ³—­.kstÓ‘Mâœ@Æ/(ì‹ðåñ 4(@vχ$ß㦔葠9#Æ_#5…“ôÌtMô4aþ¡G.ÚqÇò"Iêƒ";¼ÆøZó~”±Ë°#5±¹Ë£]õ5äÛ/èCKK–S¾üdûiÁxjÓ!ÒëqÄ ¦mäAìŽV-Ñ#b0ÿ9¢P“õUphÑñn‘kYB.Åã'Aˆly! ­ýw¬ÚmA/Ò³4ŒÞ¿Yþw6¿1…1>o„7?\/ŠM„‚ˆý±<#5³g‡‘ã"ÿ«îêÍÑ ìMSfé‡ZtžY´>õ”µ"ÙY:uè©×í7R§#Ö9D‰›/;¿+ü:ÈLœ20ÞÊ;ñ¿.ÎRýUß]§ì>öüM•cNnIï»ô#/OÐËâëøë峿ž,MÂ61ú¹§ù“Ë}^õ™¬'[XŒç*« J¼ßæ|wªŠsiùHÞ´½Å V’<°>ì³Oáð›Â+¸7þNE…»‹È„œ*jýI@ùJ„Hà8;׬×sº“uÁÂå¡É 0bî.ÊT÷À¼èôÀºSÖtǪ¦J+3½N°dl%ùðfg kD×Iú!{Hë_wçÛ†™Ï¶>ØéÎÇeâã(nvç"ìÊ<îB.&¥tÔwtô˜ëCYLæs¸™ª­$Ýh¨›±e—de^V©“ÊÿÇÝŸZ«Ûku$$Gpq3 Ý€Hb0PëÚ‹V#,°;«ÃO­=zò&°¨ã¾ZÊe2‰š7ˆ„Ý&q!þ±ãY}.+ÐWæ/b\îñ œn&݈vWdH% š=2ƒú®¹†!ð‚-Î5·6÷Ál÷ïÆCÜÅOèÉ@&àÕ=Js†¨Ï#,y]a>”VmÚ@ÂÊÕ{­y •OßAׄyáÄõ‚„× \ÖÞvæ,ÖTö²Ùá§N-e{ed:*gsàC;º¸Ü'ÆùJý~lŠHg Í®ð¸E¨‰W7‡ŽúŠžu+l¥­uSf½MÆYÔL`fe‡#/k8î± uŒq°å‡›9,èŸx$YG±©ä‚C¹ßMp­@üpÍkI·_luÌÇPaw=µ„H– w>õÉ©;qx,ÔñÈÂCÊX°L!T2šj‹vúˆeÛ.l:¼Á Úesj“5Æ2"X’~¦·O—¢ÉØ{{aϧy¼}á˜Û£ßÑ·›nÒVKJ3ÏlõʺÍ5N³¾Ò–¾Ú1,iª¬Ú{lÓ…åÚ³ u¯c³Ni0äÅtl_µ6ÔΚŽà#{³“AÁg©í¿<Šˆ{]ÉÓ^ÈsüS™)ZãÂÃij›ÞŒÄ“ú¸@è]ݤۻ¡}Ù¿<0UÆ&„Òþ¾¿7¼õßµ7È„u¯0$þÿÂ/ ˆÒ*‚g¿¶s§¦…áš¾}+˜óŒ 9ð7Ÿ‹®uüE4×J ï­±eóûú¬OÖ"&ܵ*£¤NžÓa•›ÄšcUÈ:bðÌÖxæÞxí*G¢¬¨sf¾&#/f2ÆJ&fŒ­·EVú‘ªfE*ä8R¦|¹çZV2©r¿«„Ý8Mý®Í«¢K¦p„þ•`©} 7É'˵U³QßùyØÞ9åͦQ#/(8z»X°Ìi¯KçÎÐÒe(U”W•0„~³ãøyÿ^¢ü(:zKk¬Ç’ ðŒdÀðV¨jÇŠ™û¾Õ~ënõÞNÍàã•ÊE^ÔúPù4ÆŽ„#5žBGeS‰Îá ¸éÆäiØ)ÏlO>hfëjÜj„ô¥f )•t~×3ߘŸ é BS/£j–n¬+²oº%ºCK›,¬†™k¿UE.ýЇ©šH”VéÃD/$ÏÛ»ÅD|¤îvá×Ý>}³ 1¯(Ç»àÆqš·¿EÙ°¹e% uÚ2öž§µ•ëÙi˜ÎÅÕ,Ѹ.'g±•b¹9€™YV#5ßk¯6ï#5êø*tòž0å#/2ÐRÀJ²Ÿ~Gó`jM½]å‹beýqKAJ`ñb¼­¼¿i8±!#/wî=„+-ÖØW8#,žp²CûÛˆÒÅ\wñ_Çc]îgÑ¿Ùõä_t…Ýy¼Õ×êßÝñÓC“9YH°fôQ¥þ5Œ´(ÛsŸ­š”›Í6ö8e6Äîè…;iøÑÁDvü7:L²í•ÓŠƒÍ:C¾ßÃŽï}y!!æT}£E#/înE ïQ†×ÔÒ&GÈaç´õ Ý#/=Ì4!´Kkúiÿ•†™7ô§s;cQ(Ò>=9\ÌeVŒé,¬,Y9µÜi@{}6ß_ßôÓ¶ëw0RDXìyð0Îh©ê~ú¯=O¶¥6Ê{k1¨÷|=9ñ©XÊƶØd{<³È½ˆRÔi##5;7¿ÑñP­‹R«”*&vl¸VO^5Ö5Žæq&ïèYè_f_ÑÆá‡óãÆ#5mÉÊÚ•äÒþÝ+ß FoÓœpÙŠvcgïøUôÈÈr°R~¹ÛyÜ"ij!”4f¬ä‹¢’d’K°™mí@(wÊaá›=§„õÇ“³®ã&öéQÑ\÷ú'âñÐ9Ý‚-ïß·®²GlM,]ÑÍä_Âyý?d¾÷CW“6#/úénP<¼å¹ú¯€Š¶W•ï6ì­²)†î9÷.¬9>sl:颅\†`ÒúgvÕ‡º9í>žª®ì¢YŒ0¡kË|`ÞÉ6´ÞéßìÕU¨%bÔ[ya·>ûé,ðÙq+Œ­Ci1b©œêíyØë3?TïñÆ..ˆ>Àè)®ýèÍxqûuÏz®Iûúo‡ßÄ`Ö5qŽYøç"­c0¬¦‡c5¶û´-à]¡àl„jÄ1Ï{bÜ…éÙšcçc‡GN=ýˆwä“Fz^`Å#5ç9HªÔmºj­Tœ ÕõDÈùNÛñÖóÆò#~¾Œù<Žù„&}<§åpÞ:òRÝQŽÏ4¬Œ3?–åœÙ½rÕFøðçómwÊ5èÚ@#<Ô–éPúS&79\Ó*E6HÜc>±n. E–gÛÀ: %“È{û°ä½(Ôa©#/Ó±8kŠ™‡nXÔÅ–ÌÀœS4AT(q»«Ýž2­Ÿ¯^M}PÀºm͵L‡túUø#3émk$íØä‚„¹üÆ¿Ç¡v˜Èº_=¶77˜ ‹¦Äån–âÛü æA ÈÒØFQ’›WÆbr%ºŒ)Øpr17ü çXÛŸÏ~è:«Sì~Ê:æíµük¶QË´88öÌ„¥q®0§kÕþ1Æ3ÄÉ%¿ué0#Pè!ÂÛ(¿##œÛn«jëŸf]š(ñÐh0r½tæ^ÃDYÑU{á‰ÛU »jz e~0Ž’^+c´x’ŽXuFOUY’Ëbpwù û*¬¯wIásÏ Z.7³A&ÐATiÆ$óÔtç‘ny[š«­ˆ_qsóK®·k*ºüœ9§ê†ÃÆ&Û`äe´>U\7ì¨Â&ØûËGI8å…û~_¹´€M’¬Y‡·Áù+•YcQTákC’+Ðg.ËÃUò­óÕ˜Ž.ñº4Ý5¨×œ¬gµÊê™S{w3ï¢ß¶ ­™©¦nªÔ·U@Ó\¸±l#5Zõ,Ô,nûdÆÆÔqr¯KŸŸ[߈jî[›%Ÿ&ºøLPIªä~býºaûŠú-ÍÈç#±¹€×¶,Pæ÷s®€Á0æÑeØ^8¹;=À'•¬=a Ó£MÛÔý9Y‘l˜V= Ê;ù˜®J͸j¸ººVÆ}ûg¶~·Ïfˆ;†ÄÚÆPË>¾wŠ¸Ò맶è™ðìÏù£ZëGÕVOA@%¿ùþ[?GÇñžÞóÛõxQÒÇD>ˆ¿ÒF¿”L+Й‡›ÿ›ÓDð˜ûâúìBµÝq< wõWÁ9äs¶¬ÖVj¢ªÄàÊ<ÎS¹9›-[61øØÓ_íëSïòóY{ŠûKãràr—é÷Û{yc‹v¾<ðSŸÉYâæsyV‡Õžâšr_e’ÌòÏûŸ§Ço›—Óù|–~—ól|Š²ð ÷5†ê¼c¦÷~‚ÖoÖg?ZÇVœ‰²°¶Ò#/ü ÏÇ–Z~¿ Xƒ¼áôËö&ÉÓeÑá@ªvH¡9” Ç ™–[_ì$÷~àt¿»6}ž/©\ ö°~ €ßb#,_`éÆ#/ο°`M™BI?ä/õÓÁ#,!ߢ¾™°€åa#±#/é‚6%Vá pU",#,þÇü¥ ËŽÝ³ü_Ôyk«·fDO+‘h›k öÁØ­™?Î=á6˜À Œyu£ íéÞn4LØv7*pÄÔ2“_vC„JÝn5 B"N¶¨Ö˜IµEœoRO—Å 3¹ Èz1~Ĉj á‚U1–º¢¼÷ò[§`áâÓѱîbv½çï°è|}þ Åú—Ú}®h£™¤=¨;!œ#,ÿdE, Þ.àø“­LÒËHæÆåî}ÖÉ52U¶u¨Yþ'צ* í ÞôÂêéú69¦‰èܼÇäÄAO´Oñ.‡‡øwwà¦ôé“âXñg\ÿMZ%Zß²mǸ°FG$-~AæþLéyOø/²í8Ô;:#/¼Úy >²1ò}~G×6ý¯SØ„ÑA`­'šü'ÕjY£›‚A"a‘KQ=eksý=ZŠ>'Ì2†ë¡ÌÈÙŸò“ Y*v}Ð7Wæ=¸¸;µçÃcUŒ%b.qJžº“XŽ\@"âØj.6IN‡Œ$6$ÇRg˜R±Du€Oä†AŸÑ<Š¼Þ¤?ËG¨bÿALxü*UVªa‰‘|O¢˜ÖR<¸€G°7®Ãknà#/€Çï$êÕ5îFÕïSqÜè‡#P-"†Ðñ²ÁŠ#/” )"b€N²cè{Ø\`pRƒK$aì-“"ÆÐ:\ÄNkÌ×"G:•°»°„,dLXÂT­J#/p/hÂQh:†÷çïH+P#/ Ðûâñ#5Ý™y‚ÝÕ¿õràÌ‘DÜã¡@Þ’¡€x͉¿.tJ‚†QÃBÆa2D‡ýd¹ÿ©ƒÝ ò€€xû‹—˜’#5ÒV}xT‚1òÿ+í‡ß\kƒgDÆ‹FhU<è…ÇCßá{‚JXÿÉq¯Õ¿Ï:‚ ˜(8£û<³êÎ&'[_ñÌõ³}fÖD»8RHç»?¨¸û]Á; ¨F#¸·yó4I“O}r$Õ’Ù9J>¥»äpææm9 Pþ{•T†ðüÏ)LHð§qDBD"S.‰Å¹Ÿ´ÚàáØëSHB3B= 8?ê—#/©Ä²í7ŽÿÝysµRTõ4ˆ„ €Sä4§äõþž‚ÕR„ÉƳ¼¥rl™ßm4ªUQÖ«lÕm ÏŸgzâŽý¸ag?q¸8àáæò8Ø?½÷ñqàGৈzNs‹,Xï×iå uÐÕ9”r4  îw`ä]Ñ,Û͈ÃôC­ú¾û-ë~“âF*^ƒä=ŠCÈ$%¯Rff{¿–š´6nÁkÝKIk}/òeŒʆº(ú&î?”û¤)#,ZÓ`ùT×ÐSÂû®3|s§V¸L[¡WwtÄ$N”Î êÒµ~à¤aA|‘¨Ÿñãäû!ƒ»KÓ4—iž#,,±*!¡5@´DÙ‡Ûgpøï]éá8„Ô‚Xd#åþè‰e¦JÓ¥aü”E"E‹|ƒ„¤4ìÕ:#/ú_¥Qqi,BT<Ú@Ò#,‹¼6?i`>|vîÞ#óaGÑ䘮dC1 Ž¬>¡J ¾ï»þ·46}¡öðð"*’™çÖ¦Ór‹Nñ‰Å³¸ÝP ëÒKÓb]ñÄ; #,GŽöŒD6™ø¥Ÿá±d6Q¿¡bÀûf(h©¾=ôÞé4¶xÄ—9°ˆŽF)R 0ñ‘Ã2‚Á!ÌIY"ÑÄÀ{ŽOwy_#,ÅÈšÄ>#×äଠ²‘Fm­Ïð~n5UB"{iÀâœ{Ty7, ?_ƒØ9¸Xf&f4e°³ØºS‘u0bØ.„ Xr!ù_¼ì7œûGû˜=/#,taû¿«÷÷l” `ÿ6…Ïß#$3<£¬m¡F’XÐß =.Y%„êüz¸Ž«ª¿#5Íùnî„»ìU[Ãu<ôhqkÈrªÍI ÕF³5„+Œ|‘ä|¥Ç·§HÞáI®T«|˜U3z5›–#ù¨‰z™Z›&`™±æ\ÈS©XD"“¦ìx N‡Ä£uEÈ÷iVeCMf°»D!cGùX@8l|߯èü‘¨,¨2"Hª~x¯Ù”ã,"s0þFŸó3Í®¤þ¿·ëõXö>ír6ýí÷W³—ÍU¾¦¿¾tvë€μ‚wCÅ¢$‰G$’I––ÆÉ#Ÿ`~ò xäa>Ÿ¯ô£ùDyý¨q§‡#,Þu(KCî!ÏÀ´%±°pxŠ‹_³G«K•ù—·7?h(ûãw|Ë4™fÈ‚Êñd“B¬Þ‹³XÄÄé•}Aá¸ÉɃ8)ÓID¾8ânòHàîât’HßUå]äúO<é'Wpë))¬éBŒCxÆ6ˆ,M^#yk#OFü#/Sfœ%Î;âSÜ÷‡-Q„Søï× ÷ÖgäÇ#,qô¾œ„ÉOHPÑFã›ä!dã²€½ø~•ö²Ð0¨‘#/ú/Ï\èn©¦æ5š6š6»¶×Ÿºû™ fï@xÖ$ü´ºü™Xƒ^æXö½€)g×H#,QT¹°CÔPô>ÞƒðC××÷?3ªOˆ›š±Z}ƒ@pH¾9¥¹‘#+ñ9„ ~Ç~¯pm>Þ ^óùè€F4äw_øŸ¬Óêlªr  $þËý({]›;Óñ7ˆpaÞ¬{E;#Dc‚;€àøx$Âd´lÊ6¤AÓç]qñwžAÅÜÑ€¶}¨Ïg"´DÊ<#,çá;ø”Ú4ÿŒê| ·pœ-ý9ðžÑPõ‚‚Š$!!|á4ȳ֧öKpx('™‰B&ÏEŽˆx'7ËðÌÜðäAjXúG®tŒ"± :dñ‡ÕÅCâp¯¬#5…ú»¿ã )úüt€_d„cÙù+ò }’e¯¾×Vñ=ÁàŸ(¶í~t3yxœÝähŸ *(kŒ-A[0ôº™6 b’z™$’y€\U=@f{8ÿ-´@µÊqͲ4dˆž¿GëñH¢^}ã3DI­VW½´£Ç»?¡>¾†  òå–Û¦rÜ«k|[çäÿ òÁnzŒã$ÙØF$ö·Añ‰`(2½0„*±u4Q“ŠÊÇf#5BËß…44ʽ‹…~ºTN;:šÔ)1J³ÛíøÈf &a™êQÈ$Šª&$0buq’ãÆñ#&Ën¾O5›˜NǨǠm}i§-î#,ˆ¼ÄöOg{®C1 ÷xX#/Ð_Ϭï<Á*B2† ôv;ŒDùÄj¶©vª­Kµg«³ˆ¦'¥'úÏX€ß0>¬žðö+Û¿„èêASÄ#,î6‡nÆŠrt`9+ÀR‹>SÅþAv%¿V^}MLÂÞ7 ‚iŒ3¯Ò·ôýÉ?¼Â)*Ÿç»¶'úmYCû^cCh:ÖiÆÍH#/3D"G[Ú¾#/B31tÔF®¤(wfC‡·OÍã«jç6¥­r„ˆîy­ƒf-`"÷•Ø®[ #,9RÕ|;ªªÙ,p…\À£þq6{˼Ññ ìó”*{€¡ÄcçxÛ°Ùô}FÓ`§0ô‹"¢)*F˜ >òÉÔý#,dû1EÉŠn‡e)Ô}a2}¹ÈÌ„9”hhX±ƒô\ì¹ÀðõWî»÷lËð1¯CÀWÄlŒhãYy°Ì홤w„NÒA$D"DŒQ ˆD˜Ð]È~™b!ï¢.Ì…ÌÎQgÕ}ÞáˆMwÒÕç uœ5@ŠbIrI2qÆöºDfä̦‚‚BLHzѽ`.~´P+g“P}BâQp=èþ„Á"#5° ÄP~ ôXŒ€ŒŒ2bÙ`’hXPÕèR@D0ƒ!#,báE&I¨‚dzý€¡Áƒšj4jZüÎì`Ro<ò÷¡âfFÆG‡Ž›Êø™&AB<A#ˆ°Ü«JQØÂÂõ_j4OP~1)Ù¼ÑLˆ}9šJ#5„IØ­ ÀˆGõ(þ¿ïøþèG>aöCÂï5AÈ#Uçì+)'µ¨£QÒ¡@ ±’m&S3oŸy«çï[;µskÎÜZÕÙB#bA#eSmw^xê³Ë®[Q‹{{>!œ9üíÓè«$Û:ü`x˜ÌÁ¡£Z]kuýà”ÝpËâÌA>²@%®Ð|Š( BùúÞ#,ÃUØÄ4´Ã°Úýú)’^ ”8‰l†•B‚ÁB) #56 ‚%›1Ä„:hf…È|è⥅¬”ñoòª²»ùÍ㜠=ïéveÌ^à„âE¥ÄyÑ¢A ›7'^äýSí¢–q®»´2œú¬‚m8…0-®Â‡lB¶É£Ÿ4{³ž^Æw[©š˜ÛÈFã#,Úf’³ƒ˜ÃÑm=ÿ zÈwwXÊ•®!^òÔÑ$¸Ù;Ág¶¯"ظn骔¬UQ|7¬+ýÀ?nÞÃéC .Ij^TÙHØÛên˜…}`À‡³cbåôoZýßœþé1†Ñ6}âØ«KL© ä â„‚#,ö$÷ &¸’O·êq0Y½¹‚ J<äÎ$ …Ô2¹”Àd£³#”T¢ƒ@’sì}Ýh¨€"r#ÕGSBPJfXâŽu2rŒrÙ±H&*7¦˜ "?P>'°¼ýžïп#¬¼˜“áÂÊô;OºZpìÙÕ!b÷Äã›$!·½Ï #äUóx÷37^Å7SÉ°®¡øï%by寧 bȱ;Ûõ¡PFKdZ˜*ví¥Š$™že¥ìÃxÉÉzOgÄGê#5MÉÁ ì.JGDÅþ|ÞôÌ¢¿RNÊ»Ë%ÙŠ+.ÀÄ©%#/ `ÄÀi1;½…&¥ø(­ÆrE„2–½Û# þq8D\èk\qÙõxø¦eŒ~¤`9•hT¥ŠÈ‰Ì\#…æy¼0nxho„H‡AL““#,T7»Ô#/‘ ¡l÷í-À#,@Óc¸?R(ØC·ÙöÙ.ŒL-ÈúzÎt fÌǨ u×¾øMœä" ‡ê²¦#5.€DìÕ û½X9ØrÄ:æP•×ˆ{ú“È;JéEX`“&@€YØoñ³›¹Ç¿4¬^m@ª1K ˜Ë I2mN/´ü›á2Eh®0­ÜŽ(¤Ùë^‰ûåI}²,€Ü#/ÑÞçP€‚ $4) zj™&“D);&$M¦ì/é×9À£¡ Ñ£D&èä$ZfÕÌ1úñ2:§6A¬å‰<—÷ˆþ¼£e“ë‡vÕrlwìC5s<%j¼™fgv÷§' ò´Öm¶3Dì=çëî”ðów]Ž£S£Ö{RD]‡#5â¿&Î.Aƒˆ+Ū9Wa¤Ö—^¢„Ì¥úÊ#Ú]§@ø$Ä å<“â—ëÇPIë§øeI$ÃŽÄ ;”­l h7àän\ÿV·· L‘ÓP‹É• è~‚(êgrò7·F0ŽrF* àF¯@l¤r7ÞŠà~xOZ/$ØhW§0øb˜¸Ñ ’¦%ª-‚¬LsÝ×ÀáÍíÌìsFEÞQB=õ´ÔÇ\ŸWÜè…³­<³·L¡¼îOÆRù!¨e/¥„ëõ™,<¢h<¾(ÖR,RåÜ#/™ò»w3vA&Ø?¬Þ¿O~÷¢Bâš¾"võÿRƒ3Ðn`ÌB®¥ÑQýñµ}/ =¶×ùc˜^65iÔKVäÜRMΟÎÞGgc›²h“š‚L!0‰IÈyÓvHðGiÕDçi2LÐ/ñµáTÍQþ^G4ìë ™¼Xtà†}p‰‡fì€ D Û|,8ݵ|²Û»ã†Ü3q׋±½?ˆ$ÏÖL@£ÄFL+¦Z÷‡Š4³FëŸ Ýt^ôpBÄ7£AµÁ#5CèÁ-4Hðp\ÆBÀ@è`©IõGãÞ`UîŽÓ LñûÚ(Çìˆ&\ ˆB$` Ÿ¿¨ï°.ªpmKÑèsîL»ÊÀ²à& Z*…ž‡¨àí{šfÐT7|ÿ­ÇÙ Ù=C¡ÍÆþœp„œbùôq¾XÆtL–?ëÐÄŸ€=ŽÒÞTVrG°.µ€\À'Ç8b\ÜÜàpqqÄp C¼È ¨ä•õû‰ªü{¾W€n88£·èJn»ÕG³Ã`Tv°)$+§ªüW¶ ©<ÂL«!{+ò>¿ô¸¤èU–#äˆÄíWt£ŠÅŠ2-µ#5˜ŒíøK•W iÛLY­À_Ù²’#l #¬­ÝŸÅµqíŠns¯ÞT‘¦–ôD·¿ðë?aÈžÔ­µ[i#/†Ú¡+ÒÐ¥f¶f,‹x ¸÷Õsà&öЂA–xno¾+½+'cùorXýºõ½9ŸoÚ—O²ó¨>óû_‰×õD~Gö!W*z&ýÌ*|õÒOö¸[|vKy¿y«¥ÖZæ¦o.qÓ2Ø6 jË A ,«L¢€~A¡€ÚF hàši²nÝ´ÒKÐbDÉŒJ1V4J¨„¨Ò´Ø#4°(‚±P¢¶„ˆ+Ùm·ÂÞÞu­â6ñIXÅ^à‰F ²*¤4ÿ€›Sþ g×#/ŒÜ„+ÿx¿Ôp‚Kf·Á=8 $Fhà BÈ(f¿€~}Bc‹Y$þõ–«Ô&1tõØ4AeòbÊïÝZ¹ôpÁqy :0¢G o~H wt«GRäÜÊô´*Äts† çk *ÅVLv Ä;/¦Ã7ÈLû›‡yêÐì{ȃHDS.W?=ÿ;~c³÷~/ûVñ@è„;ÁZÁ•ßƒlýFúQk¨˜¹Œgáþx»±Ú«úy/Ÿëý3b·Þl§~V’ÀÊe!’/‰ó¦f=¿ r’j‹Ð-"†œšÝý®ØN¯ äW¥¾ïÚ“×2 t“3¾î%š'3@ø@Dá' E·t@?Þcî.Î÷Ó¿´uñQì±—#/7dr‰Š*!9ÌNcÍØqúý‰F®;O7˜ŠBbqaHÌ€íøâ>>tɧ´ƒK×Ý7–1nóµÛì ¤W”P0€™À-PáBB™Ýõ¿Œ$ÍR$’R#5Á¿å‚"Fd(;ówI›Õä¤2dxDr¡øïdÞg¤qÈ!¼w ­¸3g׶£û[ØÔ)‚¶6åhJYšÃDlDÁt¡É#>jä)PÌ Åáù=nÌ7*ÛœˆA'P÷IÊï…ü†%l$Ž°¤„dàü©« 4¤áhîÕ‹@+!§§v‘‘²ç€k»ˆðsZš‹~‚üSºŒð!¿ŽñMO¦NZ3h>"Á#,R]"Aˆ HZig‰#/yš†!ç-üا“p¥Òûù¼Ÿý=ƒ´3‡×U<’mE™^ô:Œ‘EnBø¼É8<Ÿr‚°ÿOƪçÌüËšS¦¶ï©Âó¥Ñ=;iG\•;\×¾f óDœýLŸ¬õßhcÉË ·Ã_ÐãµwsI‘;-”™˜¶dˆ1êË+aïòYáT³GÒµ@ªY¬'îqÿgöŽ`”êhiôA˜"ÈžNÍñ»0¾D4ùµ4ªý|6¸ä¸Iµ&Єîu ‚¹ûàW-ÑÅDéW2Z9{š¼©%Ý$‘AQ)‘Æ|²±šôrE—yÌ!Vî=!#/iÊ:ƒŠaË¡².㼬†Z(}ø›U}¦¶BÎ~\šlG[I–÷+_OJܵÕÙv,´ÅË<ÈÃ4¥ß"¸ú A0Ž\&CïÉÛüôŽ>é’…—£EÛ#qVyO;õ#,‹Ž&¤U^#,ÛV¿#/ ÁA¿õØ/‹¯°øE·¼òi$©ñжœ•4Šõï•Hù,ù¡ü-„ó³+°Ì[„¾´Ñý VFl/žF%¦D©œ¼Œ @jñT#õ_UðÍS$hd8eb½í¯\%:LÔPþKÔÿw¾º~ß×µ’Ú=ÊoRJƒ¸›¢ñÝÏ]<áøEùÇ©}£Ãv‹#ÜøZé®#/­1RmªÄÆ}.ÚÛ•ˆµ¡¼F¸ñ×~Y#/çË›ï}&G;/kº«7å¼Àȸ칳\Œ‹•è¦*LFHzm€þ¹ðÔ¬¦×ë­*Y·^ŒíBå<žP¦Ë°@Mü²¿ ¡G5AsƒÚc Ñj«RsÍM¦óñ™ö¬&®Ü§„ÝqQ=%½‘=Pæ“ö„zt–J6œ^dxñvÓgŒïwHB^ÀíîQ#/´Ðº;œ;‹KÇEIõsyã!`Ôõõ¡ŠÒr6;öp{ëQ³ÕU9U1#01‰QS4h5)+5$ ÏQá­½ÑÆ9³•„¼>ÐfY0ã·nýˆE¥lßì{ä8¬¤ƒŒðÕlZ:¶•{V›*_ô8T50O‘ø~>_ô¯çù«ù.ÞÑœ¸äxô¼`KtymG"­Êk#/‰&³j-‘Ù³Ò¥÷YÐa]¹ïXR»‹ü*Š­Ô,Â$îÐéï«3Q¯GeR;tªá¸ò]>§óêåm§tNxPI_ñ:w‡ÞMgð9éy›ã9Ëƈ+²¬þ7=iÛü®ü˜øô<õÑŒž1é!»ŠÏ…#5ÇÛÁ1âEÙ㓶N¥Zw¾mA„¤ßar•š¡‹“;<邺ß2 !£ƒòŽ(ƒÜO~gÆ“µ¨ãX™ž;“0â !˜sG;Ì)¯`¿ëÎáõ·äûÛ§¶w÷\Ñò‡#/s%yOnËöpȇmdE‡,0;‘%°ü þc-{‰éÄñ¯U•3ì¥G¡ê«ƒ~£ßs‡†|m΋ŠæÜfûËOÁ5qow\;>Ã1Ê „këÃþª…ãéÒc}_Xó‚ÒLÃ:nWWwgºŽòÓËÙL:V€Ï›Èk©û¹ò ãÉ{Þ©­q:n³={r§¨³7 \;=¸ÝÐT ̈†P1‚ëÀó°¡¼ŠØˆƒ”Q#,("¹³0c¹Õ’Ü^7Rá@ãÌ„û¨J€ œPwAßåSŠkwÓûÕ^¦öElUNÙ ÂBïxF’sd4ó(ä†àV¶*r.¦ÙÕñ¼ægÝ]zB‚eÑ® ¡”ËØY˜.¢¬Oš©qªzyî­ó™à°dÈh›µý'¬Ì¬>´Siá(¦a¬b`îñ&@@ó rQäyW:ªÐ¤ðòÈ5Ü’¶e2W²&.ž¢ôÖÖŠcfJ3,xÎÏ~º?Å À<’4˜#ˆº€ÃYXa¡ET€0Á††±†ƒP‹J›®·£A¯ 1ÒQLç{8Š™#,p}郛!‰§¬¹à^^©~c^ÝÄé¸t'¯ÛE³{(,$’ö±!ÉaËmª©®¢a«Tbßj;[—!¼êçtvK£×.}Ú¿‡[µwôÂêì}½ý˜Æ­íøΓöj×CYËé§Ûÿ]¥Ú4Ýß¼]…€ã×M¡Cì7´‡mÊ;Š¨®ÈÕSxšŠl³ëd¼ FnË`((YM" â]•VÓŒýA&LJà/Þ•u¶î[‰5RÕýÏúŸÐø·ÄÍe,æo•Úo-ŠÙ]cU!%¤ª%„ƒòþÇT÷´¯±N!é!Q«»nÏ"¼î ‰¿½þÀz`ÉçÏm̦Ñ6“~¬IÁ| ú0‰„! +¬(ÏÚïyr.z“y ¶KK™cDw}’QµÄáÜ쨑¶Ò&¬;,„ŽCÂøb¶Ùº¼ò±EŽœ ¯\(°B,B&ðÍvȆšÔIg1G¼ÖŽ¦à&‚6Ô)ôàÀ„ÅQ˜Iã„Û'72…ÊYÄŽ{¯oãÚ믉|]T-4d¥_¤±ï.™ 01˳³¥¥­˜vyh¦ztÛ,¾@z¬”Àl qŽLBØ3vÛ ›zÍtj‚ZÙ»ø¡EYß•°ë¹«/¯5­NzʺáŽ.éÔ£)™ömk{U´i;ÊQiL<4êh±Ç6Ïqcã×WPr·Ç–ÎûÌœ"#ÓmÛû!wh”Ú^ÆŽ¼ì\¹Äa±ð[Y·¡èNZ)©lxÒ4S ^ÁÏôds>!ñà4‘“„ôî úÐÏÌb]n&ÆCÂF2îgÈ47„ë—(ÛÝçïØe×¼4,J'j=f)c òº¨MÇ8Mý|9eÝážÝwCF $‰dªIk6l~¹zôÉ«ŠRï¬{!ñ6òR`Šj‚Ó¼'ŒD˜!™½Ô22Þ$.¦3 HQ^‹5#y…ÀÆq3šÓ©²Ä)k°y ñÃzÅ,½|c¨FÄÀ‡»ùwu  ø;#/|4Ö >€·8HkÒÝ¡ì¯9Ç\x:GÕ”jì+¼Ü—7ÙG"&È÷(p³‰éz½cÔ&¦Ç¡  §q¨¡9#s oØë¹s2,©Úm#/Œha›X}ØÀÔƒà’9oVõqëÊwx„¹4ž„z/sÊâÆ9L6mt^”üJ†–$9^Æì’s¨ bˆ;xb\ðeÛþ»÷¨¡Rw»êXê-¾HÞˆ/‹™˜S¨dƒÄå @3‡Ã§ÉÀiº¶ø¯fï׃>çÞòÐOoªq›Âc-“ ,#/MÖ,û~ˆ÷Q¶Ã‰ 6‡ÔiØN<Ò¦2 ‘1ÃêŒÙ´×½d$è„ nyJ¦ÜD¦Î÷{Z$æ°`’ L¹}îšÑ\]Þ/bê`ôØȉÃÞ(‡¸Ü¤&‡QD^÷"àš@g0Gƒhj÷{0e! \(ÊBˆgüÿ@â= IMÊ’ˆÓÆmu±)¤H‘HvŠ›@×xdÙ>d¬j;ÕÉ£‡èÒ`DˆCáÁÉ¡ÃæK-„!™fBAG 1–i¡ÇØLái:àÙ6î/bŠ-jÍ~¢˜`3–3)ÝàJcXŠ¿Ÿ¡Ctˆ3(HÔbè0#,Œ] ¤;•x8Î!=–ÐÖü¦©áäf#5E!SNÙ9æ}ÿ^Ìô1¬¶˜³Ìð#5 !Ñøê`v#/s‘ 3ë©n%%=À{#:ŒŠãžÚ1@ˆ9s(ã ÍSCg³U¡@×,l¸Kd\²SU3Œ¬X7Š12âóæ›àðVp¦ne.S`a‹2=Í‚!ñ{dk2¢ÎÇFzæ9.þ—è„Ð¥aO%PÈ·LÃ#5˜Šd@g‰HzNcƒ”p›˜¬äd#Å:úŒ7¥p)¯¯Û%­ìŒæl9æÀŒ{^ðÂŽº2™–3^„¹´Ž2l#/¡F×q[–*.IÔe©RPY.ûsÙì¡Ý>¡­½‚Åžìcm¶ª]ꮪÚ³Ê]ªªª­yüîv$:†ìWÓáÖ—.DÑES1ÃÀ;Æ|¾8)›Ä5Žs¡åZNòcú¸¾„ʹ>Û žˆ˜CnÆŠdm#5ÆëU$5³Ñ3:g²¬’lf…-Ër%a=¥Š‚MXȵ‘À ÎF%F#, q.&gEÓ;-Ùê(ÊjÌ;2a!l†jŠof÷–rBgHÇ"-3$Ç(Øñ©ý° ®z}&Žž[†úíÛiu®&yüÍÅ‹±]ûDÿÖ„ íçÑ>¶ÍŒë‡ÿ:?ÛA£É!Ú=¯šæ»û0|x®Jü"©‹"¬VEø ÿÚ–,KËI‹NwïÝ]ì#/¤f‚…¤¡îòØ^zîú¸(Ö>%Â÷.X`Á**,F"”Y*–Áô( BQËú^‚‡±ª(h”ö\Š€!œ€˜:.m6#Ÿ9 ¢Ã£Ç¾0È?ÉÃýìÿŒüŪÇý?ôì I©¦5¸ô}Ð* °}ªùzvÛgêç³k³)4”ÕÚ·óճdz³ÑÞ=ÉÝJHlü=-ï)¹#,öiÏ &ýjR“Q²ÚdÛ) M¼ªŠ"HƒAHN QÏlÆ€9J·Ù\‘€Äš±iêüÓFFMlZ)rà3íþO:·Žû9qÛ¹xÀ ¬”“Ô.^Š<,û~ä„‘.ÄT¡¨ˆ4¢=Û('ïk©{¬r²5ì{ìUçýe\s´Œa©½‡‹âÒR|“ô÷ " ÌÊ%Œ A´& ¨üs=$ŠOÂ}òå4Ó#,ŒT²‚f®ªD@7)Ø @;ÐSÙ(hÀBDÈàªÀwûõŠ™—ÔsÒ¥ÂIäÅçy°Ìk1EAPp‰V ±±ŒEõÊ€Ù?AÆ&ŒF71ýí•FèkÙÜp‡”¬LhñÇãcí M`¡©³|„{L‰ÈªM°~eŠh•:üŠBÐH #,=fG@–ï§Ù 2cSàuQhbªÛÇXXÔP3–2Ï[ jFO#, kV–æ[†íû¬þtGÉ€+¦@`àÐ@ $EðÒû¦.ôÂ(A0 $ù'!:É÷ÅaDD$E"âD€W‡È.)åÅ$õ[u·[O.Þåáí×æîÓ'Ž;tUÏÕ©•¶¸ñIlNµƒXk#5iB Ð L”€¥BÉ‘6Sü¡þnW,jw^K{"õoK)%4[Þݼz­ÍìŠö\¹175ÒKË»–5Ç÷žkÇ.‘Ά74••Ýbå>¹ÛÊt»ëåk&±OªR*–‡x ‚hDÀÞ¿¤â32FÂRbkËÍ«ùðmø`\ ˆ§°˜¡q3þ‰K`Z6ôYûÈEEb±ê?)È'²×ð÷OçÈvû+“E’c©Bu‰Q¬C²æ¡È›0åˆÆÑJÒEj+”…‹œjNIA˜,¼íУž¬Ú3œú­´ÌÚZóà$`8Àãºr$ŠšR³¸®ºõU¿ÁÛ‚Ä"ª€qQàvÐ DŒd‰"áF,ŽFt#ÏÛ³–ëUH¯ñA1&öì¹äO ÇÓƒ‘Í_Jµ¼ '‚”àe#ÎTæ0¡É® \;Ò’hEd$rH”JÓntBt›)¥…%A€~,D ˆÇ®i¿‹u.œ0ðZ‡]Æ]Ámr85Ù2/â6ð݃ȓÞ8A4ÕÁRa#5î\K!¥Ž“ÏÁ1í#/#/¦¬8ˆÚ UƒµÞ^Ø!%ÔW¸/ØNÍôòý/Éus@øÄT{0îï徨å(´­õo÷ŸöÉ»nj좈AѳLË—eÌ!¡²ƒÉ™é}gÛ—¯è(Œ!EBŠ”RuvqÜœNå”rA5OM&t¾ˆ#,°‹(´3}ÒD~@ÆÌÉ ÓBéTáØ"jÓÌ¢ê–,è'žI×—Qm¡‘ 9§ö4º¬R¾þsîÒåÚfnKšÙc„@wxîÇumüþ>gaü,ÙeTJ$hªdTwÀ›ƒÀi¨Ý …Ñó #/£m±ªÅÕFEJ$¶*¦¥ZÌ…*’¥ª-’ՆʊÍšµ*Ø‚ˆúN ' òœmôÊ“”8lñ|‘a¨2 ȨœüÅ(VÑ#,@ ôý[Yœ½Lo’§…ˆp†ÚBØßì¸ðÊT`3#/ ±UÖ$ÌŒi(ô-ì;ѱ#,%• öÀÁX8±e:b=s˜z¬#/|÷U_… ÆØðGÕšFLöM6Ž˜Ë7L(âÃsCIFE h ˜6ZEWÉZ£9‰2銯·ëÚ¶D_nõ@V@Û´”ÑSc :³—hg=é9Ò­A‘m*]%]%¤#,”öÜ¿§³Á;ÈÀs ¤D*¨€;6„OÛ¼à<û6·Þ¯¼µd±ŠÍšÌªûÔáª*Jekr®Y+–»JfÅ“E¨¯ÆµÍÕãt-q+å*øÉ+8˜(n‹#, @AÈï]ç}z>Ž±µ¶úŽÿv[Êi£t´‡ü .7|^®­ ëz¤‡*ôù,‡²Ä‚$‡ïN"“Þ}¨ˆ•v>Å:ÿÙ»W¯Ëöýœßßþ6Ú˜9!Žuš.$@„ Îÿ2ü[p˜“,)µŠ’Й@îeî½*„?K ‘#5)Q`¢+åT:¶«n;N9XÉÖhæÐ)Qÿ\X/ç$&ÏÃIeTù¿öiª'T ?‚ï“Å:›x§¬1#/o / (gÂT¿«{ˆhbn#/´bDÖgdç®A²²c¨DH¥Ó¹2l`›zÝž‚ôaWõ\Ü0ÃÚ‚ÿ„Dvvu‘dC!«çq †ˆY‹ð:°°@¨i­ŒÅ¢6ÚÆA¸¿U#/¹‹o{dÖöˆä€¶úxÒ$ U 6$cL¹Ç¬zsE#5PþÇ›ç36pÅBAtʼn²¼–¶ÈÊâaDÜpÖò±ƒ@™ª‰®ËoÑO "¬ $(¾â’¢¡ëñ£¹T;5<€÷Òž1gN\Þ€ÝùÑùØÜ„Ê#ÅÐ~R›…BÖˆ)ª¢‚±eÄb]Vž¿·©æAHŒŠz‚¨¢$¨‚ #5DH ²xü‰2#,¦B†1X#,šd==ävߟsƒMjX3ù vNˆ#5Å÷QHFÅO~Úms`j#/6À#¡}@ô±d#, ² ”`†|ÁÃë²dèììõSö¿¿åŒdoß(ßž$ÛPîÂÕÛ8º“„‚"‚Ö[÷P–O|RMamC²¬. ý™³ãsg£B÷ÄL¤ø¼Ì’ù§ŸƒeZmr´¾#ÈbÒ¤GHJò8,öÒÿG‚tŒ>£Êâ÷òˆã4g¦#xVcmÖ¿[Dõ£DøL.z¦ ò­`tx~{SsÞ{.ž7Ö;g€Öœž×Ø<‘Ô²öýZFà[ÈQ0˜I»ñ~1Ï^zí…öÉT<Œ-ÀƒÌÁ`¡O¡dΙâXÈÇ×Û²X-SdéÒc(‚ˆ: ¿ÅçMÒûrw®ýGÞu£V‡ÏlþèZn uºc:·¼ü¸˜K‡­Ñ=ç–VuAÚ¨ÓFå§j–×J³5C¡!™œ°Ä+ÆB¯Ë¬1¦¶éO;îåò±#5<>?f×ëË»¿¬щ\^6&‰3Xi[²«Œ«}š^šèÅi°¥¾8Ž 66 `ÚŽÅÌ„G¬ê;8¡ÏÅ{Ôò-75¥­ hZšµ]ØzÑä¿®ÍZ[[»Š’'Šã,͵&æfñ¹«Ïf@ J0b¡cŠè©ª&hìÏ ‘‡äþ66mƒMž‹‹÷0äÞx®C¶×Ü"Ó±‚àÎo)žªÐb/ÇòrêïÞ™— /Æfï_#,À‡`À#¦3¾Fk‡¡£ ªk FÇÀf iœÂÉ“õµÂX“ ©,KíÀ/@÷lgèpÙ½œv7Â9ì¢isÙj.uäñC˜èÍqѤ÷†Fa"Ê íL(ËÂ8Aß(2p5S¯(SMUJ,b1d;vó%ÕD%&~×Ô„ÂÈ¢Ò)qæåÝ=DZ öí¾CDA‚F`˜õI=h§–}ïjá#/ÌPðŒwßàL!!“±s‘–DÊÆï˜øéÖÇ‹1;-°à9#,rF¾TÍœ îCGç³ðÿ‘ïxüÅM}`z| jFB‡*)ZP‡ÔÐ|*¦¤o/FGƒHqB:l×N0$—=HDégõ3¿vkï¼²wÁLÕ ÀØqdæõý[” 2!§}›Œc+äv@“¯ÝÚV»„Mþ§AçF6(ç,‘O#/óëÅ©š¦µ¼Úæ)dR›%E®–ìÕÔ³DÎíµuKk»ñ¬æëºë^/àxÞLj9bð¢Ô²! M¼;K˜ ‚SIyË»‹‡y¿ %„l+[óÞÚ¾Òû·ÊhjFRÔÈ«Q5ýS» ÚÃb4Z9˜œ^PmU¼{¯.³€\^øoúêýß›„žt2‰Dó.ËE#U ‰ßˆ±#€áE0žAªuªÂQÎ- YJÉCÞGB!ß#/ÿœÀï£éÀ>#/Ó'QtˆpòÉ#,#,rÛ#ÉåCª °¦C7;ë˜i’Í=h€÷%[»,9­ŒpQ9¡lGJ©„¢æe†¹újÄ3&šîÞµï@i¥ß±M †+e~Ì+‚âŽÿI%KLžÐ*¯©êdž|vž[ïH'$'ÓÐzSê¢bI"•jnÝ]hÖå»;­ÚêÝ­Ýo#CT’7©!Q4•ª#,#/$&H‚ØYöšJ…n¢B¡‚GA8žúXên%µ(.Ždb$ƒP(a áˆ}h¡–6Ï2`4LT5BÞ†ŠÏÙ£ž°šíÀÞI Žû×è<}O¿*¬-¶¶2<[ýY³ÏiÇ"Ëm±mž¢“Ä„‡V#,¥^¸aëš_» ó#/Í\vÈHPÌÃK#,ÓI:ˆ„RD#C·.#X¤7`q/ÇÈ¢éj¡Ö™Þ"ˆ wbwX‘D#v;¤á¶–·¾ÜÐCdXS à¡Øì449íÑD¼Gð¯»C4šËãz¦wÃëøóo5ìmìxÓ30ᤆ‚ÄZît¶6‰èù]ÇOÿdÅ34Q/¯Ï|r2oD”•²,HÈu¢#/±}gžÙ#òc¦³ÅZ’1ùCª¤Þü%à«Ò‘­5)$6‡߀£nÙü!û4ZÊ»I e@¯¹Ì\\6†ëNF¶Èn…$ £äµ)φ»pj²®¥J~Õ³rçÁÓÄÆ6~~–»3ÐС‚׎¨hãÒè„P®s¦úäÃ… jþÊŒ¨4ÌG9û(!¯EUCàì†3Ç7¨ÀÃ7n ­ÃA ´¼Ê/N6Aš ¨Q¸]\è|ò¡ B)L\Âaùƒa°{yÀ…Îl§²j Ð-" ê„„¹†¢Te…,‘9¿ÑÏ[²•üñ¡Ë3äCH&%•V «YAìU*#,…EV Òõ•ªœ$:Ä’ÙAÌ»±ˆF•$*$,„#2¥\c Ã3ØÒÖ“=Ì<šÍ¨Ül÷–ª3¢P A¾50tÖ,-(¸«jÙ‰€I0Ì‹#,Ûo)MD2› l²¶¾F#55`êR“®W¥GŸû'V/¾y”•Ýe•ë‰o¶”Ë‹$…;‹ÖT2‰±¤.; ººP– ã‘O”,HéÆÈ…EÙúDk-ö6™›PPrÌQ'äHéÅ´Íáµ^œSÜ‚Æ}“̶I†MK¹ue% ¼#/OwQÄö9oÌ’þ$áJ•‚ðÌ@ 9:Àq¶i#,,óF(ÐÎ$¡è/ãíÎd°À±~F6óññö÷#ìñâöšpoKž%EýKâF ©T+n‘„ã÷tæN»ô"s-qE’(¡—Yëï?µ ’B+!)ÐDè¥l>Ÿ¯W}ö†&ìÏ™kÖ2¥ž/Ë;Iëï3Ôz¨ñß…šjwHeSR‚Ž»Áp–0úžÛÉ{Óóõˆà¦&ƒìÔq¹áãøÇéˆ"ƒTIÙá„[\“Q êbçD BÍØNKœQPa0Nmj–pvT—sÖ#Þn#/ƒ~s_áò«{‡´`øæsp«í#,öþ³±…*/Z2)MÓzÕw0œâþÍÆñdoéO*TWäð4Ëõã8Ôîñ:Õ%ì(»ÕXÒrª°5ÁŸçgøY3ÒBnc1o|p#/7Ò[sQ¡¦!A9©«.Ë%Zo»-ïÜwJ,i¬#5#,U@W@t`¯?)@M†5B¨É2KäàÈ Ú'2/Z¤K@‘KÀ¹:EÊ ÈÈ –Æ#54ð ITpÇh8ÑÙœ¶ÏO&“‚ÅWMÊ8ZÂó\‰ô˜³a¦,ûŒ…aÆßé#/¶RÙÌOÊKl=ô—a<VN-ÛÅ¿IÍ+pÂ5A´ÐI§Ã$ñ ÖFh>àÕk;5åy¤2z/Ìm”„†Á5áÄÁ›‡±ÛQvb³ûÊ¢'G0Ð c#, Ŧϗ³¡;Ñõí4¶» A6e0!Šˆ¨4‹æ´¤ÏÇ¥ª.ƃ&ÆŽ%Ì”"Ùn±¤3M²IÄ#5i£I#/ #5 E4ðÒãc=íõ[&hˆ„¢ƒö³&úA…Y©b” ‘ ˆÇ@¸Ž#5 €ÞZÂãˆ}d “@¬ì‘¿ih`û^¿6ó€wn§§à™É§U>Õ0G©{`H‚@‹ ŽGYn#,5ïÑÓ«®Mc›=&Ø1¦Æ€wNÿGG"ÿa樌^oÊàq)8÷ä?L¹`—ÞOóAM ’g’©çÙdÿwæÈ!ÒB*B"‰sºvYƉè í­¿’Ðl‹6-oȹžunIKmÛ¯¹jª6Ô„‚ÿ`E´U´E$A¢ #5—iôê÷§¼£#,zˆÈ‘|ëî:¯iÏCÜ$©[¢X7ºz°îЀm…” T“íæu¦Vzž³äqHDî!2@‘†H%2RkHS$Ì–b“lZL´¥ÕÓ2¶˜dŠ6šT!’š#0)6IJÌ‘¯µÛ¦&Mi4h–R›Y¡S)™#0(Ð#/©‰I¡ÙÝD*hR$ŠIIbb Q’PZ4M’’Á(EŠiKQ²(š šFe‘¦£1!¥„”QŠ³Mgz»ö•;À8¦,ú0Ì9.ÛœX&Aò~u=JÎÙŸ·ôf̈ÿx¡=;p%­S*F9.¾ó•e† ì:¡§ºy®ƒ~)W¾/×ÝtÊe#/´îÕ¤•¬D!$Åt2ÒXï-œq1ñ ÐzŸM“Fýìß…Âöï7€y9,碓³¾åì¹·[BJ²G6”þ‰kÒË¥gßÏø¦dþ$¬|>˜/»}!‹…aº« ªhÀ\³#y,P!pÄ ^F¢ü#, @9/rÆcPÕ,ÒSiZMa4•¤¬ËL$$,qpxÖ}miåTx0ƒQÊ™Lø1Ç?büÄχŠ­ F=DØ„}ö“Dˆ•õêÚM³ ! ZÅ¥=ÙþÚäcõÖ;ÛÔµŽÅèõ}"DcqøC‘–Á[oZ}>·rþd‡/F› …Ùt”½*› Jè^á€faúþ‹²H1Õ‹õ‘½ZŽ 1d~æí“{©?å¼WÙÝ­Ûµ-ѵ´cH%µ“#V iô8$Ýiš m¿ ÒöÛMó“(á©ã#´Ê%j7®N.ø""àï3]{ãŽéDÆ°¢›Aa¿rP´OezA¹ÁÞi‚ìÆBÝ|J{Lš feðv^`ÙGäÌÜ$°Y¶ÜKß#5<öÒ@Ø#´ê@íÜeˆ¡ú½’ö?o-tž¼;î¿¢¼Í”‘@†kübØ<<õµc/Ñ´À5kìèrŸÏèÐ!V ÒiϸB½†vW5ƒI²¿5ç†ã-†?mg:eY| ±:YPìžì²ªôS||S%JÓÄ©=ý~õÊŽVpj@¨{% ܬ!¹Ï‘Ð3¯ ôœ²[ÓïäY ¸Y#,7\F0–rÑsÇ'B;Òmˤ7#5ˆÁñÞÉ ,>!C ÄÐ$ÃbaÌÃÔ#/Ôÿ¡¨Í}¤Cog‡ŸZ’ñI–ÓìvƤPû`M2!äûFˆèÖ Ó…-Ì­ÚÆÓÊ;Z#…ê¨Xe$|2’}ÙåÞùÍÖ?£V®lÛfI”Ô†ì)ÔÛÈïZºQW¬Æo a31þMf•.¥2^BåÒy51Á„-,.K¯W”£ÔZ1ìf¬Þž1`9Û©š‰”—ñ¢LKКB$ÎÔm¼JÝ µ6üt’AIÒÊΉÂæ>ùÛw•wws!šYÁŒL\.iäÁ Tø0R0JtÉžçOK7¢©á?óíÄÁz¶¹~#š¢ŒË­;"¥àFá`ÜådçάËì–Ã#5ƒC0jvœÖ ÚcTêX~Ôê¸Ü·1Roø‹g„r¤Øóˆ3%ÃÊ LBì 2´>t#/<;;, ú7žx¦dºCäÓ@Öp5‹¨íUƈڜ‘«y(aÌ\rm†–Âz¡W««2ùZBA¢ ¦³Wo0áë”àÛq’52v¾Ø³/Á§Áuy¾—h ûº;v[Û$ç3¨â3€ËÒÇu,­úfwÕØcbÔRd,vrhÀ L»_;l\;þNq#,X(‚‡cÆáŠ(ŠÕHeûÁ5-1”êqDW;4Xa&(Œ~]çªO÷Ž‡øÞu’ÛŽÇLêÀ¼øãs¸’xíÇ)Þns/x.ï>YÌ㦫 ¤’kL:‡C›Ø‘2Ž6I7= ¼c-l‚vÛ…É%ÅÞ“¥¢*êoNÐdÝΦ—ØÆëD@³ß™9;6.Än%à‘ÓÞÇG=²öâaÝðÜì¿Ün æˇbsÎéÎ'\µŽøRž¦Î]j)XÎÌqMíC“´#÷å¼—qê.gxÕßÃ7­0ln6Ôi•Â¸Ýq-n#ll#/j&¡Ü(]èºÇ&M–7K}KJÆèôRrA‘ƒaÎ`î¦é‹"Œm¾86v¤cpÎLc+ÑÆíÙ\»•ÓZÇsl£ÔÅ\#/e¬S!(òBƒfækKZï½´k**)šjÝ”ˆJfGºVXnÁC#ŸBÞ(BÛ‚ iÐ#5Ñ'Ks­ Á\½ Ï•1GQì±mP¹rIY¨M†1C8ÎÌöC´ù†ÇG2>TP™‘³.e†Ô[ê‡FPaNü+imðg`ÀŠrÐ5×U/V@ÅCd&Æ^‚,ÆÓI53S¥¤ ÓQ‰v9‡ Ta%3 8][ßPJc´$dÂ"méÙKJ¢P‘ê´TÕºùØÔ3‘É 3ø1z®C³mΕ­·Ìõ’`Lƒo´ÚwB\G,A(©Y+”;ßtÓcI¬7rX<ð5iaNF:tÞåt4 ÍËËÕ6ÂXK›e:G #5&$Y<Ú k‰ÈCEñçÃeá—Èã9€·zâòñ³Ñú‰ƒiÈDS‚QHn!¾¬s(a–M…d&°U2LŒTBš@»©O©6f¶RêT–Q§v(bÈ°2’P¹•40òd£zݘphU°-€`ªJº™8T-!–ój¬ YlY)7ªP1šË0`aV‚e©6IO$¤a–`J£€^¡ÓAX6öôÒŒM‡ Œ+ã¥dLÙR’Ù²[,¼Ô±›2evgrx³VE0`õQÇhc¶ögYföΔ:™]ë‰Ö©—ZRðz ‹LiM+ÙÂ3„‰‰w-Í ãÔ/®Ñ‰Ä!+)’e#,òôö ñ8à:H“a ë„<>VàÔ-gnK`lErùÔö×¥ó}™ÄŽí`G½+½è…PèP}R9‚AsI¦Ðî±¢`TiBƒfèÖ9³h'VÙåâ˜m‘#,@ ‡ ”ΆEÁ¶ÁÝÜÚ3#/¦Læ3ÈdçJ×¼ÑLMmH) #/¦á#H. ÑUV8(|WAÈ]G’DX°j(L Œ°:ˆÄõñÉ#,ß±ouš)‚&ßZ7-½m^¶¯%â-OnÛÒL6C„CŒŽÛ…o4ÌXn74§ž"£¯˜Ùä/ë¼ô|…‘æ#-¤J:?åike$‘#3 œ9ð3 £·}hELȆŒ÷ Ç ˜pqD` ¡‡­#/ŒAĶ‘@Š÷ǘ†ØhñÛ²M ÐQ£f&—¬GcrÕV ÒÅÚ•HˆurŽ˜U1Êò.IÀ8ɽÌ0(vî)7†Fk6Â&Â¥$,Ù3£™‰HB*Ùˆ@…À†Çc‘¾Œ8pv¨Ú‚‚x±£Iè,Òóa½Íf‘л/Y‘Øï%Óz`X†‰FÐÁÍuC­T¡k@º ,Ä׫zè6‚/#5úì”&i°ÜŒ`èpWî¬5M‡4f3•‰cžm,OqÞÁ™º5¡·#;pd0Ãr›\A¹Ë„á­Ê¡‰ªJ,&0  "BÁþÆ @‡ø¶”ôBE„M )˜»‰h °RÂìJU#5#/†ŸÞñWòx¿«Õ;€ÚüwV춌Œ‚²­M!¸>cûÌ‚N´TzÊqˆÒ—B«øÀï•#A¢¨³°µ¡²Ó!!ÜApVà^È;U îËKùEòù‡ÓÜÌj4ÈÉëÇÖ31®[>”çq9"ë_óADpX³[dú¡Ç.¦Ð‹¤ ih§¤#5tÄݺ…±RÍŽAiÅÎdÎ-+X¸#‘ƒ†Ûd¦¦k`(o Í[FFK¦ Œ#5ÚïMݧ`b̸«;¡b¨mMšv*†|.ã©´¶Œ÷À8›ˆKœd¹B‘$1ÜýÚСU{nÝ:Çk–emúi-m&ó@„U Œ‘›ïò‚PØ8„C‹ —§®‰€—#/yPåJ–,‚Ъ1Ã:z÷ E¸ª[géý?P±;÷ÇÊq:‡—à ²¯ÒE]¿vÓM+oßkè¼l¼%ɦcI]wfsu‰QmÒþÑy©ü÷#mg¢}Ƨ¦p¡Ô²¤g,rHȳÚÐ"Q#/Fžãò±2Ð>Uñø”Ýq Bá0®#/7>ÓGÞ‡ˆÈa$¶ÅRQ´¦Ú+FÕ%E-35PhÛEŒ#/ €I#, U¯ø&ïaážY‚_h –êSß·«½qLCà]NØ*~M¦½ÂžéØ˦Ÿ¹ç|ÞÉ}9š5v ²KÂÆÙ‰#Mè h$ÝFY•D…¤Ò ro!¬¨{§ŸM@H Šqö:-'„Íe¬ #ÎfÐu”/V*(~ÆRH)#,ÔÉRZ üä;¶#,÷v6hñçÑS¬Xd&A·ßUÆh*1’Ó"F¿#tJ²4&Ði©²#,\ŠÒ%¢ Ä«ÅmXÔ¸óD1–!p„HO“š3pÃLä\ÅÍeº&šEKÀ1€‰dÀfwùÏGÁðbvúÊ#/‚›”]! BÑjÅ l].t§Øè$ Ýq.´ýÄ[YD*"Ix¢ü,†ØŠä(£¹œFXÿB`>šùdé0òð°A |ûÅA¼$&œ ?mFƆ´Â~Ø#¥Ço´] 35o]ÈŠÈæºü!®Ï½ý ñk@nmpF_ol==1–„ɶW¤3ˆyQ„«Kc+ChãÚ la¦oZ4´cX±EzŸÝì°ó:ìҙǥ éVP½´[MÚé×3.º˜)d«Cƒaç¬074ê¥#53©#3“Îðãžfi™ª¿Â&©¨ý;dÎѱÎù!ÝÙÇ6Ü=ˆ.Ù¢“•@°.I›9Ä`5†#/#`†k”¢eL¬;C¬€Ú ÝÒ–S3:g"K`¹ AÍ=:j4Y%¸ºv~Øg3ˆj ‚qÚv†Ì6K:A‰F%‘–XÄ)¥rÔ)ÀÁ\Ød‰ #,ÅÌT°Ò¸0¦L1 ¦ ™C#/‹  †9‡Z$#5YEÇ„03#/Žnh/Ë[棈 ”¸?ã RD^„NFÝáeÓ×Ýë± ³Ùeýjæ°pH±]” £ý'ófn ?Q?T¡pü¡Î °Ÿ»â HÐ5à$éLò°]YG=#,‘Z@ùýPÍ)¥^î d#,ÓNqN˜U4QUUU#5¨4ïFßÛH²[h­’­bÕ¤«Uùµ”Û˜Æ~+ëÄÈ’8}üϸïd­¾h‹s#5}Ë#5ó”‹PꦊüOô`8ã¿›Ü:ubÅr¿½†âa©k²wŽËGº#/Š«d‹‘A“‡,ë§ q¤Ó2enjêˆMªt”’ÂÕÊu…®iubãê;ÞÚÊEF1¯p1¶×Ðèà\PàÄiÊtó©·¡ÁªR ‰1œ¤¥Ö;KÌ4›y¦óYÛ¢ÜÌZ’ž‡¾:Ý­t Ù&)§Už pQßPYbÞÈ…13±³Ë5B"òQ(ÜD е±fKñ-g)\áÎ:;X´3ßääáœBàQ‘2qño#"ì°˜±J|Å!¢ž†”ֵ̕+â;vÕ™§{o(Q4Þø½,m½MŒ/ˆêtQõ6ûe)Ég‰žL˜â}¶`òdCRŽ MNä2Jò¢ƒc`”VwvÍfÜË—\”ä† ¾,,Cˆî— "( ÌÅ9xokeAE¦ #,ƒPJ`Æ ˜¬FŒÍ2<Âå݈ Jte.%¡qžûæÅZóȹ4Rë&¶nÈĉ@K™…œBèÒ…8€Ð…úÙ¦#5:z¶ˆŒ©zÙŸÒ55 ø]ªîÝ’m[}Fù.Kµ³awsK·\f©Î·³s¦]ÎÉÆN»Œ¶ò‰ªéh6ëWi+r»®Ýݤů;¥5;Ow^o5¼jB×-¹­ÚTj“Ch*‘Êëi#/#/ii"Vª†…#,nÛ^62šÓI I‘6V6ÆÔÔ¢™®¥®•¥šX‰¬1b«"CÑå´ÙÀ0Æ fl#/’+[IQY’$AG‰?I«Ñ{%´"Й ö1‰±Œ˜‡}’Ã`¤¨œNM£.Ä¢-"°T†Hl²o‚ób ê;Ï;‰ØL'¬„Ï^‡êaKîZˆYLÃ?y·òb<´@÷Äà#/NíÍtFLJçmz¢×«å¾=›ÏT¯¤Kóéƒy#,ú¨UEÆz,qƒ‚æPî ‡ö¼Ïé’Hð|{†éLûK‚‡8Ú~šêÙL/B`ÁBÑjÔ‚ªÿ~ #5ÃlƒBfh •Z4XRÒ#/BD×d7Q¶Ûfv[MÅ)”a‚Ñû³3ߥ‹}Ù9-ù·XùÄ6kÚP%,jTŽ5\nƒ È3§vŠ'ݬJ¢s\mje2+çÅ@̪3p—¿ zϱ•¹êkÐ#ƒ§l‚Ó r*°+xºg"De“§çvJ9ó“Ýg ë‘t/Ð…ÂÌ(7$ÑtãxŸ§èk¨Ó¡®{ƤØkTcEÚnÍLRY&mÞfè·­Œ‡êøvüc-LªÔ„µrœä¦”Š(–·Ÿ|›[[å­ Þºf²Ò¢Y¦›i›El¤ÕJûKü?ÉÛ_¦Õ_&©¬Óm”µ¾­‘#|)‚D…š– gv¼™J×JƶrÅQm‚”o ÀÄ#/Ôˆ™ÐYÙ5ÜP£ÕH%A@$E 5Å-%&Õñiº0”jIk)¶­6ͦV̵šSE*KbÃ#ELª•±-¥0”PÚl¥2%I›)™´B˜Õ2‰)(¶5&²T•¨5)”Y šJjE(™±%©i²6jɵ4˜,‘T¦IY°•ZPl¥H”$’e’“)3’jdÑK6©¶1ª&Vƒ"FÔ”Ô¦Û*šÖ¥šL–4¦MJUK*Ù*Õ|ªµÝ­²²ÛM¤³i)*ùM­®•6mT¦Ûi*­«á«Í–¢«ÌÕcZÑl¦ØßZªåj‘5jUP‘CIF9Ÿ/HpnÏÀ–NÝoŽ†MYÛH÷e³{°Ù2í›0ñÑcBÝë'~«ÅÈ㸫 ©½»hYá$©=!â^#/)ÂÈÞD‡u/÷€1ؾèž_n'¢£²=PÂÇk´4#5.Ã,=ü½,k³g]¸bÙ 3meÌzË£»>™2Aó1ŽË`yd„E,Žàuõ¥¯¡}8þMCFßl¬ët+÷ŒYE„ Ã¥Q¦(fI QÖšÃM$DD‚jXªÅU#/ û#,;£Ü{dkù‹X'©Üè,š¡é5vî‡K°6Á0ùå&¹Ó’ v¢ª~#,© åžÅåûÐÀƒ1›°ý"|u‚E. y!ŒJ’Š­ÝÓ¯ÀºÆ2âCÛstæ¦!\ \£:q±1®"µàv_´• åïB*75¶0"t^+òA¦#/tøySyjzM‡I!Š“»4ê#ñôÇåo{ºòœÆa^E\^i­éY×O<íF‡ëu¼]ðи±FµÝ qWX¼4×Ñ沶ð·eÍ’¶½ºQW]ƒÙkÏc“B7kéR“ŽæÇ1…qPë6Mù«!ÎÿÌ]"LÅÃþŽHe™EÆZP+®ŒHŒ–Ú¹ÛéÆýƒ’cZPPRJA7+¯è—'±Š+ÚN…7HI!„ØòX;A¡–5g—ZÞÄXí=òª4ÍáGÄÔAFM#/½P*‘*0f=EîdÑhduç§ej®C2)Ò¬„BáPª °aAär+ò0€¢Ld^±zî.5£'[šÑ3D#5GÇx?!Ó¥ãQT­9ÖM°)¥hw)¹_cí#PEêzq–§MKCr¦ UK†QË4`ÅŽŽL·~%cÞPt#"#,ȆÈHÈýËiTÐëlñ¬ZŤŊ ”a&B[e¯Õ›2FŽìe$qJLØù ¯ÅÞöÌh”È#/"#,#¤Òløb#5&’G­*ä‹áÌTcÄÐhŸ,ô­†Þ-:Õ uåÕkQ5; 墬lí4QYTQ˜×¶˜Plv;¼ò´wÇy#/ÔcSfW<|ò:Òx½‚›PìàÓ·rì·NñA4ÒÀb²’tÁG­ R]Sc#Ng#>Ìðn,•D ´é‰B!²L8 ¡Írº$Š¢Jª¢„IÖ¥ ˆ[J¨ÝØY’k¦ëmGÉm½È¶+jòïY>!S®@‰Œ`F‚eAB¢*\¤–ÙB#µÄÄÌ0€}”Û×–Å׃Æd>É·#€ª1@ð3;õxÎ]Ü©q¦¸@åÝÑ"Zº#4Å–ŠW‹‰·ë_x ,À¥™ùúùùBkdÂ+õµ¢šâÿ!Õ€E‡:“A#/b`5|ܤ€(BÙ1UmµrÆͲÍ%6W]6‰×M5ŠÔj¿‘XŠ,I¶kÚQ­½÷«Ùl©hÄú?ª­#,a#,APÂ"PÆ7À°Î!Bå„îa”ü1NaÖ3÷¬ÝBÓçUk´0+Ø"A¡0¬ðf·×6˜Ä¿&®/†``i4‡ßø` `¢ì3›c°0-¡€*ŸŸÐmÃ#,ŒAV¢ª4JÑàÉg?+ŸUú›4ð;㺣,7–"’IÅ ˆψ¹ª‡×>;vI#,%ÖCh#/ý¹;Ç‘éO«Yöýyñ½Ïí½Ï镯 ­vǺ.øuQ³“‰Ûì!ø«6åF†n²àCw7i¨ÎD=wyG˜¢"»ØT"Ûöqô#¬pvv- @¡Y^F#Kô¼j(Ûh b¯XTe[1nŒX„ š¥ßìöoçÈ:Á2 B?PC¨Šq#/ªeÂÕ؃ÏÑ騱â¯Ó=ì_è0[ öúÄ=CmVKb¶¿Rjµ,®mu›U·Kj£i+¬µ¹ZÚ5²ú°ïFŘ¢‚TD$A¢% !&#,3«=wÞÂîËÑýpAW¹ÁVØÀ¹JPe$À" ê%#59#ª:BaXLÚhcAèÐÚÙw°»5 ÈÅ3a OÖsarz“Í(Ñê É8š£ÊÎ%cþQ:øÁGÁU,!ÜHwÑÞ< 1÷¤µH²ØR**+àvúÐÜQø÷hc10*Ä5Ã…hÂômXp[,‡šûä€&¡#/ÇŸq‘ãßM¼+1yåÖ~N,HVRª¡¤Àhxü½ü;;R#¨” 8J<ˆ¨R6USK‹Ç^4R †ÃÓ~¼Ÿ}ì_Œþ=!…„P6QúÉÊ&÷-š[­T&–"`åÕ¼Sh ‡ 1³ØW6¼s«¶î‰(Ù5&*RVѵ Ô×Ê[´i­¦•”öWRk%XªQÛ°-î¹@mßß¿p¥Á;#i“ïvÒEÇ€42£tñJ¶éÆ­…;ˆy³ÌoTŠU7ûmiàУ6ˆøêU&$¨gmÍ(¥8¸àðÝ`ÎqDUå‡Äa3œêèHzmW¹"Á(ª ¢ÅQ!Æêˆ#&Rä+YO’@Áa¸è ]æ’ Ø 1G¹wù '¥íí`u’$’LÀýq±ƒƒíõë¿×÷[ÝÅ é¤ÐqØ%³™¿wRh„"…›hÂ)V›¢`¿äøm#/¹›dŽzÈþzÌö‹ž–¶ün´h5õâR—¦È¬‰Cá :'ª¥t›ûŒÂQPnÊv@às’¾7i5$Ÿ{1#,Ø(2š0Ù†A“ ˆ†#/Ü …F%#,>Ìõý¸ñŸf“Õšà0†n(c‚<ù˜1ЫÌÒrÏõ¢#,¨å¤Ñ*M—ÙóTI%FÁÄ8¶Y0z¦$öi…“¾ñ“òÄt¿Š6ÒuuóObˆ{_zišó®˜‚|ºNµÄ&åßMå~hÖˆ´b-"„¡jM$%"’ªm´µ%¢Ú21™¯Ö› 2hJ‹K?q¶¹µ¦eR¥%XÔQM)i6ÓLKfµJÆ›YM-dÖ‰±ØÚPj•£"ËZQ¦U-*kU’)h5†‡æz”#/i„O÷?6“Žìd¶¤"f#€ƒˆ£ÕáücD‚5$AJ ÍZ£j5¨ÚêkZånÍà[2@$dH¸buC»«~H_r«o³¯£[š¹ÃW(ÆMÔ¿Áꄉù’ ² ùË”Íü¬¯¯uV,š”#/¤K>av\öýÙ#,2Ï~ñ¡: ·(Û°»`ˆÜ§.H€w`‰åßþw0âW„Ah€ÔöDáÏMÂzÓŠÙýÄ A2=‹öP•U*P” •¨ßäQ/j[¤(q XO½œ¯"ØÊ<Þ¿ §ðÌ•´Üm×Bƒ$€ÑÕÐ!=L=|î€âª¥Êh"jD£9–8˜'ëÝ•Å¿2Ð33²›–7ü}‚§¨‰Ú½&Œ$ziDk´ç*©°å4ø †õ@<{GÈ#/gA'1#,bjIÄ·Xj‡P3väž<䱬äN Hw0ãÈàlúḆ©ü\£Ï\»(ÍØH±’ƒŒÄ¡ýk<ÆÍœ„!pIª0Zà~¿ÙgÊ!G¹Ëú «÷Çòùi‹|@¡4´²/âçÝü¤û»My–Ôl&žä"Nçký’À½[FYD0uűŒ[ªd“Bd˜bû©e²¶ö¹Ò^^à07 š…ÅsC’»+Ž_°ÞäÂ} ‡±‡±»­S .Ü6‹i@11Å¥²„øf£&K>^&—×m5ŸFá~¬RE ‘AN䥂(Æ#b„ñKw>ïdŸ«6kG´:htt#,á=_ïÝŒ—¡p2€É¼n¬²ÈH‚‚£c¦TÛ=Ò1ˆÈ,¶’2&š,K¨QC£Ou†n–ê–‹4T$Y”²‚`UD)å-SÆ“¢~„˼S.›€(ÐÛ XcQ“¬qÀ-Ô' ùŠ÷ÁˆÌòAydfe@v`b qLqºß m]*H™ªJêä€Jd¹Ý¡-îÁçtõ¨vÁwÄ"Á\Ý++î6-¿KÍyñòåÕ7<“yrBóÎ¥~I#k,Œ'¢½>ÝÍ•E“\‘P3HoVžLÆ¢"3°ÇwkM´×m*o#/¡'EÚÖÆÆÒq8‹¹‹A-ÂH0„¤”z ]á£ïÒÖ ¤,€ÓŒQU¦¦¼ÌœÅ<eÍŸûB'0rwd§ëµ¸Žjá*Çy²K5^P¸Ç @œ3)ÙïcÞ·Ôº¨WŠ…RÅa0ý¸;§ÃaDȢ߅¶•Êoïó£}g%ø×Ã.³Ì¡T ÔåÊBIª¤‹n¼†È[FRPì#·[Ñ$Y íTiãŠ$økÒ¢µùfúÄ/êvAÎW<r²àˆ›®G$ÆbBÅÞì‰LCh~µ–Å…'6ÌA5F#,Öýäˆ7¤¥‰Oß¼(ÀF[$ï&»ÂZJËÜåóÞöcn½ŒBÛÁª?³ja䥅‹J“k.91-”âa¬†x}L®³Q·#/£ìfξž@¶k€jGR‚†‚РˆÙ±¼º]ª…`B@Fì(‰•iR´@HôE(¨„Ážf´#5¤•Àõw”:S §™±tEvoöο±P1uã±Ä5ç鬙kÈb¤ÄD(u’´ÇvËæð9´t` ¿«ØÜxÄD$6!É›UdE:ö`VAA%Z¬KÆö¶‹¸\ˆÙGèˆeêÉp×^Ó•³j‰©Èàýý°Öúü›Ý<‘}]ÜjÄ~ñhóuµ]v›xPšDÛ^ºò¥ƒQZ›JW 6ìB #,Æ„6’% 1‘¡(2¤*TUF¡ (PH}WC™È¢‚Ø÷P;{kTƒ¾ ˆ‹`©º›SU(ª¨€ªûù^§òW{Ä1\*ð&GaWŽ0­ n(šwŸ##57ôx—nïmëĬcºÂ[p™Œ(À#5Óa;@#:÷/2Þ(’µåÎæ“_R(ô€Ç¦9»ZÉ6ÐIN0ŒJlC*šDh) ›Ñ6¸L±"l˜sEg6f%Y¨–Sd WLë ÆžB]å0ìè›È‰Û­«DÈÂHÙ“Ä/òmZhl0Ò#/ós`Ö¤UD7wD 0ÚÄ1l®¤2Ž{TõEOé8 ÚpãÂB@„u"T#,/˜-ÙÖ—77¡çKïîcI©Ûê´Œ#d=^£š‘ix=KZ…ì#/À›'ùõ6á­•F¿sƒLu8š&ÇÀ:hì¡)#,êƒy, ‡¢*]ZRj™¶ÊZ6eLÖ¨ªRµùUù›[ò"W]¶Ú¹±…!(`°¤)’(£Î€‡Oݸcó!Ò<®Yh¹·£j˜_HqÚ#5€¬==Ö³VB¡ïš1NGŽÂ^uç–\T[”žö«öÑäÝYGÞAÏ ŒC#»:8ŒmNçÒãÓYÂÉŸ÷`â/ $–”kR/ë~ªÀÚE–y'áPÉ<Ö»ùf·˜ÀÚ4Ñ$ØÔÙ'½å2‰¡Ž’Êhå‡8á}“n±ªÓl@‹ŒQ:ÉP#5FõQA4ä'^ Ã#5 1ÉW)«¬ï½ºôë1LÅ‹=•_ ²¦))Š•*l#/r(\4JM¦f†AæwôÒþY’Kjé>Æ#/­µø˜þÜ‘cVÏN}M·ø¦<óMÛò#gz8ò!§Þì2vu¬#/eÁ;|jù`³ßÛDF`(ƒj¿ÕD«–™÷yyž#,zÐOIâ¢Û€Qž”`4jû{~Û‡œ^È”˜„ãÞ…ð dÅ(›N©È”ÕúñtHQ|ÑÑ÷&4Í@{R!ÄÇ*›ÑÀ܈7,cŒ —!Ïë`²|èVcSWn;>³<D’×—ê½õÓÖã„nŽ™àO‡d¿`”:üg„3!š¶#ªTÝ%T@÷DgD47:ÍŸvÁ£ Õ^}ó¯rû žŒGœ·1Ç+>ÇiïrC€Â'*¥YC(•9$—š 2idHAˆ½-"g7{´¿=Ù€¡¸/Bï6.®¯W°°³ý_EÞ+ Q!¶yVÑ`¨ÄÀdvÊ—RÚÕžvëÓ½©«lÍ[z­t֯ћSM_©uҕĈàVxâùÈ›ÍFFRàs±Ó$h1jšø$”¯ü_íbÇõ7ñ¶îÒÙè’¤=È?ìî› ƒÇ•™hæžrõ[F*&ƒkã±xŠ©ÄójV°¸²¡#Ê~HRe¬ç­ulLôеd#/0÷ƒ4â…ÅÁ±å­­Io#|Nz>P 4Ç–" ˆ§R7ø†%C2ämê﹄€G¢#`Â#5í‚H_8FHT¤Õ¨,±\ÝÂØJ€ ·vµ×,ÆÝn³Viµ›6ÔÍi’¥™«lËUu[7e4¼\“Jím}R¦bÚÙ`@E9Øèq`@ß: ë÷ÏDéÏÙñ»oUëÖæ÷<˜ÜÔ³ßÏØÒÙ5DzÌ"µäú*‘‹4„ª‡ÎÓ5!ñ>éMI¹ó†3lÂAëõlõš¾…ÒcZ<«ëÑÄ#/›rÄ£I-¥¦‹ý{¨l­>@ ÈÁkQ ²LU‡MFa°õ8½Ö¬ìbE,…” Æ4ú#/Sž¿Õ¹õ©ßW#/6ÞM»J16æ¸ß¸7plëÁð#/ÈâÊÅ_p6h^²oó®Ãnªø‚,ESøëÒ`ØßÕí[¸`”]Ô¶©#5hŽXæUÕ»°¨Dˆ€A¶ÄÂó RF~ÃVø‚Z*îÖÈ3%Ø÷Hk)JòFÛÐlÈ(3™TqMP90yÍEÁšAuög¡å#/­áTCð~”z,^G™"`÷¿=·<â‘I:~ÇÁï4òOZiƒ[9 ‰PÜäÈù}þg›òÙI0IÐFÿˆK÷#tH²À¬í dZvζâŒî0\7 ŠwnòÐ;#/ì8…‹È® Älô Ò¬ÜÖp#/ÇØ\×yܽ÷ù˜Œ"0ð3Ázõ¶ÛñâiK¸™íÚ(ˆ—IˆöÀ²RaDú•VIu }YK=™.!ö»Ò< áàE„Ö0‚È'!ÔeÁÝ)þ5‚›«1ŽÕÜkÂô Ž¡È3oÅ0ƒ? T7å àÜ„Aú tæ„&Øðº4qü`e3bXFËM£Lö›-¿#/ždl‰ß‚…@rMÓÔ±î£?Â27!áSÑ°»SXÇ•‚´ºÛ¬ÐÊR5vûÃÌø Š‡ÇßÊ|7ÓÜR~"Ä@ž €¨‰™ç;§2€^|7Á2ªº€¡êȵx«Qm¶Š¢¶Å¶£jŒQ!FÒ HP4&0»æû_ò__l'¬a€Ä;HÀ‰@?¿¡Á¹U{ ¸ØŽèØtÛO®¶qqFåœÃØ(nao3[²AD†¬Ì¹ë"1è2•Äšž—-¶ä+|±ÇšpAÌŸî#,í¦ž§˜`8óâŒ!o#˜$†Q[4ÆycP!øÖX¦20üÝ¡ðµ æú4ñý_­óU Q¨(¦‡­O^ýÔª›ÍÔ”IÐ(9†<„£ÄÏB€£`0Pž"ÂdvIOè!·ð©#/[IÀÔ£×ÇyÕ3†Ó}„ˆþ3ÍBçÕÜ|Fo«1=ð<6}Õ æeÖŽž˜Òbè T#/°*ãUÊJª’ƒÉïÁo6Í÷M¾¾å®Å]Ò«!²~Ô¡ˆÀˆ’{ÏaM² dp£AlMH?¿Ýî.xS>Cŧ£1îM|,‘¦Ýøòëd50®n>0†3¿hkľEƒÝFo5qIE.8<<4‰fjiªž ‹4ÍéßcÛC½U³5üïÂÙ”.!CF^ž¢2ónN£méEvÏ>†ùa0cc…¦ó±±—½æ¾¦ºèmi`Q00ƒ!’Ÿ€O¸eSiA›Léõ]-ÊÓ#âý%í»ìç/F 8éØ]T(£¾¬I¼¾ Úñƒ¼ç”ý8.0üa­áæy•žExѭퟧfpuꛧ<‘#5òáÃáŒÔ¤–%áq y³+Òž¤ÒœcÅQMBBÈniúÅI¼·Å‚ø¡d8ΓÙ#5ß<†×ÙÀ®Ù0áH:í@i}᤿5K`S™Ó#/$¦S«ø}aêêü“S.=êqP@o’ƒæ "¨ÌˆØZK‹d²¿8("|hUlºCHMœq­À°¦«2£J±¥ Á.å¾VñÒɼm»*®·6²m»ÇI±Z*òêK][r®íÈÌÝ×h®®ifÍÈÙ±²¥¹Â§vÖ’ÚM³l¬Œ#,´…ˆ BAB¨2ìÀl@¤œPK°ú†G ˆ­;ÑȨÛ£Ó)¡ñ¡Jk©ôaùuó÷¾vÖùµ`J•l¾5YpMZÒ”ºÕ»-¶ZóËlþ8¶P¸7Š‹Â6XjbH2@'%ÍÊÍ|my3D¶[kÊÕÑF.>/=òe5ŠÂ) €Ê„Ë!E´Vñ«©•I? íP%±X2”ض-¢1Y•Æ£TmTÍ££EE3F²Ve$ÈÍR Å´Í%±kf¯vè#5$9 ”A´÷ï°¡òÄÅ:þ,€ÉôÖ­{{#/&Õ„ “ky·í_‚ØúW§|vñm#/O:ˆ´OãÅÍ·’r½Š£]³„×VÃÑP"å#,‰H@Œ“¶rñMš*¯É+~&µ\JÚñ[¥ý[v"V)O7]&©ÝÕÓk·i)µ®&Åm£&²Vî®Ò›V•T¯W[KIQ‚”‹MÿÍ!Ä6^Ÿ™ A~’ŒüjIèJU G&0A´É F;JCay8ä X„EV)!­ÛP\7œøµJW#5#/ÅxaNŠ¦èŒ"ïW]0äÂñÕmúŸhP{ö5>Âo>«ãÆO~#5?^‹HÃ)AˆÃðEƒÞ~ÁÖ•84}& ð¸ëmf,FE[ÃôÙTlcUáŒcÓJ€ÐÒÌ­Y… ö2º$šhÁŒŸÇŠ÷ånµ´ÍáöLc,ÇzÈð³†d·øš˜ÛÇ¿aCsb­†á‹»±-PZ—öR#5¥(P ¼!Ûgꮤ¸MŒ;:>‡$Q8duÃ<^ÑwᲩœù½‹§[¢5]ÉÖó™¢mÜY`¾‚[hÆ‚QŸg{«42Š¸Ó-½?¾ãø“¾â ˆ#ö§Ö;ûñáÀ¬föÖãu»`vH©½O*£•ÄQÃ÷žt?º±ë0T‡!‰çÜLì3Kܺn¨E2ñ-Åõ!ó`y†f@<`«ôMmcTm¡-¾º_}µ¯Ï-äŒHÚGüäL¯J&12ˆÈg#,KEdχQlšÕZ5\Õµåuæê½À•ÜX1ü€nËÇ>pD  <ê0?a?C_¡ÏÙXZQ¶AÕ&´×_·y®ùq¢ÚÊV®––0£%îh€Ö ƒBƒKF¡¾@ÁÛXÍ…£ô½šØ‰Pl4$†ƒÚ¶ïvÕ¾Ø5ª™IŒQ­UãM±oŸ¸Ú¼î݉ð»Æ®¤J(D¦eR{Œ%—!a#‘¤šZawiZ{Ò¥cl¬Â‚àL#5X»‰›¹*Äid-Y* «°ˆ f c €ÂŠ‰(T(±`4½¨t6ÀLÁƒï¥¤µ\E”C2èËôé½q4bàÓ( ¢1‡¸–T„ ò_IP¼æð…#/JK¯¬úpcÒ4a`ªsõ€q•cõfLÜ&†CsÎÎWРèqŒc0Ô–£nÜþòÝš3³˜@9@’zDTQ1#,ò2“v¶ßIùüihqºX=nìšG·o¼7¢Éÿ¶¤²ÂçägƒgHÏíUyì78~X‡C8GG×!HC‘{zðç±úµ:Ô\9úpXÉŸWó𶖬¬äôþ1] ½þ¤q{8ë©qö8é ÖË(΀TáÇPUAà vü›&—ɷ䘎YJè’¤ÓHB eŠ#ÜÄI™˜ŸxÐ×mí Ç2¸¥©#5?U€yÈ,ª)ji-: [G„0÷KÁlÅ@(`-ËYEl8¶<¾€ÂàWH#“‘^yÎéáÏ>Â;u茒ÿi~6a“éã!ØgtÎÇ…ô+ÁæQÃË®6õ4õ5AÝþ÷@>þ¸’AðEUø&+»tî•\Õ¦·[MJ¾ü!VùîwÐP…D¨Þw&Vãû3‹u÷6Ûè×\J•Õ°fÓ±ˆF{‚Í…wŸ£Ù¸’I Ž-U#ÎòóÍ4櫆Iºï<Þe¢S–æ^s JjI’±”ªñmÕ+bÑ ÉcA²[Âk¦´š;¥uy¼GK¶è\·wn‘]/ñµx£ššW——mvœ¶e’uÏ5·U±«m±³MO5Ú“&Ôi6žuÜY.»­Ý”é·E+;®×*êNîÓbÑcš¨¦†(TE‡÷P(ÆÂ)qUö'²pØ`›‚‹Ù·×½UƘ[µ9QüžŠ$;ÔþÞñ-F :Eð„ €H–@S¹ˆ–U—Ú£ä$ëÄËóGÞŠÃx Ø×H7#,|`HŒLÃkÑÒûÙø¦‹õè•ÅÝ°ŒŠÐîõÞš7zòñŸu£á¹?GsÔ›NÀõ‘t•XÖfmQ)™¥ôÕíÌ$ è„#5uZ*Ðb Áp?„#,X(g:½ül*&ŒXEXD’0I†$OaáêPúÕBùòèØ5+¶u×wRÍEE»­w·m¼’ü>ï!ªgá#5ÂØÕ5jL¢·‹ÃÚR¨g ¢ÔA¢έðˆR&HÁz×M!;ŠH¢@0·1ÃB"ŠÌf£o¾uªˆÖ­×m»i³ìkÊŸë«nÕ»Ål¢&4:§žýé˜d'È@k:dÿGöáí)R0 L0)A´(‚#5l`|ÝüSCÙXÔ ú€î@#/ñ¦¶›YfËU4Ö¦ØÛi©ƒ†ð/#,1Û³é0VçQ#,uÌmõí³lšÊ¢¥Ô™›` *ÏÈñ`ÔÕT#¸ú0ÑFÑJRRj˜0²”€'ðP"$P ¹pÃrª¿êƒŽs[S>Šã5‹±\”å,AL•¦~>4Â7H΄ˆx²gW‹Llf-mEúºw÷c~«#,¥¼‘Šb„ BOÄ!{ßá?=¹^"Eå#,úe‡0ƒù³È8ƒÈg„+`_ÓÕ}CyfÊÈHC ÛIÚÔ4ˆ>7€ ÔÀÚz“8blfh J å…¡ü #>,-j#ø6 `j#/$Õ’1W&³hÂÁ8é$B(rA#/…Ú²¨0@ÞÝEd&1<¬¨#5´b#N°ÑM›¨X; •AµM¤‰„Xñ`]ÛL¨žúów•æ·ˆÖ-GŠ®X¼jå“W/‹*µâ¶«ÆW¬5úR¶Ûk;fN=Ñó{njöÖö‰0Ã#h~€bH$ÑG(‹"c\Æ<.ð ²Hk_Æ*-j‹Fž›i¡µ,Œ%£!Q*Ã6ÅîTb¨ÄIE#,ª5AE@‘‰w@ALZ`m6Ô]ƒÆC±Ï<±ÀHA}~…Ýɨ'§bWŒÅå½ù}$µ…ª ”Ž!A¤õ@Œ%(”Р7#/€º±—|ò³±†äOvj)À‘Œ$° ÄyDz·A¢ ²©€D‰(…B¨ ó÷E>A×óÕëX4¯ž6Y7OmwM¢ f#/”bubF(´„ÌèyCó?4YÐ5™á3˜Ag™OøÅ6¼zôþ¥üÔÎàÆ–ûlvAÈ[Ú>pZJ¥¤ÖðÀçÙ*üÍm5ÚFv“°ÃC$MËUÚèˆñt»¼îõÖë‰ùHÓF Á0cKOxÔÌnÉ©]!ýšp#/2ŒÃZ}G‡ý%R¨,¤³N ¢2M«O‘BPZÿ L–ڽϰÜtvc¦#5vbz"‰ù'‘êÔ/#/¦gyêA¼™Â ¯1>¸ìFâˆTWlüÕAœv÷ª ¹FEÆ"€HRD'º†˜ˆ¬¢#,‘#,“˜C¼"XSò#5â`yÓ`ì~ø#…¾Þ¨$ ¼Bﺌí§Pðþ>ödu½ê`B#’4”„§è¶¿nU°››¢ ’‚'ÐoÔ‡®Bx|úŸ¨WÓ—Jö•À."Š5'á±½}å™ÍP9JH”(˜ oÓì#MøÍõ-›¨6œh–Ã%wúÌ°:wýf79 ÕÓ¤’•*ø˜“c¥L°º†Ä@ûÐg¡Ð¢‡\ææiÆ`Ïz\·^è!ö!£[$f”§4XBKš LÈ­*­`&Y4n"Z}_$?/‚x*»ý»Û–&ào÷#/¼h‡¼Hba !ðd;¬_/Q­}h7Êúæ "/:ÜÏxð±Ö/Ë×ÆmàÛ™UT`ûäsž“»¼Ñ6]Y3PµŸÍ{4ÂÖšüÍ—èª;VÊBÝE‹–e0à:ûv„r¨Ã`Ð4#/'8eF©j¬qÛE¤¦‹„b±"À,q­Á#/#+Lé m-0f“Q2ÃìgrI §!Žú²Ù.¼æL;ëúµ HùƒNU”kbf CÕǯFsSÖçØ·÷R'¶ Kâv+Š`Ç”7±={9 lßGf-2>ú#¾Ýº‹xãˆZÞÂœ¡¨x‘ª†¯n¼ÇŸ‘ÞS¿eµI™Îé•|>Ÿõª·ò:lÊP#5Á.ƒÛ^)¥àIò z nÙp£¦ÓLMñéfÿÍß fæ‡ôl‚¥Þ5©^‡.ØÝJud„&ó#5!„3@8‡ )ùÔPhȘz#/QO@'»1ÔÃk:#/Âs>ø;ÁóÊõYZ”*€ðo†vfƒa‘UAÉðìêêÝž@JŸÏ8EuBåœs¦cÈÅš.oŽA°Mı Ô@i©Øp› n"õ¥R¡Û¯†VàeA‰Ð`T#š…pÿîöÔÀ¹@±~“K?¹’|v‘=•ýÞÐ0 Õ iL$DXªÝ–Y„´Œ` Ðò(ôêó®4 m¸¬žÝÍ#5hñ(>ú©¿Ñ1ðm§Ž#/?­üì9óœMI#5BHj¿ŸæÖÃ}_¹5}J#/~‡Ê­ÈÑ­¼šÒnD„ÄF‘ï’FrÙš»“…@ä7®ÇÍ<Ãó‡*„óÙµÉVÓee¿vÂvøxw$NIYúðñð›|h“"Øê½'¯dÐ<õCrÆXµÁ !߈h!2ocnÛìüÞZqpÂD¡ñ·=ØØ–ad1äm”" ¢#,™O2åkp´Î`ì ÒS¾ctà|]ËLõ¦ýW“„ 9Ñ1☖òFqexèô¤@îŽ?fëUÐÒáa¬';ôß¼tN*©&d8œ³ÇFÞ#/­bá=‚u³ž»YfŽ–¡˜ö:Ux1°ì¨HI$«6]ÇÖÂ0á|XBm™a¬Œ3¥|HM®JQ…8åÔæ,ãW7æï÷l—ÆŸÒÐ È9þ¹10H¤%¤"±Dô©ü‰¥a|> _éUƒw¸ˆŠ’H0ˆ²»KUÕ#/ŠŸ+›ägØ~Z}/¥0#/´Mê:·²1ƒÈ4=çÙ‡ä=éÙ.¢ý<ÍÌ4-à˜›Pr<ÎœD1Ûômz»¼Ì-¼¿jö¹ùäqò â admæC\ÕjÌ0¶ØÕ¬Õ­-K‡T\c#ç ŠÁ^%Š¤â#5šI#5–jwáx<ÖCí3ôƒhÇÕlº‰µ&W±Í-þž˜Å7AãÚo@Œ4œPCr‘†A)FP%DE!] þO¯*܆áĬé¼~žøÞÒ¿«·×½m™ Où¡TŠ´ÛÀ¤ê@>Í]`É÷*çÀt[6¸œpbZõõò`¡RÚ¡oB7‹#/]}Ùœf‰ <ŽF[CؘÀ€UUFëa…ß`}¦ì¥‘÷œ(–Æ®-Š ,HÀZÚÈ}x& ¢B·º²#/"PÔ³ÒäÃîË£©t3ìµ¢‘H";r÷ý{à~SH«ë¸î­ËmÜýû­RQ¬c[eRšVjlX–­*@B,êݲÀnxR…÷!ÄÄ ;òøô#5ŸKD‚R‘H(EÝ»ðå4Ó·ùo<ÀdRlÌÈËI&Â#/4”$¦Ä¡´ÊÃ%A²ÊšKHÓ"BÊ”©d)k÷s`Z#,Ç14t„ƒ¬GJf:Óc¡Îž©ËQ¦éá‡uáuž9Î.*v3#/&È„m1¨Œá˜A®¯ ´Ái¯%Q÷:¬Ë+Wwiå#Z¼tÃ+*qÝðif¤ž¸gè,LkzHÅâ ŠËÄ8öŽ \@ !ÞõóŸ)ãI³Ùœ¢»Bº@صYt+t'a¦˜¶@qÇ(£#”T‰¹ù&@b8˜ŽCq£â\Z.=ÛÏxÎ:oS,¢j¶†­õ¢²ö ߎ ÁÒägb5¥œÌ< 1wqáÇ&”¢òDd$‡(íõc_“#ã1ïQkR3„†ð×4V5ý ãÏóOíY;Ô1ZäI ¤þ4DF@ÂÕm¨¬‰–ÁºÆÄ#/24A#I`‚mŠ¶ CbH†Rg~¶®©\º«–›®Õ&·g%Í%æÊJ6Ć˜‰Å²´1¬™p.¶c6ÑŒ‹V#5ÀZ€;nR¡.Ñr!E’ŽË%#,æ8²¢ÚÔf?Ê#,*Â@c 3W¹“n].jw[¥¶Ûu{õ#/'·„ØÌÓšQŒAÌ<ë#,B™‘„#5ÅÓ#,{¨ãZm§ìU+qؼñA¬ ËÉXc)ÿ¼0Çðø›ÀÂB?'Yã ]5Ý]Ñ£È<ØüâWð/#5ŽÑ@Wjš2¥aeŽ(h¤b‚lt¬‡âÚlš(± ³\8l¨´›M ¢¼m¯smžæ-Ë·q‘Jr‰HÄÁ¸¢U =›y#iGM(ÚE¥ “š„qd ¾Dƒ,DCtF“X8¢‰Ë#QI_S³=Ok­{ïÃÂ%{Ž¸M- 6:7&Œ¡+…U§Kd2³ämbB¸ˆX°N5R+%"{2€±d+ 31ÆÒÆ6C ë ˜`ÃRtn(”¥#…IB=$yÔ*`ÝɳcšÖo(žjïzÝŠf;P˜›dÛ.ñæijæfyPŽ"eMž¡²X”™um[¸£ ‘Ƭ•¼#5Õds"X,#ËŒ£2†5€õˆß`ښÊÉïëñk†èh1ÐGC7DAŒj3l3 ™YÚ¨8‡¨Ñ#/j,Œ•Å‘ƒŒoÎàÃR féŒlñ­Y‚n(ë9·4TÖ€5#57× d.vt<Ô`¤yªŽŠ± á´¬f#/ôœ²j4œjŒ#/ ‚b¢Ý#5f“E³(È’Šɦ“bóLÛãÆMœcHB^»>hƒÛqËÙØÚ0‹£X>¥i °Nm(ÐvÖ­$äE‰l2ê’[BÜÁšf‰”,˜D„i4ÀND™…”’$119#,ƒ(`Pè…¤Œä¡¬GäV:Xi°Ç“Fµ}#,Œéáˆcm˜â¢6„˜&0‰ ‚hT‚"m#/,)^ª§FJ&ô{Xg&ÃAÏk´cG6»L~´c´¢¼A*u6(Ì&BÖ-#/4©ªcl[ÈËn“±1›g­M#m>Jash(Ë°Öšû¡ìbÂ…täDT×çѤpìEÐÄUHOID6<¥´ yÃpß4t=(·YeºU$â9¶H|“m'#,÷:hÜF [s(€Ùؘ;0fȈ„i-Æø*@Á’ä4!B†ÐQ bJŠ£"¤Á€4l`Ñö’È^)"¢à4fŸj´ÉÌéÜ‘iì%0±ý­*’ñ…*åM±“w½-åÝ›¤öñºë•ê¼^Mß]öWà´bƒkFª Qd`‘‹!GQ#5Õ?÷w#,YCüBd¼1#,.&ˆOϺýP6” $-Ù#,.vâ¢ê~Oæ2Æ÷¹E@_3#5#/(žª(ÔúˆBŠ2 ¨nÊH B"ˆÈ¢DŒ‹Fhƒ¸Š,™—±î B'¸¢´A9^çHä;æy{ìmò¡# BäR”Ÿ–Ÿ“Å!KFúÃyhÁ…ˆ7wRƒNçÖ‡uדù«xõÅœëcn®®š—¤ *©’Ásj‹G½%Ú¹™‚⋱‚†ótRSRHCö)gœ€víRK†æ¦ì·È˜Ê‰#/0ã§-™÷2cºþo£PDS{n)¥®åÙÞZƸK‘Þ¸k©ô¸–—à!ôÒ`6ùáw/hæÌŒGê]!¯Ú瘙Ií.À±œöÆ6AÈ¿x_Né‚!›Þq; þ°þH®­HD™¹§F*·;2“è×À “¿òyg©‰±!ê"^¸«gŸUݾÌõt48Y©/#/Ðý‡´HÆ"“L(òpDèE‘‚2%tù§`˜†Y‡¼ß{OGºÔwËRÃ*ãmTXÏêúçÖët©²å\T*#,›˜;Š5ÚkíÈ7–9”O.¢|ÂÀø`J¡Ù•[Y Ã¬Ã"ÜÎóh˜…²FbÁ"©TûY‚@ÀhZ¨ÑžæƒSé~'éãÅc«5nZUI'(i¶(°¦0%$Ù«âoƒ}Ì6À—r¾âçöåQB TÜ@´C!Uþ5A”ª¦t ÊKQ¶˜—VÅ×[ ÖOW4mðæ·_n›kžWbW¯®[kÇ5sh£xÜÖï;ZÅɵ!Ín•k`[%²BØ  KVØ#/ép¦Ýýæ·^ud®îå5\¯WÂ’,b#Hƒ¼aN@ð{4TÂØ8¦"|@º\GØ™ûƒÐb·²4c@IŠ¢å#,GÄŠÚ Ò#,z@÷?Ë€âEK´±ƒ»»omWÇ$ñ4§ƒ¾P¯Î!ÌSÎ)JÐ#—å?q @>úà…%Xù)Ô‰‚n"ÈUElïµ”×%­Ù¥®ãm×w#5ì¶tXîï.áB¶—T€§‚%€ÄÑ„pZÅj-¶´–¶íj&Úº„Y$#5j¤K6V#5˜vÉÄÂØ‘DNDQƒ$VHATˆ} #,Í#,t”¯ý¥Põ*†¿š£¥'U÷ÕOF¾áãA°GÞB&Çq–º¾ —ˆ#5©˜½¸³Àô¨!ÜzM‰X=ˆ`¿YÌÅéô”H'J^‡·`dÅï‚„:>B¹bEc„dR@²l¥14Øщ¡³-3DÊJI‰±´2¶ÑV¶Å¶ÅV›J¦U*Å©­cXÚf¢Í^hû‡Ÿik’2µ™¶@ Ð91‚•È‘>ü)pM#/1¨<¡–‘²1HEéd%T°5˜«ÊAh GGŒXÝ"˜W#5)`#/ƒeldE‘¡È1’T:„¨UFÁ‚44D"22*T ­Œ#,„•æfi–L"Ä'Ïõåkª&ô%¡ŠY¥¥Ý;7 ëO®׽^ùPD AF• B c#5FÖ‡h.*W N0é°^ËÅ6¦´“ÝshhyöKkÎ#/«EU)¥^ }#,1 ’´6ÃÃÛ±”!77´qÊà)…2u—ðm:;9øtM­`,Å#5ÎY!‹VF@A1ÄÞ©µ-Ö$<8k”bHµ›†µ’Âe.#,óm“Æááçç$¿Fb‰{¤£Žõç—]5ÕæÒåLÌßrý•ßÛ•F­¨ÛU\Õ\Ö»½¦©+ãkÝìÕÕààØç÷AÊ.qþY ”D³Úû°¹bVUÒã6±dš¤X|?f¸èmŽ8ÖAŒâ凔´}cï€r×BüÎÜâ'óÄË͸=÷PnÝO12R_áë'¸¯òvÛ¸‘´ÖâËϯ¿¶o.‘”‘ ï×eu¨={¬çpïÍl’×iõÜ“ÅÆ;ç:Ý7OKt Œk/ÑÂ)áÎ…-™Š—ÛÉ[ž/}‘äEð„/,L'ü©r‡B¤òŒ‹ôèþ©ºó’9·å]¸tMÐߊkåGW¨tYAÑ3Ï[”5ÑlJèÚ‡ÜEúy»F]Î×!Ý»®éŸÂ%#,âÅÃWN-¿b2 ÖtóßtU°uĶCŒ¯LÕK7ZXn®?“êv¹#,:°éÙN-Q“6ç¶<”h•Ò䮚ž¥°Ïå0¼‡99{ÃV48ŽŽÙ=4å²γÑ|=ÍÍvLç”ù·:8D§Èãwwj%™ ]N•æøkµŒa‚Ñnt{òƒu^9{’×F娄ǟ¥IÔ?9 ~\³½¶Í•Dã숭lÃ>7éŽÌʲéßá*ÔpDÝ5¿]NuD¤¨€ßTSLœEHˆE’æêßmyžú,[¯·ýxvvb–)ªÞWƒÕÛbOãdéb€ºL(«D”Ž—2ùÿS°wÈ´;¿®K×Oy7ËcÒ›c¢P4áÑ*“m…™¨W•Ï’’”ÇÊq[Û¾kÚwy@ûcoÍÑñð{ÃTã¢Ó<#1܇Ä÷Q'wbâü@ë¾½ìâ±ÊŽ¦u~HŠŠÉR×Þù*W˜çO•vé5Ó>ü¤#”F#5wÁTÀá öª'¤ÇRNÐú³†ºÐìÌ rldã5·îù<…ŽeÍëS’]žú=ÃñôÂ3«¦gÂH:&f#|8ßJÙjZœÊJÉÏËÇv0„! ³uŽ‹Šxéǘ!ÝÑÌ®ZœÕQ…sãšQ!Ô8s’„;È+Äu5LÆldR-ߧXRpËf‘(%¸t&!Hìj@"¢ˆÌkè/Nâ~’Ó#núž‰±gëFpðægž&˜Ý»áAÄÈéÐrúçü¾Õ´Ïq©6ºð?qä—™%bLn8ƒY|)®Ø¨ñ¬D¡ÙºøvKxdÍB—3¦zÛàMæ,4C^æ£ÜR£oä~‘¬—2_&O”O¼û˜¬àsÎÁÐç©7ï}ðkÄcŠvòÓ—#³ùônš8ü­øщH…Ë»<|:Ѫí`ƒ¬ºê‡ïD[¿e1›Ú\š»÷Æʤӱﳷ Üì.u«#ÑŸ^$àU†|£3ŸH%LôG›È´­$‰PúžÔªï¢sÇ,¤Ñlu;tm_8Ûð'äésâ]«1Çú`Ü©G„Aï‡#5ë?­å#­ðv(+t>Tú=õ®¾½<ö Aïäx @€2#5Õ‡¦æ¦&Gcª'!c–#/·Xäe“j•¦#/»•*Ô•©ò<óXœªG­_qû”4b8ì;z‹=AÀ~xHôj „qDÃ1#/*Î’v6˜±)‘){¬o¡xÑÇlè4gwò `¨äsÑ—ÅÏ•8Õ…•LbYˆØ-Á\/ILIUãœ)–Íd›mÀ9ÃmRº½Ã”(•‚YãJ^X*'¯$ÂõtÖþx“%S4!2Bð2Їs½le!ÒŠš #+‡—`“3‰—…ÚÊÂ\ºê!l2  ñ9’F£w»PW ¨ÞdÐÏa!HØ6Žã}i*ÔìÍ®“,Ìj]Š¹vmH+‘´¨óËnûd¥lrË-–¼œEŠ¡¹g2PÅj] Aò™–t#, )zè)É(— #5ˆF#,B(D[ðÄÑdÛ«…vmìdz²ÓÄ€îÐèRÏF‘,¨NHéÄÃ-òIÓ ®·@#/Ð3@Ë(ÈOœÔuç öÐÎ>± 9A%A‡š\=ZïëÅ?š•|4G°ª(="…LˆŽÈ»CÏ=Gš/¿ôK¾Ãßž<‡>7p%RÞh¥CÙL²s;Iî‡û‡H)Y.$gá„FÛ\ám°ØÌ>òùÓœ>O룦z“Ò»¢ãÕP{ƒ÷ó´‡M9ëµÉjj?Þ/£#/Û¿·k­¬„7U¨òƒ¹òwF‘®û³e1¶ˆÃw¿1¥6 X'#,Ä öJÇÄ·–Ûu¥¤kL9w*ûGnô |Pz iló0;®8~k¸óé¿F‹„ds$.j¦¸–S½£$2*!‘„’×S’Ú–3o`b‰#4@öæR÷àƒ ý8Dæ‚šyvvã˜b;8=qÀIzÓ¾.TéhünøÉÖáÆA¨Ò¦¼µØÖØq<3Gá¥:¸†ÀùŒ‘éÓM^áO•õÙK»p| 9#/š5ÞUš˜¡ª æË#5ïh*ÆN5²Qu}X5EG’ma¼°áÂÙeœ"5#/ƒ‹â¾—PAÍþüÆ8ýNœµ)é FT³†o—AÓ§\pµ Sh%¨ÔVÕ*ÉRXs›)ºÖfÌVjró¼ÊŒÌ•ÙË|¼ðL’vïlÇÉÀ´*C‚üô_ÊÇm PýX ¨ñÈ=À;ֈ缹e!M,à-²7‡R3±Áíu²œó3Îe²¸‡žy@ó((̈Æg„Py {»–ʤj®¡PÐׂ%öà˜Ì:f,øÒ­&CcÑ®d¥”Ò†#/¶…&„BÂ\ØH©½Ö–²›N,a$ß¾Mnô!Ìà:§ ØŒ ;$7„Ãj¬‘0çËì~€è®ÚòÔjxïédj†l#/~¿¯T~?"úµ¬%š—ò>œä=ÆòLo2±5!£À*€”‚}î·‰“¥D*Òs¬ðf…Ò³½1±fs“W‡D<=Áî^ÒØÈ÷¥£HQU:@ÐZX°æCV‹FѱD»¬ëw*I0 65'mû_±okV-ç–ºÕC0x5EÐØÑ¡Æ”£tZJ²F08ä àD¦@«fÞ­QA¬kšâsmͨõvíœiêGy£YUSq"T'†+·AêB¸`daL‹šbBÌQVd²ÕŒ{†±&0dUC¥›ÌwÓ6Î=>rFža†ßFv¶´O9×"}ª(ÙZ]›`Ú@ÚUÆ#¡DÐj¥†#2Yj2ZÝL3^‡võEÞ““')Œc !b3ä+•„nãËÃxºÍKÌÊ#c7ƒ´lÜA£A¶lȱÖ6¹¬5©Ñ™¼I¹s{)FÛmbm¥jZ#/µH›j¼0‹$ÍË_¦÷u®Œ½ÉÄ*qÔŠwœ#5Fu(3»ãƈŒ)a)ÓpM,(PÊ ©ÓcåƒfHÃSKÅ2¤Ô1wÌ¢ˆxpk3Žâ †iYŽ.Ílo! —R¤Æ±¶–ˆ@Óê+\ФIÛR¶Â7vÕÛmá¦oĨ#/)Âl¤‡æÂ41‰ïlñBMÐÑ¡ƒ[:JÓ6Ôj©je*Š¢…Xa†ñ“LV1·š‹.„ËÛ—KG]ÈŒ3…Ek©Š´š˜:¶†›¤†@aú°wmݳ hq²iƒ2òÈ ¶ûiæqõ<âñ˵aQÓèÃÙ”~n¡£UJ5™b´à£„Bc9GpáF2›¦ Q½åƒUƒ#cDÇF2#/BØR…hl;™1F%Ž´c4-]Fi¶pÂyë+`æ­z¥W¦dpìT¤ŠçaÌá“#jP˲ÆÔ£„rªÛ°ê ƒÐÖ?„… ­GÒ¦fn*£âjˆ‘ˆR-yZ«Œzp§m¥W—”\8@s¹eÇ-:1ês[u¡ñ­½,-™J`qšu6¾i¶Œ.òaZ³ JF™áÜ$go$®Öi‘Ôàè-2“FHÄFK3º*ÁÁ…ÓŒ»!^ž5¤E¤ŸIPÁQ®úµo´#/:Žp0ãG 0%2ÈÛ¾ÂlDqJs;¤*õÇŽ§åó„}+?_èX~×;ˆÒh©4n>õæóξw·¶zê_Ð×ÒŒ3+Ѧ#,B6i±J>°X"B“´*Q)#5UHkø¥2Iâû=µ(Òe!ߧeS¾¬gy­[€i T¦2Û³÷œŠ $UUFJ2ßê*{ÑŸñ/PèEÏó+ÚIŸCªšc‰jó=¾¸CÉûÀþ^°æ‹ëA"qm!–·JÍÈÍPƒ€ñÂ@A²ûµï¿JÙ&a28÷bÍ„Ú[Ýøš§Õ„zÞlº… uq–ÐúðöîF›ºNîäÈ!ݽx÷õ5¼i]tjaQp%-T¨Á³È3=‹g›ÝÆuë2‡^Ð÷¢? ;Q<ÍùT¡“ŒHQˆ á6o-ÕA#ôÏË9ž½Â(Vk{–±´à‘À]‰LÎÈ€ôRƒQ‘a#,X°Aˆ¯)¶¹µ«¦ñ­kË«¶¹¥R«ÍpÝüSòEæE?Aß×ß(Ò}ü$$ŒcPÙQ²’¶Ñ­(ÔF$ØQRRa¶¦VË2j’Ù¦ÅZÆÍ)*‰-&6fdÉ¥–Å)HÊZiR”fJˆ¡Šm¢l”li²Rš,Ô©¥h5"É› 0Œš2[V1­­üëßÒ¿%Þ‰‚ ñÀö¼«hâ/¶%¸PyòŒå¸ûæåteÌÄóÜýOÐ×ó°›ü\÷Õêî¶Ï\ÚD‡ÆsVÑ|’aAdƒpp½ïj–«U¬ZÊ#/5ÂþGŸ§Ç4AóÙÔo³Dó.F#5ä´v‚~Y»zOg†ƒƒM#55n’öÄ 5/öî„ð )"‚‹¬kI­}æÕ®[1¬)4H)-A›_r]¡j•BÅ#5PÅFR>´²eÏ€`'qxå!BŒ*O·Û˜\3W@Ëd}ö^¿°¸j@j" þ˜QjxoCŸŽ]+L"k¦VºŠŒ èËRûŽQÌE4\#/4‹¡w›¢eÙ“$ÂXÃ#,4Ž±w$Âl&‡…1H ªÏmM–ê”$ÅP* ÖXj%í%†¥ñÝ›&õÙcßÍÕõÍz“zÑmF:š¢¬´ò½¥*KHÆ‘#55Q’¥Ñ#5E#,ï8ã'áí5§æá ÙòÅ6FK^΃ҺâP{7¿g_©y»Þ-FÞ­»"’bTi²ƒYDqbÊÿÙÒÈlÐ.g›.j˜R´4•/ ¦d£$1A€`½Qˆ<,1‚:5$m|Ú¬ 8tˆDn`*LCq-ä "I$‘ÁPÙ·‡dœÐʨg˜b¥(¡˜HѨ€7$Ç¡æi;¼ÄMó­#/é\W‡_78ÏÚ•×(,ú/dî"B_òá6ø0 hú½*s¬añ²‰ª£-n]MµA}êÂRЗ0 úT%Ý|È#,ñ‚¿ ¡p˜{ ÄW(4ôçèþ·Œªôn%Ô¢•[«xc%Ö~~>O–ºèjIÛ:ãØ?‘ëSQž‹ñ*ûó)¤ÒÂ:#Êse·ö˜#Ø8…ïúèbáöôaç¦~ÉäX2ŸaÌÈWJñÆÓ­Œz™TZ™ÎÚäÉ64.Œ#51B}©%÷s]kÉ^vœƒ-¾ßaî°i«Ð=v²¾´äœ­r4ié>4"’§< f׸‘©"ø5,:ã»;í˶LÏgÕ&åØ›>f;}J`8§²$DW‘ë5êOñšØ§¦#/‡÷œËEŽç`VŽ@)2g³š Ú611ÿ}XwÄh7!€ì#QýÿTÄ7vuI¨™3>Þ_b7Olbwr>^þ‘BIDI(€Š%çìBöÕ(´jtû´íƒ }'‘n,,)Ÿ¿.¾¯ÏD~ìèGëì~Ç­n~MLáØÎôFB«¦‹ PÆ,+rc¹`Ã6'^ž]hlÅ0ÔU÷¡ƒÑËqQ$îö¡š©*}_m[îÃx`¾fo\e#/1IqˆoÁÚkö‰¼¤þB%„Ž¹°ÙW*Y5ÔX6Gîg|¢ƒ]82¿’Ü1´„–‘™Ÿèw»Þ:*DôyG7p‘l¹ 9R%T:­+ŠŽ\~q5Œæg”à§FÔ²4Ã0ÖÚbj„‚"Bl3Æ 2&#,¤LífÚŸÔZV’ÐÈúˆ¨ª) Ìú—l!Ã4ÈvWº«²™º"¨ih±bE `BFÈ„TIx6;8ØÓâ„Gx£½¡Èk™¡¤’9É¢K7PeÌÓ=™Ø#,˳RƘÈ­h¦RĹ”6ºsÐÙLv‘ƒª³”¬A‡8¦Më¥×'“&èy¶ ÃD…ˆ³Z(`€nQ©ê?i˜` `‚PÈÄ̃Þ"¸7§VŽ¨hͤ•B[ÊBÒ£SÈ4,U±M‚FÌÝîãø¥‘Y-…mÃs=rkš†™Ü±Qš ²dãg[YšÔE`؈‚Ù™ƒNcQ¨œWõúù¾¹Þ ûëgC‹èý #àSAcÕ›f&3ÖF|N.š°cðœ(F®u0ù„õ\ô€Ç;9ç5`Ž¯…í.†êiа;eÛCÀûï&:V3+»ä:ô)˜–t[½C‚;Î’Š[„.êö†5¦9Î'½‡<³‚XÐŽ8-TÑGˆ’Iº›AÊ… °4IAŠ’³#5Ð(„4Ãà˜o³Â^+Þž£ÈFÝøf´kq’Ç—á“SîÃJj—9½Ú›Ê㶠cïLé”hG“×2©á¤AkHÌŽqlcŒ°—Ó`CF”„8íîŠã ÎöêØDI"ÒÆL¨¬2‹™C4 xv´ÚMBÔrç4è…"•j‰D°Î²Òb|ErEbÝc,n#/3AÃkPÁ- A èw ƒ¦¶FH¨åJKy|2”˜LÕÙSÙÚâs\Iu`B2 ëÆÛ#/H³%@òÚ™Þju ©æ>Ír+R–fCÂÐe¶2g=×Ü×mtyBçC‘±Öi ¡f°E2Ç#,Ò7 ƒ@毧̇jXH8ºÎ.Q0tWF;bÑtç±Ócir8ŽMÒ(e#?ê‡h0._Òƒ Ì–‰Ó57“HaÊ< $t3 Sl†tÓi#,s´“Uˆ²P¢& mð±N5:þ[VÆ-ÎPd+‚¶’к0psW)„‡.˜(êã–Kiä¶ 5˜šf…PŒ`dYˆc0’“™Øïú×;ËÓð1 ¸ë\‡Zg;‰Ø0SC#,šÊ©&;XÒ){(zžpÛhK“bK¶èä&º†2Žƒö_ø6˜¶ÎS9’Ô`ôÊŒ¯ƒòö“wLôöx€51X0“Í“¹š£~G36‹ xÑ4õë~F´(ã›ky%\»}ˆGGѼ³Ñ_ k§Žp9kI©X«Ob\8W˜¬L°ˆ3‡f²á G”› ¥£íéxıu»Ú“¶¸ò• #5ÒtÚš–b¿o[£¦ À"l]D¥!Á˜¡*£ó~í¥¥÷ ƹȴš·¿¼7½NP¡Ù¨‚Ê]<ä¹nî7ƒ»åZ íû‚ï¨ò žzbŠd׎(ÍÙ1Ä0ã2ölUñ7’¼–¹¤å£^·*éÁX)ðžäŽtÂfªH›¦ -¬¸1laù¦‡@Íå1¯GYÛv"öÉ,˜;ç„ÎCÉœÉÕZÒ¾Rê41ë~¦XŸŸ•ôÎ0ÑÈ*ÐÆ»ùœ‚#FÎf;&Úlðæd#/ø´3J±v2›§œ¶/5Ê·æF*VøDtCH>4š[ï ’u,w1Œ`¢ÑÌËá¥GBmðX¿cõy­ÓŒÞ0fßE4Q«HˆPÈz!‹ªhEçAFH"¸ªPÝÖMO6÷ÜÉÂÄ;½S¤]Áõë- 2m)\g†`uns…˜®EÌv#DÌ" 3µœúQ4ºÙ"6#/KÀ2ÁÐÃDb¬HªŒbj0¦Iz©#/ÎUñO/wÉHRöYu,««DëJb(‘ÙÅ®ÿ#,Ì1aª"/eHÚ‚žhïCÀø3bi˜RœÊ»ƒÀ CiÁ¨Q Á’pìŒÆá Äaƒ¨bb_BÖŠ*EsI`dl!‚LZÐ6؈‰ ìªXò¨¦&Ý„—²z½}'Ñu”¹F TTEA³GnP]f^®¹=£`Ë*„;E„HH)¨ 5#,æE~íÿÜ[ײöUAÖs—¯}Ø* &ɸ‰U$_°. Äh”"%Q Èvøž@PÈO.Mæ31<Â+"Æ’©bP2Á8âd‚TLc`Ç4kÄÕçxKÍÝbT®[ÞëA±ä! d… È𢢌A¨5%TABJ‹J :éˆã#, >l|si(A¤:ënKßwL¹C®’dˆdÐØ&`¬R, „Nˆ{úÓ³´|û¼B|&>~šíFù ½pà‡ˆ)òáõ´Æ~嚈•Î†Ÿ×3¹FŒPp ‰R‘Ks1ŒµVDD Ð9†Y~И]ÄcaS&¾¨™Jëä%„õuØ'CŸAMìM€ð iÉîŽã¡L’xØÃ)âA!ÜH‹Žû"ÌCÉ©ä±Í#,…0¿‡B°ˆX¥ àïÙϲ؂l‚H„€†a>’6LNpNþ=AÓU7ö#5‡h‚˜|>#, t"qvõl"HÐjá†Tvè®#5dÜ:cD“A‘„\r,É#/ör}°áM‹BÏÌ~eŠ0„a#¥¹#ÏK5 Nè"‚i¢1XY«:ÔEŠñd<¹饤CM"ò£¿!Ý,FÙ‡†a­4¦…ªÂšØ}C¹Ï;PÚC-¶`¯³k9NPïÃ+Zë-sŸ‘‘ƒNÉ ; Ô÷gÛl¨í­õÛ”I°6“jÀ*á,YpèhYhý[¾¸©¼ïðQãU#,E€§¹% 6Ø¢j2‹•1pA-šý–a]Z³š‹06ˆpM Nÿ¬NJJ†RS,Ûs#,Þ&àŠN|P¤¡#,ë:Ûv¬®¾`R)eZ·Ò —Aý‚«! Ó.¾™Âþd|yõl C7Y0Ó®e‰ÖpLCÍ8äP$ E`AAÀU€®ç²=|°Mß#ÆƉòõª×aÈáÐ-@ª!RÈ.B¨6#,R¼„j#5~'»èý½ø$Àce„Yˆž>ߣáQ¼æÅœ+4¢SøÑÈtx×_¢ŠRÉk ‚ß…Ãð?ɨ|>>ïo*ÌŒ>k,"˜ö{M þ3Ah„'ÿÕ·Ä–ŽoN憨m·4kÊ«@(í#,¥$HßÝE‡*oßû©hÚä¾’¿ª ÝZDúbl *|ûÇd,)À_ï€vX.Øbvòر-¸$HÈLÈÅç\¬VaI)"îåŠûžtÞh5xñ^5û’çž^o+Ï|ñM¦«´E°ÙT"6¯uÛ¨à &³KQD™ Q底6Ó6†˜@J” *pþ$Šl¢›OùÊ_w›¼½y$†@!» ¼9›Æ@eÖD«M"¦!ë5ùßHö#,õö‡ok"È,€ÁH1FItIÜ‚Œ‚HKJ“$–*eh²YfKf’m_õãc}ÍWòõô)TC™Qª4še,Òîü°IüOÈEP¨‰Ÿ²–»|Æf7Ò@,)ºî¦I#,àOØc_T½´Ý×6bldÔM¬ÚŠ*Åe¦FÒ{çžjˆ@B {(#,´D"ïŸóD-ÍA5ÿ‡‰˜uw“âú¾¸Á×Iâ¯A5ÕÁ¾Cxtœþ{ŠÊÄ "ñ½WDLp1 ÷¢ž$‹Á¥ÇŠ3˜)–S T‘²Â½´`ÏžfÆð)B°ÆÄ%—óéA¸{ù›iq¢à2 Fû˜ã†1Øž¥MÂÀËCÚXS¢yL@A|Á€A¤Ím6´”„$µÍÉ­R­)6¦Útï–¦‚ Š)sVÛ7“Tì"®J€Ø=Z”`J¦H(HöÚÃe·XOn’ãK¸Ý¨ÕZ¦µÂ} @xÉàRŽ˜ô<ýT-ÙÉiHØœý4#âì:ÆØ£"H›hx’öBVÜÛl Lµ‰Ž„À?,·ïgÍóºÒå†.[6oYhD x˜`næçü¥¿©¶ÕÕúº¾¹}¾:(52&‰RE‘¬SEŠ)(*"Ú2UB•È­úm¯5#5- ÚJ€¦§á•³ñQ –|dK,'Ü2n„ŒD*–QE1cG¢Šh™ññ5± *…¡·`'¥ïŸ\p]»% n»š ´È‚…dCDZ‚´¡¬P›i²ƒ!ƒ$`'‰µòíÌÛæÎíí¥VXjc·Õ¾>øÁW6¾¿9Ž>¢ZØ–0l³(CÝÚmwû š_©ý~C´+CaXe²œÚã-‚#"T²44x d`;ý´:`&ÍlkrÜ’•}}«•¼»¨’Ú*+|®ëÎ˱\ÚZõ©ç[[Æ£E¥™ªÏrGë6³#¸Qý¥d8$-#,Ì,&íOQÏ¢I¨u#œˆr"ĺ3Çü3AZM±¦¬M ( pÈõhX}tfò]JCñ`aÀP®%Li¾pCq5‚u‚]¶ÅaÕ%A‘B0Xs¢k”´nåÕã^o*ëIbÝš™™UÜí´Ò¦Ô¡¯{µÎV+*TÔQ±­çvךû+½¡A#,¦Ac)H&5„h`ÆÈÚ[R•¥4ËfZé·nè”Ò ‚ˆNE¡RDBNεm!‰°éžXK„=¢ºÿÛ—òà«‚Yƒg±¯¤Uòf┘4Ñ8/Ž1†aU3ç qyjI²ë²©Ùíîù"Ö/PXL*&†©J8»÷zÞìñ0lèÑcMû=#/fü…º³ìÛÕB(£Š‡"­yšëÚ%ôÉ!ô^ˆKž‰ BA¢"˜5‰#/ðè:8$ÉQ;’ý 6’_éc MæÿÀZ׎§_¬•¥Çk“Û|å†ýi‹in‘Û¦Jµ ª-ä~?Prg´š¼<ûh_cBQ‘ƒQºô0m­Têð#/(PD>›r8”š_™­ê`×L‹ãõ9ô`¢ÀŸ~úÙ¤q<–ó€’Ešôbä¡HXÜáÛ(Mˉ‚„KÆV#5vÂ9¡4k%Pm¬ýLzŒlŒ¶Œ"À×F\¢é¿HbqK÷M|§hͤ†ÉpdLT“‘=Ic0äd¸(ŒR„¥ €CJâ'#Ãg¥1üÙå—÷#ö^3À!Ç<ª„¤2îz?2P?ø>³Ê¿DÉB6 ʇr³¯y±cÞÀÉï;ݦ"ó¥jIb8h™#ߎ'\¥„Ç:-¥i#,¾e#CûaU°þ¦ŠùŠ¶Ý¿hzž­:µ9´ â(dÿj‡©†È˜2*&½5趙®õmÑ߶…ÆÆF Ú[âôv3óŒõÞäB4Db†'RÖèmI€*™‚ØB#˜BC¡â”_óÄÈé†`– ¯N—À±¤ˆçç"RÚº#,“m2hæaŒ‡/b"fg;Q‰¬ãÛ¬˜‚ö ¬;h-Oî5z¼ìw™hiìºâˆ¤ýØA´ ¨cñ¯Ž+qÎz)\ X¡7 uâÆtù–‚ åþ%)`aá<‘êz¢¾*~LÌÁù]ü7¼žÜ4Ò÷̺‹DSo·\-baúâ.èg_îþ_áò~øÿ»ýÿîÿ»þͶ¿þ^Ïû7¿ÿ‡þ¼?ãþ_÷}ÿþ¹~ÿü<¿ŸüÿúßÿWûçÿ<ßønëÿ—§ðéŸþ?ùYýÿ÷ÿûÿ‡§þ{>ð³þ_ñïÿ‡øËÿχåÍÿøÿËþîÿ¯Ü~O÷þÿ¿7ßùéñ87ÝõõvŸù]†‡ô‡õ«b"jy6Å5M…\?Ð9ßJ<˜«î°B U!œpEÝ!#ZûW‘nóøwïi|§ñyÎî™$Š¢1Œy„ô2IRC²Šl`†éÝG¹¯(Ay4Ú!®z©¨§#,˜6Ç3ø]þꥂƒÜ?îßžÔÓi˜\Ùp–êx†ëqFï„_÷TK´,ã5(„æ)A@µ|nÌ&8ãt§00ÀQa×úèS<šßSÌÿxÿ/ûÞÒÊ?÷yšz6¦ÌÖÐèQþmIŒ‰ôŠ‚Å ºI'ˆÈeŒÌ ¯I?ôÍ@œIÀÜq¿ ÿ•ieqÖ&!3"…2*×r­göòì {­0ªB Ü”Ï&QFišÈ4).¨±ƒ—Y/$³ýùã’ìç1UjUø¦‘2ðÍD)(»p®ýq¡X0š+šANL1#/(=í8C(hškT˜mѤÝEpq1›ˆŒZæá–°ÛÖÓF˜›H†CÄ#/ÿeÉV×#/(k†â¯ÙæIJƒˆ”iåÅÓ%KK¦#/¡²°(R°™ÍŽÆo®'?ì&#/ôçÌö~¨]1ì¾3.ÊbVæ.Èœ¼Óò™àƲÌÌ5¡‘Þø(ÛÚ¿¤—^Íár#%µíÒsVoîÀUÓØÃy…I9óovÿy–#Ûî h1‡¢ #eëÛ³¶5c+KMoÎÃX`­±Œ9¤ž$½CÛ#/V¡¶çB¡<)aó¯´×»á¸ F¼6 ».ˆ¥ÔÏ×·*•ØŘ/S8òÒ`y±3DEa éŠHÎûs#1ïÎËXÍ¡&Hc|·E!Š†Q‹{ňPÑ~––2© E$€¨šy‘¨§J'\3Z€#,À’1-î ü ‰bfi¾ØX(/Õa狸1ågi±ZÒ#‘»#Rý^¼<À¦S ‚ˆ‹ ËJ%B…ATZ²”ʶJÒkL”²C`ÆÊú]ªå#,2Ê€qS#,™?Þ@2ˆÈÁ?ß&<*›(«yÁ-‹'3Ù( %ÂT@¥b(yóúCèïGU¤?ê‘Œ‰ yNð`ò54±Í%2gúF„c!t§“ì#5„Âdx‡‰útttþó‰,¤TG3‡ êú¥#5%±œsøâÓoæ0Ï{BŸûdk»:uNô§VÇë*K~¯xÆ=%ȼ©¾=Í©ò°ööpcõ•]*Se`nL2\aÓs.® #^áÆÙ²Ñ>Ê,7Ÿt›Qyä>–*m4ØšÙîá=(Ýá{.eoÆD'4Š°‡TCVzI”D%%Ý€-W­nm¥•´¥ëk^·ÂÕ}Ëã­IQTZ“D³hŒÆ#/1(мf±Ó¬"5Ýa+O(~^“ÒõÃñ¢ K‡?ìÄø KÔiµ @r19Nac#56œìÁäK–*%*¸”øóèI}0í$&PšÕk##=”´î#5'¯òŸe»".hp ÒH²!!7’æE Ðö‡qFO$v£“íà'‡ŒÿØ ¸zäj*„bECkµÇf•„”ÕË›­«%jF¸jûr¼Ûo%Wؽh›53_•ZüÈ£h€#,ˆäw·Ïá™åóÿ×Ö‚w!=~¨©ãå(ø{f8ò0m¶ÖŸŒx;.‰x§ª#/gȤòû?ñÿ¡EB§ýZþvÌÌ#/l‚Å'ù< Ué6áæçûÔU'ý]¿Å¨£Sõ#/ J®ýá—Ò>ý{pæWi.ò#/¹ÿÜZXßæ§wú¿ì†¯SüþÓúùµµ™ù#¥l³·¢1¡¨zeë¢×Ç¥vñ‰’©œ~®yËAƒSù>¶ÉÓ¶ˆÄÆVJsøzK„pYkϼ#Dâ¢ZÍÆ! ^G¿§,ÀŠÃ$ Œ}ûYOÎÏužº6³8•È'ÇõçÙL*Ï«Ï£o3¸žÍ~ŸWüÕ‘àRsŒâ;Ó¹j¬b/È5Y_ç²V7Ä|¤É{~¯ÿþ.äŠp¡ Ú‹ê– -#<== -#-----BEGIN PGP SIGNATURE-----\nVersion: GnuPG v2\n\niQIcBAABCgAGBQJWpU3oAAoJEGelZe39+Q5kv04P/iyvALGAg2Z8oICEDjFkEXWW\nh2CMGLItAhqb3xNeV8WUMMpY4MbRRpN6cU/SPmt+as4oVn2pozca93eWD7yOxukK\n10seOyLTBamS0Wf+BNr6jYXZRQ2N7inc2p6AD75pMOFSg2HeIeQJ0aUIAxNeeojZ\nmUiLYMdtcrF1Kh7KWZAkYSbIAEjJeobLqk2oY7UyqKcODc4RtZJV1InnO4DItEWD\nnd3F5kkVMw4pwYAXaikmCXYBKHXdF5w82KxqEjrAWSoULipX0BVCsSbQ2L0UOs5h\nKXUS4M7AaYKyCcO17E7CnVXaW+vOVyGEECxtSaExWgK5MvYHIGE1OFvb12PkUvUY\nc7CiBxk6X5eZkPyxgxDj20r8zNQVGZ8jDI8Wg08yTAl8+09qCtkE8gGMdNeHYwX8\n2xDH+A3+19022ZZdyO2t5+2AzU6Kkl1qTPKaXJWFRtr8ApD45Y4D3/GAsTNqdOMi\nWeh1XvqQdHjm9rEoJX8aBXShzCMCNhmZalbUhrdzQY6/hnl0PqnlPtyvtkjCvWoF\nXLF6q8YV/ZtqCc36vePZ6lpUQB6FG3g6fhMGraT2VOmT3TROcG17pqIz5y9+85xy\nVSaDc82uHlyzIsZ7vuhV6d9x4yXnFkjMAogCJv6mitFbQsd+LtXYkU+2Zq6wOoEp\ndLLfK0Km4Vs9FYAUbuUi\n=7D7V\n-----END PGP SIGNATURE-----\n diff --git a/gomspace/libgscsp/lib/libcsp/wscript b/gomspace/libgscsp/lib/libcsp/wscript deleted file mode 100644 index 7b9cbdba..00000000 --- a/gomspace/libgscsp/lib/libcsp/wscript +++ /dev/null @@ -1,346 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 - -# Cubesat Space Protocol - A small network-layer protocol designed for Cubesats -# Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com) -# Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk) -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -import os - -APPNAME = 'libcsp' -VERSION = '1.5' - -top = '.' -out = 'build' - -def options(ctx): - # Load GCC options - ctx.load('gcc') - - ctx.add_option('--toolchain', default=None, help='Set toolchain prefix') - - # Set libcsp options - gr = ctx.add_option_group('libcsp options') - gr.add_option('--includes', default='', help='Add additional include paths. Separate with comma') - gr.add_option('--install-csp', action='store_true', help='Installs CSP headers and lib') - - gr.add_option('--disable-output', action='store_true', help='Disable CSP output') - gr.add_option('--disable-stlib', action='store_true', help='Build objects only') - gr.add_option('--enable-rdp', action='store_true', help='Enable RDP support') - gr.add_option('--enable-qos', action='store_true', help='Enable Quality of Service support') - gr.add_option('--enable-promisc', action='store_true', help='Enable promiscuous mode support') - gr.add_option('--enable-crc32', action='store_true', help='Enable CRC32 support') - gr.add_option('--enable-hmac', action='store_true', help='Enable HMAC-SHA1 support') - gr.add_option('--enable-xtea', action='store_true', help='Enable XTEA support') - gr.add_option('--enable-bindings', action='store_true', help='Enable Python bindings') - gr.add_option('--enable-python3-bindings', action='store_true', help='Enable Python3 bindings') - gr.add_option('--enable-examples', action='store_true', help='Enable examples') - gr.add_option('--enable-dedup', action='store_true', help='Enable packet deduplicator') - - # Interfaces - gr.add_option('--enable-if-i2c', action='store_true', help='Enable I2C interface') - gr.add_option('--enable-if-kiss', action='store_true', help='Enable KISS/RS.232 interface') - gr.add_option('--enable-if-can', action='store_true', help='Enable CAN interface') - gr.add_option('--enable-if-zmqhub', action='store_true', help='Enable ZMQHUB interface') - - # Drivers - gr.add_option('--enable-can-socketcan', action='store_true', help='Enable Linux socketcan driver') - gr.add_option('--with-driver-usart', default=None, metavar='DRIVER', help='Build USART driver. [windows, linux, None]') - - # OS - gr.add_option('--with-os', metavar='OS', default='posix', help='Set operating system. Must be either \'posix\', \'macosx\', \'windows\' or \'freertos\'') - gr.add_option('--enable-init-shutdown', action='store_true', help='Use init system commands for shutdown/reboot') - - # Options - gr.add_option('--with-rdp-max-window', metavar='SIZE', type=int, default=20, help='Set maximum window size for RDP') - gr.add_option('--with-max-bind-port', metavar='PORT', type=int, default=31, help='Set maximum bindable port') - gr.add_option('--with-max-connections', metavar='COUNT', type=int, default=10, help='Set maximum number of concurrent connections') - gr.add_option('--with-conn-queue-length', metavar='SIZE', type=int, default=100, help='Set maximum number of packets in queue for a connection') - gr.add_option('--with-router-queue-length', metavar='SIZE', type=int, default=10, help='Set maximum number of packets to be queued at the input of the router') - gr.add_option('--with-padding', metavar='BYTES', type=int, default=8, help='Set padding bytes before packet length field') - gr.add_option('--with-loglevel', metavar='LEVEL', default='debug', help='Set minimum compile time log level. Must be one of \'error\', \'warn\', \'info\' or \'debug\'') - gr.add_option('--with-rtable', metavar='TABLE', default='static', help='Set routing table type') - gr.add_option('--with-connection-so', metavar='CSP_SO', type=int, default='0x0000', help='Set outgoing connection socket options, see csp.h for valid values') - gr.add_option('--with-bufalign', metavar='BYTES', type=int, help='Set buffer alignment') - -def configure(ctx): - # Validate OS - if not ctx.options.with_os in ('posix', 'windows', 'freertos', 'macosx'): - ctx.fatal('--with-os must be either \'posix\', \'windows\', \'macosx\' or \'freertos\'') - - # Validate USART drivers - if not ctx.options.with_driver_usart in (None, 'windows', 'linux'): - ctx.fatal('--with-driver-usart must be either \'windows\' or \'linux\'') - - if not ctx.options.with_loglevel in ('error', 'warn', 'info', 'debug'): - ctx.fatal('--with-loglevel must be either \'error\', \'warn\', \'info\' or \'debug\'') - - # Setup and validate toolchain - if (len(ctx.stack_path) <= 1) and ctx.options.toolchain: - ctx.env.CC = ctx.options.toolchain + 'gcc' - ctx.env.AR = ctx.options.toolchain + 'ar' - - ctx.load('gcc') - - # Set git revision define - git_rev = os.popen('git describe --always 2> /dev/null || echo unknown').read().strip() - - # Setup DEFINES - ctx.define('GIT_REV', git_rev) - - # Set build output format - ctx.env.FEATURES = ['c'] - if not ctx.options.disable_stlib: - ctx.env.FEATURES += ['cstlib'] - - # Setup CFLAGS - if (len(ctx.stack_path) <= 1) and (len(ctx.env.CFLAGS) == 0): - ctx.env.prepend_value('CFLAGS', ["-std=gnu99", "-g", "-Os", "-Wall", "-Wextra", "-Wshadow", "-Wcast-align", "-Wwrite-strings", "-Wno-unused-parameter"]) - - # Setup extra includes - ctx.env.append_unique('INCLUDES_CSP', ['include'] + ctx.options.includes.split(',')) - - # Add default files - ctx.env.append_unique('FILES_CSP', ['src/*.c','src/interfaces/csp_if_lo.c','src/transport/csp_udp.c','src/arch/{0}/**/*.c'.format(ctx.options.with_os)]) - - # Store OS as env variable - ctx.env.append_unique('OS', ctx.options.with_os) - - # Libs - if 'posix' in ctx.env.OS: - ctx.env.append_unique('LIBS', ['rt', 'pthread', 'util']) - elif 'macosx' in ctx.env.OS: - ctx.env.append_unique('LIBS', ['pthread']) - - # Check for recursion - if ctx.path == ctx.srcnode: - ctx.options.install_csp = True - - # Windows build flags - if ctx.options.with_os == 'windows': - ctx.env.append_unique('CFLAGS', ['-D_WIN32_WINNT=0x0600']) - - ctx.define_cond('CSP_FREERTOS', ctx.options.with_os == 'freertos') - ctx.define_cond('CSP_POSIX', ctx.options.with_os == 'posix') - ctx.define_cond('CSP_WINDOWS', ctx.options.with_os == 'windows') - ctx.define_cond('CSP_MACOSX', ctx.options.with_os == 'macosx') - - # Add CAN driver - if ctx.options.enable_can_socketcan: - ctx.env.append_unique('FILES_CSP', 'src/drivers/can/can_socketcan.c') - - # Add USART driver - if ctx.options.with_driver_usart != None: - ctx.env.append_unique('FILES_CSP', 'src/drivers/usart/usart_{0}.c'.format(ctx.options.with_driver_usart)) - - # Interfaces - if ctx.options.enable_if_can: - ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_can.c') - ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_can_pbuf.c') - if ctx.options.enable_if_i2c: - ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_i2c.c') - if ctx.options.enable_if_kiss: - ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_kiss.c') - if ctx.options.enable_if_zmqhub: - ctx.env.append_unique('FILES_CSP', 'src/interfaces/csp_if_zmqhub.c') - ctx.check_cfg(package='libzmq', args='--cflags --libs') - ctx.env.append_unique('LIBS', ctx.env.LIB_LIBZMQ) - - # Store configuration options - ctx.env.ENABLE_BINDINGS = ctx.options.enable_bindings - ctx.env.ENABLE_EXAMPLES = ctx.options.enable_examples - - # Check for python development - if ctx.options.enable_bindings: - ctx.env.LIBCSP_PYTHON2 = ctx.check_cfg(package='python2', args='--cflags --libs', atleast_version='2.7', mandatory=False) - if ctx.options.enable_python3_bindings: - ctx.env.LIBCSP_PYTHON3 = ctx.check_cfg(package='python3', args='--cflags --libs', atleast_version='3.5', mandatory=False) - - # Create config file - if not ctx.options.disable_output: - ctx.env.append_unique('FILES_CSP', 'src/csp_debug.c') - else: - ctx.env.append_unique('EXCL_CSP', 'src/csp_debug.c') - - if ctx.options.enable_rdp: - ctx.env.append_unique('FILES_CSP', 'src/transport/csp_rdp.c') - - if ctx.options.enable_crc32: - ctx.env.append_unique('FILES_CSP', 'src/csp_crc32.c') - else: - ctx.env.append_unique('EXCL_CSP', 'src/csp_crc32.c') - - if not ctx.options.enable_dedup: - ctx.env.append_unique('EXCL_CSP', 'src/csp_dedup.c') - - if ctx.options.enable_hmac: - ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_hmac.c') - ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_sha1.c') - - if ctx.options.enable_xtea: - ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_xtea.c') - ctx.env.append_unique('FILES_CSP', 'src/crypto/csp_sha1.c') - - ctx.env.append_unique('FILES_CSP', 'src/rtable/csp_rtable_' + ctx.options.with_rtable + '.c') - - ctx.define_cond('CSP_DEBUG', not ctx.options.disable_output) - ctx.define_cond('CSP_USE_RDP', ctx.options.enable_rdp) - ctx.define_cond('CSP_USE_CRC32', ctx.options.enable_crc32) - ctx.define_cond('CSP_USE_HMAC', ctx.options.enable_hmac) - ctx.define_cond('CSP_USE_XTEA', ctx.options.enable_xtea) - ctx.define_cond('CSP_USE_PROMISC', ctx.options.enable_promisc) - ctx.define_cond('CSP_USE_QOS', ctx.options.enable_qos) - ctx.define_cond('CSP_USE_DEDUP', ctx.options.enable_dedup) - ctx.define_cond('CSP_USE_INIT_SHUTDOWN', ctx.options.enable_init_shutdown) - ctx.define_cond('CSP_USE_CAN', ctx.options.enable_if_can) - ctx.define_cond('CSP_USE_I2C', ctx.options.enable_if_i2c) - ctx.define_cond('CSP_USE_KISS', ctx.options.enable_if_kiss) - ctx.define_cond('CSP_USE_ZMQHUB', ctx.options.enable_if_zmqhub) - ctx.define('CSP_CONN_MAX', ctx.options.with_max_connections) - ctx.define('CSP_CONN_QUEUE_LENGTH', ctx.options.with_conn_queue_length) - ctx.define('CSP_FIFO_INPUT', ctx.options.with_router_queue_length) - ctx.define('CSP_MAX_BIND_PORT', ctx.options.with_max_bind_port) - ctx.define('CSP_RDP_MAX_WINDOW', ctx.options.with_rdp_max_window) - ctx.define('CSP_PADDING_BYTES', ctx.options.with_padding) - ctx.define('CSP_CONNECTION_SO', ctx.options.with_connection_so) - - if ctx.options.with_bufalign != None: - ctx.define('CSP_BUFFER_ALIGN', ctx.options.with_bufalign) - - # Set logging level - ctx.define_cond('CSP_LOG_LEVEL_DEBUG', ctx.options.with_loglevel in ('debug')) - ctx.define_cond('CSP_LOG_LEVEL_INFO', ctx.options.with_loglevel in ('debug', 'info')) - ctx.define_cond('CSP_LOG_LEVEL_WARN', ctx.options.with_loglevel in ('debug', 'info', 'warn')) - ctx.define_cond('CSP_LOG_LEVEL_ERROR', ctx.options.with_loglevel in ('debug', 'info', 'warn', 'error')) - - # Check compiler endianness - endianness = ctx.check_endianness() - ctx.define_cond('CSP_LITTLE_ENDIAN', endianness == 'little') - ctx.define_cond('CSP_BIG_ENDIAN', endianness == 'big') - - # Check for stdbool.h - ctx.check_cc(header_name='stdbool.h', mandatory=False, define_name='CSP_HAVE_STDBOOL_H', type='cstlib') - - # Check for libsocketcan.h - if ctx.options.enable_if_can and ctx.options.enable_can_socketcan: - have_socketcan = ctx.check_cc(lib='socketcan', mandatory=False, define_name='CSP_HAVE_LIBSOCKETCAN') - if have_socketcan: - ctx.env.append_unique('LIBS', ['socketcan']) - - ctx.define('LIBCSP_VERSION', VERSION) - - ctx.write_config_header('include/csp/csp_autoconfig.h') - -def build(ctx): - - # Set install path for header files - install_path = False - if ctx.options.install_csp: - install_path = '${PREFIX}/lib' - ctx.install_files('${PREFIX}/include/csp', ctx.path.ant_glob('include/csp/*.h')) - ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_lo.h') - - if 'src/interfaces/csp_if_can.c' in ctx.env.FILES_CSP: - ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_can.h') - if 'src/interfaces/csp_if_i2c.c' in ctx.env.FILES_CSP: - ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_i2c.h') - if 'src/interfaces/csp_if_kiss.c' in ctx.env.FILES_CSP: - ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_kiss.h') - if 'src/interfaces/csp_if_zmqhub.c' in ctx.env.FILES_CSP: - ctx.install_files('${PREFIX}/include/csp/interfaces', 'include/csp/interfaces/csp_if_zmqhub.h') - if 'src/drivers/usart/usart_{0}.c'.format(ctx.options.with_driver_usart) in ctx.env.FILES_CSP: - ctx.install_as('${PREFIX}/include/csp/drivers/usart.h', 'include/csp/drivers/usart.h') - if 'src/drivers/can/can_socketcan.c' in ctx.env.FILES_CSP: - ctx.install_as('${PREFIX}/include/csp/drivers/can_socketcan.h', 'include/csp/drivers/can_socketcan.h') - - ctx.install_files('${PREFIX}/include/csp', 'include/csp/csp_autoconfig.h', cwd=ctx.bldnode) - - ctx(export_includes='include', name='csp_h') - - ctx(features=ctx.env.FEATURES, - source=ctx.path.ant_glob(ctx.env.FILES_CSP, excl=ctx.env.EXCL_CSP), - target = 'csp', - includes= ctx.env.INCLUDES_CSP, - export_includes = ctx.env.INCLUDES_CSP, - use = 'include freertos_h', - install_path = install_path, - ) - - # Build shared library for Python bindings - if ctx.env.ENABLE_BINDINGS: - ctx.shlib(source = ctx.path.ant_glob(ctx.env.FILES_CSP, excl=ctx.env.EXCL_CSP), - name = 'csp_shlib', - target = 'csp', - includes = ctx.env.INCLUDES_CSP, - export_includes = 'include', - use = ['include'], - lib = ctx.env.LIBS) - - # python3 bindings - if ctx.env.LIBCSP_PYTHON3: - ctx.shlib(source = ['src/bindings/python/pycsp.c'], - target = 'csp_py3', - includes = ctx.env.INCLUDES_CSP + ctx.env.INCLUDES_PYTHON3, - export_includes = 'include', - use = ['csp_shlib', 'include'], - lib = ctx.env.LIBS) - - # python2 bindings - if ctx.env.LIBCSP_PYTHON2: - ctx.shlib(source = ['src/bindings/python/pycsp.c'], - target = 'csp_py2', - includes = ctx.env.INCLUDES_CSP + ctx.env.INCLUDES_PYTHON2, - export_includes = 'include', - use = ['csp_shlib', 'include'], - lib = ctx.env.LIBS) - - if ctx.env.ENABLE_EXAMPLES: - ctx.program(source = ctx.path.ant_glob('examples/simple.c'), - target = 'simple', - includes = ctx.env.INCLUDES_CSP, - lib = ctx.env.LIBS, - use = 'csp') - - if ctx.options.enable_if_kiss: - ctx.program(source = 'examples/kiss.c', - target = 'kiss', - includes = ctx.env.INCLUDES_CSP, - lib = ctx.env.LIBS, - use = 'csp') - - if ctx.options.enable_if_zmqhub: - ctx.program(source = 'examples/zmqproxy.c', - target = 'zmqproxy', - includes = ctx.env.INCLUDES_CSP, - lib = ctx.env.LIBS, - use = 'csp') - - if 'posix' in ctx.env.OS: - ctx.program(source = 'examples/csp_if_fifo.c', - target = 'fifo', - includes = ctx.env.INCLUDES_CSP, - lib = ctx.env.LIBS, - use = 'csp') - - if 'windows' in ctx.env.OS: - ctx.program(source = ctx.path.ant_glob('examples/csp_if_fifo_windows.c'), - target = 'csp_if_fifo', - includes = ctx.env.INCLUDES_CSP, - use = 'csp') - -def dist(ctx): - ctx.excl = 'build/* **/.* **/*.pyc **/*.o **/*~ *.tar.gz' diff --git a/gomspace/libgscsp/src/bindings/python/pygscsp.c b/gomspace/libgscsp/src/bindings/python/pygscsp.c deleted file mode 100644 index c69d346b..00000000 --- a/gomspace/libgscsp/src/bindings/python/pygscsp.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -#include - -#include - -#if PY_MAJOR_VERSION == 3 -#define IS_PY3 -#endif - -/* gs_error_t gs_csp_i2c_init(uint8_t device, uint8_t csp_addr); */ -static PyObject* pygscsp_csp_i2c_init(PyObject *self, PyObject *args) { - uint8_t device; - uint8_t csp_addr; - - if (!PyArg_ParseTuple(args, "BB", &device, &csp_addr)) { - Py_RETURN_NONE; - } - - return Py_BuildValue("i", gs_csp_i2c_init(device, csp_addr)); -} - - -static PyMethodDef methods[] = { - - {"i2c_init", pygscsp_csp_i2c_init, METH_VARARGS, ""}, - - /* sentinel */ - {NULL, NULL, 0, NULL} -}; - -#ifdef IS_PY3 -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "libgscsp_py3", - NULL, - -1, - methods, - NULL, - NULL, - NULL, - NULL -}; -#endif - -#ifdef IS_PY3 -PyMODINIT_FUNC PyInit_libgscsp_py3(void) { -#else -PyMODINIT_FUNC initlibgscsp_py2(void) { -#endif - -#ifdef IS_PY3 - PyObject* m = PyModule_Create(&moduledef); -#else - Py_InitModule("libgscsp_py2", methods); -#endif - -#ifdef IS_PY3 - return m; -#endif - } - diff --git a/gomspace/libgscsp/src/clock.c b/gomspace/libgscsp/src/clock.c deleted file mode 100644 index 9e9a7d53..00000000 --- a/gomspace/libgscsp/src/clock.c +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Required by libcsp. - Proto-typed in ./libcsp/include/csp/arch/csp_clock.h, but with different argumet! - - __attribute__((weak)) extern void clock_get_time(csp_timestamp_t * time); - __attribute__((weak)) extern void clock_set_time(csp_timestamp_t * time); -*/ - -#include -#include - -void clock_get_time(csp_timestamp_t * time) -{ - gs_clock_get_time((gs_timestamp_t*)time); -} - -void clock_set_time(csp_timestamp_t * time) -{ - gs_clock_set_time((gs_timestamp_t*)time); -} diff --git a/gomspace/libgscsp/src/commands.c b/gomspace/libgscsp/src/commands.c deleted file mode 100644 index 6abd3019..00000000 --- a/gomspace/libgscsp/src/commands.c +++ /dev/null @@ -1,652 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static gs_error_t parse_node_timeout(gs_command_context_t *ctx, int node_index, uint8_t * node, int timeout_index, uint32_t * timeout) -{ - gs_error_t error = GS_OK; - if (node) { - *node = csp_get_address(); - - if (ctx->argc > node_index) { - error = gs_string_to_uint8(ctx->argv[node_index], node); - } - } - - if (timeout && (error == GS_OK)) { - *timeout = 1000; - - if (ctx->argc > timeout_index) { - error = gs_string_to_uint32(ctx->argv[timeout_index], timeout); - } - } - - return error; -} - -static int cmd_ping(gs_command_context_t *ctx) -{ - uint8_t node; - uint32_t timeout; - int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); - if (res) { - return res; - } - - uint32_t size = 1; - if ((ctx->argc > 3) && (gs_string_to_uint32(ctx->argv[3], &size) != GS_OK)) { - return GS_ERROR_ARG; - } - - uint32_t options = CSP_O_NONE; - if (ctx->argc > 4) { - const char * features = ctx->argv[4]; - if (strchr(features, 'r')) - options |= CSP_O_RDP; - if (strchr(features, 'x')) - options |= CSP_O_XTEA; - if (strchr(features, 'h')) - options |= CSP_O_HMAC; - if (strchr(features, 'c')) - options |= CSP_O_CRC32; - } - - printf("Ping node %u, timeout %" PRIu32 ", size %" PRIu32 ": options: 0x%" PRIx32 " ... ", node, timeout, size, options); - - const uint64_t start = gs_clock_get_nsec(); - const int time = csp_ping(node, timeout, size, options); - const uint64_t stop = gs_clock_get_nsec(); - const float elapsed = (((float)(stop - start)) / 1E6); - if (time < 0) { - printf("timeout after %.03f ms\r\n", elapsed); - return GS_ERROR_TIMEOUT; - } - - printf("reply in %.03f ms\r\n", elapsed); - - return GS_OK; -} - -static int cmd_ps(gs_command_context_t *ctx) -{ - uint8_t node; - uint32_t timeout; - int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); - if (res) { - return res; - } - - csp_ps(node, timeout); - - return GS_OK; -} - -static int cmd_memfree(gs_command_context_t *ctx) -{ - uint8_t node; - uint32_t timeout; - int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); - if (res) { - return res; - } - - csp_memfree(node, timeout); - - return GS_OK; -} - -static int cmd_reboot(gs_command_context_t *ctx) -{ - if (ctx->argc < 2) { - return GS_ERROR_ARG; - } - uint8_t node; - int res = parse_node_timeout(ctx, 1, &node, 0, NULL); - if (res) { - return res; - } - - csp_reboot(node); - - return GS_OK; -} - -static int cmd_shutdown(gs_command_context_t *ctx) -{ - if (ctx->argc < 2) { - return GS_ERROR_ARG; - } - uint8_t node; - int res = parse_node_timeout(ctx, 1, &node, 0, NULL); - if (res) { - return res; - } - - csp_shutdown(node); - - return GS_OK; -} - -static int cmd_buf_free(gs_command_context_t *ctx) -{ - uint8_t node; - uint32_t timeout; - int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); - if (res) { - return res; - } - - csp_buf_free(node, timeout); - - return GS_OK; -} - -static int cmd_uptime(gs_command_context_t *ctx) -{ - uint8_t node; - uint32_t timeout; - int res = parse_node_timeout(ctx, 1, &node, 2, &timeout); - if (res) { - return res; - } - - csp_uptime(node, timeout); - - return GS_OK; -} - -#ifdef CSP_DEBUG - -static int cmd_csp_route_print_table(gs_command_context_t *ctx) -{ - csp_route_print_table(); - return GS_OK; -} - -static int cmd_csp_route_print_interfaces(gs_command_context_t *ctx) -{ - csp_route_print_interfaces(); - return GS_OK; -} - -static int cmd_csp_conn_print_table(gs_command_context_t *ctx) -{ - csp_conn_print_table(); - return GS_OK; -} - -#endif - -#if CSP_USE_RDP -static int cmd_csp_rdp_set_opt(gs_command_context_t *ctx) -{ - if (ctx->argc < 7) { - return GS_ERROR_ARG; - } - int res; - uint32_t window_size; - if ((res = gs_string_to_uint32(ctx->argv[1], &window_size))) { - return res; - } - uint32_t conn_timeout; - if ((res = gs_string_to_uint32(ctx->argv[2], &conn_timeout))) { - return res; - } - uint32_t packet_timeout; - if ((res = gs_string_to_uint32(ctx->argv[3], &packet_timeout))) { - return res; - } - uint32_t delayed_acks; - if ((res = gs_string_to_uint32(ctx->argv[4], &delayed_acks))) { - return res; - } - uint32_t ack_timeout; - if ((res = gs_string_to_uint32(ctx->argv[5], &ack_timeout))) { - return res; - } - uint32_t ack_delay_count; - if ((res = gs_string_to_uint32(ctx->argv[6], &ack_delay_count))) { - return res; - } - - printf("Setting arguments to: window size %" PRIu32 ", conn timeout %" PRIu32 ", packet timeout %" PRIu32 ", delayed acks %" PRIu32 ", ack timeout %" PRIu32 ", ack delay count %" PRIu32 "\r\n", - window_size, conn_timeout, packet_timeout, delayed_acks, ack_timeout, ack_delay_count); - - csp_rdp_set_opt(window_size, conn_timeout, packet_timeout, delayed_acks, ack_timeout, ack_delay_count); - - return GS_OK; -} -#endif - -static int cmd_cmp_ident(gs_command_context_t *ctx) -{ - uint8_t node; - uint32_t timeout; - int ret = parse_node_timeout(ctx, 1, &node, 2, &timeout); - if (ret) { - return ret; - } - - struct csp_cmp_message msg; - - ret = csp_cmp_ident(node, timeout, &msg); - if (ret != CSP_ERR_NONE) { - printf("CSP error: %d\r\n", ret); - return gs_csp_error(ret);; - } - - printf("Hostname: %s\r\n", msg.ident.hostname); - printf("Model: %s\r\n", msg.ident.model); - printf("Revision: %s\r\n", msg.ident.revision); - printf("Date: %s\r\n", msg.ident.date); - printf("Time: %s\r\n", msg.ident.time); - - return GS_OK; -} - -static int cmd_cmp_route_set(gs_command_context_t *ctx) -{ - if (ctx->argc != 6) - return GS_ERROR_ARG; - - uint8_t node = atoi(ctx->argv[1]); - uint32_t timeout = atoi(ctx->argv[2]); - printf("Sending route_set to node %"PRIu8" timeout %"PRIu32"\r\n", node, timeout); - - struct csp_cmp_message msg; - msg.route_set.dest_node = atoi(ctx->argv[3]); - msg.route_set.next_hop_mac = atoi(ctx->argv[4]); - strncpy(msg.route_set.interface, ctx->argv[5], 10); - printf("Dest_node: %u, next_hop_mac: %u, interface %s\r\n", msg.route_set.dest_node, msg.route_set.next_hop_mac, msg.route_set.interface); - - int ret = csp_cmp_route_set(node, timeout, &msg); - if (ret != CSP_ERR_NONE) { - printf("CSP error: %d\r\n", ret); - return gs_csp_error(ret); - } - - return GS_OK; -} - -static int cmd_cmp_ifc(gs_command_context_t *ctx) { - - uint8_t node; - uint32_t timeout; - char * interface; - - if (ctx->argc > 4 || ctx->argc < 3) - return GS_ERROR_ARG; - - node = atoi(ctx->argv[1]); - interface = ctx->argv[2]; - - if (ctx->argc < 4) - timeout = 1000; - else - timeout = atoi(ctx->argv[3]); - - struct csp_cmp_message msg; - strncpy(msg.if_stats.interface, interface, CSP_CMP_ROUTE_IFACE_LEN); - - printf("Requesting interface stats for interface %s\r\n", interface); - - int ret = csp_cmp_if_stats(node, timeout, &msg); - if (ret != CSP_ERR_NONE) { - printf("CSP error: %d\r\n", ret); - return gs_csp_error(ret); - } - - msg.if_stats.tx = csp_ntoh32(msg.if_stats.tx); - msg.if_stats.rx = csp_ntoh32(msg.if_stats.rx); - msg.if_stats.tx_error = csp_ntoh32(msg.if_stats.tx_error); - msg.if_stats.rx_error = csp_ntoh32(msg.if_stats.rx_error); - msg.if_stats.drop = csp_ntoh32(msg.if_stats.drop); - msg.if_stats.autherr = csp_ntoh32(msg.if_stats.autherr); - msg.if_stats.frame = csp_ntoh32(msg.if_stats.frame); - msg.if_stats.txbytes = csp_ntoh32(msg.if_stats.txbytes); - msg.if_stats.rxbytes = csp_ntoh32(msg.if_stats.rxbytes); - msg.if_stats.irq = csp_ntoh32(msg.if_stats.irq); - - printf("%-5s tx: %05"PRIu32" rx: %05"PRIu32" txe: %05"PRIu32" rxe: %05"PRIu32"\r\n" - " drop: %05"PRIu32" autherr: %05"PRIu32 " frame: %05"PRIu32"\r\n" - " txb: %"PRIu32" rxb: %"PRIu32"\r\n\r\n", - msg.if_stats.interface, msg.if_stats.tx, msg.if_stats.rx, msg.if_stats.tx_error, msg.if_stats.rx_error, msg.if_stats.drop, - msg.if_stats.autherr, msg.if_stats.frame, msg.if_stats.txbytes, msg.if_stats.rxbytes); - - return GS_OK; -} - -static int cmd_cmp_peek(gs_command_context_t *ctx) -{ - if ((ctx->argc != 4) && (ctx->argc != 5)) - return GS_ERROR_ARG; - - uint8_t node; - uint32_t timeout; - int res = parse_node_timeout(ctx, 1, &node, 4, &timeout); - if (res) { - return res; - } - - uint32_t addr; - if (gs_string_to_uint32(ctx->argv[2], &addr)) { - return GS_ERROR_ARG; - } - - uint32_t len; - if (gs_string_to_uint32(ctx->argv[3], &len)) { - return GS_ERROR_ARG; - } - if (len > CSP_CMP_PEEK_MAX_LEN) { - return GS_ERROR_RANGE; - } - - printf("Dumping mem from node %u addr 0x%"PRIx32" len %"PRIx32" timeout %"PRIu32"\r\n", node, addr, len, timeout); - - struct csp_cmp_message msg; - msg.peek.addr = csp_hton32(addr); - msg.peek.len = len; - - int ret = csp_cmp_peek(node, timeout, &msg); - if (ret != CSP_ERR_NONE) { - printf("CSP error: %d\r\n", ret); - return gs_csp_error(ret); - } - - gs_hexdump_addr(msg.peek.data, len, GS_TYPES_UINT2PTR(addr)); - - return GS_OK; -} - -static int cmd_cmp_poke(gs_command_context_t *ctx) -{ - if ((ctx->argc != 4) && (ctx->argc != 5)) - return GS_ERROR_ARG; - - uint8_t node; - uint32_t timeout; - int res = parse_node_timeout(ctx, 1, &node, 4, &timeout); - if (res) { - return res; - } - - uint32_t addr; - if (gs_string_to_uint32(ctx->argv[2], &addr)) { - return GS_ERROR_ARG; - } - - unsigned char data[CSP_CMP_POKE_MAX_LEN]; - uint32_t len = base16_decode(ctx->argv[3], data); - if (len > CSP_CMP_PEEK_MAX_LEN) { - printf("Max length is: %u\r\n", CSP_CMP_PEEK_MAX_LEN); - return GS_ERROR_RANGE; - } - - printf("Writing to mem at node %u addr 0x%"PRIx32" len %"PRIx32" timeout %"PRIu32"\r\n", node, addr, len, timeout); - gs_hexdump_addr(data, len, GS_TYPES_UINT2PTR(addr)); - - struct csp_cmp_message msg; - msg.poke.addr = csp_hton32(addr); - msg.poke.len = len; - memcpy(msg.poke.data, data, CSP_CMP_POKE_MAX_LEN); - - int ret = csp_cmp_poke(node, timeout, &msg); - if (ret != CSP_ERR_NONE) { - printf("CSP error: %d\r\n", ret); - return gs_csp_error(ret); - } - - return GS_OK; -} - -static int cmd_cmp_clock(gs_command_context_t *ctx, uint32_t node, uint32_t timeout, const gs_timestamp_t * set) -{ - char tbuf[GS_CLOCK_ISO8601_BUFFER_LENGTH]; - struct csp_cmp_message msg; - memset(&msg, 0, sizeof(msg)); - - if (set) { - gs_clock_to_iso8601_string(set, tbuf, sizeof(tbuf)); - printf("Set time: %s (%" PRIu32 ".%09" PRIu32 " sec)\r\n", tbuf, set->tv_sec, set->tv_nsec); - msg.clock.tv_sec = csp_hton32(set->tv_sec); - msg.clock.tv_nsec = csp_hton32(set->tv_nsec); - } - - gs_timestamp_t t1, t2; - gs_clock_get_time(&t1); - int ret = csp_cmp_clock(node, timeout, &msg); - if (ret != CSP_ERR_NONE) { - return gs_csp_error(ret); - } - gs_clock_get_time(&t2); - - /* Calculate round-trip time */ - const int64_t rtt = ((uint64_t)t2.tv_sec * 1000000000 + t2.tv_nsec) - ((uint64_t)t1.tv_sec * 1000000000 + t1.tv_nsec); - - gs_timestamp_t timestamp; - timestamp.tv_sec = csp_ntoh32(msg.clock.tv_sec); - timestamp.tv_nsec = csp_ntoh32(msg.clock.tv_nsec); - - gs_clock_to_iso8601_string(×tamp, tbuf, sizeof(tbuf)); - printf("Get time: %s (%" PRIu32 ".%09" PRIu32 " sec)\r\n", tbuf, timestamp.tv_sec, timestamp.tv_nsec); - - /* Calculate time difference to local clock. This takes the round-trip - * into account, but assumes a symmetrical link */ - const int64_t remote = (uint64_t)timestamp.tv_sec * 1000000000 + timestamp.tv_nsec; - const int64_t local = (uint64_t)t1.tv_sec * 1000000000 + t1.tv_nsec + rtt / 2; - - const double diff = (remote - local) / 1000000.0; - printf("Remote is %f ms %s local time\r\n", fabs(diff), diff > 0 ? "ahead of" : "behind"); - - return GS_OK; -} - -static int cmd_cmp_clock_get(gs_command_context_t *ctx) -{ - if (ctx->argc < 2) { - return GS_ERROR_ARG; - } - - uint32_t node; - if (gs_string_to_uint32(ctx->argv[1], &node) != GS_OK) { - return GS_ERROR_ARG; - } - - uint32_t timeout = 1000; - if (ctx->argc > 2) { - if (gs_string_to_uint32(ctx->argv[2], &timeout) != GS_OK) { - return GS_ERROR_ARG; - } - } - - return cmd_cmp_clock(ctx, node, timeout, NULL); -} - -static int cmd_cmp_clock_set(gs_command_context_t *ctx) -{ - if (ctx->argc < 3) { - return GS_ERROR_ARG; - } - - uint32_t node; - if (gs_string_to_uint32(ctx->argv[1], &node) != GS_OK) { - return GS_ERROR_ARG; - } - - gs_timestamp_t ts; - if (gs_clock_from_string(ctx->argv[2], &ts) != GS_OK) { - return GS_ERROR_ARG; - } - - uint32_t timeout = 1000; - if (ctx->argc > 3) { - if (gs_string_to_uint32(ctx->argv[3], &timeout) != GS_OK) { - return GS_ERROR_ARG; - } - } - - return cmd_cmp_clock(ctx, node, timeout, &ts); -} - -static int cmd_cmp_clock_sync(gs_command_context_t *ctx) -{ - if (ctx->argc < 2) { - return GS_ERROR_ARG; - } - - uint32_t node; - if (gs_string_to_uint32(ctx->argv[1], &node) != GS_OK) { - return GS_ERROR_ARG; - } - - uint32_t timeout = 1000; - if (ctx->argc > 2) { - if (gs_string_to_uint32(ctx->argv[2], &timeout) != GS_OK) { - return GS_ERROR_ARG; - } - } - - gs_timestamp_t ts; - gs_clock_get_time(&ts); - - return cmd_cmp_clock(ctx, node, timeout, &ts); -} - -static const gs_command_t GS_COMMAND_SUB cmp_clock_commands[] = { - { - .name = "get", - .help = "Get clock on ", - .usage = " [timeout]", - .handler = cmd_cmp_clock_get, - }, - { - .name = "set", - .help = "Set time of ", - .usage = " [timeout]", - .handler = cmd_cmp_clock_set, - }, - { - .name = "sync", - .help = "Sync/set time of to time of this node", - .usage = " [timeout]", - .handler = cmd_cmp_clock_sync, - } -}; - -static const gs_command_t GS_COMMAND_SUB cmp_commands[] = { - { - .name = "ident", - .help = "Node id", - .usage = "[node] [timeout]", - .handler = cmd_cmp_ident, - },{ - .name = "route_set", - .help = "Update table", - .usage = " ", - .handler = cmd_cmp_route_set, - },{ - .name = "ifc", - .help = "Remote IFC", - .usage = " [timeout]", - .handler = cmd_cmp_ifc, - },{ - .name = "peek", - .help = "Show remote memory", - .usage = " [timeout]", - .handler = cmd_cmp_peek, - },{ - .name = "poke", - .help = "Modify remote memory", - .usage = " [timeout]", - .handler = cmd_cmp_poke, - },{ - .name = "clock", - .help = "Get/set clock", - .chain = GS_COMMAND_INIT_CHAIN(cmp_clock_commands), - } -}; - -static const gs_command_t GS_COMMAND_ROOT csp_commands[] = { - { - .name = "ping", - .help = "csp: Ping", - .usage = "[node] [timeout] [size] [opt: r|x|h|c]", - .handler = cmd_ping, - },{ - .name = "rps", - .help = "csp: Remote ps", - .usage = "[node] [timeout]", - .handler = cmd_ps, - },{ - .name = "memfree", - .help = "csp: Memory free", - .usage = "[node] [timeout]", - .handler = cmd_memfree, - },{ - .name = "buffree", - .help = "csp: Buffer free", - .usage = "[node] [timeout]", - .handler = cmd_buf_free, - },{ - .name = "reboot", - .help = "csp: Reboot", - .usage = "", - .handler = cmd_reboot, - },{ - .name = "shutdown", - .help = "csp: Shutdown", - .usage = "", - .handler = cmd_shutdown, - },{ - .name = "uptime", - .help = "csp: Uptime", - .usage = "[node] [timeout]", - .handler = cmd_uptime, - },{ - .name = "cmp", - .help = "csp: Management", - .chain = GS_COMMAND_INIT_CHAIN(cmp_commands), - }, -#ifdef CSP_DEBUG - { - .name = "route", - .help = "csp: Show routing table", - .handler = cmd_csp_route_print_table, - },{ - .name = "ifc", - .help = "csp: Show interfaces", - .handler = cmd_csp_route_print_interfaces, - },{ - .name = "conn", - .help = "csp: Show connection table", - .handler = cmd_csp_conn_print_table, - }, -#endif -#if CSP_USE_RDP - { - .name = "rdpopt", - .help = "csp: Set RDP options", - .handler = cmd_csp_rdp_set_opt, - .usage = " " - }, -#endif -}; - -gs_error_t gs_csp_register_commands(void) -{ - return GS_COMMAND_REGISTER(csp_commands); -} diff --git a/gomspace/libgscsp/src/conn.c b/gomspace/libgscsp/src/conn.c deleted file mode 100644 index 05e6459e..00000000 --- a/gomspace/libgscsp/src/conn.c +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include <../lib/libcsp/src/csp_conn.h> // internal libcsp header - -size_t gs_csp_conn_get_open(void) -{ - size_t open = 0; - size_t max_connections; - const csp_conn_t * connections = csp_conn_get_array(&max_connections); - if (connections) { - for (unsigned int i = 0; i < max_connections; ++i) { - if (connections[i].state != CONN_CLOSED) { - ++open; - } - } - } - - // csp_conn_print_table(); - - return open; -} diff --git a/gomspace/libgscsp/src/csp.c b/gomspace/libgscsp/src/csp.c deleted file mode 100644 index 2367ec6a..00000000 --- a/gomspace/libgscsp/src/csp.c +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include "local.h" - -void gs_csp_conf_get_defaults_embedded(gs_csp_conf_t * conf) -{ - static const gs_csp_conf_t defaults = { - .use_gs_log = true, - .use_command_line_options = true, - .csp_buffer_size = 256, // typical MTU size is 256 - .csp_buffers = 10, // in case of RDP connections, must be > RDP Windows size - .address = 1, - .hostname = "hostname", - .model = "model", - .revision = "revision", - }; - - *conf = defaults; - -#if GS_CSP_COMMAND_LINE_SUPPORT - conf->address = gs_csp_command_line_get_address(); -#endif -} - -void gs_csp_conf_get_defaults_server(gs_csp_conf_t * conf) -{ - gs_csp_conf_get_defaults_embedded(conf); - conf->csp_buffer_size = 512; - conf->csp_buffers = 400; -} - -gs_error_t gs_csp_init(const gs_csp_conf_t * conf) -{ - GS_CHECK_ARG(conf != NULL); - - if (conf->use_gs_log) { - gs_csp_log_init(); - } - - int res = csp_buffer_init(conf->csp_buffers, conf->csp_buffer_size); - if (res != CSP_ERR_NONE) { - log_error("%s: csp_buffer_init(buffers: %u, size: %u) failed, CSP error: %d, error: %d", - __FUNCTION__, (unsigned int) conf->csp_buffers, (unsigned int) conf->csp_buffer_size, res, gs_csp_error(res)); - return gs_csp_error(res); - } - - csp_set_hostname(conf->hostname); - csp_set_model(conf->model); - csp_set_revision(conf->revision); - - uint8_t csp_address = conf->address; -#if GS_CSP_COMMAND_LINE_SUPPORT - if (gs_csp_command_line_is_address_set()) { - csp_address = gs_csp_command_line_get_address(); - } -#endif - - res = csp_init(csp_address); - if (res != CSP_ERR_NONE) { - log_error("%s: csp_init(address: %u) failed, CSP error: %d, error: %d", - __FUNCTION__, conf->address, res, gs_csp_error(res)); - return gs_csp_error(res); - } - -#if GS_CSP_COMMAND_LINE_SUPPORT - if (conf->use_command_line_options) { - gs_error_t error = gs_csp_command_line_configure_interfaces(); - if (error) { - log_error("%s: gs_csp_command_line_configure_interfaces() failed, error: %d", - __FUNCTION__, error); - return error; - } - } -#endif - - return GS_OK; -} - -bool gs_csp_is_address_valid(uint8_t address) -{ - if (address < 1) { - return false; - } - if (address >= 33) { - return false; - } - return true; -} diff --git a/gomspace/libgscsp/src/drivers/can/can.c b/gomspace/libgscsp/src/drivers/can/can.c deleted file mode 100644 index 965977ca..00000000 --- a/gomspace/libgscsp/src/drivers/can/can.c +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define NO_OF_CAN_CHANNELS 2 -#define MAX_NAME_LENGTH 10 // It says in csp_types.h, that it should be below 10 bytes - -// change default log group -#define LOG_DEFAULT gs_can_log - -typedef struct { - // self reference device handle - uint8_t can_ch; - // CSP interface name - char interface_name[MAX_NAME_LENGTH]; - // CSP interface - csp_iface_t interface; -} gs_csp_can_interface_t; - -static gs_csp_can_interface_t csp_can_interfaces[NO_OF_CAN_CHANNELS]; - -static void gs_csp_can_rxdata_callback_isr(int hdl, - uint32_t canMsgId, - bool extendedMsgId, - const void * data, - size_t data_size, - uint32_t nowMs, - void * user_data, - gs_context_switch_t * cswitch) -{ - csp_can_rx(&csp_can_interfaces[hdl].interface, canMsgId, data, data_size, &cswitch->task_woken); -} - -// Required by libcsp -int csp_can_tx_frame(csp_iface_t *interface, uint32_t id, const uint8_t * data, uint8_t dlc) -{ - return gs_can_send_extended(((gs_csp_can_interface_t *)interface->driver)->can_ch, id, data, dlc, 1000); -} - -gs_error_t gs_csp_can_init2(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, bool set_default_route, csp_iface_t ** csp_if) -{ - GS_CHECK_HANDLE(device < NO_OF_CAN_CHANNELS); - gs_csp_can_interface_t * interface = &csp_can_interfaces[device]; - - // Register/subscribe to CAN frames for CSP - const uint32_t can_id = CFP_MAKE_DST(csp_get_address()); - const uint32_t can_mask = CFP_MAKE_DST((1 << CFP_HOST_SIZE) - 1); - - log_debug("%s(%u): id=0x%" PRIx32 ", mask=0x%" PRIx32, __FUNCTION__, device, can_id, can_mask); - - if (gs_string_empty(name)) { - name = GS_CSP_CAN_DEFAULT_IF_NAME; - } - if (strlen(name) >= MAX_NAME_LENGTH) { - return GS_ERROR_ARG; - } - - if (csp_iflist_get_by_name(name)) { - log_error("%s(%u): name: [%s] - already exists", __FUNCTION__, device, name); - return GS_ERROR_EXIST; - } - - // hook CAN into CSP - GS_STRNCPY(interface->interface_name, name); - interface->interface.name = interface->interface_name; - interface->interface.nexthop = csp_can_tx; - interface->interface.mtu = mtu; - interface->interface.driver = interface; - - csp_iflist_add(&interface->interface); - - if (csp_if) { - *csp_if = &interface->interface; - } - - gs_error_t error = gs_can_set_extended_filter_mask(0, can_id, can_mask, gs_csp_can_rxdata_callback_isr, NULL); - if (error) { - log_error("%s: gs_can_set_extended_filter_mask() failed, error: %s", __FUNCTION__, gs_error_string(error)); - return error; - } - - error = gs_can_start(device); - if (error) { - log_error("%s: gs_can_start() failed, error: %s", __FUNCTION__, gs_error_string(error)); - return error; - } - - if (set_default_route) { - // Route all to CAN - csp_rtable_set(0, 0, &interface->interface, CSP_NODE_MAC); - } - - return GS_OK; -} - -gs_error_t gs_csp_can_init(uint8_t device, uint8_t csp_addr, uint32_t mtu, const char * name, csp_iface_t ** csp_if) -{ - return gs_csp_can_init2(device, csp_addr, mtu, name, true, csp_if); -} diff --git a/gomspace/libgscsp/src/drivers/i2c/i2c.c b/gomspace/libgscsp/src/drivers/i2c/i2c.c deleted file mode 100644 index c40cd9c8..00000000 --- a/gomspace/libgscsp/src/drivers/i2c/i2c.c +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include -#include -#include -#if !defined(__linux__) -#include -#endif - -#define E_FAIL -19 // The CSP I2C driver evaluates any other value than -1 as fail - -#define I2C_FRAME_OVERHEAD (sizeof(i2c_frame_t) - sizeof(((i2c_frame_t *)0)->data)) - -static void gs_csp_i2c_rxdata_callback_isr(uint8_t handle, const uint8_t * rx, size_t rx_length, gs_context_switch_t * cswitch) -{ - i2c_frame_t * frame = (i2c_frame_t *) (rx - I2C_FRAME_OVERHEAD); - frame->len = rx_length; -#if (__linux__) - csp_i2c_rx(frame, NULL); -#else - csp_i2c_rx(frame, &cswitch->task_woken); -#endif -} - -static void * gs_csp_i2c_get_buffer(uint8_t handle) -{ - void * buff = csp_buffer_get_isr(I2C_MTU); - if (buff != NULL) { - buff = ((uint8_t *)buff) + I2C_FRAME_OVERHEAD; - } - return buff; -} - -/** - CSP send function, required by libcsp - */ -int i2c_send(int handle, i2c_frame_t * frame, uint16_t timeout) -{ - int res_tx = gs_i2c_master_transaction(handle, frame->dest, frame->data, frame->len, 0, 0, timeout); - if (res_tx == GS_OK) { - csp_buffer_free(frame); - return E_NO_ERR; - } else { - return E_FAIL; - } -} - -/** - CSP init function, required by libcsp - */ -int i2c_init(int handle, int mode, uint8_t addr, uint16_t speed, int queue_len_tx, int queue_len_rx, - i2c_callback_t callback) -{ - if (gs_i2c_slave_set_rx(handle, gs_csp_i2c_rxdata_callback_isr) != GS_OK) { - return E_FAIL; - } - if (gs_i2c_slave_set_get_rx_buf(handle, gs_csp_i2c_get_buffer, I2C_MTU) != GS_OK) { - return E_FAIL; - } - if (gs_i2c_slave_start(handle) != GS_OK) { - return E_FAIL; - } - return E_NO_ERR; -} - -gs_error_t gs_csp_i2c_init(uint8_t device, uint8_t csp_addr) -{ - int dummy_speed = 0; // Speed not used - - /* Calls CSP I2C init, which has the I2C interface instance - From here the above "i2c_init" is called */ - return gs_csp_error(csp_i2c_init(csp_addr, device, dummy_speed)); -} diff --git a/gomspace/libgscsp/src/drivers/kiss/kiss.c b/gomspace/libgscsp/src/drivers/kiss/kiss.c deleted file mode 100644 index c3357f7d..00000000 --- a/gomspace/libgscsp/src/drivers/kiss/kiss.c +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -static csp_iface_t csp_if_kiss; -static uint8_t uart_csp_device; - -static void usart_rx_callback(void * user_data, const uint8_t * data, size_t data_size, gs_context_switch_t * cswitch) -{ - csp_kiss_rx(&csp_if_kiss, (uint8_t *)data, data_size, cswitch); -} - -static void csp_kiss_putc(char c) -{ - gs_uart_write(uart_csp_device, -1, c); -} - -static void csp_kiss_discard(char c, void *pxTaskWoken) -{ - // Do nothing with discarded characters -} - -gs_error_t gs_csp_kiss_init(uint8_t device) -{ - static csp_kiss_handle_t csp_kiss_driver; - static const char * kiss_name = "KISS"; - csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_kiss, CSP_NODE_MAC); - - csp_kiss_init(&csp_if_kiss, &csp_kiss_driver, csp_kiss_putc, csp_kiss_discard, kiss_name); - - uart_csp_device = device; - - return gs_uart_set_rx_callback(device, usart_rx_callback, NULL); -} diff --git a/gomspace/libgscsp/src/error.c b/gomspace/libgscsp/src/error.c deleted file mode 100644 index 45777e31..00000000 --- a/gomspace/libgscsp/src/error.c +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -gs_error_t gs_csp_error(int csp_error) -{ - switch (csp_error) { - case CSP_ERR_NONE: /* No error */ - return GS_OK; - - case CSP_ERR_NOMEM: /* Not enough memory */ - return GS_ERROR_ALLOC; - - case CSP_ERR_INVAL: /* Invalid argument */ - return GS_ERROR_ARG; - - case CSP_ERR_TIMEDOUT: /* Operation timed out */ - return GS_ERROR_TIMEOUT; - - case CSP_ERR_USED: /* Resource already in use */ - return GS_ERROR_IN_USE; - - case CSP_ERR_NOTSUP: /* Operation not supported */ - return GS_ERROR_NOT_SUPPORTED; - - case CSP_ERR_BUSY: /* Device or resource busy */ - return GS_ERROR_BUSY; - - case CSP_ERR_ALREADY: /* Connection already in progress */ - return GS_ERROR_ALREADY_IN_PROGRESS; - - case CSP_ERR_RESET: /* Connection reset */ - return GS_ERROR_CONNECTION_RESET; - - case CSP_ERR_NOBUFS: /* No more buffer space available */ - return GS_ERROR_NO_BUFFERS; - - case CSP_ERR_TX: /* Transmission failed */ - case CSP_ERR_DRIVER: /* Error in driver layer */ - return GS_ERROR_IO; - - case CSP_ERR_AGAIN: - return GS_ERROR_AGAIN; - - case CSP_ERR_HMAC: /* HMAC failed */ - case CSP_ERR_XTEA: /* XTEA failed */ - case CSP_ERR_CRC32: /* CRC32 failed */ - return GS_ERROR_DATA; - - default: - break; - } - return csp_error; -} diff --git a/gomspace/libgscsp/src/freertos/cpu.c b/gomspace/libgscsp/src/freertos/cpu.c deleted file mode 100644 index a17fd62b..00000000 --- a/gomspace/libgscsp/src/freertos/cpu.c +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -void cpu_reset(void) -{ - gs_sys_reset(GS_SYS_RESET_CSP); -} diff --git a/gomspace/libgscsp/src/linux/command_line.c b/gomspace/libgscsp/src/linux/command_line.c deleted file mode 100644 index 7c2b9bec..00000000 --- a/gomspace/libgscsp/src/linux/command_line.c +++ /dev/null @@ -1,265 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include "../local.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define IF_NAME "if" - -#define DEFAULT_CAN_DEVICE "can0" - -#define DEFAULT_KISS_IF_NAME "KISS" -#define DEFAULT_KISS_DEVICE "/dev/ttyUSB0" -#define KISS_SPEED "speed" -#define DEFAULT_KISS_SPEED 500000 - -#define DEFAULT_ZMQ_SERVER "localhost" - -#define DEFAULT_I2C_DEVICE "0" - -#define CSP_ADDRESS_NOT_SET 255 -#define DEFAULT_CSP_ADDRESS 8 - -static uint8_t csp_address = CSP_ADDRESS_NOT_SET; -static const char * csp_can_device = NULL; -static const char * csp_kiss_device = NULL; -static const char * csp_i2c_device = NULL; -static const char * csp_zmq_server = NULL; -static const char * csp_rtable = NULL; - -static int parser(int key, char *arg, struct argp_state *state) -{ -switch (key) { - case 'a': - return gs_string_to_uint8(arg, &csp_address); - - case 'c': - if (csp_can_device) { - return GS_ERROR_IN_USE; - } - if (arg) { - csp_can_device = arg; - } else { - csp_can_device = DEFAULT_CAN_DEVICE; - } - break; - - case 'k': - if (csp_kiss_device) { - return GS_ERROR_IN_USE; - } - if (arg) { - csp_kiss_device = arg; - } else { - csp_kiss_device = DEFAULT_KISS_DEVICE; - } - break; - - case 'i': - if (csp_i2c_device) { - return GS_ERROR_IN_USE; - } - if (arg) { - csp_i2c_device = arg; - } else { - csp_i2c_device = DEFAULT_I2C_DEVICE; - } - break; - - case 'z': - if (csp_zmq_server) { - return GS_ERROR_IN_USE; - } - if (arg) { - csp_zmq_server = arg; - } else { - csp_zmq_server = DEFAULT_ZMQ_SERVER; - } - break; - - case 'R': - csp_rtable = arg; - break; - - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - -static const struct argp_option options[] = { - { - .name = "csp-address", - .key = 'a', - .arg = "ADDR", - .flags = 0, - .doc = "Set address, default: " GS_DEF2STRING(DEFAULT_CSP_ADDRESS) - }, - { - .name = "csp-rtable", - .key = 'R', - .arg = "RTABLE", - .flags = 0, - .doc = "Set routing table\nRTABLE=
/ [mac]\nExample: \"0/0 ZMQHUB 24, 24/2 ZMQHUB\"" - }, -#if (CSP_USE_CAN) - { - .name = "csp-can", - .key = 'c', - .arg = "DEVICE", - .flags = OPTION_ARG_OPTIONAL, - .doc = "Add CAN interface\nDEVICE=" DEFAULT_CAN_DEVICE - }, -#endif -#if (CSP_USE_KISS) - { - .name = "csp-kiss", - .key = 'k', - .arg = "DEVICE", - .flags = OPTION_ARG_OPTIONAL, - .doc = "Add KISS over UART interface\nDEVICE=" DEFAULT_KISS_DEVICE "," IF_NAME "=" DEFAULT_KISS_IF_NAME","KISS_SPEED"=" GS_DEF2STRING(DEFAULT_KISS_SPEED) - }, -#endif -#if (CSP_USE_I2C) - { - .name = "csp-i2c", - .key = 'i', - .arg = "DEVICE", - .flags = OPTION_ARG_OPTIONAL, - .doc = "Add I2C interface\nDEVICE=0,"GS_I2C_COMMAND_LINE_SPEED"=" GS_DEF2STRING(GS_I2C_DEFAULT_BPS) "," GS_I2C_COMMAND_LINE_ADDRESS "=1," GS_I2C_COMMAND_LINE_DEVICE "=" GS_DEF2STRING(GS_I2C_ALL_DEVICES) - }, -#endif -#if (CSP_USE_ZMQHUB) - { - .name = "csp-zmq", - .key = 'z', - .arg = "SERVER", - .flags = OPTION_ARG_OPTIONAL, - .doc = "Add ZMQ interface\nSERVER=" DEFAULT_ZMQ_SERVER - }, -#endif - { - .flags = OPTION_DOC, - .name = "Examples:" -#if (CSP_USE_CAN) - "\n CAN: configure address 10 and CAN interface can0:" - "\n $ -a10 -ccan0" -#endif -#if (CSP_USE_KISS) - "\n KISS: configure address 10 and uart on /dev/ttyUSB0 at baudrate 500000:" - "\n $ -a10 -k/dev/ttyUSB0,speed=500000" -#endif -#if (CSP_USE_I2C) - "\n I2C: configure address 10 and I2C Aardvark dongle with id 2238384015, speed 400K:" - "\n $ -a10 -i2238384015,speed=400000" -#endif -#if (CSP_USE_ZMQHUB) - "\n ZMQ: configure address 10 and ZMQ proxy on localhost:" - "\n $ -a10 -zlocalhost" -#endif - }, - {0} -}; - -static const struct argp argp = {.options = options, .parser = parser}; - -const struct argp_child gs_csp_command_line_options = {.argp = &argp, .header = "CSP"}; - -gs_error_t gs_csp_command_line_configure_interfaces(void) -{ -#if (CSP_USE_KISS) - // KISS - only here, because the embedded init functions are stubbed in libemul - if (csp_kiss_device) { - static char device[50]; - static char ifname[50]; - uint32_t speed; - int res = gs_string_get_suboption_string(csp_kiss_device, NULL, DEFAULT_KISS_DEVICE, device, sizeof(device)); - res |= gs_string_get_suboption_string(csp_kiss_device, IF_NAME, DEFAULT_KISS_IF_NAME, ifname, sizeof(ifname)); - res |= gs_string_get_suboption_uint32(csp_kiss_device, KISS_SPEED, DEFAULT_KISS_SPEED, &speed); - if (res == GS_OK) { - static csp_iface_t csp_if_kiss; - static csp_kiss_handle_t csp_kiss_driver; - csp_kiss_init(&csp_if_kiss, &csp_kiss_driver, usart_putc, usart_insert, ifname); - struct usart_conf conf = {.device = device, .baudrate = speed}; - usart_init(&conf); - void my_usart_rx(uint8_t * buf, int len, void * pxTaskWoken) { - csp_kiss_rx(&csp_if_kiss, buf, len, pxTaskWoken); - } - usart_set_callback(my_usart_rx); - } - } -#endif - -#if (CSP_USE_CAN) - // CAN - only here, because the embedded init functions are stubbed in libemul - if (csp_can_device) { - char device[50]; - int res = gs_string_get_suboption_string(csp_can_device, NULL, DEFAULT_CAN_DEVICE, device, sizeof(device)); - if (res == GS_OK) { - csp_can_socketcan_init(device, 0, 0); - } - } -#endif - -#if (CSP_USE_ZMQHUB) - // ZMQ - currently ZMQ is only supported on Linux, and therefor handled here - if (csp_zmq_server) { - char server[50]; - int res = gs_string_get_suboption_string(csp_zmq_server, NULL, DEFAULT_ZMQ_SERVER, server, sizeof(server)); - if (res == GS_OK) { - csp_zmqhub_init(csp_get_address(), server); - } - } -#endif - -#if (CSP_USE_I2C) - // I2C - if (csp_i2c_device) { - uint8_t device = 0; - gs_string_get_suboption_uint8(csp_i2c_device, GS_I2C_COMMAND_LINE_DEVICE, GS_I2C_ALL_DEVICES, &device); - if (device == GS_I2C_ALL_DEVICES) { - device = 0; - } - - char modified_options[300]; - snprintf(modified_options, sizeof(modified_options), "%s,%s=%u", csp_i2c_device, GS_I2C_COMMAND_LINE_ADDRESS, csp_get_address()); - gs_error_t error = gs_function_invoke("i2c", modified_options); - if (error) { - log_error("Failed to initialize I2C adapter, error: %s", gs_error_string(error)); - } else { - error = gs_csp_i2c_init(device, csp_get_address()); - if (error) { - log_error("gs_csp_i2c_init(%u, %u) failed, error: %s", device, csp_get_address(), gs_error_string(error)); - } - } - } -#endif - - return GS_OK; -} - -bool gs_csp_command_line_is_address_set(void) -{ - return (csp_address != CSP_ADDRESS_NOT_SET); -} - -uint8_t gs_csp_command_line_get_address(void) -{ - if (gs_csp_command_line_is_address_set()) { - return csp_address; - } - return DEFAULT_CSP_ADDRESS; -} - -const char * gs_csp_command_line_get_rtable(void) -{ - return csp_rtable; -} diff --git a/gomspace/libgscsp/src/local.h b/gomspace/libgscsp/src/local.h deleted file mode 100644 index 5c033c14..00000000 --- a/gomspace/libgscsp/src/local.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef GS_CSP_SRC_LOCAL_H -#define GS_CSP_SRC_LOCAL_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#if (__linux__) -#define GS_CSP_COMMAND_LINE_SUPPORT 1 -#include -#endif - -GS_LOG_GROUP_EXTERN(gs_csp_log); -#define LOG_DEFAULT gs_csp_log - -// local command line APIs -bool gs_csp_command_line_is_address_set(void); -uint8_t gs_csp_command_line_get_address(void); -const char * gs_csp_command_line_get_rtable(void); -gs_error_t gs_csp_command_line_configure_interfaces(void); - -#endif diff --git a/gomspace/libgscsp/src/log.c b/gomspace/libgscsp/src/log.c deleted file mode 100644 index 932e5394..00000000 --- a/gomspace/libgscsp/src/log.c +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include "local.h" - -GS_LOG_GROUP(gs_csp_log, "csp", GS_LOG_CAT_CSP, LOG_DEFAULT_MASK); - -static void gs_log_csp_debug_hook(csp_debug_level_t level, const char *format, va_list args) -{ - gs_log_level_t mapped_level; - - switch (level) { - /* Regular log levels */ - default: - case CSP_ERROR: - mapped_level = LOG_ERROR; - break; - case CSP_WARN: - mapped_level = LOG_WARNING; - break; - case CSP_INFO: - mapped_level = LOG_INFO; - break; - /* Extended log levels */ - case CSP_BUFFER: - mapped_level = LOG_TRACE; - break; - case CSP_PACKET: - mapped_level = LOG_INFO; - break; - case CSP_PROTOCOL: - mapped_level = LOG_DEBUG; - break; - case CSP_LOCK: - mapped_level = LOG_TRACE; - break; - } - - const int do_log = ((LOG_DEFAULT->mask & (1 << mapped_level)) > 0); - - if (do_log) { - /* forward to log system */ - gs_log_va(mapped_level, LOG_DEFAULT, format, args); - } -} - -gs_error_t gs_csp_log_init(void) -{ - gs_log_group_register(LOG_DEFAULT); - - csp_debug_set_level(CSP_ERROR, true); - csp_debug_set_level(CSP_WARN, true); - csp_debug_set_level(CSP_INFO, true); - csp_debug_set_level(CSP_BUFFER, true); - csp_debug_set_level(CSP_PACKET, true); - csp_debug_set_level(CSP_PROTOCOL, true); - csp_debug_set_level(CSP_LOCK, true); - - csp_debug_hook_set(gs_log_csp_debug_hook); - - return GS_OK; -} diff --git a/gomspace/libgscsp/src/router.c b/gomspace/libgscsp/src/router.c deleted file mode 100644 index 95f013eb..00000000 --- a/gomspace/libgscsp/src/router.c +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include -#include -#include -#include "../lib/libcsp/src/csp_qfifo.h" // internal libcsp header -> FIFO_TIMEOUT, csp_qfifo_wake_up() -#include <../lib/libcsp/src/csp_conn.h> // internal libcsp header -#include "local.h" - -typedef struct { - bool run; - gs_thread_t thread; -} gs_csp_router_t; - -static gs_csp_router_t gs_csp_router; - -static void * gs_csp_router_task(void *param) -{ - /* Here there be routing */ - while (gs_csp_router.run) { - csp_route_work(FIFO_TIMEOUT); - } - log_info("CSP router task terminating"); - gs_thread_exit(0); -} - -gs_error_t gs_csp_router_task_stop(void) -{ - GS_CHECK_HANDLE(gs_csp_router.run && (gs_csp_router.thread != 0)); - - // Close connections in state "RDP closing" - instead of waiting for timeout -#ifdef CSP_USE_RDP - { - size_t max_connections; - const csp_conn_t * conn = csp_conn_get_array(&max_connections); - if (conn && max_connections) { - for (unsigned int i = 0; i < max_connections; ++i, ++conn) { - if ((conn->state == CONN_OPEN) && (conn->rdp.state == RDP_CLOSE_WAIT)) { - log_info("Force close RDP %p in state closing", conn); - csp_close((csp_conn_t *) conn); - } - } - } - } -#endif - - // wait for RDP connections to close - unsigned int open = gs_csp_conn_get_open(); - if (open) { - const unsigned int MAX_TIMEOUT_MS = 30000; - log_info("Waiting up to %u mS for %u connection(s) to timeout/close ...", MAX_TIMEOUT_MS, open); - const uint32_t start_ms = gs_time_rel_ms(); - while (gs_csp_conn_get_open() && (gs_time_diff_ms(start_ms, gs_time_rel_ms()) < MAX_TIMEOUT_MS)) { - gs_time_sleep_ms(200); - } - } - - log_info("Waiting for CSP router task to stop ..."); - gs_csp_router.run = false; - csp_qfifo_wake_up(); - gs_error_t error = gs_thread_join(gs_csp_router.thread, NULL); - memset(&gs_csp_router, 0, sizeof(gs_csp_router)); - log_info("CSP router task stopped"); - return error; -} - -gs_error_t gs_csp_router_task_start(size_t stack_size, gs_thread_priority_t priority) -{ - if (gs_csp_router.run) { - return GS_ERROR_IN_USE; - } - - gs_csp_router.run = true; - gs_error_t error = gs_thread_create("RTE", gs_csp_router_task, NULL, stack_size, priority, - GS_THREAD_CREATE_JOINABLE, &gs_csp_router.thread); - if (error) { - memset(&gs_csp_router, 0, sizeof(gs_csp_router)); - } - return error; -} diff --git a/gomspace/libgscsp/src/rtable.c b/gomspace/libgscsp/src/rtable.c deleted file mode 100644 index f836e3d0..00000000 --- a/gomspace/libgscsp/src/rtable.c +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include "local.h" - -// Return interface, if only one configured -static csp_iface_t * get_single_if(unsigned int * return_count) -{ - unsigned int count = 0; - csp_iface_t * found = NULL; - - for (csp_iface_t * ifc = csp_iflist_get(); ifc; ifc = ifc->next) { - if (strcasecmp(ifc->name, "LOOP") == 0) { - // ignore loopback - } else { - ++count; - found = ifc; - } - } - *return_count = count; - return found; -} - -gs_error_t gs_csp_rtable_load(const char * rtable, bool set_default_route, bool use_command_line_option) -{ - //csp_rtable_clear(); - -#if GS_CSP_COMMAND_LINE_SUPPORT - if (use_command_line_option && gs_string_empty(rtable)) { - // try rtable from command line (if set) - rtable = gs_csp_command_line_get_rtable(); - } -#endif - - if (gs_string_empty(rtable) == false) { - - if (csp_rtable_check(rtable) > 0) { - csp_rtable_load(rtable); - log_info("%s: loaded routing table [%s]", __FUNCTION__, rtable); - return GS_OK; - } - - log_warning("%s: ignoring route table: [%s] due to error(s)", __FUNCTION__, rtable); - } - - if (set_default_route) { - unsigned int count = 0; - csp_iface_t * ifc = get_single_if(&count); - if (count == 0) { - log_warning("%s: no interfaces configured", __FUNCTION__); - return GS_ERROR_NOT_FOUND; - } - - if (count > 1) { - log_warning("%s: %u interfaces configured - will not set default routes", __FUNCTION__, count); - return GS_ERROR_AMBIGUOUS; - } - - // set default route - int res = csp_route_set(CSP_DEFAULT_ROUTE, ifc, CSP_NODE_MAC); - if (res != CSP_ERR_NONE) { - log_warning("%s: failed to set default route on interface: [%s], CSP error: %d", __FUNCTION__, ifc->name, res); - return gs_csp_error(res); - } - } - - return GS_OK; -} diff --git a/gomspace/libgscsp/src/service_dispatcher.c b/gomspace/libgscsp/src/service_dispatcher.c deleted file mode 100644 index 507549af..00000000 --- a/gomspace/libgscsp/src/service_dispatcher.c +++ /dev/null @@ -1,213 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include -#include "../lib/libcsp/src/csp_conn.h" // internal libcsp header -#include "local.h" - -static GS_LOG_GROUP(gs_cspdispatcher_log, "cspdispatcher", GS_LOG_CAT_CSP, LOG_DEFAULT_MASK); -#undef LOG_DEFAULT -#define LOG_DEFAULT gs_cspdispatcher_log - -#define WD_TIMEOUT_SECOUNDS 30 -#define DEFAULT_TIMEOUT_MS (((WD_TIMEOUT_SECOUNDS * 1000) / 3) * 2) - -struct gs_csp_service_dispatcher { - // Configuration - const gs_csp_service_dispatcher_conf_t * conf; - // Run or stop/exit. - bool run; - // Server socket - csp_socket_t * socket; - // Software watchdog - gs_swwd_hdl_t * wd; - // Thread handle. - gs_thread_t thread; -}; - -static void * service_dispatcher_task(void * parameter) -{ - gs_csp_service_dispatcher_t handle = parameter; - - unsigned int timeout_ms = (handle->conf->callback) ? 0 : DEFAULT_TIMEOUT_MS; - - log_debug("[%s] entering connection loop, timeout: %u mS", handle->conf->name, timeout_ms); - - while (handle->run) { - if (handle->wd) { - gs_swwd_touch(handle->wd); - } - - /* Wait for incoming connection, or timeout */ - csp_conn_t * conn = csp_accept(handle->socket, timeout_ms); - - if (conn) { - unsigned int in_port = csp_conn_dport(conn); - - log_debug("[%s] new connection %p on port: %u, source: %d:%d, flags: 0x%x", - handle->conf->name, conn, in_port, csp_conn_src(conn), csp_conn_sport(conn), csp_conn_flags(conn)); - - gs_csp_service_handler_t handler; - if (in_port < handle->conf->handler_array_size) { - handler = handle->conf->handler_array[in_port]; - } else { - handler = NULL; - } - - if (handler) { - gs_error_t error = (handler)(conn); - log_debug("[%s] connection on port: %u processed by %p, error: %s", - handle->conf->name, in_port, handler, gs_error_string(error)); - } else { - log_warning("[%s] no handler on port: %u - closing connection: source: %d:%d, flags: 0x%x", - handle->conf->name, in_port, csp_conn_src(conn), csp_conn_sport(conn), csp_conn_flags(conn)); - csp_close(conn); - } - } - - if (handle->conf->callback) { - timeout_ms = handle->conf->callback(); - if (timeout_ms > DEFAULT_TIMEOUT_MS) { - timeout_ms = DEFAULT_TIMEOUT_MS; - } - } - } - - log_debug("[%s] terminating ...", handle->conf->name); - gs_thread_exit(NULL); -} - -static gs_error_t service_dispatcher_create(const gs_csp_service_dispatcher_conf_t * conf, - size_t stack_size, - gs_thread_priority_t priority, - gs_csp_service_dispatcher_t * return_handle) -{ - gs_csp_service_dispatcher_t handle = calloc(1, sizeof(*handle)); - if (handle == 0) { - return GS_ERROR_ALLOC; - } - - *return_handle = handle; - - handle->conf = conf; - - // Create watchdog - if (conf->disable_watchdog == false) { - gs_error_t error = gs_swwd_register(&handle->wd, WD_TIMEOUT_SECOUNDS, NULL, NULL, conf->name); - if (error) { - log_error("[%s] gs_swwd_register(%s, %u) failed, error: %d", - conf->name, conf->name, WD_TIMEOUT_SECOUNDS, error); - handle->wd = NULL; - return error; - } - } - - // Open "server" socket - handle->socket = csp_socket(conf->socket_options); - if (handle->socket == NULL) { - log_error("[%s] csp_socket(0) failed", - conf->name); - return GS_ERROR_ALLOC; - } - - // Bind to port(s) to socket - for (unsigned int i = 0; i < conf->handler_array_size; ++i) { - if (conf->handler_array[i]) { - int res = csp_bind(handle->socket, i); - if (res) { - log_error("[%s] csp_bind(socket: %p, port: %u) failed, result: %d", - conf->name, handle->socket, i, res); - return GS_ERROR_IN_USE; - } - } - } - - // Bind on "any" port? - if (conf->bind_any) { - int res = csp_bind(handle->socket, CSP_ANY); - if (res) { - log_error("[%s] csp_bind(socket: %p, port: %u) failed, result: %d", - conf->name, handle->socket, CSP_ANY, res); - return GS_ERROR_IN_USE; - } - } - - // Create listen backlog - { - size_t backlog = conf->listen_backlog ? conf->listen_backlog : 10; - int res = csp_listen(handle->socket, backlog); - if (res) { - log_error("[%s] csp_listen(%p, %zu) failed, result: %d", - conf->name, handle->socket, backlog, res); - return GS_ERROR_UNKNOWN; - } - } - - // Launch thread - handle->run = true; - gs_error_t error = gs_thread_create(handle->conf->name, service_dispatcher_task, handle, stack_size, priority, - GS_THREAD_CREATE_JOINABLE, &handle->thread); - if (error) { - handle->thread = 0; - } - - return error; -} - -gs_error_t gs_csp_service_dispatcher_create(const gs_csp_service_dispatcher_conf_t * conf, - size_t stack_size, - gs_thread_priority_t priority, - gs_csp_service_dispatcher_t * return_handle) -{ - GS_CHECK_ARG(conf != NULL); - - gs_log_group_register(gs_cspdispatcher_log); - - gs_csp_service_dispatcher_t handle; - gs_error_t error = service_dispatcher_create(conf, stack_size, priority, &handle); - if (error) { - //gs_csp_service_dispatcher_destroy(handle); - handle = NULL; - } - - if (return_handle) { - *return_handle = handle; - } - - return error; -} - -gs_error_t gs_csp_service_dispatcher_wake_up(gs_csp_service_dispatcher_t handle) -{ - GS_CHECK_HANDLE(handle && handle->socket && handle->socket->socket); - csp_packet_t * packet = NULL; - int res = csp_queue_enqueue(handle->socket->socket, &packet, 0); - return (res == CSP_QUEUE_OK) ? GS_OK : GS_ERROR_FULL; -} - -gs_error_t gs_csp_service_dispatcher_destroy(gs_csp_service_dispatcher_t handle) -{ - GS_CHECK_HANDLE(handle && handle->conf); - - log_debug("[%s] stopping dispatcher ...", handle->conf->name); - - handle->run = false; - if (handle->thread) { - gs_csp_service_dispatcher_wake_up(handle); - gs_thread_join(handle->thread, NULL); - } - - csp_close(handle->socket); - - if (handle->wd) { - gs_swwd_deregister(&handle->wd); - } - - memset(handle, 0, sizeof(*handle)); - free(handle); - - return GS_OK; -} diff --git a/gomspace/libgscsp/src/service_handler.c b/gomspace/libgscsp/src/service_handler.c deleted file mode 100644 index b602847d..00000000 --- a/gomspace/libgscsp/src/service_handler.c +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include - -// callback for processing packets on a connection. -typedef void (*csp_service_packet_handler_t)(csp_conn_t * conn, csp_packet_t * packet); - -// Process all packets on the connectio and close it when done. -static gs_error_t call_csp_packet_handler(csp_conn_t * conn, csp_service_packet_handler_t handler) -{ - csp_packet_t *packet; - while ((packet = csp_read(conn, 0))) { - (handler)(conn, packet); - } - csp_close(conn); - return GS_OK; -} - -gs_error_t gs_csp_cmp_service_handler(csp_conn_t * conn) -{ - return call_csp_packet_handler(conn, csp_service_handler); -} - -gs_error_t gs_csp_ping_service_handler(csp_conn_t * conn) -{ - return call_csp_packet_handler(conn, csp_service_handler); -} - -gs_error_t gs_csp_ps_service_handler(csp_conn_t * conn) -{ - return call_csp_packet_handler(conn, csp_service_handler); -} - -static void memfree(csp_conn_t * conn, csp_packet_t * packet) -{ - uint32_t mem_free = 0; - - gs_mem_ram_type_t ram_type = gs_mem_get_ram_default(); - gs_mem_ram_stat_t ram_stat; - if(gs_mem_get_ram_stat(ram_type, &ram_stat) == GS_OK) { - mem_free = ram_stat.available; - } - - mem_free = util_hton32(mem_free); - memcpy(packet->data, &mem_free, sizeof(mem_free)); - packet->length = sizeof(mem_free); - - if (!csp_send(conn, packet, 0)) { - csp_buffer_free(packet); - } -} - -gs_error_t gs_csp_mem_free_service_handler(csp_conn_t * conn) -{ - return call_csp_packet_handler(conn, memfree); -} - -gs_error_t gs_csp_reboot_service_handler(csp_conn_t * conn) -{ - return call_csp_packet_handler(conn, csp_service_handler); -} - -gs_error_t gs_csp_buf_free_service_handler(csp_conn_t * conn) -{ - return call_csp_packet_handler(conn, csp_service_handler); -} - -static void uptime(csp_conn_t * conn, csp_packet_t * packet) -{ - uint32_t time = gs_time_uptime(); - time = util_hton32(time); - memcpy(packet->data, &time, sizeof(time)); - packet->length = sizeof(time); - - if (!csp_send(conn, packet, 0)) { - csp_buffer_free(packet); - } -} - -gs_error_t gs_csp_uptime_service_handler(csp_conn_t * conn) -{ - return call_csp_packet_handler(conn, uptime); -} diff --git a/gomspace/libgscsp/src/transaction.c b/gomspace/libgscsp/src/transaction.c deleted file mode 100644 index 96ba262a..00000000 --- a/gomspace/libgscsp/src/transaction.c +++ /dev/null @@ -1,67 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include - -gs_error_t gs_csp_transaction_persistent(csp_conn_t * conn, uint32_t timeout, const void * tx_buf, - size_t tx_len, void * rx_buf, size_t rx_max_len, size_t * rx_len) -{ - GS_CHECK_HANDLE(conn != NULL); - - size_t size = (rx_max_len > tx_len) ? rx_max_len : tx_len; - csp_packet_t * packet = csp_buffer_get(size); - if (packet == NULL) { - return GS_ERROR_ALLOC; - } - - /* Copy the request */ - if (tx_len > 0 && tx_buf != NULL) { - memcpy(packet->data, tx_buf, tx_len); - } - - packet->length = tx_len; - - if (!csp_send(conn, packet, timeout)) { - csp_buffer_free(packet); - return GS_ERROR_IO; - } - - /* If no reply is expected, return now */ - if (rx_max_len == 0) { - return GS_OK; - } - - packet = csp_read(conn, timeout); - if (packet == NULL) { - return GS_ERROR_IO; - } - - gs_error_t return_val; - if (rx_max_len >= packet->length) { - size = packet->length; - return_val = GS_OK; - } else { - csp_log_error("Reply length %u, buffer only %u", packet->length, rx_max_len); - size = rx_max_len; - return_val = GS_ERROR_OVERFLOW; - } - memcpy(rx_buf, packet->data, size); - *rx_len = packet->length; - csp_buffer_free(packet); - return return_val; -} - -gs_error_t gs_csp_transaction2(uint8_t prio, uint8_t dest, uint8_t port, uint32_t timeout, const void * tx_buf, - size_t tx_len, void * rx_buf, size_t rx_max_len, size_t * rx_len, uint32_t opts) -{ - csp_conn_t * conn = csp_connect(prio, dest, port, 0, opts); - if (conn == NULL) { - return GS_ERROR_HANDLE; - } - - gs_error_t res = gs_csp_transaction_persistent(conn, timeout, tx_buf, tx_len, rx_buf, rx_max_len, rx_len); - - csp_close(conn); - - return res; -} diff --git a/gomspace/libgscsp/wscript b/gomspace/libgscsp/wscript deleted file mode 100644 index a78d7f56..00000000 --- a/gomspace/libgscsp/wscript +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -# Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. - -import gs_gcc -import gs_doc -from waflib.Build import BuildContext - -APPNAME = 'gscsp' - - -def libcsp_with_os(ctx): - if ctx.gs_is_linux(): - return 'posix' - if ctx.gs_is_freertos(): - return 'freertos' - return None - - -def libcsp_with_driver_usart(ctx): - if ctx.gs_is_linux(): - return 'linux' - return None - - -def options(ctx): - ctx.load('gs_gcc gs_doc') - gs_gcc.gs_recurse(ctx) - - -def configure(ctx): - ctx.load('gs_gcc gs_doc') - - ctx.env.append_unique('FILES_GSCSP', 'src/*.c') - ctx.env.append_unique('USE_GSCSP', ['csp', 'csp_h', 'util']) - - if ctx.options.enable_if_i2c: - ctx.env.append_unique('FILES_GSCSP', 'src/drivers/i2c/*.c') - - if ctx.gs_is_freertos(): - ctx.env.append_unique('FILES_GSCSP', 'src/drivers/can/*.c') - ctx.env.append_unique('FILES_GSCSP', 'src/drivers/kiss/*.c') - ctx.env.append_unique('FILES_GSCSP', 'src/freertos/*.c') - ctx.env.append_unique('USE_GSCSP', ['embed']) - - if ctx.gs_is_linux(): - ctx.env.append_unique('FILES_GSCSP', 'src/linux/*.c') - - # libcsp options - ctx.options.with_os = libcsp_with_os(ctx) - ctx.options.with_driver_usart = libcsp_with_driver_usart(ctx) - bindings = True if (ctx.gs_is_linux() and not ctx.gs_is_build_disabled(['shlib', 'csp_shlib'])) else False - ctx.options.enable_bindings = bindings - ctx.options.enable_python3_bindings = bindings - ctx.options.disable_stlib = True - ctx.options.enable_crc32 = True - ctx.options.with_connection_so = ctx.options.with_connection_so | 0x0040 # always CRC32, disable CSP_O_NOCRC32 - - if ctx.options.enable_if_can and ctx.options.enable_can_socketcan: - ctx.check_cc(lib='socketcan', mandatory=True) - - ctx.gs_add_doxygen(input=['include', 'lib/libcsp/include']) - - gs_gcc.gs_recurse(ctx) - - -def build(ctx): - gs_gcc.gs_recurse(ctx) - - public_include = ctx.gs_include(name=APPNAME, - includes=['include']) - - ctx.gs_objects(source=ctx.path.ant_glob(ctx.env.FILES_GSCSP), - target=APPNAME, - use=ctx.env.USE_GSCSP + [public_include]) - - ctx.gs_shlib(source=ctx.path.ant_glob(ctx.env.FILES_GSCSP), - target=APPNAME, - gs_prefix='', # make library libgscsp - gs_use_shlib=ctx.env.USE_GSCSP + [public_include]) - - ctx.gs_python_bindings(source=ctx.path.ant_glob('src/bindings/python/pygscsp.c'), - target=APPNAME, - gs_prefix='', # make library libgscsp - gs_use_shlib=ctx.env.USE_GSCSP + [APPNAME, public_include], - package='libgscsp') - - -def doc(ctx): - gs_doc.add_task_library_doc(ctx, keyvalues={ - 'gs_prod_name': 'lib'+APPNAME, - 'gs_prod_desc': 'GomSpace CSP extension', - }) - - -class Doc(BuildContext): - cmd = fun = 'doc' - - -def gs_dist(ctx): - gs_gcc.gs_recurse(ctx) - ctx.add_default_files(source_module=True) - ctx.add_files(ctx.path.ant_glob(['lib/libcsp/**/*'])) - ctx.add_license_file("CSP", "lib/libcsp/COPYING") diff --git a/gomspace/libp60_client/include/p60.h b/gomspace/libp60_client/include/p60.h deleted file mode 100644 index 186d43f8..00000000 --- a/gomspace/libp60_client/include/p60.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef _P60_H_ -#define _P60_H_ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#define P60_PORT_RPARAM 7 -#define P60_PORT_GNDWDT_RESET 9 -#define P60_PORT_CMDCONTROL 10 -#define P60_PORT_GSSB_SERVICE 15 -#define P60_PORT_GSCRIPT 22 - -/** FRAM MEMORY MAP */ -#define P60_FRAM_BOARD 0x0000 - -/** FRAM FILENAMES */ -#define P60_FNO_BOARD 0 -#define P60_FNO_BOARD_DFL 4 - -#define P60_FRAM_WP_BEGIN (0x1000) -#define P60_FRAM_WP_END (0x1C00 - 1) - -/** GND WD FRAM ADDR **/ -#define P60_FRAM_GNDWDT 0x1F00 - -/** PARAM INDEX MAP */ -#define P60_BOARD_PARAM 0 - -#define DEVICE_FM24CL64B 0 - -typedef enum { - UNKNOWN_RST = 0, - GND_WDT_RST, - I2C_WDT_RST, - CAN_WDT_RST, - EXT_HARD_RST, - EXT_SOFT_RST, -} p60_reset_cause_t; - -extern const uint8_t board_fallback_type; -extern const uint8_t csp_fallback_addr; -extern const uint8_t board_rs422_mode; - -extern void module_init_early(void); -extern void module_init(void); -extern void wdt_gnd_clear(void); -extern uint16_t command_control(uint8_t *packet, uint16_t length); -extern void module_task(void * pvParameters); - -#endif /* _P60_H_ */ diff --git a/gomspace/libp60_client/include/p60_board.h b/gomspace/libp60_client/include/p60_board.h deleted file mode 100644 index 2abd906d..00000000 --- a/gomspace/libp60_client/include/p60_board.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - * NanoCom firmware - * - */ - -#ifndef P60_PARAM_H_ -#define P60_PARAM_H_ - -#include -#include - -/** - * Define memory space - */ -#define P60_BOARD_UID 0x00 -#define P60_BOARD_TYPE 0x10 -#define P60_BOARD_REV 0x11 -#define P60_BOARD_CSP_ADDR 0x12 -#define P60_BOARD_I2C_ADDR 0x13 -#define P60_BOARD_I2C_SPEED_KHZ 0x14 -#define P60_BOARD_CAN_SPEED_KHZ 0x16 -#define P60_BOARD_KISS_ENABLE 0x18 -#define P60_BOARD_RS422_MODE 0x19 -#define P60_BOARD_RS422_SPEED_KHZ 0x1C -#define P60_BOARD_RTABLE_STR 0x20 //! This one is 0x60 = 96 bytes -#define P60_BOARD_RTABLE_STR_SIZE 0x60 - -/** Define the memory size */ -#define P60_BOARD_PARAM_SIZE 0x80 - -extern const param_table_t p60_config[]; -extern const int p60_config_count; - -#endif /* P60_PARAM_H_ */ diff --git a/gomspace/libp60_client/include/power_if.h b/gomspace/libp60_client/include/power_if.h deleted file mode 100644 index 6762d1ec..00000000 --- a/gomspace/libp60_client/include/power_if.h +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - * NanoPower firmware - * - */ - -#ifndef POWER_IF_H_ -#define POWER_IF_H_ - -#include - -#define POWER_IF_SET 1 -#define POWER_IF_GET 2 -#define POWER_IF_LIST 3 - -#define POWER_IF_STATUS_OK 0 -#define POWER_IF_STATUS_ERROR 1 - -#define POWER_IF_NAME_LEN 8 - -typedef struct __attribute__((packed)) { - uint8_t ch_idx; - uint8_t mode; - uint16_t on_cnt; - uint16_t off_cnt; - uint16_t cur_lu_lim; - uint16_t cur_lim; - uint16_t voltage; - int16_t current; - uint16_t latchup; - char name[POWER_IF_NAME_LEN]; -} power_if_ch_status_t; - -typedef struct __attribute__((packed)) { - uint8_t ch_idx; - uint8_t mode; - char name[8]; -} power_if_list_t; - -typedef struct __attribute__((packed)) { - uint8_t cmd; - uint8_t status; - power_if_ch_status_t ch_status; -} power_if_cmd_request_t; - -typedef struct __attribute__((packed)) { - uint8_t cmd; - uint8_t status; - power_if_ch_status_t ch_status; -} power_if_cmd_response_t; - -typedef struct __attribute__((packed)) { - uint8_t cmd; - uint8_t status; - uint8_t count; - power_if_list_t list[16]; -} power_if_cmd_list_response_t; - -int p60_power_if_cmd(uint8_t node, uint8_t port, uint32_t timeout, uint8_t cmd, void * ch_status_p); -uint8_t p60_power_if_get_ch_idx(char * ch_name, uint8_t * ch_no, uint8_t ch_no_max); - -#endif /* POWER_IF_H_ */ diff --git a/gomspace/libp60_client/src/cmd/power_if_cmd.c b/gomspace/libp60_client/src/cmd/power_if_cmd.c deleted file mode 100644 index 9851f912..00000000 --- a/gomspace/libp60_client/src/cmd/power_if_cmd.c +++ /dev/null @@ -1,147 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include - -#include -#include - -#include - -static uint8_t power_if_port = 10; -static uint32_t power_if_timeout = 5000; - -static int cmd_power_if_port(struct command_context * ctx) { - if (ctx->argc < 2) { - printf("Current port is %d\n", power_if_port); - return CMD_ERROR_NONE; - } - power_if_port = atoi(ctx->argv[1]); - return CMD_ERROR_NONE; -} - -static int cmd_power_if_timeout(struct command_context *ctx) { - if (ctx->argc < 2) { - printf("Current timeout is %"PRIu32"\n", power_if_timeout); - return CMD_ERROR_NONE; - } - if (sscanf(command_args(ctx), "%"SCNu32, &power_if_timeout) != 1) - return CMD_ERROR_SYNTAX; - if (power_if_timeout > 30000) { - printf("Timeout set to high, limited to 30000 ms\n"); - power_if_timeout = 30000; - } - printf("Timeout set to %"PRIu32"\n", power_if_timeout); - return CMD_ERROR_NONE; -} - -static int cmd_power_if_set_get(struct command_context * ctx) { - power_if_ch_status_t ch_status; - - if (ctx->argc < 3) { - return CMD_ERROR_SYNTAX; - } - uint8_t node = atoi(ctx->argv[1]); - memset(&ch_status, 0, sizeof(ch_status)); - strncpy(ch_status.name, ctx->argv[2], 7); - ch_status.name[7] = 0; - char * cmd = ctx->argv[0]; - if (!strcmp(cmd, "status") && (ctx->argc == 3)) { - if (!p60_power_if_cmd(node, power_if_port, power_if_timeout, POWER_IF_GET, &ch_status)) { - return CMD_ERROR_FAIL; - } - } else { - if (!strcmp(cmd, "on")) { - ch_status.mode = 1; - } else if (!strcmp(cmd, "off")) { - ch_status.mode = 0; - } - ch_status.on_cnt = (ctx->argc > 3) ? atoi(ctx->argv[3]) : 0; - ch_status.off_cnt = (ctx->argc > 4) ? atoi(ctx->argv[4]) : 0; - if (!p60_power_if_cmd(node, power_if_port, power_if_timeout, POWER_IF_SET, &ch_status)) { - return CMD_ERROR_FAIL; - } - } - printf("Node %u, Output channel '%s' (%u) is %s\r\n", node, ch_status.name, ch_status.ch_idx, (ch_status.mode ? "ON": "OFF")); - printf(" ch_idx: %u\r\n", ch_status.ch_idx); - printf(" mode: %u\r\n", ch_status.mode); - printf(" on_cnt: %u\r\n", ch_status.on_cnt); - printf(" off_cnt: %u\r\n", ch_status.off_cnt); - printf(" cur_lu_lim: %u\r\n", ch_status.cur_lu_lim); - printf(" cur_lim: %u\r\n", ch_status.cur_lim); - printf(" voltage: %u\r\n", ch_status.voltage); - printf(" current: %d\r\n", ch_status.current); - printf(" latchup: %u\r\n", ch_status.latchup); - - return CMD_ERROR_NONE; -} - -static int cmd_power_if_list(struct command_context * ctx) { - if (ctx->argc < 2) { - return CMD_ERROR_SYNTAX; - } - uint8_t node = atoi(ctx->argv[1]); - power_if_cmd_list_response_t ch_list; - if (!p60_power_if_cmd(node, power_if_port, power_if_timeout, POWER_IF_LIST, &ch_list)) { - return CMD_ERROR_FAIL; - } - printf("ch name status\r\n"); - for (uint8_t ch = 0; ch < ch_list.count; ch++) { - printf("%2u %-8s %s\r\n", ch_list.list[ch].ch_idx, ch_list.list[ch].name, ch_list.list[ch].mode ? "ON": "OFF"); - } - return CMD_ERROR_NONE; -} - -command_t power_if_commands[] = { - { - .name = "port", - .help = "Set power interface port (default is 10)", - .usage = "", - .handler = cmd_power_if_port, - }, - { - .name = "timeout", - .help = "Set power interface timeout in milliseconds", - .usage = "", - .handler = cmd_power_if_timeout, - }, - { - .name = "status", - .help = "Get power channel status", - .usage = " ", - .handler = cmd_power_if_set_get, - }, - { - .name = "on", - .help = "Turn power channel on", - .usage = " [ ]", - .handler = cmd_power_if_set_get, - }, - { - .name = "off", - .help = "Turn power channel off", - .usage = " off [ ]", - .handler = cmd_power_if_set_get, - }, - { - .name = "list", - .help = "Get list power channels", - .usage = "", - .handler = cmd_power_if_list, - }, -}; - -command_t __root_command power_if_root_command[] = { - { - .name = "power", - .help = "client: NanoPower P60", - .chain = INIT_CHAIN(power_if_commands), - } -}; - -void cmd_power_if_setup(void) { - command_register(power_if_root_command); -} diff --git a/gomspace/libp60_client/src/p60_client.c b/gomspace/libp60_client/src/p60_client.c deleted file mode 100644 index 76e1a905..00000000 --- a/gomspace/libp60_client/src/p60_client.c +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - * NanoCom firmware - * - */ - -#include -#include -#include -#include - -#include -#include - -/** - * Setup info about board configuration parameters - */ -const param_table_t p60_config[] = { - {.name = "uid", .addr = P60_BOARD_UID, .type = PARAM_STRING, .size = 16}, - {.name = "type", .addr = P60_BOARD_TYPE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "rev", .addr = P60_BOARD_REV, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "csp_addr", .addr = P60_BOARD_CSP_ADDR, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "i2c_addr", .addr = P60_BOARD_I2C_ADDR, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "i2c_speed", .addr = P60_BOARD_I2C_SPEED_KHZ, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, - {.name = "can_speed", .addr = P60_BOARD_CAN_SPEED_KHZ, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, - {.name = "kiss_en", .addr = P60_BOARD_KISS_ENABLE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "rs422_mode", .addr = P60_BOARD_RS422_MODE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "rs422_speed", .addr = P60_BOARD_RS422_SPEED_KHZ, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, - {.name = "csp_rtable", .addr = P60_BOARD_RTABLE_STR, .type = PARAM_STRING, .size = P60_BOARD_RTABLE_STR_SIZE}, - -}; - -const int p60_config_count = sizeof(p60_config) / sizeof(p60_config[0]); diff --git a/gomspace/libp60_client/src/power_if.c b/gomspace/libp60_client/src/power_if.c deleted file mode 100644 index e9266ca0..00000000 --- a/gomspace/libp60_client/src/power_if.c +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - * NanoPower firmware - * - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include - -uint8_t p60_power_if_get_ch_idx(char * ch_name, uint8_t * ch_no, uint8_t ch_no_max) { - - uint8_t result = 1; - uint8_t len = strlen(ch_name); - for (int i = 0; i < len; i++) { - if (!isdigit(ch_name[i])) { - result = 0; - break; - } - } - if (result) { - *ch_no = atoi(ch_name); - if (*ch_no >= ch_no_max) { - result = 0; - } - } - return result; -} - -int p60_power_if_cmd(uint8_t node, uint8_t port, uint32_t timeout, uint8_t cmd, void * ch_status_p) { - - power_if_cmd_request_t req; - - if ((cmd == POWER_IF_SET) || (cmd == POWER_IF_GET)) { - power_if_cmd_response_t resp; - power_if_ch_status_t * ch_status = (power_if_ch_status_t *)ch_status_p; - if (cmd == POWER_IF_SET) { - req.cmd = POWER_IF_SET; - req.ch_status.mode = ch_status->mode; - req.ch_status.on_cnt = csp_hton16(ch_status->on_cnt); - req.ch_status.off_cnt = csp_hton16(ch_status->off_cnt); - } else { - req.cmd = POWER_IF_GET; - req.ch_status.mode = 0; - req.ch_status.on_cnt = 0; - req.ch_status.off_cnt = 0; - } - ch_status->name[POWER_IF_NAME_LEN - 1] = 0; - strcpy(req.ch_status.name, ch_status->name); - if (csp_transaction(CSP_PRIO_HIGH, node, port, timeout, &req, sizeof(power_if_cmd_request_t), &resp, sizeof(power_if_cmd_response_t))) { - if ((resp.cmd == POWER_IF_SET) || (resp.cmd == POWER_IF_GET)) { - if (resp.status == POWER_IF_STATUS_OK) { - ch_status->ch_idx = resp.ch_status.ch_idx; - ch_status->mode = resp.ch_status.mode; - ch_status->on_cnt = csp_ntoh16(resp.ch_status.on_cnt); - ch_status->off_cnt = csp_ntoh16(resp.ch_status.off_cnt); - ch_status->cur_lu_lim = csp_ntoh16(resp.ch_status.cur_lu_lim); - ch_status->cur_lim = csp_ntoh16(resp.ch_status.cur_lim); - ch_status->voltage = csp_ntoh16(resp.ch_status.voltage); - ch_status->current = csp_ntoh16(resp.ch_status.current); - ch_status->latchup = csp_ntoh16(resp.ch_status.latchup); - strncpy(ch_status->name, resp.ch_status.name, POWER_IF_NAME_LEN - 1); - /* Ensure zero termination*/ - ch_status->name[POWER_IF_NAME_LEN - 1] = 0; - return 1; - } - } - } - } else if (cmd == POWER_IF_LIST) { - power_if_cmd_list_response_t * ch_list = (power_if_cmd_list_response_t *)ch_status_p; - req.cmd = POWER_IF_LIST; - req.ch_status.mode = 0; - req.ch_status.on_cnt = 0; - req.ch_status.off_cnt = 0; - req.ch_status.name[0] = 0; - if (csp_transaction(CSP_PRIO_HIGH, node, port, timeout, &req, sizeof(power_if_cmd_request_t), ch_list, sizeof(power_if_cmd_list_response_t))) { - if ((ch_list->cmd == POWER_IF_LIST) && (ch_list->status == POWER_IF_STATUS_OK)) { - return 1; - } - } - } - - return 0; -} diff --git a/gomspace/libp60_client/wscript b/gomspace/libp60_client/wscript deleted file mode 100644 index dc4dcf8a..00000000 --- a/gomspace/libp60_client/wscript +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -# Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. - -APPNAME = 'p60_client' - - -def options(ctx): - gr = ctx.add_option_group('NanoPower-P60 library client options') - gr.add_option('--disable-libp60-cmd', action='store_true', help='Disable client cmd code for NanoPower-P60 library') - - -def configure(ctx): - ctx.env.append_unique('FILES_LIBP60_CLIENT', ['src/*.c']) - if not ctx.options.disable_libp60_cmd: - ctx.env.append_unique('FILES_LIBP60_CLIENT', ['src/cmd/*.c']) - - -def build(ctx): - public_include = APPNAME + '_h' - ctx(export_includes=['include'], name=public_include) - ctx.objects(source=ctx.path.ant_glob(ctx.env.FILES_LIBP60_CLIENT), - target=APPNAME, - use=['csp', 'gosh', 'param', 'param_client', 'util', public_include]) - - -def gs_dist(ctx): - ctx.add_default_files(source_module=True) diff --git a/gomspace/libparam_client/include/deprecated/param/param_client.h b/gomspace/libparam_client/include/deprecated/param/param_client.h deleted file mode 100644 index b1755541..00000000 --- a/gomspace/libparam_client/include/deprecated/param/param_client.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef PARAM_PARAM_CLIENT_H -#define PARAM_PARAM_CLIENT_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Legacy/deprecated include of header files for libparam client. -*/ - -#include -#include -#include -#include - -#endif diff --git a/gomspace/libparam_client/include/deprecated/param/param_lock.h b/gomspace/libparam_client/include/deprecated/param/param_lock.h deleted file mode 100644 index 5fab0b91..00000000 --- a/gomspace/libparam_client/include/deprecated/param/param_lock.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - * GomSpace Parameter System. - */ -#ifndef PARAM_PARAM_LOCK_H_ -#define PARAM_PARAM_LOCK_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -static inline void param_lock(param_index_t * mem) -{ - gs_param_table_lock((gs_param_table_instance_t *) mem); -} - -static inline void param_unlock(param_index_t * mem) -{ - gs_param_table_unlock((gs_param_table_instance_t *) mem); -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libparam_client/include/deprecated/param/param_serializer.h b/gomspace/libparam_client/include/deprecated/param/param_serializer.h deleted file mode 100644 index c05e782e..00000000 --- a/gomspace/libparam_client/include/deprecated/param/param_serializer.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef PARAM_PARAM_SERIALIZER_H -#define PARAM_PARAM_SERIALIZER_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - * GomSpace Parameter System - */ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef gs_param_serialize_flags_t param_serializer_flags; - -static inline int param_betoh(param_type_t type, void * item) -{ - return gs_param_betoh(type, item); -} - -static inline int param_htobe(param_type_t type, void * item) -{ - return gs_param_htobe(type, item); -} - -static inline int param_serialize_full_table(param_index_t * mem, unsigned int *start, uint8_t * buf, unsigned int maxbuflen, param_serializer_flags flags) -{ - unsigned int buf_pos = 0; - gs_error_t error = gs_param_serialize_full_table((gs_param_table_instance_t *) mem, start, flags, buf, maxbuflen, &buf_pos); - return (error == GS_OK) ? (int) buf_pos : -1; -} - -static inline gs_error_t param_serialize_item(const param_table_t * param, uint16_t addr, uint8_t * buf, uint16_t * pos, unsigned int maxlen, void * item, param_serializer_flags flags) -{ - unsigned int tmp_pos = *pos; - gs_error_t error = gs_param_serialize_item((const gs_param_table_row_t*) param, addr, item, flags, buf, maxlen, &tmp_pos); - *pos = tmp_pos; - return (error == GS_OK) ? 0 : -1; -} - -static inline gs_error_t param_deserialize(param_index_t * mem, uint8_t * buf, int len, param_serializer_flags flags) -{ - return (gs_param_deserialize((gs_param_table_instance_t *) mem, buf, len, flags) == GS_OK) ? 0 : -1; -} - -static inline gs_error_t param_deserialize_item(const param_table_t * param, uint16_t addr, param_index_t * mem, void * item, param_serializer_flags flags) -{ - return (gs_param_deserialize_item((gs_param_table_instance_t *) mem, (const gs_param_table_row_t*)param, addr, item, flags) == GS_OK) ? 0 : -1; -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libparam_client/include/deprecated/param/param_string.h b/gomspace/libparam_client/include/deprecated/param/param_string.h deleted file mode 100644 index 35e19a0b..00000000 --- a/gomspace/libparam_client/include/deprecated/param/param_string.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef PARAM_PARAM_STRING_H -#define PARAM_PARAM_STRING_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - * GomSpace Parameter System - */ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef union { - const param_table_t * row3; - const gs_param_table_row_t * row4; -} gs_param_row_align_t; - -static inline const param_table_t * param_find_name(const param_table_t rows[], size_t row_count, const char * name) -{ - gs_param_row_align_t row_in = {.row3 = rows}; - gs_param_row_align_t row_out = {.row4 = gs_param_row_by_name(name, row_in.row4, row_count)}; - return row_out.row3; -} - -static inline const param_table_t * param_find_addr(const param_table_t rows[], size_t row_count, uint16_t addr) -{ - gs_param_row_align_t row_in = {.row3 = rows}; - gs_param_row_align_t row_out = {.row4 = gs_param_row_by_address(addr, row_in.row4, row_count)}; - return row_out.row3; -} - -static inline void param_list_single(param_table_t * param, param_index_t * mem, int do_read) -{ - gs_param_list_single((gs_param_table_instance_t *) mem, (const gs_param_table_row_t *) param, (do_read != 0)); -} - -static inline void param_list(param_index_t * mem, int do_read) -{ - gs_param_list((gs_param_table_instance_t *) mem, (do_read != 0)); -} - -static inline gs_error_t param_from_string(const param_table_t * param , const char * string, void * value) -{ - return gs_param_from_string((const gs_param_table_row_t *)param , string, value); -} - -static inline int param_to_string(const param_table_t * param, char * buf, int pos, const void * value, int with_type, int max_size) -{ - unsigned int written = 0; - gs_param_to_string((const gs_param_table_row_t *)param, value, with_type, buf, max_size, pos, &written); - return (int) written; -} - -static inline const char * param_type_to_string(param_type_t type) -{ - return gs_param_type_to_string(type); -} - -static inline uint16_t param_index_chksum(param_index_t * mem) -{ - return gs_param_table_checksum((gs_param_table_instance_t*)mem); -} - -static inline uint16_t param_index_chksum2(param_index_t * mem) -{ - return gs_param_table_checksum2((gs_param_table_instance_t*)mem); -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libparam_client/include/deprecated/param/param_types.h b/gomspace/libparam_client/include/deprecated/param/param_types.h deleted file mode 100644 index 61cc8351..00000000 --- a/gomspace/libparam_client/include/deprecated/param/param_types.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef PARAM_PARAM_TYPES_H -#define PARAM_PARAM_TYPES_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Legacy/deprecated parameter types and definitions - use . -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define MAX_PARAM_NAME_LEN GS_PARAM_MAX_NAME - -/* - Legacy parameter type definition - matches gs_param_type_t exactly. - */ -typedef gs_param_type_t param_type_t; - -/* - Legacy table row definition - matches gs_param_table_row_t exactly. -*/ -typedef struct param_table_s { - uint16_t addr; - param_type_t type; - uint8_t size; - uint8_t count; // -> array_size - uint8_t flags; - char name[MAX_PARAM_NAME_LEN]; -} param_table_t; - -#define PARAM_COUNT gs_max(GS_PGM_UINT8((param)->count), 1) -#define PARAM_SIZE GS_PARAM_SIZE(param) -#define PARAM_TYPE GS_PARAM_TYPE(param) -#define PARAM_ADDR GS_PARAM_ADDR(param) -#define PARAM_FLAGS GS_PARAM_FLAGS(param) - -#define RPARAM_QUERY_MAX_LEN GS_RPARAM_MAX_QUERY - -#define PARAM_MAX_FILESIZE 0x400 - -struct param_index_s; - -/* - Legacy callback - matches gs_param_callback_func_t exactly. -*/ -typedef void (*param_callback_func)(uint16_t addr, struct param_index_s * index); - -typedef gs_param_table_id_t param_mem; - -/* - Legacy table instance definition - matches gs_param_table_instance_t exactly. -*/ -typedef struct param_index_s { - const char * name; - param_mem mem_id; - const param_table_t * table; - unsigned int count; - void * physaddr; - unsigned int size; - const gs_param_function_interface_t function_interface; - const uint16_t table_chksum; - const uint16_t chksum2; - const uint16_t checksum_le; - const gs_mutex_t lock; - param_callback_func callback; - const char * const var1; - const char * const var2; - const void * const var3; - const void * const var4; - const void * const var5; - const void * const var6; - const void * const var7; - const uint32_t var8; -} param_index_t; - -/** - Return base size of a parameter type. -*/ -static inline uint8_t param_type_size(param_type_t type) -{ - return gs_param_type_size(type); -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libparam_client/include/deprecated/param/rparam_client.h b/gomspace/libparam_client/include/deprecated/param/rparam_client.h deleted file mode 100644 index a8c2655b..00000000 --- a/gomspace/libparam_client/include/deprecated/param/rparam_client.h +++ /dev/null @@ -1,208 +0,0 @@ -#ifndef PARAM_RPARAM_CLIENT_H -#define PARAM_RPARAM_CLIENT_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - * GomSpace Parameter System - */ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Legacy magic checksum. - @deprecated use #GS_RPARAM_MAGIC_CHECKSUM (if remote products supports it). -*/ -#define GS_RPARAM_LEGACY_MAGIC_CHECKSUM 0xb00b - -static inline int rparam_get_full_table(param_index_t* idx, int node, int port, int index_id, uint32_t timeout_ms) -{ - return (gs_rparam_get_full_table((gs_param_table_instance_t *) idx, - node, - index_id, - GS_RPARAM_LEGACY_MAGIC_CHECKSUM, - timeout_ms) == GS_OK) ? 0 : -1; -} - -static inline int rparam_download_table_spec_from_remote_and_save_to_file2(const char* fname, uint8_t node, uint8_t port, param_index_t* idx, uint16_t* return_checksum, uint32_t timeout_ms) -{ - return (gs_rparam_download_table_spec((gs_param_table_instance_t *) idx, - fname, - node, - idx->mem_id, - timeout_ms, - return_checksum) == GS_OK) ? 0 : -1; -} - -static inline int rparam_download_table_spec_from_remote_and_save_to_file(const char* fname, uint8_t node, uint8_t port, param_index_t* idx, uint16_t* checksum) -{ - return rparam_download_table_spec_from_remote_and_save_to_file2(fname, node, port, idx, checksum, 10000); -} - -static inline int rparam_load_table_spec_from_file(const char* fname, param_index_t* idx, uint16_t* return_checksum) -{ - return (gs_rparam_load_table_spec((gs_param_table_instance_t *) idx, fname, return_checksum) == GS_OK) ? 0 : -1; -} - -static inline int rparam_get_single(void * out, uint16_t addr, param_type_t type, int size, int mem_id, int node, int port, uint32_t timeout_ms) -{ - return (gs_rparam_get(node, mem_id, addr, type, GS_RPARAM_LEGACY_MAGIC_CHECKSUM, timeout_ms, out, size) == GS_OK) ? size : -1; -} - -static inline int rparam_set_single(const void * in, uint16_t addr, param_type_t type, int size, int mem_id, int node, int port, uint32_t timeout_ms) -{ - return (gs_rparam_set(node, mem_id, addr, type, GS_RPARAM_LEGACY_MAGIC_CHECKSUM, timeout_ms, in, size) == GS_OK) ? size : -1; -} - -static inline int rparam_copy(uint8_t node, uint8_t port, uint32_t timeout_ms, uint8_t from, uint8_t to) -{ - return (gs_rparam_copy(node, timeout_ms, from, to) == GS_OK) ? 1 : 0; -} - -static inline int rparam_save(uint8_t node, uint8_t port, uint32_t timeout_ms, uint8_t from, uint8_t to) -{ - return (gs_rparam_save(node, timeout_ms, from, to) == GS_OK) ? 1 : 0; -} - -static inline int rparam_load(uint8_t node, uint8_t port, uint32_t timeout_ms, uint8_t from, uint8_t to) -{ - return (gs_rparam_load(node, timeout_ms, from, to) == GS_OK) ? 1 : 0; -} - -/** - * Remote getters for parameters. - * @param out pointer to the output buffer/parameter - * @param outlen length of the supplied out-buffer, only applies to rparam_get_string() - * @param addr local address of the parameter - * @param node CSP address of the node to query - * @param port CSP port of the parameter server - * @param timeout timeout on remote CSP calls - * @returns <0 on error in which case the contents of out is invalid, >0 on success - */ -static inline int rparam_get_string(char *out, int outlen, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_get_single(out, addr, PARAM_STRING, outlen, index_id, node, port, timeout_ms); -} - -/** - * Remote setters for parameters. - * @param in pointer to the buffer/parameter value to set - * @param inlen length of the supplied in-buffer, only applies to rparam_set_string() - * @param addr local address of the parameter - * @param node CSP address of the node to query - * @param port CSP port of the parameter server - * @param timeout timeout on remote CSP calls - * @returns <0 on error in which case the contents of out is invalid, >0 on success - */ -static inline int rparam_set_string(const char *in, int inlen, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_set_single(in, addr, PARAM_STRING, inlen, index_id, node, port, timeout_ms); -} - -static inline int rparam_get_uint8(uint8_t * out, uint16_t addr, int tinst_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_get_single(out, addr, PARAM_UINT8, sizeof(uint8_t), tinst_id, node, port, timeout_ms); -} - -static inline int rparam_set_uint8(const uint8_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_set_single(in, addr, PARAM_UINT8, sizeof(uint8_t), index_id, node, port, timeout_ms); -} - -static inline int rparam_get_uint16(uint16_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_get_single(out, addr, PARAM_UINT16, sizeof(uint16_t), index_id, node, port, timeout_ms); -} - -static inline int rparam_set_uint16(const uint16_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_set_single(in, addr, PARAM_UINT16, sizeof(uint16_t), index_id, node, port, timeout_ms); -} - -static inline int rparam_get_uint32(uint32_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_get_single(out, addr, PARAM_UINT32, sizeof(uint32_t), index_id, node, port, timeout_ms); -} - -static inline int rparam_set_uint32(const uint32_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_set_single(in, addr, PARAM_UINT32, sizeof(uint32_t), index_id, node, port, timeout_ms); -} - -static inline int rparam_get_uint64(uint64_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_get_single(out, addr, PARAM_UINT64, sizeof(uint64_t), index_id, node, port, timeout_ms); -} - -static inline int rparam_set_uint64(const uint64_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_set_single(in, addr, PARAM_UINT64, sizeof(uint64_t), index_id, node, port, timeout_ms); -} - -static inline int rparam_get_int8(int8_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_get_single(out, addr, PARAM_INT8, sizeof(int8_t), index_id, node, port, timeout_ms); -} - -static inline int rparam_set_int8(const int8_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_set_single(in, addr, PARAM_INT8, sizeof(int8_t), index_id, node, port, timeout_ms); -} - -static inline int rparam_get_int16(int16_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_get_single(out, addr, PARAM_INT16, sizeof(int16_t), index_id, node, port, timeout_ms); -} - -static inline int rparam_set_int16(const int16_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_set_single(in, addr, PARAM_INT16, sizeof(int16_t), index_id, node, port, timeout_ms); -} - -static inline int rparam_get_int32(int32_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_get_single(out, addr, PARAM_INT32, sizeof(int32_t), index_id, node, port, timeout_ms); -} - -static inline int rparam_set_int32(const int32_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_set_single(in, addr, PARAM_INT32, sizeof(int32_t), index_id, node, port, timeout_ms); -} - -static inline int rparam_get_int64(int64_t * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_get_single(out, addr, PARAM_INT64, sizeof(int64_t), index_id, node, port, timeout_ms); -} - -static inline int rparam_set_int64(const int64_t * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_set_single(in, addr, PARAM_INT64, sizeof(int64_t), index_id, node, port, timeout_ms); -} - -static inline int rparam_get_float(float * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_get_single(out, addr, PARAM_FLOAT, sizeof(float), index_id, node, port, timeout_ms); -} - -static inline int rparam_set_float(const float * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_set_single(in, addr, PARAM_FLOAT, sizeof(float), index_id, node, port, timeout_ms); -} - -static inline int rparam_get_double(double * out, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_get_single(out, addr, PARAM_DOUBLE, sizeof(double), index_id, node, port, timeout_ms); -} - -static inline int rparam_set_double(const double * in, uint16_t addr, int index_id, int node, int port, uint32_t timeout_ms) -{ - return rparam_set_single(in, addr, PARAM_DOUBLE, sizeof(double), index_id, node, port, timeout_ms); -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/pp/i2c/i2c.h b/gomspace/libparam_client/include/gs/param/internal/pp/i2c/i2c.h deleted file mode 100644 index 484d4959..00000000 --- a/gomspace/libparam_client/include/gs/param/internal/pp/i2c/i2c.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef GS_PARAM_INTERNAL_PP_I2C_I2C_H -#define GS_PARAM_INTERNAL_PP_I2C_I2C_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#if (GS_PARAM_INTERNAL_USE) - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define GS_PARAM_I2C_LENGTH_TABLE(length, table) ((length << 3) | (table & 0x07)) -#define GS_PARAM_I2C_LENGTH_TABLE_TO_LENGTH(lt) ((lt >> 3) & 0x1f) -#define GS_PARAM_I2C_LENGTH_TABLE_TO_TABLE(lt) (lt & 0x07) - -/** - Data structure for setting parameter. -*/ -typedef struct __attribute__ ((packed)) gs_param_i2c_set_request { - gs_i2c_slave_dispatch_header_t header; - uint8_t length_table; - uint8_t addr; - uint8_t data[]; // data (+ checksum) -} gs_param_i2c_set_request_t; - -/** - Data structure for getting parameter. -*/ -typedef struct __attribute__ ((packed)) gs_param_i2c_get_request { - gs_i2c_slave_dispatch_header_t header; - uint8_t length_table; - uint8_t addr; - uint8_t checksum; // optional -} gs_param_i2c_get_request_t; - -#ifdef __cplusplus -} -#endif -#endif -#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/pp/i2c/slave_dispatch.h b/gomspace/libparam_client/include/gs/param/internal/pp/i2c/slave_dispatch.h deleted file mode 100644 index a3779b5d..00000000 --- a/gomspace/libparam_client/include/gs/param/internal/pp/i2c/slave_dispatch.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef GS_PARAM_INTERNAL_PP_I2C_SLAVE_DISPATCH_H -#define GS_PARAM_INTERNAL_PP_I2C_SLAVE_DISPATCH_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#if (GS_PARAM_INTERNAL_USE) - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Header for I2C slave dispatch protocol - must be first in all protocols. -*/ -typedef struct __attribute__ ((packed)) gs_i2c_slave_dispatch_header { - uint8_t domain_command; -} gs_i2c_slave_dispatch_header_t; - -/** - Make header from domain and command. -*/ -#define GS_I2C_SLAVE_DISPATCH_HEADER(domain, command) ((domain << 5) | (command & 0x1f)) - -/** - Extract domain from header. -*/ -#define GS_I2C_SLAVE_DISPATCH_HEADER_TO_DOMAIN(header) ((header >> 5) & 0x7) - -/** - Extract comman from header. -*/ -#define GS_I2C_SLAVE_DISPATCH_HEADER_TO_COMMAND(header) (header & 0x1f) - -/** - Domain handler. - - Basically same features as normal I2C slave rx callback. The generic I2C dispatch interface will parse the header (first byte) - and call the associated handler, based on the domain. - - @param[in] channel I2C channel (handle). - @param[in] cmd domain specific command. - @param[in] rx_buffer Pointer to start of rx buffer. - @param[in] rx number of bytes received so far. - @param[in] cswitch If called from within an ISR (embedded platform), this will none NULL. - @return total number of bytes to receive before next call back. Return 0 to ignore rest of data - no additional call backs will be done for current I2C transaction. -*/ -typedef void (* gs_i2c_slave_dispatch_handler_t)(uint8_t channel, uint8_t cmd, const uint8_t * rx, size_t rx_length, gs_context_switch_t * cswitch); - -/** - Dispatch domains. - - Standard domains should be assigned from the lowest value. - Application/board/product should be assigned from highest value. -*/ -typedef enum { - GS_I2C_SLAVE_DISPATCH_DOMAIN_RESERVED = 0, //! Avoid use - reserved for GSSB, GSSB broadcasts UID request on domain=0, cmd=13 - GS_I2C_SLAVE_DISPATCH_DOMAIN_USER1, //! Avoid use - overlap with GSSB commands - GS_I2C_SLAVE_DISPATCH_DOMAIN_USER2, //! Avoid use - may overlap with GSSB commands - GS_I2C_SLAVE_DISPATCH_DOMAIN_USER3, //! Avoid use - may overlap with GSSB commands - GS_I2C_SLAVE_DISPATCH_DOMAIN_PARAM, //! Reserved for libparam. - GS_I2C_SLAVE_DISPATCH_DOMAIN_USER5, - GS_I2C_SLAVE_DISPATCH_DOMAIN_USER6, - GS_I2C_SLAVE_DISPATCH_DOMAIN_USER7, -} gs_i2c_slave_dispatch_domain_t; - -#ifdef __cplusplus -} -#endif -#endif -#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/pp/spi/slave_dispatch.h b/gomspace/libparam_client/include/gs/param/internal/pp/spi/slave_dispatch.h deleted file mode 100644 index 1a4a3959..00000000 --- a/gomspace/libparam_client/include/gs/param/internal/pp/spi/slave_dispatch.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef GS_PARAM_INTERNAL_PP_SPI_SLAVE_DISPATCH_H -#define GS_PARAM_INTERNAL_PP_SPI_SLAVE_DISPATCH_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#if (GS_PARAM_INTERNAL_USE) - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Header for SPI slave dispatch protocol - must be first in all protocols. -*/ -typedef struct __attribute__ ((packed)) gs_spi_slave_dispatch_header { - uint8_t domain_command; -} gs_spi_slave_dispatch_header_t; - -/** - Make header from domain and command. -*/ -#define GS_SPI_SLAVE_DISPATCH_HEADER(domain, command) ((domain << 5) | (command & 0x1f)) - -/** - Extract domain from header. -*/ -#define GS_SPI_SLAVE_DISPATCH_HEADER_TO_DOMAIN(header) ((header >> 5) & 0x7) - -/** - Extract comman from header. -*/ -#define GS_SPI_SLAVE_DISPATCH_HEADER_TO_COMMAND(header) (header & 0x1f) - -/** - Domain handler. - - Basically same features as normal SPI slave rx callback. The generic SPI dispatch interface will parse the header (first byte) - and call the associated handler, based on the domain. - - @param[in] channel SPI channel (handle). - @param[in] cmd domain specific command. - @param[in] rx_buffer Pointer to start of rx buffer. - @param[in] rx number of bytes received so far. - @param[in] cswitch If called from within an ISR (embedded platform), this will none NULL. - @return total number of bytes to receive before next call back. Return 0 to ignore rest of data - no additional call backs will be done for current SPI transaction. -*/ -typedef uint8_t (* gs_spi_slave_dispatch_handler_t)(uint8_t channel, uint8_t cmd, const uint8_t * rx_buffer, size_t rx, gs_context_switch_t * cswitch); - -/** - Dispatch domains. - - Standard domains should be assigned form the lowest value. - Application/board/product should be assigned from highest value. -*/ -typedef enum { - GS_SPI_SLAVE_DISPATCH_DOMAIN_RESERVED = 0, //! Avoid using 0, - GS_SPI_SLAVE_DISPATCH_DOMAIN_USER1, - GS_SPI_SLAVE_DISPATCH_DOMAIN_USER2, - GS_SPI_SLAVE_DISPATCH_DOMAIN_USER3, - GS_SPI_SLAVE_DISPATCH_DOMAIN_PARAM, - GS_SPI_SLAVE_DISPATCH_DOMAIN_USER5, - GS_SPI_SLAVE_DISPATCH_DOMAIN_USER6, - GS_SPI_SLAVE_DISPATCH_DOMAIN_USER7, -} gs_spi_slave_dispatch_domain_t; - -/** - Slave dispatch SPI receiver. - - Must be added on the channel as receiver function, using gs_spi_slave_set_rx(). - - @param[in] cswitch If called from within an ISR (embedded platform), this will be set and allow for triggering context switch. -*/ -uint8_t gs_spi_slave_dispatch_rx(uint8_t channel, const uint8_t * rx_buffer, size_t rx, bool new_request, gs_context_switch_t * cswitch); - -#ifdef __cplusplus -} -#endif -#endif -#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/pp/spi/spi.h b/gomspace/libparam_client/include/gs/param/internal/pp/spi/spi.h deleted file mode 100644 index b9303dcb..00000000 --- a/gomspace/libparam_client/include/gs/param/internal/pp/spi/spi.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef GS_PARAM_INTERNAL_PP_SPI_SPI_H -#define GS_PARAM_INTERNAL_PP_SPI_SPI_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#if (GS_PARAM_INTERNAL_USE) - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Domain commands. -*/ -typedef enum { - GS_PARAM_SPI_COMMAND_SET = 1, - GS_PARAM_SPI_COMMAND_GET = 2, - GS_PARAM_SPI_COMMAND_SET_WITH_CHECKSUM = 10, - GS_PARAM_SPI_COMMAND_GET_WITH_CHECKSUM = 11, -} gs_param_spi_command_t; - -#define GS_PARAM_SPI_LENGTH_TABLE(length, table) ((length << 3) | (table & 0x07)) -#define GS_PARAM_SPI_LENGTH_TABLE_TO_LENGTH(lt) ((lt >> 3) & 0x1f) -#define GS_PARAM_SPI_LENGTH_TABLE_TO_TABLE(lt) (lt & 0x07) - -/** - Data structure for setting parameter. -*/ -typedef struct __attribute__ ((packed)) gs_param_spi_set { - gs_spi_slave_dispatch_header_t header; - uint8_t length_table; - uint8_t addr; - uint8_t data[]; // data (+ checksum) -} gs_param_spi_set_t; - -/** - Data structure for getting parameter. -*/ -typedef struct __attribute__ ((packed)) gs_param_spi_get { - gs_spi_slave_dispatch_header_t header; - uint8_t length_table; - uint8_t addr; - uint8_t filler; // filler/delay - allow slave to find and prepare data/response - uint8_t data[]; // data -} gs_param_spi_get_t; - -/** - Data structure for getting parameter with checksum -*/ -typedef struct __attribute__ ((packed)) gs_param_spi_get_with_checksum { - gs_spi_slave_dispatch_header_t header; - uint8_t length_table; - uint8_t addr; - uint8_t checksum; - uint8_t filler; // filler/delay - allow slave to find and prepare data/response - uint8_t data[]; // data + checksum -} gs_param_spi_get_with_checksum_t; - -#ifdef __cplusplus -} -#endif -#endif -#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/rparam.h b/gomspace/libparam_client/include/gs/param/internal/rparam.h deleted file mode 100644 index ae70d215..00000000 --- a/gomspace/libparam_client/include/gs/param/internal/rparam.h +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef GS_PARAM_INTERNAL_RPARAM_H -#define GS_PARAM_INTERNAL_RPARAM_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#if (GS_PARAM_INTERNAL_USE) - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Max query payload in a single message (bytes). -*/ -#define GS_RPARAM_QUERY_MAX_PAYLOAD 180 - -/** - Macro for calculating total query message size, header + payload. -*/ -#define RPARAM_QUERY_LENGTH(query, payload_size) (sizeof(*query) - sizeof(query->payload) + payload_size) - -/** - R(emote) parameter request codes. -*/ -typedef enum { - /** - Get one or more parameters. - */ - RPARAM_GET = 0x00, - /** - Reply to a request. - */ - RPARAM_REPLY = 0x55, - /** - Set one or more parameters. - */ - RPARAM_SET = 0xFF, - // RPARAM_SET_TO_FILE = 0xEE, - /** - Download table specification. - */ - RPARAM_TABLE = 0x44, - /** - Copy memory slot to memory slot. - @version 4.x: Not supported. - */ - RPARAM_COPY = 0x77, - /** - Load from file (slot) to memory (slot). - @version 4.x: Only load from primary store - file (slot) is ignored. - */ - RPARAM_LOAD = 0x88, - /** - Load from file (slot) to memory (slot). - @version 4.x: load by name(s). - */ - RPARAM_LOAD_FROM_STORE = 0x89, - /** - Save from memory (slot) to file (slot). - @version 4.x: Only save to primary store - file (slot) is ignored. - */ - RPARAM_SAVE = 0x99, - /** - Save from memory (slot) to file (slot). - @version 4.x: save by name(s). - */ - RPARAM_SAVE_TO_STORE = 0x9a, - // RPARAM_CLEAR = 0xAA, - completely removed -} gs_rparam_action_t; - -/** - R(emote) parameter reply/completion codes. -*/ -typedef enum { - RPARAM_SET_OK = 1, - RPARAM_LOAD_OK = 2, - RPARAM_SAVE_OK = 3, - RPARAM_COPY_OK = 4, - // RPARAM_CLEAR_OK = 5, - RPARAM_ERROR = 0xFF, -} gs_rparam_reply_t; - -/** - Payload - save/load to/from stores - @version 4 -*/ -typedef struct __attribute__ ((packed)) { - char table[25 + 1]; - char store[25 + 1]; - char slot[25 + 1]; -} gs_rparam_query_payload_store_t; - -/** - Payload. -*/ -typedef union __attribute__ ((packed)) { - uint16_t addr[0]; //! action = RPARAM_GET - uint8_t packed[0]; //! action = RPARAM_REPLY | RPARAM_SET - struct { //! action = RPARAM_COPY | RPARAM_LOAD | RPARM_SAVE - uint8_t from; - uint8_t to; - } copy; -} gs_rparam_query_payload_t; - -/** - Protocol between client and server. - @version 4.x: layout (size) has not changed - only naming of certain fields. -*/ -typedef struct __attribute__ ((packed)) { - /** - Request (gs_rparam_action_t) or Reply (gs_rparam_reply_t). - */ - uint8_t action; - /** - Table id. - Name changed in 4.0 from \a mem. - */ - uint8_t table_id; - /** - Length/size of \a payload in bytes. - */ - uint16_t length; - /** - Fletcher's checksum. - */ - uint16_t checksum; - /** - Sequence number when split over multiple frames (messages). - */ - uint16_t seq; - /** - Total number of frames. - */ - uint16_t total; - /** - Payload. - */ - gs_rparam_query_payload_t payload; -} gs_rparam_query_t; - -#ifdef __cplusplus -} -#endif -#endif -#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/serialize.h b/gomspace/libparam_client/include/gs/param/internal/serialize.h deleted file mode 100644 index 704b67f5..00000000 --- a/gomspace/libparam_client/include/gs/param/internal/serialize.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef GS_PARAM_INTERNAL_SERIALIZE_H -#define GS_PARAM_INTERNAL_SERIALIZE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#if (GS_PARAM_INTERNAL_USE) - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Serialize data - * @param mem Pointer to indexed parameter table - * @param addr Array of addresses to serialize - * @param addr_count number of items in addr array - * @param[in|out] param_offset table parameter offset - * @param flags Set options using combination of flags - * @param buf Pointer to output - * @param buf_size Size of \a buf. - */ -gs_error_t gs_param_serialize_list(gs_param_table_instance_t * tinst, const uint16_t addr[], unsigned int addr_count, unsigned int * param_pos, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos); - -#ifdef __cplusplus -} -#endif -#endif -#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/table.h b/gomspace/libparam_client/include/gs/param/internal/table.h deleted file mode 100644 index 11b123bc..00000000 --- a/gomspace/libparam_client/include/gs/param/internal/table.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef GS_PARAM_INTERNAL_TABLE_H -#define GS_PARAM_INTERNAL_TABLE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#if (GS_PARAM_INTERNAL_USE) - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -gs_error_t gs_param_parse_name_and_array_index(const char * inp, char * name, size_t size_name, uint8_t * array_index, bool * return_is_array); - -#ifdef __cplusplus -} -#endif -#endif -#endif diff --git a/gomspace/libparam_client/include/gs/param/internal/types.h b/gomspace/libparam_client/include/gs/param/internal/types.h deleted file mode 100644 index 2644cc62..00000000 --- a/gomspace/libparam_client/include/gs/param/internal/types.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef GS_PARAM_INTERNAL_TYPES_H -#define GS_PARAM_INTERNAL_TYPES_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Table instance. -*/ -struct gs_param_table_instance { - /** - Name of table. - */ - const char * name; - - /** - Table id. - */ - gs_param_table_id_t id; - - /** - Table elements/rows. - */ - const gs_param_table_row_t * rows; - /** - Table element/row count. - */ - unsigned int row_count; - - /** - Table memory - volatile parameter store. - The allocated size must be at least \a memory_size bytes. - */ - void * memory; - - /** - Size of table data memory in bytes, normally size of memory allocated \a memory. - Size must always be specified, even when using function interface and no memory is allocated. - */ - unsigned int memory_size; - - /** - Function interface, e.g. get/set. - */ - gs_param_function_interface_t function_interface; - - /** - Checksum - based on host order (e.g. le or be). - @see gs_param_table_checksum() - */ - uint16_t checksum; - - /** - Checksum - based on big-endian (address converted to big-endian). - @see gs_param_table_checksum_be() - */ - uint16_t checksum_be; - - /** - Checksum - based on little-endian (address converted to little-endian). - @see gs_param_table_checksum_le() - */ - uint16_t checksum_le; - - /** - Lock. - Internal access/use only, use gs_param_lock() and gs_param_unlock() to lock and un-lock table. - */ - gs_mutex_t lock; - - /** - Callback for table (data) change. - */ - void (*callback)(uint16_t addr, gs_param_table_instance_t * tinst); - - /** - Store location(s). - CSV format, e.g. \"persistent,protected\". - */ - const char * stores; - - /** - Auto-persist. - */ - struct { - /** - Store. - */ - const char * store; - - /** - User context(s) for the \a set function. - */ - void * context1; - void * context2; - - /** - Set/write parameter. - */ - gs_error_t (*set)(gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, const void * item, size_t size, uint32_t flags); - } auto_persist; - - /** - Function for initializing table. - */ - gs_error_t (*initializer_function)(gs_param_table_instance_t * tinst); - - /** - Default values for initializing table. - */ - const void * default_values; - - /** - Future flags. - */ - uint32_t flags; -}; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libparam_client/include/gs/param/pp/i2c/i2c.h b/gomspace/libparam_client/include/gs/param/pp/i2c/i2c.h deleted file mode 100644 index 7ffdfd1b..00000000 --- a/gomspace/libparam_client/include/gs/param/pp/i2c/i2c.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef GS_PARAM_PP_I2C_I2C_H -#define GS_PARAM_PP_I2C_I2C_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - I2C param protocol client interface. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Commands. -*/ -typedef enum { - /** - Set parameter. - */ - GS_PARAM_I2C_COMMAND_SET = 1, - /** - Get parameter. - */ - GS_PARAM_I2C_COMMAND_GET = 2, - /** - Lock table. - */ - GS_PARAM_I2C_COMMAND_SET_LOCK_WITH_CHECKSUM = 3, - /** - Get table lock state. - */ - GS_PARAM_I2C_COMMAND_GET_LOCK_WITH_CHECKSUM = 4, - /** - Set parameter with checksum. - */ - GS_PARAM_I2C_COMMAND_SET_WITH_CHECKSUM = 10, - /** - Get parameter with checksum. - */ - GS_PARAM_I2C_COMMAND_GET_WITH_CHECKSUM = 11, -} gs_param_i2c_command_t; - -/** - Initialize the param protocol handle for I2C. - - @param[in] pp handle. - @param[in] bus bus to communicate on. - @param[in] addr address of node. - @param[in] big_endian \a true if slave is big endian. Used to convert to host endian. - @return_gs_error_t -*/ -gs_error_t gs_pp_i2c_init(gs_pp_t * pp, uint8_t bus, uint8_t addr, bool big_endian); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libparam_client/include/gs/param/pp/pp.h b/gomspace/libparam_client/include/gs/param/pp/pp.h deleted file mode 100644 index a3bbb539..00000000 --- a/gomspace/libparam_client/include/gs/param/pp/pp.h +++ /dev/null @@ -1,214 +0,0 @@ -#ifndef GS_PARAM_PP_PP_H -#define GS_PARAM_PP_PP_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Param Protocol (PP) API - generic interface for getting/setting parameters over SPI, I2C, etc. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Flags used in gs_pp_xxx() functions. - @{ -*/ -/** - Use checksum in transfer. - @see gs_pp_checksum8() -*/ -#define GS_PP_FLAG_CHECKSUM 0x0001 -/**@}*/ - -/** - Handle for a protocol connection. -*/ -typedef struct gs_pp gs_pp_t; - -/** - Callback for getting a parameter. -*/ -typedef gs_error_t (*gs_pp_get_t)(gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, uint32_t flags); - -/** - Callback for setting a parameter. -*/ -typedef gs_error_t (*gs_pp_set_t)(gs_pp_t * pp, uint8_t table_id, uint16_t addr, const void * value, size_t value_size, uint32_t flags); - -/** - Callback for setting table lock. -*/ -typedef gs_error_t (*gs_pp_get_table_lock_t)(gs_pp_t * pp, uint8_t table_id, bool * value, uint32_t flags); - -/** - Callback for setting table lock. -*/ -typedef gs_error_t (*gs_pp_set_table_lock_t)(gs_pp_t * pp, uint8_t table_id, const bool * value, uint32_t flags); - -/** - Handle for a protocol connection. -*/ -struct gs_pp { - /** - Endian type of slave. - */ - bool big_endian; - /** - Callback function for \a get. - */ - gs_pp_get_t get; - /** - Callback function for \a set. - */ - gs_pp_set_t set; - /** - Callback function for \a get_table_lock. - */ - gs_pp_get_table_lock_t get_table_lock; - /** - Callback function for \a set_table_lock. - */ - gs_pp_set_table_lock_t set_table_lock; - /** - Protocol specifics. - */ - union { - /** - SPI connection. - */ - struct { - /** - SPI slave id. - */ - uint8_t slave; - } spi; - /** - I2C connection. - */ - struct { - /** - I2C bus. - */ - uint8_t bus; - /** - I2C address. - */ - uint8_t addr; - } i2c; - } pp; -}; - -/** - Calculate very simple 8 bit checksum. - The checksum is calculated by adding all bytes. If the checksum is 0 (zero), the checksum is set to 1 (one). - @param[in] data data to calculate checksum for. - @param[in] length data length. - @return checksum -*/ -uint8_t gs_pp_checksum8(const void * data, size_t length); - -/** - Get lock value - - @param[in] pp Handle for connection - @param[in] table_id Table ID - @param[out] value Lock state (0 = unlocked, 1 = locked) - @param[in] flags - @return_gs_error_t - */ -gs_error_t gs_pp_get_table_lock(gs_pp_t * pp, uint8_t table_id, bool * value, uint32_t flags); - -/** - Set lock value - - @param[in] pp Handle for connection - @param[in] table_id Table ID - @param[in] value Lock state (0 = unlocked, 1 = locked) - @param[in] flags - @return_gs_error_t -*/ -gs_error_t gs_pp_set_table_lock(gs_pp_t * pp, uint8_t table_id, const bool * value, uint32_t flags); - -/** - Get int8. -*/ -gs_error_t gs_pp_get_int8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int8_t * value, size_t count, uint32_t flags); - -/** - Set int8. -*/ -gs_error_t gs_pp_set_int8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int8_t * value, size_t count, uint32_t flags); - -/** - Get uint8. -*/ -gs_error_t gs_pp_get_uint8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint8_t * value, size_t count, uint32_t flags); - -/** - Set uint8. -*/ -gs_error_t gs_pp_set_uint8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint8_t * value, size_t count, uint32_t flags); - -/** - Get int16. -*/ -gs_error_t gs_pp_get_int16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int16_t * value, size_t count, uint32_t flags); - -/** - Set int16. -*/ -gs_error_t gs_pp_set_int16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int16_t * value, size_t count, uint32_t flags); - -/** - Get uint16. -*/ -gs_error_t gs_pp_get_uint16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint16_t * value, size_t count, uint32_t flags); - -/** - Set uint16. -*/ -gs_error_t gs_pp_set_uint16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint16_t * value, size_t count, uint32_t flags); - -/** - Get int32. -*/ -gs_error_t gs_pp_get_int32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int32_t * value, size_t count, uint32_t flags); - -/** - Set int32. -*/ -gs_error_t gs_pp_set_int32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int32_t * value, size_t count, uint32_t flags); - -/** - Get uint32. -*/ -gs_error_t gs_pp_get_uint32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint32_t * value, size_t count, uint32_t flags); - -/** - Set uint32. -*/ -gs_error_t gs_pp_set_uint32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint32_t * value, size_t count, uint32_t flags); - -/** - Get float. -*/ -gs_error_t gs_pp_get_float(gs_pp_t * pp, uint8_t table_id, uint8_t addr, float * value, size_t count, uint32_t flags); - -/** - Set float. -*/ -gs_error_t gs_pp_set_float(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const float * value, size_t count, uint32_t flags); - -/** - Register commands. -*/ -gs_error_t gs_pp_register_commands(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libparam_client/include/gs/param/pp/spi/spi.h b/gomspace/libparam_client/include/gs/param/pp/spi/spi.h deleted file mode 100644 index 32006c45..00000000 --- a/gomspace/libparam_client/include/gs/param/pp/spi/spi.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef GS_PARAM_PP_SPI_SPI_H -#define GS_PARAM_PP_SPI_SPI_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - SPI Param Protocol (pp) client interface. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Initialize the param protocol handle for SPI. - - @param[in] pp handle. - @param[in] slave slave to communicate with. - @param[in] big_endian \a true if slave is big endian. Used to convert to host endian. - @return_gs_error_t -*/ -gs_error_t gs_pp_spi_init(gs_pp_t * pp, uint8_t slave, bool big_endian); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libparam_client/include/gs/param/rparam.h b/gomspace/libparam_client/include/gs/param/rparam.h deleted file mode 100644 index 950e22cf..00000000 --- a/gomspace/libparam_client/include/gs/param/rparam.h +++ /dev/null @@ -1,395 +0,0 @@ -#ifndef GS_PARAM_REMOTE_H -#define GS_PARAM_REMOTE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Remote parameter API - pending refactoring. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Magic checksum. - If specifying a magic checksum, the rparam server will ignore/skip checksum validation. -*/ -#define GS_RPARAM_MAGIC_CHECKSUM 0x0bb0 - -/** - Register rparam commands. - @return_gs_error_t -*/ -gs_error_t gs_rparam_register_commands(void); - -/** - Download all (data) values from a remote table to a local instance. - - @param[in] tinst local table instance. - @param[in] node CSP address. - @param[in] table_id remote table id to download. - @param[in] checksum table checksum. - @param[in] timeout_ms timeout. - @return_gs_error_t -*/ -gs_error_t gs_rparam_get_full_table(gs_param_table_instance_t * tinst, - uint8_t node, - gs_param_table_id_t table_id, - uint16_t checksum, - uint32_t timeout_ms); - -/** - Download a table specification from a remote node, store it in memory and save it to local file system. - - @note Will free existing rows - do not use this on table instances with static assigned rows. - - Table memory will be (re)allocated to match specification. - - @param[in] tinst local table instance. - @param[in] fname name of the file to store the table specification in. If NULL, no file will be stored. - @param[in] node CSP address - @param[in] table_id remote table id to download. - @param[in] timeout_ms timeout. - @param[out] return_checksum fletcher16 checksum of downloaded specification "as is" - before network/host swapping. - @return_gs_error_t - @see gs_param_table_free() -*/ -gs_error_t gs_rparam_download_table_spec(gs_param_table_instance_t * tinst, - const char * fname, - uint8_t node, - gs_param_table_id_t table_id, - uint32_t timeout_ms, - uint16_t * return_checksum); - -/** - Load a table specification from a local file and store it in memory. - - @note Will free existing rows - do not use this on table instances with static assigned rows. - - Table memory will be (re)allocated to match specification. - - @param[in] tinst local table instance. - @param[in] fname name of the file to load the table specification from. - @param[out] return_checksum fletcher16 checksum stored in file. - @return_gs_error_t - @see gs_param_table_free() -*/ -gs_error_t gs_rparam_load_table_spec(gs_param_table_instance_t * tinst, const char* fname, uint16_t * return_checksum); - -/** - Copy from one table to another table. - - @deprecated Not supported by a param 4 backend and future versions. - - @param[in] node CSP address - @param[in] timeout_ms timeout on remote CSP calls - @param[in] from from table-id. - @param[in] to to table-id. - @return_gs_error_t -*/ -gs_error_t gs_rparam_copy(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to); - -/** - Save table. - - @note On a param 4 backend, the table will always be saved to it's primary store. - - @param[in] node CSP address - @param[in] timeout_ms timeout on remote CSP calls - @param[in] id table to save. - @param[in] to to file slot - ignored on param 4 backends. - @return_gs_error_t -*/ -gs_error_t gs_rparam_save(uint8_t node, uint32_t timeout_ms, gs_param_table_id_t id, uint8_t to); - -/** - Save table. - - @version 4 - @param[in] node CSP address - @param[in] timeout_ms timeout on remote CSP calls - @param[in] table_id remote table id. - @param[in] store store name. - @param[in] slot slot within store. - @return_gs_error_t -*/ -gs_error_t gs_rparam_save_to_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id, - const char * store, const char * slot); - -/** - Load table from store. - - @note On a param 4 backend, the specified table will be loadded from it's primary store. - - @param[in] node CSP address - @param[in] timeout_ms timeout on remote CSP calls - @param[in] from from file slot - ignored on param 4 backends. - @param[in] id table to load. - @return_gs_error_t -*/ -gs_error_t gs_rparam_load(uint8_t node, uint32_t timeout_ms, uint8_t from, gs_param_table_id_t id); - -/** - Load table from store. - - @version 4 - @param[in] node CSP address - @param[in] timeout_ms timeout on remote CSP calls - @param[in] table_id remote table id. - @param[in] store store name. - @param[in] slot slot within store. - @return_gs_error_t -*/ -gs_error_t gs_rparam_load_from_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id, - const char * store, const char * slot); - -/** - Get parameter. - - @param[in] node CSP address - @param[in] table_id remote table id. - @param[in] addr parameter address (remote table). - @param[in] type parameter type. - @param[in] checksum checksum - @param[in] timeout_ms timeout - @param[out] value returned value (user allocated) - @param[in] value_size size of \a value buffer. - @return_gs_error_t -*/ -gs_error_t gs_rparam_get(uint8_t node, - gs_param_table_id_t table_id, - uint16_t addr, - gs_param_type_t type, - uint16_t checksum, - uint32_t timeout_ms, - void * value, - size_t value_size); - -/** - Set parameter. - - @param[in] node CSP address - @param[in] table_id remote table id. - @param[in] addr parameter address (remote table). - @param[in] type parameter type. - @param[in] checksum checksum - @param[in] timeout_ms timeout - @param[in] value value to set - @param[in] value_size size of \a value. - @return_gs_error_t -*/ -gs_error_t gs_rparam_set(uint8_t node, - gs_param_table_id_t table_id, - uint16_t addr, - gs_param_type_t type, - uint16_t checksum, - uint32_t timeout_ms, - const void * value, - size_t value_size); - -/** - Get string. -*/ -static inline gs_error_t gs_rparam_get_string(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, char * value, size_t value_size) -{ - return gs_rparam_get(node, table_id, addr, GS_PARAM_STRING, checksum, timeout_ms, value, value_size); -} - -/** - Set string. -*/ -static inline gs_error_t gs_rparam_set_string(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, const char * value, size_t value_size) -{ - return gs_rparam_set(node, table_id, addr, GS_PARAM_STRING, checksum, timeout_ms, value, (value_size == 0) ? (strlen(value) + 1) : value_size); -} - -/** - Get int8. -*/ -static inline gs_error_t gs_rparam_get_int8(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, int8_t * value) -{ - return gs_rparam_get(node, table_id, addr, GS_PARAM_INT8, checksum, timeout_ms, value, sizeof(*value)); -} - -/** - Set int8. -*/ -static inline gs_error_t gs_rparam_set_int8(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, int8_t value) -{ - return gs_rparam_set(node, table_id, addr, GS_PARAM_INT8, checksum, timeout_ms, &value, sizeof(value)); -} - -/** - Get uint8. -*/ -static inline gs_error_t gs_rparam_get_uint8(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, uint8_t * value) -{ - return gs_rparam_get(node, table_id, addr, GS_PARAM_UINT8, checksum, timeout_ms, value, sizeof(*value)); -} - -/** - Set uint8. -*/ -static inline gs_error_t gs_rparam_set_uint8(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, uint8_t value) -{ - return gs_rparam_set(node, table_id, addr, GS_PARAM_UINT8, checksum, timeout_ms, &value, sizeof(value)); -} - -/** - Get int16. -*/ -static inline gs_error_t gs_rparam_get_int16(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, int16_t * value) -{ - return gs_rparam_get(node, table_id, addr, GS_PARAM_INT16, checksum, timeout_ms, value, sizeof(*value)); -} - -/** - Set int16. -*/ -static inline gs_error_t gs_rparam_set_int16(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, int16_t value) -{ - return gs_rparam_set(node, table_id, addr, GS_PARAM_INT16, checksum, timeout_ms, &value, sizeof(value)); -} - -/** - Get uint16. -*/ -static inline gs_error_t gs_rparam_get_uint16(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, uint16_t * value) -{ - return gs_rparam_get(node, table_id, addr, GS_PARAM_UINT16, checksum, timeout_ms, value, sizeof(*value)); -} - -/** - Set uint16. -*/ -static inline gs_error_t gs_rparam_set_uint16(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, uint16_t value) -{ - return gs_rparam_set(node, table_id, addr, GS_PARAM_UINT16, checksum, timeout_ms, &value, sizeof(value)); -} - -/** - Get int32. -*/ -static inline gs_error_t gs_rparam_get_int32(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, int32_t * value) -{ - return gs_rparam_get(node, table_id, addr, GS_PARAM_INT32, checksum, timeout_ms, value, sizeof(*value)); -} - -/** - Set int32. -*/ -static inline gs_error_t gs_rparam_set_int32(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, int32_t value) -{ - return gs_rparam_set(node, table_id, addr, GS_PARAM_INT32, checksum, timeout_ms, &value, sizeof(value)); -} - -/** - Get uint32. -*/ -static inline gs_error_t gs_rparam_get_uint32(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, uint32_t * value) -{ - return gs_rparam_get(node, table_id, addr, GS_PARAM_UINT32, checksum, timeout_ms, value, sizeof(*value)); -} - -/** - Set uint32. -*/ -static inline gs_error_t gs_rparam_set_uint32(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, uint32_t value) -{ - return gs_rparam_set(node, table_id, addr, GS_PARAM_UINT32, checksum, timeout_ms, &value, sizeof(value)); -} - -/** - Get int64. -*/ -static inline gs_error_t gs_rparam_get_int64(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, int64_t * value) -{ - return gs_rparam_get(node, table_id, addr, GS_PARAM_INT64, checksum, timeout_ms, value, sizeof(*value)); -} - -/** - Set int64. -*/ -static inline gs_error_t gs_rparam_set_int64(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, int64_t value) -{ - return gs_rparam_set(node, table_id, addr, GS_PARAM_INT64, checksum, timeout_ms, &value, sizeof(value)); -} - -/** - Get uint64. -*/ -static inline gs_error_t gs_rparam_get_uint64(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, uint64_t * value) -{ - return gs_rparam_get(node, table_id, addr, GS_PARAM_UINT64, checksum, timeout_ms, value, sizeof(*value)); -} - -/** - Set uint64. -*/ -static inline gs_error_t gs_rparam_set_uint64(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, uint64_t value) -{ - return gs_rparam_set(node, table_id, addr, GS_PARAM_UINT64, checksum, timeout_ms, &value, sizeof(value)); -} - -/** - Get float. -*/ -static inline gs_error_t gs_rparam_get_float(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, float * value) -{ - return gs_rparam_get(node, table_id, addr, GS_PARAM_FLOAT, checksum, timeout_ms, value, sizeof(*value)); -} - -/** - Set float. -*/ -static inline gs_error_t gs_rparam_set_float(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, float value) -{ - return gs_rparam_set(node, table_id, addr, GS_PARAM_FLOAT, checksum, timeout_ms, &value, sizeof(value)); -} - -/** - Get double. -*/ -static inline gs_error_t gs_rparam_get_double(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, double * value) -{ - return gs_rparam_get(node, table_id, addr, GS_PARAM_DOUBLE, checksum, timeout_ms, value, sizeof(*value)); -} - -/** - Set double. -*/ -static inline gs_error_t gs_rparam_set_double(uint8_t node, gs_param_table_id_t table_id, uint16_t addr, - uint16_t checksum, uint32_t timeout_ms, double value) -{ - return gs_rparam_set(node, table_id, addr, GS_PARAM_DOUBLE, checksum, timeout_ms, &value, sizeof(value)); -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libparam_client/include/gs/param/serialize.h b/gomspace/libparam_client/include/gs/param/serialize.h deleted file mode 100644 index 9b935e3d..00000000 --- a/gomspace/libparam_client/include/gs/param/serialize.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef GS_PARAM_CLIENT_SERIALIZE_H -#define GS_PARAM_CLIENT_SERIALIZE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Serialize API - pending refactoring. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Serialize/deserialize flags - Flags must be in range: bit 8 - 15, to avoid clash with other parts of the parameter system. -*/ -typedef enum { - GS_PARAM_SF_DRY_RUN = (1 << 8), //!< F_DRY_RUN do not write to memory - GS_PARAM_SF_TO_BIG_ENDIAN = (1 << 9), //!< F_TO_BIG_ENDIAN Convert from host to big endian - GS_PARAM_SF_FROM_BIG_ENDIAN = (1 << 10), //!< F_FROM_BIG_ENDIAN Confert from big endian to host order - GS_PARAM_SF_PACKED = (1 << 11), //!< F_PACKED Do not pack addresses - - F_DRY_RUN = GS_PARAM_SF_DRY_RUN, - F_TO_BIG_ENDIAN = GS_PARAM_SF_TO_BIG_ENDIAN, - F_FROM_BIG_ENDIAN = GS_PARAM_SF_FROM_BIG_ENDIAN, - F_PACKED = GS_PARAM_SF_PACKED, -} gs_param_serialize_flags_t; - -/** - * In-place conversion of a single parameter from big endian to host byte order - * @param type param type - * @param item pointer to parameter memory - * @return 1 if memory has been swapped, 0 if not - */ -bool gs_param_betoh(gs_param_type_t type, void * item); - -/** - * In-place conversion of a single parameter from host byte order to big endian - * @param type param type - * @param item porinter to parameter memory - * @return 1 if memory has been swapped, 0 if not - */ -bool gs_param_htobe(gs_param_type_t type, void * item); - -/** - Serialize data - - @param[in] tinst table. - @param[in,out] param_pos parameter iterator. - @param[in] flags flags. - @param[out] buf user supplied buffer of \a buf_size. - @param[in] buf_size of size of \a buf - @param[in,out] buf_pos index into \a buf - @return_gs_error_t -*/ -gs_error_t gs_param_serialize_full_table(gs_param_table_instance_t * tinst, unsigned int * param_pos, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos); - -/** - Serialize single item - - @param[in] param parameter to serialize - @param[in] addr Address of item - @param[in] item item to serialize. - @param[in] flags flags. - @param[out] buf user supplied buffer of \a buf_size. - @param[in] buf_size of size of \a buf - @param[in,out] buf_pos index into \a buf - @return_gs_error_t -*/ -gs_error_t gs_param_serialize_item(const gs_param_table_row_t * param, uint16_t addr, const void * item, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos); - -/** - Deserialize packed parameters into memory - - @param[in] tinst table. - @param[in] buf serialized data. - @param[in] buf_size size \a buf containing serialized data - @param[in] flags flags. - @return_gs_error_t -*/ -gs_error_t gs_param_deserialize(gs_param_table_instance_t * tinst, const uint8_t * buf, unsigned int buf_size, uint32_t flags); - -/** - Deserialize a sginle item from a string into memory - - @param[in] tinst table. - @param param Pointer to specific parameter to deserialize - @param addr Address of parameter - @param item Pointer to memory area where item should be written - @param flags Set options using combination of flags - @return_gs_error_t -*/ -gs_error_t gs_param_deserialize_item(gs_param_table_instance_t * tinst, const gs_param_table_row_t * param, uint16_t addr, const void * item, uint32_t flags); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libparam_client/include/gs/param/table.h b/gomspace/libparam_client/include/gs/param/table.h deleted file mode 100644 index 0b5e153d..00000000 --- a/gomspace/libparam_client/include/gs/param/table.h +++ /dev/null @@ -1,428 +0,0 @@ -#ifndef GS_PARAM_TABLE_H -#define GS_PARAM_TABLE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Client table API. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Allocate table memory when creating a table. - - Flags must be in range: bit 16 - 23, to avoid clash with other parts of the parameter system. -*/ -#define GS_PARAM_TABLE_F_ALLOC_MEMORY 0x0100 -/** - Allocate table rows. - - Flags must be in range: bit 16 - 23, to avoid clash with other parts of the parameter system. -*/ -#define GS_PARAM_TABLE_F_ALLOC_ROWS 0x0200 -/** - Disable table locking. - - Flags must be in range: bit 16 - 23, to avoid clash with other parts of the parameter system. -*/ -#define GS_PARAM_TABLE_F_NO_LOCK 0x0400 - -/** - Calculate memory size based on table rows. - - @param[in] rows rows - @param[in] row_count row count. - @return size of table or 0 in case of invalid arguments. -*/ -size_t gs_param_calc_table_size(const gs_param_table_row_t * rows, size_t row_count); - -/** - Return size of table instance. -*/ -size_t gs_param_table_instance_size(void); - -/** - Clear (and check size) of memory for table instance. - - @param[in] var user allocated space of at least gs_param_table_instance_size() bytes. - @param[in] var_size of \a var. - @return table instance - @see gs_param_table_instance_size() - @see #GS_PARAM_TINST_VAR -*/ -gs_param_table_instance_t * gs_param_table_instance_clear(void * var, size_t var_size); - -/** - Allocates aligned space on the stack for a table instance structure. - @param[in] var name of table instsance variable. -*/ -#define GS_PARAM_TINST_VAR(var) uint8_t var##__data [gs_param_table_instance_size()] __attribute__ ((aligned(4))); gs_param_table_instance_t * var = gs_param_table_instance_clear(var##__data, sizeof(var##__data)) - -/** - Allocate memory for table instance. - - Use gs_param_table_free() to free any internal resources. - - Use standard free() to free allocated memory. - - @return table instance on success, otherwise NULL. -*/ -gs_param_table_instance_t * gs_param_table_instance_alloc(void); - -/** - Find row by name. - - @param[in] name parameter name. - @param[in] rows rows - @param[in] row_count row count. - @return row or NULL if not found. -*/ -const gs_param_table_row_t * gs_param_row_by_name(const char * name, const gs_param_table_row_t * rows, size_t row_count); - -/** - Find row by address. - - @param[in] addr parameter address. - @param[in] rows rows - @param[in] row_count row count. - @return row or NULL if not found. -*/ -const gs_param_table_row_t * gs_param_row_by_address(uint16_t addr, const gs_param_table_row_t * rows, size_t row_count); - -/** - Return table memory. - - @note handle with care - any read/write should be atomic to prevent inconsistent data. - - @param[in] tinst table instance - @param[out] return_size if not NULL, the memory size is returned. - @return pointer to the table's data memory. -*/ -void * gs_param_table_get_memory(gs_param_table_instance_t * tinst, size_t * return_size); - -/** - Return table rows. - - @param[in] tinst table instance - @param[out] return_count if not NULL, the row count is returned. - @return pointer to the table rows. -*/ -const gs_param_table_row_t * gs_param_table_get_rows(gs_param_table_instance_t * tinst, size_t * return_count); - -/** - Lock table (recursive). - - @param[in] tinst table instance - @return_gs_error_t -*/ -gs_error_t gs_param_table_lock(gs_param_table_instance_t * tinst); - -/** - Unlock table. - - Unlock must be called once for every time gs_param_table_lock() has been called. - - @param[in] tinst table instance - @return_gs_error_t -*/ -gs_error_t gs_param_table_unlock(gs_param_table_instance_t * tinst); - -/** - Free internal resources and clears instance. - - @param[in] tinst table instance - @return_gs_error_t -*/ -gs_error_t gs_param_table_free(gs_param_table_instance_t * tinst); - -/** - Print a single parameter on stream. - - @param[in] tinst table instanc. - @param[in] row row to print. - @param[in] list_data \a true includes parameter value. - @param[in] flags flags to control output format: #GS_PARAM_F_SHOW_SCIENTIFIC, #GS_PARAM_F_SHOW_HEX. - @param[in] out output stream. - @return_gs_error_t -*/ -gs_error_t gs_param_list_single_to_stream(gs_param_table_instance_t * tinst, const gs_param_table_row_t * row, bool list_data, uint32_t flags, FILE * out); - -/** - Print a single parameter on stdout. - - @param[in] tinst table instanc. - @param[in] row row to print. - @param[in] list_data \a true includes parameter value. - @return_gs_error_t -*/ -static inline gs_error_t gs_param_list_single(gs_param_table_instance_t * tinst, const gs_param_table_row_t * row, bool list_data) -{ - return gs_param_list_single_to_stream(tinst, row, list_data, 0, stdout); -} - -/** - Print entire table on stream. - - @param[in] tinst table instanc. - @param[in] list_data \a true includes parameter value. - @param[in] flags flags to control output format: #GS_PARAM_F_SHOW_SCIENTIFIC, #GS_PARAM_F_SHOW_HEX. - @param[in] out output stream. - @return_gs_error_t -*/ -gs_error_t gs_param_list_to_stream(gs_param_table_instance_t * tinst, bool list_data, uint32_t flags, FILE * out); - -/** - Print entire table on stdout. - - @param[in] tinst table instanc. - @param[in] list_data \a true includes parameter value. - @return_gs_error_t -*/ -static inline gs_error_t gs_param_list(gs_param_table_instance_t * tinst, bool list_data) -{ - return gs_param_list_to_stream(tinst, list_data, 0, stdout); -} - -/** - Convert string to parameter. - - @param[in] row row defining the parameter to convert. - @param[in] string string to convert. - @param[out] return_value user supplied buffer for returning the value - must be at least the size specified in \a row - @return_gs_error_t -*/ -gs_error_t gs_param_from_string(const gs_param_table_row_t * row, const char * string, void * return_value); - -/** - Convert parameter to string. - - @param[in] row row defining the parameter to convert. - @param[in] value parameter value to convert. - @param[in] with_type \a true includes data type. - @param[in] flags flags to control output format: #GS_PARAM_F_SHOW_SCIENTIFIC, #GS_PARAM_F_SHOW_HEX. - @param[out] buf user supplied buffer of \a buf_size bytes. - @param[in] buf_size size of \a buf in bytes. - @param[in] buf_pos buffer position to insert string. - @param[out] return_buf_written number of bytes written to \a buf. - @return_gs_error_t -*/ -gs_error_t gs_param_to_string2(const gs_param_table_row_t * row, const void * value, bool with_type, uint32_t flags, char * buf, unsigned int buf_size, unsigned int buf_pos, unsigned int * return_buf_written); - -/** - Convert parameter to string. - - @param[in] row row defining the parameter to convert. - @param[in] value parameter value to convert. - @param[in] with_type \a true includes data type. - @param[out] buf user supplied buffer of \a buf_size bytes. - @param[in] buf_size size of \a buf in bytes. - @param[in] buf_pos buffer position to insert string. - @param[out] return_buf_written number of bytes written to \a buf. - @return_gs_error_t -*/ -static inline gs_error_t gs_param_to_string(const gs_param_table_row_t * row, const void * value, bool with_type, char * buf, unsigned int buf_size, unsigned int buf_pos, unsigned int * return_buf_written) -{ - return gs_param_to_string2(row, value, with_type, 0, buf, buf_size, buf_pos, return_buf_written); -} - -/** - Convert parameter type to string. - - @param[in] type parameter type. - @return pointer to a static string. -*/ -const char * gs_param_type_to_string(gs_param_type_t type); - -/** - Return size of parameter type. - - @param[in] type parameter type. - @return size of parameter type in bytes. -*/ -uint8_t gs_param_type_size(gs_param_type_t type); - -/** - Get table checksum - little-endian. - @note Use/exchange gs_param_table_checksum_be(), as this is calculated the same on all platforms. - @param[in] tinst table instance. - @returns 16-bit fletcher checksum -*/ -uint16_t gs_param_table_checksum_le(gs_param_table_instance_t * tinst); - -/** - Get table checksum - big-endian/network-order (prefered). - @param[in] tinst table instance. - @returns 16-bit fletcher checksum -*/ -uint16_t gs_param_table_checksum_be(gs_param_table_instance_t * tinst); - -/** - Get table checksum - host-order (not cross-platform). - @deprecated use gs_param_table_checksum_be() - @param[in] tinst table instance. - @returns 16-bit fletcher checksum -*/ -uint16_t gs_param_table_checksum(gs_param_table_instance_t * tinst); - -/** - Get table checksum - big-endian. - @deprecated use gs_param_table_checksum_be() - @param[in] tinst table instance. - @returns 16-bit fletcher checksum -*/ -static inline uint16_t gs_param_table_checksum2(gs_param_table_instance_t * tinst) -{ - return gs_param_table_checksum_be(tinst); -} - -/** - Get/read parameter from table. - - @param[in] tinst table instanc. - @param[in] addr parameter address (offset in table). - @param[in] type parameter type. - @param[out] return_value value of parameter - user supplied memory of at least \a size size. - @param[in] size number of bytes to get/read - must match \a type, e.g. 4 bytes for an uint32_t. - @param[in] flags flags. - @return_gs_error_t -*/ -gs_error_t gs_param_get(gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, void * return_value, size_t size, uint32_t flags); - -/** - Set/write parameter in table. - - @param[in] tinst table instanc. - @param[in] addr parameter address (offset in table). - @param[in] type parameter type. - @param[in] value value of parameter. - @param[in] size number of bytes to set/write - must match \a type, e.g. 4 bytes for an uint32_t. - @param[in] flags flags. - @return_gs_error_t -*/ -gs_error_t gs_param_set(gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, const void * value, size_t size, uint32_t flags); - -/** - Get string parameter. - - @param[in] tinst table instanc. - @param[in] addr parameter address (offset in table). - @param[out] buf value of parameter - user supplied memory of at least parameter size + 1 to hold NUL termination. - @param[in] buf_size size of \a buf - ensure room for NUL termination. - @param[in] flags flags. - @return GS_ERROR_OVERFLOW if string + NUL termination exceeds \a buf_size. - @return_gs_error_t -*/ -gs_error_t gs_param_get_string(gs_param_table_instance_t * tinst, uint16_t addr, char * buf, size_t buf_size, uint32_t flags); - -/** - Set string parameter. - - @param[in] tinst table. - @param[in] addr parameter address (offset in table). - @param[in] value string to save - parameter must be able to hold string + NUL termination. - @param[in] flags flags. - @return GS_ERROR_OVERFLOW if string + NUL termination exceeds parameter size. - @return_gs_error_t -*/ -gs_error_t gs_param_set_string(gs_param_table_instance_t * tinst, uint16_t addr, const char * value, uint32_t flags); - -/** - Get data parameter. - - @param[in] tinst table instanc. - @param[in] addr parameter address (offset in table). - @param[out] buf value of parameter - user supplied memory of at least parameter size. - @param[in] buf_size size of \a buf. - @param[in] flags flags. - @return GS_ERROR_OVERFLOW if parameter size is greater than \a buf_size. - @return_gs_error_t -*/ -gs_error_t gs_param_get_data(gs_param_table_instance_t * tinst, uint16_t addr, void * buf, size_t buf_size, uint32_t flags); - -/** - Set data parameter. - - @param[in] tinst table instanc. - @param[in] addr parameter address (offset in table). - @param[in] value value of parameter. - @param[in] value_size size of \a value. - @param[in] flags flags. - @return GS_ERROR_OVERFLOW if parameter size is greater than \a buf_size. - @return_gs_error_t -*/ -gs_error_t gs_param_set_data(gs_param_table_instance_t * tinst, uint16_t addr, const void * value, size_t value_size, uint32_t flags); - -/** - Macro for expanding get/set functions. - @param[in] name function suffix name. - @param[in] native_type native type - @param[in] param_type parameter type -*/ -#define GS_PARAM_PASTE(name, native_type, param_type) \ - static inline gs_error_t gs_param_get_##name(gs_param_table_instance_t * tinst, uint16_t addr, native_type * buf, uint32_t flags) { \ - return gs_param_get(tinst, addr, param_type, buf, sizeof(*buf), flags); \ - } \ - static inline native_type gs_param_get_##name##_nc(gs_param_table_instance_t * tinst, uint16_t addr, uint32_t flags) { \ - native_type value = 0; \ - gs_param_get(tinst, addr, param_type, &value, sizeof(value), flags); \ - return value; \ - } \ - static inline gs_error_t gs_param_set_##name(gs_param_table_instance_t * tinst, uint16_t addr, native_type value, uint32_t flags) { \ - return gs_param_set(tinst, addr, param_type, &value, sizeof(value), flags); \ - } - -/** - Get/set boolean. -*/ -GS_PARAM_PASTE(bool, bool, GS_PARAM_BOOL) -/** - Get/set uint8. -*/ -GS_PARAM_PASTE(uint8, uint8_t, GS_PARAM_UINT8) -/** - Get/set uint16. -*/ -GS_PARAM_PASTE(uint16, uint16_t, GS_PARAM_UINT16) -/** - Get/set uint32. -*/ -GS_PARAM_PASTE(uint32, uint32_t, GS_PARAM_UINT32) -/** - Get/set uint64. -*/ -GS_PARAM_PASTE(uint64, uint64_t, GS_PARAM_UINT64) -/** - Get/set int8. -*/ -GS_PARAM_PASTE(int8, int8_t, GS_PARAM_INT8) -/** - Get/set int16. -*/ -GS_PARAM_PASTE(int16, int16_t, GS_PARAM_INT16) -/** - Get/set int32. -*/ -GS_PARAM_PASTE(int32, int32_t, GS_PARAM_INT32) -/** - Get/set int64. -*/ -GS_PARAM_PASTE(int64, int64_t, GS_PARAM_INT64) -/** - Get/set double. -*/ -GS_PARAM_PASTE(double, double, GS_PARAM_DOUBLE) -/** - Get/set float. -*/ -GS_PARAM_PASTE(float, float, GS_PARAM_FLOAT) - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libparam_client/include/gs/param/types.h b/gomspace/libparam_client/include/gs/param/types.h deleted file mode 100644 index 61efbb10..00000000 --- a/gomspace/libparam_client/include/gs/param/types.h +++ /dev/null @@ -1,272 +0,0 @@ -#ifndef GS_PARAM_TYPES_H -#define GS_PARAM_TYPES_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Parameter types. -*/ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Macros for accessing table row members. - These macros can be used to access members in a cross-platform way, compensating for the AVR8's memory model. - @{ -*/ -#define GS_PARAM_ARRAY_SIZE(p) gs_max(GS_PGM_UINT8((p)->array_size), 1) -#define GS_PARAM_SIZE(p) GS_PGM_UINT8((p)->size) -#define GS_PARAM_TYPE(p) GS_PGM_UINT8((p)->type) -#define GS_PARAM_ADDR(p) GS_PGM_UINT16((p)->addr) -#define GS_PARAM_FLAGS(p) GS_PGM_UINT8((p)->flags) -/** @} */ - -/** - Max parameter name - including 0 termination. - @note In some rare/old table definitions, the name may not be NULL terminated. -*/ -#define GS_PARAM_MAX_NAME 14 - -/** - Parameter flags. - Flags must be in range: bit 0 - 7, to avoid clash with other parts of the parameter system. -*/ -typedef enum { - /** - Parameter will be stored in configured auto-persist store when set. - @note Flag must be specified when setting the parameter. - */ - GS_PARAM_F_AUTO_PERSIST = (1 << 0), - /** - @deprecated Not supported in version 4.0 - */ - PARAM_F_READONLY = (1 << 1), - /** - Skip callback, when parameter is set. - @note Flag must be specified when setting the parameter. - */ - GS_PARAM_F_NO_CALLBACK = (1 << 2), - /** - Show/display parameter in hex. - */ - GS_PARAM_F_SHOW_HEX = (1 << 3), - /** - Show double/float using scientific notation. - */ - GS_PARAM_F_SHOW_SCIENTIFIC = (1 << 4), - - PARAM_F_NOCALLBACK = GS_PARAM_F_NO_CALLBACK, - PARAM_F_PERSIST = GS_PARAM_F_AUTO_PERSIST, -} gs_param_flags_t; - -/** - * Parameter types. - */ -typedef enum __attribute__((__packed__)) { - /** - Unsigned 8 bit (uint8_t). - */ - GS_PARAM_UINT8 = 0, - /** - Unsigned 16 bit (uint16_t). - */ - GS_PARAM_UINT16 = 1, - /** - Unsigned 32 bit (uint32_t). - */ - GS_PARAM_UINT32 = 2, - /** - Unsigned 64 bit (uint64_t). - */ - GS_PARAM_UINT64 = 3, - /** - Signed 8 bit (int8_t). - */ - GS_PARAM_INT8 = 4, - /** - Signed 16 bit (int16_t). - */ - GS_PARAM_INT16 = 5, - /** - Signed 32 bit (int32_t). - */ - GS_PARAM_INT32 = 6, - /** - Signed 64 bit (int64_t). - */ - GS_PARAM_INT64 = 7, - /** - @deprecated - use #GS_PARAM_UINT8 and #GS_PARAM_F_SHOW_HEX. - */ - PARAM_X8 = 8, - /** - @deprecated - use #GS_PARAM_UINT16 and #GS_PARAM_F_SHOW_HEX. - */ - PARAM_X16 = 9, - /** - @deprecated - use #GS_PARAM_UINT32 and #GS_PARAM_F_SHOW_HEX. - */ - PARAM_X32 = 10, - /** - @deprecated - use #GS_PARAM_UINT64 and #GS_PARAM_F_SHOW_HEX. - */ - PARAM_X64 = 11, - /** - Double. - */ - GS_PARAM_DOUBLE = 12, - /** - Float. - */ - GS_PARAM_FLOAT = 13, - /** - C or null-terminated string. - @note The specified \a size must include space for the NUL character. - */ - GS_PARAM_STRING = 14, - /** - Data (binary blob). - Binary blob: [0, 0x40, 0x4f] -> '00404f' - */ - GS_PARAM_DATA = 15, - /** - Boolean. - Expected same size as uint8_t. - */ - GS_PARAM_BOOL = 16, - - PARAM_UINT8 = GS_PARAM_UINT8, - PARAM_UINT16 = GS_PARAM_UINT16, - PARAM_UINT32 = GS_PARAM_UINT32, - PARAM_UINT64 = GS_PARAM_UINT64, - PARAM_INT8 = GS_PARAM_INT8, - PARAM_INT16 = GS_PARAM_INT16, - PARAM_INT32 = GS_PARAM_INT32, - PARAM_INT64 = GS_PARAM_INT64, - PARAM_DOUBLE = GS_PARAM_DOUBLE, - PARAM_FLOAT = GS_PARAM_FLOAT, - PARAM_STRING = GS_PARAM_STRING, - PARAM_DATA = GS_PARAM_DATA, - PARAM_BOOL = GS_PARAM_BOOL, -} gs_param_type_t; - -/** - Table row. - - A table row defines one parameter, and a table is defined by one or more rows. - - @note Make sure to update gs_param_table_checksum2(), if adding fields > 1 byte. - - @note AVR8: Table definitions must be located in \a program memory, i.e. must be const. -*/ -typedef struct __attribute__((__packed__)) { - /** - Address (or offset) in table. - */ - uint16_t addr; - /** - Type. - */ - gs_param_type_t type; - /** - Size of element. - uint32_t = 4, string[5] = 5 (4 characters + 1 for NUL), etc. - */ - uint8_t size; - /** - Array size. - Size greater than 1, will make the parameter an array - if the value is 0 or 1, the parameter is not an array. - */ - uint8_t array_size; - /** - Flags. - @see gs_param_flags_t - */ - uint8_t flags; - /** - Name (C string). - @note In some rare/old table definitions, the name may not be NUL terminated. - */ - char name[GS_PARAM_MAX_NAME]; -} gs_param_table_row_t; - -/** - Table instance. -*/ -typedef struct gs_param_table_instance gs_param_table_instance_t; - -/** - Table id. - - Tables can be associated with a number/id, which normally is unique on a specific node. -*/ -typedef uint8_t gs_param_table_id_t; - -/** - Undefined table id. -*/ -#define GS_PARAM_UNDEFINED_TABLE_ID 255 - -/** - Function for setting a parameter. - - @param[in] context user context/reference. - @param[in] tinst table instance. - @param[in] addr parameter address. - @param[in] type parameter type. - @param[in] item parameter value. - @param[in] size parameter size (e.g. how many bytes to copy from \a item). - @param[in] flags flags related to the operation - these may vary depending on the context. - @return_gs_error_t -*/ -typedef gs_error_t (*gs_param_table_function_set_t)(void * context, gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, const void * item, size_t size, uint32_t flags); - -/** - Function for getting a parameter. - - @param[in] context user context/reference. - @param[in] tinst table instance. - @param[in] addr parameter address. - @param[in] type parameter type. - @param[out] item parameter buffer (provided by the caller). - @param[in] size parameter size (e.g. how many bytes to copy to \a item). - @param[in] flags flags related to the operation - these may vary depending on the context. - @return_gs_error_t -*/ -typedef gs_error_t (*gs_param_table_function_get_t)(void * context, gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, void * item, size_t size, uint32_t flags); - -/** - Function interface for setting and getting parameters. - Functions will be invoked, when set/get is called on the table instance. -*/ -typedef struct { - /** - User context, provided in the callback functions. - */ - void * context; - /** - Called when setting a parameter. - */ - gs_param_table_function_set_t set; - /** - Called when getting a parameter. - */ - gs_param_table_function_get_t get; -} gs_param_function_interface_t; - -/** - Callback function for changed parameter. - See gs_param_table_create() for details. -*/ -typedef void (*gs_param_callback_func_t)(uint16_t addr, gs_param_table_instance_t * tinst); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libparam_client/src/bindings/python/pyparam.c b/gomspace/libparam_client/src/bindings/python/pyparam.c deleted file mode 100644 index bbb35b7a..00000000 --- a/gomspace/libparam_client/src/bindings/python/pyparam.c +++ /dev/null @@ -1,1084 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -#include -#include - -#include -#include -#include -#include - -#if PY_MAJOR_VERSION == 3 -#define IS_PY3 -#endif - -static inline int to_int(char c) -{ - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'A' && c <= 'F') return 10 + c - 'A'; - if (c >= 'a' && c <= 'f') return 10 + c - 'a'; - return -1; -} - -/* static inline int rparam_get_string(char *out, int outlen, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_get_string(PyObject *self, PyObject *args) -{ - uint16_t addr; - uint16_t string_size; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "HHii|ii", &addr, &string_size, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - char buffer[string_size]; - memset(&buffer, 0, string_size); - int result = rparam_get_string(&buffer[0], string_size, addr, index_id, node, port, timeout); - return Py_BuildValue("is", result, buffer); -} - -/* static inline int rparam_set_string(char *in, int inlen, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_set_string(PyObject *self, PyObject *args) -{ - char* in; - int inlen; - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "siHii|ii", &in, &inlen, &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - return Py_BuildValue("i", rparam_set_string(in, inlen, addr, index_id, node, port, timeout)); -} - -/* static inline int rparam_get_string(char *out, int outlen, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_get_data(PyObject *self, PyObject *args) -{ - uint16_t addr; - uint16_t data_size; - int index_id; - int node; - int port = 7; - int timeout = 1000; - - if (!PyArg_ParseTuple(args, "HHii|ii", &addr, &data_size, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - char buffer[data_size]; - memset(&buffer, 0, data_size); - - //Reading as raw string: - int result = rparam_get_string(&buffer[0], data_size, addr, index_id, node, port, timeout); - - //Convert to string of HEX bytes - uint16_t bblen=2*data_size; - char bb[bblen+1]; - memset(bb,0, sizeof(bb)); - - char *bb_ptr = &bb[0]; - for (int i = 0; i < data_size; i++) { - sprintf(bb_ptr, "%02"PRIX8, ((uint8_t *) buffer)[i]); - bb_ptr+=2; - } - - return Py_BuildValue("is", result, bb); -} - -/* static inline int rparam_set_string(char *in, int inlen, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_set_data(PyObject *self, PyObject *args) -{ - char* in; - int inlen; - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - gs_error_t error = GS_OK; - - if (!PyArg_ParseTuple(args, "siHii|ii", &in, &inlen, &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - //inlen is number of bytes in DATA param in table, in reality the string will be twice as long, since it contains HEX-string... - // e.g., DEADBEEF00000000 is 16 characters but only corresponds to 8 bytes - char outbuffer[inlen]; - memset(outbuffer, 0, sizeof(outbuffer)); - - if ((inlen % 2) == 0) { - // validate data first - not to end up with invalid/strange data - for (int i = 0; i < inlen; ++i) { - if (to_int(in[i]) < 0) { - error = GS_ERROR_DATA; - break; - } - } - if (error == GS_OK) { - uint8_t * out = (uint8_t *) outbuffer; - for (int i = 0; i < inlen; i += 2, ++out) { - *out = (16 * to_int(in[i])) + to_int(in[i+1]); - } - error = GS_OK; - } - } else { - error = GS_ERROR_DATA; - } - - if (error != GS_OK) { - return Py_BuildValue("i", error); - } else { - return Py_BuildValue("i", rparam_set_string(outbuffer, inlen, addr, index_id, node, port, timeout)); - } -} - -/* static inline int rparam_get_uint8(uint8_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_get_uint8(PyObject *self, PyObject *args) -{ - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - uint8_t value; - int result = rparam_get_uint8(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("iB", result, value); -} - -/* static inline int rparam_set_uint8(uint8_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_set_uint8(PyObject *self, PyObject *args) -{ - uint8_t value; - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "BHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - int result = rparam_set_uint8(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("i", result); -} - -/* static inline int rparam_get_uint16(uint16_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_get_uint16(PyObject *self, PyObject *args) -{ - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - uint16_t value; - int result = rparam_get_uint16(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("iH", result, value); -} - -/* static inline int rparam_set_uint16(uint16_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_set_uint16(PyObject *self, PyObject *args) -{ - uint16_t value; - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "HHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - int result = rparam_set_uint16(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("i", result); -} - -/* static inline int rparam_get_uint32(uint32_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_get_uint32(PyObject *self, PyObject *args) -{ - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - uint32_t value; - int result = rparam_get_uint32(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("iI", result, value); -} - -/* static inline int rparam_set_uint32(uint32_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_set_uint32(PyObject *self, PyObject *args) -{ - uint32_t value; - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "IHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - int result = rparam_set_uint32(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("i", result); -} - -/* static inline int rparam_get_uint64(uint64_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_get_uint64(PyObject *self, PyObject *args) -{ - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - uint64_t value; - int result = rparam_get_uint64(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("iK", result, value); -} - -/* static inline int rparam_set_uint64(uint64_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_set_uint64(PyObject *self, PyObject *args) -{ - uint64_t value; - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "KHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - int result = rparam_set_uint64(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("i", result); -} - -/* static inline int rparam_get_int8(int8_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_get_int8(PyObject *self, PyObject *args) -{ - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - int8_t value; - int result = rparam_get_int8(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("hb", result, value); -} - -/* static inline int rparam_set_int8(int8_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_set_int8(PyObject *self, PyObject *args) -{ - int8_t value; - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "bHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - int result = rparam_set_int8(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("i", result); -} - -/* static inline int rparam_get_int16(int16_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_get_int16(PyObject *self, PyObject *args) -{ - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - int16_t value; - int result = rparam_get_int16(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("ih", result, value); -} - -/* static inline int rparam_set_int16(int16_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_set_int16(PyObject *self, PyObject *args) -{ - int16_t value; - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "hHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - int result = rparam_set_int16(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("i", result); -} - -/* static inline int rparam_get_int32(int32_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_get_int32(PyObject *self, PyObject *args) -{ - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - int32_t value; - int result = rparam_get_int32(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("il", result, value); -} - -/* static inline int rparam_set_int32(int32_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_set_int32(PyObject *self, PyObject *args) -{ - int32_t value; - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "lHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - int result = rparam_set_int32(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("i", result); -} - -/* static inline int rparam_get_int64(int64_t * out, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_get_int64(PyObject *self, PyObject *args) -{ - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - int64_t value; - int result = rparam_get_int64(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("iL", result, value); -} - -/* static inline int rparam_set_int64(int64_t * in, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_set_int64(PyObject *self, PyObject *args) -{ - int64_t value; - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "LHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - int result = rparam_set_int64(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("i", result); -} - -/* static inline int rparam_get_float(float * out, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_get_float(PyObject *self, PyObject *args) -{ - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - float value; - int result = rparam_get_float(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("if", result, value); -} - -/* static inline int rparam_set_float(float * in, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_set_float(PyObject *self, PyObject *args) -{ - float value; - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "fHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - int result = rparam_set_float(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("i", result); -} - -/* static inline int rparam_get_double(double * out, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_get_double(PyObject *self, PyObject *args) -{ - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "Hii|ii", &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - double value; - int result = rparam_get_double(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("id", result, value); -} - -/* static inline int rparam_set_double(double * in, uint16_t addr, int index_id, int node, int port, int timeout) */ -static PyObject* pyrparam_set_double(PyObject *self, PyObject *args) -{ - double value; - uint16_t addr; - int index_id; - int node; - int port = 7; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "dHii|ii", &value, &addr, &index_id, &node, &port, &timeout)) { - Py_RETURN_NONE; - } - - int result = rparam_set_double(&value, addr, index_id, node, port, timeout); - return Py_BuildValue("i", result); -} - -/*gs_error_t gs_rparam_save_to_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id, - const char * store, const char * slot)*/ -static PyObject* pyrparam_save_to_store(PyObject *self, PyObject *args) -{ - uint8_t table_id; - char* store; - int node; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "Bsi|i", &table_id, &store, &node, &timeout)) { - Py_RETURN_NONE; - } - - int result = gs_rparam_save_to_store(node, timeout, table_id, store, NULL); - return Py_BuildValue("i", result); -} -/*gs_error_t gs_rparam_load_from_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id, - const char * store, const char * slot)*/ -static PyObject* pyrparam_load_from_store(PyObject *self, PyObject *args) -{ - uint8_t table_id; - char* store; - int node; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "Bsi|i", &table_id, &store, &node, &timeout)) { - Py_RETURN_NONE; - } - - int result = gs_rparam_load_from_store(node, timeout, table_id, store, NULL); - return Py_BuildValue("i", result); -} - -/*gs_error_t gs_rparam_save(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to) */ -static PyObject* pyrparam_save(PyObject *self, PyObject *args) -{ - uint8_t table_id; - uint8_t file_id; - int node; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "BBi|i", &table_id, &file_id, &node, &timeout)) { - Py_RETURN_NONE; - } - - int result = gs_rparam_save(node, timeout, table_id, file_id); - return Py_BuildValue("i", result); -} - -/*gs_error_t gs_rparam_load(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to) */ -static PyObject* pyrparam_load(PyObject *self, PyObject *args) -{ - uint8_t table_id; - uint8_t file_id; - int node; - int timeout = 1000; - if (!PyArg_ParseTuple(args, "BBi|i", &file_id, &table_id, &node, &timeout)) { - Py_RETURN_NONE; - } - - int result = gs_rparam_load(node, timeout, file_id, table_id); - return Py_BuildValue("i", result); -} - -/*int rparam_download_table_spec_from_remote_and_save_to_file2(const char* fname, uint8_t node, uint8_t port, param_index_t* index, uint16_t* checksum, uint32_t timeout);*/ -static PyObject* pyrparam_download_table_spec_from_remote_and_save_to_file2(PyObject *self, PyObject *args) -{ - char* fname; - int fname_len; - int mem_id; - int node; - int port; - uint16_t checksum; - int timeout; - if (!PyArg_ParseTuple(args, "s#iiiHi", &fname, &fname_len, &node, &port, &mem_id, &checksum, &timeout)) { - Py_RETURN_NONE; - } - - GS_PARAM_TINST_VAR(tinst); - int result = gs_rparam_download_table_spec(tinst, fname, node, mem_id, timeout, &checksum); - gs_param_table_free(tinst); // free allocated resources by gs_rparam_download_table_spec() - return Py_BuildValue("i", result); -} - -/* gs_error_t gs_param_io_i2c_init(gs_param_io_t * io, uint8_t bus, uint8_t addr, bool big_endian); */ - -static PyObject* pyioparam_i2c_init(PyObject *self, PyObject *args) -{ - uint8_t bus; - uint8_t addr; - uint8_t big_endian; - if (!PyArg_ParseTuple(args, "BBB", &bus, &addr, &big_endian)) { - Py_RETURN_NONE; - } - gs_pp_t* io = malloc(sizeof(gs_pp_t)); - gs_error_t error = gs_pp_i2c_init(io, bus, addr, big_endian); - return Py_BuildValue("iO", error, PyCapsule_New(io, "gs_pp_t", NULL)); -} - -static PyObject* pyioparam_io_free(PyObject *self, PyObject *args) -{ - PyObject *io_capsule; - if (!PyArg_ParseTuple(args, "O", &io_capsule)) { - Py_RETURN_NONE; - } - free(PyCapsule_GetPointer(io_capsule, "gs_pp_t")); - Py_RETURN_NONE; -} - -/* -gs_error_t gs_pp_get_int8( - gs_pp_t * io, - uint8_t table_id, - uint8_t addr, - int8_t * value, - size_t count, - uint32_t flags); -*/ -static PyObject* pyioparam_io_get_int8(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint8_t addr; - int8_t value; - if (!PyArg_ParseTuple(args, "OBB", &io_capsule, &table_id, &addr)) { - Py_RETURN_NONE; - } - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_get_int8(tmp, table_id, addr, &value, 1, 0); - if (error) { - value = 0; - } - return Py_BuildValue("ib", error, value); -} - -/* -gs_error_t gs_pp_set_int8( - gs_pp_t * io, - uint8_t table_id, - uint8_t addr, - const int8_t * value, - size_t count, - uint32_t flags); -*/ -static PyObject* pyioparam_io_set_int8(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint8_t addr; - int8_t value; - if (!PyArg_ParseTuple(args, "ObBB", &io_capsule, &value, &table_id, &addr)) { - Py_RETURN_NONE; - } - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_set_int8(tmp, table_id, addr, &value, 1, 0); - return Py_BuildValue("i", error); -} - -/* -gs_error_t gs_pp_get_uint8( - gs_pp_t * io, - uint8_t table_id, - uint8_t addr, - uint8_t * value, - size_t count, - uint32_t flags); -*/ -static PyObject* pyioparam_io_get_uint8(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint8_t addr; - uint8_t value; - if (!PyArg_ParseTuple(args, "OBB", &io_capsule, &table_id, &addr)) { - Py_RETURN_NONE; - } - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_get_uint8(tmp, table_id, addr, &value, 1, 0); - if (error) { - value = 0; - } - return Py_BuildValue("iB", error, value); -} - -/* -gs_error_t gs_pp_set_uint8( - gs_pp_t * io, - uint8_t table_id, - uint8_t addr, - const uint8_t * value, - size_t count, - uint32_t flags); -*/ -static PyObject* pyioparam_io_set_uint8(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint8_t addr; - uint8_t value; - if (!PyArg_ParseTuple(args, "OBBB", &io_capsule, &value, &table_id, &addr)) { - Py_RETURN_NONE; - } - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_set_uint8(tmp, table_id, addr, &value, 1, 0); - return Py_BuildValue("i", error); -} - -/* -gs_error_t gs_pp_get_int16( - gs_pp_t * io, - uint8_t table_id, - uint8_t addr, - int16_t * value, - size_t count, - uint32_t flags); -*/ -static PyObject* pyioparam_io_get_int16(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint8_t addr; - int16_t value; - if (!PyArg_ParseTuple(args, "OBB", &io_capsule, &table_id, &addr)) { - Py_RETURN_NONE; - } - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_get_int16(tmp, table_id, addr, &value, 1, 0); - if (error) { - value = 0; - } - return Py_BuildValue("ih", error, value); -} - -/* -gs_error_t gs_pp_set_int16( - gs_pp_t * io, - uint8_t table_id, - uint8_t addr, - const int16_t * value, - size_t count, - uint32_t flags); -*/ -static PyObject* pyioparam_io_set_int16(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint8_t addr; - int16_t value; - if (!PyArg_ParseTuple(args, "OhBB", &io_capsule, &value, &table_id, &addr)) { - Py_RETURN_NONE; - } - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_set_int16(tmp, table_id, addr, &value, 1, 0); - return Py_BuildValue("i", error); -} - -/* -gs_error_t gs_pp_get_uint16( - gs_pp_t * io, - uint8_t table_id, - uint8_t addr, - uint16_t * value, - size_t count, - uint32_t flags); -*/ -static PyObject* pyioparam_io_get_uint16(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint8_t addr; - uint16_t value; - if (!PyArg_ParseTuple(args, "OBB", &io_capsule, &table_id, &addr)) { - Py_RETURN_NONE; - } - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_get_uint16(tmp, table_id, addr, &value, 1, 0); - if (error) { - value = 0; - } - return Py_BuildValue("iH", error, value); -} - -/* -gs_error_t gs_pp_set_uint16( - gs_pp_t * io, - uint8_t table_id, - uint8_t addr, - const uint16_t * value, - size_t count, - uint32_t flags); -*/ -static PyObject* pyioparam_io_set_uint16(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint8_t addr; - uint16_t value; - if (!PyArg_ParseTuple(args, "OHBB", &io_capsule, &value, &table_id, &addr)) { - Py_RETURN_NONE; - } - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_set_uint16(tmp, table_id, addr, &value, 1, 0); - return Py_BuildValue("i", error); -} - -/* -gs_error_t gs_pp_get_int32( - gs_pp_t * io, - uint8_t table_id, - uint8_t addr, - int32_t * value, - size_t count, - uint32_t flags); -*/ -static PyObject* pyioparam_io_get_int32(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint8_t addr; - int32_t value; - if (!PyArg_ParseTuple(args, "OBB", &io_capsule, &table_id, &addr)) { - Py_RETURN_NONE; - } - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_get_int32(tmp, table_id, addr, &value, 1, 0); - if (error) { - value = 0; - } - return Py_BuildValue("ii", error, value); -} - -/* -gs_error_t gs_pp_set_int32( - gs_pp_t * io, - uint8_t table_id, - uint8_t addr, - const int32_t * value, - size_t count, - uint32_t flags); -*/ -static PyObject* pyioparam_io_set_int32(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint8_t addr; - int32_t value; - if (!PyArg_ParseTuple(args, "OiBB", &io_capsule, &value, &table_id, &addr)) { - Py_RETURN_NONE; - } - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_set_int32(tmp, table_id, addr, &value, 1, 0); - return Py_BuildValue("i", error); -} - -/* -gs_error_t gs_pp_get_uint32( - gs_pp_t * io, - uint8_t table_id, - uint8_t addr, - uint32_t * value, - size_t count, - uint32_t flags); -*/ -static PyObject* pyioparam_io_get_uint32(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint8_t addr; - uint32_t value; - if (!PyArg_ParseTuple(args, "OBB", &io_capsule, &table_id, &addr)) { - Py_RETURN_NONE; - } - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_get_uint32(tmp, table_id, addr, &value, 1, 0); - if (error) { - value = 0; - } - return Py_BuildValue("iI", error, value); -} -/* -gs_error_t gs_pp_set_uint32( - gs_pp_t * io, - uint8_t table_id, - uint8_t addr, - const uint32_t * value, - size_t count, - uint32_t flags); -*/ - -static PyObject* pyioparam_io_set_uint32(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint8_t addr; - uint32_t value; - if (!PyArg_ParseTuple(args, "OIBB", &io_capsule, &value, &table_id, &addr)) { - Py_RETURN_NONE; - } - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_set_uint32(tmp, table_id, addr, &value, 1, 0); - return Py_BuildValue("i", error); -} -/* -gs_error_t gs_pp_get_float( - gs_pp_t * io, - uint8_t table_id, - uint8_t addr, - float * value, - size_t count, - uint32_t flags); -*/ -static PyObject* pyioparam_io_get_float(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint8_t addr; - float value; - if (!PyArg_ParseTuple(args, "OBB", &io_capsule, &table_id, &addr)) { - Py_RETURN_NONE; - } - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_get_float(tmp, table_id, addr, &value, 1, 0); - if (error) { - value = 0; - } - return Py_BuildValue("if", error, value); -} - -/* -gs_error_t gs_pp_set_float( - gs_pp_t * io, - uint8_t table_id, - uint8_t addr, - const float * value, - size_t count, - uint32_t flags); -*/ -static PyObject* pyioparam_io_set_float(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint8_t addr; - float value; - if (!PyArg_ParseTuple(args, "OfBB", &io_capsule, &value, &table_id, &addr)) { - Py_RETURN_NONE; - } - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_set_float(tmp, table_id, addr, &value, 1, 0); - return Py_BuildValue("i", error); -} - -static PyObject* pyioparam_spi_init(PyObject* self, PyObject* args) -{ - uint8_t addr; - uint8_t big_endian; - if (!PyArg_ParseTuple(args, "BB", &addr, &big_endian)) { - Py_RETURN_NONE; - } - gs_pp_t* io = malloc(sizeof(gs_pp_t)); - gs_error_t error = gs_pp_spi_init(io, addr, big_endian); - return Py_BuildValue("iO", error, PyCapsule_New(io, "gs_pp_t", NULL)); -} - -/** - Get lock value - - @param[in] pp Handle for connection - @param[in] table_id Table ID - @param[out] value Lock state (0 = unlocked, 1 = locked) - @param[in] flags - @return_gs_error_t -gs_error_t gs_pp_get_table_lock(gs_pp_t * pp, uint8_t table_id, bool * value, uint32_t flags); -*/ - -static PyObject* pyioparam_get_table_lock(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint32_t flags = 0; - if (!PyArg_ParseTuple(args, "OB|I", &io_capsule, &table_id, &flags)) { - Py_RETURN_NONE; - } - bool result; - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_get_table_lock(tmp, table_id, &result, flags); - - uint8_t retval = result ? 1 : 0; - return Py_BuildValue("iB", error, retval); -} -/** - Set lock value - - @param[in] pp Handle for connection - @param[in] table_id Table ID - @param[in] value Lock state (0 = unlocked, 1 = locked) - @param[in] flags - @return_gs_error_t - - gs_error_t gs_pp_set_table_lock(gs_pp_t * pp, uint8_t table_id, const bool * value, uint32_t flags); - */ - -static PyObject* pyioparam_set_table_lock(PyObject* self, PyObject* args) -{ - PyObject* io_capsule; - uint8_t table_id; - uint32_t flags = 0; - uint8_t status; - if (!PyArg_ParseTuple(args, "OBB|I", &io_capsule, &table_id, &status, &flags)) { - Py_RETURN_NONE; - } - bool setval = status ? true : false; - gs_pp_t* tmp = PyCapsule_GetPointer(io_capsule, "gs_pp_t"); - gs_error_t error = gs_pp_set_table_lock(tmp, table_id, &setval, flags); - return Py_BuildValue("i", error); -} -static PyMethodDef methods[] = { - - /* param/rparam_client.h */ - {"rparam_get_string", pyrparam_get_string, METH_VARARGS, ""}, - {"rparam_set_string", pyrparam_set_string, METH_VARARGS, ""}, - - {"rparam_get_float", pyrparam_get_float, METH_VARARGS, ""}, - {"rparam_set_float", pyrparam_set_float, METH_VARARGS, ""}, - {"rparam_get_double", pyrparam_get_double, METH_VARARGS, ""}, - {"rparam_set_double", pyrparam_set_double, METH_VARARGS, ""}, - - {"rparam_get_uint8", pyrparam_get_uint8, METH_VARARGS, ""}, - {"rparam_set_uint8", pyrparam_set_uint8, METH_VARARGS, ""}, - {"rparam_get_uint16", pyrparam_get_uint16, METH_VARARGS, ""}, - {"rparam_set_uint16", pyrparam_set_uint16, METH_VARARGS, ""}, - {"rparam_get_uint32", pyrparam_get_uint32, METH_VARARGS, ""}, - {"rparam_set_uint32", pyrparam_set_uint32, METH_VARARGS, ""}, - {"rparam_get_uint64", pyrparam_get_uint64, METH_VARARGS, ""}, - {"rparam_set_uint64", pyrparam_set_uint64, METH_VARARGS, ""}, - - {"rparam_get_int8", pyrparam_get_int8, METH_VARARGS, ""}, - {"rparam_set_int8", pyrparam_set_int8, METH_VARARGS, ""}, - {"rparam_get_int16", pyrparam_get_int16, METH_VARARGS, ""}, - {"rparam_set_int16", pyrparam_set_int16, METH_VARARGS, ""}, - {"rparam_get_int32", pyrparam_get_int32, METH_VARARGS, ""}, - {"rparam_set_int32", pyrparam_set_int32, METH_VARARGS, ""}, - {"rparam_get_int64", pyrparam_get_int64, METH_VARARGS, ""}, - {"rparam_set_int64", pyrparam_set_int64, METH_VARARGS, ""}, - - {"rparam_get_data", pyrparam_get_data, METH_VARARGS, ""}, - {"rparam_set_data", pyrparam_set_data, METH_VARARGS, ""}, - - {"rparam_save_to_store", pyrparam_save_to_store, METH_VARARGS, "" }, - {"rparam_load_from_store", pyrparam_load_from_store, METH_VARARGS, "" }, - {"rparam_save", pyrparam_save, METH_VARARGS, "" }, - {"rparam_load", pyrparam_load, METH_VARARGS, "" }, - - {"rparam_download_table_spec_from_remote_and_save_to_file2", pyrparam_download_table_spec_from_remote_and_save_to_file2, METH_VARARGS, ""}, - - - /* param/rparam_client.h */ - {"pp_i2c_init", pyioparam_i2c_init, METH_VARARGS, ""}, - {"pp_spi_init", pyioparam_spi_init, METH_VARARGS, ""}, - {"pp_get_int8", pyioparam_io_get_int8, METH_VARARGS, ""}, - {"pp_get_uint8", pyioparam_io_get_uint8, METH_VARARGS, ""}, - {"pp_set_int8", pyioparam_io_set_int8, METH_VARARGS, ""}, - {"pp_set_uint8", pyioparam_io_set_uint8, METH_VARARGS, ""}, - {"pp_get_int16", pyioparam_io_get_int16, METH_VARARGS, ""}, - {"pp_get_uint16", pyioparam_io_get_uint16, METH_VARARGS, ""}, - {"pp_set_int16", pyioparam_io_set_int16, METH_VARARGS, ""}, - {"pp_set_uint16", pyioparam_io_set_uint16, METH_VARARGS, ""}, - {"pp_get_int32", pyioparam_io_get_int32, METH_VARARGS, ""}, - {"pp_get_uint32", pyioparam_io_get_uint32, METH_VARARGS, ""}, - {"pp_set_int32", pyioparam_io_set_int32, METH_VARARGS, ""}, - {"pp_set_uint32", pyioparam_io_set_uint32, METH_VARARGS, ""}, - {"pp_get_float", pyioparam_io_get_float, METH_VARARGS, ""}, - {"pp_set_float", pyioparam_io_set_float, METH_VARARGS, ""}, - {"pp_io_free", pyioparam_io_free, METH_VARARGS, ""}, - {"pp_get_table_lock", pyioparam_get_table_lock, METH_VARARGS, ""}, - {"pp_set_table_lock", pyioparam_set_table_lock, METH_VARARGS, ""}, - - /* sentinel */ - {NULL, NULL, 0, NULL} -}; - -#ifdef IS_PY3 -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "libgsparam_client_py3", - NULL, /* module documentation, may be NULL */ - -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ - methods, - NULL, - NULL, - NULL, - NULL -}; -#endif - -#ifdef IS_PY3 -PyMODINIT_FUNC PyInit_libgsparam_client_py3(void) { -#else -PyMODINIT_FUNC initlibgsparam_client_py2(void) -{ -#endif - -#ifdef IS_PY3 - PyObject* m = PyModule_Create(&moduledef); -#else - Py_InitModule("libgsparam_client_py2", methods); -#endif - -#ifdef IS_PY3 - return m; -#endif -} diff --git a/gomspace/libparam_client/src/pp/cmd/master_cmd.c b/gomspace/libparam_client/src/pp/cmd/master_cmd.c deleted file mode 100644 index 404f5472..00000000 --- a/gomspace/libparam_client/src/pp/cmd/master_cmd.c +++ /dev/null @@ -1,418 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include -#include - -static bool use_checksum; - -static gs_pp_t gs_pp; - -static int cmd_spi_init(gs_command_context_t *ctx) -{ - uint8_t slave; - gs_error_t error = gs_string_to_uint8(ctx->argv[1], &slave); - if (error) { - return error; - } - - bool big_endian = false; - if (ctx->argc > 2) { - error = gs_string_to_bool(ctx->argv[2], &big_endian); - if (error) { - return error; - } - } - - error = gs_pp_spi_init(&gs_pp, slave, big_endian); - if (error) { - memset(&gs_pp, 0, sizeof(gs_pp)); - return error; - } - - return GS_OK; -} - -static int cmd_i2c_init(gs_command_context_t *ctx) -{ - uint8_t bus; - gs_error_t error = gs_string_to_uint8(ctx->argv[1], &bus); - if (error) { - return GS_ERROR_ARG; - } - - uint8_t addr; - error = gs_string_to_uint8(ctx->argv[2], &addr); - if (error) { - return GS_ERROR_ARG; - } - - bool big_endian = false; - if (ctx->argc > 3) { - error = gs_string_to_bool(ctx->argv[3], &big_endian); - if (error) { - return GS_ERROR_ARG; - } - } - - error = gs_pp_i2c_init(&gs_pp, bus, addr, big_endian); - if (error) { - memset(&gs_pp, 0, sizeof(gs_pp)); - return error; - } - - return GS_OK; -} - -static int cmd_checksum(gs_command_context_t *ctx) -{ - if (ctx->argc > 1) { - if (gs_string_to_bool(ctx->argv[1], &use_checksum)) { - return GS_ERROR_ARG; - } - } - printf("Use CHECKSUM: %d\r\n", use_checksum); - return GS_OK; -} - -// get_xxxx
-static int cmd_parse(gs_command_context_t *ctx, - uint32_t * table, uint32_t * addr) -{ - if (ctx->argc < 3) { - return GS_ERROR_ARG; - } - - gs_error_t error = gs_string_to_uint32(ctx->argv[1], table); - if (error || (*table > 7)) { - return GS_ERROR_ARG; - } - - error = gs_string_to_uint32(ctx->argv[2], addr); - if (error || (*addr > 255)) { - return GS_ERROR_ARG; - } - - return GS_OK; -} - -static int cmd_get_parse(gs_command_context_t * ctx, - uint32_t * table, uint32_t * addr, uint32_t * count) -{ - int res = cmd_parse(ctx, table, addr); - if (res == GS_OK) { - *count = 1; - if (ctx->argc > 3) { - gs_error_t error = gs_string_to_uint32(ctx->argv[3], count); - if (error || (*count > 100)) { - return GS_ERROR_ARG; - } - } - } - - return res; -} - -#define CMD_GET(_ctx, _type, _func, _format) \ - { \ - uint32_t table; \ - uint32_t addr; \ - uint32_t count; \ - int res = cmd_get_parse(_ctx, &table, &addr, &count); \ - if (res == GS_OK) { \ - _type value[count]; \ - gs_error_t error = _func(&gs_pp, table, addr, value, count, use_checksum ? GS_PP_FLAG_CHECKSUM : 0); \ - if (error) { \ - return error; \ - } \ - printf("value(s): "); \ - for (unsigned int i = 0; i < count; ++i) { \ - printf("%" _format " ", value[i]); \ - } \ - printf("\r\n"); \ - } \ - return res; \ - } - -static int cmd_get_int8(gs_command_context_t * ctx) -{ - CMD_GET(ctx, int8_t, gs_pp_get_int8, PRId8); -} - -static int cmd_get_int16(gs_command_context_t * ctx) -{ - CMD_GET(ctx, int16_t, gs_pp_get_int16, PRId16); -} - -static int cmd_get_int32(gs_command_context_t * ctx) -{ - CMD_GET(ctx, int32_t, gs_pp_get_int32, PRId32); -} - -static int cmd_get_uint8(gs_command_context_t * ctx) -{ - CMD_GET(ctx, uint8_t, gs_pp_get_uint8, PRIu8); -} - -static int cmd_get_uint16(gs_command_context_t * ctx) -{ - CMD_GET(ctx, uint16_t, gs_pp_get_uint16, PRIu16); -} - -static int cmd_get_uint32(gs_command_context_t * ctx) -{ - CMD_GET(ctx, uint32_t, gs_pp_get_uint32, PRIu32); -} - -static int cmd_get_float(gs_command_context_t * ctx) -{ - CMD_GET(ctx, float, gs_pp_get_float, "f"); -} - -#define CMD_SET(_ctx, _type, _func, _convert) \ - { \ - const unsigned int MAX_VALUES = 20; \ - uint32_t table; \ - uint32_t addr; \ - int res = cmd_parse(_ctx, &table, &addr); \ - if (res == GS_OK) { \ - _type value[MAX_VALUES]; \ - unsigned int count = 0; \ - for (int i = 3; (i < _ctx->argc) && (count < MAX_VALUES); ++i, ++count) { \ - res = _convert(_ctx->argv[i], &value[count]); \ - if (res) { \ - return GS_ERROR_DATA; \ - } \ - } \ - res = _func(&gs_pp, table, addr, value, count, use_checksum ? GS_PP_FLAG_CHECKSUM : 0); \ - } \ - return res; \ - } - -static int cmd_set_int8(gs_command_context_t * ctx) -{ - CMD_SET(ctx, int8_t, gs_pp_set_int8, gs_string_to_int8); -} - -static int cmd_set_int16(gs_command_context_t * ctx) -{ - CMD_SET(ctx, int16_t, gs_pp_set_int16, gs_string_to_int16); -} - -static int cmd_set_int32(gs_command_context_t * ctx) -{ - CMD_SET(ctx, int32_t, gs_pp_set_int32, gs_string_to_int32); -} - -static int cmd_set_uint8(gs_command_context_t * ctx) -{ - CMD_SET(ctx, uint8_t, gs_pp_set_uint8, gs_string_to_uint8); -} - -static int cmd_set_uint16(gs_command_context_t * ctx) -{ - CMD_SET(ctx, uint16_t, gs_pp_set_uint16, gs_string_to_uint16); -} - -static int cmd_set_uint32(gs_command_context_t * ctx) -{ - CMD_SET(ctx, uint32_t, gs_pp_set_uint32, gs_string_to_uint32); -} - -static int cmd_set_float(gs_command_context_t * ctx) -{ - CMD_SET(ctx, float, gs_pp_set_float, gs_string_to_float); -} - -static int cmd_get_table_lock(gs_command_context_t * ctx) -{ - uint32_t table; - gs_error_t res = gs_string_to_uint32(ctx->argv[1], &table); - if (res == GS_OK) { - if (table <= 7) { - bool lock; - res = gs_pp_get_table_lock(&gs_pp, table, &lock, GS_PP_FLAG_CHECKSUM); - if (res == GS_OK) { - const char locked[] = "locked\n"; - const char unlocked[] = "unlocked\n"; - const char * lock_state = (lock) ? locked : unlocked; - printf("Table %s", lock_state); - } - } else { - res = GS_ERROR_ARG; - } - } - return res; -} - -static int cmd_set_table_lock(gs_command_context_t * ctx) -{ - uint32_t table; - gs_error_t res = gs_string_to_uint32(ctx->argv[1], &table); - if (res == GS_OK) { - if (table <= 7) { - uint32_t lock; - res = gs_string_to_uint32(ctx->argv[2], &lock); - if (res == GS_OK) { - if(lock <= 1) { - res = gs_pp_set_table_lock(&gs_pp, table, (bool *)&lock, GS_PP_FLAG_CHECKSUM); - } else { - res = GS_ERROR_ARG; - } - } - } else { - res = GS_ERROR_ARG; - } - } - return res; -} - -static const gs_command_t gs_param_cmd_master_pp_sub[] = { - { - .name = "spi_init", - .help = "Initialize/setup SPI device", - .usage = " [big_endian]", - .handler = cmd_spi_init, - .mandatory_args = 1, - .optional_args = 1, - },{ - .name = "i2c_init", - .help = "Initialize/setup I2C device", - .usage = " [big_endian]", - .handler = cmd_i2c_init, - .mandatory_args = 2, - .optional_args = 1, - },{ - .name = "checksum", - .help = "Enable/disable checksum", - .usage = "[0|1]", - .handler = cmd_checksum, - .optional_args = 1, - },{ - .name = "get_table_lock", - .help = "Get table lock (0 = unlocked, 1 = locked)", - .usage = "
", - .mandatory_args = 1, - .handler = cmd_get_table_lock, - },{ - .name = "set_table_lock", - .help = "Set table lock (0 = unlocked, 1 = locked)", - .usage = "
", - .mandatory_args = 2, - .handler = cmd_set_table_lock, - },{ - .name = "get_int8", - .help = "Get int8", - .usage = "
[count]", - .handler = cmd_get_int8, - .mandatory_args = 2, - .optional_args = 1, - },{ - .name = "get_int16", - .help = "Get int16", - .usage = "
[count]", - .handler = cmd_get_int16, - .mandatory_args = 2, - .optional_args = 1, - },{ - .name = "get_int32", - .help = "Get int32", - .usage = "
[count]", - .handler = cmd_get_int32, - .mandatory_args = 2, - .optional_args = 1, - },{ - .name = "get_uint8", - .help = "Get uint8", - .usage = "
[count]", - .handler = cmd_get_uint8, - .mandatory_args = 2, - .optional_args = 1, - },{ - .name = "get_uint16", - .help = "Get uint16", - .usage = "
[count]", - .handler = cmd_get_uint16, - .mandatory_args = 2, - .optional_args = 1, - },{ - .name = "get_uint32", - .help = "Get uint32", - .usage = "
[count]", - .handler = cmd_get_uint32, - .mandatory_args = 2, - .optional_args = 1, - },{ - .name = "get_float", - .help = "Get float", - .usage = "
[count]", - .handler = cmd_get_float, - .mandatory_args = 2, - .optional_args = 1, - },{ - .name = "set_int8", - .help = "Set int8", - .usage = "
[data] ...", - .handler = cmd_set_int8, - .mandatory_args = 3, - .optional_args = 20, - },{ - .name = "set_int16", - .help = "Set int16", - .usage = "
[data] ...", - .handler = cmd_set_int16, - .mandatory_args = 3, - .optional_args = 20, - },{ - .name = "set_int32", - .help = "Set int32", - .usage = "
[data] ...", - .handler = cmd_set_int32, - .mandatory_args = 3, - .optional_args = 20, - },{ - .name = "set_uint8", - .help = "Set uint8", - .usage = "
[data] ...", - .handler = cmd_set_uint8, - .mandatory_args = 3, - .optional_args = 20, - },{ - .name = "set_uint16", - .help = "Set uint16", - .usage = "
[data] ...", - .handler = cmd_set_uint16, - .mandatory_args = 3, - .optional_args = 20, - },{ - .name = "set_uint32", - .help = "Set uint32", - .usage = "
[data] ...", - .handler = cmd_set_uint32, - .mandatory_args = 3, - .optional_args = 20, - },{ - .name = "set_float", - .help = "Set float", - .usage = "
[data] ...", - .handler = cmd_set_float, - .mandatory_args = 3, - .optional_args = 20, - } -}; - -static const gs_command_t GS_COMMAND_ROOT gs_param_cmd_master_pp[] = { - { - .name = "pp", - .help = "Param Protocol interface", - .chain = GS_COMMAND_INIT_CHAIN(gs_param_cmd_master_pp_sub), - } -}; - -gs_error_t gs_pp_register_commands(void) -{ - return GS_COMMAND_REGISTER(gs_param_cmd_master_pp); -} diff --git a/gomspace/libparam_client/src/pp/i2c/i2c.c b/gomspace/libparam_client/src/pp/i2c/i2c.c deleted file mode 100644 index 912bbeb5..00000000 --- a/gomspace/libparam_client/src/pp/i2c/i2c.c +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#define GS_PARAM_INTERNAL_USE 1 - -#include -#include -#include -#include -#include - -static gs_error_t gs_pp_i2c_write(gs_param_i2c_command_t cmd, gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, bool checksum) -{ - GS_CHECK_RANGE(table_id <= 7); - GS_CHECK_RANGE(addr <= 255); - GS_CHECK_RANGE((value_size > 0) && (value_size <= 31)); - - gs_param_i2c_set_request_t * request; - const size_t size = (sizeof(*request) + value_size + (checksum ? 1 : 0)); - request = alloca(size); - - request->header.domain_command = GS_I2C_SLAVE_DISPATCH_HEADER(GS_I2C_SLAVE_DISPATCH_DOMAIN_PARAM, cmd); - request->length_table = GS_PARAM_I2C_LENGTH_TABLE(value_size, table_id); - request->addr = addr; - memcpy(request->data, value, value_size); - - if (checksum) { - request->data[value_size] = gs_pp_checksum8(request, size - 1); - } - return gs_i2c_master_transaction(pp->pp.i2c.bus, pp->pp.i2c.addr, request, size, NULL, 0, 1000); - -} - -static gs_error_t gs_pp_i2c_read(gs_param_i2c_command_t cmd, gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, bool checksum) -{ - GS_CHECK_RANGE(table_id <= 7); - GS_CHECK_RANGE(addr <= 255); - GS_CHECK_RANGE((value_size > 0) && (value_size <= 31)); - - gs_param_i2c_get_request_t request; - memset(&request, 0, sizeof(request)); - request.length_table = GS_PARAM_I2C_LENGTH_TABLE(value_size, table_id); - request.addr = addr; - size_t request_size; - - uint8_t reply[value_size + sizeof(request.checksum)]; // + for checksum - memset(reply, 0, sizeof(reply)); - size_t reply_size; - - request.header.domain_command = GS_I2C_SLAVE_DISPATCH_HEADER(GS_I2C_SLAVE_DISPATCH_DOMAIN_PARAM, cmd); - - if (checksum) { - request.checksum = gs_pp_checksum8(&request, (sizeof(request) - sizeof(request.checksum))); - request_size = sizeof(request); - reply_size = sizeof(reply); - } else { - request_size = sizeof(request) - sizeof(request.checksum); - reply_size = sizeof(reply) - sizeof(request.checksum); - } - - gs_error_t error = gs_i2c_master_transaction(pp->pp.i2c.bus, pp->pp.i2c.addr, &request, request_size, reply, reply_size, 1000); - if (error == GS_OK) { - if (checksum) { - if (gs_pp_checksum8(reply, value_size) != reply[value_size]) { - return GS_ERROR_DATA; - } - } - memcpy(value, reply, value_size); - } - return error; - -} - -static gs_error_t gs_pp_i2c_get(gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, uint32_t flags) -{ - gs_param_i2c_command_t cmd; - bool checksum = false; - if (flags & GS_PP_FLAG_CHECKSUM) { - checksum = true; - cmd = GS_PARAM_I2C_COMMAND_GET_WITH_CHECKSUM; - } else { - cmd = GS_PARAM_I2C_COMMAND_GET; - } - return gs_pp_i2c_read(cmd, pp, table_id, addr, value, value_size, checksum); -} - -static gs_error_t gs_pp_i2c_set(gs_pp_t * pp, uint8_t table_id, uint16_t addr, const void * value, size_t value_size, uint32_t flags) -{ - gs_param_i2c_command_t cmd; - bool checksum = false; - if (flags & GS_PP_FLAG_CHECKSUM) { - checksum = true; - cmd = GS_PARAM_I2C_COMMAND_SET_WITH_CHECKSUM; - } else { - cmd = GS_PARAM_I2C_COMMAND_SET; - } - return gs_pp_i2c_write(cmd, pp, table_id, addr, (void *)value, value_size, checksum); -} - -static gs_error_t gs_pp_i2c_set_table_lock(gs_pp_t * pp, uint8_t table_id, const bool * value, uint32_t flags) -{ - gs_param_i2c_command_t cmd = GS_PARAM_I2C_COMMAND_SET_LOCK_WITH_CHECKSUM; - bool checksum = true; - return gs_pp_i2c_write(cmd, pp, table_id, 0, (void *)value, 1, checksum); -} - -static gs_error_t gs_pp_i2c_get_table_lock(gs_pp_t * pp, uint8_t table_id, bool * value, uint32_t flags) -{ - gs_param_i2c_command_t cmd = GS_PARAM_I2C_COMMAND_GET_LOCK_WITH_CHECKSUM; - bool checksum = true; - return gs_pp_i2c_read(cmd, pp, table_id, 0, value, 1, checksum); -} - -gs_error_t gs_pp_i2c_init(gs_pp_t * pp, uint8_t bus, uint8_t addr, bool big_endian) -{ - GS_CHECK_HANDLE(pp != NULL); - - memset(pp, 0, sizeof(*pp)); - - pp->get = gs_pp_i2c_get; - pp->set = gs_pp_i2c_set; - pp->set_table_lock = gs_pp_i2c_set_table_lock; - pp->get_table_lock = gs_pp_i2c_get_table_lock; - pp->big_endian = big_endian; - - pp->pp.i2c.bus = bus; - pp->pp.i2c.addr = addr; - - return GS_OK; -} diff --git a/gomspace/libparam_client/src/pp/pp.c b/gomspace/libparam_client/src/pp/pp.c deleted file mode 100644 index e9a20cfd..00000000 --- a/gomspace/libparam_client/src/pp/pp.c +++ /dev/null @@ -1,189 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include - -static inline bool gs_pp_endian_convert(gs_pp_t * pp) -{ - return (pp && (pp->big_endian != gs_endian_big())); -} - -static gs_error_t gs_pp_get(gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, uint32_t flags) -{ - if (pp == NULL) { - return GS_ERROR_HANDLE; - } - if (pp->get == NULL) { - return GS_ERROR_NOT_IMPLEMENTED; - } - return pp->get(pp, table_id, addr, value, value_size, flags); -} - -static gs_error_t gs_pp_set(gs_pp_t * pp, uint8_t table_id, uint16_t addr, const void * value, size_t value_size, uint32_t flags) -{ - if (pp == NULL) { - return GS_ERROR_HANDLE; - } - if (pp->set == NULL) { - return GS_ERROR_NOT_IMPLEMENTED; - } - return pp->set(pp, table_id, addr, value, value_size, flags); -} - -uint8_t gs_pp_checksum8(const void * data_in, size_t length) -{ - const uint8_t * data = data_in; - unsigned int checksum = 0; - for (unsigned int i = 0; i < length; ++i) { - checksum += *data++; - } - checksum &= 0xff; - return checksum ? checksum : 1; -} - -gs_error_t gs_pp_get_table_lock(gs_pp_t * pp, uint8_t table_id, bool * value, uint32_t flags) -{ - GS_CHECK_ARG(value != NULL); - GS_CHECK_HANDLE(pp != NULL); - if (pp->get_table_lock == NULL) { - return GS_ERROR_NOT_IMPLEMENTED; - } - return pp->get_table_lock(pp, table_id, value, flags); -} - -gs_error_t gs_pp_set_table_lock(gs_pp_t * pp, uint8_t table_id, const bool * value, uint32_t flags) -{ - GS_CHECK_ARG(value != NULL); - GS_CHECK_HANDLE(pp != NULL); - if (pp->set_table_lock == NULL) { - return GS_ERROR_NOT_IMPLEMENTED; - } - return pp->set_table_lock(pp, table_id, value, flags); -} - -// int8_t -gs_error_t gs_pp_get_int8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int8_t * value, size_t count, uint32_t flags) -{ - return gs_pp_get_uint8(pp, table_id, addr, (uint8_t *) value, count, flags); -} - -gs_error_t gs_pp_set_int8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int8_t * value, size_t count, uint32_t flags) -{ - return gs_pp_set_uint8(pp, table_id, addr, (const uint8_t *) value, count, flags); -} - -// uint8_t - -gs_error_t gs_pp_get_uint8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint8_t * value, size_t count, uint32_t flags) -{ - GS_CHECK_ARG(value != NULL); - GS_CHECK_ARG(count > 0); - return gs_pp_get(pp, table_id, addr, value, (sizeof(*value) * count), flags); -} - -gs_error_t gs_pp_set_uint8(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint8_t * value, size_t count, uint32_t flags) -{ - GS_CHECK_ARG(value != NULL); - GS_CHECK_ARG(count > 0); - return gs_pp_set(pp, table_id, addr, value, (sizeof(*value) * count), flags); -} - -// int16_t - -gs_error_t gs_pp_get_int16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int16_t * value, size_t count, uint32_t flags) -{ - return gs_pp_get_uint16(pp, table_id, addr, (uint16_t *) value, count, flags); -} - -gs_error_t gs_pp_set_int16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int16_t * value, size_t count, uint32_t flags) -{ - return gs_pp_set_uint16(pp, table_id, addr, (const uint16_t *) value, count, flags); -} - -// uint16_t - -gs_error_t gs_pp_get_uint16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint16_t * value, size_t count, uint32_t flags) -{ - GS_CHECK_ARG(value != NULL); - GS_CHECK_ARG(count > 0); - gs_error_t error = gs_pp_get(pp, table_id, addr, value, (sizeof(*value) * count), flags); - if (gs_pp_endian_convert(pp)) { - gs_bswap_16_array(value, value, count); - } - return error; -} - -gs_error_t gs_pp_set_uint16(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint16_t * value, size_t count, uint32_t flags) -{ - GS_CHECK_ARG(value != NULL); - GS_CHECK_ARG(count > 0); - uint16_t _converted[count]; - if (gs_pp_endian_convert(pp)) { - gs_bswap_16_array(value, _converted, count); - value = _converted; - } - return gs_pp_set(pp, table_id, addr, value, (sizeof(*value) * count), flags); -} - -// int32_t - -gs_error_t gs_pp_get_int32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, int32_t * value, size_t count, uint32_t flags) -{ - return gs_pp_get_uint32(pp, table_id, addr, (uint32_t *) value, count, flags); -} - -gs_error_t gs_pp_set_int32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const int32_t * value, size_t count, uint32_t flags) -{ - return gs_pp_set_uint32(pp, table_id, addr, (const uint32_t *) value, count, flags); -} - -// uint32_t - -gs_error_t gs_pp_get_uint32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, uint32_t * value, size_t count, uint32_t flags) -{ - GS_CHECK_ARG(value != NULL); - GS_CHECK_ARG(count > 0); - gs_error_t error = gs_pp_get(pp, table_id, addr, value, (sizeof(*value) * count), flags); - if (gs_pp_endian_convert(pp)) { - gs_bswap_32_array(value, value, count); - } - return error; -} - -gs_error_t gs_pp_set_uint32(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const uint32_t * value, size_t count, uint32_t flags) -{ - GS_CHECK_ARG(value != NULL); - GS_CHECK_ARG(count > 0); - uint32_t _converted[count]; - if (gs_pp_endian_convert(pp)) { - gs_bswap_32_array(value, _converted, count); - value = _converted; - } - return gs_pp_set(pp, table_id, addr, value, (sizeof(*value) * count), flags); -} - -gs_error_t gs_pp_get_float(gs_pp_t * pp, uint8_t table_id, uint8_t addr, float * value, size_t count, uint32_t flags) -{ - GS_CHECK_ARG(value != NULL); - GS_CHECK_ARG(count > 0); - gs_error_t error = gs_pp_get(pp, table_id, addr, value, (sizeof(*value) * count), flags); - if (gs_pp_endian_convert(pp)) { - gs_bswap_float_array(value, value, count); - } - return error; -} - -gs_error_t gs_pp_set_float(gs_pp_t * pp, uint8_t table_id, uint8_t addr, const float * value, size_t count, uint32_t flags) -{ - GS_CHECK_ARG(value != NULL); - GS_CHECK_ARG(count > 0); - float _converted[count]; - if (gs_pp_endian_convert(pp)) { - gs_bswap_float_array(value, _converted, count); - value = _converted; - } - return gs_pp_set(pp, table_id, addr, value, (sizeof(*value) * count), flags); -} diff --git a/gomspace/libparam_client/src/pp/spi/spi.c b/gomspace/libparam_client/src/pp/spi/spi.c deleted file mode 100644 index 7e594e9f..00000000 --- a/gomspace/libparam_client/src/pp/spi/spi.c +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#define GS_PARAM_INTERNAL_USE 1 - -#include -#include -#include -#include -#include - -static gs_error_t gs_pp_spi_get(gs_pp_t * pp, uint8_t table_id, uint16_t addr, void * value, size_t value_size, uint32_t flags) -{ - GS_CHECK_RANGE(table_id <= 7); - GS_CHECK_RANGE(addr <= 255); - - if (flags & GS_PP_FLAG_CHECKSUM) { - gs_param_spi_get_with_checksum_t * request; - const size_t size = (sizeof(*request) + value_size + 1); // +1 for CHECKSUM in returned data - request = alloca(size); - memset(request, 0, size); - request->header.domain_command = GS_SPI_SLAVE_DISPATCH_HEADER(GS_SPI_SLAVE_DISPATCH_DOMAIN_PARAM, GS_PARAM_SPI_COMMAND_GET_WITH_CHECKSUM); - request->length_table = GS_PARAM_SPI_LENGTH_TABLE(value_size, table_id); - request->addr = addr; - request->checksum = gs_pp_checksum8(request, (sizeof(*request) - sizeof(request->filler))); - - gs_error_t error = gs_spi_master_transaction(pp->pp.spi.slave, request, request, size, 1000); - if (error == GS_OK) { - if (gs_pp_checksum8(request->data, value_size) != request->data[value_size]) { - return GS_ERROR_DATA; - } - memcpy(value, request->data, value_size); - } - return error; - - } else { - gs_param_spi_get_t * request; - const size_t size = (sizeof(*request) + value_size); - request = alloca(size); - memset(request, 0, size); - request->header.domain_command = GS_SPI_SLAVE_DISPATCH_HEADER(GS_SPI_SLAVE_DISPATCH_DOMAIN_PARAM, GS_PARAM_SPI_COMMAND_GET); - request->length_table = GS_PARAM_SPI_LENGTH_TABLE(value_size, table_id); - request->addr = addr; - - gs_error_t error = gs_spi_master_transaction(pp->pp.spi.slave, request, request, size, 1000); - if (error == GS_OK) { - memcpy(value, request->data, value_size); - } - return error; - } -} - -static gs_error_t gs_pp_spi_set(gs_pp_t * pp, uint8_t table_id, uint16_t addr, const void * value, size_t value_size, uint32_t flags) -{ - GS_CHECK_RANGE(table_id <= 7); - GS_CHECK_RANGE(addr <= 255); - - gs_param_spi_set_t * request; - const size_t size = (sizeof(*request) + value_size + ((flags & GS_PP_FLAG_CHECKSUM) ? 1 : 0)); - request = alloca(size); - if (flags & GS_PP_FLAG_CHECKSUM) { - request->header.domain_command = GS_SPI_SLAVE_DISPATCH_HEADER(GS_SPI_SLAVE_DISPATCH_DOMAIN_PARAM, GS_PARAM_SPI_COMMAND_SET_WITH_CHECKSUM); - } else { - request->header.domain_command = GS_SPI_SLAVE_DISPATCH_HEADER(GS_SPI_SLAVE_DISPATCH_DOMAIN_PARAM, GS_PARAM_SPI_COMMAND_SET); - } - request->length_table = GS_PARAM_SPI_LENGTH_TABLE(value_size, table_id); - request->addr = addr; - memcpy(request->data, value, value_size); - - if (flags & GS_PP_FLAG_CHECKSUM) { - request->data[value_size] = gs_pp_checksum8(request, size - 1); - } - - return gs_spi_master_transaction(pp->pp.spi.slave, request, NULL, size, 1000); -} - -gs_error_t gs_pp_spi_init(gs_pp_t * pp, uint8_t slave, bool big_endian) -{ - GS_CHECK_HANDLE(pp != NULL); - - memset(pp, 0, sizeof(*pp)); - - pp->get = gs_pp_spi_get; - pp->set = gs_pp_spi_set; - pp->set_table_lock = NULL; // Not implemented - pp->get_table_lock = NULL; // Not implemented - pp->big_endian = big_endian; - - pp->pp.spi.slave = slave; - - return GS_OK; -} diff --git a/gomspace/libparam_client/src/rparam/cmd/cmd_rparam.c b/gomspace/libparam_client/src/rparam/cmd/cmd_rparam.c deleted file mode 100644 index de1bd6d8..00000000 --- a/gomspace/libparam_client/src/rparam/cmd/cmd_rparam.c +++ /dev/null @@ -1,354 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#define GS_PARAM_INTERNAL_USE 1 - -#include -#include -#include -#include -#include "../query.h" -#include -#include -#include -#include -#include -#include - -#define MAX_FILENAME 100 - -/** Remote param system setup */ -static gs_param_table_instance_t rparam_tinst; -static gs_rparam_query_handle_t rquery = {.timeout_ms = 10000}; -static char * rparam_wd; - -#define CHECK_TABLE() \ - if (rparam_tinst.rows == NULL) { \ - fprintf(ctx->out, "Run download or init to setup table\n"); \ - return GS_ERROR_NOT_FOUND; \ - } - -static int cmd_rparam_list(gs_command_context_t *ctx) -{ - CHECK_TABLE(); - return gs_param_list_to_stream(&rparam_tinst, true, 0, ctx->out); -} - -static void make_filename(char * fname, size_t fname_size) -{ - char cwd[MAX_FILENAME + 1]; - const char * wd; - if (gs_string_empty(rparam_wd) == false) { - wd = rparam_wd; - } else if (gs_getcwd(cwd, sizeof(cwd)) == GS_OK) { - wd = cwd; - } else { - wd = NULL; - } - if (gs_string_empty(wd) == false) { - snprintf(fname, fname_size, "%s/param-%d-%u.bin", wd, rquery.node, rquery.table_id); - } else { - fname[0] = 0; - } -} - -static int cmd_rparam_init_from_local_file(gs_command_context_t *ctx) -{ - if (gs_string_to_uint8(ctx->argv[1], &rquery.node)) { - return GS_ERROR_ARG; - } - if (ctx->argc > 2) { - if (gs_string_to_uint8(ctx->argv[2], &rquery.table_id)) { - return GS_ERROR_ARG; - } - } - - char fname[100]; - make_filename(fname, sizeof(fname)); - return gs_rparam_load_table_spec(&rparam_tinst, fname, &rquery.checksum); -} - -static int cmd_rparam_init_from_remote_node(gs_command_context_t *ctx) -{ - if (gs_string_to_uint8(ctx->argv[1], &rquery.node)) { - return GS_ERROR_ARG; - } - if (ctx->argc > 2) { - if (gs_string_to_uint8(ctx->argv[2], &rquery.table_id)) { - return GS_ERROR_ARG; - } - } - - char fname[100]; - make_filename(fname, sizeof(fname)); - return gs_rparam_download_table_spec(&rparam_tinst, fname, rquery.node, rquery.table_id, rquery.timeout_ms, &rquery.checksum); -} - -static int cmd_rparam_send(gs_command_context_t *ctx) -{ - CHECK_TABLE(); - - gs_error_t error = gs_rparam_query_send(&rquery, &rparam_tinst); - if (error == GS_OK) { - if (rquery.action == RPARAM_GET) { - const gs_param_table_row_t * last_print = NULL; - for (unsigned int i = 0; i < rquery.length / 2; ++i) { - const gs_param_table_row_t * row = gs_param_row_by_address(rquery.payload.addr[i], rparam_tinst.rows, rparam_tinst.row_count); - if (row != last_print) { // work-around to avoid duplicate lines for elements within same array - gs_param_list_single_to_stream(&rparam_tinst, row, true, 0, ctx->out); - last_print = row; - } - } - } - gs_rparam_query_reset(&rquery); - } - return error; -} - -static int cmd_rparam_get(gs_command_context_t *ctx) -{ - CHECK_TABLE(); - - gs_rparam_query_set_quiet(&rquery, false); - gs_error_t error = gs_rparam_query_get(&rquery, &rparam_tinst, ctx->argv[1]); - if ((error == GS_OK) && rquery.auto_send) { - error = cmd_rparam_send(ctx); - } - - return error; -} - -static int cmd_rparam_getall(gs_command_context_t *ctx) -{ - CHECK_TABLE(); - - fprintf(ctx->out, "Downloading table content for table %i from server %u\n", rquery.table_id, rquery.node); - gs_error_t error = gs_rparam_get_full_table(&rparam_tinst, rquery.node, rquery.table_id, rquery.checksum, rquery.timeout_ms); - if (error == GS_OK) { - gs_param_list_to_stream(&rparam_tinst, true, 0, ctx->out); - } - return error; -} - -static int cmd_rparam_set(gs_command_context_t *ctx) -{ - CHECK_TABLE(); - - gs_error_t error = gs_rparam_query_set(&rquery, &rparam_tinst, ctx->argv[1], &ctx->argv[2], ctx->argc - 2); - if ((error == GS_OK) && rquery.auto_send) { - error = cmd_rparam_send(ctx); - } - - return error; -} - -static int cmd_rparam_copy(gs_command_context_t *ctx) -{ - uint8_t from; - if (gs_string_to_uint8(ctx->argv[1], &from)) { - return GS_ERROR_ARG; - } - - uint8_t to; - if (gs_string_to_uint8(ctx->argv[2], &to)) { - return GS_ERROR_ARG; - } - - return gs_rparam_copy(rquery.node, rquery.timeout_ms, from, to); -} - -static int cmd_rparam_load(gs_command_context_t *ctx) -{ - uint8_t table_id; - if (gs_string_to_uint8(ctx->argv[2], &table_id)) { - return GS_ERROR_ARG; - } - uint8_t file_id; - if (gs_string_to_uint8(ctx->argv[1], &file_id)) { - // This may be a store - no way of validating - return gs_rparam_load_from_store(rquery.node, rquery.timeout_ms, table_id, ctx->argv[1], NULL); - } - - return gs_rparam_load(rquery.node, rquery.timeout_ms, file_id, table_id); -} - -static int cmd_rparam_save(gs_command_context_t *ctx) -{ - uint8_t table_id; - if (gs_string_to_uint8(ctx->argv[1], &table_id)) { - return GS_ERROR_ARG; - } - uint8_t file_id; - if (gs_string_to_uint8(ctx->argv[2], &file_id)) { - // This may be a store - no way of validating - return gs_rparam_save_to_store(rquery.node, rquery.timeout_ms, table_id, ctx->argv[2], NULL); - } - - return gs_rparam_save(rquery.node, rquery.timeout_ms, table_id, file_id); -} - -static int cmd_rparam_reset(gs_command_context_t *ctx) -{ - gs_rparam_query_reset(&rquery); - return GS_OK; -} - -static int cmd_rparam_set_autosend(gs_command_context_t *ctx) -{ - if (ctx->argc > 1) { - if (gs_string_to_bool(ctx->argv[1], &rquery.auto_send)) { - return GS_ERROR_ARG; - } - } - fprintf(ctx->out, "auto send: %d\r\n", rquery.auto_send); - return GS_OK; -} - -static int cmd_set_wd(gs_command_context_t *ctx) -{ - if (ctx->argc > 1) { - if (rparam_wd == NULL) { - rparam_wd = malloc(MAX_FILENAME + 1); - if (rparam_wd == NULL) { - return GS_ERROR_ALLOC; - } - } - strcpy(rparam_wd, ctx->argv[1]); - } - fprintf(ctx->out, "working directory: %s\r\n", rparam_wd ? rparam_wd : "not set"); - return GS_OK; -} - -static int cmd_rparam_set_timeout(gs_command_context_t *ctx) -{ - if (ctx->argc > 1) { - if (gs_string_to_uint32(ctx->argv[1], &rquery.timeout_ms)) { - return GS_ERROR_ARG; - } - } - fprintf(ctx->out, "timeout: %"PRIu32" mS\r\n", rquery.timeout_ms); - return GS_OK; -} - -static int cmd_rparam_set_checksum(gs_command_context_t *ctx) -{ - if (ctx->argc > 1) { - if (strcasecmp(ctx->argv[1], "magic") == 0) { - rquery.checksum = GS_RPARAM_MAGIC_CHECKSUM; - } else if (gs_string_to_uint16(ctx->argv[1], &rquery.checksum)) { - return GS_ERROR_ARG; - } - } - fprintf(ctx->out, "checksum: 0x%04x (magic: 0x%04x)\r\n", rquery.checksum, GS_RPARAM_MAGIC_CHECKSUM); - return GS_OK; -} - -static const gs_command_t rparam_commands[] = { - { - .name = "init", - .help = "Set server and load table spec. from file", - .usage = " [table-id]", - .handler = cmd_rparam_init_from_local_file, - .mandatory_args = 1, - .optional_args = 1, - },{ - .name = "download", - .help = "Set server and download table spec.", - .usage = " [table-id]", - .handler = cmd_rparam_init_from_remote_node, - .mandatory_args = 1, - .optional_args = 1, - },{ - .name = "getall", - .help = "Download full table contents from server", - .handler = cmd_rparam_getall, - .mandatory_args = GS_COMMAND_NO_ARGS, - },{ - .name = "list", - .help = "Lists the table specification", - .handler = cmd_rparam_list, - .mandatory_args = GS_COMMAND_NO_ARGS, - },{ - .name = "get", - .help = "Add a 'get' to the current query transaction", - .usage = "", - .handler = cmd_rparam_get, - .mandatory_args = 1, - },{ - .name = "set", - .help = "Add a 'set' to the current query transaction", - .usage = " [value] ...", - .handler = cmd_rparam_set, - .mandatory_args = 2, - .optional_args = 100, - },{ - .name = "copy", - .usage = " ", - .help = "Copy table to table (version <= 3 only)", - .handler = cmd_rparam_copy, - .mandatory_args = 2, - },{ - .name = "load", - .usage = " ", - .help = "Load table", - .handler = cmd_rparam_load, - .mandatory_args = 2, - },{ - .name = "save", - .usage = " ", - .help = "Save table", - .handler = cmd_rparam_save, - .mandatory_args = 2, - /* },{ */ - /* .name = "print", */ - /* .help = "Print the current query", */ - /* .handler = cmd_rparam_print, */ - /* .mandatory_args = GS_COMMAND_NO_ARGS, */ - },{ - .name = "reset", - .help = "Reset the current query", - .handler = cmd_rparam_reset, - .mandatory_args = GS_COMMAND_NO_ARGS, - },{ - .name = "send", - .help = "Send the current query", - .handler = cmd_rparam_send, - .mandatory_args = GS_COMMAND_NO_ARGS, - },{ - .name = "wd", - .help = "Set working directory for init/download", - .usage = "[path]", - .handler = cmd_set_wd, - .optional_args = 1, - },{ - .name = "timeout", - .help = "Set timeout", - .usage = "[timeout mS]", - .handler = cmd_rparam_set_timeout, - .optional_args = 1, - },{ - .name = "checksum", - .help = "Set checksum", - .usage = "[magic|]", - .handler = cmd_rparam_set_checksum, - .optional_args = 1, - },{ - .name = "autosend", - .usage = "[bool]", - .help = "Enable/disable autosend for set and get queries", - .handler = cmd_rparam_set_autosend, - .optional_args = 1, - } -}; - -static const gs_command_t GS_COMMAND_ROOT rparam_root_command[] = { - { - .name = "rparam", - .help = "Remote access to Parameter System", - .chain = GS_COMMAND_INIT_CHAIN(rparam_commands), - }, -}; - -gs_error_t gs_rparam_register_commands(void) -{ - return GS_COMMAND_REGISTER(rparam_root_command); -} diff --git a/gomspace/libparam_client/src/rparam/deprecated_rparam.c b/gomspace/libparam_client/src/rparam/deprecated_rparam.c deleted file mode 100644 index 418f468c..00000000 --- a/gomspace/libparam_client/src/rparam/deprecated_rparam.c +++ /dev/null @@ -1,6 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -// Old deprecated API uses common data - making it not thread-safe. -//gs_rparam_handle_t rparam_handle; diff --git a/gomspace/libparam_client/src/rparam/query.c b/gomspace/libparam_client/src/rparam/query.c deleted file mode 100644 index 79144e33..00000000 --- a/gomspace/libparam_client/src/rparam/query.c +++ /dev/null @@ -1,212 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#define GS_PARAM_INTERNAL_USE 1 - -#include "query.h" -#include -#include -#include -#include "../serialize_local.h" -#include -#include - -bool gs_rparam_query_is_set(gs_rparam_query_handle_t * handle) -{ - return (handle->length > 0); -} - -void gs_rparam_query_reset(gs_rparam_query_handle_t * handle) -{ - handle->action = RPARAM_GET; - handle->length = 0; - handle->get_size = 0; -} - -void gs_rparam_query_set_quiet(gs_rparam_query_handle_t * handle, bool quiet) -{ - handle->quiet = quiet; -} - -gs_error_t gs_rparam_query_get(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst, const char* param_name) -{ - if (tinst->rows == NULL) - return GS_ERROR_NOT_FOUND; - - /* Ensure correct header */ - if (handle->action != RPARAM_GET) { - gs_rparam_query_reset(handle); - handle->action = RPARAM_GET; - } - - char shortname[GS_PARAM_MAX_NAME + 20]; - uint8_t array_index = 0; - bool is_array; - if (gs_param_parse_name_and_array_index(param_name, shortname, sizeof(shortname), &array_index, &is_array)) { - return GS_ERROR_ARG; - } - - const gs_param_table_row_t * param = gs_param_row_by_name(shortname, tinst->rows, tinst->row_count); - if (param == NULL) { - return GS_ERROR_NOT_FOUND; - } - - if (array_index >= GS_PARAM_ARRAY_SIZE(param)) { - return GS_ERROR_RANGE; - } - - unsigned int start; - unsigned int end; - if (is_array) { - start = array_index; - end = start + 1; - } else { - start = 0; - end = GS_PARAM_ARRAY_SIZE(param); - } - for (unsigned int i = start; i < end; ++i) { - - /* Size check */ - if (handle->get_size + param->size + sizeof(uint16_t) > GS_RPARAM_QUERY_MAX_PAYLOAD) { - return GS_ERROR_OVERFLOW; - } - - /* Add to query */ - handle->payload.addr[handle->length/2] = param->addr + (param->size * i); - handle->length += sizeof(uint16_t); - handle->get_size += param->size + sizeof(uint16_t); - } - - return GS_OK; -} - -gs_error_t gs_rparam_query_set(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst, const char* param_name, char * values[], uint8_t value_count) -{ - /* Ensure correct header */ - if (handle->action != RPARAM_SET) { - gs_rparam_query_reset(handle); - handle->action = RPARAM_SET; - } - - char shortname[GS_PARAM_MAX_NAME + 20]; - uint8_t array_index = 0; - if (gs_param_parse_name_and_array_index(param_name, shortname, sizeof(shortname), &array_index, NULL)) { - return GS_ERROR_ARG; - } - - const gs_param_table_row_t * param = gs_param_row_by_name(shortname, tinst->rows, tinst->row_count); - if (param == NULL) { - return GS_ERROR_NOT_FOUND; - } - - if (array_index >= GS_PARAM_ARRAY_SIZE(param)) { - return GS_ERROR_RANGE; - } - - for (unsigned int i = 0; i < value_count; i++) { - - /* Parse input */ - uint8_t value[param->size]; - gs_error_t error = gs_param_from_string(param, values[i], value); - if (error) { - return error; - } - - unsigned int bytes = 0; - error = gs_param_serialize_item(param, param->addr + (param->size * (array_index + i)), value, F_TO_BIG_ENDIAN, - &handle->payload.packed[handle->length], GS_RPARAM_QUERY_MAX_PAYLOAD - handle->length, &bytes); - if (error) { - return error; - } - handle->length += bytes; - } - - return GS_OK; -} - -gs_error_t gs_rparam_query_send(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst) -{ - if (tinst->rows == NULL) { - return GS_ERROR_NOT_FOUND; - } - - if (handle->length == 0) { - return GS_ERROR_NO_DATA; - } - - gs_rparam_query_t * query; - - /* Allocate outgoing buffer */ - csp_packet_t * packet = csp_buffer_get(RPARAM_QUERY_LENGTH(query, GS_RPARAM_QUERY_MAX_PAYLOAD)); - if (packet == NULL) { - return GS_ERROR_NO_BUFFERS; - } - - csp_conn_t * conn = csp_connect(CSP_PRIO_HIGH, handle->node, GS_CSP_PORT_RPARAM, handle->timeout_ms, CSP_O_CRC32); - if (conn == NULL) { - csp_buffer_free(packet); - return GS_ERROR_IO; - } - - query = (gs_rparam_query_t *) packet->data; - - query->action = handle->action; - query->table_id = handle->table_id; - query->seq = 0; - query->total = 0; - query->length = csp_hton16(handle->length); - query->checksum = csp_hton16(handle->checksum); - - /* Copy payload to message */ - packet->length = RPARAM_QUERY_LENGTH(query, handle->length); - memcpy(&query->payload, &handle->payload, handle->length); - - /* Deal with endianness */ - if (handle->action == RPARAM_GET) { - for (unsigned int i = 0; i < (handle->length/2); i++) { - query->payload.addr[i] = csp_hton16(query->payload.addr[i]); - } - } - - /* Send packet */ - if (!csp_send(conn, packet, 0)) { - csp_buffer_free(packet); - csp_close(conn); - return GS_ERROR_IO; - } - - /* Read reply */ - packet = csp_read(conn, handle->timeout_ms); - if (packet == NULL) { - csp_close(conn); - return GS_ERROR_TIMEOUT; - } - - if (packet->length <= 1) { - gs_error_t error = GS_OK; - if (packet->length == 1) { - if (packet->data[0] == RPARAM_ERROR) { - error = GS_ERROR_DATA; - } - } else { - error = GS_ERROR_NO_DATA; - } - csp_buffer_free(packet); - csp_close(conn); - return error; - } - - /* We have a reply */ - gs_rparam_query_t * reply = (gs_rparam_query_t *) packet->data; - reply->length = csp_ntoh16(reply->length); - - gs_error_t error; - if (reply->action == RPARAM_REPLY) { - error = gs_param_deserialize(tinst, reply->payload.packed, reply->length, F_FROM_BIG_ENDIAN); - } else { - error = GS_ERROR_TYPE; - } - - csp_buffer_free(packet); - csp_close(conn); - return error; -} diff --git a/gomspace/libparam_client/src/rparam/query.h b/gomspace/libparam_client/src/rparam/query.h deleted file mode 100644 index 507a870a..00000000 --- a/gomspace/libparam_client/src/rparam/query.h +++ /dev/null @@ -1,110 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - - -#include - -/** - Rparam query handle. -*/ -typedef struct { - /** - CSP node. - */ - uint8_t node; - /** - Remote table id. - */ - gs_param_table_id_t table_id; - /** - Remote table (definition) checksum. - */ - uint16_t checksum; - /** - Timeout (mS). - */ - uint32_t timeout_ms; - /** - If quite - no output to stdout. - */ - bool quiet; - /** - Auto send. - */ - bool auto_send; - /** - Type/action. - */ - int action; - /** - Size of current query. - */ - unsigned int length; - /** - Estimated total 'get' size. - */ - unsigned int get_size; - /** - Space for payload data. - @note must be last in struct. - */ - union { - uint16_t addr[0]; - uint8_t packed[GS_RPARAM_QUERY_MAX_PAYLOAD]; - } payload; -} gs_rparam_query_handle_t; - -/** - Set whether rparam API should print to stdout or not. - - @param[in] handle handle - @param[in] quiet \a true print to stdout. -*/ -void gs_rparam_query_set_quiet(gs_rparam_query_handle_t * handle, bool quiet); - -/** - Return true if any query has been set. - - @param[in] handle handle - @return \a true if any query has been set. -*/ -bool gs_rparam_query_is_set(gs_rparam_query_handle_t * handle); - -/** - Add a 'get' query to the current query, after a succesfull rparam_query_send() - the parameter value can be read using rparam_queury_get_value() - - @param[in] handle handle - @param[in] tinst table. - @param[in] param_name name of the parameter. - @return_gs_error_t - @see rparam_query_send() -*/ -gs_error_t gs_rparam_query_get(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst, const char* param_name); - -/** - Add a 'set' query to the current query. Use rparam_query_send() to execute the set query. - - @param[in] handle handle - @param[in] tinst table. - @param[in] param_name name of the parameter to set - @param[in] values array of values to set, multiple values can be set for array type parameters - @param[in] value_count number of elements in \a values - @return_gs_error_t - @see rparam_query_send() -*/ -gs_error_t gs_rparam_query_set(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst, const char* param_name, char * values[], uint8_t value_count); - -/** - Send the current query - - @param[in] handle handle - @param[in] tinst table. - @return_gs_error_t -*/ -gs_error_t gs_rparam_query_send(gs_rparam_query_handle_t * handle, gs_param_table_instance_t * tinst); - -/** - Reset/clear the current query - @param[in] handle handle -*/ -void gs_rparam_query_reset(gs_rparam_query_handle_t * handle); diff --git a/gomspace/libparam_client/src/rparam/rparam.c b/gomspace/libparam_client/src/rparam/rparam.c deleted file mode 100644 index d8ba79bd..00000000 --- a/gomspace/libparam_client/src/rparam/rparam.c +++ /dev/null @@ -1,474 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#define GS_PARAM_INTERNAL_USE 1 - -#include -#include -#include -#include "../serialize_local.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static gs_error_t gs_rparam_command(uint8_t node, uint32_t timeout_ms, uint8_t action, uint8_t table_id, - const void * payload, size_t payload_size, char reply_ok) -{ - gs_rparam_query_t * query = alloca(RPARAM_QUERY_LENGTH(query, payload_size)); - query->action = action; - query->table_id = table_id; - query->length = csp_hton16(payload_size); - query->checksum = csp_hton16(GS_RPARAM_MAGIC_CHECKSUM); // Ignore checksum - query->seq = 0; - query->total = 0; - memcpy(&query->payload, payload, payload_size); - - /* Run single packet transaction */ - char reply = 0; - if (csp_transaction2(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, query, RPARAM_QUERY_LENGTH(query, payload_size), - &reply, 1, CSP_O_CRC32) <= 0) { - return GS_ERROR_IO; - } - - return (reply == reply_ok) ? GS_OK : GS_ERROR_UNKNOWN; -} - -gs_error_t gs_rparam_copy(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to) -{ - gs_rparam_query_payload_t payload; - payload.copy.from = from; - payload.copy.to = to; - return gs_rparam_command(node, timeout_ms, RPARAM_COPY, from, &payload, sizeof(payload.copy), RPARAM_COPY_OK); -} - -static gs_error_t gs_rparam_store(uint8_t node, uint32_t timeout_ms, uint8_t action, char reply_ok, uint8_t table_id, - const char * table, const char * store, const char * slot) -{ - gs_rparam_query_payload_store_t payload; - memset(&payload, 0, sizeof(payload)); - if (table && (gs_string_empty(table) == false)) { - GS_STRNCPY(payload.table, table); - } - if (store && (gs_string_empty(store) == false)) { - GS_STRNCPY(payload.store, store); - } - if (slot && (gs_string_empty(slot) == false)) { - GS_STRNCPY(payload.slot, slot); - } - return gs_rparam_command(node, timeout_ms, action, table_id, &payload, sizeof(payload), reply_ok); -} - -gs_error_t gs_rparam_save_to_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id, - const char * store, const char * slot) -{ - return gs_rparam_store(node, timeout_ms, RPARAM_SAVE_TO_STORE, RPARAM_SAVE_OK, table_id, NULL, store, slot); -} - -gs_error_t gs_rparam_load_from_store(uint8_t node, uint32_t timeout_ms, uint8_t table_id, - const char * store, const char * slot) -{ - return gs_rparam_store(node, timeout_ms, RPARAM_LOAD_FROM_STORE, RPARAM_LOAD_OK, table_id, NULL, store, slot); -} - -gs_error_t gs_rparam_save(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to) -{ - gs_rparam_query_payload_t payload; - payload.copy.from = from; - payload.copy.to = to; - return gs_rparam_command(node, timeout_ms, RPARAM_SAVE, from, &payload, sizeof(payload.copy), RPARAM_SAVE_OK); -} - -gs_error_t gs_rparam_load(uint8_t node, uint32_t timeout_ms, uint8_t from, uint8_t to) -{ - gs_rparam_query_payload_t payload; - payload.copy.from = from; - payload.copy.to = to; - return gs_rparam_command(node, timeout_ms, RPARAM_LOAD, to, &payload, sizeof(payload.copy), RPARAM_LOAD_OK); -} - -static gs_error_t update_table(const char * func, - gs_param_table_instance_t * tinst, - gs_param_table_row_t * rows, unsigned int row_count, - uint16_t checksum) -{ - size_t memory_size = gs_param_calc_table_size(rows, row_count); - if ((tinst->memory == NULL) || (tinst->memory_size < memory_size)) { - // (re)allocate memory - if (memory_size == 0) { - return GS_ERROR_NOT_SUPPORTED; - } - memory_size = gs_max(1000U, memory_size); - void * memory = calloc(1, memory_size); - if (memory == NULL) { - return GS_ERROR_ALLOC; - } - - free(tinst->memory); - tinst->memory = memory; - tinst->memory_size = memory_size; - tinst->flags |= GS_PARAM_TABLE_F_ALLOC_MEMORY; - } - - free((void*)tinst->rows); - tinst->rows = rows; - tinst->row_count = row_count; - tinst->checksum_be = tinst->checksum_le = 0; - tinst->flags |= GS_PARAM_TABLE_F_ALLOC_ROWS; - - if ((checksum != gs_param_table_checksum_le(tinst)) && (checksum != gs_param_table_checksum_be(tinst))) { - log_error("%s: table specification has invalid checksum: %u - different from LE: %u and BE: %u", - func, checksum, gs_param_table_checksum_le(tinst), gs_param_table_checksum_be(tinst)); - return GS_ERROR_DATA; - } - - return GS_OK; -} - -gs_error_t gs_rparam_load_table_spec(gs_param_table_instance_t * tinst, const char* fname, uint16_t * return_checksum) -{ - GS_CHECK_HANDLE(tinst != NULL); - GS_CHECK_ARG(fname != NULL); - - FILE * fd = fopen(fname, "r"); - if (fd == NULL) { - return GS_ERROR_NOT_FOUND; - } - - struct stat file_stat; - if (fstat(fileno(fd), &file_stat) != 0) { - log_error("%s: failed to stat file [%s]", __FUNCTION__, fname); - fclose(fd); - return GS_ERROR_IO; - } - - void * rows = calloc(file_stat.st_size, 1); - if (rows == NULL) { - fclose(fd); - return GS_ERROR_ALLOC; - } - - uint16_t checksum = 0; - size_t rs1 = fread(&checksum, 1, sizeof(checksum), fd); - size_t rs2 = fread(rows, 1, file_stat.st_size, fd); - fclose(fd); - - const unsigned int single_row_size = sizeof(*tinst->rows); - const unsigned int all_row_size = (file_stat.st_size - sizeof(checksum)); - const unsigned int row_count = (all_row_size) / single_row_size; - if ((rs1 != sizeof(checksum)) || (rs2 != all_row_size) || (rs2 != (single_row_size * row_count))) { - log_error("%s: incomplete/invalid read, expected %u + %u - read %u + %u, single row size: %u", __FUNCTION__, - (unsigned int) sizeof(checksum), row_count, - (unsigned int) rs1, (unsigned int) rs2, single_row_size); - free(rows); - return GS_ERROR_IO; - } - - gs_error_t error = update_table(__FUNCTION__, tinst, rows, row_count, checksum); - - if (error == GS_OK) { - if (return_checksum) { - *return_checksum = checksum; - } - } - - return error; -} - -gs_error_t gs_rparam_download_table_spec(gs_param_table_instance_t * tinst, - const char * fname, - uint8_t node, - gs_param_table_id_t table_id, - uint32_t timeout_ms, - uint16_t * return_checksum) -{ - csp_conn_t * conn = csp_connect(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, CSP_O_CRC32); - if (conn == NULL) { - return GS_ERROR_IO; - } - - /* Allocate outgoing buffer */ - gs_rparam_query_t * query; - csp_packet_t * packet = csp_buffer_get(RPARAM_QUERY_LENGTH(query, 0)); - if (packet == NULL) { - csp_close(conn); - return GS_ERROR_NO_BUFFERS; - } - - // setup request - query = (gs_rparam_query_t *) packet->data; - query->action = RPARAM_TABLE; - query->table_id = table_id; - query->length = 0; - query->checksum = csp_hton16(GS_RPARAM_MAGIC_CHECKSUM); // Ignore checksum - query->seq = 0; - query->total = 0; - - packet->length = RPARAM_QUERY_LENGTH(query, 0); - if (!csp_send(conn, packet, 0)) { - csp_buffer_free(packet); - csp_close(conn); - return GS_ERROR_IO; - } - - /* Receive remote parameter table, in host byte order - * Note: This is necessary, because the SFP functions does not know the dataformat - * and hence cannot be converted server-side. */ - void * dataout = NULL; - int totalsize = 0; - int result = csp_sfp_recv(conn, &dataout, &totalsize, timeout_ms); - csp_close(conn); - - if (result < 0) { - free(dataout); - return GS_ERROR_IO; - } - - gs_param_table_row_t * rows = dataout; - const uint8_t row_count = totalsize / sizeof(*rows); - - /* Calculate checksum on table (before converting endians!) */ - const uint16_t checksum = gs_fletcher16(rows, totalsize); - - /* Autodetect Endians */ - int sum_first = 0; - int sum_last = 0; - for (unsigned int i = 0; i < row_count; i++) { - sum_first += (rows[i].addr & 0xFF00) >> 8; - sum_last += rows[i].addr & 0xFF; - } - - /* Correct endians */ - if (sum_first > sum_last) { - for (unsigned int i = 0; i < row_count; i++) { - rows[i].addr = (((rows[i].addr & 0xff00) >> 8) | ((rows[i].addr & 0x00ff) << 8)); - } - } - - gs_error_t error = update_table(__FUNCTION__, tinst, rows, row_count, checksum); - if (error == GS_OK) { - - if (return_checksum) { - *return_checksum = checksum; - } - - // If filename provided, store table specification to file. - if (gs_string_empty(fname) == false) { - FILE * fd = fopen(fname, "w"); - if (fd == NULL) { - log_error("%s: failed to open/create file: [%s]", __FUNCTION__, fname); - return GS_ERROR_IO; - } - const size_t ws1_size = sizeof(checksum); - const size_t ws1 = fwrite(&checksum, 1, ws1_size, fd); - const size_t ws2 = fwrite(rows, 1, totalsize, fd); - fclose(fd); - if ((ws1 != ws1_size) || (ws2 != (size_t) totalsize)) { - log_error("%s: failed to write %u + %d - wrote %u + %u", __FUNCTION__, - (unsigned int) sizeof(checksum), totalsize, (unsigned int) ws1, (unsigned int) ws2); - return GS_ERROR_IO; - } - } - } - - return error; -} - -gs_error_t gs_rparam_get_full_table(gs_param_table_instance_t * tinst, - uint8_t node, - gs_param_table_id_t table_id, - uint16_t checksum, - uint32_t timeout_ms) -{ - GS_CHECK_HANDLE(tinst != NULL); - GS_CHECK_HANDLE(tinst->rows != NULL); - GS_CHECK_HANDLE(tinst->memory != NULL); - - unsigned int expected_bytes = 0; - { - unsigned int param_pos = 0; - gs_error_t error = gs_param_serialize_full_table(tinst, ¶m_pos, GS_PARAM_SF_DRY_RUN, NULL, 10000, &expected_bytes); - if (error) { - return error; - } - } - - gs_rparam_query_t * query; - csp_packet_t * request = csp_buffer_get(RPARAM_QUERY_LENGTH(query, 0)); - if (request == NULL) { - return GS_ERROR_NO_BUFFERS; - } - - csp_conn_t * conn = csp_connect(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, CSP_O_CRC32); - if (!conn) { - csp_buffer_free(request); - return GS_ERROR_IO; - } - - query = (gs_rparam_query_t *) request->data; - query->action = RPARAM_GET; - query->table_id = table_id; - query->length = 0; // == get full table - query->checksum = csp_hton16(checksum); - query->seq = 0; - query->total = 0; - - request->length = RPARAM_QUERY_LENGTH(query, 0); - if (!csp_send(conn, request, timeout_ms)) { - csp_buffer_free(request); - csp_close(conn); - return GS_ERROR_IO; - } - - csp_packet_t * reply; - gs_error_t error = GS_OK; - unsigned int total_bytes = 0; - while ((reply = csp_read(conn, timeout_ms)) != NULL) { - - /* We have a reply */ - query = (void *) reply->data; - const uint16_t qlength = csp_ntoh16(query->length); - total_bytes += qlength; - const uint16_t seq = csp_ntoh16(query->seq); - const uint16_t total = csp_ntoh16(query->total); - - if (query->action == RPARAM_REPLY) { - error = gs_param_deserialize(tinst, query->payload.packed, qlength, F_FROM_BIG_ENDIAN); - } - csp_buffer_free(reply); - - if (error || (seq >= total)) { - break; - } - } - - if (reply == NULL) { - error = GS_ERROR_TIMEOUT; - } - - if ((error == GS_OK) && (expected_bytes != total_bytes)) { - log_warning("%s: expected %u != received %u bytes", __FUNCTION__, expected_bytes, total_bytes); - error = GS_ERROR_DATA; - } - - csp_close(conn); - - return error; -} - -gs_error_t gs_rparam_get(uint8_t node, - gs_param_table_id_t table_id, - uint16_t addr, - gs_param_type_t type, - uint16_t checksum, - uint32_t timeout_ms, - void * value, - size_t value_size) -{ - /* Calculate length */ - gs_rparam_query_t * query; - const size_t query_size = RPARAM_QUERY_LENGTH(query, sizeof(query->payload.addr[0])); - const size_t reply_payload_size = (value_size + sizeof(query->payload.addr[0])); - const size_t reply_size = RPARAM_QUERY_LENGTH(query, reply_payload_size); - - query = alloca(reply_size); - query->action = RPARAM_GET; - query->table_id = table_id; - query->checksum = csp_hton16(checksum); - query->seq = 0; - query->total = 0; - query->payload.addr[0] = csp_hton16(addr); - query->length = csp_hton16(sizeof(query->payload.addr[0])); - - /* Run single packet transaction */ - if (csp_transaction2(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, query, query_size, query, reply_size, CSP_O_CRC32) <= 0) { - return GS_ERROR_IO; - } - - /* We have a reply */ - query->length = csp_ntoh16(query->length); - - if (query->length != reply_payload_size) { - log_warning("%s: Invalid reply size %u - expected %u", __FUNCTION__, query->length, (unsigned int) reply_payload_size); - return GS_ERROR_DATA; - } - - /* Read address */ - query->payload.addr[0] = csp_betoh16(query->payload.addr[0]); - if (query->payload.addr[0] != addr) { - log_warning("%s: Invalid address in reply %u", __FUNCTION__, query->payload.addr[0]); - return GS_ERROR_DATA; - } - - /* Read value */ - memcpy(value, &query->payload.packed[2], value_size); - gs_param_betoh(type, value); - - return GS_OK; -} - -gs_error_t gs_rparam_set(uint8_t node, - gs_param_table_id_t table_id, - uint16_t addr, - gs_param_type_t type, - uint16_t checksum, - uint32_t timeout_ms, - const void * value, - size_t value_size) -{ - /* Calculate length */ - gs_rparam_query_t * query; - const size_t payload_size = (value_size + sizeof(query->payload.addr[0])); - const size_t query_size = RPARAM_QUERY_LENGTH(query, payload_size); - - query = alloca(query_size); - query->action = RPARAM_SET; - query->table_id = table_id; - query->seq = 0; - query->total = 0; - query->checksum = csp_hton16(checksum); - - /* Actual set query */ - unsigned int bytes = 0; - gs_error_t error = gs_param_serialize_item_direct(type, value_size, addr, value, F_TO_BIG_ENDIAN, query->payload.packed, payload_size, &bytes); - if (error) { - return error; - } - - /* Add to query */ - query->length = csp_hton16(bytes); - - /* Run single packet transaction */ - if (csp_transaction2(CSP_PRIO_HIGH, node, GS_CSP_PORT_RPARAM, timeout_ms, query, query_size, query, 1, CSP_O_CRC32) <= 0) { - return GS_ERROR_IO; - } - - /* We have a reply */ - query->length = csp_ntoh16(query->length); - - if ((query->action != RPARAM_SET_OK) || (query->length != bytes)) { - log_warning("%s: Invalid reply: size %u - expected %u, action %u - expected %u", - __FUNCTION__, query->length, bytes, query->action, RPARAM_SET_OK); - return GS_ERROR_DATA; - } - - return GS_OK; -} - -gs_error_t gs_rparam_query_get_value(gs_param_table_instance_t * tinst, const char* param_name, uint16_t param_no, void* val_p, size_t val_size) -{ - const gs_param_table_row_t * t = gs_param_row_by_name(param_name, tinst->rows, tinst->row_count); - if (t == NULL) { - return GS_ERROR_NOT_FOUND; - } - - if (val_size < t->size) { - return GS_ERROR_OVERFLOW; - } - - return gs_param_get(tinst, t->addr + (param_no * t->size), t->type, val_p, t->size, 0); -} diff --git a/gomspace/libparam_client/src/serialize.c b/gomspace/libparam_client/src/serialize.c deleted file mode 100644 index d55fea98..00000000 --- a/gomspace/libparam_client/src/serialize.c +++ /dev/null @@ -1,353 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#define GS_PARAM_INTERNAL_USE 1 - -#include "serialize_local.h" -#include -#include -#include -#include -#include -#include -#include - -#include // need PARM_X??? definitions - -bool gs_param_betoh(gs_param_type_t type, void * item) -{ - if (item) { - switch (type) { - case GS_PARAM_UINT16: - case GS_PARAM_INT16: - case PARAM_X16: - { - *(uint16_t *) item = util_betoh16(*(uint16_t *) item); - return true; - } - case GS_PARAM_UINT32: - case GS_PARAM_INT32: - case PARAM_X32: - { - *(uint32_t *) item = util_betoh32(*(uint32_t *) item); - return true; - } - case GS_PARAM_UINT64: - case GS_PARAM_INT64: - case PARAM_X64: - { - *(uint64_t *) item = util_betoh64(*(uint64_t *) item); - return true; - } - case GS_PARAM_FLOAT: - { - *(float *) item = util_ntohflt(*(float *) item); - return true; - } - case GS_PARAM_DOUBLE: - { - *(double *) item = util_ntohdbl(*(double *) item); - return true; - } - - case GS_PARAM_UINT8: - case GS_PARAM_INT8: - case PARAM_X8: - case GS_PARAM_STRING: - case GS_PARAM_DATA: - case GS_PARAM_BOOL: - // no swap - break; - } - } - return false; -} - -bool gs_param_htobe(gs_param_type_t type, void * item) -{ - if (item) { - switch (type) { - case PARAM_UINT16: - case PARAM_INT16: - case PARAM_X16: - { - *(uint16_t *) item = util_htobe16(*(uint16_t *) item); - return true; - } - case PARAM_UINT32: - case PARAM_INT32: - case PARAM_X32: - { - *(uint32_t *) item = util_htobe32(*(uint32_t *) item); - return true; - } - case PARAM_UINT64: - case PARAM_INT64: - case PARAM_X64: - { - *(uint64_t *) item = util_htobe64(*(uint64_t *) item); - return true; - } - case PARAM_FLOAT: - { - *(float *) item = util_htonflt(*(float *) item); - return true; - } - case PARAM_DOUBLE: - { - *(double *) item = util_htondbl(*(double *) item); - return true; - } - - case PARAM_UINT8: - case PARAM_INT8: - case PARAM_X8: - case PARAM_STRING: - case PARAM_DATA: - case PARAM_BOOL: - // no swap - break; - } - } - return false; -} - -static bool gs_param_require_endian_swap(gs_param_type_t type) -{ - switch (type) { - case PARAM_UINT16: - case PARAM_INT16: - case PARAM_X16: - case PARAM_UINT32: - case PARAM_INT32: - case PARAM_X32: - case PARAM_UINT64: - case PARAM_INT64: - case PARAM_X64: - case PARAM_FLOAT: - case PARAM_DOUBLE: - // swap - break; - - case PARAM_UINT8: - case PARAM_INT8: - case PARAM_X8: - case PARAM_STRING: - case PARAM_DATA: - case PARAM_BOOL: - // no swap - return false; - - default: - break; - } - return true; -} - -static gs_error_t gs_param_serialize_array(gs_param_table_instance_t * tinst, const gs_param_table_row_t * param, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos) -{ - const unsigned int param_size = GS_PARAM_SIZE(param); - const unsigned int param_array_size = GS_PARAM_ARRAY_SIZE(param); - const gs_param_type_t param_type = GS_PARAM_TYPE(param); - - /* Calculate total parameter size (full array) */ - { - unsigned int size = param_size * param_array_size; - if ((flags & F_PACKED) == 0) { - size += param_array_size * sizeof(uint16_t); // address - } - - /* Return if parameter array would exceed maxbuf */ - if (*buf_pos + size > buf_size) { - return GS_ERROR_OVERFLOW; - } - } - - uint8_t value[param_size]; - gs_error_t error = GS_OK; - for (unsigned int j = 0; (j < param_array_size) && (error == GS_OK); j++) { - const uint16_t addr = GS_PARAM_ADDR(param) + (param_size * j); - error = gs_param_get(tinst, addr, param_type, value, param_size, 0); - if (error == GS_OK) { - error = gs_param_serialize_item(param, addr, value, flags, buf, buf_size, buf_pos); - } - } - - return error; -} - -gs_error_t gs_param_serialize_item_direct(gs_param_type_t param_type, unsigned int param_size, uint16_t addr, const void * item, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos) -{ - /* Check length */ - if ((((flags & F_PACKED) ? 0 : sizeof(addr)) + param_size + *buf_pos) > buf_size) { - return GS_ERROR_OVERFLOW; - } - - /* Include address if not packed */ - if ((flags & F_PACKED) == 0) { - - if (flags & F_TO_BIG_ENDIAN) { - addr = util_htobe16(addr); - } - - if ((flags & F_DRY_RUN) == 0) { - memcpy(&buf[*buf_pos], &addr, sizeof(addr)); - } - - *buf_pos += sizeof(addr); - } - - if ((flags & F_DRY_RUN) == 0) { - if (flags & F_TO_BIG_ENDIAN) { - void * tmp = alloca(param_size); // this must be aligned - memcpy(tmp, item, param_size); - gs_param_htobe(param_type, tmp); - item = tmp; - } - memcpy(&buf[*buf_pos], item, param_size); - } - - *buf_pos += param_size; - - return GS_OK; -} - -gs_error_t gs_param_serialize_item(const gs_param_table_row_t * param, uint16_t addr, const void * item, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos) -{ - const gs_param_type_t param_type = GS_PARAM_TYPE(param); - const unsigned int param_size = GS_PARAM_SIZE(param); - return gs_param_serialize_item_direct(param_type, param_size, addr, item, flags, buf, buf_size, buf_pos); -} - -gs_error_t gs_param_serialize_full_table(gs_param_table_instance_t * tinst, unsigned int * param_pos, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos) -{ - if (flags & GS_PARAM_SF_DRY_RUN) { - buf = NULL; - buf_size = -1; // Max size - } - gs_error_t error = GS_OK; - unsigned int i = *param_pos; - for (; i < tinst->row_count; i++) { - const gs_param_table_row_t * param = &tinst->rows[i]; - error = gs_param_serialize_array(tinst, param, flags, buf, buf_size, buf_pos); - if (error) { - break; - } - } - *param_pos = i; - return error; -} - -gs_error_t gs_param_serialize_list(gs_param_table_instance_t * tinst, - const uint16_t addr[], unsigned int addr_count, - unsigned int * param_pos, uint32_t flags, - uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos) -{ - if (tinst == NULL) { - return GS_ERROR_HANDLE; - } - - gs_error_t error = GS_OK; - unsigned int i = *param_pos; - for (; i < addr_count; ++i) { - const gs_param_table_row_t * param = gs_param_row_by_address(addr[i], tinst->rows, tinst->row_count); - if (param == NULL) { - continue; - } - - const gs_param_type_t param_type = GS_PARAM_TYPE(param); - const unsigned int param_size = GS_PARAM_SIZE(param); - uint8_t value[param_size]; - error = gs_param_get(tinst, addr[i], param_type, value, param_size, 0); - if (error) { - break; - } - error = gs_param_serialize_item(param, addr[i], value, flags, buf, buf_size, buf_pos); - if (error) { - break; - } - } - *param_pos = i; - - return error; -} - -gs_error_t gs_param_deserialize_item(gs_param_table_instance_t * tinst, - const gs_param_table_row_t * param, - uint16_t addr, - const void * item, - uint32_t flags) -{ - const gs_param_type_t param_type = GS_PARAM_TYPE(param); - const unsigned int param_size = GS_PARAM_SIZE(param); - - if (flags & F_FROM_BIG_ENDIAN) { - if (gs_param_require_endian_swap(param_type)) { - - // Copy to temporary storage, so we don't mess with input memory - void * tmp = alloca(param_size); - memcpy(tmp, item, param_size); - - gs_param_betoh(param_type, tmp); - - // Replace input pointer - item = tmp; - } - } - - gs_error_t error = GS_OK; - if ((flags & F_DRY_RUN) == 0) { - error = gs_param_set(tinst, addr, param_type, item, param_size, GS_PARAM_FLAGS(param)); - } - - return error; -} - -gs_error_t gs_param_deserialize(gs_param_table_instance_t * tinst, const uint8_t * buf, unsigned int buf_size, uint32_t flags) -{ - unsigned int pos = 0; - unsigned int count = 0; - gs_error_t error = GS_OK; - while ((pos < buf_size) && (error == GS_OK)) { - - if (flags & F_PACKED) { - /** PACKED */ - - /* Find in table */ - const gs_param_table_row_t * param = &tinst->rows[count]; - const unsigned int param_array_size = GS_PARAM_ARRAY_SIZE(param); - const unsigned int param_size = GS_PARAM_SIZE(param); - - /* For each item in array */ - for (unsigned int j = 0; (j < param_array_size) && (error == GS_OK); j++) { - uint16_t addr = GS_PARAM_ADDR(param) + (param_size * j); - error = gs_param_deserialize_item(tinst, param, addr, &buf[pos], flags); - pos += param_size; - } - - } else { - /** NOT PACKED */ - - /* Read address from data */ - uint16_t addr; - memcpy(&addr, &buf[pos], sizeof(addr)); - if (flags & F_FROM_BIG_ENDIAN) { - addr = util_betoh16(addr); - } - pos += sizeof(addr); - - /* Find in table */ - const gs_param_table_row_t * param = gs_param_row_by_address(addr, tinst->rows, tinst->row_count); - if (param == NULL) { - return GS_ERROR_NOT_FOUND; - } - - /* Copy value */ - error = gs_param_deserialize_item(tinst, param, addr, &buf[pos], flags); - pos += GS_PARAM_SIZE(param); - } - - count++; - } - - return error; -} diff --git a/gomspace/libparam_client/src/serialize_local.h b/gomspace/libparam_client/src/serialize_local.h deleted file mode 100644 index 15de4a51..00000000 --- a/gomspace/libparam_client/src/serialize_local.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef SRC_SERIALIZE_LOCAL_H -#define SRC_SERIALIZE_LOCAL_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -gs_error_t gs_param_serialize_item_direct(gs_param_type_t param_type, unsigned int param_size, uint16_t addr, const void * item, uint32_t flags, uint8_t * buf, unsigned int buf_size, unsigned int * buf_pos); - -#endif diff --git a/gomspace/libparam_client/src/string.c b/gomspace/libparam_client/src/string.c deleted file mode 100644 index ddbc5094..00000000 --- a/gomspace/libparam_client/src/string.c +++ /dev/null @@ -1,589 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#define GS_PARAM_INTERNAL_USE 1 - -#include -#include -#include -#include -#include -#include -#include - -size_t gs_param_calc_table_size(const gs_param_table_row_t * rows, size_t row_count) -{ - if (rows && row_count) { - const gs_param_table_row_t * last_row = rows; - // table rows may not be in assending address- so we have to run through the entire table. - for (size_t i = 0; i < row_count; ++i, ++rows) { - if (GS_PARAM_ADDR(rows) > GS_PARAM_ADDR(last_row)) { - last_row = rows; - } - } - return (GS_PARAM_ADDR(last_row) + (GS_PARAM_SIZE(last_row) * GS_PARAM_ARRAY_SIZE(last_row))); - } - return 0; -} - -const gs_param_table_row_t * gs_param_row_by_name(const char * name, const gs_param_table_row_t * rows, size_t row_count) -{ - if (rows) { - for (unsigned int i = 0; i < row_count; ++i, ++rows) { - if (GS_PGM_STRNCASECMP(name, rows->name, GS_PARAM_MAX_NAME) == 0) { - return rows; - } - } - } - return NULL; -} - -const gs_param_table_row_t * gs_param_row_by_address(uint16_t addr, const gs_param_table_row_t * rows, size_t row_count) -{ - if (rows) { - for (unsigned int i = 0; i < row_count; ++i, ++rows) { - const unsigned int param_array_size = GS_PARAM_ARRAY_SIZE(rows); - const unsigned int param_size = GS_PARAM_SIZE(rows); - const unsigned int param_addr = GS_PARAM_ADDR(rows); - for (unsigned int j = 0; j < param_array_size; ++j) { - if ((param_addr + (j * param_size)) == addr) { - return rows; - } - } - } - } - return NULL; -} - -/** - memcpy is used, because data/value may not be aligned correctly and cause crash if accessed directly. -*/ -gs_error_t gs_param_to_string_buffer(const gs_param_table_row_t * param, const void * value, bool with_type, uint32_t flags, gs_bytebuffer_t *bb) -{ - flags |= param->flags; - const uint8_t param_type = GS_PARAM_TYPE(param); - switch (param_type) { - case GS_PARAM_BOOL: { - if (with_type == 1) { - gs_bytebuffer_printf(bb, "BL "); - } - gs_bytebuffer_printf(bb, "%s", *(uint8_t *) value ? "true" : "false"); - break; - } - case GS_PARAM_INT8: { - if (with_type == 1) { - gs_bytebuffer_printf(bb, "I8 "); - } - gs_bytebuffer_printf(bb, "%d", *(int8_t *) value); - break; - } - case PARAM_X8: - flags |= GS_PARAM_F_SHOW_HEX; - // fallthrough - case GS_PARAM_UINT8: { - if (with_type == 1) { - gs_bytebuffer_printf(bb, "U8 "); - } - if (flags & GS_PARAM_F_SHOW_HEX) { - gs_bytebuffer_printf(bb, "0x%02"PRIx8, *(uint8_t *) value); - } else { - gs_bytebuffer_printf(bb, "%u", *(uint8_t *) value); - } - break; - } - case GS_PARAM_INT16: { - int16_t tmp; - memcpy(&tmp, value, sizeof(tmp)); - if (with_type == 1) { - gs_bytebuffer_printf(bb, "I16 "); - } - gs_bytebuffer_printf(bb, "%"PRId16, tmp); - break; - } - case PARAM_X16: - flags |= GS_PARAM_F_SHOW_HEX; - // fallthrough - case GS_PARAM_UINT16: { - uint16_t tmp; - memcpy(&tmp, value, sizeof(tmp)); - if (with_type == 1) { - gs_bytebuffer_printf(bb, "U16 "); - } - if (flags & GS_PARAM_F_SHOW_HEX) { - gs_bytebuffer_printf(bb, "0x%04"PRIx16, tmp); - } else { - gs_bytebuffer_printf(bb, "%"PRIu16, tmp); - } - break; - } - case GS_PARAM_INT32: { - int32_t tmp; - memcpy(&tmp, value, sizeof(tmp)); - if (with_type == 1) { - gs_bytebuffer_printf(bb, "I32 "); - } - gs_bytebuffer_printf(bb, "%"PRId32, tmp); - break; - } - case PARAM_X32: - flags |= GS_PARAM_F_SHOW_HEX; - // fallthrough - case GS_PARAM_UINT32: { - uint32_t tmp; - memcpy(&tmp, value, sizeof(tmp)); - if (with_type == 1) { - gs_bytebuffer_printf(bb, "U32 "); - } - if (flags & GS_PARAM_F_SHOW_HEX) { - gs_bytebuffer_printf(bb, "0x%08"PRIx32, tmp); - } else { - gs_bytebuffer_printf(bb, "%"PRIu32, tmp); - } - break; - } -#ifdef PRIu64 - case GS_PARAM_INT64: { - int64_t tmp; - memcpy(&tmp, value, sizeof(tmp)); - if (with_type == 1) { - gs_bytebuffer_printf(bb, "I64 "); - } - gs_bytebuffer_printf(bb, "%"PRId64, tmp); - break; - } - case PARAM_X64: - flags |= GS_PARAM_F_SHOW_HEX; - // fallthrough - case GS_PARAM_UINT64: { - uint64_t tmp; - memcpy(&tmp, value, sizeof(tmp)); - if (with_type == 1) { - gs_bytebuffer_printf(bb, "U64 "); - } - if (flags & GS_PARAM_F_SHOW_HEX) { - gs_bytebuffer_printf(bb, "0x%016"PRIx64, tmp); - } else { - gs_bytebuffer_printf(bb, "%"PRIu64, tmp); - } - break; - } -#endif - case GS_PARAM_FLOAT: { - float tmp; - memcpy(&tmp, value, sizeof(tmp)); - if (with_type == 1) { - gs_bytebuffer_printf(bb, "FLT "); - } - if (flags & GS_PARAM_F_SHOW_SCIENTIFIC) { - gs_bytebuffer_printf(bb, "%e", (double) tmp); - } else { - gs_bytebuffer_printf(bb, "%f", (double) tmp); - } - break; - } - case GS_PARAM_DOUBLE: { - double tmp; - memcpy(&tmp, value, sizeof(tmp)); - if (with_type == 1) { - gs_bytebuffer_printf(bb, "DBL "); - } - if (flags & GS_PARAM_F_SHOW_SCIENTIFIC) { - gs_bytebuffer_printf(bb, "%e", tmp); - } else { - gs_bytebuffer_printf(bb, "%f", tmp); - } - break; - } - case GS_PARAM_STRING: { - if (with_type == 1) { - gs_bytebuffer_printf(bb, "STR "); - } - gs_bytebuffer_append(bb, "\"", 1); - // handle missing NUL termination. - const size_t len = strnlen((const char*)value, GS_PARAM_SIZE(param)); - gs_bytebuffer_append(bb, value, len); - gs_bytebuffer_append(bb, "\"", 1); - break; - } - case GS_PARAM_DATA: { - if (with_type == 1) { - gs_bytebuffer_printf(bb, "DAT "); - } - for (int i = 0; i < GS_PARAM_SIZE(param); i++) { - gs_bytebuffer_printf(bb, "%02"PRIX8, ((uint8_t *) value)[i]); - } - break; - } - default: { - log_error("%s: Unknown param type %u", __FUNCTION__, param_type); - break; - } - } - - return GS_OK; -} - -gs_error_t gs_param_to_string2(const gs_param_table_row_t * param, const void * value, bool with_type, uint32_t flags, char * buf, unsigned int buf_size, unsigned int buf_pos, unsigned int * buf_written) -{ - GS_CHECK_ARG(buf_pos <= buf_size); - gs_bytebuffer_t bb; - gs_bytebuffer_init(&bb, &buf[buf_pos], (buf_size - buf_pos)); - gs_error_t error = gs_param_to_string_buffer(param, value, with_type, flags, &bb); - if (error == GS_OK) { - gs_bytebuffer_get_as_string(&bb, &error); // this will add NUL termination, but may truncate buffer - error = gs_bytebuffer_get_state(&bb); - if (buf_written) { - *buf_written = bb.used; - } - } - return error; -} - -const char * gs_param_type_to_string(gs_param_type_t type) -{ - switch (type) { - case GS_PARAM_BOOL: return "bool"; - case GS_PARAM_UINT8: return "uint8_t"; - case GS_PARAM_UINT16: return "uint16_t"; - case GS_PARAM_UINT32: return "uint32_t"; - case GS_PARAM_UINT64: return "uint65_t"; - case GS_PARAM_INT8: return "int8_t"; - case GS_PARAM_INT16: return "int16_t"; - case GS_PARAM_INT32: return "int32_t"; - case GS_PARAM_INT64: return "int64_t"; - case PARAM_X8: return "uint8_t"; - case PARAM_X16: return "uint16_t"; - case PARAM_X32: return "uint32_t"; - case PARAM_X64: return "uint64_t"; - case GS_PARAM_FLOAT: return "float"; - case GS_PARAM_DOUBLE: return "double"; - case GS_PARAM_STRING: return "char"; - case GS_PARAM_DATA: return "char"; - } - return ""; -} - -static inline int to_int(char c) -{ - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'A' && c <= 'F') return 10 + c - 'A'; - if (c >= 'a' && c <= 'f') return 10 + c - 'a'; - return -1; -} - -gs_error_t gs_param_from_string(const gs_param_table_row_t * param, const char * string, void * value) -{ - if ((param == NULL) || (string == NULL) || (value == NULL)) { - return GS_ERROR_ARG; - } - - if (GS_PARAM_TYPE(param) != GS_PARAM_STRING) { - // skip only space - not white-space, e.g. isspace() - for (; *string == ' '; ++string); - } - - gs_error_t error = GS_OK; - - switch(GS_PARAM_TYPE(param)) { - - case GS_PARAM_BOOL: - { - bool parsein = false; - error = gs_string_to_bool(string, &parsein); - if (error == GS_OK) { - *((uint8_t *) value) = parsein; - } - } - break; - - case GS_PARAM_UINT8: - { - uint8_t parsein; - error = gs_string_to_uint8(string, &parsein); - if (error == GS_OK) { - *((uint8_t *) value) = parsein; - } - } - break; - - case GS_PARAM_UINT16: - { - uint16_t parsein; - error = gs_string_to_uint16(string, &parsein); - if (error == GS_OK) { - *((uint16_t *) value) = parsein; - } - } - break; - - case GS_PARAM_UINT32: - { - uint32_t parsein; - error = gs_string_to_uint32(string, &parsein); - if (error == GS_OK) { - *((uint32_t *) value) = parsein; - } - } - break; - - case GS_PARAM_UINT64: - { - uint64_t parsein; - error = gs_string_to_uint64(string, &parsein); - if (error == GS_OK) { - *((uint64_t *) value) = parsein; - } - } - break; - - case GS_PARAM_INT8: - { - int8_t parsein; - error = gs_string_to_int8(string, &parsein); - if (error == GS_OK) { - *((int8_t *) value) = parsein; - } - } - break; - - case GS_PARAM_INT16: - { - int16_t parsein; - error = gs_string_to_int16(string, &parsein); - if (error == GS_OK) { - *((int16_t *) value) = parsein; - } - } - break; - - case GS_PARAM_INT32: - { - int32_t parsein; - error = gs_string_to_int32(string, &parsein); - if (error == GS_OK) { - *((int32_t *) value) = parsein; - } - } - break; - - case GS_PARAM_INT64: - { - int64_t parsein; - error = gs_string_to_int64(string, &parsein); - if (error == GS_OK) { - *((int64_t *) value) = parsein; - } - } - break; - - case PARAM_X8: - { - uint32_t parsein; - error = gs_string_hex_to_uint32(string, &parsein); - if (error == GS_OK) { - if (parsein <= UINT8_MAX) { - *((uint8_t *) value) = parsein; - } else { - error = GS_ERROR_OVERFLOW; - } - } - } - break; - - case PARAM_X16: - { - uint32_t parsein; - error = gs_string_hex_to_uint32(string, &parsein); - if (error == GS_OK) { - if (parsein <= UINT16_MAX) { - *((uint16_t *) value) = parsein; - } else { - error = GS_ERROR_OVERFLOW; - } - } - } - break; - - case PARAM_X32: - { - uint32_t parsein; - error = gs_string_hex_to_uint32(string, &parsein); - if (error == GS_OK) { - *((uint32_t *) value) = parsein; - } - } - break; - - case PARAM_X64: - { - uint64_t parsein; - error = gs_string_hex_to_uint64(string, &parsein); - if (error == GS_OK) { - *((uint64_t *) value) = parsein; - } - } - break; - - case GS_PARAM_FLOAT: - { - float parsein; - error = gs_string_to_float(string, &parsein); - if (error == GS_OK) { - *((float *) value) = parsein; - } - } - break; - - case GS_PARAM_DOUBLE: - { - double parsein; - error = gs_string_to_double(string, &parsein); - if (error == GS_OK) { - *((double *) value) = parsein; - } - } - break; - - case GS_PARAM_STRING: - { - const size_t ilen = strnlen(string, GS_PARAM_SIZE(param) + 1); // 0 terminator - if (ilen <= GS_PARAM_SIZE(param)) { - memset(value, 0, GS_PARAM_SIZE(param)); - memcpy(value, string, ilen); - } else { - error = GS_ERROR_OVERFLOW; - } - } - break; - - case GS_PARAM_DATA: - { - const size_t MAX_LEN = (GS_PARAM_SIZE(param) * 2); - const size_t ilen = strnlen(string, MAX_LEN + 1); - if (ilen > MAX_LEN) { - error = GS_ERROR_OVERFLOW; - } else if ((ilen % 2) == 0) { - - // validate data first - not to end up with invalid/strange data - for (unsigned int i = 0; i < ilen; ++i) { - if (to_int(string[i]) < 0) { - error = GS_ERROR_DATA; - break; - } - } - if (error == GS_OK) { - uint8_t * out = (uint8_t *) value; - memset(out, 0, GS_PARAM_SIZE(param)); - for (unsigned int i = 0; i < ilen; i += 2, ++out) { - *out = (16 * to_int(string[i])) + to_int(string[i+1]); - } - error = GS_OK; - } - } else { - error = GS_ERROR_DATA; - } - } - break; - } - - return error; -} - -gs_error_t gs_param_list_single_to_stream(gs_param_table_instance_t * tinst, const gs_param_table_row_t * param, - bool list_data, uint32_t flags, FILE * out) -{ - if (param == NULL) { - return GS_ERROR_HANDLE; - } - - gs_error_t error = GS_OK; - const uint16_t addr = GS_PARAM_ADDR(param); - - fprintf(out, " 0x%04X %-16.14"GS_PGM_FMT_STR, addr, param->name); // ensure missing NUL termination doesn't cause problems. - - if (list_data) { - const gs_param_type_t param_type = GS_PARAM_TYPE(param); - const unsigned int param_array_size = GS_PARAM_ARRAY_SIZE(param); - const unsigned int param_size = GS_PARAM_SIZE(param); - uint8_t value[param_size]; - char buf[100]; - for (unsigned int j = 0; (j < param_array_size) && (error == GS_OK); j++) { - error = gs_param_get(tinst, addr + (param_size * j), param_type, value, param_size, 0); - if (error == GS_OK) { - gs_param_to_string2(param, value, (j == 0) ? 1 : 0, flags, buf, sizeof(buf), 0, NULL); - fprintf(out, "%s ", buf); - } - } - } - fprintf(out, "\r\n"); - return error; -} - -gs_error_t gs_param_list_to_stream(gs_param_table_instance_t * tinst, bool list_data, uint32_t flags, FILE * out) -{ - GS_CHECK_HANDLE(tinst != NULL); - - gs_error_t error = GS_OK; - for (unsigned int i = 0; (i < tinst->row_count) && (error == GS_OK); ++i) { - error = gs_param_list_single_to_stream(tinst, &tinst->rows[i], list_data, flags, out); - } - - return error; -} - -gs_error_t gs_param_parse_name_and_array_index(const char * inp, char * name, size_t size_name, uint8_t * return_index, bool * return_is_array) -{ - if (inp == NULL) { - return GS_ERROR_ARG; - } - - uint8_t a_index; - size_t name_len; - gs_error_t error; - bool is_array; - const char * pai = strchr(inp, '['); // look for array index - if (pai) { - name_len = pai - inp; - char tmp[20]; - GS_STRNCPY(tmp, pai+1); - char * endp = strchr(tmp, ']'); - if (endp) { - *endp = 0; - } - error = gs_string_to_uint8(tmp, &a_index); - is_array = true; - } else { - error = GS_OK; - name_len = strlen(inp); - is_array = false; - a_index = 0; - } - - if (error == GS_OK) { - if (name_len >= size_name) { - error = GS_ERROR_OVERFLOW; - } else { - strncpy(name, inp, name_len); - name[name_len] = 0; - - // remove trailing white-space - if (name_len) { - for (int i = name_len-1; i >= 0; --i) { - if (name[i] && isspace((int)name[i])) { - name[i] = 0; - } else { - break; - } - } - } - - if (return_index) { - *return_index = (is_array) ? a_index : 0; - } - if (return_is_array) { - *return_is_array = is_array; - } - } - } - - return error; -} diff --git a/gomspace/libparam_client/src/table.c b/gomspace/libparam_client/src/table.c deleted file mode 100644 index 3aea93ad..00000000 --- a/gomspace/libparam_client/src/table.c +++ /dev/null @@ -1,393 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#define GS_PARAM_INTERNAL_USE 1 - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static void _copy_data(gs_param_type_t type, void * dst, const void * src, size_t size) -{ -#if (GS_PARAM_ATOMIC_ACCESS) - switch (type) { - case GS_PARAM_UINT8: - case GS_PARAM_INT8: - case PARAM_X8: - case GS_PARAM_STRING: - case GS_PARAM_DATA: - case GS_PARAM_BOOL: - break; - - case GS_PARAM_UINT16: - case GS_PARAM_INT16: - case PARAM_X16: - if (!((intptr_t)src & 1) && !((intptr_t)dst & 1)) { - // (u)int16 aligned correctly - const uint16_t * s = src; - uint16_t * d = dst; - const unsigned int count = (size / sizeof(*d)); - for (unsigned int i = 0; i < count; ++i, ++d, ++s) { - *d = *s; - } - //printf("%s:int16\r\n", __FUNCTION__); - return; - } - break; - - case GS_PARAM_UINT32: - case GS_PARAM_INT32: - case PARAM_X32: - case GS_PARAM_FLOAT: - if (!((intptr_t)src & 3) && !((intptr_t)dst & 3)) { - // (u)int32 aligned correctly - const uint32_t * s = src; - uint32_t * d = dst; - const unsigned int count = (size / sizeof(*d)); - for (unsigned int i = 0; i < count; ++i, ++d, ++s) { - *d = *s; - } - //printf("%s:int32\r\n", __FUNCTION__); - return; - } - break; - - case GS_PARAM_UINT64: - case GS_PARAM_INT64: - case PARAM_X64: - case GS_PARAM_DOUBLE: - break; - } -#endif - - // fallback - do byte copy - memcpy(dst, src, size); -} - -gs_error_t gs_param_table_lock(gs_param_table_instance_t * tinst) -{ - if (tinst->lock) { - return gs_mutex_lock(tinst->lock); - } - return GS_OK; -} - -gs_error_t gs_param_table_unlock(gs_param_table_instance_t * tinst) -{ - if (tinst->lock) { - return gs_mutex_unlock(tinst->lock); - } - return GS_OK; -} - -static gs_error_t gs_param_table_lock_free(gs_param_table_instance_t * tinst) -{ - if (tinst && tinst->lock) { - gs_mutex_destroy(tinst->lock); - tinst->lock = NULL; - } - return GS_OK; -} - -gs_error_t gs_param_table_free(gs_param_table_instance_t * tinst) -{ - if (tinst) { - if (tinst->flags & GS_PARAM_TABLE_F_ALLOC_MEMORY) { - free(tinst->memory); - } - if (tinst->flags & GS_PARAM_TABLE_F_ALLOC_ROWS) { - free((void*)tinst->rows); - } - if (tinst->lock) { - gs_param_table_lock_free(tinst); - } - memset(tinst, 0, sizeof(*tinst)); - } - return GS_OK; -} - -static void checksum_update(gs_param_table_instance_t * tinst) -{ - const uint16_t no_swap = gs_fletcher16(tinst->rows, (sizeof(*tinst->rows) * tinst->row_count)); - - // fletcher16 with swapped fields > 1 byte - gs_fletcher16_t f16; - gs_fletcher16_init(&f16); - for (unsigned int i = 0; i < tinst->row_count; ++i) { - gs_param_table_row_t row = tinst->rows[i]; - row.addr = gs_bswap_16(row.addr); - gs_fletcher16_update(&f16, &row, sizeof(row)); - } - const uint16_t swap = gs_fletcher16_finalize(&f16); - - if (gs_endian_big()) { - tinst->checksum_be = no_swap; - tinst->checksum_le = swap; - } else { - tinst->checksum_be = swap; - tinst->checksum_le = no_swap; - } -} - -uint16_t gs_param_table_checksum_be(gs_param_table_instance_t * tinst) -{ - if (tinst && tinst->rows && tinst->row_count) { - if (tinst->checksum_be == 0) { - checksum_update(tinst); - } - return tinst->checksum_be; - } - return 0; -} - -uint16_t gs_param_table_checksum_le(gs_param_table_instance_t * tinst) -{ - if (tinst && tinst->rows && tinst->row_count) { - if (tinst->checksum_le == 0) { - checksum_update(tinst); - } - return tinst->checksum_le; - } - return 0; -} - -uint16_t gs_param_table_checksum(gs_param_table_instance_t * tinst) -{ - if (gs_endian_big()) { - return gs_param_table_checksum_be(tinst); - } else { - return gs_param_table_checksum_le(tinst); - } -} - -gs_error_t gs_param_get(gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, void * value, size_t value_size, uint32_t flags) -{ - if (tinst == NULL) { - return GS_ERROR_HANDLE; - } - - if ((addr + value_size) > tinst->memory_size) { - return GS_ERROR_RANGE; - } - - gs_error_t error = GS_ERROR_NOT_SUPPORTED; - if (tinst->function_interface.get) { - error = (tinst->function_interface.get)(tinst->function_interface.context, tinst, addr, type, value, value_size, flags); - } else if (tinst->memory) { - gs_param_table_lock(tinst); - _copy_data(type, value, ((uint8_t*)(tinst->memory)) + addr, value_size); - gs_param_table_unlock(tinst); - error = GS_OK; - } - - if ((error == GS_OK) && (flags & GS_PARAM_SF_TO_BIG_ENDIAN) && !gs_endian_big()) { - gs_param_htobe(type, value); - } - - return error; -} - -gs_error_t gs_param_set(gs_param_table_instance_t * tinst, uint16_t addr, gs_param_type_t type, const void * value, size_t value_size, uint32_t flags) -{ - if (tinst == NULL) { - return GS_ERROR_HANDLE; - } - - if ((addr + value_size) > tinst->memory_size) { - return GS_ERROR_RANGE; - } - - if ((flags & GS_PARAM_SF_FROM_BIG_ENDIAN) && !gs_endian_big()) { - void * tmp = alloca(value_size); // this must be aligned - memcpy(tmp, value, value_size); - value = tmp; - gs_param_betoh(type, tmp); - } - - gs_error_t error = GS_ERROR_NOT_SUPPORTED; - if (tinst->function_interface.set) { - error = (tinst->function_interface.set)(tinst->function_interface.context, tinst, addr, type, value, value_size, flags); - } else if (tinst->memory) { - gs_param_table_lock(tinst); - _copy_data(type, ((uint8_t*)(tinst->memory)) + addr, value, value_size); - gs_param_table_unlock(tinst); - - if (tinst->auto_persist.set && (flags & GS_PARAM_F_AUTO_PERSIST)) { - (tinst->auto_persist.set)(tinst, addr, type, value, value_size, flags); - } - error = GS_OK; - } - - // Callbacks - if ((error == GS_OK) && tinst->callback && ((flags & GS_PARAM_F_NO_CALLBACK) == 0)) { - (tinst->callback)(addr, tinst); - } - - return error; -} - -uint8_t gs_param_type_size(gs_param_type_t type) -{ - switch (type) { - case GS_PARAM_UINT8: - case GS_PARAM_INT8: - case PARAM_X8: - case GS_PARAM_STRING: - case GS_PARAM_DATA: - return sizeof(int8_t); - case GS_PARAM_INT16: - case GS_PARAM_UINT16: - case PARAM_X16: - return sizeof(int16_t); - case GS_PARAM_INT32: - case GS_PARAM_UINT32: - case PARAM_X32: - return sizeof(int32_t); - case GS_PARAM_INT64: - case GS_PARAM_UINT64: - case PARAM_X64: - return sizeof(int64_t); - case GS_PARAM_DOUBLE: - return sizeof(double); - case GS_PARAM_FLOAT: - return sizeof(float); - case GS_PARAM_BOOL: - return sizeof(bool); - } - return 0; -} - -void * gs_param_table_get_memory(gs_param_table_instance_t * tinst, size_t * return_size) -{ - if (tinst && tinst->memory) { - if (return_size) { - *return_size = tinst->memory_size; - } - return tinst->memory; - } - return NULL; -} - -const gs_param_table_row_t * gs_param_table_get_rows(gs_param_table_instance_t * tinst, size_t * return_count) -{ - if (tinst && tinst->rows && tinst->row_count) { - if (return_count) { - *return_count = tinst->row_count; - } - return tinst->rows; - } - return NULL; -} - -size_t gs_param_table_instance_size(void) -{ - return sizeof(gs_param_table_instance_t); -} - -gs_param_table_instance_t * gs_param_table_instance_clear(void * var, size_t var_size) -{ - gs_param_table_instance_t * tinst = NULL; - if (var && (var_size >= sizeof(*tinst))) { - tinst = (gs_param_table_instance_t *) var; - memset(tinst, 0, sizeof(*tinst)); - } - return tinst; -} - -gs_param_table_instance_t * gs_param_table_instance_alloc(void) -{ - return calloc(1, sizeof(gs_param_table_instance_t)); -} - -gs_error_t gs_param_get_string(gs_param_table_instance_t * tinst, uint16_t addr, char * buf, size_t buf_size, uint32_t flags) -{ - if (tinst == NULL) { - return GS_ERROR_HANDLE; - } - if (buf == NULL) { - return GS_ERROR_ARG; - } - - const gs_param_table_row_t * param = gs_param_row_by_address(addr, tinst->rows, tinst->row_count); - if (param == NULL) { - return GS_ERROR_RANGE; - } - - if (buf_size <= param->size) { - return GS_ERROR_OVERFLOW; - } - - gs_error_t error = gs_param_get(tinst, addr, param->type, buf, param->size, flags); - buf[param->size] = 0; - return error; -} - -gs_error_t gs_param_set_string(gs_param_table_instance_t * tinst, uint16_t addr, const char * value, uint32_t flags) -{ - if (tinst == NULL) { - return GS_ERROR_HANDLE; - } - if (value == NULL) { - return GS_ERROR_ARG; - } - - const gs_param_table_row_t * param = gs_param_row_by_address(addr, tinst->rows, tinst->row_count); - if (param == NULL) { - return GS_ERROR_RANGE; - } - - const size_t len = strlen(value) + 1; - if (len > GS_PARAM_SIZE(param)) { - return GS_ERROR_OVERFLOW; - } - - return gs_param_set(tinst, addr, param->type, value, len, flags); // flags have full control -} - -gs_error_t gs_param_get_data(gs_param_table_instance_t * tinst, uint16_t addr, void * buf, size_t buf_size, uint32_t flags) -{ - if (tinst == NULL) { - return GS_ERROR_HANDLE; - } - if (buf == NULL) { - return GS_ERROR_ARG; - } - - const gs_param_table_row_t * param = gs_param_row_by_address(addr, tinst->rows, tinst->row_count); - if (param == NULL) { - return GS_ERROR_RANGE; - } - - if (buf_size < param->size) { - return GS_ERROR_OVERFLOW; - } - - return gs_param_get(tinst, addr, param->type, buf, param->size, flags); -} - -gs_error_t gs_param_set_data(gs_param_table_instance_t * tinst, uint16_t addr, const void * value, size_t value_size, uint32_t flags) -{ - if (tinst == NULL) { - return GS_ERROR_HANDLE; - } - if (value == NULL) { - return GS_ERROR_ARG; - } - - const gs_param_table_row_t * param = gs_param_row_by_address(addr, tinst->rows, tinst->row_count); - if (param == NULL) { - return GS_ERROR_RANGE; - } - - if (value_size > GS_PARAM_SIZE(param)) { - return GS_ERROR_OVERFLOW; - } - - return gs_param_set(tinst, addr, param->type, value, value_size, flags); // flags have full control -} diff --git a/gomspace/libparam_client/wscript b/gomspace/libparam_client/wscript deleted file mode 100644 index ea023583..00000000 --- a/gomspace/libparam_client/wscript +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -# Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. - -import os -import gs_gcc -import gs_doc - -APPNAME = 'param_client' - - -def options(ctx): - ctx.load('gs_gcc gs_doc') - gs_gcc.gs_recurse(ctx) - - gr = ctx.add_option_group('libparam client options') - gr.add_option('--param_client-disable-cmd', action='store_true', help='Disable GOSH commands') - gr.add_option('--param-enable-atomic-access', action='store_true', help='Enable atomic read/write of 16/32/float') - - -def configure(ctx): - ctx.load('gs_gcc gs_doc') - - ctx.env.append_unique('USE_PARAM_CLIENT', ['gscsp', 'util']) - - ctx.env.append_unique('FILES_PARAM_CLIENT', ['src/*.c', 'src/rparam/*.c', - 'src/pp/*.c', 'src/pp/i2c/*.c', 'src/pp/spi/*.c']) - - if not ctx.options.param_client_disable_cmd: - ctx.env.append_unique('FILES_PARAM_CLIENT', ['src/rparam/cmd/*.c', 'src/pp/cmd/*.c']) - - if ctx.options.param_enable_atomic_access: - ctx.env.append_unique('DEFINES_PARAM_CLIENT', ['GS_PARAM_ATOMIC_ACCESS=1']) - - ctx.gs_register_handler(function='param_gen_4_0', filepath='./tools/waf_param.py') - ctx.gs_register_handler(function='param_gen_4_2', filepath='./tools/waf_param.py') - ctx.gs_register_handler(function='param_gen_4_3', filepath='./tools/waf_param.py') - - ctx.gs_add_doxygen(exclude=['*/include/deprecated/param/*', '*/include/gs/param/internal/*']) - - gs_gcc.gs_recurse(ctx) - - -def build(ctx): - gs_gcc.gs_recurse(ctx) - - public_include = ctx.gs_include(name=APPNAME, - includes=['include', 'include/deprecated', 'include/deprecated/param']) - - if ctx.env.GS_ARCH not in ['avr8']: - ctx.gs_objects(source=ctx.path.ant_glob(ctx.env.FILES_PARAM_CLIENT), - target=APPNAME, - defines=ctx.env.DEFINES_PARAM_CLIENT, - use=ctx.env.USE_PARAM_CLIENT + [public_include]) - - ctx.gs_shlib(source=ctx.path.ant_glob(ctx.env.FILES_PARAM_CLIENT), - target=APPNAME, - defines=ctx.env.DEFINES_PARAM_CLIENT, - gs_use_shlib=ctx.env.USE_PARAM_CLIENT + [public_include]) - - ctx.gs_python_bindings(source=ctx.path.ant_glob('src/bindings/python/pyparam.c'), - target=APPNAME, - gs_use_shlib=ctx.env.USE_PARAM_CLIENT + [APPNAME, public_include], - package='libparam') - - -def gs_dist(ctx): - gs_gcc.gs_recurse(ctx) - ctx.add_default_files(source_module=True) diff --git a/gomspace/libutil/include/conf_util.h b/gomspace/libutil/include/conf_util.h deleted file mode 100644 index d96c3665..00000000 --- a/gomspace/libutil/include/conf_util.h +++ /dev/null @@ -1,12 +0,0 @@ -/* WARNING! All changes made to this file will be lost! */ - -#ifndef W_INCLUDE_CONF_UTIL_H_WAF -#define W_INCLUDE_CONF_UTIL_H_WAF - -#define UTIL_LITTLE_ENDIAN 1 -/* #undef UTIL_BIG_ENDIAN */ -#define GS_CONSOLE_HISTORY_LEN 10 -#define GS_CONSOLE_INPUT_LEN 100 -/* #undef GS_LOG_ENABLE_ISR_LOGS */ - -#endif /* W_INCLUDE_CONF_UTIL_H_WAF */ diff --git a/gomspace/libutil/include/deprecated/gs/gosh/command/command.h b/gomspace/libutil/include/deprecated/gs/gosh/command/command.h deleted file mode 100644 index 540afea4..00000000 --- a/gomspace/libutil/include/deprecated/gs/gosh/command/command.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef GS_GOSH_COMMAND_COMMAND_H -#define GS_GOSH_COMMAND_COMMAND_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - Legacy header file - use gs/util/gosh/command.h -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define CMD_ERROR_NONE GS_OK -#define CMD_ERROR_FAIL GS_ERROR_UNKNOWN -#define CMD_ERROR_SYNTAX GS_ERROR_ARG -#define CMD_ERROR_NOMEM GS_ERROR_ALLOC -#define CMD_ERROR_INVALID GS_ERROR_DATA -#define CMD_ERROR_NOTFOUND GS_ERROR_NOT_FOUND - -#define CMD_HIDDEN GS_COMMAND_FLAG_HIDDEN - -#define __root_command GS_COMMAND_ROOT -#define __sub_command GS_COMMAND_SUB - -#define INIT_CHAIN(__list) GS_COMMAND_INIT_CHAIN(__list) -#define command_register(__cmd) GS_COMMAND_REGISTER(__cmd) - -typedef struct command command_t; - -static inline const char * command_args(gs_command_context_t *ctx) -{ - return gs_command_args(ctx); -} - -static inline int command_run(char *line) -{ - gs_error_t result = GS_OK; - gs_error_t error = gs_command_run(line, &result); - if (error == GS_OK) { - return result; - } - return error; -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h b/gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h deleted file mode 100644 index e0e40329..00000000 --- a/gomspace/libutil/include/deprecated/gs/gosh/gosh/getopt.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef GS_GOSH_GOSH_GETOPT_H -#define GS_GOSH_GOSH_GETOPT_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - Legacy header file - use gs/util/gosh/getopt.h -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -static inline int gosh_getopt(gs_command_context_t *ctx, const char *opts) -{ - return gs_command_getopt(ctx, opts); -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/deprecated/gs/gosh/util/console.h b/gomspace/libutil/include/deprecated/gs/gosh/util/console.h deleted file mode 100644 index a8d1c94d..00000000 --- a/gomspace/libutil/include/deprecated/gs/gosh/util/console.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef GS_GOSH_UTIL_CONSOLE_H -#define GS_GOSH_UTIL_CONSOLE_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - Legacy header file - use gs/util/gosh/console.h -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -static inline int console_init(void) -{ - return gs_console_init(); -} - -static inline int console_exit(void) -{ - return gs_console_exit(); -} - -static inline void console_set_hostname(const char *host) -{ - gs_console_set_prompt(host); -} - -static inline void console_clear(void) -{ - gs_console_clear(); -} - -static inline void console_update(void) -{ - gs_console_update(); -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/deprecated/util/color_printf.h b/gomspace/libutil/include/deprecated/util/color_printf.h deleted file mode 100644 index a2129460..00000000 --- a/gomspace/libutil/include/deprecated/util/color_printf.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef DEPRECATED_UTIL_COLOR_PRINTF_H -#define DEPRECATED_UTIL_COLOR_PRINTF_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -typedef enum color_printf_e { - /* Colors */ - COLOR_COLORS = GS_COLOR_COLORS, - COLOR_NONE = GS_COLOR_NONE, - COLOR_BLACK = GS_COLOR_BLACK, - COLOR_RED = GS_COLOR_RED, - COLOR_GREEN = GS_COLOR_GREEN, - COLOR_YELLOW = GS_COLOR_YELLOW, - COLOR_BLUE = GS_COLOR_BLUE, - COLOR_MAGENTA = GS_COLOR_MAGENTA, - COLOR_CYAN = GS_COLOR_CYAN, - COLOR_WHITE = GS_COLOR_WHITE, - /* Attributes */ - COLOR_ATTRS = GS_COLOR_ATTRS, - COLOR_BOLD = GS_COLOR_BOLD, -} color_printf_t; - -#define color_printf gs_color_printf - -#endif diff --git a/gomspace/libutil/include/gs/uthash/utarray.h b/gomspace/libutil/include/gs/uthash/utarray.h deleted file mode 100644 index 145f3631..00000000 --- a/gomspace/libutil/include/gs/uthash/utarray.h +++ /dev/null @@ -1,231 +0,0 @@ -/* -Copyright (c) 2008-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -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. -*/ - -/* a dynamic array implementation using macros - */ -#ifndef UTARRAY_H -#define UTARRAY_H - -#define UTARRAY_VERSION 1.9.9 - -#ifdef __GNUC__ -#define _UNUSED_ __attribute__ ((__unused__)) -#else -#define _UNUSED_ -#endif - -#include /* size_t */ -#include /* memset, etc */ -#include /* exit */ - -#define oom() exit(-1) - -typedef void (ctor_f)(void *dst, const void *src); -typedef void (dtor_f)(void *elt); -typedef void (init_f)(void *elt); -typedef struct { - size_t sz; - init_f *init; - ctor_f *copy; - dtor_f *dtor; -} UT_icd; - -typedef struct { - unsigned i,n;/* i: index of next available slot, n: num slots */ - UT_icd icd; /* initializer, copy and destructor functions */ - char *d; /* n slots of size icd->sz*/ -} UT_array; - -#define utarray_init(a,_icd) do { \ - memset(a,0,sizeof(UT_array)); \ - (a)->icd=*_icd; \ -} while(0) - -#define utarray_done(a) do { \ - if ((a)->n) { \ - if ((a)->icd.dtor) { \ - size_t _ut_i; \ - for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ - (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ - } \ - } \ - free((a)->d); \ - } \ - (a)->n=0; \ -} while(0) - -#define utarray_new(a,_icd) do { \ - a=(UT_array*)malloc(sizeof(UT_array)); \ - utarray_init(a,_icd); \ -} while(0) - -#define utarray_free(a) do { \ - utarray_done(a); \ - free(a); \ -} while(0) - -#define utarray_reserve(a,by) do { \ - if (((a)->i+by) > ((a)->n)) { \ - while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \ - if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd.sz)) == NULL) oom(); \ - } \ -} while(0) - -#define utarray_push_back(a,p) do { \ - utarray_reserve(a,1); \ - if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \ - else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \ -} while(0) - -#define utarray_pop_back(a) do { \ - if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \ - else { (a)->i--; } \ -} while(0) - -#define utarray_extend_back(a) do { \ - utarray_reserve(a,1); \ - if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \ - else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \ - (a)->i++; \ -} while(0) - -#define utarray_len(a) ((a)->i) - -#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL) -#define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd.sz*(j) ))) - -#define utarray_insert(a,p,j) do { \ - if (j > (a)->i) utarray_resize(a,j); \ - utarray_reserve(a,1); \ - if ((j) < (a)->i) { \ - memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \ - ((a)->i - (j))*((a)->icd.sz)); \ - } \ - if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \ - else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \ - (a)->i++; \ -} while(0) - -#define utarray_inserta(a,w,j) do { \ - if (utarray_len(w) == 0) break; \ - if (j > (a)->i) utarray_resize(a,j); \ - utarray_reserve(a,utarray_len(w)); \ - if ((j) < (a)->i) { \ - memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \ - _utarray_eltptr(a,j), \ - ((a)->i - (j))*((a)->icd.sz)); \ - } \ - if ((a)->icd.copy) { \ - size_t _ut_i; \ - for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \ - (a)->icd.copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \ - } \ - } else { \ - memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \ - utarray_len(w)*((a)->icd.sz)); \ - } \ - (a)->i += utarray_len(w); \ -} while(0) - -#define utarray_resize(dst,num) do { \ - size_t _ut_i; \ - if (dst->i > (size_t)(num)) { \ - if ((dst)->icd.dtor) { \ - for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \ - (dst)->icd.dtor(utarray_eltptr(dst,_ut_i)); \ - } \ - } \ - } else if (dst->i < (size_t)(num)) { \ - utarray_reserve(dst,num-dst->i); \ - if ((dst)->icd.init) { \ - for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \ - (dst)->icd.init(utarray_eltptr(dst,_ut_i)); \ - } \ - } else { \ - memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd.sz*(num-dst->i)); \ - } \ - } \ - dst->i = num; \ -} while(0) - -#define utarray_concat(dst,src) do { \ - utarray_inserta((dst),(src),utarray_len(dst)); \ -} while(0) - -#define utarray_erase(a,pos,len) do { \ - if ((a)->icd.dtor) { \ - size_t _ut_i; \ - for(_ut_i=0; _ut_i < len; _ut_i++) { \ - (a)->icd.dtor(utarray_eltptr((a),pos+_ut_i)); \ - } \ - } \ - if ((a)->i > (pos+len)) { \ - memmove( _utarray_eltptr((a),pos), _utarray_eltptr((a),pos+len), \ - (((a)->i)-(pos+len))*((a)->icd.sz)); \ - } \ - (a)->i -= (len); \ -} while(0) - -#define utarray_renew(a,u) do { \ - if (a) utarray_clear(a); \ - else utarray_new((a),(u)); \ -} while(0) - -#define utarray_clear(a) do { \ - if ((a)->i > 0) { \ - if ((a)->icd.dtor) { \ - size_t _ut_i; \ - for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ - (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ - } \ - } \ - (a)->i = 0; \ - } \ -} while(0) - -#define utarray_sort(a,cmp) do { \ - qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \ -} while(0) - -#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp) - -#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL) -#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL)) -#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL)) -#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL) -#define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(size_t)(a)->icd.sz) : -1) - -/* last we pre-define a few icd for common utarrays of ints and strings */ -static void utarray_str_cpy(void *dst, const void *src) { - char **_src = (char**)src, **_dst = (char**)dst; - *_dst = (*_src == NULL) ? NULL : strdup(*_src); -} -static void utarray_str_dtor(void *elt) { - char **eltc = (char**)elt; - if (*eltc) free(*eltc); -} -static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor}; -static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL}; -static const UT_icd ut_ptr_icd _UNUSED_ = {sizeof(void*),NULL,NULL,NULL}; - -#endif /* UTARRAY_H */ diff --git a/gomspace/libutil/include/gs/uthash/uthash.h b/gomspace/libutil/include/gs/uthash/uthash.h deleted file mode 100644 index c8c6d25c..00000000 --- a/gomspace/libutil/include/gs/uthash/uthash.h +++ /dev/null @@ -1,960 +0,0 @@ -/* -Copyright (c) 2003-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -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. -*/ - -#ifndef UTHASH_H -#define UTHASH_H - -#include /* memcmp,strlen */ -#include /* ptrdiff_t */ -#include /* exit() */ - -/* These macros use decltype or the earlier __typeof GNU extension. - As decltype is only available in newer compilers (VS2010 or gcc 4.3+ - when compiling c++ source) this code uses whatever method is needed - or, for VS2008 where neither is available, uses casting workarounds. */ -#if defined(_MSC_VER) /* MS compiler */ -#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ -#define DECLTYPE(x) (decltype(x)) -#else /* VS2008 or older (or VS2010 in C mode) */ -#define NO_DECLTYPE -#define DECLTYPE(x) -#endif -#elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__) -#define NO_DECLTYPE -#define DECLTYPE(x) -#else /* GNU, Sun and other compilers */ -#define DECLTYPE(x) (__typeof(x)) -#endif - -#ifdef NO_DECLTYPE -#define DECLTYPE_ASSIGN(dst,src) \ -do { \ - char **_da_dst = (char**)(&(dst)); \ - *_da_dst = (char*)(src); \ -} while(0) -#else -#define DECLTYPE_ASSIGN(dst,src) \ -do { \ - (dst) = DECLTYPE(dst)(src); \ -} while(0) -#endif - -/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */ -#if defined (_WIN32) -#if defined(_MSC_VER) && _MSC_VER >= 1600 -#include -#elif defined(__WATCOMC__) -#include -#else -typedef unsigned int uint32_t; -typedef unsigned char uint8_t; -#endif -#else -#include -#endif - -#define UTHASH_VERSION 1.9.9 - -#ifndef uthash_fatal -#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ -#endif -#ifndef uthash_malloc -#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ -#endif -#ifndef uthash_free -#define uthash_free(ptr,sz) free(ptr) /* free fcn */ -#endif - -#ifndef uthash_noexpand_fyi -#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ -#endif -#ifndef uthash_expand_fyi -#define uthash_expand_fyi(tbl) /* can be defined to log expands */ -#endif - -/* initial number of buckets */ -#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ -#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ -#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ - -/* calculate the element whose hash handle address is hhe */ -#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) - -#define HASH_FIND(hh,head,keyptr,keylen,out) \ -do { \ - out=NULL; \ - if (head) { \ - unsigned _hf_bkt,_hf_hashv; \ - HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ - if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ - HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ - keyptr,keylen,out); \ - } \ - } \ -} while (0) - -#ifdef HASH_BLOOM -#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) -#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) -#define HASH_BLOOM_MAKE(tbl) \ -do { \ - (tbl)->bloom_nbits = HASH_BLOOM; \ - (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ - if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ - memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ - (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ -} while (0) - -#define HASH_BLOOM_FREE(tbl) \ -do { \ - uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ -} while (0) - -#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) -#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) - -#define HASH_BLOOM_ADD(tbl,hashv) \ - HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) - -#define HASH_BLOOM_TEST(tbl,hashv) \ - HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) - -#else -#define HASH_BLOOM_MAKE(tbl) -#define HASH_BLOOM_FREE(tbl) -#define HASH_BLOOM_ADD(tbl,hashv) -#define HASH_BLOOM_TEST(tbl,hashv) (1) -#define HASH_BLOOM_BYTELEN 0 -#endif - -#define HASH_MAKE_TABLE(hh,head) \ -do { \ - (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ - sizeof(UT_hash_table)); \ - if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ - memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ - (head)->hh.tbl->tail = &((head)->hh); \ - (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ - (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ - (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ - (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ - HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ - if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ - memset((head)->hh.tbl->buckets, 0, \ - HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ - HASH_BLOOM_MAKE((head)->hh.tbl); \ - (head)->hh.tbl->signature = HASH_SIGNATURE; \ -} while(0) - -#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ - HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add) - -#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ -do { \ - replaced=NULL; \ - HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced); \ - if (replaced!=NULL) { \ - HASH_DELETE(hh,head,replaced); \ - }; \ - HASH_ADD(hh,head,fieldname,keylen_in,add); \ -} while(0) - -#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ -do { \ - unsigned _ha_bkt; \ - (add)->hh.next = NULL; \ - (add)->hh.key = (char*)(keyptr); \ - (add)->hh.keylen = (unsigned)(keylen_in); \ - if (!(head)) { \ - head = (add); \ - (head)->hh.prev = NULL; \ - HASH_MAKE_TABLE(hh,head); \ - } else { \ - (head)->hh.tbl->tail->next = (add); \ - (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ - (head)->hh.tbl->tail = &((add)->hh); \ - } \ - (head)->hh.tbl->num_items++; \ - (add)->hh.tbl = (head)->hh.tbl; \ - HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ - (add)->hh.hashv, _ha_bkt); \ - HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ - HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ - HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ - HASH_FSCK(hh,head); \ -} while(0) - -#define HASH_TO_BKT( hashv, num_bkts, bkt ) \ -do { \ - bkt = ((hashv) & ((num_bkts) - 1)); \ -} while(0) - -/* delete "delptr" from the hash table. - * "the usual" patch-up process for the app-order doubly-linked-list. - * The use of _hd_hh_del below deserves special explanation. - * These used to be expressed using (delptr) but that led to a bug - * if someone used the same symbol for the head and deletee, like - * HASH_DELETE(hh,users,users); - * We want that to work, but by changing the head (users) below - * we were forfeiting our ability to further refer to the deletee (users) - * in the patch-up process. Solution: use scratch space to - * copy the deletee pointer, then the latter references are via that - * scratch pointer rather than through the repointed (users) symbol. - */ -#define HASH_DELETE(hh,head,delptr) \ -do { \ - struct UT_hash_handle *_hd_hh_del; \ - if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ - uthash_free((head)->hh.tbl->buckets, \ - (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ - HASH_BLOOM_FREE((head)->hh.tbl); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - head = NULL; \ - } else { \ - unsigned _hd_bkt; \ - _hd_hh_del = &((delptr)->hh); \ - if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ - (head)->hh.tbl->tail = \ - (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ - (head)->hh.tbl->hho); \ - } \ - if ((delptr)->hh.prev) { \ - ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ - (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ - } else { \ - DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ - } \ - if (_hd_hh_del->next) { \ - ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \ - (head)->hh.tbl->hho))->prev = \ - _hd_hh_del->prev; \ - } \ - HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ - HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ - (head)->hh.tbl->num_items--; \ - } \ - HASH_FSCK(hh,head); \ -} while (0) - - -/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ -#define HASH_FIND_STR(head,findstr,out) \ - HASH_FIND(hh,head,findstr,(unsigned)strlen(findstr),out) -#define HASH_ADD_STR(head,strfield,add) \ - HASH_ADD(hh,head,strfield[0],strlen(add->strfield),add) -#define HASH_REPLACE_STR(head,strfield,add,replaced) \ - HASH_REPLACE(hh,head,strfield[0],(unsigned)strlen(add->strfield),add,replaced) -#define HASH_FIND_INT(head,findint,out) \ - HASH_FIND(hh,head,findint,sizeof(int),out) -#define HASH_ADD_INT(head,intfield,add) \ - HASH_ADD(hh,head,intfield,sizeof(int),add) -#define HASH_REPLACE_INT(head,intfield,add,replaced) \ - HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) -#define HASH_FIND_PTR(head,findptr,out) \ - HASH_FIND(hh,head,findptr,sizeof(void *),out) -#define HASH_ADD_PTR(head,ptrfield,add) \ - HASH_ADD(hh,head,ptrfield,sizeof(void *),add) -#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ - HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) -#define HASH_DEL(head,delptr) \ - HASH_DELETE(hh,head,delptr) - -/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. - * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. - */ -#ifdef HASH_DEBUG -#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) -#define HASH_FSCK(hh,head) \ -do { \ - struct UT_hash_handle *_thh; \ - if (head) { \ - unsigned _bkt_i; \ - unsigned _count; \ - char *_prev; \ - _count = 0; \ - for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ - unsigned _bkt_count = 0; \ - _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ - _prev = NULL; \ - while (_thh) { \ - if (_prev != (char*)(_thh->hh_prev)) { \ - HASH_OOPS("invalid hh_prev %p, actual %p\n", \ - _thh->hh_prev, _prev ); \ - } \ - _bkt_count++; \ - _prev = (char*)(_thh); \ - _thh = _thh->hh_next; \ - } \ - _count += _bkt_count; \ - if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ - HASH_OOPS("invalid bucket count %u, actual %u\n", \ - (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ - } \ - } \ - if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("invalid hh item count %u, actual %u\n", \ - (head)->hh.tbl->num_items, _count ); \ - } \ - /* traverse hh in app order; check next/prev integrity, count */ \ - _count = 0; \ - _prev = NULL; \ - _thh = &(head)->hh; \ - while (_thh) { \ - _count++; \ - if (_prev !=(char*)(_thh->prev)) { \ - HASH_OOPS("invalid prev %p, actual %p\n", \ - _thh->prev, _prev ); \ - } \ - _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ - _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ - (head)->hh.tbl->hho) : NULL ); \ - } \ - if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("invalid app item count %u, actual %u\n", \ - (head)->hh.tbl->num_items, _count ); \ - } \ - } \ -} while (0) -#else -#define HASH_FSCK(hh,head) -#endif - -/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to - * the descriptor to which this macro is defined for tuning the hash function. - * The app can #include to get the prototype for write(2). */ -#ifdef HASH_EMIT_KEYS -#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ -do { \ - unsigned _klen = fieldlen; \ - write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ - write(HASH_EMIT_KEYS, keyptr, fieldlen); \ -} while (0) -#else -#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) -#endif - -/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ -#ifdef HASH_FUNCTION -#define HASH_FCN HASH_FUNCTION -#else -#define HASH_FCN HASH_JEN -#endif - -/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ -#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned _hb_keylen=keylen; \ - char *_hb_key=(char*)(key); \ - (hashv) = 0; \ - while (_hb_keylen--) { (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; } \ - bkt = (hashv) & (num_bkts-1); \ -} while (0) - - -/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at - * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ -#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned _sx_i; \ - char *_hs_key=(char*)(key); \ - hashv = 0; \ - for(_sx_i=0; _sx_i < keylen; _sx_i++) \ - hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ - bkt = hashv & (num_bkts-1); \ -} while (0) -/* FNV-1a variation */ -#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned _fn_i; \ - char *_hf_key=(char*)(key); \ - hashv = 2166136261UL; \ - for(_fn_i=0; _fn_i < keylen; _fn_i++) { \ - hashv = hashv ^ _hf_key[_fn_i]; \ - hashv = hashv * 16777619; \ - } \ - bkt = hashv & (num_bkts-1); \ -} while(0) - -#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned _ho_i; \ - char *_ho_key=(char*)(key); \ - hashv = 0; \ - for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ - hashv += _ho_key[_ho_i]; \ - hashv += (hashv << 10); \ - hashv ^= (hashv >> 6); \ - } \ - hashv += (hashv << 3); \ - hashv ^= (hashv >> 11); \ - hashv += (hashv << 15); \ - bkt = hashv & (num_bkts-1); \ -} while(0) - -#define HASH_JEN_MIX(a,b,c) \ -do { \ - a -= b; a -= c; a ^= ( c >> 13 ); \ - b -= c; b -= a; b ^= ( a << 8 ); \ - c -= a; c -= b; c ^= ( b >> 13 ); \ - a -= b; a -= c; a ^= ( c >> 12 ); \ - b -= c; b -= a; b ^= ( a << 16 ); \ - c -= a; c -= b; c ^= ( b >> 5 ); \ - a -= b; a -= c; a ^= ( c >> 3 ); \ - b -= c; b -= a; b ^= ( a << 10 ); \ - c -= a; c -= b; c ^= ( b >> 15 ); \ -} while (0) - -#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned _hj_i,_hj_j,_hj_k; \ - unsigned char *_hj_key=(unsigned char*)(key); \ - hashv = 0xfeedbeef; \ - _hj_i = _hj_j = 0x9e3779b9; \ - _hj_k = (unsigned)(keylen); \ - while (_hj_k >= 12) { \ - _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ - + ( (unsigned)_hj_key[2] << 16 ) \ - + ( (unsigned)_hj_key[3] << 24 ) ); \ - _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ - + ( (unsigned)_hj_key[6] << 16 ) \ - + ( (unsigned)_hj_key[7] << 24 ) ); \ - hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ - + ( (unsigned)_hj_key[10] << 16 ) \ - + ( (unsigned)_hj_key[11] << 24 ) ); \ - \ - HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ - \ - _hj_key += 12; \ - _hj_k -= 12; \ - } \ - hashv += keylen; \ - switch ( _hj_k ) { \ - case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ - case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ - case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ - case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ - case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ - case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ - case 5: _hj_j += _hj_key[4]; \ - case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ - case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ - case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ - case 1: _hj_i += _hj_key[0]; \ - } \ - HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ - bkt = hashv & (num_bkts-1); \ -} while(0) - -/* The Paul Hsieh hash function */ -#undef get16bits -#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ - || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) -#define get16bits(d) (*((const uint16_t *) (d))) -#endif - -#if !defined (get16bits) -#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ - +(uint32_t)(((const uint8_t *)(d))[0]) ) -#endif -#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ -do { \ - unsigned char *_sfh_key=(unsigned char*)(key); \ - uint32_t _sfh_tmp, _sfh_len = keylen; \ - \ - int _sfh_rem = _sfh_len & 3; \ - _sfh_len >>= 2; \ - hashv = 0xcafebabe; \ - \ - /* Main loop */ \ - for (;_sfh_len > 0; _sfh_len--) { \ - hashv += get16bits (_sfh_key); \ - _sfh_tmp = (uint32_t)(get16bits (_sfh_key+2)) << 11 ^ hashv; \ - hashv = (hashv << 16) ^ _sfh_tmp; \ - _sfh_key += 2*sizeof (uint16_t); \ - hashv += hashv >> 11; \ - } \ - \ - /* Handle end cases */ \ - switch (_sfh_rem) { \ - case 3: hashv += get16bits (_sfh_key); \ - hashv ^= hashv << 16; \ - hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)] << 18); \ - hashv += hashv >> 11; \ - break; \ - case 2: hashv += get16bits (_sfh_key); \ - hashv ^= hashv << 11; \ - hashv += hashv >> 17; \ - break; \ - case 1: hashv += *_sfh_key; \ - hashv ^= hashv << 10; \ - hashv += hashv >> 1; \ - } \ - \ - /* Force "avalanching" of final 127 bits */ \ - hashv ^= hashv << 3; \ - hashv += hashv >> 5; \ - hashv ^= hashv << 4; \ - hashv += hashv >> 17; \ - hashv ^= hashv << 25; \ - hashv += hashv >> 6; \ - bkt = hashv & (num_bkts-1); \ -} while(0) - -#ifdef HASH_USING_NO_STRICT_ALIASING -/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. - * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. - * MurmurHash uses the faster approach only on CPU's where we know it's safe. - * - * Note the preprocessor built-in defines can be emitted using: - * - * gcc -m64 -dM -E - < /dev/null (on gcc) - * cc -## a.c (where a.c is a simple test file) (Sun Studio) - */ -#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) -#define MUR_GETBLOCK(p,i) p[i] -#else /* non intel */ -#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) -#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) -#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) -#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) -#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) -#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) -#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) -#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) -#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) -#else /* assume little endian non-intel */ -#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) -#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) -#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) -#endif -#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ - (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ - (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ - MUR_ONE_THREE(p)))) -#endif -#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) -#define MUR_FMIX(_h) \ -do { \ - _h ^= _h >> 16; \ - _h *= 0x85ebca6b; \ - _h ^= _h >> 13; \ - _h *= 0xc2b2ae35l; \ - _h ^= _h >> 16; \ -} while(0) - -#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ -do { \ - const uint8_t *_mur_data = (const uint8_t*)(key); \ - const int _mur_nblocks = (keylen) / 4; \ - uint32_t _mur_h1 = 0xf88D5353; \ - uint32_t _mur_c1 = 0xcc9e2d51; \ - uint32_t _mur_c2 = 0x1b873593; \ - uint32_t _mur_k1 = 0; \ - const uint8_t *_mur_tail; \ - const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ - int _mur_i; \ - for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ - _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ - _mur_k1 *= _mur_c1; \ - _mur_k1 = MUR_ROTL32(_mur_k1,15); \ - _mur_k1 *= _mur_c2; \ - \ - _mur_h1 ^= _mur_k1; \ - _mur_h1 = MUR_ROTL32(_mur_h1,13); \ - _mur_h1 = _mur_h1*5+0xe6546b64; \ - } \ - _mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ - _mur_k1=0; \ - switch((keylen) & 3) { \ - case 3: _mur_k1 ^= _mur_tail[2] << 16; \ - case 2: _mur_k1 ^= _mur_tail[1] << 8; \ - case 1: _mur_k1 ^= _mur_tail[0]; \ - _mur_k1 *= _mur_c1; \ - _mur_k1 = MUR_ROTL32(_mur_k1,15); \ - _mur_k1 *= _mur_c2; \ - _mur_h1 ^= _mur_k1; \ - } \ - _mur_h1 ^= (keylen); \ - MUR_FMIX(_mur_h1); \ - hashv = _mur_h1; \ - bkt = hashv & (num_bkts-1); \ -} while(0) -#endif /* HASH_USING_NO_STRICT_ALIASING */ - -/* key comparison function; return 0 if keys equal */ -#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) - -/* iterate over items in a known bucket to find desired item */ -#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ -do { \ - if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ - else out=NULL; \ - while (out) { \ - if ((out)->hh.keylen == keylen_in) { \ - if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \ - } \ - if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \ - else out = NULL; \ - } \ -} while(0) - -/* add an item to a bucket */ -#define HASH_ADD_TO_BKT(head,addhh) \ -do { \ - head.count++; \ - (addhh)->hh_next = head.hh_head; \ - (addhh)->hh_prev = NULL; \ - if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ - (head).hh_head=addhh; \ - if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ - && (addhh)->tbl->noexpand != 1) { \ - HASH_EXPAND_BUCKETS((addhh)->tbl); \ - } \ -} while(0) - -/* remove an item from a given bucket */ -#define HASH_DEL_IN_BKT(hh,head,hh_del) \ - (head).count--; \ - if ((head).hh_head == hh_del) { \ - (head).hh_head = hh_del->hh_next; \ - } \ - if (hh_del->hh_prev) { \ - hh_del->hh_prev->hh_next = hh_del->hh_next; \ - } \ - if (hh_del->hh_next) { \ - hh_del->hh_next->hh_prev = hh_del->hh_prev; \ - } - -/* Bucket expansion has the effect of doubling the number of buckets - * and redistributing the items into the new buckets. Ideally the - * items will distribute more or less evenly into the new buckets - * (the extent to which this is true is a measure of the quality of - * the hash function as it applies to the key domain). - * - * With the items distributed into more buckets, the chain length - * (item count) in each bucket is reduced. Thus by expanding buckets - * the hash keeps a bound on the chain length. This bounded chain - * length is the essence of how a hash provides constant time lookup. - * - * The calculation of tbl->ideal_chain_maxlen below deserves some - * explanation. First, keep in mind that we're calculating the ideal - * maximum chain length based on the *new* (doubled) bucket count. - * In fractions this is just n/b (n=number of items,b=new num buckets). - * Since the ideal chain length is an integer, we want to calculate - * ceil(n/b). We don't depend on floating point arithmetic in this - * hash, so to calculate ceil(n/b) with integers we could write - * - * ceil(n/b) = (n/b) + ((n%b)?1:0) - * - * and in fact a previous version of this hash did just that. - * But now we have improved things a bit by recognizing that b is - * always a power of two. We keep its base 2 log handy (call it lb), - * so now we can write this with a bit shift and logical AND: - * - * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) - * - */ -#define HASH_EXPAND_BUCKETS(tbl) \ -do { \ - unsigned _he_bkt; \ - unsigned _he_bkt_i; \ - struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ - UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ - _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ - 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ - if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ - memset(_he_new_buckets, 0, \ - 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ - tbl->ideal_chain_maxlen = \ - (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ - ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ - tbl->nonideal_items = 0; \ - for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ - { \ - _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ - while (_he_thh) { \ - _he_hh_nxt = _he_thh->hh_next; \ - HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ - _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ - if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ - tbl->nonideal_items++; \ - _he_newbkt->expand_mult = _he_newbkt->count / \ - tbl->ideal_chain_maxlen; \ - } \ - _he_thh->hh_prev = NULL; \ - _he_thh->hh_next = _he_newbkt->hh_head; \ - if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ - _he_thh; \ - _he_newbkt->hh_head = _he_thh; \ - _he_thh = _he_hh_nxt; \ - } \ - } \ - uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ - tbl->num_buckets *= 2; \ - tbl->log2_num_buckets++; \ - tbl->buckets = _he_new_buckets; \ - tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ - (tbl->ineff_expands+1) : 0; \ - if (tbl->ineff_expands > 1) { \ - tbl->noexpand=1; \ - uthash_noexpand_fyi(tbl); \ - } \ - uthash_expand_fyi(tbl); \ -} while(0) - - -/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ -/* Note that HASH_SORT assumes the hash handle name to be hh. - * HASH_SRT was added to allow the hash handle name to be passed in. */ -#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) -#define HASH_SRT(hh,head,cmpfcn) \ -do { \ - unsigned _hs_i; \ - unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ - struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ - if (head) { \ - _hs_insize = 1; \ - _hs_looping = 1; \ - _hs_list = &((head)->hh); \ - while (_hs_looping) { \ - _hs_p = _hs_list; \ - _hs_list = NULL; \ - _hs_tail = NULL; \ - _hs_nmerges = 0; \ - while (_hs_p) { \ - _hs_nmerges++; \ - _hs_q = _hs_p; \ - _hs_psize = 0; \ - for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ - _hs_psize++; \ - _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ - ((void*)((char*)(_hs_q->next) + \ - (head)->hh.tbl->hho)) : NULL); \ - if (! (_hs_q) ) break; \ - } \ - _hs_qsize = _hs_insize; \ - while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ - if (_hs_psize == 0) { \ - _hs_e = _hs_q; \ - _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ - ((void*)((char*)(_hs_q->next) + \ - (head)->hh.tbl->hho)) : NULL); \ - _hs_qsize--; \ - } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ - _hs_e = _hs_p; \ - if (_hs_p){ \ - _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ - ((void*)((char*)(_hs_p->next) + \ - (head)->hh.tbl->hho)) : NULL); \ - } \ - _hs_psize--; \ - } else if (( \ - cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ - DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ - ) <= 0) { \ - _hs_e = _hs_p; \ - if (_hs_p){ \ - _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ - ((void*)((char*)(_hs_p->next) + \ - (head)->hh.tbl->hho)) : NULL); \ - } \ - _hs_psize--; \ - } else { \ - _hs_e = _hs_q; \ - _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ - ((void*)((char*)(_hs_q->next) + \ - (head)->hh.tbl->hho)) : NULL); \ - _hs_qsize--; \ - } \ - if ( _hs_tail ) { \ - _hs_tail->next = ((_hs_e) ? \ - ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ - } else { \ - _hs_list = _hs_e; \ - } \ - if (_hs_e) { \ - _hs_e->prev = ((_hs_tail) ? \ - ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ - } \ - _hs_tail = _hs_e; \ - } \ - _hs_p = _hs_q; \ - } \ - if (_hs_tail){ \ - _hs_tail->next = NULL; \ - } \ - if ( _hs_nmerges <= 1 ) { \ - _hs_looping=0; \ - (head)->hh.tbl->tail = _hs_tail; \ - DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ - } \ - _hs_insize *= 2; \ - } \ - HASH_FSCK(hh,head); \ - } \ -} while (0) - -/* This function selects items from one hash into another hash. - * The end result is that the selected items have dual presence - * in both hashes. There is no copy of the items made; rather - * they are added into the new hash through a secondary hash - * hash handle that must be present in the structure. */ -#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ -do { \ - unsigned _src_bkt, _dst_bkt; \ - void *_last_elt=NULL, *_elt; \ - UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ - ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ - if (src) { \ - for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ - for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ - _src_hh; \ - _src_hh = _src_hh->hh_next) { \ - _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ - if (cond(_elt)) { \ - _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ - _dst_hh->key = _src_hh->key; \ - _dst_hh->keylen = _src_hh->keylen; \ - _dst_hh->hashv = _src_hh->hashv; \ - _dst_hh->prev = _last_elt; \ - _dst_hh->next = NULL; \ - if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ - if (!dst) { \ - DECLTYPE_ASSIGN(dst,_elt); \ - HASH_MAKE_TABLE(hh_dst,dst); \ - } else { \ - _dst_hh->tbl = (dst)->hh_dst.tbl; \ - } \ - HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ - HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ - (dst)->hh_dst.tbl->num_items++; \ - _last_elt = _elt; \ - _last_elt_hh = _dst_hh; \ - } \ - } \ - } \ - } \ - HASH_FSCK(hh_dst,dst); \ -} while (0) - -#define HASH_CLEAR(hh,head) \ -do { \ - if (head) { \ - uthash_free((head)->hh.tbl->buckets, \ - (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ - HASH_BLOOM_FREE((head)->hh.tbl); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - (head)=NULL; \ - } \ -} while(0) - -#define HASH_OVERHEAD(hh,head) \ - ((head) ? ( \ - (size_t)((((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ - ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ - (sizeof(UT_hash_table)) + \ - (HASH_BLOOM_BYTELEN)))) : 0) - -#ifdef NO_DECLTYPE -#define HASH_ITER(hh,head,el,tmp) \ -for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ - el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) -#else -#define HASH_ITER(hh,head,el,tmp) \ -for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ - el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) -#endif - -/* obtain a count of items in the hash */ -#define HASH_COUNT(head) HASH_CNT(hh,head) -#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) - -typedef struct UT_hash_bucket { - struct UT_hash_handle *hh_head; - unsigned count; - - /* expand_mult is normally set to 0. In this situation, the max chain length - * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If - * the bucket's chain exceeds this length, bucket expansion is triggered). - * However, setting expand_mult to a non-zero value delays bucket expansion - * (that would be triggered by additions to this particular bucket) - * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. - * (The multiplier is simply expand_mult+1). The whole idea of this - * multiplier is to reduce bucket expansions, since they are expensive, in - * situations where we know that a particular bucket tends to be overused. - * It is better to let its chain length grow to a longer yet-still-bounded - * value, than to do an O(n) bucket expansion too often. - */ - unsigned expand_mult; - -} UT_hash_bucket; - -/* random signature used only to find hash tables in external analysis */ -#define HASH_SIGNATURE 0xa0111fe1 -#define HASH_BLOOM_SIGNATURE 0xb12220f2 - -typedef struct UT_hash_table { - UT_hash_bucket *buckets; - unsigned num_buckets, log2_num_buckets; - unsigned num_items; - struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ - ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ - - /* in an ideal situation (all buckets used equally), no bucket would have - * more than ceil(#items/#buckets) items. that's the ideal chain length. */ - unsigned ideal_chain_maxlen; - - /* nonideal_items is the number of items in the hash whose chain position - * exceeds the ideal chain maxlen. these items pay the penalty for an uneven - * hash distribution; reaching them in a chain traversal takes >ideal steps */ - unsigned nonideal_items; - - /* ineffective expands occur when a bucket doubling was performed, but - * afterward, more than half the items in the hash had nonideal chain - * positions. If this happens on two consecutive expansions we inhibit any - * further expansion, as it's not helping; this happens when the hash - * function isn't a good fit for the key domain. When expansion is inhibited - * the hash will still work, albeit no longer in constant time. */ - unsigned ineff_expands, noexpand; - - uint32_t signature; /* used only to find hash tables in external analysis */ -#ifdef HASH_BLOOM - uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ - uint8_t *bloom_bv; - char bloom_nbits; -#endif - -} UT_hash_table; - -typedef struct UT_hash_handle { - struct UT_hash_table *tbl; - void *prev; /* prev element in app order */ - void *next; /* next element in app order */ - struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ - struct UT_hash_handle *hh_next; /* next hh in bucket order */ - void *key; /* ptr to enclosing struct's key */ - unsigned keylen; /* enclosing struct's key len */ - unsigned hashv; /* result of hash-fcn(key) */ -} UT_hash_handle; - -#endif /* UTHASH_H */ diff --git a/gomspace/libutil/include/gs/uthash/utlist.h b/gomspace/libutil/include/gs/uthash/utlist.h deleted file mode 100644 index b5f3f04c..00000000 --- a/gomspace/libutil/include/gs/uthash/utlist.h +++ /dev/null @@ -1,757 +0,0 @@ -/* -Copyright (c) 2007-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -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. -*/ - -#ifndef UTLIST_H -#define UTLIST_H - -#define UTLIST_VERSION 1.9.9 - -#include - -/* - * This file contains macros to manipulate singly and doubly-linked lists. - * - * 1. LL_ macros: singly-linked lists. - * 2. DL_ macros: doubly-linked lists. - * 3. CDL_ macros: circular doubly-linked lists. - * - * To use singly-linked lists, your structure must have a "next" pointer. - * To use doubly-linked lists, your structure must "prev" and "next" pointers. - * Either way, the pointer to the head of the list must be initialized to NULL. - * - * ----------------.EXAMPLE ------------------------- - * struct item { - * int id; - * struct item *prev, *next; - * } - * - * struct item *list = NULL: - * - * int main() { - * struct item *item; - * ... allocate and populate item ... - * DL_APPEND(list, item); - * } - * -------------------------------------------------- - * - * For doubly-linked lists, the append and delete macros are O(1) - * For singly-linked lists, append and delete are O(n) but prepend is O(1) - * The sort macro is O(n log(n)) for all types of single/double/circular lists. - */ - -/* These macros use decltype or the earlier __typeof GNU extension. - As decltype is only available in newer compilers (VS2010 or gcc 4.3+ - when compiling c++ code), this code uses whatever method is needed - or, for VS2008 where neither is available, uses casting workarounds. */ -#ifdef _MSC_VER /* MS compiler */ -#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ -#define LDECLTYPE(x) decltype(x) -#else /* VS2008 or older (or VS2010 in C mode) */ -#define NO_DECLTYPE -#define LDECLTYPE(x) char* -#endif -#elif defined(__ICCARM__) -#define NO_DECLTYPE -#define LDECLTYPE(x) char* -#else /* GNU, Sun and other compilers */ -#define LDECLTYPE(x) __typeof(x) -#endif - -/* for VS2008 we use some workarounds to get around the lack of decltype, - * namely, we always reassign our tmp variable to the list head if we need - * to dereference its prev/next pointers, and save/restore the real head.*/ -#ifdef NO_DECLTYPE -#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } -#define _NEXT(elt,list,next) ((char*)((list)->next)) -#define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } -/* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */ -#define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } -#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } -#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } -#else -#define _SV(elt,list) -#define _NEXT(elt,list,next) ((elt)->next) -#define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to) -/* #define _PREV(elt,list,prev) ((elt)->prev) */ -#define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) -#define _RS(list) -#define _CASTASGN(a,b) (a)=(b) -#endif - -/****************************************************************************** - * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * - * Unwieldy variable names used here to avoid shadowing passed-in variables. * - *****************************************************************************/ -#define LL_SORT(list, cmp) \ - LL_SORT2(list, cmp, next) - -#define LL_SORT2(list, cmp, next) \ -do { \ - LDECLTYPE(list) _ls_p; \ - LDECLTYPE(list) _ls_q; \ - LDECLTYPE(list) _ls_e; \ - LDECLTYPE(list) _ls_tail; \ - int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ - if (list) { \ - _ls_insize = 1; \ - _ls_looping = 1; \ - while (_ls_looping) { \ - _CASTASGN(_ls_p,list); \ - list = NULL; \ - _ls_tail = NULL; \ - _ls_nmerges = 0; \ - while (_ls_p) { \ - _ls_nmerges++; \ - _ls_q = _ls_p; \ - _ls_psize = 0; \ - for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ - _ls_psize++; \ - _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ - if (!_ls_q) break; \ - } \ - _ls_qsize = _ls_insize; \ - while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ - if (_ls_psize == 0) { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ - } else if (_ls_qsize == 0 || !_ls_q) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ - } else if (cmp(_ls_p,_ls_q) <= 0) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ - } else { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ - } \ - if (_ls_tail) { \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ - } else { \ - _CASTASGN(list,_ls_e); \ - } \ - _ls_tail = _ls_e; \ - } \ - _ls_p = _ls_q; \ - } \ - if (_ls_tail) { \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ - } \ - if (_ls_nmerges <= 1) { \ - _ls_looping=0; \ - } \ - _ls_insize *= 2; \ - } \ - } \ -} while (0) - - -#define DL_SORT(list, cmp) \ - DL_SORT2(list, cmp, prev, next) - -#define DL_SORT2(list, cmp, prev, next) \ -do { \ - LDECLTYPE(list) _ls_p; \ - LDECLTYPE(list) _ls_q; \ - LDECLTYPE(list) _ls_e; \ - LDECLTYPE(list) _ls_tail; \ - int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ - if (list) { \ - _ls_insize = 1; \ - _ls_looping = 1; \ - while (_ls_looping) { \ - _CASTASGN(_ls_p,list); \ - list = NULL; \ - _ls_tail = NULL; \ - _ls_nmerges = 0; \ - while (_ls_p) { \ - _ls_nmerges++; \ - _ls_q = _ls_p; \ - _ls_psize = 0; \ - for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ - _ls_psize++; \ - _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ - if (!_ls_q) break; \ - } \ - _ls_qsize = _ls_insize; \ - while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ - if (_ls_psize == 0) { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ - } else if (_ls_qsize == 0 || !_ls_q) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ - } else if (cmp(_ls_p,_ls_q) <= 0) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ - } else { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ - } \ - if (_ls_tail) { \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ - } else { \ - _CASTASGN(list,_ls_e); \ - } \ - _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ - _ls_tail = _ls_e; \ - } \ - _ls_p = _ls_q; \ - } \ - _CASTASGN(list->prev, _ls_tail); \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ - if (_ls_nmerges <= 1) { \ - _ls_looping=0; \ - } \ - _ls_insize *= 2; \ - } \ - } \ -} while (0) - -#define CDL_SORT(list, cmp) \ - CDL_SORT2(list, cmp, prev, next) - -#define CDL_SORT2(list, cmp, prev, next) \ -do { \ - LDECLTYPE(list) _ls_p; \ - LDECLTYPE(list) _ls_q; \ - LDECLTYPE(list) _ls_e; \ - LDECLTYPE(list) _ls_tail; \ - LDECLTYPE(list) _ls_oldhead; \ - LDECLTYPE(list) _tmp; \ - int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ - if (list) { \ - _ls_insize = 1; \ - _ls_looping = 1; \ - while (_ls_looping) { \ - _CASTASGN(_ls_p,list); \ - _CASTASGN(_ls_oldhead,list); \ - list = NULL; \ - _ls_tail = NULL; \ - _ls_nmerges = 0; \ - while (_ls_p) { \ - _ls_nmerges++; \ - _ls_q = _ls_p; \ - _ls_psize = 0; \ - for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ - _ls_psize++; \ - _SV(_ls_q,list); \ - if (_NEXT(_ls_q,list,next) == _ls_oldhead) { \ - _ls_q = NULL; \ - } else { \ - _ls_q = _NEXT(_ls_q,list,next); \ - } \ - _RS(list); \ - if (!_ls_q) break; \ - } \ - _ls_qsize = _ls_insize; \ - while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ - if (_ls_psize == 0) { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ - if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ - } else if (_ls_qsize == 0 || !_ls_q) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ - if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ - } else if (cmp(_ls_p,_ls_q) <= 0) { \ - _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ - _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ - if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ - } else { \ - _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ - _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ - if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ - } \ - if (_ls_tail) { \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ - } else { \ - _CASTASGN(list,_ls_e); \ - } \ - _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ - _ls_tail = _ls_e; \ - } \ - _ls_p = _ls_q; \ - } \ - _CASTASGN(list->prev,_ls_tail); \ - _CASTASGN(_tmp,list); \ - _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list); \ - if (_ls_nmerges <= 1) { \ - _ls_looping=0; \ - } \ - _ls_insize *= 2; \ - } \ - } \ -} while (0) - -/****************************************************************************** - * singly linked list macros (non-circular) * - *****************************************************************************/ -#define LL_PREPEND(head,add) \ - LL_PREPEND2(head,add,next) - -#define LL_PREPEND2(head,add,next) \ -do { \ - (add)->next = head; \ - head = add; \ -} while (0) - -#define LL_CONCAT(head1,head2) \ - LL_CONCAT2(head1,head2,next) - -#define LL_CONCAT2(head1,head2,next) \ -do { \ - LDECLTYPE(head1) _tmp; \ - if (head1) { \ - _tmp = head1; \ - while (_tmp->next) { _tmp = _tmp->next; } \ - _tmp->next=(head2); \ - } else { \ - (head1)=(head2); \ - } \ -} while (0) - -#define LL_APPEND(head,add) \ - LL_APPEND2(head,add,next) - -#define LL_APPEND2(head,add,next) \ -do { \ - LDECLTYPE(head) _tmp; \ - (add)->next=NULL; \ - if (head) { \ - _tmp = head; \ - while (_tmp->next) { _tmp = _tmp->next; } \ - _tmp->next=(add); \ - } else { \ - (head)=(add); \ - } \ -} while (0) - -#define LL_DELETE(head,del) \ - LL_DELETE2(head,del,next) - -#define LL_DELETE2(head,del,next) \ -do { \ - LDECLTYPE(head) _tmp; \ - if ((head) == (del)) { \ - (head)=(head)->next; \ - } else { \ - _tmp = head; \ - while (_tmp->next && (_tmp->next != (del))) { \ - _tmp = _tmp->next; \ - } \ - if (_tmp->next) { \ - _tmp->next = ((del)->next); \ - } \ - } \ -} while (0) - -/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ -#define LL_APPEND_VS2008(head,add) \ - LL_APPEND2_VS2008(head,add,next) - -#define LL_APPEND2_VS2008(head,add,next) \ -do { \ - if (head) { \ - (add)->next = head; /* use add->next as a temp variable */ \ - while ((add)->next->next) { (add)->next = (add)->next->next; } \ - (add)->next->next=(add); \ - } else { \ - (head)=(add); \ - } \ - (add)->next=NULL; \ -} while (0) - -#define LL_DELETE_VS2008(head,del) \ - LL_DELETE2_VS2008(head,del,next) - -#define LL_DELETE2_VS2008(head,del,next) \ -do { \ - if ((head) == (del)) { \ - (head)=(head)->next; \ - } else { \ - char *_tmp = (char*)(head); \ - while ((head)->next && ((head)->next != (del))) { \ - head = (head)->next; \ - } \ - if ((head)->next) { \ - (head)->next = ((del)->next); \ - } \ - { \ - char **_head_alias = (char**)&(head); \ - *_head_alias = _tmp; \ - } \ - } \ -} while (0) -#ifdef NO_DECLTYPE -#undef LL_APPEND -#define LL_APPEND LL_APPEND_VS2008 -#undef LL_DELETE -#define LL_DELETE LL_DELETE_VS2008 -#undef LL_DELETE2 -#define LL_DELETE2 LL_DELETE2_VS2008 -#undef LL_APPEND2 -#define LL_APPEND2 LL_APPEND2_VS2008 -#undef LL_CONCAT /* no LL_CONCAT_VS2008 */ -#undef DL_CONCAT /* no DL_CONCAT_VS2008 */ -#endif -/* end VS2008 replacements */ - -#define LL_COUNT(head,el,counter) \ - LL_COUNT2(head,el,counter,next) \ - -#define LL_COUNT2(head,el,counter,next) \ -{ \ - counter = 0; \ - LL_FOREACH2(head,el,next){ ++counter; } \ -} - -#define LL_FOREACH(head,el) \ - LL_FOREACH2(head,el,next) - -#define LL_FOREACH2(head,el,next) \ - for(el=head;el;el=(el)->next) - -#define LL_FOREACH_SAFE(head,el,tmp) \ - LL_FOREACH_SAFE2(head,el,tmp,next) - -#define LL_FOREACH_SAFE2(head,el,tmp,next) \ - for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) - -#define LL_SEARCH_SCALAR(head,out,field,val) \ - LL_SEARCH_SCALAR2(head,out,field,val,next) - -#define LL_SEARCH_SCALAR2(head,out,field,val,next) \ -do { \ - LL_FOREACH2(head,out,next) { \ - if ((out)->field == (val)) break; \ - } \ -} while(0) - -#define LL_SEARCH(head,out,elt,cmp) \ - LL_SEARCH2(head,out,elt,cmp,next) - -#define LL_SEARCH2(head,out,elt,cmp,next) \ -do { \ - LL_FOREACH2(head,out,next) { \ - if ((cmp(out,elt))==0) break; \ - } \ -} while(0) - -#define LL_REPLACE_ELEM(head, el, add) \ -do { \ - LDECLTYPE(head) _tmp; \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ - (add)->next = (el)->next; \ - if ((head) == (el)) { \ - (head) = (add); \ - } else { \ - _tmp = head; \ - while (_tmp->next && (_tmp->next != (el))) { \ - _tmp = _tmp->next; \ - } \ - if (_tmp->next) { \ - _tmp->next = (add); \ - } \ - } \ -} while (0) - -#define LL_PREPEND_ELEM(head, el, add) \ -do { \ - LDECLTYPE(head) _tmp; \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ - (add)->next = (el); \ - if ((head) == (el)) { \ - (head) = (add); \ - } else { \ - _tmp = head; \ - while (_tmp->next && (_tmp->next != (el))) { \ - _tmp = _tmp->next; \ - } \ - if (_tmp->next) { \ - _tmp->next = (add); \ - } \ - } \ -} while (0) \ - - -/****************************************************************************** - * doubly linked list macros (non-circular) * - *****************************************************************************/ -#define DL_PREPEND(head,add) \ - DL_PREPEND2(head,add,prev,next) - -#define DL_PREPEND2(head,add,prev,next) \ -do { \ - (add)->next = head; \ - if (head) { \ - (add)->prev = (head)->prev; \ - (head)->prev = (add); \ - } else { \ - (add)->prev = (add); \ - } \ - (head) = (add); \ -} while (0) - -#define DL_APPEND(head,add) \ - DL_APPEND2(head,add,prev,next) - -#define DL_APPEND2(head,add,prev,next) \ -do { \ - if (head) { \ - (add)->prev = (head)->prev; \ - (head)->prev->next = (add); \ - (head)->prev = (add); \ - (add)->next = NULL; \ - } else { \ - (head)=(add); \ - (head)->prev = (head); \ - (head)->next = NULL; \ - } \ -} while (0) - -#define DL_CONCAT(head1,head2) \ - DL_CONCAT2(head1,head2,prev,next) - -#define DL_CONCAT2(head1,head2,prev,next) \ -do { \ - LDECLTYPE(head1) _tmp; \ - if (head2) { \ - if (head1) { \ - _tmp = (head2)->prev; \ - (head2)->prev = (head1)->prev; \ - (head1)->prev->next = (head2); \ - (head1)->prev = _tmp; \ - } else { \ - (head1)=(head2); \ - } \ - } \ -} while (0) - -#define DL_DELETE(head,del) \ - DL_DELETE2(head,del,prev,next) - -#define DL_DELETE2(head,del,prev,next) \ -do { \ - assert((del)->prev != NULL); \ - if ((del)->prev == (del)) { \ - (head)=NULL; \ - } else if ((del)==(head)) { \ - (del)->next->prev = (del)->prev; \ - (head) = (del)->next; \ - } else { \ - (del)->prev->next = (del)->next; \ - if ((del)->next) { \ - (del)->next->prev = (del)->prev; \ - } else { \ - (head)->prev = (del)->prev; \ - } \ - } \ -} while (0) - -#define DL_COUNT(head,el,counter) \ - DL_COUNT2(head,el,counter,next) \ - -#define DL_COUNT2(head,el,counter,next) \ -{ \ - counter = 0; \ - DL_FOREACH2(head,el,next){ ++counter; } \ -} - -#define DL_FOREACH(head,el) \ - DL_FOREACH2(head,el,next) - -#define DL_FOREACH2(head,el,next) \ - for(el=head;el;el=(el)->next) - -/* this version is safe for deleting the elements during iteration */ -#define DL_FOREACH_SAFE(head,el,tmp) \ - DL_FOREACH_SAFE2(head,el,tmp,next) - -#define DL_FOREACH_SAFE2(head,el,tmp,next) \ - for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) - -/* these are identical to their singly-linked list counterparts */ -#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR -#define DL_SEARCH LL_SEARCH -#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 -#define DL_SEARCH2 LL_SEARCH2 - -#define DL_REPLACE_ELEM(head, el, add) \ -do { \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ - if ((head) == (el)) { \ - (head) = (add); \ - (add)->next = (el)->next; \ - if ((el)->next == NULL) { \ - (add)->prev = (add); \ - } else { \ - (add)->prev = (el)->prev; \ - (add)->next->prev = (add); \ - } \ - } else { \ - (add)->next = (el)->next; \ - (add)->prev = (el)->prev; \ - (add)->prev->next = (add); \ - if ((el)->next == NULL) { \ - (head)->prev = (add); \ - } else { \ - (add)->next->prev = (add); \ - } \ - } \ -} while (0) - -#define DL_PREPEND_ELEM(head, el, add) \ -do { \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ - (add)->next = (el); \ - (add)->prev = (el)->prev; \ - (el)->prev = (add); \ - if ((head) == (el)) { \ - (head) = (add); \ - } else { \ - (add)->prev->next = (add); \ - } \ -} while (0) \ - - -/****************************************************************************** - * circular doubly linked list macros * - *****************************************************************************/ -#define CDL_PREPEND(head,add) \ - CDL_PREPEND2(head,add,prev,next) - -#define CDL_PREPEND2(head,add,prev,next) \ -do { \ - if (head) { \ - (add)->prev = (head)->prev; \ - (add)->next = (head); \ - (head)->prev = (add); \ - (add)->prev->next = (add); \ - } else { \ - (add)->prev = (add); \ - (add)->next = (add); \ - } \ -(head)=(add); \ -} while (0) - -#define CDL_DELETE(head,del) \ - CDL_DELETE2(head,del,prev,next) - -#define CDL_DELETE2(head,del,prev,next) \ -do { \ - if ( ((head)==(del)) && ((head)->next == (head))) { \ - (head) = 0L; \ - } else { \ - (del)->next->prev = (del)->prev; \ - (del)->prev->next = (del)->next; \ - if ((del) == (head)) (head)=(del)->next; \ - } \ -} while (0) - -#define CDL_COUNT(head,el,counter) \ - CDL_COUNT2(head,el,counter,next) \ - -#define CDL_COUNT2(head, el, counter,next) \ -{ \ - counter = 0; \ - CDL_FOREACH2(head,el,next){ ++counter; } \ -} - -#define CDL_FOREACH(head,el) \ - CDL_FOREACH2(head,el,next) - -#define CDL_FOREACH2(head,el,next) \ - for(el=head;el;el=((el)->next==head ? 0L : (el)->next)) - -#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ - CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) - -#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \ - for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ - (el) && ((tmp2)=(el)->next, 1); \ - ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) - -#define CDL_SEARCH_SCALAR(head,out,field,val) \ - CDL_SEARCH_SCALAR2(head,out,field,val,next) - -#define CDL_SEARCH_SCALAR2(head,out,field,val,next) \ -do { \ - CDL_FOREACH2(head,out,next) { \ - if ((out)->field == (val)) break; \ - } \ -} while(0) - -#define CDL_SEARCH(head,out,elt,cmp) \ - CDL_SEARCH2(head,out,elt,cmp,next) - -#define CDL_SEARCH2(head,out,elt,cmp,next) \ -do { \ - CDL_FOREACH2(head,out,next) { \ - if ((cmp(out,elt))==0) break; \ - } \ -} while(0) - -#define CDL_REPLACE_ELEM(head, el, add) \ -do { \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ - if ((el)->next == (el)) { \ - (add)->next = (add); \ - (add)->prev = (add); \ - (head) = (add); \ - } else { \ - (add)->next = (el)->next; \ - (add)->prev = (el)->prev; \ - (add)->next->prev = (add); \ - (add)->prev->next = (add); \ - if ((head) == (el)) { \ - (head) = (add); \ - } \ - } \ -} while (0) - -#define CDL_PREPEND_ELEM(head, el, add) \ -do { \ - assert(head != NULL); \ - assert(el != NULL); \ - assert(add != NULL); \ - (add)->next = (el); \ - (add)->prev = (el)->prev; \ - (el)->prev = (add); \ - (add)->prev->next = (add); \ - if ((head) == (el)) { \ - (head) = (add); \ - } \ -} while (0) \ - -#endif /* UTLIST_H */ - diff --git a/gomspace/libutil/include/gs/uthash/utstring.h b/gomspace/libutil/include/gs/uthash/utstring.h deleted file mode 100644 index 867442c8..00000000 --- a/gomspace/libutil/include/gs/uthash/utstring.h +++ /dev/null @@ -1,393 +0,0 @@ -/* -Copyright (c) 2008-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -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. -*/ - -/* a dynamic string implementation using macros - */ -#ifndef UTSTRING_H -#define UTSTRING_H - -#define UTSTRING_VERSION 1.9.9 - -#ifdef __GNUC__ -#define _UNUSED_ __attribute__ ((__unused__)) -#else -#define _UNUSED_ -#endif - -#include -#include -#include -#include -#define oom() exit(-1) - -typedef struct { - char *d; - size_t n; /* allocd size */ - size_t i; /* index of first unused byte */ -} UT_string; - -#define utstring_reserve(s,amt) \ -do { \ - if (((s)->n - (s)->i) < (size_t)(amt)) { \ - (s)->d = (char*)realloc((s)->d, (s)->n + amt); \ - if ((s)->d == NULL) oom(); \ - (s)->n += amt; \ - } \ -} while(0) - -#define utstring_init(s) \ -do { \ - (s)->n = 0; (s)->i = 0; (s)->d = NULL; \ - utstring_reserve(s,100); \ - (s)->d[0] = '\0'; \ -} while(0) - -#define utstring_done(s) \ -do { \ - if ((s)->d != NULL) free((s)->d); \ - (s)->n = 0; \ -} while(0) - -#define utstring_free(s) \ -do { \ - utstring_done(s); \ - free(s); \ -} while(0) - -#define utstring_new(s) \ -do { \ - s = (UT_string*)calloc(sizeof(UT_string),1); \ - if (!s) oom(); \ - utstring_init(s); \ -} while(0) - -#define utstring_renew(s) \ -do { \ - if (s) { \ - utstring_clear(s); \ - } else { \ - utstring_new(s); \ - } \ -} while(0) - -#define utstring_clear(s) \ -do { \ - (s)->i = 0; \ - (s)->d[0] = '\0'; \ -} while(0) - -#define utstring_bincpy(s,b,l) \ -do { \ - utstring_reserve((s),(l)+1); \ - if (l) memcpy(&(s)->d[(s)->i], b, l); \ - (s)->i += l; \ - (s)->d[(s)->i]='\0'; \ -} while(0) - -#define utstring_concat(dst,src) \ -do { \ - utstring_reserve((dst),((src)->i)+1); \ - if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \ - (dst)->i += (src)->i; \ - (dst)->d[(dst)->i]='\0'; \ -} while(0) - -#define utstring_len(s) ((unsigned)((s)->i)) - -#define utstring_body(s) ((s)->d) - -_UNUSED_ static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) { - int n; - va_list cp; - while (1) { -#ifdef _WIN32 - cp = ap; -#else - va_copy(cp, ap); -#endif - n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp); - va_end(cp); - - if ((n > -1) && ((size_t) n < (s->n-s->i))) { - s->i += n; - return; - } - - /* Else try again with more space. */ - if (n > -1) utstring_reserve(s,n+1); /* exact */ - else utstring_reserve(s,(s->n)*2); /* 2x */ - } -} -#ifdef __GNUC__ -/* support printf format checking (2=the format string, 3=start of varargs) */ -static void utstring_printf(UT_string *s, const char *fmt, ...) - __attribute__ (( format( printf, 2, 3) )); -#endif -_UNUSED_ static void utstring_printf(UT_string *s, const char *fmt, ...) { - va_list ap; - va_start(ap,fmt); - utstring_printf_va(s,fmt,ap); - va_end(ap); -} - -/******************************************************************************* - * begin substring search functions * - ******************************************************************************/ -/* Build KMP table from left to right. */ -_UNUSED_ static void _utstring_BuildTable( - const char *P_Needle, - size_t P_NeedleLen, - long *P_KMP_Table) -{ - long i, j; - - i = 0; - j = i - 1; - P_KMP_Table[i] = j; - while (i < (long) P_NeedleLen) - { - while ( (j > -1) && (P_Needle[i] != P_Needle[j]) ) - { - j = P_KMP_Table[j]; - } - i++; - j++; - if (i < (long) P_NeedleLen) - { - if (P_Needle[i] == P_Needle[j]) - { - P_KMP_Table[i] = P_KMP_Table[j]; - } - else - { - P_KMP_Table[i] = j; - } - } - else - { - P_KMP_Table[i] = j; - } - } - - return; -} - - -/* Build KMP table from right to left. */ -_UNUSED_ static void _utstring_BuildTableR( - const char *P_Needle, - size_t P_NeedleLen, - long *P_KMP_Table) -{ - long i, j; - - i = P_NeedleLen - 1; - j = i + 1; - P_KMP_Table[i + 1] = j; - while (i >= 0) - { - while ( (j < (long) P_NeedleLen) && (P_Needle[i] != P_Needle[j]) ) - { - j = P_KMP_Table[j + 1]; - } - i--; - j--; - if (i >= 0) - { - if (P_Needle[i] == P_Needle[j]) - { - P_KMP_Table[i + 1] = P_KMP_Table[j + 1]; - } - else - { - P_KMP_Table[i + 1] = j; - } - } - else - { - P_KMP_Table[i + 1] = j; - } - } - - return; -} - - -/* Search data from left to right. ( Multiple search mode. ) */ -_UNUSED_ static long _utstring_find( - const char *P_Haystack, - size_t P_HaystackLen, - const char *P_Needle, - size_t P_NeedleLen, - long *P_KMP_Table) -{ - long i, j; - long V_FindPosition = -1; - - /* Search from left to right. */ - i = j = 0; - while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) ) - { - while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) ) - { - i = P_KMP_Table[i]; - } - i++; - j++; - if (i >= (int)P_NeedleLen) - { - /* Found. */ - V_FindPosition = j - i; - break; - } - } - - return V_FindPosition; -} - - -/* Search data from right to left. ( Multiple search mode. ) */ -_UNUSED_ static long _utstring_findR( - const char *P_Haystack, - size_t P_HaystackLen, - const char *P_Needle, - size_t P_NeedleLen, - long *P_KMP_Table) -{ - long i, j; - long V_FindPosition = -1; - - /* Search from right to left. */ - j = (P_HaystackLen - 1); - i = (P_NeedleLen - 1); - while ( (j >= 0) && (j >= i) ) - { - while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) ) - { - i = P_KMP_Table[i + 1]; - } - i--; - j--; - if (i < 0) - { - /* Found. */ - V_FindPosition = j + 1; - break; - } - } - - return V_FindPosition; -} - - -/* Search data from left to right. ( One time search mode. ) */ -_UNUSED_ static long utstring_find( - UT_string *s, - long P_StartPosition, /* Start from 0. -1 means last position. */ - const char *P_Needle, - size_t P_NeedleLen) -{ - long V_StartPosition; - long V_HaystackLen; - long *V_KMP_Table; - long V_FindPosition = -1; - - if (P_StartPosition < 0) - { - V_StartPosition = s->i + P_StartPosition; - } - else - { - V_StartPosition = P_StartPosition; - } - V_HaystackLen = s->i - V_StartPosition; - if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) - { - V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); - if (V_KMP_Table != NULL) - { - _utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table); - - V_FindPosition = _utstring_find(s->d + V_StartPosition, - V_HaystackLen, - P_Needle, - P_NeedleLen, - V_KMP_Table); - if (V_FindPosition >= 0) - { - V_FindPosition += V_StartPosition; - } - - free(V_KMP_Table); - } - } - - return V_FindPosition; -} - - -/* Search data from right to left. ( One time search mode. ) */ -_UNUSED_ static long utstring_findR( - UT_string *s, - long P_StartPosition, /* Start from 0. -1 means last position. */ - const char *P_Needle, - size_t P_NeedleLen) -{ - long V_StartPosition; - long V_HaystackLen; - long *V_KMP_Table; - long V_FindPosition = -1; - - if (P_StartPosition < 0) - { - V_StartPosition = s->i + P_StartPosition; - } - else - { - V_StartPosition = P_StartPosition; - } - V_HaystackLen = V_StartPosition + 1; - if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) - { - V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); - if (V_KMP_Table != NULL) - { - _utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table); - - V_FindPosition = _utstring_findR(s->d, - V_HaystackLen, - P_Needle, - P_NeedleLen, - V_KMP_Table); - - free(V_KMP_Table); - } - } - - return V_FindPosition; -} -/******************************************************************************* - * end substring search functions * - ******************************************************************************/ - -#endif /* UTSTRING_H */ diff --git a/gomspace/libutil/include/gs/util/base16.h b/gomspace/libutil/include/gs/util/base16.h deleted file mode 100644 index 0fddccc5..00000000 --- a/gomspace/libutil/include/gs/util/base16.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef GS_UTIL_BASE16_H -#define GS_UTIL_BASE16_H -/* - * Copyright (C) 2010 Michael Brown . - * - * This program 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 2 of the - * License, or any later version. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/** - @file - - Encoding and decoding base16 arrays to and from strings. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Calculate length of base16-encoded data - - @param raw_len Raw data length - @return Encoded string length (excluding NUL) -*/ -static inline size_t base16_encoded_len(size_t raw_len) -{ - return (2 * raw_len); -} - -/** - Calculate maximum length of base16-decoded string - @param encoded Encoded string - @return Maximum length of raw data -*/ -static inline size_t base16_decoded_max_len(const char *encoded) -{ - return ((strlen(encoded) + 1) / 2); -} - -/** - Base16-encode data - - The buffer must be the correct length for the encoded string. Use - something like - - char buf[ base16_encoded_len ( len ) + 1 ]; - - (the +1 is for the terminating NUL) to provide a buffer of the - correct size. - - @param raw Raw data - @param len Length of raw data - @param encoded Buffer for encoded string -*/ -void base16_encode(const uint8_t *raw, size_t len, char *encoded); - -/** - Base16-decode data - - The buffer must be large enough to contain the decoded data. Use - something like - - char buf[ base16_decoded_max_len ( encoded ) ]; - - to provide a buffer of the correct size. - - @param encoded Encoded string - @param raw Raw data - @return Length of raw data, or negative error (gs_error_t) -*/ -int base16_decode(const char *encoded, uint8_t *raw); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/bytebuffer.h b/gomspace/libutil/include/gs/util/bytebuffer.h deleted file mode 100644 index ad727e01..00000000 --- a/gomspace/libutil/include/gs/util/bytebuffer.h +++ /dev/null @@ -1,173 +0,0 @@ -#ifndef GS_UTIL_BYTEBUFFER_h -#define GS_UTIL_BYTEBUFFER_h -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Byte buffer provides formatting/serialzing of text/binary data. The buffer keeps track of used space, and prevents overrun. - - The current buffer state can be checked using gs_bytebuffer_state(). - - @dontinclude bytebuffer/bytebuffer_test.c - @skip TEST_gs_bytebuffer_use_case - @until } -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Buffer handle. - Never access handle members directly. -*/ -typedef struct { - /** - Internal: Pointer to user supplied buffer. - @see gs_bytebuffer_init() - */ - uint8_t * buffer; - /** - Internal: Size of user supplied buffer. - @see gs_bytebuffer_init() - */ - size_t size; - /** - Internal: Number of bytes used. - */ - size_t used; - /** - Internal: FUTURE: Committed used - */ - size_t committed_used; - /** - Internal: flags to keep track of buffer state. - */ - uint8_t flags; -} gs_bytebuffer_t; - -/** - Initialize buffer. - - @param[in] bb handle. - @param[in] buffer user supplied buffer of \a buffer_size size (bytes). If NULL, the buffer will keep track of required bytes. - @param[in] buffer_size size of \a buffer. - @return_gs_error_t -*/ -gs_error_t gs_bytebuffer_init(gs_bytebuffer_t * bb, void * buffer, size_t buffer_size); - -/** - Insert data using vprintf. - - @param[in] bb handle. - @param[in] format printf syntax for formatting data - @param[in] ap variable argument list. -*/ -void gs_bytebuffer_vprintf(gs_bytebuffer_t * bb, const char * format, va_list ap); - -/** - Insert data using printf. - - @param[in] bb handle. - @param[in] format printf syntax for formatting data -*/ -void gs_bytebuffer_printf(gs_bytebuffer_t * bb, const char * format, ...) __attribute__ ((format (__printf__, 2, 3))); - -/** - Append data to buffer. - - @param[in] bb handle. - @param[in] data data to append to buffer. - @param[in] length length of data (bytes). -*/ -void gs_bytebuffer_append(gs_bytebuffer_t * bb, const void * data, size_t length); - -/** - Append string to buffer. - - @param[in] bb handle. - @param[in] string string to append to buffer. -*/ -void gs_bytebuffer_append_string(gs_bytebuffer_t * bb, const char * string); - -/** - Append string to buffer. - - @param[in] bb handle. - @param[in] string string to append to buffer. - @param[in] max_length max characters to append from \a string. -*/ -void gs_bytebuffer_append_string_max(gs_bytebuffer_t * bb, const char * string, size_t max_length); - -/** - Return buffer as string - enforcing NUL termination. - - This will always add a NUL termination (zero), which may lead to overflow/truncation of the string. - The NUL termination is NOT added to \a used count. - - @param[in] bb handle. - @param[out] error optional, state of buffer - see gs_bytebuffer_error(). - @return C-string (NUL terminated) -*/ -char * gs_bytebuffer_get_as_string(gs_bytebuffer_t * bb, gs_error_t * error); - -/** - Return buffer state. - - @param[in] bb handle. - @return GS_ERROR_OVERFLOW if data has been truncated. - @return GS_ERROR_DATA in case of error during formatting. - @return_gs_error_t -*/ -gs_error_t gs_bytebuffer_get_state(gs_bytebuffer_t * bb); - -/** - Return buffer (user supplied). - - @param[in] bb handle. -*/ -static inline void * gs_bytebuffer_get_buffer(gs_bytebuffer_t * bb) -{ - return bb->buffer; -} - -/** - Return buffer size (user supplied). - - @param[in] bb handle. - @return buffer size -*/ -static inline size_t gs_bytebuffer_get_size(gs_bytebuffer_t * bb) -{ - return bb->size; -} - -/** - Return number of free bytes. - - @param[in] bb handle. - @return number of free bytes. -*/ -static inline size_t gs_bytebuffer_get_free(gs_bytebuffer_t * bb) -{ - return (bb->size) ? (bb->size - bb->used) : 0; -} - -/** - Return number of used bytes. - - @param[in] bb handle. - @return used bytes. -*/ -static inline size_t gs_bytebuffer_get_used(gs_bytebuffer_t * bb) -{ - return bb->used; -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/byteorder.h b/gomspace/libutil/include/gs/util/byteorder.h deleted file mode 100644 index 3d2d6bef..00000000 --- a/gomspace/libutil/include/gs/util/byteorder.h +++ /dev/null @@ -1,341 +0,0 @@ -#ifndef GS_UTIL_BYTEORDER_H -#define GS_UTIL_BYTEORDER_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Convert numbers between host and network order. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Convert value from host order to network order - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_htons(uint16_t value); - -/** - Convert value from network order to host order - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_ntohs(uint16_t value); - -/** - Convert value from host order to network order - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_htonl(uint32_t value); - -/** - Convert value from network order to host order - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_ntohl(uint32_t value); - -/** - Convert value from host order to network order - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_hton16(uint16_t value); - -/** - Convert value from host order to network order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_hton16_array(const uint16_t * from, uint16_t * to, size_t count); - -/** - Convert value from network order to host order - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_ntoh16(uint16_t value); - -/** - Convert value from network order to host order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_ntoh16_array(const uint16_t * from, uint16_t * to, size_t count); - -/** - Convert value from host order to network order - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_hton32(uint32_t value); - -/** - Convert value from host order to network order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_hton32_array(const uint32_t * from, uint32_t * to, size_t count); - -/** - Convert value from network order to host order - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_ntoh32(uint32_t value); - -/** - Convert value from network order to host order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_ntoh32_array(const uint32_t * from, uint32_t * to, size_t count); - -/** - Convert value from host order to network order - @param[in] value value to convert. - @return converted value. -*/ -uint64_t util_hton64(uint64_t value); - -/** - Convert value from host order to network order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_hton64_array(const uint64_t * from, uint64_t * to, size_t count); - -/** - Convert value from network order to host order - @param[in] value value to convert. - @return converted value. -*/ -uint64_t util_ntoh64(uint64_t value); - -/** - Convert value from network order to host order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_ntoh64_array(const uint64_t * from, uint64_t * to, size_t count); - -/** - Convert value from host order to network order - @param[in] value value to convert. - @return converted value. -*/ -float util_htonflt(float value); - -/** - Convert value from host order to network order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_htonflt_array(const float * from, float * to, size_t count); - -/** - Convert value from network order to host order - @param[in] value value to convert. - @return converted value. -*/ -float util_ntohflt(float value); - -/** - Convert value from network order to host order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_ntohflt_array(const float * from, float * to, size_t count); - -/** - Convert value from host order to network order - @param[in] value value to convert. - @return converted value. -*/ -double util_htondbl(double value); - -/** - Convert value from host order to network order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_htondbl_array(const double * from, double * to, size_t count); - -/** - Convert value from network order to host order - @param[in] value value to convert. - @return converted value. -*/ -double util_ntohdbl(double value); - -/** - Convert value from network order to host order - @param[in] from value to convert. - @param[out] to value converted. - @param[in] count element count -*/ -void util_ntohdbl_array(const double * from, double * to, size_t count); - -/** - Convert value from host order to big endian. - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_htobe16(uint16_t value); - -/** - Convert value from host order to little endian. - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_htole16(uint16_t value); - -/** - Convert value from big endian to host order. - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_betoh16(uint16_t value); - -/** - Convert value from little endian to host order. - @param[in] value value to convert. - @return converted value. -*/ -uint16_t util_letoh16(uint16_t value); - -/** - Convert value from host order to big endian. - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_htobe32(uint32_t value); - -/** - Convert value from host order to little endian. - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_htole32(uint32_t value); - -/** - Convert value from big endian to host order. - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_betoh32(uint32_t value); - -/** - Convert value from little endian to host order. - @param[in] value value to convert. - @return converted value. -*/ -uint32_t util_letoh32(uint32_t value); - -/** - Convert value from host order to big endian. - @param[in] value value to convert. - @return converted value. -*/ -uint64_t util_htobe64(uint64_t value); - -/** - Convert value from host order to little endian. - @param[in] value value to convert. - @return converted value. -*/ -uint64_t util_htole64(uint64_t value); - -/** - Convert value from big endian to host order. - @param[in] value value to convert. - @return converted value. -*/ -uint64_t util_betoh64(uint64_t value); - -/** - Convert value from little endian to host order. - @param[in] value value to convert. - @return converted value. -*/ -uint64_t util_letoh64(uint64_t value); - -/** - Byte swap. - @param[in] value value to byteswap. - @return swapped value -*/ -uint16_t gs_bswap_16(uint16_t value); - -/** - Byte swap array. - @param[in] from from address. - @param[out] to to address. - @param[in] count element count. -*/ -void gs_bswap_16_array(const uint16_t * from, uint16_t * to, size_t count); - -/** - Byte swap. - @param[in] value value to byteswap. - @return swapped value -*/ -uint32_t gs_bswap_32(uint32_t value); - -/** - Byte swap array. - @param[in] from from address. - @param[out] to to address. - @param[in] count element count. -*/ -void gs_bswap_32_array(const uint32_t * from, uint32_t * to, size_t count); - -/** - Byte swap. - @param[in] value value to byteswap. - @return swapped value -*/ -uint64_t gs_bswap_64(uint64_t value); - -/** - Byte swap array. - @param[in] from from address. - @param[out] to to address. - @param[in] count element count. -*/ -void gs_bswap_64_array(const uint64_t * from, uint64_t * to, size_t count); - -/** - Byte swap. - @param[in] value value to byteswap. - @return swapped value -*/ -float gs_bswap_float(float value); - -/** - Byte swap array. - @param[in] from from address. - @param[out] to to address. - @param[in] count element count. -*/ -void gs_bswap_float_array(const float * from, float * to, size_t count); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/check.h b/gomspace/libutil/include/gs/util/check.h deleted file mode 100644 index 23920161..00000000 --- a/gomspace/libutil/include/gs/util/check.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef GS_UTIL_CHECK_H -#define GS_UTIL_CHECK_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Argument checking. - - Logs can be enabled through a define. -*/ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if (GS_CHECK_LOG) -#define GS_CHECK_HANDLE(check) if (!(check)) { log_error("Invalid handle - assert: " GS_DEF2STRING(check)); return GS_ERROR_HANDLE;} -#define GS_CHECK_ARG(check) if (!(check)) { log_error("Invalid argument - assert: " GS_DEF2STRING(check)); return GS_ERROR_ARG;} -#define GS_CHECK_SUPPORTED(check) if (!(check)) { log_error("Not supported - assert: " GS_DEF2STRING(check)); return GS_ERROR_NOT_SUPPORTED;} -#define GS_CHECK_RANGE(check) if (!(check)) { log_error("Invalid range - assert: " GS_DEF2STRING(check)); return GS_ERROR_RANGE;} -#else -/** - Perform evalution of 'check' and return GS_ERROR_HANDLE if not 'true'. -*/ -#define GS_CHECK_HANDLE(check) if (!(check)) { return GS_ERROR_HANDLE;} -/** - Perform evalution of 'check' and return GS_ERROR_ARG if not 'true'. -*/ -#define GS_CHECK_ARG(check) if (!(check)) { return GS_ERROR_ARG;} -/** - Perform evalution of 'check' and return GS_ERROR_NOT_SUPPORTED if not 'true'. -*/ -#define GS_CHECK_SUPPORTED(check) if (!(check)) { return GS_ERROR_NOT_SUPPORTED;} -/** - Perform evalution of 'check' and return GS_ERROR_RANGE if not 'true'. -*/ -#define GS_CHECK_RANGE(check) if (!(check)) { return GS_ERROR_RANGE;} -#endif - -/** - Assert on 'value'. - - @deprecated use GS_STATIC_ASSERT() -*/ -#define GS_CHECK_STATIC_ASSERT(condition, name) GS_STATIC_ASSERT(condition, name) - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/clock.h b/gomspace/libutil/include/gs/util/clock.h deleted file mode 100644 index 1d4a9548..00000000 --- a/gomspace/libutil/include/gs/util/clock.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef GS_UTIL_CLOCK_H -#define GS_UTIL_CLOCK_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Get/set time (including RTC), convert to/from string. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Returns real time/clock (UTC - time since Epoch/1970). - - If the platform supports a Real Time Clock, the RTC is normally read on first call. An offset is calculated for the relative clock, which - then is used to calculate the actual time. - - @note clock_get_time() is proto-typed in libcsp as weak, but with different argument which MUST match gs_timestamp_t. - @param[out] time user allocated buffer, contaning the current UTC time. -*/ -void gs_clock_get_time(gs_timestamp_t * time); - -/** - Set real time/clock (UTC). - If the platform supports a Real Time Clock, the RTC is also updated. - @param[in] time UTC time. - @return_gs_error_t -*/ -gs_error_t gs_clock_set_time(const gs_timestamp_t * time); - -/** - Returns elapsed time since some unspecified starting point. - @param[out] time user allocated buffer, receives elapsed time. - @see gs_time_rel_ms() -*/ -void gs_clock_get_monotonic(gs_timestamp_t * time); - -/** - Returns number of elapsed nano-seconds since some unspecified starting point. - @return nano-seconds. -*/ -uint64_t gs_clock_get_nsec(void); - -/** - Buffer length for containing full ISO8601 timestamp - including zero (0) termination. -*/ -#define GS_CLOCK_ISO8601_BUFFER_LENGTH 21 - -/** - Convert UTC to a ISO8601 string. - ISO8601 timestamp: 2017-03-30T06:20:45Z - @param[in] utc_time UTC time. - @param[out] buffer user allocated buffer. - @param[in] buffer_size size of \a buf. - @return_gs_error_t -*/ -gs_error_t gs_clock_to_iso8601_string(const gs_timestamp_t * utc_time, char * buffer, size_t buffer_size); - -/** - Convert UTC to a ISO8601 string. - ISO8601 timestamp: 2017-03-30T06:20:45Z - @param[in] utc_sec UTC seconds. - @param[out] buffer user allocated buffer. - @param[in] buffer_size size of \a buf. - @return_gs_error_t -*/ -gs_error_t gs_clock_to_iso8601_string2(uint32_t utc_sec, char * buffer, size_t buffer_size); - -/** - Convert string (UTC time) to timstamp. - Parse string as: - 1. \.\ - number of seconds elapsed since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). - 2. YYYY-MM-DDTHH:MM:SSZ - ISO8601 - @param[in] str time - @param[out] ts time - @return_gs_error_t -*/ -gs_error_t gs_clock_from_string(const char * str, gs_timestamp_t * ts); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/crc32.h b/gomspace/libutil/include/gs/util/crc32.h deleted file mode 100644 index f2be6775..00000000 --- a/gomspace/libutil/include/gs/util/crc32.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef GS_UTIL_CRC32_H -#define GS_UTIL_CRC32_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - CRC32 checksumes. - - https://en.wikipedia.org/wiki/Cyclic_redundancy_check. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Return init/seed value for CRC-32. - @return initial/seed value for CRC-32, using 0xffffffff. - @see gs_crc32_update(), gs_crc32_finalize() -*/ -uint32_t gs_crc32_init(void); - -/** - Update CRC-32. - @param[in] crc current CRC-32 - @param[in] block start of memory block. - @param[in] length length of \a block. - @return updated CRC-32. - @see gs_crc32_init(), gs_crc32_finalize() -*/ -uint32_t gs_crc32_update(uint32_t crc, const void * block, size_t length); - -/** - Return finalized CRC-32. - @param[in] crc Checksum is finalized by xor'ing 0xffffffff. - @return finalized CRC-32. - @see gs_crc32_init(), gs_crc32_update() -*/ -uint32_t gs_crc32_finalize(uint32_t crc); - -/** - Return finalized CRC-32 on amemory block. - - @param[in] block block to calculate CRC-32 on. - @param[in] length length/size of \a block. - @return finalized CRC-32. -*/ -uint32_t gs_crc32(const void *block, size_t length); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/crc8.h b/gomspace/libutil/include/gs/util/crc8.h deleted file mode 100644 index 99b14d0a..00000000 --- a/gomspace/libutil/include/gs/util/crc8.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef GS_UTIL_CRC8_H -#define GS_UTIL_CRC8_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - CRC8 checksumes. - - https://en.wikipedia.org/wiki/Cyclic_redundancy_check. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Return init/seed value for CRC-8. - @return initial/seed value for CRC-8, using 0xff. - @see gs_crc8_update(), gs_crc8_finalize() -*/ -uint8_t gs_crc8_init(void); - -/** - Update CRC-8. - @param[in] crc current CRC-8 - @param[in] block start of memory block. - @param[in] length length of \a block. - @return updated CRC-8. - @see gs_crc8_init(), gs_crc8_finalize() -*/ -uint8_t gs_crc8_update(uint8_t crc, const void * block, size_t length); - -/** - Return finalized CRC-8. - @param[in] crc Checksum is finalized by xor'ing 0xffffffff. - @return finalized CRC-8. - @see gs_crc8_init(), gs_crc8_update() -*/ -uint8_t gs_crc8_finalize(uint8_t crc); - -/** - Return finalized CRC-8 on amemory block. - - @param[in] block block to calculate CRC-8 on. - @param[in] length length/size of \a block. - @return finalized CRC-8. -*/ -uint8_t gs_crc8(const void *block, size_t length); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/delay.h b/gomspace/libutil/include/gs/util/delay.h deleted file mode 100644 index d205b48c..00000000 --- a/gomspace/libutil/include/gs/util/delay.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef GS_UTIL_DELAY_H -#define GS_UTIL_DELAY_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Delay execution. - - @note Most implementations uses busy waiting. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Delay for number of microseconds. - @note Linux doesn't busy wait. - @param us Number of microseconds to wait -*/ -void gs_delay_us(uint32_t us); - -/** - Return current counter used for us delays - @return timestamp in us -*/ -uint16_t gs_delay_ts_get(void); - -/** - Wait until delay has passed since timestamp - - @param[in] ts Timestamp in us - @param[in] delay The requested delay since ts -*/ -void gs_delay_from_ts(uint16_t ts, uint16_t delay); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/can/can.h b/gomspace/libutil/include/gs/util/drivers/can/can.h deleted file mode 100644 index 27f7acd5..00000000 --- a/gomspace/libutil/include/gs/util/drivers/can/can.h +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_CAN_CAN_H -#define GS_UTIL_DRIVERS_CAN_CAN_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - CAN interface. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Default log group for CAN driver. -*/ -GS_LOG_GROUP_EXTERN(gs_can_log); - -/** - Bit-rate (default). -*/ -#define GS_CAN_DEFAULT_BPS 1000000 - -/** - Callback for handling received data (from CAN driver). - @param[in] device hardware device - @param[in] canMsgId standard or extended message id. - @param[in] extendedMsgId \a true if extended id, \a false if standard id. - @param[in] data pointer to data. - @param[in] data_size size of data. - @param[in] nowMs current relative time in mS. - @param[in] user_data user data. - @param[in] cswitch If called from within an ISR (embedded platform), this will none NULL. -*/ -typedef void (*gs_can_rxdata_callback_t)(int hdl, - uint32_t canMsgId, - bool extendedMsgId, - const void * data, - size_t data_size, - uint32_t nowMs, - void * user_data, - gs_context_switch_t * cswitch); - -/** - Send CAN message with standard id (11 bits). - @param[in] device hardware device - @param[in] canMsgId standard CAN message id. - @param[in] data pointer to data. - @param[in] data_size size of data. - @param[in] timeout_ms timeout in mS. - @return GS_ERROR_FULL if Tx queue is full - @return_gs_error_t -*/ -gs_error_t gs_can_send_standard(uint8_t device, uint32_t canMsgId, const void * data, size_t data_size, int timeout_ms); - -/** - Send CAN message with exended id (29 bits). - @param[in] device hardware device - @param[in] canExtMsgId exteneded message id. - @param[in] data pointer to data. - @param[in] data_size size of data. - @param[in] timeout_ms timeout in mS. - @return GS_ERROR_FULL if Tx queue is full - @return_gs_error_t -*/ -gs_error_t gs_can_send_extended(uint8_t device, uint32_t canExtMsgId, const void * data, size_t data_size, int timeout_ms); - -/** - Set filter and callback for standard message id. - @param[in] device hardware device - @param[in] canMsgId standard message id. - @param[in] mask filter mask. - @param[in] rx_callback callback function. - @param[in] rx_user_data user data provided in callback. - @return GS_ERROR_FULL if all message id slots are used. - @return_gs_error_t -*/ -gs_error_t gs_can_set_standard_filter_mask(uint8_t device, uint32_t canMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * rx_user_data); - -/** - Set filter and callback for extended message id. - @param[in] device hardware device - @param[in] canExtMsgId extended message id. - @param[in] mask filter mask. - @param[in] rx_callback callback function. - @param[in] rx_user_data user data provided in callback. - @return GS_ERROR_FULL if all message id slots are used. - @return_gs_error_t -*/ -gs_error_t gs_can_set_extended_filter_mask(uint8_t device, uint32_t canExtMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * rx_user_data); - -/** - Stop CAN layer. - If a CAN transceiver is present and controlled, it will be disabled. - @param[in] device hardware device - @return_gs_error_t -*/ -gs_error_t gs_can_stop(uint8_t device); - -/** - Start CAN layer. - Clear all buffers and start CAN. - If a CAN transceiver is present and controlled, it will be enabled. - @param[in] device hardware device - @return_gs_error_t -*/ -gs_error_t gs_can_start(uint8_t device); - -/** - Get current CAN layer error state. - @param[in] device hardware device - @param[out] restart_required \a true if CAN layer should be re-started. Pass NULL, if not wanted. - @return_gs_error_t -*/ -gs_error_t gs_can_error_state(uint8_t device, bool * restart_required); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/gpio/gpio.h b/gomspace/libutil/include/gs/util/drivers/gpio/gpio.h deleted file mode 100644 index ff2803c0..00000000 --- a/gomspace/libutil/include/gs/util/drivers/gpio/gpio.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_GPIO_GPIO_H -#define GS_UTIL_DRIVERS_GPIO_GPIO_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - GPIO interface provides a generic interface toward hardware GPIO's. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - GPIO definition. -*/ -typedef struct { - //! Chip/group/port number which the GPIO belongs to. - uint16_t port; - //! The pin number of the GPIO. - uint16_t pin; -} gs_gpio_t; - -/** - GPIO interrupt function. -*/ -typedef void (*gs_gpio_isr_t)(gs_context_switch_t * cswitch); - -/** - Configuration for interrupt related to a GPIO. -*/ -typedef struct { - //! True if it shall trigger on rising edge. - bool rising_edge; - //! True if it shall trigger on falling edge. - bool falling_edge; - //! True if it shall have high priority (if nested isr supported). - bool high_priority; - //! ISR to be called on trigger. - gs_gpio_isr_t isr; -} gs_interrupt_conf_t; - -/** - GPIO get value - - @param[in] gpio The gpio to read - @param[in] value Returned GPIO value (true/false = High/Low) - @return_gs_error_t -*/ -gs_error_t gs_gpio_get(gs_gpio_t gpio, bool *value); - -/** - GPIO get value without error check - - @param[in] gpio The gpio to read - @return GPIO value (true/false = High/Low) -*/ -bool gs_gpio_get_nc(gs_gpio_t gpio); - -/** - GPIO set value - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @return_gs_error_t -*/ -gs_error_t gs_gpio_set(gs_gpio_t gpio, bool value); - -/** - GPIO set value without error check - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) -*/ -void gs_gpio_set_nc(gs_gpio_t gpio, bool value); - -/** - Initialize GPIO as an external interrupt pin. - - @param[in] gpio The gpio to configure - @param[in] conf Configuration of interrupt pin - @return_gs_error_t - */ -gs_error_t gs_gpio_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/i2c/common.h b/gomspace/libutil/include/gs/util/drivers/i2c/common.h deleted file mode 100644 index 895847d3..00000000 --- a/gomspace/libutil/include/gs/util/drivers/i2c/common.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_I2C_COMMON_H -#define GS_UTIL_DRIVERS_I2C_COMMON_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Common (master and slave) I2C definitions. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Default log group for I2C driver. -*/ -GS_LOG_GROUP_EXTERN(gs_i2c_log); - -/** - I2C mode. -*/ -typedef enum { - //! Master mode - GS_I2C_MASTER = 0, - //! Multimaster mode - GS_I2C_MULTI_MASTER = 1, - //! Slave mode - GS_I2C_SLAVE = 2, -} gs_i2c_mode_t; - -/** - Cross-platform I2C configuration. -*/ -typedef struct { - //! Data order, True: MSB first, False: LSB first (default = True) - bool data_order_msb; - //! Device mode (master, multimaster, or slave) - gs_i2c_mode_t mode; - //! Address of node in multimaster and slave mode (not used in master mode) - uint16_t addr; - //! Bits per second (default is #GS_I2C_DEFAULT_BPS) - uint32_t bps; - //! Address size in bits, 7, 8 or 10 bits (default/prefered is #GS_I2C_DEFAULT_ADDRESS_SIZE) - uint8_t addrbits; -} gs_i2c_config_t; - -/** - Cross-platform I2C configuration. - @deprecated use gs_i2c_config_t. -*/ -typedef gs_i2c_config_t gs_i2c_bus_config_t; - -/** - Default bit-rate. -*/ -#define GS_I2C_DEFAULT_BPS 100000 - -/** - Default address size. -*/ -#define GS_I2C_DEFAULT_ADDRESS_SIZE 7 - -/** - Default data order (MSB). -*/ -#define GS_I2C_DEFAULT_DATA_ORDER_MSB 1 - -/** - Speed (command line sub-option). -*/ -#define GS_I2C_COMMAND_LINE_SPEED "speed" - -/** - Device (command line sub-option). -*/ -#define GS_I2C_COMMAND_LINE_DEVICE "device" - -/** - Address (command line sub-option). -*/ -#define GS_I2C_COMMAND_LINE_ADDRESS "address" - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/i2c/master.h b/gomspace/libutil/include/gs/util/drivers/i2c/master.h deleted file mode 100644 index 169d5d2a..00000000 --- a/gomspace/libutil/include/gs/util/drivers/i2c/master.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_I2C_MASTER_H -#define GS_UTIL_DRIVERS_I2C_MASTER_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - I2C master interface. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Perform transaction to I2C slave. - @param[in] device hardware device (bus) - @param[in] addr slave address - @param[in] tx transmit buffer - @param[in] txlen number of bytes to transmit - @param[out] rx receive buffer - can be NULL. - @param[in] rxlen number of bytes to receive. - @param[in] timeout_ms timeout in milliseconds, primarily for locking the I2C channel. - @return_gs_error_t -*/ -gs_error_t gs_i2c_master_transaction(uint8_t device, uint8_t addr, const void * tx, size_t txlen, void * rx, size_t rxlen, int timeout_ms); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/i2c/slave.h b/gomspace/libutil/include/gs/util/drivers/i2c/slave.h deleted file mode 100644 index 540000e3..00000000 --- a/gomspace/libutil/include/gs/util/drivers/i2c/slave.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_I2C_SLAVE_H -#define GS_UTIL_DRIVERS_I2C_SLAVE_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - I2C slave interface. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Start/enable I2C bus reception. - - Reception should not automatically be enabled by their init() functions, as this will complicate adding additional layers/hooks. - - @param[in] device I2C bus (handle) - @return_gs_error_t -*/ -gs_error_t gs_i2c_slave_start(uint8_t device); - -/** - Rx callback. - - Function called when data has been received on the bus (I2C write operation complete). - - @param[in] device I2C bus (handle). - @param[in] rx receive buffer. - @param[in] rx_length number of bytes received. - @param_cswitch -*/ -typedef void (* gs_i2c_slave_receive_t)(uint8_t device, const uint8_t * rx, size_t rx_length, gs_context_switch_t * cswitch); - -/** - Set rx callback. - - @param[in] device I2C bus (handle). - @param[in] rx Rx callback. - @return_gs_error_t -*/ -gs_error_t gs_i2c_slave_set_rx(uint8_t device, gs_i2c_slave_receive_t rx); - -/** - Get rx buffer callback. - - Function called from driver, for getting a pointer to the rx buffer. - - @param[in] device I2C bus (handle). -*/ -typedef void * (* gs_i2c_slave_get_rx_buf_t)(uint8_t device); - -/** - Set rx buffer get callback. - - @param[in] device I2C bus (handle). - @param[in] get_rx_buf get rx buffer callback. - @param[in] buf_length length of buffer retrieved with this callback. - @return_gs_error_t -*/ -gs_error_t gs_i2c_slave_set_get_rx_buf(uint8_t device, gs_i2c_slave_get_rx_buf_t get_rx_buf, size_t buf_length); - -/** - Set response data. - - @param[in] device I2C bus (handle). - @param[in] tx pointer to data. NOTE: data is not copied due to performance, so data must stay valid until the response has been sent. - @param[in] tx_length length of data. - @return_gs_error_t -*/ -gs_error_t gs_i2c_slave_set_response(uint8_t device, const uint8_t * tx, size_t tx_length); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/spi/common.h b/gomspace/libutil/include/gs/util/drivers/spi/common.h deleted file mode 100644 index 069a346e..00000000 --- a/gomspace/libutil/include/gs/util/drivers/spi/common.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_SPI_COMMON_H -#define GS_UTIL_DRIVERS_SPI_COMMON_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Common (master and slave) SPI definitions. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Default log group for SPI driver. -*/ -GS_LOG_GROUP_EXTERN(gs_spi_log); - -/** - SPI mode - clock polarity and phase. -*/ -typedef enum { - /** - Polarity = 0, Phase = 0 (default). - */ - GS_SPI_MODE_CPOL0_CPHA0 = 0, - /** - Polarity = 0, Phase = 1. - */ - GS_SPI_MODE_CPOL0_CPHA1 = 1, - /** - Polarity = 1, Phase = 0. - */ - GS_SPI_MODE_CPOL1_CPHA0 = 2, - /** - Polarity = 1, Phase = 1. - */ - GS_SPI_MODE_CPOL1_CPHA1 = 3 -} gs_spi_mode_t; - -/** - Default bit-rate. -*/ -#define GS_SPI_DEFAULT_BPS 400000 - -/** - Speed (command line sub-option). -*/ -#define GS_SPI_COMMAND_LINE_SPEED "speed" - -/** - Slave (command line sub-option). -*/ -#define GS_SPI_COMMAND_LINE_SLAVE "slave" - -/** - Device (command line sub-option). -*/ -#define GS_SPI_COMMAND_LINE_DEVICE "device" - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/spi/master.h b/gomspace/libutil/include/gs/util/drivers/spi/master.h deleted file mode 100644 index 986f1ce4..00000000 --- a/gomspace/libutil/include/gs/util/drivers/spi/master.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_SPI_MASTER_H -#define GS_UTIL_DRIVERS_SPI_MASTER_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - SPI master interface. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Cross-platform master SPI configuration. -*/ -typedef struct { - /** - Data order, \a True: MSB first, \a False: LSB first - Default: \a True. - */ - bool data_order_msb; - /** - Bits per second. - Default: #GS_SPI_DEFAULT_BPS. - */ - uint32_t bps; - /** - Mode, specifying polarity and phase. - Default: #GS_SPI_MODE_CPOL0_CPHA0. - */ - gs_spi_mode_t mode; - /** - Character size in bits, 8-16 bits. - Default: 8 bits (prefered). - */ - uint8_t bits; -} gs_spi_master_slave_config_t; - -/** - Single master transaction. -*/ -typedef struct { - /** - Pointer to tx data, or NULL if no tx. - */ - const void *tx; - /** - Pointer to rx buffer, or NULL if no rx. - */ - void *rx; - /** - Size/length of rx/tx (bytes). - */ - size_t size; -} gs_spi_master_trans_t; - -/** - Close/free slave. - Freeing resources associated with the slave. - @param[in] slave SPI slave - @return_gs_error_t -*/ -gs_error_t gs_spi_master_close_slave(uint8_t slave); - -/** - Perform transaction to/from a pre-configured SPI slave. - Basically for i < size: send tx[i] and receive rx[i]. - @note: 8 bit SPI character size required! - @param[in] slave SPI slave - @param[in] tx tx buffer - @param[out] rx rx buffer - can be NULL. - @param[in] size number of to send and also receive. - @param[in] timeout_ms timeout in milliseconds, primarily for locking the SPI device. - @return_gs_error_t -*/ -gs_error_t gs_spi_master_transaction(uint8_t slave, const void * tx, void * rx, size_t size, int timeout_ms); - -/** - Perform N transaction to/from a pre-configured SPI slave within one chip selection - @note: 8 bit SPI character size required! - @param[in] slave SPI slave - @param[in] trans Pointer to transactions - @param[in] count Number of transactions (rx and/or tx) to complete - @param[in] timeout_ms timeout in milliseconds, primarily for locking the SPI device. - @return_gs_error_t -*/ -gs_error_t gs_spi_master_transactions(uint8_t slave, gs_spi_master_trans_t *trans, size_t count, int timeout_ms); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/spi/slave.h b/gomspace/libutil/include/gs/util/drivers/spi/slave.h deleted file mode 100644 index 0be02a8e..00000000 --- a/gomspace/libutil/include/gs/util/drivers/spi/slave.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_SPI_SLAVE_H -#define GS_UTIL_DRIVERS_SPI_SLAVE_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - SPI slave interface. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Cross-platform slave SPI configuration. -*/ -typedef struct { - /** - Data order, \a True: MSB first, \a False: LSB first - Default: \a True. - */ - bool data_order_msb; - /** - Mode, specifying polarity and phase. - Default: #GS_SPI_MODE_CPOL0_CPHA0. - */ - gs_spi_mode_t mode; - /** - Character size in bits, 8-16 bits. - Default: 8 bits (prefered). - */ - uint8_t bits; -} gs_spi_slave_config_t; - -/** - Start/enable SPI device reception. - - Reception should not automatically be enabled by their init() functions, as this will complicate adding additional layers/hooks. - - @param[in] device SPI device (handle) - @return_gs_error_t -*/ -gs_error_t gs_spi_slave_start(uint8_t device); - -/** - Rx callback. - - Function called as data is recevied on the device. - - @param[in] device SPI device (handle). - @param[in] rx_buffer Pointer to start of rx buffer. - @param[in] rx number of bytes received so far. - @param[in] new_request \a true on the first callback of new data, \a false on receiving additional data during same \a chip-select. Can be used to bring receiver back in sync with new request. - @param_cswitch - @return total number of bytes to receive before next call back. Return 0 to ignore rest of data - no additional call backs will be done for current SPI transaction. -*/ -typedef uint8_t (* gs_spi_slave_receive_t)(uint8_t device, const uint8_t * rx_buffer, size_t rx, bool new_request, gs_context_switch_t * cswitch); - -/** - Set rx callback. - - @param[in] device SPI device (handle). - @param[in] rx Rx callback. - @return_gs_error_t -*/ -gs_error_t gs_spi_slave_set_rx(uint8_t device, gs_spi_slave_receive_t rx); - -/** - Set response data. - - @param[in] device SPI device (handle). - @param[in] offset offset (in bytes) for the response, counted from start of request, i.e. offset of 2 means data will be sent as the 3rd byte. - @param[in] tx pointer to data. NOTE: data is not copied due to performance, so data must stay valid until the response has been sent. - @param[in] size size of data. - @return_gs_error_t -*/ -gs_error_t gs_spi_slave_set_response(uint8_t device, size_t offset, const uint8_t * tx, size_t size); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/sys/memory.h b/gomspace/libutil/include/gs/util/drivers/sys/memory.h deleted file mode 100644 index ca3862df..00000000 --- a/gomspace/libutil/include/gs/util/drivers/sys/memory.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_SYS_MEMORY_H -#define GS_UTIL_DRIVERS_SYS_MEMORY_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Cross platform memory status API. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - RAM status - Containing different size parameters describing RAM usage. - All sizes are in bytes. - If a parameter is not available/supported on a specific platform, the parameter is set to -1. - */ -typedef struct { - //! total size of RAM - long total; - //! max available RAM for allocation after initialization of of global/static variables - long max_available; - //! available RAM at runtime for dynamic allocation - long available; - //! Lowest registered available RAM since boot - long min_available; -} gs_mem_ram_stat_t; - -/** - RAM types - Defines the different RAM types (external/internal) supported on - the various platforms. - */ -typedef enum { - GS_MEM_RAM_TYPE_INTERNAL = 0,//!< Internal RAM type - GS_MEM_RAM_TYPE_EXTERNAL //!< External RAM type -} gs_mem_ram_type_t; - -/** - Get status of internal RAM - - @param[out] ram_stat RAM status, each member of struct is -1 if not supported on specific platform - @return_gs_error_t - */ -gs_error_t gs_mem_get_int_ram_stat(gs_mem_ram_stat_t * ram_stat); - -/** - Get status of external RAM - - @param[out] ram_stat RAM status, each member of struct is -1 if not supported on specific platform - @return_gs_error_t - */ -gs_error_t gs_mem_get_ext_ram_stat(gs_mem_ram_stat_t * ram_stat); - - -/** - Get status of selected RAM - - @param[in] type RAM type to query status for - @param[out] ram_stat RAM status, each member of struct is -1 if not supported on specific platform - @return_gs_error_t - */ -gs_error_t gs_mem_get_ram_stat(gs_mem_ram_type_t type, gs_mem_ram_stat_t * ram_stat); - - -/** - Get default RAM type - - returns the default RAM type used for allocations (Heap). - @return gs_mem_ram_type_t - */ -gs_mem_ram_type_t gs_mem_get_ram_default(); - - -/** - Print RAM status. - - @param[in] ram_stat RAM status - @param[in] out output stream - @return_gs_error_t - */ -gs_error_t gs_mem_print_ram_stat(gs_mem_ram_stat_t * ram_stat, FILE * out); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/drivers/watchdog/device.h b/gomspace/libutil/include/gs/util/drivers/watchdog/device.h deleted file mode 100644 index 613e511e..00000000 --- a/gomspace/libutil/include/gs/util/drivers/watchdog/device.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef GS_UTIL_DRIVERS_HW_WATCHDOG_H -#define GS_UTIL_DRIVERS_HW_WATCHDOG_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Hardward watchdog (HWWD) device interface. - - Hardware Watchdog interface which provides a generic interface towards - any HWWD. Most HWWD implementation should be able to fit behind - this interface, with just a small "adaption" layer needed. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Hardware watchdog driver interface. -*/ -typedef struct gs_watchdog_dev_ops gs_watchdog_dev_ops_t; - -/** - Hardware watchdog (HWWD) device structure - - Structure that describes the HWWD device and holds - the parameters needed for storing e.g. timeout values etc. -*/ -typedef struct gs_watchdog_device { - int id; /**< An ID for the HWWD device - This is currently not used. */ - const gs_watchdog_dev_ops_t *ops; /**< Pointer to ops struct defining the operations a HWWD device supports. */ - unsigned int timeout; /**< The timeout value that the HWWD device should be configured with. */ - unsigned int pretimeout; /**< The pretimeout (if supported) by the HWWD device */ - unsigned int min_timeout; /**< Minimum timeout value supported by the HWWD device */ - unsigned int max_timeout; /**< Maximum timeout value supported by the HWWD device */ - void *driver_data; /**< Pointer to driver specific data can be used by the HWWD driver impl. */ -} gs_watchdog_device_t; - -/** - Hardware watchdog driver interface. -*/ -struct gs_watchdog_dev_ops -{ - /* mandatory operations */ - gs_error_t (*start)(gs_watchdog_device_t *); /**< Starts the HWWD device */ - gs_error_t (*stop)(gs_watchdog_device_t *); /**< Stops the HWWD device */ - gs_error_t (*ping)(gs_watchdog_device_t *); /**< Polls the HWWD device and restart count-down */ - /* optional operations */ - gs_error_t (*set_timeout)(gs_watchdog_device_t *, unsigned int); /**< (Optional) Set timeout of the HWWD device */ - gs_error_t (*set_pretimeout)(gs_watchdog_device_t *, unsigned int); /**< (Optional) Set Pre-timeout of the HWWD device */ - gs_error_t (*restart)(gs_watchdog_device_t *); /**< (Optional) Restart the HWWD device */ - unsigned int (*get_timeleft)(gs_watchdog_device_t *); /**< (Optional) Get time left until HWWD device times out. */ - int (*status)(gs_watchdog_device_t *); /**< (Optional) Reads status of the HWWD device */ -}; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/endian.h b/gomspace/libutil/include/gs/util/endian.h deleted file mode 100644 index 15e22ae1..00000000 --- a/gomspace/libutil/include/gs/util/endian.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef GS_UTIL_ENDIAN_H -#define GS_UTIL_ENDIAN_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Detecting endian type. -*/ - -// generated by waf configure, defines either UTIL_BIG_ENDIAN or UTIL_LITTLE_ENDIAN -#include "../../conf_util.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if !UTIL_BIG_ENDIAN && !UTIL_LITTLE_ENDIAN - #error No endian defined -#endif -#if UTIL_BIG_ENDIAN && UTIL_LITTLE_ENDIAN - #error Both big and little endian defined -#endif - -#include - -/** - Returns \a true if platform is big endian. -*/ -static inline bool gs_endian_big(void) -{ -#if (UTIL_BIG_ENDIAN) - return true; -#else - return false; -#endif -} - -/** - Returns \a true if platform is little endian. -*/ -static inline bool gs_endian_little(void) -{ -#if (UTIL_LITTLE_ENDIAN) - return true; -#else - return false; -#endif -} - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/error.h b/gomspace/libutil/include/gs/util/error.h deleted file mode 100644 index d1743165..00000000 --- a/gomspace/libutil/include/gs/util/error.h +++ /dev/null @@ -1,199 +0,0 @@ -#ifndef GS_UTIL_ERROR_H -#define GS_UTIL_ERROR_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Common error code definitions. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Common/generic error codes. - Based on POSIX \a errno values, but negative instead of positive. -*/ -typedef enum gs_error_t { - /** - Success - ok (POSIX). - */ - GS_OK = 0, - /** - Operation not permitted (POSIX.1: EPERM). - */ - GS_ERROR_PERM = -1, - /** - Interrupted system call (or Interrupted function call) (POSIX: EINTR). - */ - GS_ERROR_INTR = -4, - /** - Input/output error (POSIX.1: EIO) - */ - GS_ERROR_IO = -5, - /** - Resource temporarily unavailable (may be the same value as EWOULDBLOCK) (POSIX.1: EAGAIN). - */ - GS_ERROR_AGAIN = -11, - /** - Cannot allocate memory (or Not enough space) (POSIX.1: ENOMEM). - */ - GS_ERROR_ALLOC = -12, - /** - Permission denied (POSIX.1: EACCES). - */ - GS_ERROR_ACCESS = -13, - /** - Device or resource busy (POSIX.1: EBUSY). - */ - GS_ERROR_BUSY = -16, - /** - File exists (POSIX.1-2001: EEXIST). - */ - GS_ERROR_EXIST = -17, - /** - Invalid argument (POSIX.1: EINVAL). - */ - GS_ERROR_ARG = -22, - /** - Function not implemented (POSIX.1: ENOSYS) - */ - GS_ERROR_NOT_IMPLEMENTED = -38, - /** - Value too large to be stored in data type (POSIX.1: EOVERFLOW). - Example: trying to put 50 characters into a 10 character array. - @see GS_ERROR_RANGE. - */ - GS_ERROR_OVERFLOW = -75, - /** - Operation not supported (POSIX.1: ENOTSUP) - */ - GS_ERROR_NOT_SUPPORTED = -95, - /** - Address already in use (POSIX.1: EADDRINUSE). - */ - GS_ERROR_IN_USE = -98, - /** - Connection reset (POSIX.1-2001: ECONNRESET). - */ - GS_ERROR_CONNECTION_RESET = -104, - /** - No buffer space available (POSIX.1 (XSI STREAMS option): ENOBUFS). - */ - GS_ERROR_NO_BUFFERS = -105, - /** - Timeout (POSIX.1-2001: ETIMEDOUT). - */ - GS_ERROR_TIMEOUT = -110, - /** - Connection already in progress (POSIX.1-2001: EALREADY). - */ - GS_ERROR_ALREADY_IN_PROGRESS = -114, - - /** - Handle error (GOMspace). - */ - GS_ERROR_HANDLE = -2000, // from errno.h: #define __ELASTERROR 2000 /* Users can add values starting here */ - /** - Not found (GOMspace). - */ - GS_ERROR_NOT_FOUND = -2001, - /** - Full (GOMspace). - */ - GS_ERROR_FULL = -2002, - /** - Range error (GOMspace). - Example: specifying 120 hours, where only 0-23 is valid. - @see GS_ERROR_OVERFLOW - */ - GS_ERROR_RANGE = -2003, - /** - Data error (GOMspace). - */ - GS_ERROR_DATA = -2004, - /** - Unknown error (GOMspace). - @note avoid use - use specific error to improve debugging/troubleshooting. - */ - GS_ERROR_UNKNOWN = -2005, - /** - No data available (GOMspace). - */ - GS_ERROR_NO_DATA = -2006, - /** - Stale data - not updated (GOMspace). - */ - GS_ERROR_STALE = -2007, - /** - Type error (GOMspace). - */ - GS_ERROR_TYPE = -2008, - /** - Ambiguous error (GOMspace). - */ - GS_ERROR_AMBIGUOUS = -2009, - /** - State error (GOMspace). - */ - GS_ERROR_STATE = -2010, - -} gs_error_t; - -/** - * Convert an error code to a string. - * Uses standard POSIX strerror() under the hood. - * @param[in] error error to convert. If negative (e.g. \a gs_error_t), it is first converted to a positive value. - * @return string usefull for logging purposes (should not be used for programatically processing). - */ -const char * gs_error_string(int error); - -/** - Convert standard POSIX \a errno to gs_error_t. - @param[in] error POSIX error code (errno). - @return convert error code, by simply converting to a negative number. -*/ -gs_error_t gs_error(int error); - -#if (GS_UTIL_DEPRECATED_ERROR_CODES) -/** - Legacy error definitions. - @deprecated Use standard gs_error_t codes - these defines are only kept, so very old code (not yet update to use #gs_error_t) can compile. - @{ -*/ -#define E_NO_ERR -1 -#define E_NO_DEVICE -2 -#define E_MALLOC_FAIL -3 -#define E_THREAD_FAIL -4 -#define E_NO_QUEUE -5 -#define E_INVALID_BUF_SIZE -6 -#define E_INVALID_PARAM -7 -#define E_NO_SS -8 -#define E_GARBLED_BUFFER -9 -#define E_FLASH_ERROR -10 -#define E_BOOT_SER -13 -#define E_BOOT_DEBUG -14 -#define E_BOOT_FLASH -15 -#define E_TIMEOUT -16 -#define E_NO_BUFFER -17 -#define E_OUT_OF_MEM -18 -#define E_FAIL -19 -/** @} */ - -/** - Converts legacy error definitions to string. - @deprecated Use standard gs_error_t codes - this function is only kept, so very old code (not yet update to use #gs_error_t) can compile. - @param[in] code error code - @return string describing the error. -*/ -const char * error_string(int code) __attribute__((deprecated)); - -#endif // GS_UTIL_DEPRECATED_ERROR_CODES - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/fletcher.h b/gomspace/libutil/include/gs/util/fletcher.h deleted file mode 100644 index 5b24c23c..00000000 --- a/gomspace/libutil/include/gs/util/fletcher.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef GS_UTIL_FLETCHER_H -#define GS_UTIL_FLETCHER_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Fletcher16 checksum, -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Fletcher16 checksum (read using copy function). - - Data is read from \a data, using the specified \a memcpyfcn function. - - @param[in] data data. - @param[in] size number of \a data bytes. - @param[in] memcpyfcn memory copy function. If NULL is specified, standard memcpy will be used. - @returns fletcher16 checksum -*/ -uint16_t gs_fletcher16_memcpy(const void * data, size_t size, void * (*memcpyfcn)(void *, const void *, size_t)); - -/** - Fletcher16 checksum (read from program memory). - - AVR8: reads from program memory. - Other architectures: identical to gs_fletcher16(). - - @param[in] data_in data. - @param[in] size number of \a data bytes. - @returns fletcher16 checksum -*/ -uint16_t gs_fletcher16_P(const void * data_in, size_t size); - -/** - Fletcher16 checksum. - - @param[in] data data. - @param[in] size number of \a data bytes. - @returns fletcher16 checksum -*/ -uint16_t gs_fletcher16(const void * data, size_t size); - -/** - Fletcher16 working set. - @see gs_fletcher16_init(), gs_fletcher16_update(), gs_fletcher16_finalize() -*/ -typedef struct { - /** - Sum1 - internal. - */ - uint16_t sum1; - /** - Sum2 - internal. - */ - uint16_t sum2; -} gs_fletcher16_t; - -/** - Initialize fletcher16 working set. - @param[in] f16 working set. -*/ -void gs_fletcher16_init(gs_fletcher16_t * f16); - -/** - Update fletcher16 checksum. - @param[in] f16 working set. - @param[in] data data. - @param[in] size number of \a data bytes. -*/ -void gs_fletcher16_update(gs_fletcher16_t * f16, const void * data, size_t size); - -/** - Finalize fletcher16 checksum and return it. - - @param[in] f16 working set. - @returns fletcher16 checksum -*/ -uint16_t gs_fletcher16_finalize(gs_fletcher16_t * f16); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/function_scheduler.h b/gomspace/libutil/include/gs/util/function_scheduler.h deleted file mode 100644 index 229c5031..00000000 --- a/gomspace/libutil/include/gs/util/function_scheduler.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef GS_UTIL_FUNCTION_SCHEDULER -#define GS_UTIL_FUNCTION_SCHEDULER -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Function scheduler. - - Simple framework for invoking functions at intervals. - - Instead of creating a lot of tasks (which uses memory), this framework can be used to schedule execution of functions at specified intervals. - - Once setup, calling gs_function_scheduler_execute_ms() will execute all functions timed out and return the time, until the next function has - to be executed or max timeout specified (or max wait time supported on the platform). - - The API supports multiple schedulers, but is not thread-safe. - - @note Do NOT use for time critical control, as the actual time interval is influenced by the host thread and other scheduled functions. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Scheduler handle. -*/ -typedef struct gs_function_scheduler gs_function_scheduler_t; - -/** - Function callback. - - @return timeout in mS until next callback. -*/ -typedef uint32_t (*gs_function_scheduler_function_t)(void * user_data); - -/** - Initialize scheduler. - Memory is allocated once for \a max_entries. - @param[in] max_timeout_ms max timeout in mS. - @param[in] max_entries max number of entries for this scheduler. - @param[out] scheduler reference to created scheduler. - @return_gs_error_t -*/ -gs_error_t gs_function_scheduler_create(uint32_t max_timeout_ms, unsigned int max_entries, gs_function_scheduler_t ** scheduler); - -/** - Free scheduler (release resources). - @param[in] scheduler scheduler. - @return_gs_error_t -*/ -gs_error_t gs_function_scheduler_destroy(gs_function_scheduler_t * scheduler); - -/** - Execute scheduled function(s) and returns number of mS until next execute must be called again. - - @note Return type is \a int to prevent overflow on platforms where int is less than 32 bits. - - @param[in] scheduler scheduler. - @return next timeout in mS. -*/ -int gs_function_scheduler_execute_ms(gs_function_scheduler_t * scheduler); - -/** - Register function to be executed at mS intervals. - @param[in] scheduler scheduler. - @param[in] first_timeout_ms mS until first execution. - @param[in] func function to execute. - @param[in] user_data function user data. - @return_gs_error_t -*/ -gs_error_t gs_function_scheduler_register_ms(gs_function_scheduler_t * scheduler, uint32_t first_timeout_ms, gs_function_scheduler_function_t func, void * user_data); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/gosh/command.h b/gomspace/libutil/include/gs/util/gosh/command.h deleted file mode 100644 index 8187152e..00000000 --- a/gomspace/libutil/include/gs/util/gosh/command.h +++ /dev/null @@ -1,503 +0,0 @@ -#ifndef GS_UTIL_GOSH_COMMAND_H -#define GS_UTIL_GOSH_COMMAND_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Command framework. - - Provides a simple way of organizing commands in a hierarchy. A command is a text string mapping to a function - supporting arguments. -*/ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Max langth of a command (including NUL termination). -*/ -#define GS_COMMAND_MAX_LEN_COMMAND 20 - -/** - Flag for hiding command in help and tab-complete. -*/ -#define GS_COMMAND_FLAG_HIDDEN 0x02 - -/** - 'root' command attribute. - - On embedded (none Linux) systems, it is prefered to store as much as possible in \a program memory, in order to save RAM. - This is accomplished by tagging all \a root commands with this attribute, which instructs the linker to put all commands in a named - section. This section is then through the linker-script, placed in \a program memory. - The command framework can read commands directly from this section, and therefore doesn't need an RAM to maintain the list. - - The gs_command_register() must still be called for all \a root commands, which ensures that the linker doesn't throw away the - command objects, due to missing code reference. - - On a Linux system, the commands are not group in a section. Instead gs_command_register() dynamicly builds a list with the commands. - - @see gs_command_register() -*/ -#if (__linux__ == 0) -#define GS_COMMAND_ROOT __attribute__ ((section(".commands"))) -#else -#define GS_COMMAND_ROOT -#endif - -/** - Sub command attribute, - - Only necesasry on AVR8, due to its memory model. -*/ -#define GS_COMMAND_SUB GS_PGM_OBJECT - -/** - Macro for initializing command chains. -*/ -#define GS_COMMAND_INIT_CHAIN(__list) {.list = __list, .count = GS_ARRAY_SIZE(__list)} - -/** - Macro for registering commands. - - @see gs_command_register() -*/ -#define GS_COMMAND_REGISTER(__cmd) gs_command_register(__cmd, GS_ARRAY_SIZE(__cmd)) - -/** - Command reference. - @note Use gs_command_t instead of 'struct command'. -*/ -typedef struct command gs_command_t; - -/** - Commands context reference - @note Use gs_command_context_t instead of struct command_context - */ -typedef struct command_context gs_command_context_t; - -/** - Command output interface -*/ -typedef struct command_io_functions { - /** - Function interface for setting result - @param output_ctx pointer to output context for the given impl. - @param group Group name specifies the group that a given key/value pair belongs to. - @param key key name - @param value string value of the result - @return_gs_error_t - */ - gs_error_t (*set_result)(gs_command_context_t *ctx, const char *group, const char *key, const char *value); - /** - Function interface for flushing results. Used by the command handler to ensure output/results - are flushed to stdout/File or any other receiver of the output. - @param output_ctx pointer to output context for the given impl. - @return_gs_error_t - */ - gs_error_t (*flush)(gs_command_context_t *ctx); - /** - Function interface for waiting for key/input - @param output_ctx pointer to output context for the given impl. - @param ch pointer to character returned by function - @param timeout_ms maximum time to wait of the character. - @return_gs_error_t - */ - gs_error_t (*wait_for_key)(gs_command_context_t *ctx, int *ch, int timeout_ms); -} gs_command_io_functions_t; - - - -/** - Command context for executing a command. -*/ -struct command_context { - /** - Input (raw) command line, including arguments. - */ - const char * command_line; - - /** - Command being executed. - */ - const gs_command_t * command; - - /** - Number of arguments (standard argc style). - */ - int argc; - - /** - Argument array (standard argv style). - */ - char **argv; - - /** - FILE handle for capturing stdout from command. - */ - FILE* out; - - /** - getopt variable. - */ - int optind; - - /** - getopt variable. - */ - int optopt; - - /** - getopt variable. - */ - char *optarg; - - /** - getopt variable. - */ - int optsp; - - /** - Function interface for I/O operations - */ - const gs_command_io_functions_t *io_functions; - - /** - Pointer for storing the context used by the I/O functions - */ - void * io_ctx; -}; - -/** - Command logging call-back - - logs information on the command called. - @param[in] cmd_line command line string - @param[in] ret return code from command execution framework - @param[in] cmd_ret return code from the executed command - @param[in] start time_stamp when command execution started. - @param[in] end time_stamp when command execution completed. - @param[in] ctx context pointer for the logger. - @return_gs_error_t -*/ -typedef gs_error_t (*gs_command_log_t)(const char *cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t start, gs_timestamp_t end, void * ctx); - -/** - Command handler. -*/ -typedef int (*gs_command_handler_t)(gs_command_context_t * ctx); - -/** - Completer call-back (tab complete). - - @param[in] ctx command context. - @param[in] arg_to_complete argument to complete - @return #GS_OK Found at least 1 match. - The \a completer is expected to have completed more of the command line. - If the framework detects multiple matches, the framework will proceed as if #GS_ERROR_AMBIGUOUS was returned. - The framework doesn't expect anything to be printed to \a out, but will update/refresh the console line. - @return #GS_ERROR_AMBIGUOUS Ambiguous - multiple matches or force the framework to show help. - The \a completer may have extended/completed more of the command line. - The framework expects the \a completer to have printed to \a out, and will show help/usage for the command on a new line. - @return #GS_ERROR_NOT_FOUND (or others) No matches found or no more arguments to complete. - The framewrok doesn't expect anything to be printed to \a out, and will not update the console. -*/ -typedef gs_error_t (*gs_command_completer_t)(gs_command_context_t * ctx, int arg_to_complete); - -/** - Add token - helper to 'tab complete' argument(s). - - @param[in] ctx command context. - @param[in] token possible completion - the API will find the common part. - @param[in] exact \a true if \a token is an exact match - all other added tokens will be ignored. - @return number of tokens added. -*/ -unsigned int gs_command_completer_add_token(gs_command_context_t * ctx, const char * token, bool exact); - -/** - Chain element for chaning sub-commands. -*/ -typedef struct { - /** - Command list. - */ - const gs_command_t * list; - /** - Number of commands in the \a list. - */ - unsigned int count; -} gs_command_chain_t; - -/** - Signals no command arguments in command definition, see mandatory arguments. -*/ -#define GS_COMMAND_NO_ARGS 255 - -/** - Command definition. -*/ -struct command { -#if (__AVR__) - char name[GS_COMMAND_MAX_LEN_COMMAND]; - char help[50]; - char usage[50]; -#else - /** - Name. - */ - const char * const name; - /** - Help text. - */ - const char * const help; - /** - Usage text. - */ - const char * const usage; -#endif - /** - Command handler - the "actual command function". - */ - gs_command_handler_t handler; -#if (__AVR__ == 0) - /** - Completer function - helps completing an argument. - */ - gs_command_completer_t completer; -#endif - /** - Sub-command (if any). - */ - gs_command_chain_t chain; - /** - Mode/flags. - See #GS_COMMAND_FLAG_HIDDEN. - */ - unsigned int mode; - /** - Number of mandatory (minimum) arguments. - - @note Due to backwards compatibility, 0 (zero) cannot be used to signal no arguments - use #GS_COMMAND_NO_ARGS instead, if command doesn't take any arguments (mandatory or optional). - */ - uint8_t mandatory_args; - /** - Number of optional arguments. - */ - uint8_t optional_args; - /** - Filler for future use. - */ - uint8_t filler[2]; -}; - -/** - Returns the arguments as a string, where arguments are separated by spaces. - @param ctx command context. - @return Pointer to concatenated arguments -*/ -const char * gs_command_args(gs_command_context_t *ctx); - -/** - Execute command. - @deprecated Replaced by gs_command_execute & gs_command_execute_stdio - - Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return - result is stored in \a command_result. - - @param[in] command Command to execute, including arguments separated by spaces. - @param[out] command_result Result returned by \a command (if executed). Use \a NULL to ignore result. - @return #GS_ERROR_NOT_FOUND if command wasn't found. - @return #GS_ERROR_ARG if number of argumenets exceeds \a mandatory + \a optional count. - @return_gs_error_t -*/ -gs_error_t gs_command_run(const char * command, gs_error_t * command_result); - -/** - Execute command. - - Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return - result is stored in \a command_result. - - @param[in] command Command to execute, including arguments separated by spaces. - @param[out] command_result Result returned by \a command (if executed). Use \a NULL to ignore result. - @param[in] out output (FILE) stream - @param[in] iof Pointer to function interface of IO operations - @param[in] iof_ctx Pointer to context used by the IO function interface - @return #GS_ERROR_NOT_FOUND if command wasn't found. - @return #GS_ERROR_ARG if number of argumenets exceeds \a mandatory + \a optional count. - @return_gs_error_t -*/ -gs_error_t gs_command_execute(const char * command, gs_error_t * command_result, FILE *out, const gs_command_io_functions_t * iof, void * iof_ctx); - -/** - Execute command. - - Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return - result is stored in \a command_result. The results are printed on stdout and input captured on stdin. - - @param[in] command Command to execute, including arguments separated by spaces. - @param[out] command_result Result from command. Use \a NULL to ignore result. - @return #GS_OK if command was executed - result returned in \a command_result. Otherwise an error indicating why the command wasn't executed. -*/ -gs_error_t gs_command_execute_stdio(const char * command, gs_error_t * command_result); - -/** - Set output - - Sets output from command, using the io function struct in ctx. - - @param[in] ctx the command context - @param[in] group a string specifying the group of the result. Leave blank if not used. - @param[in] key a string specifying the key/name of the result variable. - @param[in] value a string representation of the result value. - @return_gs_error_t -*/ -gs_error_t gs_command_set_output(gs_command_context_t *ctx, const char* group, const char* key, const char* value); - -/** - Set output - - Sets output from command using printf formatting, using the io function struct in ctx. - - @param[in] ctx the command context - @param[in] group a string specifying the group of the result. Leave blank if not used. - @param[in] key a string specifying the key/name of the result variable. - @param[in] format printf syntax for formatting data - @return_gs_error_t -*/ -gs_error_t gs_command_set_output_printf(gs_command_context_t *ctx, const char* group, const char* key, const char * format, ...); - -/** - Flush output/Results - - Instruct the command output stream & results to be flushed from it's buffers. - - @param[in] ctx the command context - @return_gs_error_t -*/ -gs_error_t gs_command_flush_output(gs_command_context_t *ctx); - -/** - Wait for any key input - - Instruct the command input stream to wait for any key. - - @param[in] ctx the command context - @param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milliseconds. - @return true if command should proceed (either because of key press present or if no input stream available) -*/ -bool gs_command_wait_any_key(gs_command_context_t *ctx, int timeout_ms); - -/** - Wait for key input - - Instruct the io stream to wait for a key, and return the pressed key in ch. - - @param[in] ctx the command context - @param[out] ch the character that was read on the input stream - @param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milliseconds. - @return #GS_OK if key was read - @return #GS_ERROR_HANDLE if no input stream is present - @return #GS_ERROR_TIMEOUT on timeout. -*/ -gs_error_t gs_command_wait_key(gs_command_context_t *ctx, int* ch, int timeout_ms); - -/** - Register commands. - - gs_command_init() must be called prior to registering any commands. - - See #GS_COMMAND_ROOT for details. - - @param[in] cmds Pointer to command array - @param[in] cmd_count Number of commands in command array - @return_gs_error_t -*/ -gs_error_t gs_command_register(const gs_command_t * cmds, size_t cmd_count); - -/** - Initialize command system and register default commands. - - Registers following commands: gs_log_register_commands() and gs_command_register_default_commands(). - - @param[in] min_stack_size Minimum stack size required for executing commands. The stack size will be used by other sub-systems such as gs_console, g-script. Stack size may be ignored on some platforms, e.g. Linux. - @return_gs_error_t - @see gs_command_init_no_commands() -*/ -gs_error_t gs_command_init(size_t min_stack_size); - -/** - Initialize command system (without any default commands). - - @param[in] min_stack_size Minimum stack size required for executing commands. The stack size will be used by other sub-systems such as gs_console, g-script. Stack size may be ignored on some platforms, e.g. Linux. - @return_gs_error_t - @see gs_command_init() -*/ -gs_error_t gs_command_init_no_commands(size_t min_stack_size); - - -/** - Register a call-back used for logging of command execution. - - @param[in] log_cb the logging call back. - @param[in] log_ctx pointer to context data. Set to NULL if not used. - @return_gs_error_t -*/ -gs_error_t gs_command_register_logger(gs_command_log_t log_cb, void *log_ctx); - -/** - Default implementation of the command logger, that can be used if no other - custom command logger is provided by the system. - - @param[in] cmd_line command line string - @param[in] ret return code provided by the command execution function. - @param[in] cmd_ret return code provided by the executed command. - @param[in] t_start time stamp when command execution started. - @param[in] t_end time stamp when command execution completed. - @param[in] log_ctx context for the command logger. - @return_gs_error_t -*/ -gs_error_t gs_command_logger_default(const char* cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t t_start, gs_timestamp_t t_end, void * log_ctx); - -/** - Return minimum stack size. - @return minimm stack size required for executing commands. The minimum stack size is set by call to gs_command_init(). -*/ -size_t gs_command_get_stack_size(void); - -/** - Register set of default commands. - @return_gs_error_t -*/ -gs_error_t gs_command_register_default_commands(void); - -/** - Split line into argc/argv. - - @param[in] line line to split - the line will be chop up into argv. - @param[out] argc argc count. - @param[out] argv argv array. - @param[in] max_argc max argv elements. - @return \a true if successfull, else \a false. -*/ -bool gs_command_build_argv(char *line, int *argc, char **argv, int max_argc); - -/** - Parse options. - - Adapted from AT&T public domain source from: - http://www.informatica.co.cr/unix-source-code/research/1985/1103.html - - @param[in] ctx command context. - @param[in] opts options - @return option character -*/ -int gs_command_getopt(gs_command_context_t *ctx, const char *opts); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/gosh/console.h b/gomspace/libutil/include/gs/util/gosh/console.h deleted file mode 100644 index e0c9c42a..00000000 --- a/gomspace/libutil/include/gs/util/gosh/console.h +++ /dev/null @@ -1,123 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -#ifndef GS_UTIL_GOSH_CONSOLE_H -#define GS_UTIL_GOSH_CONSOLE_H -/** - @file - - Console (stdin/stdout) interface for running commands. - - This assumes a VT102 terminal emulator, and tries to fix some of minicom's quirks with e.g. home/end keys. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Initialize the API and console. - - @deprecated version 3.4, use gs_console_start() - - @return_gs_error_t -*/ -gs_error_t gs_console_init(void); - -/** - Restores terminal settings (only relevant on Linux). - - @deprecated version 3.4, this is handled by an installed exit-handler in gs_console_start(). - - @return_gs_error_t -*/ -gs_error_t gs_console_exit(void); - -/** - Set console prompt. - - @param[in] prompt user prompt - the API only stores the pointer, so do not modify/delete content. NULL or empty string is ignored (no change). -*/ -void gs_console_set_prompt(const char * prompt); - -/** - Clear the console screen -*/ -void gs_console_clear(void); - -/** - Update console. -*/ -void gs_console_update(void); - -/** - Create console thread. - - The console thread reads from stdin and writes to stdout. - - The thread is created with low priority, #GS_THREAD_PRIORITY_LOW. - - @deprecated version 3.4, use gs_console_start() - - @param[out] handle handle to created thread - thread will be created joinable if supported by platform. Use NULL, if not wanted. - @return_gs_error_t -*/ -gs_error_t gs_console_create_thread(gs_thread_t * handle); - -/** - Create console thread with priority. - - The console thread reads from stdin and writes to stdout. - - @deprecated version 3.4, use gs_console_start() - - @param[in] priority thread priority, normally #GS_THREAD_PRIORITY_LOW. - @param[out] handle handle to created thread - thread will be created joinable if supported by platform. Use NULL, if not wanted. - @return_gs_error_t -*/ -gs_error_t gs_console_create_thread_with_priority(gs_thread_priority_t priority, gs_thread_t * handle); - -/** - @anchor GS_CONSOLE_F - @defgroup GS_CONSOLE_F Console flags. - Use with gs_console_start() to configure behaviour. - @{ -*/ -/** - Linux only: no signal handlers installed (e.g. to catch SIG_TERM). - @see gs_console_start() -*/ -#define GS_CONSOLE_F_NO_SIGNAL_HANDLER 0x0001 -/** @} */ - -/** - Start console thread (priority: #GS_THREAD_PRIORITY_LOW). - - The console thread reads from stdin and writes to stdout. The thread is created with low priority, #GS_THREAD_PRIORITY_LOW. - - Linux: Changes terminal settings and installs an atexit() handler to restore the settings, Signal handlers will be installed to catch SIG_TERM -> exit() and ignore SIG_INT (controlled by option on command line) - unless #GS_CONSOLE_F_NO_SIGNAL_HANDLER is specified. - - @param[in] prompt set console prompt by calling gs_console_set_prompt(). - @param[in] flags configure behaviour, see @ref GS_CONSOLE_F definitions. - @return #GS_ERROR_EXIST if console thread already created. - @return_gs_error_t -*/ -gs_error_t gs_console_start(const char * prompt, uint32_t flags); - -/** - Stop (and join with) console thread. - - @note This is only supported on Linux. - - The thread is interrupted using pthread_cancel(), which does not guarantee \a clean shutdown if the thread is busy executing a command. - - @return #GS_ERROR_NOT_SUPPORTED if not supported on current platform. - @return #GS_ERROR_HANDLE if no console has been started with gs_console_start(). - @return_gs_error_t -*/ -gs_error_t gs_console_stop(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/hexdump.h b/gomspace/libutil/include/gs/util/hexdump.h deleted file mode 100644 index 43a085e5..00000000 --- a/gomspace/libutil/include/gs/util/hexdump.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef GS_UTIL_HEXDUMP_H -#define GS_UTIL_HEXDUMP_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Dump memory as hex numbers and ascii characters. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Dump memory to an output stream. - @param[in] src memory address. - @param[in] len number of bytes to dump. - @param[in] disp_addr display address, used instead of \a src. - @param[in] out output stream. -*/ -void gs_hexdump_to_stream(const void * src, size_t len, const void * disp_addr, FILE* out); - -/** - Dump memory on stdout. - - @param[in] src memory address. - @param[in] len number of bytes to dump. -*/ -static inline void gs_hexdump(const void *src, size_t len) -{ - gs_hexdump_to_stream(src, len, src, stdout); -} - -/** - Dump memory on stdout. - @param[in] src memory address. - @param[in] len number of bytes to dump. - @param[in] disp_addr display address, used instead of \a src. -*/ -static inline void gs_hexdump_addr(const void * src, size_t len, const void * disp_addr) -{ - gs_hexdump_to_stream(src, len, disp_addr, stdout); -} - -#ifdef __cplusplus -} -#endif -#endif - - diff --git a/gomspace/libutil/include/gs/util/linux/argp.h b/gomspace/libutil/include/gs/util/linux/argp.h deleted file mode 100644 index b8eff835..00000000 --- a/gomspace/libutil/include/gs/util/linux/argp.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef GS_UTIL_LINUX_ARGP_H -#define GS_UTIL_LINUX_ARGP_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Extensions to GNU argp parser (convenience functions). -*/ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Wrapper for argp_parse. - - This function will call exit/terminate the process, if parsing fails. - - \a argv may be re-organized. - - @param[in] argp argp struct. - @param[in] argc argument count, i.e. standard argc. - @param[in] argv argument array, i.e. standard argv. - @param[in] flags future use. - @param[out] arg_index first unparsed option (-> argv modified). - @param[in] revision program revision, e.g. 3.0.1-12-g0cf1b59+. -*/ -void gs_argp_parse(const struct argp * argp, - int argc, char ** argv, - unsigned int flags, int * arg_index, - const char * revision); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/command_line.h b/gomspace/libutil/include/gs/util/linux/command_line.h deleted file mode 100644 index d9dbc3a3..00000000 --- a/gomspace/libutil/include/gs/util/linux/command_line.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef GS_UTIL_LINUX_COMMAND_LINE_H -#define GS_UTIL_LINUX_COMMAND_LINE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Command line support. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Command line options for ignoring CTRL-C -*/ -extern const struct argp_child gs_console_command_line_ignore_ctrlc_argp; - -/** - Command line options for adding -h (help). -*/ -const struct argp_child gs_help_command_line_argp; - -/** - Return if ctrl-c ignored on command line. - @return \a true i ctrl-c ignored. -*/ -bool gs_command_line_ignore_ctrlc(void); - -/** - Return program name based on argv[0]. - @param[in] argv expected to be argv[0] amd point to the program name (possibly with full path). - @return program name. -*/ -const char * gs_command_line_program_name(const char * argv); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/can/can.h b/gomspace/libutil/include/gs/util/linux/drivers/can/can.h deleted file mode 100644 index f04b3f83..00000000 --- a/gomspace/libutil/include/gs/util/linux/drivers/can/can.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef GS_UTIL_LINUX_DRIVERS_CAN_CAN_H -#define GS_UTIL_LINUX_DRIVERS_CAN_CAN_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Linux CAN interface. - - @note Only 1 filter/mask can be set, using gs_can_set_standard_filter_mask() or gs_can_set_extended_filter_mask() -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Open and initialize a CAN handle. - @param[in] ifname name of CAN interface. - @param[out] handle opened CAN handle. - @return_gs_error_t -*/ -gs_error_t gs_can_open(const char * ifname, int * handle); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h deleted file mode 100644 index f04cc1f5..00000000 --- a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio.h +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef GS_UTIL_LINUX_DRIVERS_GPIO_H -#define GS_UTIL_LINUX_DRIVERS_GPIO_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - @brief GPIO interface - - GPIO interface provides a generic interface where specific GPIO drivers can be plugged in. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - GomSpace linux driver GPIO get value - - @param[in] gpio The gpio to read - @param[in] value Returned GPIO value (true/false = High/Low) - @param[in] driver_data data to specific driver - - @return_gs_error_t -*/ -typedef gs_error_t (*gs_gpio_get_t)(gs_gpio_t gpio, bool *value, void * driver_data); - -/** - GomSpace linux driver GPIO get value without error check - - @param[in] gpio The gpio to read - @param[in] driver_data data to specific driver - - @return GPIO value (true/false = High/Low) -*/ -typedef bool (*gs_gpio_get_nc_t)(gs_gpio_t gpio, void * driver_data); - -/** - GomSpace linux driver GPIO set value - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @param[in] driver_data data to specific driver - - @return_gs_error_t -*/ -typedef gs_error_t (*gs_gpio_set_t)(gs_gpio_t gpio, bool value, void * driver_data); - -/** - GomSpace linux driver GPIO set value without error check - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @param[in] driver_data data to specific driver -*/ -typedef void (*gs_gpio_set_nc_t)(gs_gpio_t gpio, bool value, void * driver_data); - -/** - GomSpace linux driver initialize GPIO as an external interrupt pin - - @param[in] gpio The gpio to configure - @param[in] conf Configuration of interrupt pin - @param[in] driver_data data to specific driver - - @return_gs_error_t - */ -typedef gs_error_t (*gs_gpio_init_as_interrupt_t)(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data); - - -/** - Every port. - */ -#define GS_GPIO_ALL_PORTS UINT16_MAX - -/** - Every pin. - */ -#define GS_GPIO_ALL_PINS UINT16_MAX - -/** - GPIO driver. - */ -typedef struct { - /** - Function for handling GPIO get. - */ - gs_gpio_get_t get_handler; - /** - Function for handling GPIO get no check. - */ - gs_gpio_get_nc_t get_nc_handler; - /** - Function for handling GPIO set. - */ - gs_gpio_set_t set_handler; - /** - Function for handling GPIO set no check. - */ - gs_gpio_set_nc_t set_nc_handler; - /** - Function for handling GPIO initialize as interrupt. - */ - gs_gpio_init_as_interrupt_t init_as_interrupt_handler; -} gs_gpio_driver_t; - - -/** - GPIO driver entry - */ -typedef struct { - /** - GPIO port, to which the driver is used (if GS_GPIO_ALL_PORTS, then all ports uses this driver). - */ - uint16_t port; - /** - GPIO pin, to which the driver is used (if GS_GPIO_ALL_PINS, then all pins uses this driver). - */ - uint16_t pin; - /** - GPIO driver. - */ - const gs_gpio_driver_t * driver; - /** - Driver specific data. - */ - void * driver_data; -} gs_gpio_driver_entry_t; - -/** - Register a driver. - - A specific driver can be assigned to a port and pin or it can be assigned to all pins and/or all ports. - - The latest registered driver, which fit the GPIO, is the one used. - - @param[in] driver_entry driver and configuration to be registered - @return_gs_error_t - */ -gs_error_t gs_gpio_register_driver(const gs_gpio_driver_entry_t * driver_entry); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h deleted file mode 100644 index 0f95e5aa..00000000 --- a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_sysfs.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_SYSFS_H_ -#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_SYSFS_H_ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - @brief Linux GPIO driver based on sysfs. - This driver needs to be registered in the generic GPIO linux driver @see 'gs/util/linux/drivers/gpio/gpio.h' -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - GPIO sysfs driver data. - - @note Driver takes no driver data, so a NULL pointer is valid -*/ -typedef void * gs_gpio_sysfs_driver_data_t; - -/** - GPIO sysfs driver interface. -*/ -extern const gs_gpio_driver_t gs_gpio_sysfs_driver; - -/** - GPIO sysfs initialize - - @param[in] gpio The gpio to initialize - @param[in] output Direction of pin (True/False = Output/Input) - @param[in] init_value Pin state if configured as output (True/False = High/Low) - @param[in] active_low if set pin is configured as active low (so a gs_gpio_sysfs_set with 1 will actually set value low) - @return_gs_error_t - */ -gs_error_t gs_gpio_sysfs_initialize(gs_gpio_t gpio, bool output, bool init_value, bool active_low); - -/** - GPIO sysfs get value - - @param[in] gpio The gpio to read - @param[in] value Returned GPIO value (true/false = High/Low) - @param[in] driver_data data to driver (not used) - @return_gs_error_t -*/ -gs_error_t gs_gpio_sysfs_get(gs_gpio_t gpio, bool *value, void * driver_data); - -/** - GPIO sysfs get value without error check - - @param[in] gpio The gpio to read - @param[in] driver_data data to driver (not used) - @return GPIO value (true/false = High/Low) -*/ -bool gs_gpio_sysfs_get_nc(gs_gpio_t gpio, void * driver_data); - -/** - GPIO sysfs set value - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @param[in] driver_data data to driver (not used) - @return_gs_error_t -*/ -gs_error_t gs_gpio_sysfs_set(gs_gpio_t gpio, bool value, void * driver_data); - -/** - GPIO sysfs set value without error check - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @param[in] driver_data data to driver (not used) -*/ -void gs_gpio_sysfs_set_nc(gs_gpio_t gpio, bool value, void * driver_data); - -/** - Initialize GPIO sysfs as an external interrupt pin - - @param[in] gpio The gpio to configure - @param[in] conf Configuration of interrupt pin - @param[in] driver_data data to driver (not used) - @return_gs_error_t - */ -gs_error_t gs_gpio_sysfs_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h b/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h deleted file mode 100644 index e61b70a4..00000000 --- a/gomspace/libutil/include/gs/util/linux/drivers/gpio/gpio_virtual.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_VIRTUAL_H_ -#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_GPIO_GPIO_VIRTUAL_H_ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - @brief Linux GPIO driver to be used in unit tests. - This driver needs to be registered in the generic GPIO linux driver @see 'gs/util/linux/drivers/gpio/gpio.h' -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - GPIO virtual driver data. - - @note Driver takes no driver data, so a NULL pointer is valid -*/ -typedef void * gs_gpio_virtual_driver_data_t; - -/** - GPIO virtual driver interface. -*/ -extern const gs_gpio_driver_t gs_gpio_virtual_driver; - -/** - GPIO virtual driver entry, where all ports and pins are routed to virtual driver - */ -extern const gs_gpio_driver_entry_t gs_gpio_virtual_driver_entry_all; - -/** - GPIO virtual initialize - - @param[in] gpio The gpio to initialize - @param[in] output Direction of pin (True/False = Output/Input) - @param[in] value Pin state if configured as output (True/False = High/Low) - @return_gs_error_t - */ -gs_error_t gs_gpio_virtual_initialize(gs_gpio_t gpio, bool output, bool value); - -/** - GPIO virtual get value - - @param[in] gpio The gpio to read - @param[in] value Returned GPIO value (true/false = High/Low) - @param[in] driver_data data to driver (not used) - @return_gs_error_t -*/ -gs_error_t gs_gpio_virtual_get(gs_gpio_t gpio, bool *value, void * driver_data); - -/** - GPIO virtual get value without error check - - @param[in] gpio The gpio to read - @param[in] driver_data data to driver (not used) - @return GPIO value (true/false = High/Low) -*/ -bool gs_gpio_virtual_get_nc(gs_gpio_t gpio, void * driver_data); - -/** - GPIO virtual set value - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @param[in] driver_data data to driver (not used) - @return_gs_error_t -*/ -gs_error_t gs_gpio_virtual_set(gs_gpio_t gpio, bool value, void * driver_data); - -/** - GPIO virtual set value without error check - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @param[in] driver_data data to driver (not used) -*/ -void gs_gpio_virtual_set_nc(gs_gpio_t gpio, bool value, void * driver_data); - -/** - Initialize GPIO virtual as an external interrupt pin - - @param[in] gpio The gpio to configure - @param[in] conf Configuration of interrupt pin - @param[in] driver_data data to driver (not used) - @return_gs_error_t - */ -gs_error_t gs_gpio_virtual_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data); - -/** - Force set a pin - - This sets a pin regardless if it is configured as input, output or interrupt - If the pin is configured as interrupt, the registered ISR's will be called within this function, - if the transition matches (rising/falling) - - @note This function is specific to this driver and is should not be registered. - - @param[in] gpio The gpio to set - @param[in] value GPIO value (true/false = High/Low) - @return_gs_error_t - */ -gs_error_t gs_gpio_virtual_force_set(gs_gpio_t gpio, bool value); - -/** - Get transitions - - This gives the number of transitions ((high -> low) + (low -> high)), - since last time this function was called at this pin. This function resets the counter of the pin. - An even number means, that the pin has the same state as it was initialized to. - - @note This function is specific to this driver and should not be registered - - @param[in] gpio The gpio, of which transitions are given - @param[out] transitions Number of transitions - @return - */ -gs_error_t gs_gpio_virtual_get_transistions(gs_gpio_t gpio, uint32_t * transitions); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h b/gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h deleted file mode 100644 index 858c26a2..00000000 --- a/gomspace/libutil/include/gs/util/linux/drivers/i2c/i2c.h +++ /dev/null @@ -1,198 +0,0 @@ -#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_I2C_I2C_H_ -#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_I2C_I2C_H_ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - @brief Linux I2C plugin driver -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - GomSpace linux driver I2C master transaction. - - @see 'gs/util/drivers/i2c/master.h' - - @param[in] device I2C device - @param[in] addr I2C address - @param[in] tx tx buffer - @param[in] txlen bytes to be sent - @param[out] rx rx buffer - @param[in] rxlen bytes to be received - @param[in] timeout_ms timeout in milliseconds - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (* gs_i2c_master_transaction_t)(uint8_t device, uint8_t addr, const void * tx, size_t txlen, - void * rx, size_t rxlen, int timeout_ms, void * driver_data); - -/** - GomSpace linux driver I2C slave start. - - @see 'gs/util/drivers/i2c/slave.h' - - @param[in] device I2C device - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (* gs_i2c_slave_start_t)(uint8_t device, void * driver_data); - -/** - GomSpace linux driver I2C set rx callback - - @see 'gs/util/drivers/i2c/slave.h' - - @param[in] device I2C device - @param[in] rx rx callback - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (* gs_i2c_slave_set_rx_t)(uint8_t device, gs_i2c_slave_receive_t rx, void * driver_data); - -/** - GomSpace linux driver I2C slave set 'get_rx_buffer' callback. - - @see 'gs/util/drivers/i2c/slave.h' - - @param[in] device I2C device - @param[in] get_rx_buf get_rx_buf callback - @param[in] buf_length length of buffer received by calling callback - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (* gs_i2c_slave_set_get_rx_buf_t)(uint8_t device, gs_i2c_slave_get_rx_buf_t get_rx_buf, size_t buf_length, void * driver_data); - -/** - GomSpace linux driver I2C slave set slave response. - - @see 'gs/util/drivers/i2c/slave.h' - - @param[in] device I2C device - @param[in] tx tx buffer - @param[in] tx_length bytes to be send - @param[in] driver_data data to specific driver - @return_gs_error_t -*/ -typedef gs_error_t (* gs_i2c_slave_set_response_t)(uint8_t device, const uint8_t * tx, size_t tx_length, void * driver_data); - -/** - Every I2C device ([0 : 254]). - */ -#define GS_I2C_ALL_DEVICES 255 - -/** - Every I2C address (0 : 127]). - */ -#define GS_I2C_ALL_ADDR 255 - -/** - I2C master driver. - */ -typedef struct { - /** - Function for handling master transactions. - */ - gs_i2c_master_transaction_t master_transaction_handler; -} gs_i2c_master_driver_t; - - -/** - I2C master driver entry - */ -typedef struct { - /** - I2C device, to which the driver is used (if GS_I2C_ALL_DEVICES, then all devices uses this driver). - */ - uint8_t device; - /** - I2C addr, to which the driver is used (if GS_I2C_ALL_ADDR, then all addr on given device uses this driver). - */ - uint8_t addr; - /** - I2C master driver. - */ - const gs_i2c_master_driver_t * driver; - /** - Driver specific data. - */ - void * driver_data; -} gs_i2c_master_driver_entry_t; - - -/** - I2C slave driver - */ -typedef struct { - /** - Function for handling slave start. - */ - gs_i2c_slave_start_t start_handler; - /** - Function for handling the 'setting of rx callback'. - */ - gs_i2c_slave_set_rx_t set_rx_handler; - /** - Function for handling setting of an 'rx buff get' function. - */ - gs_i2c_slave_set_get_rx_buf_t set_get_rx_buf_handler; - /** - Function for handling 'set response'. - */ - gs_i2c_slave_set_response_t set_response_handler; -} gs_i2c_slave_driver_t; - - -/** - I2C slave driver entry. - */ -typedef struct { - /** - I2C device, to which the driver is used (if GS_I2C_ALL_DEVICES, then all devices uses this driver). - */ - uint8_t device; - /** - I2C slave driver. - */ - const gs_i2c_slave_driver_t * driver; - /** - Driver specific data. - */ - void * driver_data; -} gs_i2c_slave_driver_entry_t; - - -/** - Register a master driver. - - A specific driver can be assigned to a specific address and device - or it can be registered to every address on a device or every address on every device. - - The latest registered driver, which fit the device an address, is the one used. - - @param[in] driver_entry driver and configuration to be registered - @return_gs_error_t - */ -gs_error_t gs_i2c_master_register_driver(const gs_i2c_master_driver_entry_t * driver_entry); - -/** - Register a slave driver - - A specific driver can be assigned to a specific device or a driver can be assigned to every device. - - The latest registered driver, which fit the device, is the one used. - - @param[in] driver_entry driver and configuration to be registered - @return_gs_error_t - */ -gs_error_t gs_i2c_slave_register_driver(const gs_i2c_slave_driver_entry_t * driver_entry); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h b/gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h deleted file mode 100644 index 24e5ae22..00000000 --- a/gomspace/libutil/include/gs/util/linux/drivers/spi/spi.h +++ /dev/null @@ -1,175 +0,0 @@ -#ifndef LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_SPI_SPI_H_ -#define LIB_LIBUTIL_INCLUDE_GS_UTIL_LINUX_DRIVERS_SPI_SPI_H_ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Linux SPI plugin driver -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Linux driver SPI master transactions. - - @see 'gs/util/drivers/spi/master.h' - - @param[in] slave SPI slave - @param[in] trans Pointer to transactions - @param[in] count Number of transactions (rx and/or tx) to complete - @param[in] timeout_ms timeout in milliseconds, primarily for locking the SPI device. - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (*gs_spi_master_transactions_t)(uint8_t slave, gs_spi_master_trans_t *trans, size_t count, - int timeout_ms, void * driver_data); - -/** - Linux driver SPI slave start. - - @see 'gs/util/drivers/spi/slave.h' - - @param[in] device SPI device (handle) - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (* gs_spi_slave_start_t)(uint8_t device, void * driver_data); - -/** - Linux driver SPI set rx callback - - @see 'gs/util/drivers/spi/slave.h' - - @param[in] device SPI device (handle). - @param[in] rx Rx callback. - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (* gs_spi_slave_set_rx_t)(uint8_t device, gs_spi_slave_receive_t rx, void * driver_data); - -/** - Linux driver SPI slave set slave response. - - @see 'gs/util/drivers/spi/slave.h' - - @param[in] device SPI device (handle). - @param[in] offset offset (in bytes) for the response, counted from start of request, i.e. offset of 2 means data will be sent as the 3rd byte. - @param[in] tx pointer to data. NOTE: data is not copied due to performance, so data must stay valid until the response has been sent. - @param[in] size size of data. - @param[in] driver_data data to specific driver - @return_gs_error_t - */ -typedef gs_error_t (* gs_spi_slave_set_response_t)(uint8_t device, size_t offset, const uint8_t * tx, size_t size, void * driver_data); - -/** - Every SPI slave ([0 : 254]). - */ -#define GS_SPI_ALL_SLAVES 255 - -/** - Every SPI device (0 : 254]). - */ -#define GS_SPI_ALL_DEVICES 255 - - -/** - SPI master driver. - */ -typedef struct { - /** - Function for handling master transactions. - */ - gs_spi_master_transactions_t master_transactions_handler; -} gs_spi_master_driver_t; - - -/** - SPI master driver entry - */ -typedef struct { - /** - SPI slave, to which the driver is used (if #GS_SPI_ALL_SLAVES, then all slaves uses this driver). - */ - uint8_t slave; - /** - SPI master driver. - */ - const gs_spi_master_driver_t * driver; - /** - Driver specific data. - */ - void * driver_data; -} gs_spi_master_driver_entry_t; - - -/** - SPI slave driver - */ -typedef struct { - /** - Function for handling slave start. - */ - gs_spi_slave_start_t start_handler; - /** - Function for handling the 'setting of rx callback'. - */ - gs_spi_slave_set_rx_t set_rx_handler; - /** - Function for handling 'set response'. - */ - gs_spi_slave_set_response_t set_response_handler; -} gs_spi_slave_driver_t; - - -/** - SPI slave driver entry. - */ -typedef struct { - /** - SPI device, to which the driver is used (if #GS_SPI_ALL_DEVICES, then all devices uses this driver). - */ - uint8_t device; - /** - SPI slave driver. - */ - const gs_spi_slave_driver_t * driver; - /** - Driver specific data. - */ - void * driver_data; -} gs_spi_slave_driver_entry_t; - - -/** - Register a master driver. - - A specific driver can be assigned to a slave or it can be assigned to every slave. - - The latest registered driver, which fit the slave, is the one used. - - @param[in] driver_entry driver and configuration to be registered - @return_gs_error_t - */ -gs_error_t gs_spi_master_register_driver(const gs_spi_master_driver_entry_t * driver_entry); - -/** - Register a slave driver - - A specific driver can be assigned to a specific device or a driver can be assigned to every device. - - The latest registered driver, which fit the device, is the one used. - - @param[in] driver_entry driver and configuration to be registered - @return_gs_error_t - */ -gs_error_t gs_spi_slave_register_driver(const gs_spi_slave_driver_entry_t * driver_entry); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/exitcode.h b/gomspace/libutil/include/gs/util/linux/exitcode.h deleted file mode 100644 index 35e89f06..00000000 --- a/gomspace/libutil/include/gs/util/linux/exitcode.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef GS_UTIL_LINUX_EXITCODE_H -#define GS_UTIL_LINUX_EXITCODE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - "standard" Linux exit codes. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Program completed ok (from stdlib.h) -*/ -#define GS_EXITCODE_OK EXIT_SUCCESS - -/** - Program terminated due to an error (from stdlib.h). -*/ -#define GS_EXITCODE_ERROR EXIT_FAILURE - -/** - Program terminated due to invalid usage, eg argument (from sysexits.h). -*/ -#define GS_EXITCODE_USAGE EX_USAGE - -/** - Program terminated due to a signal (from [TLDP](http://www.tldp.org/LDP/abs/html/exitcodes.html)). -*/ -#define GS_EXITCODE_SIGNAL(sig) (128 + sig) - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/function.h b/gomspace/libutil/include/gs/util/linux/function.h deleted file mode 100644 index b918993d..00000000 --- a/gomspace/libutil/include/gs/util/linux/function.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef GS_UTIL_LINUX_FUNCTION_H -#define GS_UTIL_LINUX_FUNCTION_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Function interface - invokes a function by name. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Function prototype. - @param[in] arg argument provided to gs_function_invoke(). - @return_gs_error_t -*/ -typedef gs_error_t (*gs_function_t)(void * arg); - -/** - Register \a function by name. - - @param[in] short_name short name for function, used by gs_function_invoke() to find function to invoke. - @param[in] long_name long name (unique) for function, used by gs_function_invoke() to find function to invoke. - @param[in] function function to be invoked by gs_function_invoke() - @return #GS_ERROR_FULL if registry is full. - @return_gs_error_t -*/ -gs_error_t gs_function_register(const char * short_name, const char * long_name, gs_function_t function); - -/** - Invoke \a function by name. - - The return value is from the registered function, except for #GS_ERROR_NOT_IMPLEMENTED. - - @param[in] name registered function name. - @param[in] arg argument for function. - @return #GS_ERROR_NOT_IMPLEMENTED if the \a name isn't found. - @return_gs_error_t -*/ -gs_error_t gs_function_invoke(const char * name, void * arg); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/rtc.h b/gomspace/libutil/include/gs/util/linux/rtc.h deleted file mode 100644 index fa063f76..00000000 --- a/gomspace/libutil/include/gs/util/linux/rtc.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef GS_UTIL_LINUX_RTC_H -#define GS_UTIL_LINUX_RTC_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Real Time Clock interface (linux). -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Register Real Time Clock interface. - @note Setting the RTC will normally require special permission. - @param[in] get if true, get will be registered. - @param[in] set if true, set will be registered. - @return_gs_error_t -*/ -gs_error_t gs_rtc_register_linux(bool get, bool set); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/signal.h b/gomspace/libutil/include/gs/util/linux/signal.h deleted file mode 100644 index b3c280e7..00000000 --- a/gomspace/libutil/include/gs/util/linux/signal.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef GS_UTIL_LINUX_SIGNAL_H -#define GS_UTIL_LINUX_SIGNAL_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Signal helpers - catch and ignore. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Standard Linux signal handler. -*/ -typedef void (*gs_signal_handler)(int signal, siginfo_t *si, void *context); - -/** - Register/catch signal and invoke handler. - @param[in] signal signal to catch. - @param[in] handler signal handler. If \a handler is NULL, a default handler will be invoked, which calls exit(#GS_EXITCODE_SIGNAL + signal). - @return_gs_error_t -*/ -gs_error_t gs_signal_catch(int signal, gs_signal_handler handler); - -/** - Ignore signal - @param[in] signal signal to ignore. - @return_gs_error_t -*/ -gs_error_t gs_signal_ignore(int signal); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/linux/sysfs_helper.h b/gomspace/libutil/include/gs/util/linux/sysfs_helper.h deleted file mode 100644 index ad05a6fe..00000000 --- a/gomspace/libutil/include/gs/util/linux/sysfs_helper.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef GS_UTIL_SYSFS_HELPER_H -#define GS_UTIL_SYSFS_HELPER_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Sysfs interface. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Sysfs write (GPIO). -*/ -gs_error_t gs_sysfs_write_file(const char *path, const char *value); - -/** - Sysfs read (GPIO). -*/ -gs_error_t gs_sysfs_read_file(const char *path, char *value, size_t len); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/log.h b/gomspace/libutil/include/gs/util/log.h deleted file mode 100644 index 13659adf..00000000 --- a/gomspace/libutil/include/gs/util/log.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef GS_UTIL_LOG_H -#define GS_UTIL_LOG_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Log interface. - - The log interface supports logging to different group. - - Logging is done through groups (domains), which can runtime be re-configured with level. -*/ -#include - -#endif diff --git a/gomspace/libutil/include/gs/util/log/appender/appender.h b/gomspace/libutil/include/gs/util/log/appender/appender.h deleted file mode 100644 index 29a0c140..00000000 --- a/gomspace/libutil/include/gs/util/log/appender/appender.h +++ /dev/null @@ -1,189 +0,0 @@ -#ifndef GS_UTIL_LOG_APPENDER_APPENDER_H -#define GS_UTIL_LOG_APPENDER_APPENDER_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Log Appender interface. - - The log appender interface supports logging to different "stores". - Logging is done through groups, which can be registered to different log appenders. - Each log appender has it's own filter (level mask). - Examples of log appenders could be: console, file, vmem, ... -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/** - Log appender (forward declaration) - All log groups log to one or more appenders. The Log appender is responsible - for putting the actual log data to a store/console or some other log medium. -*/ -typedef struct gs_log_appender gs_log_appender_t; - -/** - Log appender record iterator callback function - - @param[in] ctx context data for iterator. - @param[in] level log level of record being iterated - @param[in] ts timestamp of record being iterated - @param[in] group group string (zero terminated) of record being iterated - @param[in] msg message string (zero terminated) of record being iterated - @return true/false: Return false to discontinue iteration. -*/ -typedef bool (*gs_log_record_iterator_t)(void *ctx, gs_log_level_t level, const gs_timestamp_t *ts, const char *group, const char *msg); - -/** - Log appender driver interface -*/ -typedef struct { - /** appender init function */ - gs_error_t (*init)(gs_log_appender_t *appender); - /** appender function */ - void (*append)(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va); - /** appender function for isr context */ - void (*append_isr)(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va); - /** appender function for getting appender details string */ - void (*info)(gs_log_appender_t *appender, char * info_str, uint8_t str_size); - /** appender function for iterating stored appenders log history */ - void (*hist)(gs_log_appender_t *appender, void * ctx, gs_log_record_iterator_t iter); - /** appender function for clearing it's log history */ - void (*clear)(gs_log_appender_t *appender); - /** appender function for flushing cached log entries to it's store. - This is only relevant for appenders implementing a log cache. */ - void (*flush)(gs_log_appender_t *appender); -} gs_log_appender_driver_t; - -/** - Log appender - All log groups log to one or more appenders. The Log appender is responsible - for putting the actual log data to a store/console or some other log medium. -*/ -struct gs_log_appender { - /** Name of the appender */ - const char * name; - /** appender driver interface */ - const gs_log_appender_driver_t * drv; - /** appender driver configuration data */ - const void * drv_config; - /** appender driver data - dynamic/internal data */ - void * drv_data; - /** appender level mask */ - uint8_t mask; -}; - -/** - Register an appender for the given log group. - All logging, where the mask matches the groups \a level_mask, will be forwarded to this appender. - - @param[in] group_name Name of the group. - @param[in] appender_name Name of appender to register for this group. - @return gs_error_t -*/ -gs_error_t gs_log_group_register_appender(const char * group_name, const char * appender_name); - -/** - Log appender iterator callback function - - @param[in] ctx context data for iterator. - @param[in] appender log appender being iterated - - @return true/false: Return false to discontinue iteration. -*/ -typedef bool (*gs_log_appender_iterator_t)(void *ctx, gs_log_appender_t * appender); - -/** - Iterate all or specific log appender(s). - - @param[in] name name of log appender, or NULL/\"all\" for all groups. - @param[in] ctx user context data. - @param[in] iter iterator, return \a true to continue, \a false to break iteration. - @return_gs_error_t -*/ -gs_error_t gs_log_appender_iterate(const char * name, void * ctx, gs_log_appender_iterator_t iter); - -/** - Iterate registered appenders for a specific group. - - @param[in] group log group to iterate appenders on. - @param[in] ctx user context data. - @param[in] iter appender iterator, return \a true to continue, \a false to break iteration. - @return gs_error_t -*/ -gs_error_t gs_log_group_appender_iterate(gs_log_group_t * group, void * ctx, gs_log_appender_iterator_t iter); - -/** - Register log appender. - - The log appender will be registered and initialized (if the appender has en init function, see #gs_log_appender_driver_t) - - The appender will not be attached to any log groups. For registering an appender to a group, use gs_log_group_register_appender() - - @param[in] appender appender - must stay in memory during the life-time of the application - @return_gs_error_t -*/ -gs_error_t gs_log_appender_register(gs_log_appender_t *appender); - -/** - Add log appender(s). - - The log appender will be registered and initialized (if the appender has en init function, see #gs_log_appender_driver_t) - - The appender will not be attached to any log groups. For registering an appender to a group, use gs_log_group_register_appender() - - @deprecated impossible to determine which appender fails, use gs_log_appender_register() - @param[in] appenders array of appender(s) - must stay in memory during the life-time of the application - @param[in] count array count - number of appenders. - @return_gs_error_t -*/ -gs_error_t gs_log_appender_add(gs_log_appender_t *appenders, uint16_t count); - -/** - Set log appender level mask. - - @param[in] appender_name log appender name - @param[in] mask level mask to set. - @return_gs_error_t -*/ -gs_error_t gs_log_appender_set_level_mask(const char * appender_name, uint8_t mask); - -/** - Get log appender level mask. - - @param[in] appender_name log appender name - @param[out] mask returned current level mask. - @return_gs_error_t -*/ -gs_error_t gs_log_appender_get_level_mask(const char * appender_name, uint8_t *mask); - -/** - Iterate log history for all or specific log appender. - - @param[in] name name of log appender, or NULL/\"all\" for all appenders. - @param[in] ctx user context data for iterator. - @param[in] iter iterator, return \a true to continue, \a false to break iteration. - @return gs_error_t -*/ -gs_error_t gs_log_appender_history_iterate(const char * name, void * ctx, gs_log_record_iterator_t iter); - -/** - Flush all log appenders data to storage. - - This will call the flush API (if implemented) for all log appenders - available on the system. This should be called on regular basis from - a system thread to ensure all cached data is correctly flushed to their - stores. - - @return gs_error_t -*/ -gs_error_t gs_log_appender_flush_all(); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/log/appender/console.h b/gomspace/libutil/include/gs/util/log/appender/console.h deleted file mode 100644 index 37f63fc5..00000000 --- a/gomspace/libutil/include/gs/util/log/appender/console.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef GS_UTIL_LOG_APPENDER_CONSOLE_H -#define GS_UTIL_LOG_APPENDER_CONSOLE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Console log appender - logs to stdout. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Log appender for console - - This log appender is the standard appender which is always available - on any system. The appender should be registered to the root group, - in order to get console/stdio logs. -*/ -extern gs_log_appender_t gs_log_appender_console; - -/** - Log appender for console callback type - - This callback function can be used for registering a user defined logger function if - the default can not be used for the given system. - - @param[in] appender pointer to the console appender. - @param[in] level log level for log message - @param[in] group log group for log message - @param[in] ts timestamp for log message - @param[in] format format of message in printf style - @param[in] va variable argument list in printf style - - @return void -*/ -typedef void (*gs_log_appender_console_cb_t)(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va); - -/** - Set Log appender for console callback - - When set, the given callback is called instead of the default console log function. - To revert back to the default console log function, call this function with NULL as parameter. - - @param[in] cb callback to use for console logging. - - @return gs_error_t -*/ -gs_error_t gs_log_appender_console_set_cb(gs_log_appender_console_cb_t cb); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/log/appender/simple_file.h b/gomspace/libutil/include/gs/util/log/appender/simple_file.h deleted file mode 100644 index ab2537a6..00000000 --- a/gomspace/libutil/include/gs/util/log/appender/simple_file.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef GS_UTIL_LOG_APPENDER_SIMPLE_FILE_H -#define GS_UTIL_LOG_APPENDER_SIMPLE_FILE_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Simple log-file appender. -*/ -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Simple File Log Appender driver configuration -*/ -typedef struct gs_log_appender_simple_file_config { - /** - Name of file to create/write logs to - */ - const char *filename; - /** - Truncate the file, when opening the log file. - */ - bool truncate; - /** - Uee local time stamps when logging to log file, otherwise UTC. - */ - bool use_local_time; -} gs_log_appender_simple_file_config_t; - -/** - Log appender for file. -*/ -extern const gs_log_appender_driver_t gs_log_appender_simple_file_driver; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/log/log.h b/gomspace/libutil/include/gs/util/log/log.h deleted file mode 100644 index 9781bb09..00000000 --- a/gomspace/libutil/include/gs/util/log/log.h +++ /dev/null @@ -1,853 +0,0 @@ -#ifndef GS_UTIL_LOG_LOG_H -#define GS_UTIL_LOG_LOG_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Log interface. - - Logging is done through groups (domains), where the level mask can be changed runtime. -*/ - -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Name of the root log group -*/ -#define GS_LOG_GROUP_ROOT "root" - -/** - Log levels. - - The levels can easily be mapped to standard syslog severity levels (https://en.wikipedia.org/wiki/Syslog). -*/ -typedef enum { - /** - Trace (more detailed than \a debug). - - syslog: maps to \a debug (or \a trace if supported). - */ - GS_LOG_TRACE = 0, - /** - Debug. - - syslog: maps to \a debug. - */ - GS_LOG_DEBUG = 1, - /** - Informational. - - syslog: maps to \a informational. - */ - GS_LOG_INFO = 2, - /** - Normal but significant conditions. - - syslog: maps to \a notice. - */ - GS_LOG_NOTICE = 3, - /** - Warning. - - syslog: maps to \a warning. - */ - GS_LOG_WARNING = 4, - /** - Error. - - syslog: maps to \a error. - */ - GS_LOG_ERROR = 5, - - /** - Trace (more detailed than \a debug). - @deprecated use #GS_LOG_TRACE - */ - LOG_TRACE = GS_LOG_TRACE, - /** - Debug. - @deprecated use #GS_LOG_DEBUG - */ - LOG_DEBUG = GS_LOG_DEBUG, - /** - Informational. - @deprecated use #GS_LOG_INFO - */ - LOG_INFO = GS_LOG_INFO, - /** - Normal but significant conditions. - @deprecated use #GS_LOG_NOTICE - */ - LOG_NOTICE = GS_LOG_NOTICE, - /** - Warning. - @deprecated use #GS_LOG_WARNING - */ - LOG_WARNING = GS_LOG_WARNING, - /** - Error. - @deprecated use #GS_LOG_ERROR - */ - LOG_ERROR = GS_LOG_ERROR, -} gs_log_level_t; - -/** - Log categories. - - The category is a way of grouping information about which sub-systems have logged. It is primarily used in the \a - telemetry table, to indicate what sub-systems have logged an \a error or \a warning - indicating a possible problem. - - Up to 32 categories are supported (stored in a uint32). - - Categories should be unique within a single node. However, nothing happens if categories clashes - it will only be more difficult to determine what part of the system logged. - - Standard categories are defined from #GS_LOG_CAT_1 and up. Products or mission specific software should start from #GS_LOG_CAT_32 and down. -*/ -typedef enum { - //! Standard, used for #GS_LOG_CAT_DEFAULT - GS_LOG_CAT_1 = 1 << 0, - //! Standard, used for #GS_LOG_CAT_DRIVER - GS_LOG_CAT_2 = 1 << 1, - //! Standard, used for #GS_LOG_CAT_CSP - GS_LOG_CAT_3 = 1 << 2, - //! Standard, used for #GS_LOG_CAT_PARAM - GS_LOG_CAT_4 = 1 << 3, - //! Standard, used for #GS_LOG_CAT_FILE_SYSTEM - GS_LOG_CAT_5 = 1 << 4, - //! Standard, used for #GS_LOG_CAT_COMMAND - GS_LOG_CAT_6 = 1 << 5, - //! Standard, used for #GS_LOG_CAT_HK - GS_LOG_CAT_7 = 1 << 6, - //! Standard, used for #GS_LOG_CAT_FP - GS_LOG_CAT_8 = 1 << 7, - //! Standard, used for #GS_LOG_CAT_ADCS - GS_LOG_CAT_9 = 1 << 8, - GS_LOG_CAT_10 = 1 << 9, - GS_LOG_CAT_11 = 1 << 10, - GS_LOG_CAT_12 = 1 << 11, - GS_LOG_CAT_13 = 1 << 12, - GS_LOG_CAT_14 = 1 << 13, - GS_LOG_CAT_15 = 1 << 14, - GS_LOG_CAT_16 = 1 << 15, -#if (__AVR__ == 0) - GS_LOG_CAT_17 = 1 << 16, - GS_LOG_CAT_18 = 1 << 17, - GS_LOG_CAT_19 = 1 << 18, - GS_LOG_CAT_20 = 1 << 19, - GS_LOG_CAT_21 = 1 << 20, - GS_LOG_CAT_22 = 1 << 21, - GS_LOG_CAT_23 = 1 << 22, - GS_LOG_CAT_24 = 1 << 23, - GS_LOG_CAT_25 = 1 << 24, - GS_LOG_CAT_26 = 1 << 25, - GS_LOG_CAT_27 = 1 << 26, - GS_LOG_CAT_28 = 1 << 27, - GS_LOG_CAT_29 = 1 << 28, - GS_LOG_CAT_30 = 1 << 29, - GS_LOG_CAT_31 = 1 << 30, - //! Product or mission specific - start here and down - GS_LOG_CAT_32 = 1 << 31, -#endif -} gs_log_category_t; - -/** - @defgroup reserved_log_categories Reserved/assigned log categories. - These categories are assigned/reserved for certain sub-systems. - @{ -*/ - /** - Default, used if nothing else fits. - */ -#define GS_LOG_CAT_DEFAULT GS_LOG_CAT_1 - /** - Driver layer. - */ -#define GS_LOG_CAT_DRIVER GS_LOG_CAT_2 - /** - CSP. - */ -#define GS_LOG_CAT_CSP GS_LOG_CAT_3 - /** - Parameter system. - */ -#define GS_LOG_CAT_PARAM GS_LOG_CAT_4 - /** - File system. - */ -#define GS_LOG_CAT_FILE_SYSTEM GS_LOG_CAT_5 - /** - Command framework and execution. - */ -#define GS_LOG_CAT_COMMAND GS_LOG_CAT_6 - /** - Housekeeping System. - */ -#define GS_LOG_CAT_HK GS_LOG_CAT_7 - /** - Flight Planner. - */ -#define GS_LOG_CAT_FP GS_LOG_CAT_8 - /** - ADCS - */ -#define GS_LOG_CAT_ADCS GS_LOG_CAT_9 -/** @} */ - -struct gs_log_list; /* forward declared private log list struct */ -/** - Log list type (private) - - Private gs_log_list type. -*/ -typedef struct gs_log_list gs_log_list_t; - -/** - Log group. - All logs are logged to a \a group. The group contains the current log level mask, - which controls whether the log is carried through or not. -*/ -typedef struct { - /** - Name of log group. - */ - const char * name; - /** - Category, see #gs_log_category_t. - */ - uint32_t category; - /** - Current level mask, see #gs_log_level_t. - */ - uint8_t mask; - /** - Is group additive, if \a true (default) logging will be done on both root appenders and this groups appenders - if \a false, logging will only be done to this groups appenders. - */ - bool additivity; - /** - Private list of appenders. - */ - gs_log_list_t * appenders; -#if (__AVR__) - uint16_t dummy_align; -#endif -} gs_log_group_t; - -/** - Log masks (levels converted to mask). - @{ -*/ -/** - Trace level enabled. -*/ -#define GS_LOG_TRACE_MASK (1 << GS_LOG_TRACE) -/** - Debug level enabled. -*/ -#define GS_LOG_DEBUG_MASK (1 << GS_LOG_DEBUG) -/** - Info level enabled. -*/ -#define GS_LOG_INFO_MASK (1 << GS_LOG_INFO) -/** - Notice level enabled. -*/ -#define GS_LOG_NOTICE_MASK (1 << GS_LOG_NOTICE) -/** - Warning level enabled. -*/ -#define GS_LOG_WARNING_MASK (1 << GS_LOG_WARNING) -/** - Error level enabled. -*/ -#define GS_LOG_ERROR_MASK (1 << GS_LOG_ERROR) -/** - All levels enabled. -*/ -#define GS_LOG_ALL_MASK (GS_LOG_TRACE_MASK | GS_LOG_DEBUG_MASK | GS_LOG_INFO_MASK | GS_LOG_NOTICE_MASK | GS_LOG_WARNING_MASK | GS_LOG_ERROR_MASK) -/** - Default levels enabled - #GS_LOG_ERROR, #GS_LOG_WARNING and #GS_LOG_NOTICE. -*/ -#define GS_LOG_DEFAULT_MASK (GS_LOG_ERROR_MASK | GS_LOG_WARNING_MASK | GS_LOG_NOTICE_MASK) -/** - Trace level enabled. - @deprecated use #GS_LOG_TRACE_MASK -*/ -#define LOG_TRACE_MASK GS_LOG_TRACE_MASK -/** - Debug level enabled. - @deprecated use #GS_LOG_DEBUG_MASK -*/ -#define LOG_DEBUG_MASK GS_LOG_DEBUG_MASK -/** - Info level enabled. - @deprecated use #GS_LOG_INFO_MASK -*/ -#define LOG_INFO_MASK GS_LOG_INFO_MASK -/** - Notice level enabled. - @deprecated use #GS_LOG_NOTICE_MASK -*/ -#define LOG_NOTICE_MASK GS_LOG_NOTICE_MASK -/** - Warning level enabled. - @deprecated use #GS_LOG_WARNING_MASK -*/ -#define LOG_WARNING_MASK GS_LOG_WARNING_MASK -/** - Error level enabled. - @deprecated use #GS_LOG_ERROR_MASK -*/ -#define LOG_ERROR_MASK GS_LOG_ERROR_MASK -/** - All levels enabled. - @deprecated use #GS_LOG_ALL_MASK -*/ -#define LOG_ALL_MASK GS_LOG_ALL_MASK -/** - Default levels enabled - #GS_LOG_ERROR, #GS_LOG_WARNING and #GS_LOG_NOTICE. - @deprecated use #GS_LOG_DEFAULT_MASK -*/ -#define LOG_DEFAULT_MASK GS_LOG_DEFAULT_MASK -/**@}*/ - -/** - Define/Create a log group. - - @note name clash: This defines a variable, which potentially is \a global, meaning possibility of name clashes. Therefore log group should always - be prefixed with something that makes it fairly unique, i.e. component name. Example: gs_a3200dock_log - log group used by liba3200dock library. - - @param[in] group name of variables created. See note above about name clash. - @param[in] name_in display name - @param[in] cat_in log group category - @param[in] level_mask log level mask. -*/ -#define GS_LOG_GROUP(group, name_in, cat_in, level_mask) \ - gs_log_group_t group##_s = {.name = name_in, .category = cat_in, \ - .mask = level_mask, .additivity = true, \ - .appenders = NULL}; \ - gs_log_group_t * group = &group##_s - -/** - Define log group with initial mask for \a print and \a store. - - @note name clash: This defines a variable, which potentially is \a global, meaning possibility of name clashes. Therefore log group should always - be prefixed with something that makes it fairly unique, i.e. component name. Example: gs_a3200dock_log - log group used by liba3200dock library. - - @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(...) instead. - - @param[in] group name of variables created. See note above about name clash. - @param[in] name_in display name - @param[in] print_mask enable mask for \a print. - @param[in] store_mask enable mask for \a store. -*/ -#define LOG_GROUP_MASKED(group, name_in, print_mask, store_mask) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, (print_mask | store_mask)) - -/** - Declare log group as external (defined else where). - - @param[in] group the log group variable defined elsewhere. -*/ -#define GS_LOG_GROUP_EXTERN(group) extern gs_log_group_t * group - -/** - Define log group - levels are #GS_LOG_DEFAULT_MASK - - @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(..) instead. -*/ -#define LOG_GROUP(group, name_in) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, LOG_DEFAULT_MASK) - -/** - Define verbose log group - all levels are enabled (#GS_LOG_ALL_MASK) - - @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(..) instead. -*/ -#define LOG_GROUP_VERBOSE(group, name_in) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, LOG_ALL_MASK) - -/** - Define silent log group - all levels are disabled. - - @deprecated This MACRO is no longer supported, use #GS_LOG_GROUP(..) instead. -*/ -#define LOG_GROUP_SILENT(group, name_in) GS_LOG_GROUP(group, name_in, GS_LOG_CAT_DEFAULT, 0) - -/** - Declare log group as external (defined else where). - - @deprecated use #GS_LOG_GROUP_EXTERN(...) instead. -*/ -#define LOG_GROUP_EXTERN(group) GS_LOG_GROUP_EXTERN(group) - -/** - Default log group. - This can be overridden by a define -*/ -extern gs_log_group_t * LOG_DEFAULT; - -/** - Initializes the log system. - - @param[in] with_console_appender Enable/Disable console log appender - @return_gs_error_t -*/ -gs_error_t gs_log_init(bool with_console_appender); - -/** - Set log group level mask. - - @param[in] group_name log group name - @param[in] mask level mask to set. - @return_gs_error_t -*/ -gs_error_t gs_log_group_set_level_mask(const char * group_name, uint8_t mask); - -/** - Get log group level mask. - - @param[in] group_name log group name - @param[out] mask returned current level mask. - @return_gs_error_t -*/ -gs_error_t gs_log_group_get_level_mask(const char * group_name, uint8_t *mask); - -/** - Log group iterator callback function - - @param[in] ctx context data for iterator. - @param[in] group log group being iterated. - - @return true/false: Return false to discontinue iteration. -*/ -typedef bool (*gs_log_group_iterator_t)(void *ctx, gs_log_group_t * group); - -/** - Iterate all or specific log group(s). - - @param[in] group_name name of log group, or NULL/\"all\" for all groups. - @param[in] ctx user context data. - @param[in] iter iterator, return \a true to continue, \a false to break iteration. - @return_gs_error_t -*/ -gs_error_t gs_log_group_iterate(const char * group_name, void * ctx, gs_log_group_iterator_t iter); - -/** - Register a log group in the log system. - - The log group will be added to a system wide list of log groups, enabling list and set of level. - - @note The group must remain valid during the life-time of the application. - - @param[in] group The log group to be added to the system. - @return_gs_error_t -*/ -gs_error_t gs_log_group_register(gs_log_group_t *group); - -/** - Register a log group in the log system. - - @note The group must stay in memory during the life-time of the application - @see gs_log_group_register() - @param[in] group The log group to be added to the system. - @return_gs_error_t -*/ -static inline gs_error_t gs_log_group_add(gs_log_group_t *group) -{ - return gs_log_group_register(group); -} - -/** - Checks if a level is enabled on a log group - - @param[in] group The log group to check. - @param[in] level The log level to check if it's set on the group. - @return bool (true if enabled / false if not enabled) -*/ -bool gs_log_group_is_level_enabled(gs_log_group_t *group, gs_log_level_t level); - -/** - Convert string to log level. - - @param[in] str log level. - @param[out] return_level converted log level. - @return_gs_error_t -*/ -gs_error_t gs_log_string_to_level(const char * str, gs_log_level_t * return_level); - -/** - Convert level to single character. - - @param[in] level log level - @return single character representing the \a level. -*/ -char gs_log_level_to_char(gs_log_level_t level); - - -/** - Register Log commands. - @return_gs_error_t -*/ -gs_error_t gs_log_register_commands(void); - -/** - Generic log. - @note This function should not be called directly, use log macros. - - @param level log level - @param group log group. If NULL, the \a default log group will be used. - @param format Format string (printf style). -*/ -void gs_log(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) __attribute__ ((format (__printf__, 3, 4))); - -/** - Generic log from ISR. - @note This function should not be called directly, use log macros. - - @param level log level - @param group log group. If NULL, the \a default log group will be used. - @param format Format string (printf style). -*/ -void gs_log_isr(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) __attribute__ ((format (__printf__, 3, 4))); - -/** - Generic log (va_list). - @note This function should not be called directly, use log macros. - - @param level log level - @param group log group. If NULL, the \a default log group will be used. - @param format Format string (printf style). - @param args arguments for \a format. -*/ -void gs_log_va(gs_log_level_t level, gs_log_group_t * group, const char * format, va_list args); - -/** - Enable/disable color in \a print logs. - Default is \a enabled/true. - - @param[in] color \a true to enable color, \a false disable color. -*/ -void gs_log_set_print_color(bool color); - -/** - Level to color (begin). - - @param[in] level log level. - @return color string. -*/ -const char * gs_log_level_to_color_begin(gs_log_level_t level); - -/** - Level to color (end). - - @return color string. -*/ -const char * gs_log_level_to_color_end(void); - -/** - Take a level as input an create a level mask enabling all - levels with priority >= level. - - If level is e.g. LOG_INFO, the mask will enable Error, Warn & Info. - - * @param level the log level. - * @return level mask - */ -uint8_t gs_log_level_to_mask(gs_log_level_t level); - -/** - Convert string to log mask. - - Format: [+-]level[,[+-]level] - - + add level, - remove level. - - @param[in] str log mask - @param[in] current_mask current mask, used when input format contains + or -. - @param[out] return_mask converted log mask. - @return_gs_error_t -*/ -gs_error_t gs_log_string_to_mask(const char *str, uint8_t current_mask, uint8_t * return_mask); - -#if !(__DOXYGEN__) -/** - Internal macro for checking if log is enabled, before making log. -*/ -#define __gs_log(level, group, format, ...) \ - if (group->mask & (1 << level)) { \ - gs_log(level, group, GS_PGM_STR(format), ##__VA_ARGS__); \ - } - -/** - Internal macro for checking if log is enabled for isr, before making log. -*/ -#define __gs_log_isr(level, group, format, ...) \ - if (group->mask & (1 << level)) { \ - gs_log_isr(level, group, GS_PGM_STR(format), ##__VA_ARGS__); \ - } - -/** - Internal macro used for performing a log only once. - @note This creates a \a static \a variable. -*/ -#define __gs_log_once(level, group, format, ...) \ - ({ \ - static bool print_once; \ - if (!print_once) { \ - print_once = true; \ - __gs_log(level, group, format, ##__VA_ARGS__); \ - } \ - }) -#endif // __DOXYGEN__ - -/** - Default compile-time enabling/disabling of all levels - Unless levels are individually defined, this will be the default value. -*/ -#if !defined(GS_LOG_DISABLE_ALL) -#define GS_LOG_DISABLE_ALL 1 -#endif - -/** - Disable \a error level compile-time by defining a value > 0 -*/ -#if !defined(GS_LOG_DISABLE_ERROR) -#define GS_LOG_DISABLE_ERROR GS_LOG_DISABLE_ALL -#endif - -/** - Disable \a warning level compile-time by defining a value > 0 -*/ -#if !defined(GS_LOG_DISABLE_WARNING) -#define GS_LOG_DISABLE_WARNING GS_LOG_DISABLE_ALL -#endif - -/** - Disable \a notice level compile-time by defining a value > 0 -*/ -#if !defined(GS_LOG_DISABLE_NOTICE) -#define GS_LOG_DISABLE_NOTICE GS_LOG_DISABLE_ALL -#endif - -/** - Disable \a info level compile-time by defining a value > 0 -*/ -#if !defined(GS_LOG_DISABLE_INFO) -#define GS_LOG_DISABLE_INFO GS_LOG_DISABLE_ALL -#endif - -/** - Disable \a debug level compile-time by defining a value > 0 -*/ -#if !defined(GS_LOG_DISABLE_DEBUG) -#define GS_LOG_DISABLE_DEBUG GS_LOG_DISABLE_ALL -#endif - -/** - Disable \a trace level compile-time by defining a value > 0 -*/ -#if !defined(GS_LOG_DISABLE_TRACE) -#define GS_LOG_DISABLE_TRACE GS_LOG_DISABLE_ALL -#endif - -/** - Log \a error to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_error(format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log(LOG_ERROR, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a error from ISR to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_error_isr(format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log_isr(LOG_ERROR, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a error to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_error_group(group, format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log(LOG_ERROR, (group), format, ##__VA_ARGS__); } - -/** - Log \a error only once to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_error_once(format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log_once(LOG_ERROR, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a error only once to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_error_once_group(group, format, ...) { if (!GS_LOG_DISABLE_ERROR) __gs_log_once(LOG_ERROR, (group), format, ##__VA_ARGS__); } - -/** - Log \a warning to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_warning(format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log(LOG_WARNING, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a warning from ISR to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_warning_isr(format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log_isr(LOG_WARNING, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a warning to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_warning_group(group, format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log(LOG_WARNING, (group), format, ##__VA_ARGS__); } - -/** - Log \a warning only once to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_warning_once(format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log_once(LOG_WARNING, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a warning only once to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_warning_once_group(group, format, ...) { if (!GS_LOG_DISABLE_WARNING) __gs_log_once(LOG_WARNING, (group), format, ##__VA_ARGS__); } - -/** - Log \a notice to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_notice(format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log(LOG_NOTICE, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a notice from ISR to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_notice_isr(format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log_isr(LOG_NOTICE, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a notice to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_notice_group(group, format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log(LOG_NOTICE, (group), format, ##__VA_ARGS__); } - -/** - Log \a notice only once to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_notice_once(format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log_once(LOG_NOTICE, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a notice only once to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_notice_once_group(group, format, ...) { if (!GS_LOG_DISABLE_NOTICE) __gs_log_once(LOG_NOTICE, (group), format, ##__VA_ARGS__); } - -/** - Log \a info to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_info(format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log(LOG_INFO, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a info from ISR to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_info_isr(format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log_isr(LOG_INFO, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a info to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_info_group(group, format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log(LOG_INFO, (group), format, ##__VA_ARGS__); } - -/** - Log \a info only once to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_info_once(format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log_once(LOG_INFO, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a info only once to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_info_once_group(group, format, ...) { if (!GS_LOG_DISABLE_INFO) __gs_log_once(LOG_INFO, (group), format, ##__VA_ARGS__); } - -/** - Log \a debug to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_debug(format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log(LOG_DEBUG, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a debug from ISR to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_debug_isr(format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log_isr(LOG_DEBUG, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a debug to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_debug_group(group, format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log(LOG_DEBUG, (group), format, ##__VA_ARGS__); } - -/** - Log \a debug only once to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_debug_once(format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log_once(LOG_DEBUG, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a debug only once to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_debug_once_group(group, format, ...) { if (!GS_LOG_DISABLE_DEBUG) __gs_log_once(LOG_DEBUG, (group), format, ##__VA_ARGS__); } - -/** - Log \a trace to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_trace(format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log(LOG_TRACE, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a trace from ISR to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_trace_isr(format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log_isr(LOG_TRACE, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a trace to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_trace_group(group, format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log(LOG_TRACE, (group), format, ##__VA_ARGS__); } - -/** - Log \a trace only once to default group (LOG_DEFAULT). - @param[in] format Format string (printf style). -*/ -#define log_trace_once(format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log_once(LOG_TRACE, LOG_DEFAULT, format, ##__VA_ARGS__); } - -/** - Log \a trace only once to group. - @param[in] group log group (gs_log_group_t *). - @param[in] format Format string (printf style). -*/ -#define log_trace_once_group(group, format, ...) { if (!GS_LOG_DISABLE_TRACE) __gs_log_once(LOG_TRACE, (group), format, ##__VA_ARGS__); } - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/minmax.h b/gomspace/libutil/include/gs/util/minmax.h deleted file mode 100644 index 4b9edf74..00000000 --- a/gomspace/libutil/include/gs/util/minmax.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef GS_UTIL_MINMAX_H -#define GS_UTIL_MINMAX_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Min/max utilities. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Return minimum value. - @param[in] x value - @param[in] y value - @return the lowest value of the input parameters. -*/ -#define gs_min(x,y) ({ \ - __typeof__ (x) _x = (x); \ - __typeof__ (y) _y = (y); \ - _x < _y ? _x : _y; }) - -/** - Return maximum value. - @param[in] x value - @param[in] y value - @return the maximum value of the input parameters. -*/ -#define gs_max(x,y) ({ \ - __typeof__ (x) _x = (x); \ - __typeof__ (y) _y = (y); \ - _x > _y ? _x : _y; }) - -/** - Return minimum value. - @param[in] x value - @param[in] y value - @param[in] z value - @return the lowest value of the input parameters. -*/ -#define gs_min3(x,y,z) gs_min(gs_min((x),(y)), (z)) - -/** - Return maximum value. - @param[in] x value - @param[in] y value - @param[in] z value - @return the maximum value of the input parameters. -*/ -#define gs_max3(x,y,z) gs_max(gs_max((x),(y)), (z)) - -/** - Clamp value within min/max. - @param[in] x value - @param[in] _max max value - @param[in] _min min value - @return value between min and max. -*/ -#define gs_clamp(x, _min, _max) ({ \ - gs_min(gs_max((x), (_min)), (_max)); }) - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/mutex.h b/gomspace/libutil/include/gs/util/mutex.h deleted file mode 100644 index b5a411f7..00000000 --- a/gomspace/libutil/include/gs/util/mutex.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef GS_UTIL_MUTEX_H -#define GS_UTIL_MUTEX_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Mutex (recursive). - - The mutex API wraps POSIX \a pthread_mutex and FreeRTOS \a mutex. - - @note Mutex can not be used from within an ISR routine - use gs_sem instead. -*/ - -#include -#if __linux__ -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if __linux__ -/** - Mutex handle. -*/ -typedef pthread_mutex_t * gs_mutex_t; -#else -typedef struct gs_freertos_mutex_t * gs_mutex_t; -#endif - -/** - Create mutex. - @param[out] mutex handle. - @return error code. -*/ -gs_error_t gs_mutex_create(gs_mutex_t * mutex); - -/** - Destroy mutex - free resources. - @param[in] mutex handle. - @return error code. -*/ -gs_error_t gs_mutex_destroy(gs_mutex_t mutex); - -/** - Lock mutex. - @param[in] mutex handle. - @return error code. -*/ -gs_error_t gs_mutex_lock(gs_mutex_t mutex); - -/** - Unlock mutex. - @param[in] mutex handle. - @return error code. -*/ -gs_error_t gs_mutex_unlock(gs_mutex_t mutex); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/pgm.h b/gomspace/libutil/include/gs/util/pgm.h deleted file mode 100644 index 04e39013..00000000 --- a/gomspace/libutil/include/gs/util/pgm.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef GS_UTIL_PROGMEM_H -#define GS_UTIL_PROGMEM_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Macros for handling special memory access. - - On most targets/processors, constant data/strings are located in the program space and can be read in the same way as data in the data space. - However, on a few targets (e.g. avr/avr8), data/strings must be marked in a special way in order to go into the program space, see #GS_PGM_STR() - - Using following macros, will make it easier to make cross-platform code and avoid \#if/\#endif. - These macros should only be used where the code also needs to run on avr/avr8. - - @note Including this header on avr/avr8 will REDEFINE printf!. - - http://www.atmel.com/webdoc/avrlibcreferencemanual/group__avr__pgmspace.html. - http://www.nongnu.org/avr-libc/user-manual/pgmspace.html. -*/ - -#include -#if defined(__AVR__) -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(__AVR__) || (__DOXYGEN__) -/** - Special program/data memory handling. -*/ -#define GS_PGM 1 - -/** - Place object in program space (must be const). - Example: static const uint8_t data8[] GS_PGM_OBJECT = {1, 255}; -*/ -#define GS_PGM_OBJECT PROGMEM - -/** - Place const string in program space. - By default the string goes into data, uses thereby uses up space. - Once the string is placed in program space, xx_P functions must be used to access them - see #GS_PGM_PRINTF. - @note printf is re-defined by including this header -*/ -#define GS_PGM_STR(str) PSTR(str) - -/** - Read uint8 from program space (near). -*/ -#define GS_PGM_UINT8(value) pgm_read_byte(&(value)) - -/** - Read uint8 from program space using a pointer (near). -*/ -#define GS_PGM_UINT8_BY_PTR(value) pgm_read_byte(value) - -/** - Read word from program space (near). -*/ -#define GS_PGM_UINT16(value) pgm_read_word(&(value)) -/** - Read word from program space using a pointer (near). -*/ -#define GS_PGM_UINT16_BY_PTR(value) pgm_read_word(value) - -/** - Read dword from program space (near). -*/ -#define GS_PGM_UINT32(value) pgm_read_dword(&(value)) -/** - Read word from program space using a pointer (near). -*/ -#define GS_PGM_UINT32_BY_PTR(value) pgm_read_dword(value) - -/** - Memcpy from program space (near). - @param[in] dst destination. - @param[in] src source - program space. - @param[in] n number of bytes to copy -*/ -#define GS_PGM_MEMCPY(dst, src, n) memcpy_P(dst, src, n) - -/** - String compare (program space) - @param[in] s1 string 1 - @param[in] s2 string 2 - program space. - @param[in] n max number of bytes to compare -*/ -#define GS_PGM_STRNCMP(s1,s2,n) strncmp_P(s1, s2, n) - -/** - String compare (program space) - @param[in] s1 string 1 - @param[in] s2 string 2 - program space. - @param[in] n max number of bytes to compare -*/ -#define GS_PGM_STRNCASECMP(s1,s2,n) strncasecmp_P(s1, s2, n) - -/** - String formatting character for referencing a string placed in programs space. -*/ -#define GS_PGM_FMT_STR "S" - -/** - printf (format string in program space). - Example: print \a param->name (from prgram space) and \a value from data space, using a format string in program space. - GS_PGM_PRINTF(GS_PGM_STR("%"GS_PGM_FMT_STR", %d"), param->name, value) -*/ -#define GS_PGM_PRINTF(format, ...) printf_P(format, ##__VA_ARGS__) - -/** - vprintf (format string in program space). -*/ -#define GS_PGM_VPRINTF(format, va) vfprintf_P(stdout, format, va) - -/** - snprintf (format string in program space). -*/ -#define GS_PGM_SNPRINTF(buf, bufsize, format, ...) snprintf_P(buf, bufsize, format, ##__VA_ARGS__) - -/** - vsnprintf (format string in program space). -*/ -#define GS_PGM_VSNPRINTF(buf, bufsize, format, va) vsnprintf_P(buf, bufsize, format, va) - -/** - redefines printf (puts format string in program space) - */ -#undef printf -#define printf(format, ...) GS_PGM_PRINTF(GS_PGM_STR(format), ## __VA_ARGS__) - -#else - -#undef GS_PGM - -#define GS_PGM_OBJECT -#define GS_PGM_STR(str) (str) -#define GS_PGM_UINT8(value) (value) -#define GS_PGM_UINT8_BY_PTR(value) (*(value)) -#define GS_PGM_UINT16(value) (value) -#define GS_PGM_UINT16_BY_PTR(value) (*(value)) -#define GS_PGM_UINT32(value) (value) -#define GS_PGM_UINT32_BY_PTR(value) (*(value)) -#define GS_PGM_MEMCPY(dst, src, size) memcpy(dst, src, size) -#define GS_PGM_STRNCMP(s1,pgmstr,size) strncmp(s1, pgmstr, size) -#define GS_PGM_STRNCASECMP(s1,pgmstr,size) strncasecmp(s1, pgmstr, size) - -#define GS_PGM_FMT_STR "s" -#define GS_PGM_PRINTF(format, ...) printf(format, ## __VA_ARGS__) -#define GS_PGM_VPRINTF(format, va) vprintf(format, va) -#define GS_PGM_SNPRINTF(buf, bufsize, format, ...) snprintf(buf, bufsize, format, ##__VA_ARGS__) -#define GS_PGM_VSNPRINTF(buf, bufsize, format, va) vsnprintf(buf, bufsize, format, va) - -#endif - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/queue.h b/gomspace/libutil/include/gs/util/queue.h deleted file mode 100644 index 43b7e9ae..00000000 --- a/gomspace/libutil/include/gs/util/queue.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef GS_UTIL_QUEUE_H -#define GS_UTIL_QUEUE_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Queue. - - The queue API wraps FreeRTOS \a queue. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if __linux__ -/** - Queue handle. -*/ -typedef struct gs_pthread_queue * gs_queue_t; -#else -typedef struct gs_freertos_queue_t * gs_queue_t; -#endif - -/** - Create queue. - - @param[in] items max number of items on the queue. - @param[in] item_size size of item (bytes). - @param[out] queue created queue. - @return_gs_error_t -*/ -gs_error_t gs_queue_create(size_t items, size_t item_size, gs_queue_t * queue); - -/** - Destroy queue - free resources. - - @param[in] queue handle. - @return_gs_error_t -*/ -gs_error_t gs_queue_destroy(gs_queue_t queue); - -/** - Enqueue object on queue. - @param[in] queue handle. - @param[in] value pointer to object, size specified at gs_queue_create(). - @param_int_timeout_ms - @return_gs_error_timeout - @return_gs_error_t -*/ -gs_error_t gs_queue_enqueue(gs_queue_t queue, const void *value, int timeout_ms); - -/** - Enqueue object on queue from within an ISR. - @param[in] queue handle. - @param[in] value pointer to object, size specified at gs_queue_create(). - @param[in] cswitch context switch. - @return GS_ERROR_FULL if queue is full. - @return_gs_error_t -*/ -gs_error_t gs_queue_enqueue_isr(gs_queue_t queue, const void * value, gs_context_switch_t * cswitch); - -/** - Dequeue object from queue. - @param[in] queue handle. - @param[out] buf element - size specified in gs_queue_create(). - @param_int_timeout_ms - @return_gs_error_timeout - @return_gs_error_t -*/ -gs_error_t gs_queue_dequeue(gs_queue_t queue, int timeout_ms, void *buf); - -/** - Dequeue object from queue from within an ISR. - @param[in] queue handle. - @param[in] cswitch context switch. - @param[out] buf element - size specified in gs_queue_create(). - @return GS_ERROR_NOT_FOUND if no elements in queue. - @return_gs_error_t -*/ -gs_error_t gs_queue_dequeue_isr(gs_queue_t queue, gs_context_switch_t * cswitch, void * buf); - -/** - Return queue size. - @param[in] queue handle. - @return queue size -*/ -unsigned int gs_queue_size(gs_queue_t queue); - -/** - Return queue size from within an ISR. - @param[in] queue handle. - @return queue size -*/ -unsigned int gs_queue_size_isr(gs_queue_t queue); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/rtc.h b/gomspace/libutil/include/gs/util/rtc.h deleted file mode 100644 index b1988925..00000000 --- a/gomspace/libutil/include/gs/util/rtc.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef GS_UTIL_RTC_H -#define GS_UTIL_RTC_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Real Time Clock interface. - - The RTC driver is used by gs_clock_get_time() and gs_clock_set_time(). -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Platform supporting RTC must register the driver, before the rest of the system can access it. - @see gs_rtc_register() -*/ -typedef struct { - /** - Call-back for getting RTC time. - @param[out] time user allocated struct for returning time. - */ - gs_error_t (*get_time)(void * driver_data, gs_timestamp_t * time); - /** - Call-back for setting RTC time. - @param[in] time user allocated struct for returning time. - */ - gs_error_t (*set_time)(void * driver_data, const gs_timestamp_t * time); -} gs_rtc_driver_t; - -/** - Register RTC driver. - @param[in] driver driver - data/struct must remain valid as long as registered. - @param[in] driver_data driver specific data, forwarded to driver when set/get is called. - @return_gs_error_t -*/ -gs_error_t gs_rtc_register(const gs_rtc_driver_t * driver, void * driver_data); - -/** - Return GS_OK if RTC is supported. -*/ -gs_error_t gs_rtc_supported(void); - -/** - Set RTC. -*/ -gs_error_t gs_rtc_get_time(gs_timestamp_t * time); - -/** - Get RTC. -*/ -gs_error_t gs_rtc_set_time(const gs_timestamp_t * time); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/sem.h b/gomspace/libutil/include/gs/util/sem.h deleted file mode 100644 index 4afd4d7d..00000000 --- a/gomspace/libutil/include/gs/util/sem.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef GS_UTIL_SEM_H -#define GS_UTIL_SEM_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Semaphore. - - The semaphore API wraps POSIX \a semaphore and FreeRTOS \a counted semaphore. - - Main difference is that FreeRTOS uses different API calls, when called from within - an ISR routine. -*/ - -#include -#if __linux__ -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if __linux__ -/** - Semaphore handle. -*/ -typedef sem_t * gs_sem_t; -#else -typedef struct gs_freertos_sem_t * gs_sem_t; -#endif - -/** - Create semaphore. - @param[in] initialValue initial value. - @param[out] sem created semaphore. - @return_gs_error_t -*/ -gs_error_t gs_sem_create(unsigned int initialValue, gs_sem_t * sem); - -/** - Destroy semaphore - free resources. - @param[in] sem handle. - @return_gs_error_t -*/ -gs_error_t gs_sem_destroy(gs_sem_t sem); - -/** - Wait for semaphore to be signaled. - @param[in] sem handle. - @param_int_timeout_ms - @return_gs_error_timeout - @return_gs_error_t -*/ -gs_error_t gs_sem_wait(gs_sem_t sem, int timeout_ms); - -/** - Post/signal semaphore. - @param[in] sem handle. - @return_gs_error_t -*/ -gs_error_t gs_sem_post(gs_sem_t sem); - -/** - Post/signal semaphore from within a ISR. - @param[in] sem handle. - @param[in] cswitch context switch. - @return_gs_error_t -*/ -gs_error_t gs_sem_post_isr(gs_sem_t sem, gs_context_switch_t * cswitch); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/stdio.h b/gomspace/libutil/include/gs/util/stdio.h deleted file mode 100644 index 992d4dda..00000000 --- a/gomspace/libutil/include/gs/util/stdio.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef GS_UTIL_STDIO_H -#define GS_UTIL_STDIO_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - GomSpace extensions to standard \a stdio.h. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Put character on stdout. -*/ -gs_error_t gs_stdio_putchar(int ch); - -/** - Read character from stdin with timeout. - @param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milli seconds. - @param[out] ch character read. If NULL, one character from stdin is still consumed - but nothing returned. - @return GS_ERROR_TIMEOUT on timeout - @return_gs_error_t -*/ -gs_error_t gs_stdio_getchar_timed(int timeout_ms, int *ch); - -/** - Read character from stdin. - Blocks until a character is available. - @param[out] ch character read. If NULL, one character from stdin is still consumed - but nothing returned. - @return_gs_error_t -*/ -static inline gs_error_t gs_stdio_getchar(int * ch) -{ - return gs_stdio_getchar_timed(-1, ch); -} - -/** - Read characters from stdin. - Blocks until all characters are read. - @param[in,out] buf user supplied buffer for receiving characters. - @param[in] n number of characters to read. - @return_gs_error_t -*/ -gs_error_t gs_stdio_get(char * buf, size_t n); - -/** - Write characters to stdout. - Blocks until characters are written. - @param[in] buf characters to write. - @param[in] n number of characters to write. - @param[in] text if \a true, new lines (\\n) are converted to \\r\\n. - @return_gs_error_t -*/ -gs_error_t gs_stdio_put(const char * buf, size_t n, bool text); - -/** - Pattern for printing a byte as binary. - @see GS_STDIO_BYTETOBINARY() -*/ -#define GS_STDIO_BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d" - -/** - Macro for splitting a byte info 'bits'. -*/ -#define GS_STDIO_BYTETOBINARY(byte) \ - (byte & 0x80 ? 1 : 0), \ - (byte & 0x40 ? 1 : 0), \ - (byte & 0x20 ? 1 : 0), \ - (byte & 0x10 ? 1 : 0), \ - (byte & 0x08 ? 1 : 0), \ - (byte & 0x04 ? 1 : 0), \ - (byte & 0x02 ? 1 : 0), \ - (byte & 0x01 ? 1 : 0) - -/** - Color definitions for gs_color_printf() - @see gs_color_printf() -*/ -typedef enum { - /** - Colors. - */ - GS_COLOR_COLORS = 0x00ff, - GS_COLOR_NONE = 0, - GS_COLOR_BLACK = 1, - GS_COLOR_RED = 2, - GS_COLOR_GREEN = 3, - GS_COLOR_YELLOW = 4, - GS_COLOR_BLUE = 5, - GS_COLOR_MAGENTA = 6, - GS_COLOR_CYAN = 7, - GS_COLOR_WHITE = 8, - /** - Attributes - */ - GS_COLOR_ATTRS = 0xff00, - GS_COLOR_BOLD = 0x100, -} gs_color_printf_t; - -/** - Printf with colors on stdout. - - Using the standard terminal escape sequences for setting the color. - @param[in] color color settings. - @param[in] format standard printf format string. -*/ -void gs_color_printf(gs_color_printf_t color, const char * format, ...) __attribute__ ((format (__printf__, 2, 3))); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/string.h b/gomspace/libutil/include/gs/util/string.h deleted file mode 100644 index 034af8c6..00000000 --- a/gomspace/libutil/include/gs/util/string.h +++ /dev/null @@ -1,391 +0,0 @@ -#ifndef GS_UTIL_STRING_H -#define GS_UTIL_STRING_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - String utilitizes. - - All string parsing functions will return #GS_OK if the string was parsed entirely. - If the string contains characters that are not part of the selected base, the functions will return #GS_ERROR_DATA. - If the value parsed is bigger than the output type, the functions will return #GS_ERROR_OVERFLOW. - Spaces are ignored by all functions. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Macro helper for concatening tokens. -*/ -#define GS_STRINGZ(x) #x - -/** - Stringify a preprocessing token. -*/ -#define GS_DEF2STRING(x) GS_STRINGZ(x) - -/** - * Strncpy (using size of destination) and forced zero termination. - */ -#define GS_STRNCPY(dst,src) strncpy(dst,src,GS_ARRAY_SIZE(dst));dst[GS_ARRAY_SIZE(dst)-1] = 0 - -/** - Convert string to int32 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_int32(const char * string, int32_t * value); - -/** - Convert string to uint32 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_uint32(const char * string, uint32_t * value); - -/** - Convert string to int64 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_int64(const char * string, int64_t * value); - -/** - Convert string to uint64 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_uint64(const char * string, uint64_t * value); - -/** - Convert string to int8 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 12 (decimal), 0x12 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_int8(const char * string, int8_t * value); - -/** - Convert string to uint8 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 12 (decimal), 0x12 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_uint8(const char * string, uint8_t * value); - -/** - Convert string to int16 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_int16(const char * string, int16_t * value); - -/** - Convert string to uint16 (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_uint16(const char * string, uint16_t * value); - -/** - Convert string to uint32 (hexadecimal). - Accepts: hexadecimal (no leading 0x), e.g. a123, A123. - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_hex_to_uint32(const char * string, uint32_t * value); - -/** - Convert string to uint64 (hexadecimal). - Accepts: hexadecimal (no leading 0x), e.g. a123, A123. - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_hex_to_uint64(const char * string, uint64_t * value); - -/** - Convert string to boolean. - Accepts: true, false, on, off, 1, 0 (ignores case) - @param[in] string string to convert. - @param[out] pvalue converted value - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_bool(const char * string, bool * pvalue); - -/** - Convert string to float. - @param[in] string string to convert. - @param[out] pvalue converted value - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_float(const char * string, float * pvalue); - -/** - Convert string to double. - @param[in] string string to convert. - @param[out] pvalue converted value - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_double(const char * string, double * pvalue); - -/** - Return string for boolean value (true or false). - @param[in] value value - @return \a 'true' if input is true, else \a 'false'. -*/ -const char * gs_string_from_bool(bool value); - -/** - Convert string to pointer (decimal or hexadecimal). - Accepts: decimal or hexadecimal, 1234 (decimal), 0x1234 (hexadecimal) - @param[in] string string to convert. - @param[out] value converted value - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -gs_error_t gs_string_to_pointer(const char * string, void ** value); - -/** - Format size as Bytes, Kilo or Mega. - - Output examples: \a 512.0B, \a 1.0K and \a 1.0M. - - @param[in] size size in bytes - @param[out] buffer formatted size - @param[in] buffer_size size of \a buf - @return GS_ERROR_OVERFLOW if the resulting value is larger than the output type - @return GS_ERROR_DATA if the input string could not be parsed completely - @return GS_ERROR_ARG if the input string is a NULL pointer -*/ -char * gs_string_bytesize(long size, char *buffer, size_t buffer_size); - -/** - GS implementation of gcc's strtol - Instead of setting errno this function takes a pointer to err which is set - the same way as with gcc's strtol - - @param[in] nptr input string - @param[out] endptr the pointer to the end of the string parsed - @param[in] base number system (10 or 16) - @param[out] err return value if overflow - @return converted value -*/ -int32_t gs_string_strto32int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); - -/** - GS implementation of gcc's strtoul - Instead of setting errno this function takes a pointer to err which is set - the same way as with gcc's strtoul - - @param[in] nptr input string - @param[out] endptr the pointer to the end of the string parsed - @param[in] base number system (10 or 16) - @param[out] err return value if overflow - @return converted value -*/ -uint64_t gs_string_strto64uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); - -/** - GS implementation of gcc's strtoul - Instead of setting errno this function takes a pointer to err which is set - the same way as with gcc's strtoul - - @param[in] nptr input string - @param[out] endptr the pointer to the end of the string parsed - @param[in] base number system (10 or 16) - @param[out] err return value if overflow - @return converted value -*/ -int64_t gs_string_strto64int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); - -/** - GS implementation of gcc's strtoul - Instead of setting errno this function takes a pointer to err which is set - the same way as with gcc's strtoul - - @param[in] nptr input string - @param[out] endptr the pointer to the end of the string parsed - @param[in] base number system (10 or 16) - @param[out] err return value if overflow - @return converted value -*/ -uint32_t gs_string_strto32uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err); - -/** - Returns pointer to first none-space character. - - @param[in] string string - @return NULL if \a string is NULL, otherwise first none-space character. -*/ -const char * gs_string_skip_leading_spaces(const char * string); - -/** - Check if a string is NULL or empty. - - @param[in] string string - @return true if string is empty or NULL. -*/ -bool gs_string_empty(const char * string); - -/** - Case-insentive wilcard match (similiar to fnmatch). - - Supports following wildcard(s): - - * (asterix) zero or more characters. - - This may be extended in future versions and will not be considered a break of the API. - - @param[in] pattern pattern to match against \a string. - @param[in] string string to match against \a pattern - @return \a true if match, else \ false -*/ -bool gs_string_match(const char * pattern, const char * string); - -/** - Returns \a true if string contains wildcards. - - @param[in] string string to check for wildcards. - @return \a true if string contains wildcards recognized by gs_string_match(). -*/ -bool gs_string_has_wildcards(const char * string); - -/** - Trim string in buffer by removing leading/trailing white space. - - Uses isspace(c). - - @param[in] buffer buffer to trim. - @param[in] buffer_size size of \a buffer. -*/ -void gs_string_trim(char * buffer, size_t buffer_size); - -/** - Returns \a true if string ends with endswith. - - @param[in] string string to check - @param[in] endswith string that string should end with - @return \a true if string endswith endswith -*/ -bool gs_string_endswith(const char * string, const char * endswith); - -/** - Extract suboption from a string. - - @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". - @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). - @param[out] buf user buffer for returning value of sub-option. - @param[in] buf_size size of \a buf user buffer. - @return_gs_error_t -*/ -gs_error_t gs_string_get_suboption(const char * options, const char * suboption, char * buf, size_t buf_size); - -/** - Extract suboption (as string) from a string. - - @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". - @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). - @param[in] def default value, returned if sub-option isn't found. - @param[out] buf user buffer for returning value of sub-option. - @param[in] buf_size size of \a buf user buffer. - @return If the sub-option isn't found, the \a def default value will be copied to \a buf and #GS_OK will be returned. - @return_gs_error_t -*/ -gs_error_t gs_string_get_suboption_string(const char * options, const char * suboption, const char * def, char * buf, size_t buf_size); - -/** - Extract suboption (as uint8) from a string. - - @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". - @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). - @param[in] def default value, returned if sub-option isn't found. - @param[out] value user supplied buffer for returning the value. - @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. - @return_gs_error_t -*/ -gs_error_t gs_string_get_suboption_uint8(const char * options, const char * suboption, uint8_t def, uint8_t * value); - -/** - Extract suboption (as uint16) from a string. - - @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". - @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). - @param[in] def default value, returned if sub-option isn't found. - @param[out] value user supplied buffer for returning the value. - @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. - @return_gs_error_t -*/ -gs_error_t gs_string_get_suboption_uint16(const char * options, const char * suboption, uint16_t def, uint16_t * value); - -/** - Extract suboption (as uint32) from a string. - - @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". - @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). - @param[in] def default value, returned if sub-option isn't found. - @param[out] value user supplied buffer for returning the value. - @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. - @return_gs_error_t -*/ -gs_error_t gs_string_get_suboption_uint32(const char * options, const char * suboption, uint32_t def, uint32_t * value); - -/** - Extract suboption (as bool) from a string. - - @param[in] options options string, e.g. \"/dev/ttyUSB1,speed=9600,parity=no,databits=8\". - @param[in] suboption sub-option to extract. If NULL or empty, the first option will be extracted (if present). - @param[in] def default value, returned if sub-option isn't found. - @param[out] value user supplied buffer for returning the value. - @return If the sub-option isn't found, the \a def default value will be copied to \a value and #GS_OK will be returned. - @return_gs_error_t -*/ -gs_error_t gs_string_get_suboption_bool(const char * options, const char * suboption, bool def, bool * value); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/test/cmocka.h b/gomspace/libutil/include/gs/util/test/cmocka.h deleted file mode 100644 index 43648627..00000000 --- a/gomspace/libutil/include/gs/util/test/cmocka.h +++ /dev/null @@ -1,136 +0,0 @@ -#ifndef GS_UTIL_TEST_CMOCKA_H -#define GS_UTIL_TEST_CMOCKA_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Cmocka extensions. - - Official site for cmocka https://cmocka.org. -*/ - -#include - -// cmocka -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if !(__DOXYGEN__) -// internal helpers - use macros -void _gs_assert_int_equal(const intptr_t a, const intptr_t b, bool equal, const char * const file, const int line); -void _gs_assert_uint_equal(const uintptr_t a, const uintptr_t b, bool equal, bool hex, const char * const file, const int line); -void _gs_assert_error_equal(const int a, const int b, bool equal, const char * const file, const int line); -void _gs_assert_float_equal(const float a, const float b, const float diff, bool equal, const char * const file, const int line); -void _gs_assert_double_equal(const double a, const double b, const double diff, bool equal, const char * const file, const int line); -#endif - -/** - Assert int (print value as signed). -*/ -#define GS_ASSERT_INT_EQUAL(a,b) _gs_assert_int_equal((intptr_t) (a), (intptr_t) (b), true, __FILE__, __LINE__) -/** - Assert unsigned int (print value as unsigned). -*/ -#define GS_ASSERT_UINT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, false, __FILE__, __LINE__) -/** - Assert int (print value as hex). -*/ -#define GS_ASSERT_XINT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, true, __FILE__, __LINE__) -/** - Assert #gs_error_t (print value and error text). -*/ -#define GS_ASSERT_ERROR_EQUAL(a,b) _gs_assert_error_equal(a, b, true, __FILE__, __LINE__) -/** - Assert #GS_OK (print value and error text). -*/ -#define GS_ASSERT_ERROR_OK(a) _gs_assert_error_equal(a, GS_OK, true, __FILE__, __LINE__) -/** - Assert float (print value as signed). -*/ -#define GS_ASSERT_FLOAT_EQUAL(a,b,diff) _gs_assert_float_equal(a, b, diff, true, __FILE__, __LINE__) -/** - Assert double (print value as signed). -*/ -#define GS_ASSERT_DOUBLE_EQUAL(a,b,diff) _gs_assert_double_equal(a, b, diff, true, __FILE__, __LINE__) - -/** - Assert int (print value as signed). -*/ -#define GS_ASSERT_INT_NOT_EQUAL(a,b) _gs_assert_int_equal((intptr_t) (a), (intptr_t) (b), false, __FILE__, __LINE__) -/** - Assert unsigned int (print value as unsigned). -*/ -#define GS_ASSERT_UINT_NOT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), false, false, __FILE__, __LINE__) -/** - Assert int (print value as hex). -*/ -#define GS_ASSERT_XINT_NOT_EQUAL(a,b) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), false, true, __FILE__, __LINE__) -/** - Assert #GS_OK (print value and error text). -*/ -#define GS_ASSERT_ERROR_NOT_EQUAL(a,b) _gs_assert_error_equal(a, b, false, __FILE__, __LINE__) - -/** - Code reference. -*/ -#define GS_REF() __FILE__,__LINE__ -/** - Assert int with code reference (print value as signed). -*/ -#define GS_ASSERT_INT_EQUAL_REF(a,b,file,line) _gs_assert_int_equal((intptr_t) (a), (intptr_t) (b), true, file, file, line) -/** - Assert unsigned int with code reference (print value as unsigned). -*/ -#define GS_ASSERT_UINT_EQUAL_REF(a,b,file,line) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, false, file, line) -/** - Assert int with code reference (print value as hex). -*/ -#define GS_ASSERT_XINT_EQUAL_REF(a,b,file,line) _gs_assert_uint_equal((uintptr_t) (a), (uintptr_t) (b), true, true, file, line) -/** - Assert #gs_error_t with code reference (print value and error text). -*/ -#define GS_ASSERT_ERROR_EQUAL_REF(a,b,file,line) _gs_assert_error_equal(a, b, true, file, line) -/** - Assert #GS_OK with code reference (print value and error text). -*/ -#define GS_ASSERT_ERROR_OK_REF(a,file,line) _gs_assert_error_equal(a, GS_OK, true, file, line) - -/** - Run \a cmocka test group. - - @param[in] name name of test. If name is \a tests and GS_TEST_NAME is set, GS_TEST_NAME will be used instead. - @param[in] tests array of tests. - @param[in] num_tests number of tests. - @param[in] setup setup function, can be NULL. - @param[in] teardown teardown function, can be NULL. - @return 0 on success. -*/ -static inline int gs_cmocka_run_group_tests(const char *name, - const struct CMUnitTest * const tests, - const size_t num_tests, - CMFixtureFunction setup, - CMFixtureFunction teardown) -{ -#ifdef GS_TEST_NAME // set by buildtools::gs_test_cmocka.py - if (strcasecmp(name, "tests") == 0) { - name = GS_DEF2STRING(GS_TEST_NAME); - } -#endif - return _cmocka_run_group_tests(name, tests, num_tests, setup, teardown); -} - -#ifdef GS_TEST_NAME -// hi-jack cmocka's macro -#undef cmocka_run_group_tests -#define cmocka_run_group_tests(tests, setup, teardown) gs_cmocka_run_group_tests(GS_DEF2STRING(tests), tests, GS_ARRAY_SIZE(tests), setup, teardown) -#endif - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/test/command.h b/gomspace/libutil/include/gs/util/test/command.h deleted file mode 100644 index d2227017..00000000 --- a/gomspace/libutil/include/gs/util/test/command.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef GS_UTIL_TEST_COMMAND_H -#define GS_UTIL_TEST_COMMAND_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Command Test framework. - - Provides a simple way of unit-testing/validating commands. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Validate command execution. - - Runs a commands and validates the output/results agains the inputs. - Asserts if the results does not match. - - @param[in] cmd command (including arguments) to execute. - @param[in] ret expected return code from the command execution framework. - @param[in] cmd_ret expected return code from the commands handler. This is only validated if (ret = GS_OK). - @param[in] std_in string with expected command input. - @param[in] std_out string with expected command output. Wildcards (*\/?) are supported. - @param[in] file string with file name. - @param[in] line string with line no. - @return void -*/ -void _gs_assert_command_validate(const char *cmd, gs_error_t ret, gs_error_t cmd_ret, const char *std_in, const char *std_out, const char * const file, const int line); - -/** - Validate command results returned from last command execution. - Asserts if the results does not match. - - @param[in] no the result no to verify. - @param[in] group string with expected group id. Wildcards (*\/?) are supported. - @param[in] key string with expected key. Wildcards (*\/?) are supported. - @param[in] value string with expected value. Wildcards (*\/?) are supported. - @param[in] file string with file name. - @param[in] line string with line no. - @return void -*/ -void _gs_assert_command_validate_last_result(unsigned int no, const char *group, const char *key, const char *value, const char * const file, const int line); - -/** - Validate command execution. - - Runs a commands and validates the output/results agains the inputs. - Asserts if the results does not match. - - @param[in] cmd command (including arguments) to execute. - @param[in] ret expected return code from the command execution framework. - @param[in] cmd_ret expected return code from the commands handler. This is only validated if (ret = GS_OK). - @param[in] std_in string with expected command input. - @param[in] std_out string with expected command output. Wildcards (*\/?) are supported. - @return void -*/ -#define GS_ASSERT_COMMAND(cmd,ret,cmd_ret,std_in,std_out) _gs_assert_command_validate(cmd,ret,cmd_ret,std_in,std_out, __FILE__, __LINE__); - -/** - Validate command results returned from last command execution. - Asserts if the results does not match. - - @param[in] no the result no to verify. - @param[in] group string with expected group id. Wildcards (*\/?) are supported. - @param[in] key string with expected key. Wildcards (*\/?) are supported. - @param[in] value string with expected value. Wildcards (*\/?) are supported. - @return void -*/ -#define GS_ASSERT_COMMAND_RESULT(no,group,key,value) _gs_assert_command_validate_last_result(no,group,key,value, __FILE__, __LINE__); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/test/log.h b/gomspace/libutil/include/gs/util/test/log.h deleted file mode 100644 index 13322953..00000000 --- a/gomspace/libutil/include/gs/util/test/log.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef GS_UTIL_TEST_LOG_H -#define GS_UTIL_TEST_LOG_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - Log Test framework. - - Provides a simple way of veriyfing logs generated during unit-testing. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Assert log count - internal helper function. -*/ -void gs_assert_log_count(int level, unsigned int count, const char * file, int line); - -/** - Assert log messag and count - internal helper function. -*/ -void gs_assert_log(unsigned int stack_index, unsigned int count, gs_log_level_t level, const char * pattern, const char * file, int line); - -/** - Initialize framework, by installing a callback for \a print. - @param[in] verbose of \a true, logs will be printed on stdout. -*/ -void gs_test_log_init(bool verbose); - -/** - Clear log stats. -*/ -void gs_test_log_clear(void); - -/** - Assert number of error logs. -*/ -#define GS_ASSERT_LOG_ERROR(cnt) gs_assert_log_count(LOG_ERROR, cnt, __FILE__, __LINE__); - -/** - Assert number of warning logs. -*/ -#define GS_ASSERT_LOG_WARNING(cnt) gs_assert_log_count(LOG_WARNING, cnt, __FILE__, __LINE__); - -/** - Assert number of notice logs. -*/ -#define GS_ASSERT_LOG_NOTICE(cnt) gs_assert_log_count(LOG_NOTICE, cnt, __FILE__, __LINE__); - -/** - Assert number of info logs. -*/ -#define GS_ASSERT_LOG_INFO(cnt) gs_assert_log_count(LOG_INFO, cnt, __FILE__, __LINE__); - -/** - Assert number of debug logs. -*/ -#define GS_ASSERT_LOG_DEBUG(cnt) gs_assert_log_count(LOG_DEBUG, cnt, __FILE__, __LINE__); - -/** - Assert number of trace logs. -*/ -#define GS_ASSERT_LOG_TRACE(cnt) gs_assert_log_count(LOG_TRACE, cnt, __FILE__, __LINE__); - -/** - Assert number of all logs. -*/ -#define GS_ASSERT_LOG_ALL(cnt) gs_assert_log_count(-1, cnt, __FILE__, __LINE__); - -/** - Assert/find number of entries matching level and pattern. -*/ -#define GS_ASSERT_LOG(count,level,pattern) gs_assert_log(-1, count, level, pattern, __FILE__, __LINE__) - -/** - Assert log at stack index against matching level and pattern. -*/ -#define GS_ASSERT_LOG_AT(stack_index,level,pattern) gs_assert_log(stack_index, 1, level, pattern, __FILE__, __LINE__) - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/thread.h b/gomspace/libutil/include/gs/util/thread.h deleted file mode 100644 index 37340818..00000000 --- a/gomspace/libutil/include/gs/util/thread.h +++ /dev/null @@ -1,173 +0,0 @@ -#ifndef GS_UTIL_THREAD_H -#define GS_UTIL_THREAD_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Thread/task API based on POSIX standard. - - The thread API wraps POSIX \a pthread and FreeRTOS \a task. -*/ - -#include -#if __linux__ -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if __linux__ -/** - Thread handle. -*/ -typedef pthread_t gs_thread_t; -#else -typedef struct gs_freertos_task_t * gs_thread_t; -#endif - -/** - Type used to declare thread stack buffer for gs_thread_create_with_stack. -*/ -typedef uint32_t gs_stack_type_t; - -/** - Thread priorities. - These values are mapped to platform specific values. -*/ -typedef enum { - /** - Idle (lowest) priority. - Typical use: Not much - runs when nothing else runs. - FreeRTOS: Idle thread. - */ - GS_THREAD_PRIORITY_IDLE = 5, - /** - Low priority. - Typical use: Service applications, e.g. servicing requests from the outside. - GOMspace: housekeeping, GOSH. - */ - GS_THREAD_PRIORITY_LOW = 10, - /** - Normal priority. - Typical use: Control - the primary application(s). - */ - GS_THREAD_PRIORITY_NORMAL = 15, - /** - High priority. - Typical use: Drivers off loading data from hardware to software buffers. - GOMspace: csp_route_task. - */ - GS_THREAD_PRIORITY_HIGH = 20, - /** - High priority. - Typical use: Very time critical threads. No long, time consuming processing. - FreeRTOS: Timer thread. - */ - GS_THREAD_PRIORITY_CRITICAL = 25, -} gs_thread_priority_t; - -/** - Thread function. -*/ -typedef void * (*gs_thread_func_t)(void * parameter); - -/** - Create thread as joinable. - @note only supported on linux. The thread must be joined to free all resources. -*/ -#define GS_THREAD_CREATE_JOINABLE 0x0001 - -/** - Create thread (or task on some platforms). - - pthread/Posix supports exit value and join, FreeRTOS supports neither (perhaps in the future), so API is designed after Posix. - - FreeRTOS: a thread must always terminate with a call to gs_thread_exit(). - linux: a thread is by default created detached, unless #GS_THREAD_CREATE_JOINABLE is specified. - - @param[in] name name of thread. Ignored on Linux. - @param[in] func function for thread to execute. - @param[in] parameter parameter parsed to the thread function. - @param[in] stack_size number of bytes to allocate for stack - not used/supported on all platforms. Ignored on Linux. - @param[in] priority thread priority. Ignored on Linux. - @param[in] flags flags to control creation, see #GS_THREAD_CREATE_JOINABLE. - @param[out] handle handle to the created thread, use NULL if not wanted. - @return_gs_error_t -*/ -gs_error_t gs_thread_create(const char * const name, - gs_thread_func_t func, - void * parameter, - size_t stack_size, - gs_thread_priority_t priority, - uint32_t flags, - gs_thread_t * handle); - -/** - Create thread (or task on some platforms) with user supplied buffer for stack. - - pthread/Posix supports exit value and join, FreeRTOS supports neither (perhaps in the future), so API is designed after Posix. - - FreeRTOS: a thread must always terminate with a call to gs_thread_exit(). - FreeRTOS v9.0 must be compiled with configSUPPORT_STATIC_ALLOCTION set to 1 - otherwise warning log is printed and user supplied - stack buffer is discarded - linux: a thread is by default created detached, unless #GS_THREAD_CREATE_JOINABLE is specified. - stack_buf is ignored. - - @param[in] name name of thread. Ignored on Linux. - @param[in] func function for thread to execute. - @param[in] parameter parameter parsed to the thread function. - @param[in] stack_size size of the user supplied stack buffer - not used/supported on all platforms. Ignored on Linux. - @param[in] stack_buf User supplied stack buffer - not used/supported on all platforms. Ignored on Linux. - @param[in] priority thread priority. Ignored on Linux. - @param[in] flags flags to control creation, see #GS_THREAD_CREATE_JOINABLE. - @param[out] handle handle to the created thread, use NULL if not wanted. - @return_gs_error_t -*/ -gs_error_t gs_thread_create_with_stack(const char * const name, - gs_thread_func_t func, - void * parameter, - size_t stack_size, - gs_stack_type_t *stack_buf, - gs_thread_priority_t priority, - uint32_t flags, - gs_thread_t * handle); - -/** - Exit current thread. - @param[in] exit_value exit value. -*/ -void gs_thread_exit(void * exit_value) __attribute__ ((noreturn)); - -/** - Sleep for X milli-seconds. - @note FreeRTOS: minimum sleep time depends on ticks per milli-second. A thread is suspended minimum 1 tick - unless \a time_ms is 0, in which case yield is called. - @deprecated use gs_time_sleep_ms() - @param[in] time_ms milli-seconds to sleep. -*/ -void gs_thread_sleep_ms(uint32_t time_ms); - -/** - Join with a terminated thread. - - @note Only supported on Linux and primarily used for testing. - @note This is not based on pthread_cancel(), so the user must have signaled the thread to stop - otherwise this will hang forever. - - @param[in] thread handle. - @param[out] return_retval return value from thread, use NULL if not wanted. - @return_gs_error_t -*/ -gs_error_t gs_thread_join(gs_thread_t thread, void ** return_retval); - -/** - Block thread forever. - - Primarily used in Linux applications main() to block main thread. -*/ -void gs_thread_block(void) __attribute__ ((noreturn)); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/time.h b/gomspace/libutil/include/gs/util/time.h deleted file mode 100644 index d4425906..00000000 --- a/gomspace/libutil/include/gs/util/time.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef GS_UTIL_TIME_H -#define GS_UTIL_TIME_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Releative time. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Converts minutes to seconds. -*/ -#define GS_TIME_MINS_TO_SECS(m) (m * 60) - -/** - Converts hours to seconds. -*/ -#define GS_TIME_HOURS_TO_SECS(h) (h * GS_TIME_MINS_TO_SECS(60)) - -/** - Converts days to seconds. -*/ -#define GS_TIME_DAYS_TO_SECS(d) (d * GS_TIME_HOURS_TO_SECS(24)) - -/** - Return relative time (milli seconds). - @note This will eventually wrap on all platforms - platform must wrap on 32 bit. - @return relativ milli seconds -*/ -uint32_t gs_time_rel_ms(void); - -/** - Return relative time (milli seconds). - @note This will eventually wrap on all platforms - platform must wrap on 32 bit. - @return relativ milli seconds -*/ -uint32_t gs_time_rel_ms_isr(void); - -/** - Returns seconds since process started. - @note On some platforms (e.g. Linux), first call will set offset and - first call it therefor not thread-safe. - @return seconds since boot (or process startup). -*/ -uint32_t gs_time_uptime(void); - -/** - Return time difference, compensating for time wrap due to 32 bit. - @note the function can not detect multiple time wraps, so function using it should - take action within 32 bit time. - @param[in] ref_ms reference time. - @param[in] now_ms current time. - @returns ms difference, compensating for time wrapping (if now_ms is less than ref_ms). -*/ -uint32_t gs_time_diff_ms(uint32_t ref_ms, uint32_t now_ms); - -/** - Sleep for X milli-seconds. - No busy waiting. - @note FreeRTOS: minimum sleep time depends on ticks per second. Suspends execution for minimum 1 tick - unless \a time is 0, in which case yield is called. - @param[in] time_ms milli-seconds to sleep. -*/ -void gs_time_sleep_ms(uint32_t time_ms); - -/** - Sleep X milli-seconds relative to reference. - - This sleep function uses a reference \a ref_ms to compensate for variance in processing time. - - No busy waiting. - - @param[in,out] ref_ms time reference. - @param[in] sleep_ms how many milli-seconds to sleep - relative to reference. - @return \a true if sleep time relative to last reference couldn't be done (reference reset), \a false if normal sleep was done. -*/ -bool gs_time_sleep_until_ms(uint32_t * ref_ms, uint32_t sleep_ms); - -/** - Sleep for X nano-seconds. - No busy waiting. - @note FreeRTOS: minimum sleep time depends on ticks per second. Suspends execution for minimum 1 tick - unless \a time is 0, in which case yield is called. - @param[in] time_ns nano-seconds to sleep. -*/ -void gs_time_sleep_ns(uint64_t time_ns); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/timestamp.h b/gomspace/libutil/include/gs/util/timestamp.h deleted file mode 100644 index 80fef6da..00000000 --- a/gomspace/libutil/include/gs/util/timestamp.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef GS_UTIL_TIMESTAMP_H -#define GS_UTIL_TIMESTAMP_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Timestamp utilities, for add, subtract, compare, copy, etc. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Number of nano seconds per second. -*/ -#define GS_TIMESTAMP_NSEC_PER_SEC 1000000000 - -/** - Portable time structure. - - Stanadard timespec_t is non-portable, so this structure must be used instead -*/ -typedef struct { - /** Seconds. */ - uint32_t tv_sec; - /** Nano seconds. */ - uint32_t tv_nsec; -} gs_timestamp_t; - -/** - @deprecated Use gs_timestamp_t -*/ -typedef gs_timestamp_t timestamp_t; - -/** - Add 2 timestamp's (t1 = t1 + t2). - @param[in,out] t1 timestamp - @param[in] t2 timestamp. - @return 0 on success, otherwise -1 -*/ -int timestamp_add(gs_timestamp_t * t1, const gs_timestamp_t * t2); - -/** - Subtract 2 timestamp's (t1 = t1 - t2) - @param[in,out] t1 timestamp - @param[in] t2 timestamp. - @return 0 on success, otherwise -1 -*/ -int timestamp_diff(gs_timestamp_t * t1, const gs_timestamp_t * t2); - -/** - Check if t2 is greate than t1. - @param[in] t1 time to compare - @param[in] t2 time to compare - @return 1 if t2 > t1, else 0. -1 on bad arguments. -*/ -int timestamp_ge(const gs_timestamp_t * t1, const gs_timestamp_t * t2); - -/** - Copy timestamp. - @param[in] from from timestamp - @param[out] to to timestamp - @return 0 on success, otherwise -1 -*/ -int timestamp_copy(const gs_timestamp_t * from, gs_timestamp_t * to); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/types.h b/gomspace/libutil/include/gs/util/types.h deleted file mode 100644 index 2c0d0597..00000000 --- a/gomspace/libutil/include/gs/util/types.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef GS_UTIL_TYPES_H -#define GS_UTIL_TYPES_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Base type definitions and functions. - - In some rare cases, it is impossible to make code that works on all platforms. In these cases the following defines may be used to - exclude/include code: - | define | Platform | - | :----: | :---- | - | \_\_AVR\_\_ | 8 bit, e.g. atmega1281, atmega2560, attiny25, attiny44, attiny84 | - | \_\_linux\_\_ | 32/64 bit, Linux based | - - -*/ - -#include // intXX_t -#include // bool -#include // size_t - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Control static declaration at compile time. - Allows unit tests to access internal functions or variables. - @note Static declared variables are initialized to zero by the compiler - BUT if you use GS_NO_STATIC instead of static, they will not be initialized. -*/ -#if GS_NO_STATIC -#define GS_STATIC -#else -#define GS_STATIC static -#endif - -/** - Convert integer to pointer. -*/ -#define GS_TYPES_INT2PTR(value) ((void*)(intptr_t)(value)) - -/** - Convert integer to pointer. -*/ -#define GS_TYPES_UINT2PTR(value) ((void*)(uintptr_t)(value)) - -/** - Convert pointer to integer. -*/ -#define GS_TYPES_PTR2INT(value) ((intptr_t)(void*)(value)) - -/** - Convert pointer to integer. -*/ -#define GS_TYPES_PTR2UINT(value) ((uintptr_t)(void*)(value)) - -/** - Assert on 'value'. - - Example: - GS_STATIC_ASSERT(sizeof(int) >= 2, int_must_be_at_least_16bit); - fails if size of (int) is less than 2 bytes. -*/ -#define GS_STATIC_ASSERT(condition, name) typedef char name[(condition) ? 1 : -1] - -/** - Context switch state. - Used by FreeRTOS when waking a higher priority task/thread from within an ISR. - The actual struct is defined in libembed. -*/ -typedef struct gs_context_switch gs_context_switch_t; - -/** - Return element count of array. -*/ -#define GS_ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) - -/** - Address union. -*/ -typedef union { - /** - Normal address pointer. - */ - void* p; - /** - Address pointer as an unsigned value. - */ - uintptr_t u; -} gs_address_t; - -/** - @cond HIDDEN_SYMBOLS - Compile check size of primitives (just to be sure, that they are what we expect). -*/ -GS_STATIC_ASSERT(sizeof(gs_address_t) == sizeof(void*), unexpected_address_void_pointer_size); -GS_STATIC_ASSERT(sizeof(gs_address_t) == sizeof(uintptr_t), unexpected_address_uintptr_size); -GS_STATIC_ASSERT(sizeof(bool) == sizeof(uint8_t), unexpected_bool_size); -GS_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), unexpected_float_size); -#if (__AVR__) -// avr/avr8 is 8 bit -GS_STATIC_ASSERT(sizeof(int) == sizeof(int16_t), unexpected_int_size_on_avr8); -#else -// rest should be 32 or 64 bit -GS_STATIC_ASSERT(sizeof(int) == sizeof(int32_t), unexpected_int_size); -GS_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t), unexpected_double_size); -#endif -/** @endcond */ - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/unistd.h b/gomspace/libutil/include/gs/util/unistd.h deleted file mode 100644 index a8b65845..00000000 --- a/gomspace/libutil/include/gs/util/unistd.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef GS_UTIL_UNISTD_H -#define GS_UTIL_UNISTD_H -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - GomSpace extensions to standard \a unistd.h. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Get current working directory. - - @note Linux uses standard getcwd(). - - @param[out] buf user supplied buffer for returning path. - @param[in] bufsize size of \a buf. - @return #GS_ERROR_NOT_FOUND if no current directory is set. - @return #GS_ERROR_RANGE if \a buf is too small - @return_gs_error_t -*/ -gs_error_t gs_getcwd(char * buf, size_t bufsize); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/vmem.h b/gomspace/libutil/include/gs/util/vmem.h deleted file mode 100644 index 19576a63..00000000 --- a/gomspace/libutil/include/gs/util/vmem.h +++ /dev/null @@ -1,194 +0,0 @@ -#ifndef GS_UTIL_VMEM_H -#define GS_UTIL_VMEM_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Virtual memory interface. - - The API provides support for accessing different hardware components using a common API, by providing a component specific driver. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Virtual memory mapping. -*/ -typedef struct gs_vmem gs_vmem_t; - -/** - VMEM driver write. - - @param[in] vmem vmem entry. - @param[in] to Address where to write data to. - @param[in] from Address where to write data from. - @param[in] size Number of bytes to write. - @return_gs_error_t -*/ -typedef gs_error_t (*gs_vmem_write_function_t)(const gs_vmem_t * vmem, void* to, const void * from, size_t size); - -/** - VMEM driver read. - - @param[in] vmem vmem entry. - @param[in] to Address where to read data to. - @param[in] from Address where to read data from. - @param[in] size Number of bytes to read. - @return_gs_error_t -*/ -typedef gs_error_t (*gs_vmem_read_function_t)(const gs_vmem_t * vmem, void* to, const void * from, size_t size); - -/** - VMEM driver lock. - - @param[in] vmem vmem entry. - @param[in] on Enable/Disable lock. - @return_gs_error_t -*/ -typedef gs_error_t (*gs_vmem_lock_function_t)(const gs_vmem_t * vmem, bool on); - -/** - VMEM driver information. - - Return relevant information for the VMEM driver. - - @param[in] vmem vmem entry. - @param[in] buffer user allocated buffer for returning information. - @param[in] buffer_size size (length) of \a buffer. - @return_gs_error_t -*/ -typedef gs_error_t (*gs_vmem_info_function_t)(const gs_vmem_t * vmem, char * buffer, size_t buffer_size); - -/** - VMEM driver interface. -*/ -typedef struct { - /** - Write function. - */ - const gs_vmem_write_function_t write; - /** - Read function. - */ - const gs_vmem_read_function_t read; - /** - Lock function. - */ - const gs_vmem_lock_function_t lock; - /** - Information function. - */ - const gs_vmem_info_function_t info; -} gs_vmem_driver_t; - -/** - Virtual memory mapping. - - @note Call gs_vmem_set_map() for registering mappings. -*/ -struct gs_vmem { - /** - Logical name of enry. - */ - const char *const name; - /** - Virtual memory start. - */ - gs_address_t virtmem; - /** - Physical memory start. - This address only makes sense for the VMEM driver. - */ - gs_address_t physmem; - /** - Size of memory block. - */ - const size_t size; - /** - Driver function. - */ - const gs_vmem_driver_t* drv; - /** - Driver data. - */ - const void* drv_data; -}; - -/** - Set VMEM mapping. - Must be done for the API to work. - @param[in] map VMEM mapping table, must be terminated with an NULL entry. - @return_gs_error_t -*/ -gs_error_t gs_vmem_set_map(const gs_vmem_t * map); - -/** - Return VMEM map. -*/ -const gs_vmem_t * gs_vmem_get_map(void); - -/** - Print all VMEM entries to stdout. - @param[in] out output stream - @return_gs_error_t -*/ -gs_error_t gs_vmem_list(FILE * out); - -/** - Get VMEM entry by name. - @param[in] name name of VMEM entry. - @return VMEM mapping or NULL if not found. -*/ -const gs_vmem_t * gs_vmem_get_by_name(const char * name); - -/** - Lock/un-lock VMEM area. - @param[in] name name of VMEM entry. - @param[in] on Enable/Disable lock. - @return GS_ERROR_NOT_FOUND area not found. - @return GS_ERROR_NOT_SUPPORTED if locking isn't supported. - @return_gs_error_t -*/ -gs_error_t gs_vmem_lock_by_name(const char * name, bool on); - -/** - Lock/un-lock all VMEM areas. - @param[in] on lock on or off. - @return_gs_error_t -*/ -gs_error_t gs_vmem_lock_all(bool on); - -/** - memcpy on VMEM. - @note if no VMEM entries are found, a normal memcpy is called with the provided pointers. - @param[in] to to location. - @param[in] from from location. - @param[in] size number of bytes to copy. -*/ -void* gs_vmem_cpy(void* to, const void* from, size_t size); - -/** - Macro for calling gs_vmem_cpy(). -*/ -#define GS_VMEM_CPY(to, from, size) gs_vmem_cpy(to, from, size) - -/** - Macro for calling gs_vmem_cpy(). - @deprecated Use gs_vmem_cpy() directly. -*/ -#define VMEM_CPY(to, from, size) gs_vmem_cpy(to, from, size) - -/** - Register VMEM commands. - @return_gs_error_t -*/ -gs_error_t gs_vmem_register_commands(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/watchdog/watchdog.h b/gomspace/libutil/include/gs/util/watchdog/watchdog.h deleted file mode 100644 index 30d2bd30..00000000 --- a/gomspace/libutil/include/gs/util/watchdog/watchdog.h +++ /dev/null @@ -1,143 +0,0 @@ -#ifndef GS_UTIL_WATCHDOG_WATCHDOG_H -#define GS_UTIL_WATCHDOG_WATCHDOG_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Software watchdog client interface. - - The software watchdog (SWWD) enables having multiple instances of a Watchdog. - The software watchdog manages the HW watchdog, and will ultimately - trigger the HW watchdog, if one or more clients are not servicing the - software watchdog. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Software Watchdog handle -*/ -typedef struct gs_swwd_hdl gs_swwd_hdl_t; - -/** - Software watchdog callback function. - - Called by the SWWD upon timeout. - @param[in] userdata user data provided on gs_swwd_register() -*/ -typedef void (*gs_swwd_callback_function_t)(void * userdata); - -/** - Watchdog timeout action. -*/ -typedef enum { - /** - Reset system on timeout (stops touching the hardware watchdog). - Once the watchdog has timeout, the watchdog cannot be re-activated. - */ - GS_SWWD_TIMEOUT_ACTION_RESET = 0, - /** - Log 'warning' on timeout, but otherwise ignore the timeout. - The watchdog can re-activated by touching the watchdog again. - */ - GS_SWWD_TIMEOUT_ACTION_LOG = 1, -} gs_swwd_timeout_action_t; - -/** - Create the software watchdog back-end. - - Only one SWWD back-end can exist at any given time. - - @param[in] max_clients The maximum number of Software Watchog clients supported. - @param[in] dev The HW Watchdog device to use. - @return_gs_error_t -*/ -gs_error_t gs_swwd_create(uint32_t max_clients, gs_watchdog_device_t *dev); - -/** - Destroy the Software Watchdog back-end (and stop the SWWD monitor task if started). - - @param[in] timeout_s Maximum number of seconds to allow this operation to complete. - @return_gs_error_t -*/ -gs_error_t gs_swwd_destroy(uint32_t timeout_s); - -/** - Check for expired software watchdog clients. This function is only to be used if the - SWWD monitor task is not started. Otherwise the SWWD task will handle this in the back- - ground. I.e: - - In passive mode this function must be called periodically to check for expired - clients, and service the HW watchdog. - - In active mode this function is called in background by the SWWD monitor task. - - The interval between these checks should be much less that the HW watchdog - timeout period, to ensure that the HW Watchdog is correctly serviced. - Calling this e.g. every 1-3 seconds will be a good default. - - @param[out] num_expired The number of SW Watchog clients currently expired. - @return_gs_error_t -*/ -gs_error_t gs_swwd_check_expired_clients(uint32_t *num_expired); - -/** - Register/create a new software watchdog instance - - @param[out] wdt_handle A reference to software watchdog handle - @param[in] timeout Timeout in seconds. - @param[in] callback Callback function which is called on timeout. NULL if unused. - @param[in] userdata Pointer to user data used in the callback function. Ignored if callback is NULL. - @param[in] client_name A descriptive name given by the user in order to identify the watchdog/client - the pointer must remain valid as long as the watchdog is registered. - @param[in] action what action to take, when/if the watchdog times out. - @return_gs_error_t -*/ -gs_error_t gs_swwd_register_with_action(gs_swwd_hdl_t ** wdt_handle, uint32_t timeout, gs_swwd_callback_function_t callback, void * userdata, const char *client_name, gs_swwd_timeout_action_t action); - -/** - Register/create a software watchdog with action \a reset on timeout. - - @param[out] wdt_handle A reference to software watchdog handle - @param[in] timeout Timeout in seconds before the software watchdog fires. - @param[in] callback Callback function which is called on timeout. NULL if unused. - @param[in] userdata Pointer to user data used in the callback function. Ignored if callback is NULL. - @param[in] client_name A descriptive name given by the user in order to identify the watchdog/client - the pointer must remain valid as long as the watchdog is registered. - @return_gs_error_t -*/ -static inline gs_error_t gs_swwd_register(gs_swwd_hdl_t ** wdt_handle, uint32_t timeout, gs_swwd_callback_function_t callback, void * userdata, const char *client_name) -{ - return gs_swwd_register_with_action(wdt_handle, timeout, callback, userdata, client_name, GS_SWWD_TIMEOUT_ACTION_RESET); -} - -/** - De-Register a Software Watchdog instance - - @param[in] wdt_handle A software watchdog handle - @return_gs_error_t -*/ -gs_error_t gs_swwd_deregister(gs_swwd_hdl_t ** wdt_handle); - -/** - Touch Software Watchdog to reset the timer - - @param[in] wdt_handle A software watchdog handle - @return_gs_error_t -*/ -gs_error_t gs_swwd_touch(gs_swwd_hdl_t * wdt_handle); - -/** - Set timeout of the Software Watchdog. - - @param[in] wdt_handle A software watchdog handle - @param[in] timeout Timeout in seconds before the SWWD fires. - @return_gs_error_t -*/ -gs_error_t gs_swwd_set_timeout(gs_swwd_hdl_t * wdt_handle, uint32_t timeout); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/watchdog/watchdog_task.h b/gomspace/libutil/include/gs/util/watchdog/watchdog_task.h deleted file mode 100644 index 833f1511..00000000 --- a/gomspace/libutil/include/gs/util/watchdog/watchdog_task.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef GS_UTIL_WATCHDOG_WATCHDOG_TASK_H -#define GS_UTIL_WATCHDOG_WATCHDOG_TASK_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Software Watchdog server/task interface - - The Software Watchdog task implements the core (backend) functionality of the the software watchdog. - The Client API for the SW watchdog is implemented in watchdog.h - - @note This API is not thread safe! -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Start the Software Watchdog monitor task if the SWWD is to be used as a - separate task (active mode). - In this case the SWWD task will monitor expired clients in the background - and the polling API gs_swwd_check_expired_clients() needs not to be called by - the user. - - @return_gs_error_t -*/ - -gs_error_t gs_swwd_monitor_task_start(); - -/** - Stops the Software Watchdog monitor task - - @param[in] timeout_s Maximum number of seconds to allow this operation to complete. - - @return_gs_error_t -*/ -gs_error_t gs_swwd_monitor_task_stop(uint32_t timeout_s); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/gomspace/libutil/include/gs/util/zip/zip.h b/gomspace/libutil/include/gs/util/zip/zip.h deleted file mode 100644 index 04c87974..00000000 --- a/gomspace/libutil/include/gs/util/zip/zip.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef LIBUTIL_ZIP_ZIP_UTILS_H -#define LIBUTIL_ZIP_ZIP_UTILS_H -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - Compress/decompress API based on zlib compressed data format specification standards. -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/** - Compress file. - - @param[in] src file to be compressed. - @param[out] dest compressed output file. - @return_gs_error_t -*/ -int gs_zip_compress_file(const char *src, const char *dest); - -/** - Decompress file. - - @param[in] src file to be secompressed. - @param[out] dest decompressed output file. - @return_gs_error_t -*/ -int gs_zip_decompress_file(const char *src, const char *dest); - -/** - Compress data. - - @param[in] src pointer to the data to be compressed. - @param[in] src_len size of the data. - @param[out] dest pointer to the compressed data. - @param[out] dest_len pointer to the size of the compressed data. - @return_gs_error_t -*/ -int gs_zip_compress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t *dest_len); - -/** - Decompress data. - - @param[in] src pointer to the data to be decompressed. - @param[in] src_len size of the data. - @param[out] dest pointer to the decompressed data. - @param[out] dest_len size of the destination memory area. - @param[out] decomp_len pointer to the size of the decompressed data. - @return_gs_error_t -*/ -int gs_zip_decompress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t dest_len, uint32_t *decomp_len); - - -#ifdef __cplusplus -} -#endif -#endif /* LIBUTIL_ZIP_ZIP_UTILS_H */ diff --git a/gomspace/libutil/src/base16.c b/gomspace/libutil/src/base16.c deleted file mode 100644 index da3a83c6..00000000 --- a/gomspace/libutil/src/base16.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2010 Michael Brown . - * - * This program 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 2 of the - * License, or any later version. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -void base16_encode(const uint8_t * raw, size_t len, char *encoded) -{ - const uint8_t *raw_bytes = raw; - char *encoded_bytes = encoded; - size_t remaining = len; - - for (; remaining--; encoded_bytes += 2) - snprintf(encoded_bytes, 3, "%02X", *(raw_bytes++)); - -} - -int base16_decode(const char *encoded, uint8_t *raw) -{ - uint8_t *raw_bytes = raw; - if (encoded) { - const char *encoded_bytes = encoded; - char buf[3]; - char *endp; - - while (encoded_bytes[0]) { - if (!encoded_bytes[1]) { - log_error("Base16-encoded string \"%s\" has invalid length\n", - encoded); - return GS_ERROR_ARG; - } - memcpy(buf, encoded_bytes, 2); - buf[2] = '\0'; - *(raw_bytes++) = (uint8_t) strtoul(buf, &endp, 16); - if (*endp != '\0') { - log_error("Base16-encoded string \"%s\" has invalid byte \"%s\"\n", - encoded, buf); - return GS_ERROR_ARG; - } - encoded_bytes += 2; - } - } - return (int)(raw_bytes - raw); -} diff --git a/gomspace/libutil/src/bindings/python/pyutil.c b/gomspace/libutil/src/bindings/python/pyutil.c deleted file mode 100644 index b2924ba6..00000000 --- a/gomspace/libutil/src/bindings/python/pyutil.c +++ /dev/null @@ -1,73 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -#if PY_MAJOR_VERSION == 3 -#define IS_PY3 -#endif - -/** - * Helpers - */ - -static PyObject* pyutil_get_clock_time(PyObject *self, PyObject *args) { - gs_timestamp_t ts; - gs_clock_get_time(&ts); - return Py_BuildValue("II", ts.tv_sec, ts.tv_nsec); -} - - -static PyObject* pyutil_error_string(PyObject *self, PyObject *args) -{ - int error; - if (!PyArg_ParseTuple(args, "i", &error)) - { - Py_RETURN_NONE; - } - return Py_BuildValue("s", gs_error_string(error)); -} - -static PyMethodDef methods[] = { - - /* helpers */ - {"get_clock_time", pyutil_get_clock_time, METH_NOARGS, ""}, - {"error_string", pyutil_error_string, METH_VARARGS, ""}, - - /* sentinel */ - {NULL, NULL, 0, NULL} -}; - -#ifdef IS_PY3 -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "libgsutil_py3", - NULL, /* module documentation, may be NULL */ - -1, /* size of per-interpreter state of the module, - or -1 if the module keeps state in global variables. */ - methods, - NULL, - NULL, - NULL, - NULL -}; -#endif - -#ifdef IS_PY3 -PyMODINIT_FUNC PyInit_libgsutil_py3(void) { -#else -PyMODINIT_FUNC initlibgsutil_py2(void) { -#endif - -#ifdef IS_PY3 - PyObject* m = PyModule_Create(&moduledef); -#else - Py_InitModule("libgsutil_py2", methods); -#endif - -#ifdef IS_PY3 - return m; -#endif -} - diff --git a/gomspace/libutil/src/bytebuffer.c b/gomspace/libutil/src/bytebuffer.c deleted file mode 100644 index 49b5a495..00000000 --- a/gomspace/libutil/src/bytebuffer.c +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -#define GS_BYTEBUFFER_F_FAILED 0x01 -#define GS_BYTEBUFFER_F_OVERRUN 0x02 - -gs_error_t gs_bytebuffer_init(gs_bytebuffer_t * bb, void * buffer, size_t buffer_size) -{ - GS_CHECK_HANDLE(bb != NULL); - memset(bb, 0, sizeof(*bb)); - if (buffer) { - if (buffer_size < 2) { - // must always have room for NUL termination. - return GS_ERROR_ARG; - } - bb->buffer = buffer; - bb->size = buffer_size; - } else { - // dry run - don't insert anything in buffer, but increment used - } - - return GS_OK; -} - -void gs_bytebuffer_vprintf(gs_bytebuffer_t * bb, const char * format, va_list ap) -{ - int res; - if (bb->buffer == NULL) { - // dry run - char buf[3]; - res = vsnprintf(buf, 0, format, ap); - if (res >= 0) { - bb->used += res; - } - } else { - const size_t free_bytes = gs_bytebuffer_get_free(bb); - res = vsnprintf((char*)&bb->buffer[bb->used], free_bytes, format, ap); - if (res > 0) { - if ((size_t)res >= free_bytes) { - // over run - bb->flags |= GS_BYTEBUFFER_F_OVERRUN; - bb->used = bb->size; - bb->buffer[bb->size - 1] = 0; - } else { - bb->used += res; - } - } - } - if (res < 0) { - bb->flags |= GS_BYTEBUFFER_F_FAILED; - } -} - -void gs_bytebuffer_printf(gs_bytebuffer_t * bb, const char * format, ...) -{ - va_list ap; - va_start(ap, format); - gs_bytebuffer_vprintf(bb, format, ap); - va_end(ap); -} - -void gs_bytebuffer_append(gs_bytebuffer_t * bb, const void * data, size_t length) -{ - if (bb->buffer == NULL) { - // dry run - bb->used += length; - } else { - const size_t free_bytes = gs_bytebuffer_get_free(bb); - if (free_bytes >= length) { - memcpy(&bb->buffer[bb->used], data, length); - bb->used += length; - } else { - memcpy(&bb->buffer[bb->used], data, free_bytes); - bb->flags |= GS_BYTEBUFFER_F_OVERRUN; - bb->used += free_bytes; - } - } -} - -void gs_bytebuffer_append_string(gs_bytebuffer_t * bb, const char * string) -{ - if (gs_string_empty(string) == false) { - gs_bytebuffer_append(bb, string, strlen(string)); - } -} - -void gs_bytebuffer_append_string_max(gs_bytebuffer_t * bb, const char * string, size_t max_length) -{ - if (gs_string_empty(string) == false) { - gs_bytebuffer_append(bb, string, strnlen(string, max_length)); - } -} - -char * gs_bytebuffer_get_as_string(gs_bytebuffer_t * bb, gs_error_t * error) -{ - if (bb && bb->buffer) { - // handle NUL termination - if (bb->used < bb->size) { - bb->buffer[bb->used] = 0; - } else { - // overrun - truncation buffer - bb->flags |= GS_BYTEBUFFER_F_OVERRUN; - bb->buffer[bb->used - 1] = 0; - } - if (error) { - *error = gs_bytebuffer_get_state(bb); - } - return (char*) bb->buffer; - } - return NULL; -} - -gs_error_t gs_bytebuffer_get_state(gs_bytebuffer_t * bb) -{ - if (bb) { - if (bb->flags & GS_BYTEBUFFER_F_FAILED) { - return GS_ERROR_DATA; - } - if (bb->flags & GS_BYTEBUFFER_F_OVERRUN) { - return GS_ERROR_OVERFLOW; - } - return GS_OK; - } - return GS_ERROR_HANDLE; -} diff --git a/gomspace/libutil/src/byteorder.c b/gomspace/libutil/src/byteorder.c deleted file mode 100644 index e00c9737..00000000 --- a/gomspace/libutil/src/byteorder.c +++ /dev/null @@ -1,323 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include - -/* Convert 16-bit number from host byte order to network byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_hton16(uint16_t h16) { -#if UTIL_BIG_ENDIAN - return h16; - -#elif UTIL_LITTLE_ENDIAN - return (uint16_t)(((h16 & 0xff00) >> 8) | - ((h16 & 0x00ff) << 8)); -#endif -} - -/* Convert 16-bit number from network byte order to host byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_ntoh16(uint16_t n16) { - return util_hton16(n16); -} - -/* Convert 32-bit number from host byte order to network byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_hton32(uint32_t h32) { -#if UTIL_BIG_ENDIAN - return h32; - -#elif UTIL_LITTLE_ENDIAN - return (((h32 & 0xff000000) >> 24) | - ((h32 & 0x000000ff) << 24) | - ((h32 & 0x0000ff00) << 8) | - ((h32 & 0x00ff0000) >> 8)); -#endif -} - -/* Convert 32-bit number from network byte order to host byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_ntoh32(uint32_t n32) { - return util_hton32(n32); -} - -/* Convert 64-bit number from host byte order to network byte order */ -extern inline uint64_t __attribute__ ((__const__)) util_hton64(uint64_t h64) { -#if UTIL_BIG_ENDIAN - return h64; - -#elif UTIL_LITTLE_ENDIAN - return (((h64 & 0xff00000000000000LL) >> 56) | - ((h64 & 0x00000000000000ffLL) << 56) | - ((h64 & 0x00ff000000000000LL) >> 40) | - ((h64 & 0x000000000000ff00LL) << 40) | - ((h64 & 0x0000ff0000000000LL) >> 24) | - ((h64 & 0x0000000000ff0000LL) << 24) | - ((h64 & 0x000000ff00000000LL) >> 8) | - ((h64 & 0x00000000ff000000LL) << 8)); -#endif -} - -/* Convert 64-bit number from host byte order to network byte order */ -extern inline uint64_t __attribute__ ((__const__)) util_ntoh64(uint64_t n64) { - return util_hton64(n64); -} - -/* Convert float from host byte order to network byte order */ -extern inline float __attribute__ ((__const__)) util_htonflt(float f) { -#if UTIL_BIG_ENDIAN - return f; - -#elif UTIL_LITTLE_ENDIAN - union v { - float f; - uint32_t i; - }; - union v val; - val.f = f; - val.i = util_hton32(val.i); - return val.f; -#endif -} - -/* Convert float from host byte order to network byte order */ -extern inline float __attribute__ ((__const__)) util_ntohflt(float f) { - return util_htonflt(f); -} - -/* Convert double from host byte order to network byte order */ -extern inline double __attribute__ ((__const__)) util_htondbl(double d) { -#if UTIL_BIG_ENDIAN - return d; - -#elif UTIL_LITTLE_ENDIAN - union v { - double d; - uint64_t i; - }; - union v val; - val.d = d; - val.i = util_hton64(val.i); - return val.d; -#endif -} - -/* Convert float from host byte order to network byte order */ -extern inline double __attribute__ ((__const__)) util_ntohdbl(double d) { - return util_htondbl(d); -} - -/* Convert 16-bit number from host byte order to big endian byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_htobe16(uint16_t h16) { - return util_hton16(h16); -} - -/* Convert 16-bit number from host byte order to little endian byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_htole16(uint16_t h16) { -#if UTIL_LITTLE_ENDIAN - return h16; - -#elif UTIL_BIG_ENDIAN - return (uint16_t)(((h16 & 0xff00) >> 8) | - ((h16 & 0x00ff) << 8)); -#endif -} - -/* Convert 16-bit number from big endian byte order to little endian byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_betoh16(uint16_t be16) { - return util_ntoh16(be16); -} - -/* Convert 16-bit number from little endian byte order to host byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_letoh16(uint16_t le16) { - return util_htole16(le16); -} - -/* Convert 32-bit number from host byte order to big endian byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_htobe32(uint32_t h32) { - return util_hton32(h32); -} - -/* Convert 32-bit number from little endian byte order to host byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_htole32(uint32_t h32) { -#if UTIL_LITTLE_ENDIAN - return h32; - -#elif UTIL_BIG_ENDIAN - return (((h32 & 0xff000000) >> 24) | - ((h32 & 0x000000ff) << 24) | - ((h32 & 0x0000ff00) << 8) | - ((h32 & 0x00ff0000) >> 8)); -#endif -} - -/* Convert 32-bit number from big endian byte order to host byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_betoh32(uint32_t be32) { - return util_ntoh32(be32); -} - -/* Convert 32-bit number from little endian byte order to host byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_letoh32(uint32_t le32) { - return util_htole32(le32); -} - -/* Convert 64-bit number from host byte order to big endian byte order */ -extern inline uint64_t __attribute__ ((__const__)) util_htobe64(uint64_t h64) { - return util_hton64(h64); -} - -/* Convert 64-bit number from host byte order to little endian byte order */ -extern inline uint64_t __attribute__ ((__const__)) util_htole64(uint64_t h64) { -#if UTIL_LITTLE_ENDIAN - return h64; - -#elif UTIL_BIG_ENDIAN - return (((h64 & 0xff00000000000000LL) >> 56) | - ((h64 & 0x00000000000000ffLL) << 56) | - ((h64 & 0x00ff000000000000LL) >> 40) | - ((h64 & 0x000000000000ff00LL) << 40) | - ((h64 & 0x0000ff0000000000LL) >> 24) | - ((h64 & 0x0000000000ff0000LL) << 24) | - ((h64 & 0x000000ff00000000LL) >> 8) | - ((h64 & 0x00000000ff000000LL) << 8)); -#endif -} - -/* Convert 64-bit number from big endian byte order to host byte order */ -extern inline uint64_t __attribute__ ((__const__)) util_betoh64(uint64_t be64) { - return util_ntoh64(be64); -} - -/* Convert 64-bit number from little endian byte order to host byte order */ -extern inline uint64_t __attribute__ ((__const__)) util_letoh64(uint64_t le64) { - return util_htole64(le64); -} - -/* Convert 16-bit number from host byte order to network byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_htons(uint16_t h16) { - return util_hton16(h16); -} - -/* Convert 16-bit number from network byte order to host byte order */ -extern inline uint16_t __attribute__ ((__const__)) util_ntohs(uint16_t n16) { - return util_ntoh16(n16); -} - -/* Convert 32-bit number from host byte order to network byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_htonl(uint32_t h32) { - return util_hton32(h32); -} - -/* Convert 32-bit number from network byte order to host byte order */ -extern inline uint32_t __attribute__ ((__const__)) util_ntohl(uint32_t n32) { - return util_ntoh32(n32); -} - -#define BYTEORDER_ARRAY(convert, from, to, count) { \ - for (unsigned int i = 0; i < count; ++i, ++from, ++to) { \ - *to = convert(*from); \ - } \ - } - -void util_hton16_array(const uint16_t * from, uint16_t * to, size_t count) -{ - BYTEORDER_ARRAY(util_hton16, from, to, count); -} - -void util_hton32_array(const uint32_t * from, uint32_t * to, size_t count) -{ - BYTEORDER_ARRAY(util_hton32, from, to, count); -} - -void util_hton64_array(const uint64_t * from, uint64_t * to, size_t count) -{ - BYTEORDER_ARRAY(util_hton64, from, to, count); -} - -void util_ntoh16_array(const uint16_t * from, uint16_t * to, size_t count) -{ - BYTEORDER_ARRAY(util_ntoh16, from, to, count); -} - -void util_ntoh32_array(const uint32_t * from, uint32_t * to, size_t count) -{ - BYTEORDER_ARRAY(util_ntoh32, from, to, count); -} - -void util_ntoh64_array(const uint64_t * from, uint64_t * to, size_t count) -{ - BYTEORDER_ARRAY(util_ntoh64, from, to, count); -} - -void util_htonflt_array(const float * from, float * to, size_t count) -{ - BYTEORDER_ARRAY(util_htonflt, from, to, count); -} - -void util_ntohflt_array(const float * from, float * to, size_t count) -{ - BYTEORDER_ARRAY(util_ntohflt, from, to, count); -} - -void util_htondbl_array(const double * from, double * to, size_t count) -{ - BYTEORDER_ARRAY(util_htondbl, from, to, count); -} - -void util_ntohdbl_array(const double * from, double * to, size_t count) -{ - BYTEORDER_ARRAY(util_ntohdbl, from, to, count); -} - -uint16_t gs_bswap_16(uint16_t value) -{ - return (uint16_t)(((value & 0xff00) >> 8) | - ((value & 0x00ff) << 8)); -} - -void gs_bswap_16_array(const uint16_t * from, uint16_t * to, size_t count) -{ - BYTEORDER_ARRAY(gs_bswap_16, from, to, count); -} - -uint32_t gs_bswap_32(uint32_t value) -{ - return (((value & 0xff000000) >> 24) | - ((value & 0x000000ff) << 24) | - ((value & 0x0000ff00) << 8) | - ((value & 0x00ff0000) >> 8)); -} - -void gs_bswap_32_array(const uint32_t * from, uint32_t * to, size_t count) -{ - BYTEORDER_ARRAY(gs_bswap_32, from, to, count); -} - -uint64_t gs_bswap_64(uint64_t value) -{ - return (((value & 0xff00000000000000LL) >> 56) | - ((value & 0x00000000000000ffLL) << 56) | - ((value & 0x00ff000000000000LL) >> 40) | - ((value & 0x000000000000ff00LL) << 40) | - ((value & 0x0000ff0000000000LL) >> 24) | - ((value & 0x0000000000ff0000LL) << 24) | - ((value & 0x000000ff00000000LL) >> 8) | - ((value & 0x00000000ff000000LL) << 8)); -} - -void gs_bswap_64_array(const uint64_t * from, uint64_t * to, size_t count) -{ - BYTEORDER_ARRAY(gs_bswap_64, from, to, count); -} - -float gs_bswap_float(float value) -{ - union v { - float f; - uint32_t i; - } val; - val.f = value; - val.i = gs_bswap_32(val.i); - return val.f; -} - -void gs_bswap_float_array(const float * from, float * to, size_t count) -{ - BYTEORDER_ARRAY(gs_bswap_float, from, to, count); -} diff --git a/gomspace/libutil/src/clock.c b/gomspace/libutil/src/clock.c deleted file mode 100644 index ac215df6..00000000 --- a/gomspace/libutil/src/clock.c +++ /dev/null @@ -1,113 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include - -#if !__AVR__ -#include -#endif - -gs_error_t gs_clock_to_iso8601_string2(uint32_t utc_sec, char * buf, size_t buf_size) -{ - if ((buf == NULL) || (buf_size == 0)) { - return GS_ERROR_ARG; - } - -#if __AVR__ - int res = snprintf(buf, buf_size, "%"PRIu32"Z", utc_sec); - if ((res < 0) || ((size_t)res >= buf_size)) { - buf[buf_size - 1] = 0; - return GS_ERROR_RANGE; - } -#else - const time_t time_seconds = (time_t) utc_sec; - struct tm tm_buf; - struct tm * tm = gmtime_r(&time_seconds, &tm_buf); - if (tm == NULL) { - int res = snprintf(buf, buf_size, "%ldZ", time_seconds); - if ((res < 0) || ((size_t)res >= buf_size)) { - buf[buf_size - 1] = 0; - } - return GS_ERROR_DATA; - } - - // ISO8601 timestamp: 2017-03-30T06:20:45Z - int res = snprintf(buf, buf_size, "%04d-%02d-%02dT%02d:%02d:%02dZ", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - if ((res < 0) || ((size_t)res >= buf_size)) { - buf[buf_size - 1] = 0; - return GS_ERROR_RANGE; - } -#endif - - return GS_OK; -} - -gs_error_t gs_clock_to_iso8601_string(const gs_timestamp_t * utc_time, char * buf, size_t buf_size) -{ - if (utc_time == NULL) { - return GS_ERROR_ARG; - } - - return gs_clock_to_iso8601_string2(utc_time->tv_sec, buf, buf_size); -} - -gs_error_t gs_clock_from_string(const char * str, gs_timestamp_t * ts) -{ - if (!str || !str[0] || !ts) { - return GS_ERROR_ARG; - } - - // check for . - { - uint32_t sec; - uint32_t nsec; - int res = sscanf(str, "%" SCNu32 ".%" SCNu32, &sec, &nsec); - if (res == 2) { - ts->tv_sec = sec; - ts->tv_nsec = nsec; - return GS_OK; - } - } - -#if !__AVR__ - // check for ISO8601 - { - struct tm tm; - memset(&tm, 0, sizeof(tm)); // no daylight saving - //int res = sscanf(str, "%" SCNd32 "-%" SCNd32 "-%" SCNd32 "T%" SCNd32 ":%" SCNd32 ":%" SCNd32 "Z", - int res = sscanf(str, "%d-%d-%dT%d:%d:%dZ", - &tm.tm_year, &tm.tm_mon, &tm.tm_mday, - &tm.tm_hour, &tm.tm_min, &tm.tm_sec); - if ((res == 6) && - (tm.tm_year >= 1970) && (tm.tm_year <= 2038) && - (tm.tm_mon >= 1) && (tm.tm_mon <= 12) && - (tm.tm_mday >= 1) && (tm.tm_mday <= 31) && - (tm.tm_hour >= 0) && (tm.tm_hour <= 23) && - (tm.tm_min >= 0) && (tm.tm_min <= 59) && - (tm.tm_sec >= 0) && (tm.tm_sec <= 60)) - { - tm.tm_year -= 1900; - tm.tm_mon -= 1; - -#if __linux__ - // not posix compliant - time_t sec = timegm(&tm); -#else - // embedded platforms do not have timezones/daylight-saving - so standard mktime works - time_t sec = mktime(&tm); -#endif - if (sec >= 0) { - ts->tv_sec = (uint32_t) sec; - ts->tv_nsec = 0; - return GS_OK; - } - } - } -#endif - - return GS_ERROR_DATA; -} diff --git a/gomspace/libutil/src/crc32.c b/gomspace/libutil/src/crc32.c deleted file mode 100644 index 90d21832..00000000 --- a/gomspace/libutil/src/crc32.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * efone - Distributed internet phone system. - * - * (c) 1999,2000 Krzysztof Dabrowski - * (c) 1999,2000 ElysiuM deeZine - * - * This program 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 - * 2 of the License, or (at your option) any later version. - * - * Based on implementation by Finn Yannick Jacobs - */ - -#include -#include - -static const uint32_t crc_tab[256] GS_PGM_OBJECT = { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -}; - -#define CALC_CRC32_STEP(crc,byte) (((crc >> 8) & 0x00FFFFFF) ^ GS_PGM_UINT32_BY_PTR(&crc_tab[(crc ^ byte) & (uint32_t) 0xFF])) - -uint32_t gs_crc32_init(void) -{ - return 0xFFFFFFFF; -} - -uint32_t gs_crc32_update(uint32_t crc, const void * block, size_t length) -{ - if (block && length) { - const uint8_t * u8 = block; - for (unsigned int i = 0; i < length; i++) { - crc = CALC_CRC32_STEP(crc, *u8++); - } - } - return crc; -} - -uint32_t gs_crc32_finalize(uint32_t crc) -{ - return (crc ^ 0xFFFFFFFF); -} - -uint32_t gs_crc32(const void * block, size_t length) -{ - return gs_crc32_finalize(gs_crc32_update(gs_crc32_init(), block, length)); -} diff --git a/gomspace/libutil/src/crc8.c b/gomspace/libutil/src/crc8.c deleted file mode 100644 index aa810b31..00000000 --- a/gomspace/libutil/src/crc8.c +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -static const uint8_t crc_tab[256] GS_PGM_OBJECT = { - 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, - 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, - 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, - 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, - 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, - 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, - 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, - 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, - 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, - 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, - 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, - 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, - 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, - 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, - 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, - 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, - 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, - 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, - 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, - 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, - 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, - 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, - 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, - 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, - 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, - 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, - 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, - 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, - 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, - 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, - 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, - 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 -}; - - -#define CALC_CRC8_STEP(crc,byte) ((crc >> 8) ^ GS_PGM_UINT8_BY_PTR(&crc_tab[(crc ^ byte) & (uint8_t) 0xFF])) - -uint8_t gs_crc8_init(void) -{ - return 0xFF; -} - -uint8_t gs_crc8_update(uint8_t crc, const void * block, size_t length) -{ - if (block && length) { - const uint8_t * u8 = block; - for (unsigned int i = 0; i < length; i++) { - crc = CALC_CRC8_STEP(crc, *u8++); - } - } - return crc; -} - -uint8_t gs_crc8_finalize(uint8_t crc) -{ - return (crc ^ 0x00); -} - -uint8_t gs_crc8(const void * block, size_t length) -{ - return gs_crc8_finalize(gs_crc8_update(gs_crc8_init(), block, length)); -} diff --git a/gomspace/libutil/src/drivers/can/can.c b/gomspace/libutil/src/drivers/can/can.c deleted file mode 100644 index c08eaddb..00000000 --- a/gomspace/libutil/src/drivers/can/can.c +++ /dev/null @@ -1,6 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -// deifne common log group. -GS_LOG_GROUP(gs_can_log, "can", GS_LOG_CAT_DRIVER, GS_LOG_DEFAULT_MASK); diff --git a/gomspace/libutil/src/drivers/i2c/i2c.c b/gomspace/libutil/src/drivers/i2c/i2c.c deleted file mode 100644 index acd9e60e..00000000 --- a/gomspace/libutil/src/drivers/i2c/i2c.c +++ /dev/null @@ -1,6 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -// define common log group. -GS_LOG_GROUP(gs_i2c_log, "i2c", GS_LOG_CAT_DRIVER, GS_LOG_DEFAULT_MASK); diff --git a/gomspace/libutil/src/drivers/spi/spi.c b/gomspace/libutil/src/drivers/spi/spi.c deleted file mode 100644 index eea8153a..00000000 --- a/gomspace/libutil/src/drivers/spi/spi.c +++ /dev/null @@ -1,6 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -// define common log group. -GS_LOG_GROUP(gs_spi_log, "spi", GS_LOG_CAT_DRIVER, GS_LOG_DEFAULT_MASK); diff --git a/gomspace/libutil/src/drivers/sys/memory.c b/gomspace/libutil/src/drivers/sys/memory.c deleted file mode 100644 index 365dcf4a..00000000 --- a/gomspace/libutil/src/drivers/sys/memory.c +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -static const char * long_to_string(char * buf, size_t buf_size, long lvalue) -{ - if (lvalue >= 0) { - snprintf(buf, buf_size, "%ld", lvalue); - return buf; - } - return "Unknown"; -} - -gs_error_t gs_mem_get_ram_stat(gs_mem_ram_type_t type, gs_mem_ram_stat_t * ram_stat) -{ - if (type == GS_MEM_RAM_TYPE_INTERNAL) { - return gs_mem_get_int_ram_stat(ram_stat); - } else if (type == GS_MEM_RAM_TYPE_EXTERNAL) { - return gs_mem_get_ext_ram_stat(ram_stat); - } - - /* Unsupported memory type */ - return GS_ERROR_NOT_SUPPORTED; -} - -gs_error_t gs_mem_print_ram_stat(gs_mem_ram_stat_t * ram_stat, FILE * out) -{ - GS_CHECK_ARG(ram_stat != NULL); - char buf[20]; - - fprintf(out, "Total: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->total)); - fprintf(out, "Max available: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->max_available)); - fprintf(out, "Min available: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->min_available)); - fprintf(out, "Available: %s\r\n", long_to_string(buf, sizeof(buf), ram_stat->available)); - return GS_OK; -} diff --git a/gomspace/libutil/src/error.c b/gomspace/libutil/src/error.c deleted file mode 100644 index 57e42abd..00000000 --- a/gomspace/libutil/src/error.c +++ /dev/null @@ -1,106 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#define GS_UTIL_DEPRECATED_ERROR_CODES 1 - -#include -#include -#include -#include - -#ifdef __AVR__ -const char * gs_error_string(int error) -{ - /** - avr: const strings are not automatically stored in program space (see gs/util/pgm.h), and if stored - in program space, they require special formatting in logs (i.e. "%S"). - So we settle for simple error string, with the error nnumber - no need to change log/(s)printf etc. - @note: solution is not 100% thread/task safe. - */ - static char buffer[15]; // large enough to always keep zero termination, due to no thread/task lock - snprintf(buffer, sizeof(buffer), "%d", error); - return buffer; -} -#else -const char * gs_error_string(int error) -{ - switch (error) { - case GS_OK: return "GS_OK(0)"; - case GS_ERROR_PERM: return GS_DEF2STRING(GS_ERROR_PERM) "(-1)"; - case GS_ERROR_INTR: return GS_DEF2STRING(GS_ERROR_INTR) "(-4)"; - case GS_ERROR_IO: return GS_DEF2STRING(GS_ERROR_IO) "(-5)"; - case GS_ERROR_AGAIN: return GS_DEF2STRING(GS_ERROR_AGAIN) "(-11)"; - case GS_ERROR_ALLOC: return GS_DEF2STRING(GS_ERROR_ALLOC) "(-12)"; - case GS_ERROR_ACCESS: return GS_DEF2STRING(GS_ERROR_ACCESS) "(-13)"; - case GS_ERROR_BUSY: return GS_DEF2STRING(GS_ERROR_BUSY) "(-16)"; - case GS_ERROR_EXIST: return GS_DEF2STRING(GS_ERROR_EXIST) "(-17)"; - case GS_ERROR_ARG: return GS_DEF2STRING(GS_ERROR_ARG) "(-22)"; - case GS_ERROR_NOT_IMPLEMENTED: return GS_DEF2STRING(GS_ERROR_NOT_IMPLEMENTED) "(-38)"; - case GS_ERROR_OVERFLOW: return GS_DEF2STRING(GS_ERROR_OVERFLOW) "(-75)"; - case GS_ERROR_NOT_SUPPORTED: return GS_DEF2STRING(GS_ERROR_NOT_SUPPORTED) "(-95)"; - case GS_ERROR_IN_USE: return GS_DEF2STRING(GS_ERROR_IN_USE) "(-98)"; - case GS_ERROR_CONNECTION_RESET: return GS_DEF2STRING(GS_ERROR_CONNECTION_RESET) "(-104)"; - case GS_ERROR_NO_BUFFERS: return GS_DEF2STRING(GS_ERROR_NO_BUFFERS) "(-105)"; - case GS_ERROR_TIMEOUT: return GS_DEF2STRING(GS_ERROR_TIMEOUT) "(-110)"; - case GS_ERROR_ALREADY_IN_PROGRESS: return GS_DEF2STRING(GS_ERROR_ALREADY_IN_PROGRESS) "(-114)"; - - case GS_ERROR_HANDLE: return GS_DEF2STRING(GS_ERROR_HANDLE) "(-2000)"; - case GS_ERROR_NOT_FOUND: return GS_DEF2STRING(GS_ERROR_NOT_FOUND) "(-2001)"; - case GS_ERROR_FULL: return GS_DEF2STRING(GS_ERROR_FULL) "(-2002)"; - case GS_ERROR_RANGE: return GS_DEF2STRING(GS_ERROR_RANGE) "(-2003)"; - case GS_ERROR_DATA: return GS_DEF2STRING(GS_ERROR_DATA) "(-2004)"; - case GS_ERROR_UNKNOWN: return GS_DEF2STRING(GS_ERROR_UNKNOWN) "(-2005)"; - case GS_ERROR_NO_DATA: return GS_DEF2STRING(GS_ERROR_NO_DATA) "(-2006)"; - case GS_ERROR_STALE: return GS_DEF2STRING(GS_ERROR_STALE) "(-2007)"; - case GS_ERROR_TYPE: return GS_DEF2STRING(GS_ERROR_TYPE) "(-2008)"; - case GS_ERROR_AMBIGUOUS: return GS_DEF2STRING(GS_ERROR_AMBIGUOUS) "(-2009)"; - case GS_ERROR_STATE: return GS_DEF2STRING(GS_ERROR_STATE) "(-2010)"; - } - - // as fallback we use standard POSIX error string - const int posix_error = abs(error); - return strerror(posix_error); -} -#endif - -gs_error_t gs_error(int error) -{ - return (abs(error) * -1); -} - -#ifndef __AVR__ -const char * error_string(int code) -{ - switch (code) { - case E_NO_ERR: - return "No error"; - case E_NO_DEVICE: - return "No device"; - case E_MALLOC_FAIL: - return "Malloc fail"; - case E_THREAD_FAIL: - return "Thread failure"; - case E_NO_QUEUE: - return "No such queue"; - case E_INVALID_BUF_SIZE: - return "Invalid buffer size"; - case E_INVALID_PARAM: - return "Invalid paramater"; - case E_NO_SS: - return "No such subsystem"; - case E_GARBLED_BUFFER: - return "Rubbish in buffer"; - case E_FLASH_ERROR: - return "FLASH error"; - case E_BOOT_SER: - return "Thread boot fail: serial driver"; - case E_BOOT_DEBUG: - return "Thread boot fail: debug console"; - case E_BOOT_FLASH: - return "Thread boot fail: flash driver"; - case E_NO_BUFFER: - return "No buffer"; - default: - return "Unknown error"; - } -} -#endif diff --git a/gomspace/libutil/src/fletcher.c b/gomspace/libutil/src/fletcher.c deleted file mode 100644 index a9dab265..00000000 --- a/gomspace/libutil/src/fletcher.c +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -uint16_t gs_fletcher16_memcpy(const void * data_in, size_t count, void * (*memcpyfcn)(void *, const void *, size_t)) -{ - if (memcpyfcn == NULL) { - memcpyfcn = &memcpy; - } - - uint16_t sum1 = 0; - uint16_t sum2 = 0; - - if (data_in && count) { - const uint8_t * data = data_in; - for (unsigned int idx = 0; idx < count; ++idx) { - uint8_t byte; - (*memcpyfcn)(&byte, &data[idx], 1); - sum1 = (uint16_t)((sum1 + byte) % 255); - sum2 = (uint16_t)((sum2 + sum1) % 255); - } - } - return (uint16_t)((sum2 << 8) | sum1); -} - -uint16_t gs_fletcher16_P(const void * data_in, size_t count) -{ - uint16_t sum1 = 0; - uint16_t sum2 = 0; - - if (data_in && count) { - const uint8_t * data = data_in; - for (unsigned int idx = 0; idx < count; ++idx) { - sum1 = (uint16_t)((sum1 + GS_PGM_UINT8_BY_PTR(data++)) % 255); - sum2 = (uint16_t)((sum2 + sum1) % 255); - } - } - return (uint16_t)((sum2 << 8) | sum1); -} - -uint16_t gs_fletcher16(const void * data_in, size_t size) -{ - uint16_t sum1 = 0; - uint16_t sum2 = 0; - - if (data_in && size) { - const uint8_t * data = data_in; - for (unsigned int idx = 0; idx < size; ++idx) { - sum1 = (uint16_t)((sum1 + (*data++)) % 255); - sum2 = (uint16_t)((sum2 + sum1) % 255); - } - } - return (uint16_t)((sum2 << 8) | sum1); -} - -void gs_fletcher16_init(gs_fletcher16_t * f16) -{ - f16->sum1 = f16->sum2 = 0; -} - -void gs_fletcher16_update(gs_fletcher16_t * f16, const void * data_in, size_t size) -{ - if (f16 && data_in && size) { - const uint8_t * data = data_in; - for (unsigned int idx = 0; idx < size; ++idx) { - f16->sum1 = (uint16_t)((f16->sum1 + (*data++)) % 255); - f16->sum2 = (uint16_t)((f16->sum2 + f16->sum1) % 255); - } - } -} - -uint16_t gs_fletcher16_finalize(gs_fletcher16_t * f16) -{ - return (uint16_t)((f16->sum2 << 8) | f16->sum1); -} diff --git a/gomspace/libutil/src/function_scheduler.c b/gomspace/libutil/src/function_scheduler.c deleted file mode 100644 index a89c8db2..00000000 --- a/gomspace/libutil/src/function_scheduler.c +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include - -#include -#include -#include -#include -#include -#include - -typedef struct { - // function to call - gs_function_scheduler_function_t function; - // function's user data - void * user_data; - // timeout in mS - uint32_t timeout_ms; - // last execution time in mS - uint32_t last_exec_ms; -} gs_function_scheduler_entry_t; - -struct gs_function_scheduler { - // Max timeout in mS - uint32_t max_timeout_ms; - // allocated entries - unsigned int max_entries; - // entries - gs_function_scheduler_entry_t * entries; -}; - -GS_CHECK_STATIC_ASSERT(sizeof(int) >= 2, int_must_be_at_least_16bit); - -gs_error_t gs_function_scheduler_create(uint32_t max_timeout_ms, unsigned int max_entries, gs_function_scheduler_t ** return_scheduler) -{ - GS_CHECK_ARG(max_timeout_ms <= INT_MAX); - GS_CHECK_ARG(max_entries > 0); - GS_CHECK_ARG(return_scheduler != NULL); - - gs_function_scheduler_entry_t * entries = calloc(max_entries, sizeof(*entries)); - if (entries == NULL) { - return GS_ERROR_ALLOC; - } - - gs_function_scheduler_t * scheduler = calloc(1, sizeof(*scheduler)); - if (scheduler == NULL) { - free (entries); - return GS_ERROR_ALLOC; - } - - scheduler->max_timeout_ms = max_timeout_ms; - scheduler->entries = entries; - scheduler->max_entries = max_entries; - - *return_scheduler = scheduler; - - return GS_OK; -} - -gs_error_t gs_function_scheduler_destroy(gs_function_scheduler_t * scheduler) -{ - GS_CHECK_HANDLE(scheduler); - free(scheduler->entries); - free(scheduler); - return GS_OK; -} - -gs_error_t gs_function_scheduler_register_ms(gs_function_scheduler_t * scheduler, - uint32_t first_timeout_ms, gs_function_scheduler_function_t func, void * user_data) -{ - GS_CHECK_HANDLE(scheduler != NULL); - GS_CHECK_ARG(func != NULL); - - gs_function_scheduler_entry_t * entry = scheduler->entries; - for (unsigned int i = 0; i < scheduler->max_entries; ++i, ++entry) { - if (entry->function == NULL) { - entry->function = func; - entry->user_data = user_data; - entry->timeout_ms = first_timeout_ms; - entry->last_exec_ms = gs_time_rel_ms(); - return GS_OK; - } - } - - return GS_ERROR_FULL; -} - -int gs_function_scheduler_execute_ms(gs_function_scheduler_t * scheduler) -{ - uint32_t timeout_ms = 5000; // max timeout to ensure gs_time_rel_ms() works correctly (wrapping more than once is bad) - - if (scheduler) { - timeout_ms = scheduler->max_timeout_ms; - uint32_t now_ms = gs_time_rel_ms(); - - gs_function_scheduler_entry_t * entry = scheduler->entries; - for (unsigned int i = 0; i < scheduler->max_entries; ++i, ++entry) { - if (entry->function) { - uint32_t elapsed = gs_time_diff_ms(entry->last_exec_ms, now_ms); - if (elapsed >= entry->timeout_ms) { - entry->timeout_ms = (entry->function)(entry->user_data); - entry->last_exec_ms = now_ms = gs_time_rel_ms(); - elapsed = 0; - } - timeout_ms = gs_min(timeout_ms, (entry->timeout_ms - elapsed)); - } - } - } - - return (int)((timeout_ms < INT_MAX) ? timeout_ms : INT_MAX); -} diff --git a/gomspace/libutil/src/gosh/command.c b/gomspace/libutil/src/gosh/command.c deleted file mode 100644 index b68d6c82..00000000 --- a/gomspace/libutil/src/gosh/command.c +++ /dev/null @@ -1,754 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include "command_local.h" - -#include -#include - -#include // register commands -#include // register commands -#include -#include -#include "../lock.h" - -#define MAX_ARGC 30 - -#ifdef __AVR__ -#include -#define cmd_strcmp strcmp_P -#define cmd_strncmp strncmp_P -#define cmd_strlen strlen_P -#define cmd_strcpy strcpy_P -#define cmd_read_ptr(ptr) ((void *) pgm_read_word(ptr)) -#define cmd_read_int(ptr) pgm_read_word(ptr) -#else -#define cmd_strcmp strcmp -#define cmd_strncmp strncmp -#define cmd_strlen strlen -#define cmd_strcpy strcpy -#define cmd_read_ptr(ptr) *ptr -#define cmd_read_int(ptr) *ptr -#endif - -// define common command log group. -static GS_LOG_GROUP(gs_command_log, "command", GS_LOG_CAT_COMMAND, LOG_DEFAULT_MASK | LOG_INFO_MASK); -#define LOG_DEFAULT gs_command_log - -/** - Compile check that size of gs_command_t is multiplum of 4. -*/ -GS_STATIC_ASSERT((sizeof(gs_command_t) % 4) == 0, gs_command_t_is_not_a_multiplum_of_4); - -// Private context -typedef struct process_context { - // command context - must be first, as it is used to access private context (same address) - gs_command_context_t context; - // process function - gs_error_t (*process)(const gs_command_t * const cmds, int cmd_count, int arg_offset, struct process_context * pc); - // command error - gs_error_t error; - // only exact match (space after last argument) - bool requires_exact_match; - // first command match - const gs_command_t * cmd; - // number of hits when hunting commands, completion etc. - unsigned int hits; - // complete result - struct { - char * line; - size_t token_start; - } complete; -} private_context_t; - -// command block -typedef struct gs_command_block { - //! Pointer to command block. - const gs_command_t * commands; - //! Number of commands in command block. - size_t count; - //! Reference to next command block. - struct gs_command_block * next; -} gs_command_block_t; - -// commands -static gs_command_block_t g_commands; - -// minimum stack size in bytes. -static size_t g_stack_size; - -// command logger callback -static gs_command_log_t g_command_logger = NULL; -static void * g_command_logger_ctx = NULL; - -static gs_error_t command_stdio_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value) -{ - static const char* printed_group_header = NULL; - /* Print Group header if Group string is non-empty */ - if ((group != NULL) && (group[0] != '\0')) { - if (printed_group_header != group) { - fprintf(ctx->out, "%s:\r\n", group); - printed_group_header = group; - } - } - /* Print ": " if key string is non-empty */ - if (key != NULL) { - if (key[0] != '\0') { - if ((group != NULL) && (group[0] != '\0')) { - fprintf(ctx->out, " %s: ", key); - } else { - fprintf(ctx->out, "%s: ", key); - } - } - } - fprintf(ctx->out, "%s\r\n", value); - return GS_OK; -} - -gs_error_t gs_command_stdio_flush(gs_command_context_t *ctx) -{ - fflush(ctx->out); - return GS_OK; -} - -gs_error_t gs_command_stdio_wait_for_key(gs_command_context_t *ctx, int *ch, int timeout_ms) -{ - return gs_stdio_getchar_timed(timeout_ms, ch); -} - -static const gs_command_io_functions_t stdio_functions = { - .set_result = command_stdio_set_result, - .flush = gs_command_stdio_flush, - .wait_for_key = gs_command_stdio_wait_for_key -}; - -const char * gs_command_args(gs_command_context_t *ctx) -{ - if (ctx->argc > 1) { - // find first matching argument (= starts with) - this is not 100% and doesn't handle arguments with spaces (quoted) - const char * arg = ctx->command_line; - while (arg && arg[0]) { - if (strncmp(arg, ctx->argv[1], strlen(ctx->argv[1])) == 0) { - return arg; - } - // skip argument - for (; *arg && (*arg != ' '); ++arg); - // skip spaces - // cppcheck-suppress redundantCondition - for (; *arg && (*arg == ' '); ++arg); - } - } - return ""; -} - -bool gs_command_build_argv(char *line, int *argc, char **argv, int max_argc) -{ - // Skip spaces - for (; line && *line && isspace((unsigned int)*line); ++line); - - *argc = 0; - argv[*argc] = line; - - char quote = 0; - - while (*line) { - // check for quote's: ' or " - if ((*line == '\'') || (*line == '\"')) { - if (quote == 0) { - quote = *line; - argv[*argc]++; - } else if (quote == *line) { - quote = 0; - *line = '\0'; - } - } - // check for whitespace and no quotes active - else if (isspace((unsigned int)*line) && quote == 0) { - /* Delete space */ - *line++ = '\0'; - - // skip spaces - for (; *line && isspace((unsigned int)*line); ++line); - - /* If there is more data, we have another argument */ - if (*line) { - (*argc)++; - if (*argc >= max_argc) { - return false; - } - argv[*argc] = line; - } - - continue; - } - - line++; - } - - (*argc)++; - if (*argc >= max_argc) { - return false; - } - - // According to C11 section 5.1.2.2.1, argv[argc] must be NULL - argv[*argc] = NULL; - - // Check for invalid number of quotes - return (quote == 0) ? true : false; -} - -static inline gs_error_t command_logger(const char *cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t ts, gs_timestamp_t te) -{ - gs_lock_lock(); - gs_command_log_t logger = g_command_logger; - void * log_ctx = g_command_logger_ctx; - gs_lock_unlock(); - - if (logger) { - return logger(cmd_line, ret, cmd_ret, ts, te, log_ctx); - } - return GS_OK; -} - -static gs_error_t command_execute(const gs_command_t * const cmds, int cmd_count, int arg_offset, private_context_t * pc) -{ - for (int i = 0; i < cmd_count; i++) { - const gs_command_t * cmd = &cmds[i]; - - if (cmd_strcmp(pc->context.argv[arg_offset], cmd->name) == 0) { - // check for sub-commands - const gs_command_t * list = (void*) cmd_read_ptr(&cmd->chain.list); - if (list) { - ++arg_offset; - if (arg_offset >= pc->context.argc) { - return GS_ERROR_TYPE; - } - return command_execute(list, cmd_read_int(&cmd->chain.count), arg_offset, pc); - } - - gs_command_handler_t handler = (void *) cmd_read_ptr(&cmd->handler); - if (handler == NULL) { - return GS_ERROR_NOT_IMPLEMENTED; - } - - pc->context.argc -= arg_offset; - pc->context.argv = &pc->context.argv[arg_offset]; - pc->context.command = cmd; - - // check arguments - if specified - if (cmd->mandatory_args || cmd->optional_args) { - const int min_args = (cmd->mandatory_args == GS_COMMAND_NO_ARGS) ? 0 : cmd->mandatory_args; - const int args = (pc->context.argc - 1); - if (args < min_args) { - return GS_ERROR_ARG; - } - if (args > (min_args + cmd->optional_args)) { - return GS_ERROR_ARG; - } - } - - pc->error = handler(&pc->context); - return GS_OK; // command was excecuted - } - } - - return GS_ERROR_NOT_FOUND; -} - -static gs_error_t command_process(private_context_t * pc) -{ - const char * command = gs_string_skip_leading_spaces(pc->context.command_line); - - // Make copy of string, because command parser mangles destroys it - const size_t command_len = strlen(command); - char command_copy[command_len + 1]; - strcpy(command_copy, command); - - if (command_len && command[command_len-1] == ' ') { - pc->requires_exact_match = true; - } - - pc->context.optsp = 1; - pc->context.optind = 1; - pc->context.optopt = '?'; - pc->context.command_line = command; - - // split into arguments - char *argv[MAX_ARGC + 1]; - if (gs_command_build_argv(command_copy, &pc->context.argc, argv, MAX_ARGC + 1) == false) { - return GS_ERROR_ARG; - } - pc->context.argv = argv; - - gs_error_t error = GS_ERROR_NOT_FOUND; - for (const gs_command_block_t * block = &g_commands; block && (error == GS_ERROR_NOT_FOUND); block = block->next) { - if (block->commands) { - error = (pc->process)(block->commands, block->count, 0, pc); - } - } - - return error; -} - -gs_error_t gs_command_run(const char * command, gs_error_t * return_command_result) -{ - return gs_command_execute_stdio(command, return_command_result); -} - -gs_error_t gs_command_execute_stdio(const char * command, gs_error_t * return_command_result) -{ - return gs_command_execute(command, return_command_result, stdout, &stdio_functions, NULL); -} - -gs_error_t gs_command_execute(const char * command, gs_error_t * return_command_result, FILE *out, - const gs_command_io_functions_t *iof, void *iof_ctx) -{ - command = gs_string_skip_leading_spaces(command); - GS_CHECK_ARG(gs_string_empty(command) == false); - - private_context_t pc = { - .process = command_execute, - .error = GS_OK, - .context = { - .command_line = command, - .out = out, - .io_functions = iof, - .io_ctx = iof_ctx, - } - }; - gs_timestamp_t tm_start, tm_end; - gs_clock_get_time(&tm_start); - gs_error_t error = command_process(&pc); - gs_clock_get_time(&tm_end); - command_logger(pc.context.command_line, error, pc.error, tm_start, tm_end); - if ((error == GS_OK) && return_command_result) { - *return_command_result = pc.error; - } - return error; -} - -gs_error_t gs_command_set_output(gs_command_context_t *ctx, const char* group, const char* key, const char* value) -{ - GS_CHECK_ARG(ctx); - - if (ctx->io_functions && ctx->io_functions->set_result) { - return ctx->io_functions->set_result(ctx, group, key, value); - } - - /* If no IO-function set - ignore the data and send Success */ - return GS_OK; -} - -gs_error_t gs_command_set_output_printf(gs_command_context_t *ctx, const char* group, const char* key, const char * format, ...) -{ - GS_CHECK_ARG(ctx); - - if (ctx->io_functions && ctx->io_functions->set_result) - { - va_list args; - va_start(args, format); - char value[256]; - int size = vsnprintf(value, sizeof(value), format, args); - va_end(args); - - /* Don't allow to set truncated results - Return error in this case */ - if (size >= (int)sizeof(value)) { - return GS_ERROR_ALLOC; - } - - return ctx->io_functions->set_result(ctx, group, key, value); - } - - /* If no IO-function set - ignore the data and send Success */ - return GS_OK; -} - -gs_error_t gs_command_flush_output(gs_command_context_t *ctx) -{ - GS_CHECK_ARG(ctx); - - if (ctx->io_functions && ctx->io_functions->flush) { - return ctx->io_functions->flush(ctx); - } - - /* If no IO-function set - ignore the data and send Success */ - return GS_OK; -} - -bool gs_command_wait_any_key(gs_command_context_t *ctx, int timeout_ms) -{ - int ch; - gs_error_t ret = gs_command_wait_key(ctx, &ch, timeout_ms); - - if (ret == GS_ERROR_TIMEOUT) { - return false; - } - - /* Ensure that a commands handler will not stall if IO function if not available etc. - False will only be returned in case of a positive timeout */ - return true; -} - -gs_error_t gs_command_wait_key(gs_command_context_t *ctx, int* ch, int timeout_ms) -{ - if (ctx && ctx->io_functions && ctx->io_functions->wait_for_key) - { - return ctx->io_functions->wait_for_key(ctx, ch, timeout_ms); - } - - /* If no IO-function set set return GS_ERROR_HANDLE */ - return GS_ERROR_HANDLE; -} - -unsigned int gs_command_completer_add_token(gs_command_context_t * ctx, const char * token, bool exact) -{ - private_context_t * pc = (private_context_t *) ctx; - char * line = &pc->complete.line[pc->complete.token_start]; - - if (token == NULL) { - // mark any pending partial token as exact - if ((line[0] == 0) || (pc->hits != 1)) { - return pc->hits; - } - exact = true; - } - - if (exact) { - if (token) { - strcpy(line, token); - } - strcat(line, " "); - pc->complete.token_start = strlen(pc->complete.line); - pc->hits = 1; - } else { - if (pc->hits == 0) { - strcpy(line, token); - } else { - for (; *line && *token && (*line == *token); ++line, ++token); - *line = 0; - } - ++pc->hits; - } - - return pc->hits; -} - -static unsigned int command_complete_add(private_context_t * pc, const gs_command_t * cmd, bool exact) -{ - if (cmd) { - pc->cmd = cmd; - return gs_command_completer_add_token(&pc->context, cmd->name, exact); - } else { - return gs_command_completer_add_token(&pc->context, NULL, exact); - } -} - -static gs_error_t command_complete(const gs_command_t * const cmds, int cmd_count, int arg_offset, private_context_t * pc) -{ - if (arg_offset > 0) { - // command we are looking for must be in this block - pc->hits = 0; - } - pc->cmd = NULL; - bool exact_match = false; - - for (int i = 0; i < cmd_count; i++) { - const gs_command_t * cmd = &cmds[i]; - - if (cmd_read_int(&cmd->mode) & GS_COMMAND_FLAG_HIDDEN) { - continue; - } - - if (gs_string_empty(pc->context.argv[arg_offset])) { - // exceeding known token(s) - partial match - command_complete_add(pc, cmd, false); - continue; - } - - if (pc->requires_exact_match || ((arg_offset+1) < pc->context.argc)) { - // must be an exact match - if (cmd_strcmp(pc->context.argv[arg_offset], cmd->name) == 0) { - command_complete_add(pc, cmd, true); - exact_match = true; - break; - } - } else if (cmd_strncmp(pc->context.argv[arg_offset], cmd->name, - strlen(pc->context.argv[arg_offset])) == 0) { - // partial match - command_complete_add(pc, cmd, false); - } - } - - if (exact_match || ((arg_offset > 0) && (pc->hits == 1))) { - command_complete_add(pc, NULL, true); - - if (strlen(pc->complete.line) > strlen(pc->context.command_line)) { - return GS_OK; - } - - if (pc->cmd->chain.list) { - return command_complete(pc->cmd->chain.list, pc->cmd->chain.count, arg_offset+1, pc); - } - - // command arguments - pc->context.argc -= arg_offset; - pc->context.argv = &pc->context.argv[arg_offset]; - pc->context.command = pc->cmd; - - // add the "already" completed ones - int arg_to_complete = 1; - for (; arg_to_complete < (pc->context.argc - 1); ++arg_to_complete) { - gs_command_completer_add_token(&pc->context, pc->context.argv[arg_to_complete], true); - } - // add the last - if its completed (space after) - if ((arg_to_complete < pc->context.argc) && pc->requires_exact_match) { - // cppcheck-suppress unreadVariable - not used on __AVR__ because it doesn't support 'completer' - gs_command_completer_add_token(&pc->context, pc->context.argv[arg_to_complete], true); - ++arg_to_complete; - } - -#if (__AVR__ == 0) - if (pc->cmd->completer) { - pc->hits = 0; - (pc->cmd->completer)(&pc->context, arg_to_complete); - } else -#endif - { - pc->hits = 1; // no completer - assume single hit - } - - return GS_OK; // only used for breaking loop - } - - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_command_complete(char *line, size_t max_line_length, FILE* out) -{ - const size_t line_len = strlen(line); - char buffer[max_line_length]; - buffer[0] = 0; - private_context_t pc = { - .process = command_complete, - .context = { - .command_line = line, - .out = out, - }, - .complete = { - .line = buffer, - }, - }; - command_process(&pc); - gs_command_completer_add_token(&pc.context, NULL, true); - if (strlen(buffer) > line_len ) { - strcpy(line, buffer); - } - switch (pc.hits) { - case 0: - return GS_ERROR_NOT_FOUND; - case 1: - return GS_OK; - default: - return GS_ERROR_AMBIGUOUS; - } -} - -static void command_help_print(const gs_command_t * const cmd, private_context_t * pc) -{ - if (pc->hits == 1) { - if (cmd->help) { - fprintf(pc->context.out, "%s\r\n", cmd->help); - } - if (cmd->chain.count == 0) { - fprintf(pc->context.out, "usage: %s %s\r\n", cmd->name, cmd->usage ? cmd->usage : ""); - } else { - for (unsigned int i = 0; i < cmd->chain.count; ++i) { - const gs_command_t * scmd = &cmd->chain.list[i]; - - if (scmd->mode & GS_COMMAND_FLAG_HIDDEN) { - continue; - } - fprintf(pc->context.out, " %-19s %s\r\n", scmd->name, scmd->help ? scmd->help : ""); - } - } - } else { - fprintf(pc->context.out, " %-19s %s\r\n", cmd->name, cmd->help ? cmd->help : ""); - } -} - -static void command_help_hit(const gs_command_t * const cmd, private_context_t * pc) -{ - pc->error = GS_OK; - ++pc->hits; - if (pc->hits == 1) { - // single hit so far - hold off printing until we know if we get more - pc->cmd = cmd; - } else { - if (pc->cmd) { - command_help_print(pc->cmd, pc); - pc->cmd = NULL; - } - command_help_print(cmd, pc); - } -} - -static gs_error_t command_help(const gs_command_t * const cmds, int cmd_count, int arg_offset, private_context_t * pc) -{ - for (int i = 0; i < cmd_count; i++) { - const gs_command_t * cmd = &cmds[i]; - - if (cmd_read_int(&cmd->mode) & GS_COMMAND_FLAG_HIDDEN) { - continue; - } - - if (pc->requires_exact_match || ((arg_offset+1) < pc->context.argc)) { - // must be an exact match - if (cmd_strcmp(pc->context.argv[arg_offset], cmd->name) == 0) { - const gs_command_t * list = (void*) cmd_read_ptr(&cmd->chain.list); - if (list && ((arg_offset+1) < pc->context.argc)) { - return command_help(list, cmd_read_int(&cmd->chain.count), arg_offset+1, pc); - } - command_help_hit(cmd, pc); - } - - } else if (cmd_strncmp(pc->context.argv[arg_offset], cmd->name, - strlen(pc->context.argv[arg_offset])) == 0) { - command_help_hit(cmd, pc); - } - } - - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_command_show_help(const char * command, FILE* out) -{ - private_context_t pc = { - .process = command_help, - .error = GS_ERROR_NOT_FOUND, - .context = { - .command_line = command, - .out = out, - } - }; - gs_error_t error = command_process(&pc); - if (pc.cmd) { - command_help_print(pc.cmd, &pc); - error = GS_OK; - } else if ((error == GS_ERROR_NOT_FOUND) && pc.hits) { - error = GS_OK; - } - return error; -} - -gs_error_t gs_command_register(const gs_command_t * commands, size_t count) -{ - GS_CHECK_ARG(commands != NULL); - GS_CHECK_ARG(count > 0); - - gs_error_t error = GS_OK; - - gs_lock_lock(); - { - // check if command block already installed - gs_command_block_t * last_block = NULL; - for (gs_command_block_t * block = &g_commands; block; block = block->next) { - if (block->commands) { - const gs_command_t * cmd = block->commands; - // loop through because it may be in the linked blocks - for (size_t i = 0; i < block->count; ++i, ++cmd) { - if (cmd == commands) { - error = GS_ERROR_EXIST; - break; - } - } - } - last_block = block; - } - - if (error == GS_OK) { - gs_command_block_t * block = calloc(1, sizeof(*block)); - if (block) { - // Insert command last, so lock isn't needed when accessing commands - block->commands = commands; - block->count = count; - block->next = NULL; - last_block->next = block; - } else { - error = GS_ERROR_ALLOC; - } - } - } - gs_lock_unlock(); - - return (error != GS_ERROR_EXIST) ? error : GS_OK; -} - -size_t gs_command_get_stack_size(void) -{ - return g_stack_size; -} - -gs_error_t gs_command_init_no_commands(size_t stack_size) -{ - g_stack_size = stack_size; - - gs_error_t error = gs_lock_init(); - if (error) { - return error; - } - - gs_log_group_register(gs_command_log); - -#if (__linux__ == 0) - // look up static linked commands - only embedded (= none linux) systems - gs_command_block_t * block = &g_commands; - extern volatile unsigned int __command_start __attribute__ ((__weak__)); - extern volatile unsigned int __command_end __attribute__ ((__weak__)); - if (&__command_start) { - block->count = ((ptrdiff_t)&__command_end - (ptrdiff_t)&__command_start) / sizeof(gs_command_t); - block->commands = (gs_command_t *) &__command_start; - } -#endif - - return GS_OK; -} - -gs_error_t gs_command_init(size_t stack_size) -{ - gs_error_t error = gs_command_init_no_commands(stack_size); - if (error == GS_OK) { - // register default commands - gs_command_register_default_commands(); - gs_log_register_commands(); - } - return error; -} - -gs_error_t gs_command_logger_default(const char* cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t t_start, gs_timestamp_t t_end, void *log_ctx) -{ - (void)log_ctx; - - timestamp_diff(&t_end, &t_start); - if (ret == GS_OK) { - log_info_group(gs_command_log, "'%s' returned '%s' [" - "t: <%04"PRIu32".%06"PRIu32">, dt: <%01"PRIu32".%06"PRIu32">]", - cmd_line, gs_error_string(cmd_ret), - t_start.tv_sec, t_start.tv_nsec/1000, t_end.tv_sec, t_end.tv_nsec/1000); - } else { - log_info_group(gs_command_log, "'%s' could not be run, returned '%s' [" - "t: <%04"PRIu32".%06"PRIu32">]", - cmd_line, gs_error_string(ret), - t_start.tv_sec, t_start.tv_nsec/1000); - } - return GS_OK; -} - -gs_error_t gs_command_register_logger(gs_command_log_t log_cb, void *log_ctx) -{ - gs_lock_lock(); - g_command_logger = log_cb; - g_command_logger_ctx = log_ctx; - gs_lock_unlock(); - - return GS_OK; -} - diff --git a/gomspace/libutil/src/gosh/command_local.h b/gomspace/libutil/src/gosh/command_local.h deleted file mode 100644 index 69f715e1..00000000 --- a/gomspace/libutil/src/gosh/command_local.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -/** - Command I/O function - flush stdout. -*/ -gs_error_t gs_command_stdio_flush(gs_command_context_t *ctx); - -/** - Command I/O function - wait for a key. -*/ -gs_error_t gs_command_stdio_wait_for_key(gs_command_context_t *ctx, int *ch, int timeout_ms); - -/** - Complete command. - @param[in] line command line to complete - @param[in] max \a length (size) - @param[in] out output stream, e.g. stdout -*/ -gs_error_t gs_command_complete(char *line, size_t max_line_length, FILE* out); - -/** - Show help. - @param line command line to show help for. - @param out output stream, e.g. stdout -*/ -gs_error_t gs_command_show_help(const char * command, FILE * out); - -/** - Change console mode. - @param[in] mode console mode, 'cci' - @return_gs_error_t -*/ -int gs_console_change_mode(const char * mode); diff --git a/gomspace/libutil/src/gosh/console.c b/gomspace/libutil/src/gosh/console.c deleted file mode 100644 index 99b04aac..00000000 --- a/gomspace/libutil/src/gosh/console.c +++ /dev/null @@ -1,758 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - @file - - The console interface provides support for executing commands over stdout (typically a serial port). - - The connection can run in 2 modes: - - normal, standard GOSH interface (Human Machine Interface), echo characters, prompt, etc. - - cci, Computer Computer Interface. Simple text interface, but with tagged output format - easier to parse by a computer. -*/ -#include "console_local.h" -#include "command_local.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include // console defines set through Waf options - -#if (__linux__) -#include -#include -#include -#include -#endif - -/* Max history length (elements) */ -#ifndef GS_CONSOLE_HISTORY_LEN -#define GS_CONSOLE_HISTORY_LEN 10 -#endif - -/* Max input length */ -#ifndef GS_CONSOLE_INPUT_LEN -#define GS_CONSOLE_INPUT_LEN 100 -#endif - -#define CONTROL(X) ((X) - '@') - -typedef enum { - CONSOLE_NORMAL = 0, - CONSOLE_ESCAPE = 1, - CONSOLE_PRE_ESCAPE = 2, -} console_escape_t; - -static const char hash_prompt[] = "\033[1;30m # "; - -static const char backspace_char = '\b'; -static const char space_char = ' '; -static const char cr_char = '\r'; -static const char nl_char = '\n'; - -static const char * user_prompt = "gosh"; - -static console_escape_t escape = CONSOLE_NORMAL; - -#if (GS_CONSOLE_HISTORY_LEN > 0) -static int history_elements; -static int history_cur; -static int history_browse; -static char history[GS_CONSOLE_HISTORY_LEN][GS_CONSOLE_INPUT_LEN+1]; -#endif - -static int size; -static int pos; -static char buf[GS_CONSOLE_INPUT_LEN+1]; -static gs_thread_t console_thread; - -#if (__linux__) -static bool termios_changed; -static struct termios old_stdin; -static struct termios old_stdout; -#endif - -static gs_mutex_t g_cci_lock; // Lock for protecting stdout for async output, e.g. log messages -static gs_error_t command_io_cci_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value); -static const gs_command_io_functions_t cci_io_functions = { - .set_result = command_io_cci_set_result, - .flush = gs_command_stdio_flush, - .wait_for_key = gs_command_stdio_wait_for_key, -}; -#define CCI_START_TAG "[X[" -#define CCI_END_TAG "]X]" - -static void gs_console_write(const char *str, int length) -{ - for (int i = 0; i < length; i++) { - putchar(str[i]); - } -} - -static void gs_console_prompt(void) -{ - static const char col_start[] = "\033[1;32m"; - static const char col_end[] = "\033[0m"; - - gs_console_write(col_start, sizeof(col_start) - 1); - gs_console_write(user_prompt, strlen(user_prompt)); - gs_console_write(hash_prompt, sizeof(hash_prompt) - 1); - gs_console_write(col_end, sizeof(col_end) - 1); -} - -void gs_console_set_prompt(const char * _prompt) -{ - if (gs_string_empty(_prompt) == false) { - user_prompt = _prompt; - } -} - -static void gs_console_reset(void) -{ - pos = size = 0; - buf[pos] = 0; - gs_console_prompt(); -} - -static void gs_console_rewind(void) -{ - int plen = strlen(hash_prompt) + strlen(user_prompt); - gs_console_write(&cr_char, 1); - while (size-- + plen) { - gs_console_write(&space_char, 1); - } - pos = size = 0; - gs_console_write(&cr_char, 1); -} - -void gs_console_clear(void) -{ - static const char clear[] = "\033[H\033[2J"; - gs_console_write(clear, sizeof(clear) - 1); - gs_console_rewind(); - gs_console_reset(); -} - -void gs_console_update(void) -{ - gs_console_rewind(); - gs_console_prompt(); - pos = size = strlen(buf); - gs_console_write(buf, size); -} - -#if (GS_CONSOLE_HISTORY_LEN > 0) - -static void gs_console_history_add(void) -{ - strncpy(history[history_cur], buf, GS_CONSOLE_INPUT_LEN); - history[history_cur][GS_CONSOLE_INPUT_LEN] = 0; - - history_browse = 0; - history_cur = (history_cur + 1) % GS_CONSOLE_HISTORY_LEN; - - if (history_elements < GS_CONSOLE_HISTORY_LEN) { - history_elements++; - } -} - -static void gs_console_last_line(void) -{ - if (history_elements < 1) { - return; - } - - if (history_browse >= history_elements) { - return; - } - - gs_console_rewind(); - history_browse++; - strcpy(buf, history[(history_cur - history_browse + GS_CONSOLE_HISTORY_LEN) % GS_CONSOLE_HISTORY_LEN]); - gs_console_update(); -} - -static void gs_console_next_line(void) -{ - if (history_elements < 1) { - return; - } - - if (history_browse < 1) { - return; - } - - gs_console_rewind(); - history_browse--; - if (history_browse > 0) { - strcpy(buf, history[(history_cur - history_browse + GS_CONSOLE_HISTORY_LEN) % GS_CONSOLE_HISTORY_LEN]); - } else { - buf[0] = '\0'; - } - gs_console_update(); -} - -#endif - -static void gs_console_forward_char(void) -{ - if (pos < size) { - gs_console_write(&buf[pos], 1); - pos++; - } -} - -static void gs_console_end_of_line(void) -{ - while (pos < size) { - gs_console_forward_char(); - } -} - -static void gs_console_backward_char(void) -{ - if (pos > 0) { - pos--; - gs_console_write(&backspace_char, 1); - } -} - -static void gs_console_beginning_of_line(void) -{ - while (pos) { - gs_console_backward_char(); - } -} - -static void gs_console_newline(void) -{ - gs_console_write(&cr_char, 1); - gs_console_write(&nl_char, 1); -} - -static bool gs_command_not_empty(const char *ibuf) -{ - while (*ibuf) { - if (!isblank((int) *ibuf++)) { - return true; - } - } - return false; -} - -static void show_help(const char * command) -{ - gs_error_t error = gs_command_show_help(command, stdout); - if (error) { - printf("Could not show help for \'%s\': %s (%d)\r\n", command, gs_error_string(error), error); - } -} - -static void gs_console_execute(void) -{ - gs_console_newline(); - buf[GS_CONSOLE_INPUT_LEN] = 0; // ensure 0 termination - if (size > 0 && gs_command_not_empty(buf)) { -#if (GS_CONSOLE_HISTORY_LEN > 0) - gs_console_history_add(); -#endif - gs_error_t result = GS_OK; - gs_error_t error = gs_command_execute_stdio(buf, &result); - if (error == GS_ERROR_TYPE) { - show_help(buf); - } else if (error == GS_ERROR_NOT_FOUND) { - printf("Unknown command \'%s\'\r\n", buf); - } else if (error == GS_ERROR_ARG) { - show_help(buf); - } else if (error) { - printf("Command \'%s\' did not execute: %s (%d)\r\n", buf, gs_error_string(error), error); - } else if (result == GS_ERROR_ARG) { - show_help(buf); - } else if (result) { - printf("Command \'%s\' executed, but returned error: %s (%d)\r\n", buf, gs_error_string(result), result); - } - } - gs_console_reset(); -} - -static void gs_console_complete(void) -{ - /* We don't expand in the middle of a line */ - if (size != pos) { - return; - } - - const size_t old_buf_len = strlen(buf); - gs_error_t ret = gs_command_complete(buf, sizeof(buf), stdout); - if ((ret == GS_OK) && (old_buf_len == strlen(buf))) { - // completed (again) and no change - show help - ret = GS_ERROR_AMBIGUOUS; - } - switch (ret) { - case GS_ERROR_AMBIGUOUS: - gs_console_newline(); - show_help(buf); - gs_console_update(); - break; - case GS_OK: - gs_console_update(); - break; - default: - case GS_ERROR_NOT_FOUND: - break; - } -} - -static void gs_console_insert(char c) -{ - int i; - int diff = size - pos; - - if (size >= GS_CONSOLE_INPUT_LEN) { - return; - } - - memmove(&buf[pos + 1], &buf[pos], diff); - buf[pos] = c; - - gs_console_write(&buf[pos], diff + 1); - for (i = 0; i < diff; i++) { - gs_console_write(&backspace_char, 1); - } - - size++; - pos++; - buf[size] = '\0'; -} - -static void gs_console_insert_overwrite(char c) -{ - buf[pos++] = c; - - if (pos > size) { - size++; - } - - gs_console_write(&c, 1); -} - -static void gs_console_delete(void) -{ - int i; - int diff = size - pos; - - /* Nothing to delete */ - if (size == pos) { - return; - } - - size--; - memmove(&buf[pos], &buf[pos + 1], diff - 1); - buf[size] = '\0'; - - gs_console_write(&buf[pos], diff - 1); - gs_console_write(&space_char, 1); - for (i = 0; i < diff; i++) { - gs_console_write(&backspace_char, 1); - } -} - -static void gs_console_backspace(void) -{ - if (pos < 1) { - return; - } - - gs_console_backward_char(); - gs_console_delete(); -} - -static void gs_console_kill_line(void) -{ - int i; - int diff; - - diff = size - pos; - - if (diff == 0) { - return; - } - - for (i = 0; i < diff; i++) { - gs_console_write(&space_char, 1); - } - for (i = 0; i < diff; i++) { - gs_console_write(&backspace_char, 1); - } - - memset(&buf[pos], 0, diff); - size = pos; -} - -static void gs_console_kill_line_from_beginning(void) -{ - gs_console_beginning_of_line(); - gs_console_kill_line(); -} - -static void gs_console_backward_kill_word(void) -{ - while (pos > 0 && buf[pos - 1] == ' ') { - gs_console_backspace(); - } - while (pos > 0 && buf[pos - 1] != ' ') { - gs_console_backspace(); - } -} - -static void gs_console_transpose_chars(void) -{ - char c1, c2; - - if (size < 2 || pos < 1) { - return; - } - - if (pos == size) { - c1 = buf[pos - 1]; - c2 = buf[pos - 2]; - - gs_console_backward_char(); - gs_console_backward_char(); - gs_console_insert_overwrite(c1); - gs_console_insert_overwrite(c2); - } else { - c1 = buf[pos]; - c2 = buf[pos - 1]; - - gs_console_backward_char(); - gs_console_insert_overwrite(c1); - gs_console_insert_overwrite(c2); - } -} - -static void gs_console_normal(char c) -{ - switch (c) { - case CONTROL('A'): - gs_console_beginning_of_line(); - break; - case CONTROL('B'): - gs_console_backward_char(); - break; - case CONTROL('C'): - // Either ignored or handled through signals - break; - case CONTROL('D'): - gs_console_delete(); - break; - case CONTROL('E'): - gs_console_end_of_line(); - break; - case CONTROL('F'): - gs_console_forward_char(); - break; - case CONTROL('K'): - gs_console_kill_line(); - break; - case CONTROL('L'): - gs_console_clear(); - break; -#if (GS_CONSOLE_HISTORY_LEN > 0) - case CONTROL('N'): - gs_console_next_line(); - break; - case CONTROL('P'): - gs_console_last_line(); - break; -#endif - case CONTROL('T'): - gs_console_transpose_chars(); - break; - case CONTROL('U'): - gs_console_kill_line_from_beginning(); - break; - case CONTROL('W'): - gs_console_backward_kill_word(); - break; - case CONTROL('Z'): - // We cannot suspend - break; - case CONTROL('H'): - case 0x7f: - gs_console_backspace(); - break; - case '\r': - case '\n': - gs_console_execute(); - break; - case '\t': - gs_console_complete(); - break; - case '\033': - escape = CONSOLE_ESCAPE; - break; - default: - if (escape == CONSOLE_ESCAPE) { - if ((c == '[') || (c == 'O')) { - c = getchar(); - if (c == 'F') - gs_console_end_of_line(); - if (c == 'H') - gs_console_beginning_of_line(); -#if (GS_CONSOLE_HISTORY_LEN > 0) - if (c == 'A') - gs_console_last_line(); - if (c == 'B') - gs_console_next_line(); -#endif - if (c == 'C') - gs_console_forward_char(); - if (c == 'D') - gs_console_backward_char(); - if (c == '1') - if (getchar() == '~') - gs_console_beginning_of_line(); - if (c == '3') - if (getchar() == '~') - gs_console_delete(); - } - escape = CONSOLE_NORMAL; - break; - } - - if (isprint((unsigned char) c)) { - gs_console_insert(c); - } - - break; - } -} - -static gs_error_t command_io_cci_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value) -{ - gs_mutex_lock(g_cci_lock); - { - printf(CCI_START_TAG "cmd_res,%s,%s,%s" CCI_END_TAG, group, key, value); - } - gs_mutex_unlock(g_cci_lock); - return GS_OK; -} - -static void gs_console_cci_log(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) -{ - va_list my_va; - va_copy(my_va, va); - - gs_mutex_lock(g_cci_lock); - { - printf(CCI_START_TAG "log,%04"PRIu32".%06"PRIu32",%c,%s,", ts->tv_sec, ts->tv_nsec / 1000, gs_log_level_to_char(level), group->name); - vprintf(format, my_va); - printf(CCI_END_TAG "\r\n"); - } - gs_mutex_unlock(g_cci_lock); - - va_end(my_va); -} - -static void gs_console_cci(char c) -{ - switch (c) { - case CONTROL('C'): - case CONTROL('L'): - size = 0; - buf[0] = 0; - break; - case '\r': - case '\n': - buf[GS_CONSOLE_INPUT_LEN] = 0; // ensure 0 termination - if (size > 0 && gs_command_not_empty(buf)) { - static unsigned int seq; // simple sequence number keep incrementing - - gs_mutex_lock(g_cci_lock); - ++seq; - printf(CCI_START_TAG "cmd_exec_begin,%u,%s" CCI_END_TAG "\r\n", seq, buf); - gs_mutex_unlock(g_cci_lock); - - gs_error_t result = GS_OK; - gs_error_t error = gs_command_execute(buf, &result, stdout, &cci_io_functions, NULL); - - gs_mutex_lock(g_cci_lock); - printf(CCI_START_TAG "cmd_exec_end,%u,%d,%d" CCI_END_TAG "\r\n", seq, error, result); - gs_mutex_unlock(g_cci_lock); - } - size = 0; - buf[0] = 0; - break; - default: - if (isprint((unsigned char) c) && (size < GS_CONSOLE_INPUT_LEN)) { - buf[size++] = c; - buf[size] = 0; - } - break; - } -} - -// Currrent mode handler, switch by sending command -static void (*console_handler)(char c) = gs_console_normal; - -int gs_console_change_mode(const char * mode) -{ - if (strcasecmp(mode, "cci") == 0) { - gs_error_t error = GS_OK; - if (console_handler != gs_console_cci) { - error = gs_mutex_create(&g_cci_lock); - if (error == GS_OK) { - gs_log_appender_console_set_cb(gs_console_cci_log); - console_handler = gs_console_cci; // change console handler - } - } - return error; - } - return GS_ERROR_NOT_SUPPORTED; -} - -static void * gs_console_thread(void * param) -{ - gs_console_reset(); - while (1) { - char c = getchar(); - console_handler(c); - } - - gs_thread_exit(NULL); -} - -gs_error_t gs_console_exit(void) -{ -#if (__linux__) - if (termios_changed) { - tcsetattr(STDIN_FILENO, TCSANOW, &old_stdin); - tcsetattr(STDOUT_FILENO, TCSANOW, &old_stdout); - } -#endif - return GS_OK; -} - -#if (__linux__) -static inline void exithandler(void) -{ - printf("\n"); - gs_console_exit(); -} -#endif - -static gs_error_t gs_console_init2(uint32_t flags) -{ -#if (__linux__) - // save current stdio setting, for restoring when terminating process - tcgetattr(STDIN_FILENO, &old_stdin); - tcgetattr(STDOUT_FILENO, &old_stdout); - - // change stdin settings - { - struct termios new = old_stdin; - new.c_iflag &= ~(IGNCR | ICRNL); - new.c_lflag &= ~(ECHO | ICANON | IEXTEN); - new.c_cc[VTIME]=0; - new.c_cc[VMIN]=1; - tcsetattr(STDIN_FILENO, TCSANOW, &new); - } - // change stdout settings - { - struct termios new = old_stdout; - new.c_iflag &= ~(IGNCR | ICRNL); - new.c_lflag &= ~(ECHO | ICANON | IEXTEN); - new.c_cc[VTIME]=0; - new.c_cc[VMIN]=1; - tcsetattr(STDOUT_FILENO, TCSANOW, &new); - } - - termios_changed = true; - - // add exit-handler to restore original termianl settings - atexit(exithandler); - - // install signal handlers to ensure terminal settings are restored - if ((flags & GS_CONSOLE_F_NO_SIGNAL_HANDLER) == 0) { - // install signal handler(s) to ensure atexit() is called - gs_signal_catch(SIGTERM, NULL); - - if (gs_command_line_ignore_ctrlc() == false) { - gs_signal_catch(SIGINT, NULL); - } - } -#endif - -#if (__AVR__ == 0) - /** This is very important on AVR32 */ - setvbuf(stdin, NULL, _IONBF, 0); - setvbuf(stdout, NULL, _IONBF, 0); - setvbuf(stderr, NULL, _IONBF, 0); -#endif - return GS_OK; -} - -gs_error_t gs_console_init() -{ - return gs_console_init2(0); -} - -static gs_error_t _console_create_thread(gs_thread_priority_t priority, gs_thread_t * handle, uint32_t thread_create_flags) -{ - gs_error_t error = gs_thread_create("CONSOLE", - gs_console_thread, NULL, - gs_command_get_stack_size(), - priority, - thread_create_flags, - handle); - if (error == GS_OK) { - // give thread a few moments to print prompt - gs_time_sleep_ms(20); - } - return error; -} - -gs_error_t gs_console_create_thread(gs_thread_t * handle) -{ - return _console_create_thread(GS_THREAD_PRIORITY_LOW, handle, 0); -} - -gs_error_t gs_console_create_thread_with_priority(gs_thread_priority_t priority, gs_thread_t * handle) -{ - return _console_create_thread(priority, handle, 0); -} - -gs_error_t gs_console_start(const char * prompt, uint32_t flags) -{ - if (console_thread) { - return GS_ERROR_EXIST; - } - - gs_console_init2(flags); - gs_console_set_prompt(prompt); - - return _console_create_thread(GS_THREAD_PRIORITY_LOW, &console_thread, GS_THREAD_CREATE_JOINABLE); -} - -gs_error_t gs_console_stop(void) -{ - if (console_thread == 0) { - return GS_ERROR_HANDLE; - } -#if (__linux__) - if (pthread_cancel(console_thread) != 0) { - return GS_ERROR_IO; - } - gs_error_t error = gs_thread_join(console_thread, NULL); - if (error == GS_OK) { - console_thread = 0; - } - return error; -#else - return GS_ERROR_NOT_SUPPORTED; -#endif -} diff --git a/gomspace/libutil/src/gosh/console_local.h b/gomspace/libutil/src/gosh/console_local.h deleted file mode 100644 index 1332e732..00000000 --- a/gomspace/libutil/src/gosh/console_local.h +++ /dev/null @@ -1,10 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -/** - Change console mode. - @param[in] mode console mode, 'rgosh', 'normal' - @return_gs_error_t -*/ -int gs_console_change_mode(const char * mode); diff --git a/gomspace/libutil/src/gosh/default_commands.c b/gomspace/libutil/src/gosh/default_commands.c deleted file mode 100644 index fb535318..00000000 --- a/gomspace/libutil/src/gosh/default_commands.c +++ /dev/null @@ -1,277 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include "command_local.h" -#include "console_local.h" - -#include - -#if defined(__linux__) -#include -#include -#endif - -#include -#include -#include -#include -#include - -static int cmd_help(gs_command_context_t * context) -{ - return gs_command_show_help(gs_command_args(context), context->out); -} - -static int cmd_sleep(gs_command_context_t * context) -{ - uint32_t sleep_ms; - gs_error_t error = gs_string_to_uint32(context->argv[1], &sleep_ms); - if (error) { - return error; - } - - gs_time_sleep_ms(sleep_ms); - - return GS_OK; -} - -static int cmd_watch(gs_command_context_t * context, bool check_error) -{ - uint32_t sleep_ms; - gs_error_t error = gs_string_to_uint32(context->argv[1], &sleep_ms); - if (error) { - return error; - } - - fprintf(context->out, "Execution delay: %" PRIu32 "\r\n", sleep_ms); - - char * new_command = strstr(gs_command_args(context), " "); - if (new_command == NULL) { - return GS_ERROR_ARG; - } else { - new_command = new_command + 1; - } - - fprintf(context->out, "Command: %s\r\n", new_command); - - while(1) { - - gs_error_t cmd_result; - error = gs_command_execute(new_command, &cmd_result, context->out, context->io_functions, context->io_ctx); - if (error) { - return error; - } - if (check_error && cmd_result) { - return cmd_result; - } - - if (gs_stdio_getchar_timed(sleep_ms, NULL) != GS_ERROR_TIMEOUT) { - break; - } - } - - return GS_OK; -} - -static int cmd_watch_nocheck(gs_command_context_t * context) -{ - return cmd_watch(context, false); -} - -static int cmd_watch_check(gs_command_context_t * context) -{ - return cmd_watch(context, true); -} - -#define CONTROL(X) ((X) - '@') - -static int cmd_batch(gs_command_context_t * ctx) -{ - char c; - int quit = 0, execute = 0; - unsigned int batch_size = 100; - unsigned int batch_input = 0; - unsigned int batch_count = 0; - char * batch[20] = {}; - printf("Type each command followed by enter, hit ctrl+e to end typing, ctrl+x to cancel:\r\n"); - - /* Wait for ^q to quit. */ - while (quit == 0) { - - /* Get character */ - c = getchar(); - - switch (c) { - - /* CTRL + X */ - case 0x18: - quit = 1; - break; - - /* CTRL + E */ - case 0x05: - execute = 1; - quit = 1; - break; - - /* Backspace */ - case CONTROL('H'): - case 0x7f: - if (batch_input > 0) { - putchar('\b'); - putchar(' '); - putchar('\b'); - batch_input--; - } - break; - - case '\r': - putchar('\r'); - putchar('\n'); - if ((batch[batch_count] != NULL) && (batch_input < batch_size)) - batch[batch_count][batch_input++] = '\r'; - if ((batch[batch_count] != NULL) && (batch_input < batch_size)) - batch[batch_count][batch_input++] = '\0'; - batch_count++; - batch_input = 0; - if (batch_count == 20) - quit = 1; - break; - - default: - putchar(c); - if (batch[batch_count] == NULL) { - batch[batch_count] = calloc(GS_CONSOLE_INPUT_LEN+1, 1); - } - - if ((batch[batch_count] != NULL) && (batch_input < batch_size)) - batch[batch_count][batch_input++] = c; - break; - } - } - - if (execute) { - printf("\r\n"); - for (unsigned int i = 0; i <= batch_count; i++) { - if (batch[i]) - printf("[%02u] %s\r\n", i, batch[i]); - } - printf("Press ctrl+e to execute, or any key to abort\r\n"); - c = getchar(); - if (c != 0x05) - execute = 0; - } - - /* Run/Free batch job */ - for (unsigned int i = 0; i <= batch_count; i++) { - if (execute && batch[i]) { - printf("EXEC [%02u] %s\r\n", i, batch[i]); - gs_command_run(batch[i], NULL); - } - free(batch[i]); - } - - return GS_OK; -} - -#if defined(__linux__) -static int cmd_exit(gs_command_context_t * context) -{ - gs_console_exit(); - exit(EXIT_SUCCESS); - return GS_OK; -} -#endif - -static int cmd_clock(gs_command_context_t * ctx) -{ - if (ctx->argc > 1) { - gs_timestamp_t ts; - gs_error_t error = gs_clock_from_string(ctx->argv[1], &ts); - if (error) { - return GS_ERROR_ARG; - } - error = gs_clock_set_time(&ts); - if (error) { - fprintf(ctx->out, "Failed to set time, error=%s\r\n", gs_error_string(error)); - return GS_ERROR_DATA; - } - } - - timestamp_t clock; - gs_clock_get_monotonic(&clock); - fprintf(ctx->out, "monotonic: %10"PRIu32".%09"PRIu32" sec\r\n", clock.tv_sec, clock.tv_nsec); - gs_command_set_output_printf(ctx, "", "monotonic", "%10"PRIu32".%09"PRIu32"", clock.tv_sec, clock.tv_nsec); - - char tbuf[25]; - gs_clock_get_time(&clock); - gs_clock_to_iso8601_string(&clock, tbuf, sizeof(tbuf)); - fprintf(ctx->out, "realtime: %10"PRIu32".%09"PRIu32" sec -> %s\r\n", clock.tv_sec, clock.tv_nsec, tbuf); - gs_command_set_output_printf(ctx, "", "realtime", "%10"PRIu32".%09"PRIu32"", clock.tv_sec, clock.tv_nsec); - - return GS_OK; -} - -static int cmd_console_mode(gs_command_context_t * ctx) -{ - return gs_console_change_mode(ctx->argv[1]); -} - -static const gs_command_t GS_COMMAND_ROOT cmd_default[] = { - { - .name = "help", - .help = "Show help", - .usage = "[command[ subcommand[ arg ...]]]", - .handler = cmd_help, - .optional_args = 100, - },{ - .name = "sleep", - .help = "Sleep X ms", - .usage = "", - .handler = cmd_sleep, - .mandatory_args = 1, - },{ - .name = "watch", - .help = "Run commands at intervals (abort with key)", - .usage = " [arg ...]", - .handler = cmd_watch_nocheck, - .mandatory_args = 2, - .optional_args = 100, - },{ - .name = "watch_check", - .help = "Like 'watch', but abort if command fails", - .usage = " ", - .handler = cmd_watch_check, - .mandatory_args = 2, - .optional_args = 100, - },{ - .name = "batch", - .help = "Run multiple commands", - .handler = cmd_batch, - .mode = GS_COMMAND_FLAG_HIDDEN, - },{ - .name = "clock", - .help = "Get/set system clock", - .usage = "[ | ]", - .handler = cmd_clock, - .optional_args = 1, - },{ - .name = "console_mode", - .help = "Console mode(s): cci", - .usage = "", - .handler = cmd_console_mode, - .mode = GS_COMMAND_FLAG_HIDDEN, - .mandatory_args = 1, - }, -#if defined(__linux__) - { - .name = "exit", - .help = "Exit program", - .handler = cmd_exit, - }, -#endif -}; - -gs_error_t gs_command_register_default_commands(void) -{ - return GS_COMMAND_REGISTER(cmd_default); -} diff --git a/gomspace/libutil/src/gosh/getopt.c b/gomspace/libutil/src/gosh/getopt.c deleted file mode 100644 index 81055bef..00000000 --- a/gomspace/libutil/src/gosh/getopt.c +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include - -#include -#include -#include - -int gs_command_getopt(gs_command_context_t *ctx, const char *opts) -{ - int c; - char *cp; - - if (ctx->optsp == 1) { - if (ctx->optind >= ctx->argc || - ctx->argv[ctx->optind][0] != '-' || - ctx->argv[ctx->optind][1] == '\0') { - return EOF; - } else if (!strcmp(ctx->argv[ctx->optind], "--")) { - ctx->optind++; - return EOF; - } - } - - ctx->optopt = c = ctx->argv[ctx->optind][ctx->optsp]; - if (c == ':' || (cp = strchr(opts, c)) == NULL) { - printf("illegal option -- %c\r\n", c); - if (ctx->argv[ctx->optind][++ctx->optsp] == '\0') { - ctx->optind++; - ctx->optsp = 1; - } - return '?'; - } - - if (*++cp == ':') { - if (ctx->argv[ctx->optind][ctx->optsp+1] != '\0') { - ctx->optarg = &ctx->argv[ctx->optind++][ctx->optsp+1]; - } else if(++ctx->optind >= ctx->argc) { - printf("option requires an argument -- %c\r\n", c); - ctx->optsp = 1; - return '?'; - } else { - ctx->optarg = ctx->argv[ctx->optind++]; - } - ctx->optsp = 1; - } else { - if (ctx->argv[ctx->optind][++ctx->optsp] == '\0') { - ctx->optsp = 1; - ctx->optind++; - } - ctx->optarg = NULL; - } - - return c; -} diff --git a/gomspace/libutil/src/hexdump.c b/gomspace/libutil/src/hexdump.c deleted file mode 100644 index 7330ef91..00000000 --- a/gomspace/libutil/src/hexdump.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include - -static void print_disp_addr02(FILE * out, uintptr_t disp_addr) -{ - fprintf(out, "0x%02"PRIx32" : ", (uint32_t) disp_addr); -} -static void print_disp_addr04(FILE * out, uintptr_t disp_addr) -{ - fprintf(out, "0x%04"PRIx32" : ", (uint32_t) disp_addr); -} -static void print_disp_addrxx(FILE * out, uintptr_t disp_addr) -{ -#if defined(PRIx64) - fprintf(out, "0x%08"PRIx64" : ", (uint64_t) disp_addr); -#else - fprintf(out, "0x%08"PRIx32" : ", (uint32_t) disp_addr); -#endif -} - -void gs_hexdump_to_stream(const void * in_src, size_t len, const void * in_disp_addr, FILE* out) -{ - volatile const uint8_t * src = in_src; - uintptr_t disp_addr = GS_TYPES_PTR2UINT(in_disp_addr); - const uintptr_t end_disp_addr = disp_addr + len; - - // work-rounds for not printing NIL (if address 0), align addresses, not supporting %zx, %*x or %08p on all platforms - void (*print_addr)(FILE * out, uintptr_t disp_addr); - if (end_disp_addr <= 0xff) { - print_addr = print_disp_addr02; - } else if (end_disp_addr <= 0xffff) { - print_addr = print_disp_addr04; - } else { - print_addr = print_disp_addrxx; - } - - print_addr(out, disp_addr); - - size_t i = 0; - size_t j = 0; - size_t k = 0; - char text[17]; - for(; i < len; ++i) { - const uint8_t ch = *src++; - ++disp_addr; - - // hex - fprintf(out, "%02x ", ch); - ++j; - if (j == 8) { - fprintf(out, " "); - } - - // printable - if ((ch < 32) || (ch > 126)) { - text[k] = '.'; - } else { - text[k] = (char) ch; - } - ++k; - text[k] = 0; - - // newline? - if(j >= 16) { - fprintf(out, "|%-16.16s|\r\n", text); - j = 0; - k = 0; - text[k] = 0; - - if (i < (len - 1)) { - print_addr(out, disp_addr); - } - } - } - if ((i == 0) || (i % 16)) { - if (j) { - // something was printed - show textual - for (; j < 16; j++) { - if (j == 7) { - fprintf(out, " "); - } - fprintf(out, " "); - } - fprintf(out, "|%-16.16s|", text); - } - fprintf(out, "\r\n"); - } -} diff --git a/gomspace/libutil/src/linux/argp.c b/gomspace/libutil/src/linux/argp.c deleted file mode 100644 index e9156595..00000000 --- a/gomspace/libutil/src/linux/argp.c +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -void gs_argp_parse(const struct argp * argp, - int argc, char ** argv, - unsigned int flags, int * return_arg_index, - const char * revision) -{ - if (gs_string_empty(revision) == false) { - argp_program_version = revision; - } - - int arg_index = 0; - int res = argp_parse(argp, argc, argv, 0, &arg_index, 0); - if (res) { - printf("Failed to parse argument/option (result: %d)\n", res); - exit(GS_EXITCODE_USAGE); - } - - if ((return_arg_index == NULL) && (arg_index < argc)) { - // application doesn't expect unhandled arguments - for (int i = arg_index; i < argc; ++i) { - printf("Unhandled/unknown argument: [%s]\n", argv[i]); - } - exit(GS_EXITCODE_USAGE); - } - - if (return_arg_index) { - *return_arg_index = arg_index; - } -} diff --git a/gomspace/libutil/src/linux/clock.c b/gomspace/libutil/src/linux/clock.c deleted file mode 100644 index 191aac25..00000000 --- a/gomspace/libutil/src/linux/clock.c +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include - -void gs_clock_get_time(gs_timestamp_t * time) -{ - struct timespec now; - clock_gettime(CLOCK_REALTIME, &now); - - time->tv_sec = (uint32_t) now.tv_sec; - time->tv_nsec = (uint32_t) now.tv_nsec; -} - -gs_error_t gs_clock_set_time(const gs_timestamp_t * time) -{ - struct timespec now; - now.tv_sec = time->tv_sec; - now.tv_nsec = time->tv_nsec; - - int res = clock_settime(CLOCK_REALTIME, &now); - if (res != 0) { - return gs_error(errno); - } - - gs_error_t error = GS_OK; - if (gs_rtc_supported() == GS_OK) { - error = gs_rtc_set_time(time); - } - - return error; -} - -void gs_clock_get_monotonic(gs_timestamp_t * time) -{ - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - - time->tv_sec = (uint32_t) now.tv_sec; - time->tv_nsec = (uint32_t) now.tv_nsec; -} - -uint64_t gs_clock_get_nsec(void) -{ - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - - return (((uint64_t)now.tv_sec) * GS_TIMESTAMP_NSEC_PER_SEC) + ((uint64_t)now.tv_nsec); -} - -/** - Required by libcsp. - Proto-typed in ./libcsp/include/csp/arch/csp_clock.h, but with different argumet! - - __attribute__((weak)) extern void clock_get_time(csp_timestamp_t * time); - __attribute__((weak)) extern void clock_set_time(csp_timestamp_t * time); -*/ -void clock_get_time(gs_timestamp_t * time) -{ - gs_clock_get_time(time); -} - -void clock_set_time(const gs_timestamp_t * time) -{ - gs_clock_set_time(time); -} diff --git a/gomspace/libutil/src/linux/command_line.c b/gomspace/libutil/src/linux/command_line.c deleted file mode 100644 index e95cd602..00000000 --- a/gomspace/libutil/src/linux/command_line.c +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -#define KEY_IGNORE_CTRLC 200 - -static bool ignore_ctrlc; - -static int parser(int key, char *arg, struct argp_state *state) -{ - switch (key) { - case KEY_IGNORE_CTRLC: - ignore_ctrlc = true; - gs_signal_ignore(SIGINT); - break; - - case 'h': - argp_help(state->root_argp, state->out_stream, ARGP_HELP_STD_HELP, state->name); - exit(0); - break; - - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - -static const struct argp_option options[] = { - { - .name = "ignore-ctrlc", - .key = KEY_IGNORE_CTRLC, - .doc = "Ignore/disable CTRL-C" - }, - {0} -}; - -static const struct argp argp_console = {.options = options, .parser = parser}; - -const struct argp_child gs_console_command_line_ignore_ctrlc_argp = {.argp = &argp_console}; - -bool gs_command_line_ignore_ctrlc(void) -{ - return ignore_ctrlc; -} - -static const struct argp_option help_options[] = { - { - .name = "help", - .key = 'h', - .doc = "Give this help list" - }, - {0} -}; - -static const struct argp gs_argp_help = {.options = help_options, .parser = parser}; - -const struct argp_child gs_help_command_line_argp = {.argp = &gs_argp_help}; - -const char * gs_command_line_program_name(const char * argv) -{ - if (gs_string_empty(argv) == false) { - const char * name = strrchr(argv, '/'); - if (name) { - // skip slash - ++name; - if (gs_string_empty(name) == false) { - return name; - } - } else { - return argv; - } - } - return ""; -} diff --git a/gomspace/libutil/src/linux/cwd.c b/gomspace/libutil/src/linux/cwd.c deleted file mode 100644 index 1cfe373d..00000000 --- a/gomspace/libutil/src/linux/cwd.c +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -gs_error_t gs_getcwd(char * buf, size_t bufsize) -{ - if (buf && bufsize) { - char * wd = getcwd(buf, bufsize); - if (wd) { - return GS_OK; - } - switch(errno) { - case ENAMETOOLONG: - case ERANGE: - return GS_ERROR_RANGE; - - case EACCES: - case ENOENT: - return GS_ERROR_NOT_FOUND; - - default: - break; - } - } - return GS_ERROR_ARG; -} diff --git a/gomspace/libutil/src/linux/delay.c b/gomspace/libutil/src/linux/delay.c deleted file mode 100644 index f0a39081..00000000 --- a/gomspace/libutil/src/linux/delay.c +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -void gs_delay_us(uint32_t time_us) -{ - uint64_t ns = time_us; - ns *= 1000LL; - gs_time_sleep_ns(ns); -} - -uint16_t gs_delay_ts_get(void) -{ - return 0; -} - -void gs_delay_from_ts(uint16_t ts, uint16_t delay) -{ - -} diff --git a/gomspace/libutil/src/linux/drivers/can/can.c b/gomspace/libutil/src/linux/drivers/can/can.c deleted file mode 100644 index 40a6b8c8..00000000 --- a/gomspace/libutil/src/linux/drivers/can/can.c +++ /dev/null @@ -1,308 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -typedef struct { - // true if handle is in use - bool inuse; - - // opened socket - int can_socket; - - // receiver thread - gs_thread_t rxthread; - - // received data callback - gs_can_rxdata_callback_t rx_callback; - void * user_data; - -} gs_can_handle_t; - -#define MAX_CAN_HANDLES 10 -static gs_can_handle_t can_handles[MAX_CAN_HANDLES]; - -static int gs_can_alloc_handle(void) -{ - int handle_id; - for (handle_id = 0; (handle_id < MAX_CAN_HANDLES) && (can_handles[handle_id].inuse == true); ++handle_id); - - if (handle_id < MAX_CAN_HANDLES) { - gs_can_handle_t * handle = &can_handles[handle_id]; - memset(handle, 0, sizeof(*handle)); - handle->inuse = true; - handle->can_socket = -1; - } - - return handle_id; -} - -static inline gs_can_handle_t * gs_can_handle(uint8_t hdl) -{ - if (hdl >= MAX_CAN_HANDLES) { - return NULL; - } - if (can_handles[hdl].inuse == false) { - return NULL; - } - return &can_handles[hdl]; -} - -static void * gs_can_rx_thread(void * parameter) -{ - int hdl = (int) GS_TYPES_PTR2INT(parameter); - - log_debug("%s: running, hdl: %d", __FUNCTION__, hdl); - - gs_can_handle_t * handle = gs_can_handle(hdl); - if (handle == NULL) { - log_error("%s: CAN handle: %d is invalid or not opened", __FUNCTION__, hdl); - gs_thread_exit(NULL); - } - - while (1) { - /* Read CAN frame */ - struct can_frame frame; - ssize_t nbytes = read(handle->can_socket, &frame, sizeof(frame)); - if (nbytes < 0) { - log_error("%s: read() on socket failed, error: %s", __FUNCTION__, strerror(errno)); - continue; - } - - if (nbytes != sizeof(frame)) { - log_warning("%s: read() returned incomplete CAN frame of %d bytes - ignoring frame", __FUNCTION__, (int) nbytes); - continue; - } - - /* Frame type */ - if (frame.can_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) { - /* Drop error and remote frames */ - log_warning("%s: discarding ERR/RTR frame, can_id: 0x%x", __FUNCTION__, frame.can_id); - continue; - } - - const bool extId = (frame.can_id & CAN_EFF_FLAG) ? true : false; - if (extId) { - frame.can_id &= CAN_EFF_MASK; - } else { - frame.can_id &= CAN_SFF_MASK; - } - handle->rx_callback(hdl, frame.can_id, extId, frame.data, frame.can_dlc, gs_time_rel_ms(), handle->user_data, false); - } - - /* We should never reach this point */ - return NULL; -} - -static gs_error_t gs_can_send(uint8_t hdl, uint32_t canMsgId, bool extended, const void * data, size_t data_size, int timeout_ms) -{ - gs_can_handle_t * handle = gs_can_handle(hdl); - if (handle == NULL) { - return GS_ERROR_HANDLE; - } - - if ((data == NULL) || (data_size > 8)) { - log_error("%s: invalid data: %p, data_size: %u", __FUNCTION__, (void*) data, (unsigned int) data_size); - return GS_ERROR_ARG; - } - - struct can_frame frame; - memset(&frame, 0, sizeof(frame)); - frame.can_id = canMsgId; - if (extended) { - frame.can_id |= CAN_EFF_FLAG; - } - - memcpy(frame.data, data, data_size); - - frame.can_dlc = (uint8_t) data_size; - - const int DELAY_MS = 10; - while (write(handle->can_socket, &frame, sizeof(frame)) != sizeof(frame)) { - if ((timeout_ms > 0) && (errno == ENOBUFS)) { - // Wait a bit and try again - gs_thread_sleep_ms(DELAY_MS); - timeout_ms -= DELAY_MS; - } else { - gs_error_t gserror = gs_error(errno); - log_error("%s: write() failed, error: %s", __FUNCTION__, gs_error_string(gserror)); - return gserror; - } - } - - return GS_OK; -} - -gs_error_t gs_can_send_standard(uint8_t hdl, uint32_t canMsgId, const void * data, size_t data_size, int timeout_ms) -{ - return gs_can_send(hdl, canMsgId, false, data, data_size, timeout_ms); -} - -gs_error_t gs_can_send_extended(uint8_t hdl, uint32_t canExtMsgId, const void * data, size_t data_size, int timeout_ms) -{ - return gs_can_send(hdl, canExtMsgId, true, data, data_size, timeout_ms); -} - -static void gs_can_close(gs_can_handle_t * handle) -{ - if (handle->can_socket >= 0) { - close(handle->can_socket); - } - - // free instance - must be the last thing done, no lock needed - handle->inuse = false; -} - -gs_error_t gs_can_open(const char * ifname, int * return_handle) -{ - if ((ifname == NULL) || (ifname[0] == 0) || (return_handle == NULL)) { - log_error("%s: invalid CAN interface name", __FUNCTION__); - return GS_ERROR_ARG; - } - - int handle_id = gs_can_alloc_handle(); - if (handle_id >= MAX_CAN_HANDLES) { - log_error("%s: no free handles", __FUNCTION__); - return GS_ERROR_FULL; - } - gs_can_handle_t * handle = &can_handles[handle_id]; - - /* Create socket */ - if ((handle->can_socket = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { - gs_error_t gserror = gs_error(errno); - log_error("%s: socket() failed, error: %s", __FUNCTION__, gs_error_string(gserror)); - gs_can_close(handle); - return gserror; - } - - /* Locate interface */ - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1); - if (ioctl(handle->can_socket, SIOCGIFINDEX, &ifr) < 0) { - gs_error_t gserror = gs_error(errno); - log_error("%s: ioctl(ifname: [%s]) failed, error: %s", __FUNCTION__, ifr.ifr_name, gs_error_string(gserror)); - gs_can_close(handle); - return gserror; - } - - /* Bind the socket to CAN interface */ - struct sockaddr_can addr; - memset(&addr, 0, sizeof(addr)); - addr.can_family = AF_CAN; - addr.can_ifindex = ifr.ifr_ifindex; - if (bind(handle->can_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - gs_error_t gserror = gs_error(errno); - log_error("%s: bind() failed, error: %s", __FUNCTION__, gs_error_string(gserror)); - gs_can_close(handle); - return gserror; - } - - *return_handle = handle_id; - - return GS_OK; -} - -static gs_error_t gs_can_set_filter_mask(uint8_t hdl, bool extended, uint32_t canMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * user_data) -{ - gs_can_handle_t * handle = gs_can_handle(hdl); - if (handle == NULL) { - return GS_ERROR_HANDLE; - } - - if (extended) { - if ((canMsgId > CAN_EFF_MASK) || (mask > CAN_EFF_MASK)) { - return GS_ERROR_ARG; - } - } else { - if ((canMsgId > CAN_SFF_MASK) || (mask > CAN_SFF_MASK)) { - return GS_ERROR_ARG; - } - } - - handle->rx_callback = rx_callback; - handle->user_data = user_data; - - struct can_filter filter; - filter.can_id = canMsgId; - filter.can_mask = mask; - if (extended == false) { - filter.can_mask |= (CAN_EFF_MASK & ~CAN_SFF_MASK); - } - - if (setsockopt(handle->can_socket, SOL_CAN_RAW, CAN_RAW_FILTER, &filter, sizeof(filter)) < 0) { - gs_error_t gserror = gs_error(errno); - log_error("%s: setsockopt(id: 0x%x, mask: 0x%x) failed, error: %s", __FUNCTION__, canMsgId, mask, gs_error_string(gserror)); - return gserror; - } - - return GS_OK; -} - -gs_error_t gs_can_set_standard_filter_mask(uint8_t hdl, uint32_t canMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * user_data) -{ - return gs_can_set_filter_mask(hdl, false, canMsgId, mask, rx_callback, user_data); -} - -gs_error_t gs_can_set_extended_filter_mask(uint8_t hdl, uint32_t canExtMsgId, uint32_t mask, gs_can_rxdata_callback_t rx_callback, void * user_data) -{ - return gs_can_set_filter_mask(hdl, true, canExtMsgId, mask, rx_callback, user_data); -} - -gs_error_t gs_can_start(uint8_t hdl) -{ - gs_can_handle_t * handle = gs_can_handle(hdl); - if (handle == NULL) { - return GS_ERROR_HANDLE; - } - - if (handle->rxthread) { - return GS_OK; - } - - /* Create receiver thread */ - gs_error_t gserror = gs_thread_create("rxcan", gs_can_rx_thread, GS_TYPES_INT2PTR(hdl), 0, GS_THREAD_PRIORITY_HIGH, 0, &handle->rxthread); - if (gserror) { - log_error("s: gs_thread_create() failed, error: %s", gs_error_string(gserror)); - return gserror; - } - - return GS_OK; -} - -gs_error_t gs_can_stop(uint8_t hdl) -{ - gs_can_handle_t * handle = gs_can_handle(hdl); - if (handle == NULL) { - return GS_ERROR_HANDLE; - } - - return GS_ERROR_NOT_IMPLEMENTED; -} - -gs_error_t gs_can_error_state(uint8_t hdl, bool * restart_required) -{ - gs_can_handle_t * handle = gs_can_handle(hdl); - if (handle == NULL) { - return GS_ERROR_HANDLE; - } - - if (restart_required) { - *restart_required = false; - } - - // missing error state check on CAN layer - - return GS_OK; -} diff --git a/gomspace/libutil/src/linux/drivers/gpio/gpio.c b/gomspace/libutil/src/linux/drivers/gpio/gpio.c deleted file mode 100644 index 484c6a58..00000000 --- a/gomspace/libutil/src/linux/drivers/gpio/gpio.c +++ /dev/null @@ -1,102 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -#define MAX_DRIVERS 20 - -typedef struct { - gs_gpio_driver_entry_t entry; - bool in_use; -} gs_gpio_driver_handle_t; - -static gs_gpio_driver_handle_t gpio_drivers[MAX_DRIVERS]; -static uint8_t max_index_in_use = 0; - - -static inline gs_gpio_driver_entry_t * gs_find_driver_entry(gs_gpio_t * gpio) -{ - gs_gpio_driver_handle_t * handle; - for (int i = max_index_in_use; i >= 0; i--) { - handle = &gpio_drivers[i]; - if (((gpio->pin == handle->entry.pin) || (handle->entry.pin == GS_GPIO_ALL_PINS)) && - ((gpio->port == handle->entry.port) || (handle->entry.port == GS_GPIO_ALL_PORTS)) && - (handle->in_use == true)) { - return &handle->entry; - } - } - return NULL; -} - -gs_error_t gs_gpio_get(gs_gpio_t gpio, bool *value) -{ - gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); - if (driver_entry) { - if (driver_entry->driver->get_handler) { - return driver_entry->driver->get_handler(gpio, value, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -bool gs_gpio_get_nc(gs_gpio_t gpio) -{ - gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); - if (driver_entry) { - if (driver_entry->driver->get_nc_handler) { - return driver_entry->driver->get_nc_handler(gpio, driver_entry->driver_data); - } - } - return false; -} - -gs_error_t gs_gpio_set(gs_gpio_t gpio, bool value) -{ - gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); - if (driver_entry) { - if (driver_entry->driver->set_handler) { - return driver_entry->driver->set_handler(gpio, value, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -void gs_gpio_set_nc(gs_gpio_t gpio, bool value) -{ - gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); - if (driver_entry) { - if (driver_entry->driver->set_nc_handler) { - driver_entry->driver->set_nc_handler(gpio, value, driver_entry->driver_data); - } - } -} - -gs_error_t gs_gpio_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf) -{ - gs_gpio_driver_entry_t * driver_entry = gs_find_driver_entry(&gpio); - if (driver_entry) { - if (driver_entry->driver->init_as_interrupt_handler) { - return driver_entry->driver->init_as_interrupt_handler(gpio, conf, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_gpio_register_driver(const gs_gpio_driver_entry_t * driver_entry) -{ - GS_CHECK_ARG(driver_entry != NULL); - GS_CHECK_ARG(driver_entry->driver != NULL); - - gs_gpio_driver_handle_t * handle; - for (uint8_t i = 0; i < MAX_DRIVERS; i++) { - handle = &gpio_drivers[i]; - if (handle->in_use == false) { - handle->entry = *driver_entry; - handle->in_use = true; - max_index_in_use = i; - return GS_OK; - } - } - /* Not enough space in buffer */ - return GS_ERROR_FULL; -} diff --git a/gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c b/gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c deleted file mode 100644 index 57efd042..00000000 --- a/gomspace/libutil/src/linux/drivers/gpio/gpio_sysfs.c +++ /dev/null @@ -1,145 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ -/** - @file - - @brief GPIO Implementation for Linux of the GPIO API in libutil. - - The GPIO driver provides a simple interface toward driving HW GPIO's. -*/ - -#include - -#include -#include -#include -#include - -#include - -#include - -gs_error_t gs_gpio_sysfs_initialize(gs_gpio_t gpio, bool output,bool init_value, bool active_low) -{ - char gpio_pin_str[6]; - snprintf(gpio_pin_str, sizeof(gpio_pin_str), "%d", gpio.pin); - - /* Try to unexport first */ - gs_sysfs_write_file("/sys/class/gpio/unexport", gpio_pin_str); - - if (gs_sysfs_write_file("/sys/class/gpio/export", gpio_pin_str) != GS_OK) - { - log_warning("failed to export GPIO %s: %s", gpio_pin_str, strerror(errno)); - return GS_ERROR_NOT_SUPPORTED; - } - - char gpio_sys_fname[128]; - snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/active_low", gpio.pin); - const char * active_low_str = active_low ? "1" : "0"; - - if (gs_sysfs_write_file(gpio_sys_fname, active_low_str) != GS_OK) - { - log_warning("failed to set GPIO %d active_low: %s", gpio.pin, strerror(errno)); - return GS_ERROR_NOT_SUPPORTED; - } - - snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/direction", gpio.pin); - - /* Glitch-free output set (high/low makes pin an output and sets value to 1/0 respectively)*/ - const char * dir = output ? (init_value ? "high" : "low") : "in"; - - if (gs_sysfs_write_file(gpio_sys_fname, dir) != GS_OK) - { - log_warning("failed to set GPIO %d direction: %s", gpio.pin, strerror(errno)); - return GS_ERROR_NOT_SUPPORTED; - } - - return GS_OK; -} - -gs_error_t gs_gpio_sysfs_get(gs_gpio_t gpio, bool *value, void * driver_data) -{ - char gpio_sys_fname[128]; - snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); - - if (access(gpio_sys_fname, R_OK) != 0) - { - log_error("GPIO %d not initialized - Can't read the input.", gpio.pin); - return GS_ERROR_ACCESS; - } - - char value_str[10]; - gs_error_t ret = gs_sysfs_read_file(gpio_sys_fname, value_str, sizeof(value_str)); - if (ret == GS_OK) - { - if (strcmp(value_str, "1") == 0) - *value = true; - else - *value = false; - } - - return ret; -} - -bool gs_gpio_sysfs_get_nc(gs_gpio_t gpio, void * driver_data) -{ - char gpio_sys_fname[128]; - snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); - - if (access(gpio_sys_fname, R_OK) != 0) - { - log_error("GPIO %d not initialized - Can't read the input.", gpio.pin); - return 0; - } - - char value_str[10]; - gs_sysfs_read_file(gpio_sys_fname, value_str, sizeof(value_str)); - - if (strncmp(value_str, "1", 10) == 0) { - return true; - } else { - return false; - } -} - -gs_error_t gs_gpio_sysfs_set(gs_gpio_t gpio, bool value, void * driver_data) -{ - const char *value_str = value ? "1" : "0"; - - char gpio_sys_fname[128]; - snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); - if (access(gpio_sys_fname, W_OK) == 0) - { - return gs_sysfs_write_file(gpio_sys_fname, value_str); - } - - log_error("GPIO %d not initialized - Can't set the output.", gpio.pin); - return GS_ERROR_ACCESS; -} - -void gs_gpio_sysfs_set_nc(gs_gpio_t gpio, bool value, void * driver_data) -{ - const char *value_str = value ? "1" : "0"; - - char gpio_sys_fname[128]; - snprintf(gpio_sys_fname, sizeof(gpio_sys_fname), "/sys/class/gpio/gpio%d/value", gpio.pin); - if (access(gpio_sys_fname, W_OK) == 0) - { - gs_sysfs_write_file(gpio_sys_fname, value_str); - return; - } - log_error("GPIO %d not initialized - Can't set the output.", gpio.pin); -} - -gs_error_t gs_gpio_sysfs_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data) -{ - return GS_ERROR_NOT_IMPLEMENTED; -} - -const gs_gpio_driver_t gs_gpio_sysfs_driver = { - .get_handler = gs_gpio_sysfs_get, - .get_nc_handler = gs_gpio_sysfs_get_nc, - .set_handler = gs_gpio_sysfs_set, - .set_nc_handler = gs_gpio_sysfs_set_nc, - .init_as_interrupt_handler = gs_gpio_sysfs_init_as_interrupt, -}; - diff --git a/gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c b/gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c deleted file mode 100644 index ce20c885..00000000 --- a/gomspace/libutil/src/linux/drivers/gpio/gpio_virtual.c +++ /dev/null @@ -1,171 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -#define MAX_VPINS 500 - -#define FALLING_EDGE_FLAG 0x1 -#define RISING_EDGE_FLAG 0x2 - -typedef struct { - gs_gpio_t gpio; - bool output; - bool value; - bool in_use; - gs_gpio_isr_t isr; - uint8_t edge_flags; - uint32_t transistions; -} gs_gpio_virtual_t; - -static gs_gpio_virtual_t vpins[MAX_VPINS]; - -gs_error_t gs_gpio_virtual_initialize(gs_gpio_t gpio, bool output, bool value) -{ - gs_gpio_virtual_t * pin; - for (uint16_t i = 0; i < MAX_VPINS; i++) { - pin = &vpins[i]; - if ((!pin->in_use) || ((pin->gpio.pin == gpio.pin) && (pin->gpio.port == gpio.port))) { - pin->gpio = gpio; - pin->output = output; - pin->value = value; - pin->in_use = true; - return GS_OK; - } - } - return GS_ERROR_FULL; -} - -static gs_gpio_virtual_t * find_vpin(gs_gpio_t * gpio) -{ - gs_gpio_virtual_t * pin; - for (uint16_t i = 0; i < MAX_VPINS; i++) { - pin = &vpins[i]; - if (pin->gpio.pin == gpio->pin) { - if (pin->gpio.port == gpio->port) { - if (pin->in_use) { - return pin; - } - } - } - } - return NULL; -} - -gs_error_t gs_gpio_virtual_get(gs_gpio_t gpio, bool *value, void * driver_data) -{ - gs_gpio_virtual_t * pin = find_vpin(&gpio); - if (pin) { - *value = pin->value; - return GS_OK; - } - return GS_ERROR_NOT_FOUND; -} - -bool gs_gpio_virtual_get_nc(gs_gpio_t gpio, void * driver_data) -{ - gs_gpio_virtual_t * pin = find_vpin(&gpio); - if (pin) { - return pin->value; - } - return false; -} - -gs_error_t gs_gpio_virtual_set(gs_gpio_t gpio, bool value, void * driver_data) -{ - gs_gpio_virtual_t * pin = find_vpin(&gpio); - if (pin) { - if (pin->output) { - if (pin->value != value) { - pin->value = value; - pin->transistions++; - } - return GS_OK; - } - return GS_ERROR_PERM; - } - return GS_ERROR_NOT_FOUND; -} - -void gs_gpio_virtual_set_nc(gs_gpio_t gpio, bool value, void * driver_data) -{ - gs_gpio_virtual_t * pin = find_vpin(&gpio); - if (pin) { - if (pin->output) { - if (pin->value != value) { - pin->value = value; - pin->transistions++; - } - } - } -} - -gs_error_t gs_gpio_virtual_init_as_interrupt(gs_gpio_t gpio, const gs_interrupt_conf_t * conf, void * driver_data) -{ - gs_gpio_virtual_t * pin; - for (uint16_t i = 0; i < MAX_VPINS; i++) { - pin = &vpins[i]; - if ((!pin->in_use) || ((pin->gpio.pin == gpio.pin) && (pin->gpio.port == gpio.port))) { - pin->gpio = gpio; - pin->output = false; - pin->value = 0; - pin->in_use = true; - pin->isr = conf->isr; - if (conf->falling_edge) { - pin->edge_flags |= FALLING_EDGE_FLAG; - } - if (conf->rising_edge) { - pin->edge_flags |= RISING_EDGE_FLAG; - } - return GS_OK; - } - } - return GS_ERROR_FULL; -} - -gs_error_t gs_gpio_virtual_force_set(gs_gpio_t gpio, bool value) -{ - gs_gpio_virtual_t * pin = find_vpin(&gpio); - if (pin) { - bool old_value = pin->value; - if (old_value != value) { - pin->value = value; - pin->transistions++; - if (pin->isr) { - if ((old_value == false) && (pin->edge_flags & RISING_EDGE_FLAG)) { - pin->isr(NULL); - } else if ((old_value == true) && (pin->edge_flags & FALLING_EDGE_FLAG)) { - pin->isr(NULL); - } - } - } - return GS_OK; - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_gpio_virtual_get_transistions(gs_gpio_t gpio, uint32_t * transitions) -{ - gs_gpio_virtual_t * pin = find_vpin(&gpio); - if (pin) { - *transitions = pin->transistions; - pin->transistions = 0; - return GS_OK; - } - return GS_ERROR_NOT_FOUND; -} - -const gs_gpio_driver_t gs_gpio_virtual_driver = { - .get_handler = gs_gpio_virtual_get, - .get_nc_handler = gs_gpio_virtual_get_nc, - .set_handler = gs_gpio_virtual_set, - .set_nc_handler = gs_gpio_virtual_set_nc, - .init_as_interrupt_handler = gs_gpio_virtual_init_as_interrupt, -}; - - -const gs_gpio_driver_entry_t gs_gpio_virtual_driver_entry_all = { - .port = GS_GPIO_ALL_PORTS, - .pin = GS_GPIO_ALL_PINS, - .driver = &gs_gpio_virtual_driver, - .driver_data = NULL, -}; diff --git a/gomspace/libutil/src/linux/drivers/i2c/i2c.c b/gomspace/libutil/src/linux/drivers/i2c/i2c.c deleted file mode 100644 index 679ae3f7..00000000 --- a/gomspace/libutil/src/linux/drivers/i2c/i2c.c +++ /dev/null @@ -1,144 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -#define MAX_DRIVERS 20 -#define HIGHEST_I2C_ADDR 127 - -typedef struct { - gs_i2c_master_driver_entry_t entry; - bool in_use; -} gs_i2c_master_driver_handle_t; - -typedef struct { - gs_i2c_slave_driver_entry_t entry; - bool in_use; -} gs_i2c_slave_driver_handle_t; - -static gs_i2c_master_driver_handle_t master_drivers[MAX_DRIVERS]; -static gs_i2c_slave_driver_handle_t slave_drivers[MAX_DRIVERS]; - -static uint8_t max_index_master_in_use = 0; -static uint8_t max_index_slave_in_use = 0; - -gs_error_t gs_i2c_master_transaction(uint8_t device, uint8_t addr, const void * tx, - size_t txlen, - void * rx, - size_t rxlen, - int timeout_ms) -{ - GS_CHECK_RANGE(addr <= HIGHEST_I2C_ADDR); - gs_i2c_master_driver_handle_t * handle; - for (int i = max_index_master_in_use; i >= 0; i--) { - handle = &master_drivers[i]; - if (((device == handle->entry.device) || (handle->entry.device == GS_I2C_ALL_DEVICES)) - && ((addr == handle->entry.addr) || (handle->entry.addr == GS_I2C_ALL_ADDR)) - && (handle->in_use == true)) { - if (handle->entry.driver->master_transaction_handler) { - return handle->entry.driver->master_transaction_handler(device, addr, tx, txlen, rx, rxlen, timeout_ms, handle->entry.driver_data); - } - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_i2c_master_register_driver(const gs_i2c_master_driver_entry_t * driver_entry) -{ - GS_CHECK_ARG(driver_entry != NULL); - GS_CHECK_ARG(driver_entry->driver != NULL); - - GS_CHECK_RANGE((driver_entry->addr == GS_I2C_ALL_ADDR) || (driver_entry->addr <= HIGHEST_I2C_ADDR)); - - gs_i2c_master_driver_handle_t * handle; - for (uint8_t i = 0; i < MAX_DRIVERS; i++) { - handle = &master_drivers[i]; - if (handle->in_use == false) { - handle->entry = *driver_entry; - handle->in_use = true; - max_index_master_in_use = i; - return GS_OK; - } - } - - /* Not enough space in buffer */ - return GS_ERROR_FULL; -} - -static inline gs_i2c_slave_driver_entry_t * gs_slave_find_driver_entry(uint8_t device) -{ - gs_i2c_slave_driver_handle_t * handle; - for (int i = max_index_slave_in_use; i >= 0; i--) { - handle = &slave_drivers[i]; - if (((device == handle->entry.device) || (handle->entry.device == GS_I2C_ALL_DEVICES)) - && (handle->in_use == true)) { - return &handle->entry; - } - } - return NULL; -} - -gs_error_t gs_i2c_slave_start(uint8_t device) -{ - gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); - if (driver_entry) { - if (driver_entry->driver->start_handler) { - return driver_entry->driver->start_handler(device, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_i2c_slave_set_rx(uint8_t device, gs_i2c_slave_receive_t rx) -{ - gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); - if (driver_entry) { - if (driver_entry->driver->set_rx_handler) { - return driver_entry->driver->set_rx_handler(device, rx, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_i2c_slave_set_get_rx_buf(uint8_t device, gs_i2c_slave_get_rx_buf_t get_rx_buf, size_t buf_length) -{ - gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); - if (driver_entry) { - if (driver_entry->driver->set_get_rx_buf_handler) { - return driver_entry->driver->set_get_rx_buf_handler(device, get_rx_buf, buf_length, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_i2c_slave_set_response(uint8_t device, const uint8_t * tx, size_t tx_length) -{ - gs_i2c_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); - if (driver_entry) { - if (driver_entry->driver->set_response_handler) { - return driver_entry->driver->set_response_handler(device, tx, tx_length, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_i2c_slave_register_driver(const gs_i2c_slave_driver_entry_t * driver_entry) -{ - GS_CHECK_ARG(driver_entry != NULL); - GS_CHECK_ARG(driver_entry->driver != NULL); - - gs_i2c_slave_driver_handle_t * handle; - for (uint8_t i = 0; i < MAX_DRIVERS; i++) { - handle = &slave_drivers[i]; - if (handle->in_use == false) { - handle->entry = *driver_entry; - handle->in_use = true; - max_index_slave_in_use = i; - return GS_OK; - } - } - - /* Not enough space in buffer */ - return GS_ERROR_FULL; -} diff --git a/gomspace/libutil/src/linux/drivers/spi/spi.c b/gomspace/libutil/src/linux/drivers/spi/spi.c deleted file mode 100644 index 6756482c..00000000 --- a/gomspace/libutil/src/linux/drivers/spi/spi.c +++ /dev/null @@ -1,137 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -#define MAX_DRIVERS 20 - -typedef struct { - gs_spi_master_driver_entry_t entry; - bool in_use; -} gs_spi_master_driver_handle_t; - -typedef struct { - gs_spi_slave_driver_entry_t entry; - bool in_use; -} gs_spi_slave_driver_handle_t; - -static gs_spi_master_driver_handle_t master_drivers[MAX_DRIVERS]; -static gs_spi_slave_driver_handle_t slave_drivers[MAX_DRIVERS]; - -static uint8_t max_index_master_in_use = 0; -static uint8_t max_index_slave_in_use = 0; - -static inline gs_spi_master_driver_entry_t * gs_master_find_driver_entry(uint8_t slave) -{ - gs_spi_master_driver_handle_t * handle; - for (int i = max_index_master_in_use; i >= 0; i--) { - handle = &master_drivers[i]; - if (((slave == handle->entry.slave) || (handle->entry.slave == GS_SPI_ALL_SLAVES)) && (handle->in_use == true)) { - return &handle->entry; - } - } - return NULL; -} - -gs_error_t gs_spi_master_transaction(uint8_t slave, const void * tx, void * rx, size_t size, int timeout_ms) -{ - gs_spi_master_trans_t trans = {.tx = tx, .rx = rx, .size = size}; - return gs_spi_master_transactions(slave, &trans, 1, timeout_ms); -} - -gs_error_t gs_spi_master_transactions(uint8_t slave, gs_spi_master_trans_t *trans, size_t count, int timeout_ms) -{ - gs_spi_master_driver_entry_t * driver_entry = gs_master_find_driver_entry(slave); - if (driver_entry) { - if (driver_entry->driver->master_transactions_handler) { - return driver_entry->driver->master_transactions_handler(slave, trans, count, timeout_ms, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_spi_master_register_driver(const gs_spi_master_driver_entry_t * driver_entry) -{ - GS_CHECK_ARG(driver_entry != NULL); - GS_CHECK_ARG(driver_entry->driver != NULL); - - gs_spi_master_driver_handle_t * handle; - for (uint8_t i = 0; i < MAX_DRIVERS; i++) { - handle = &master_drivers[i]; - if (handle->in_use == false) { - handle->entry = *driver_entry; - handle->in_use = true; - max_index_master_in_use = i; - return GS_OK; - } - } - - /* Not enough space in buffer */ - return GS_ERROR_FULL; -} - -static inline gs_spi_slave_driver_entry_t * gs_slave_find_driver_entry(uint8_t device) -{ - gs_spi_slave_driver_handle_t * handle; - for (int i = max_index_slave_in_use; i >= 0; i--) { - handle = &slave_drivers[i]; - if (((device == handle->entry.device) || (handle->entry.device == GS_SPI_ALL_DEVICES)) - && (handle->in_use == true)) { - return &handle->entry; - } - } - return NULL; -} - -gs_error_t gs_spi_slave_start(uint8_t device) -{ - gs_spi_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); - if (driver_entry) { - if (driver_entry->driver->start_handler) { - return driver_entry->driver->start_handler(device, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_spi_slave_set_rx(uint8_t device, gs_spi_slave_receive_t rx) -{ - gs_spi_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); - if (driver_entry) { - if (driver_entry->driver->set_rx_handler) { - return driver_entry->driver->set_rx_handler(device, rx, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_spi_slave_set_response(uint8_t device, size_t offset, const uint8_t * tx, size_t size) -{ - gs_spi_slave_driver_entry_t * driver_entry = gs_slave_find_driver_entry(device); - if (driver_entry) { - if (driver_entry->driver->set_response_handler) { - return driver_entry->driver->set_response_handler(device, offset, tx, size, driver_entry->driver_data); - } - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_spi_slave_register_driver(const gs_spi_slave_driver_entry_t * driver_entry) -{ - GS_CHECK_ARG(driver_entry != NULL); - GS_CHECK_ARG(driver_entry->driver != NULL); - - gs_spi_slave_driver_handle_t * handle; - for (uint8_t i = 0; i < MAX_DRIVERS; i++) { - handle = &slave_drivers[i]; - if (handle->in_use == false) { - handle->entry = *driver_entry; - handle->in_use = true; - max_index_slave_in_use = i; - return GS_OK; - } - } - /* Not enough space in buffer */ - return GS_ERROR_FULL; -} diff --git a/gomspace/libutil/src/linux/drivers/sys/memory.c b/gomspace/libutil/src/linux/drivers/sys/memory.c deleted file mode 100644 index 8def9988..00000000 --- a/gomspace/libutil/src/linux/drivers/sys/memory.c +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -gs_error_t gs_mem_get_int_ram_stat(gs_mem_ram_stat_t * ram_stat) -{ - return GS_ERROR_NOT_SUPPORTED; -} - -gs_error_t gs_mem_get_ext_ram_stat(gs_mem_ram_stat_t * ram_stat) -{ - struct sysinfo info; - int res = sysinfo(&info); - if (res != GS_OK) { - return res; - } - - ram_stat->total = info.totalram; - ram_stat->max_available = -1; - ram_stat->min_available = -1; - ram_stat->available = info.freeram; - - return GS_OK; -} - -gs_mem_ram_type_t gs_mem_get_ram_default() -{ - return GS_MEM_RAM_TYPE_EXTERNAL; -} diff --git a/gomspace/libutil/src/linux/function.c b/gomspace/libutil/src/linux/function.c deleted file mode 100644 index 9e0f7c0f..00000000 --- a/gomspace/libutil/src/linux/function.c +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -typedef struct { - const char * short_name; - const char * long_name; - gs_function_t function; -} gs_function_register_t; - -static gs_function_register_t registry[10]; - -gs_error_t gs_function_register(const char * short_name, const char * long_name, gs_function_t function) -{ - for (unsigned int i = 0; i < GS_ARRAY_SIZE(registry); ++i) { - gs_function_register_t * cb = ®istry[i]; - if ((cb->short_name == NULL) && (cb->long_name == NULL)) { - cb->short_name = short_name; - cb->long_name = long_name; - cb->function = function; - return GS_OK; - } - } - return GS_ERROR_FULL; -} - -gs_error_t gs_function_invoke(const char * name, void * arg) -{ - for (unsigned int i = 0; i < GS_ARRAY_SIZE(registry); ++i) { - gs_function_register_t * cb = ®istry[i]; - if ((gs_string_empty(cb->short_name) == false) && (strcasecmp(cb->short_name, name) == 0)) { - return (cb->function)(arg); - } - if ((gs_string_empty(cb->long_name) == false) && (strcasecmp(cb->long_name, name) == 0)) { - return (cb->function)(arg); - } - } - - return GS_ERROR_NOT_IMPLEMENTED; -} diff --git a/gomspace/libutil/src/linux/mutex.c b/gomspace/libutil/src/linux/mutex.c deleted file mode 100644 index 00336510..00000000 --- a/gomspace/libutil/src/linux/mutex.c +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -gs_error_t gs_mutex_create(gs_mutex_t * mutex) -{ - if (mutex == NULL) { - return GS_ERROR_ARG; - } - - *mutex = malloc(sizeof(pthread_mutex_t)); - if (*mutex == NULL) { - return GS_ERROR_ALLOC; - } - - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - int res = pthread_mutex_init(*mutex, &attr); - if (res < 0) { - res = gs_error(errno); - free(*mutex); - } - - return res; -} - -gs_error_t gs_mutex_destroy(gs_mutex_t mutex) -{ - int res = GS_OK; - if (mutex) { - res = pthread_mutex_destroy(mutex); - if (res < 0) { - res = gs_error(errno); - } - free(mutex); - } - return res; -} - -gs_error_t gs_mutex_lock(gs_mutex_t mutex) -{ - int res = pthread_mutex_lock(mutex); - if (res < 0) { - res = gs_error(errno); - } - return res; -} - -gs_error_t gs_mutex_unlock(gs_mutex_t mutex) -{ - int res = pthread_mutex_unlock(mutex); - if (res < 0) { - res = gs_error(errno); - } - return res; -} diff --git a/gomspace/libutil/src/linux/queue.c b/gomspace/libutil/src/linux/queue.c deleted file mode 100644 index cb477f70..00000000 --- a/gomspace/libutil/src/linux/queue.c +++ /dev/null @@ -1,217 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ -/** - * Inspired by c-pthread-queue by Matthew Dickinson - * http://code.google.com/p/c-pthread-queue/ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define PTHREAD_QUEUE_ARG GS_ERROR_ARG -#define PTHREAD_QUEUE_EMPTY GS_ERROR_NOT_FOUND -#define PTHREAD_QUEUE_FULL GS_ERROR_FULL -#define PTHREAD_QUEUE_TIMEOUT GS_ERROR_TIMEOUT -#define PTHREAD_QUEUE_OK GS_OK - -typedef struct gs_pthread_queue { - uint8_t * buffer; - size_t size; - size_t item_size; - size_t items; - size_t in; - size_t out; - pthread_mutex_t mutex; - pthread_cond_t cond_full; - pthread_cond_t cond_empty; -} pthread_queue_t; - -static pthread_queue_t * pthread_queue_create(size_t length, size_t item_size) -{ - pthread_queue_t * q = malloc(sizeof(pthread_queue_t)); - - if (q != NULL) { - q->buffer = malloc(length*item_size); - if (q->buffer != NULL) { - q->size = length; - q->item_size = item_size; - q->items = 0; - q->in = 0; - q->out = 0; - if (pthread_mutex_init(&(q->mutex), NULL) || pthread_cond_init(&(q->cond_full), NULL) || pthread_cond_init(&(q->cond_empty), NULL)) { - free(q->buffer); - free(q); - q = NULL; - } - } else { - free(q); - q = NULL; - } - } - - return q; -} - -static void pthread_queue_delete(pthread_queue_t * q) -{ - if (q) { - free(q->buffer); - free(q); - } -} - -static int pthread_queue_enqueue(pthread_queue_t * queue, const void * value, uint32_t timeout) -{ - /* Calculate timeout */ - struct timespec ts; - if (clock_gettime(CLOCK_REALTIME, &ts)) { - return PTHREAD_QUEUE_ARG; - } - - uint32_t sec = timeout / 1000; - uint32_t nsec = (timeout - 1000 * sec) * 1000000; - - ts.tv_sec += sec; - - if (ts.tv_nsec + nsec > 1000000000) - ts.tv_sec++; - - ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; - - /* Get queue lock */ - pthread_mutex_lock(&(queue->mutex)); - - while (queue->items == queue->size) { - int ret = -1; - if (timeout) { - ret = pthread_cond_timedwait(&(queue->cond_full), &(queue->mutex), &ts); - } - if (ret) { - pthread_mutex_unlock(&(queue->mutex)); - return PTHREAD_QUEUE_TIMEOUT; - } - } - - /* Coby object from input buffer */ - memcpy(queue->buffer+(queue->in * queue->item_size), value, queue->item_size); - queue->items++; - queue->in = (queue->in + 1) % queue->size; - pthread_mutex_unlock(&(queue->mutex)); - - /* Nofify blocked threads */ - pthread_cond_broadcast(&(queue->cond_empty)); - - return PTHREAD_QUEUE_OK; -} - -static int pthread_queue_dequeue(pthread_queue_t * queue, void * buf, uint32_t timeout) -{ - /* Calculate timeout */ - struct timespec ts; - if (clock_gettime(CLOCK_REALTIME, &ts)) { - return PTHREAD_QUEUE_ARG; - } - - uint32_t sec = timeout / 1000; - uint32_t nsec = (timeout - 1000 * sec) * 1000000; - - ts.tv_sec += sec; - - if (ts.tv_nsec + nsec > 1000000000) - ts.tv_sec++; - - ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; - - /* Get queue lock */ - pthread_mutex_lock(&(queue->mutex)); - while (queue->items == 0) { - int ret = -1; - if (timeout) { - ret = pthread_cond_timedwait(&(queue->cond_empty), &(queue->mutex), &ts); - } - if (ret) { - pthread_mutex_unlock(&(queue->mutex)); - return PTHREAD_QUEUE_TIMEOUT; - } - } - - /* Coby object to output buffer */ - memcpy(buf, queue->buffer+(queue->out * queue->item_size), queue->item_size); - queue->items--; - queue->out = (queue->out + 1) % queue->size; - pthread_mutex_unlock(&(queue->mutex)); - - /* Nofify blocked threads */ - pthread_cond_broadcast(&(queue->cond_full)); - - return PTHREAD_QUEUE_OK; -} - -static size_t pthread_queue_items(pthread_queue_t * queue) -{ - pthread_mutex_lock(&(queue->mutex)); - size_t items = queue->items; - pthread_mutex_unlock(&(queue->mutex)); - return items; -} - -gs_error_t gs_queue_create(size_t items, size_t item_size, gs_queue_t * queue) -{ - if (queue == NULL) { - return GS_ERROR_ARG; - } - pthread_queue_t * q = pthread_queue_create(items, item_size); - if (q == NULL) { - return GS_ERROR_ALLOC; - } - *queue = q; - return GS_OK; -} - -gs_error_t gs_queue_destroy(gs_queue_t queue) -{ - pthread_queue_delete(queue); - return GS_OK; -} - -gs_error_t gs_queue_enqueue(gs_queue_t queue, const void *value, int timeout_ms) -{ - return pthread_queue_enqueue(queue, value, (timeout_ms >= 0) ? timeout_ms : INT_MAX); -} - -gs_error_t gs_queue_enqueue_isr(gs_queue_t queue, const void * value, gs_context_switch_t * cswitch) -{ - (void) cswitch; - gs_error_t error = gs_queue_enqueue(queue, value, 0); - return (error != GS_ERROR_TIMEOUT) ? error : GS_ERROR_FULL; -} - -gs_error_t gs_queue_dequeue(gs_queue_t queue, int timeout_ms, void *buf) -{ - return pthread_queue_dequeue(queue, buf, (timeout_ms >= 0) ? timeout_ms : INT_MAX); -} - -gs_error_t gs_queue_dequeue_isr(gs_queue_t queue, gs_context_switch_t * cswitch, void *buf) -{ - (void) cswitch; - gs_error_t error = gs_queue_dequeue(queue, 0, buf); - return (error != GS_ERROR_TIMEOUT) ? error : GS_ERROR_NOT_FOUND; -} - -unsigned int gs_queue_size(gs_queue_t queue) -{ - if (queue) { - return pthread_queue_items(queue); - } - return 0; -} - -unsigned int gs_queue_size_isr(gs_queue_t queue) -{ - return gs_queue_size(queue); -} diff --git a/gomspace/libutil/src/linux/rtc.c b/gomspace/libutil/src/linux/rtc.c deleted file mode 100644 index ff241d58..00000000 --- a/gomspace/libutil/src/linux/rtc.c +++ /dev/null @@ -1,78 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -static gs_error_t gs_rtc_get(void * driver_data, gs_timestamp_t * return_time) -{ - if (return_time == NULL) { - return GS_ERROR_ARG; - } - - return_time->tv_sec = 0; - return_time->tv_nsec = 0; - - int fd = open("/dev/rtc", O_RDONLY | O_CLOEXEC); - if (fd < 0) { - return gs_error(errno); - } - - struct tm tm; - memset(&tm, 0, sizeof(tm)); - int res = ioctl(fd, RTC_RD_TIME, &tm); - close(fd); - if (res < 0) { - return gs_error(errno); - } - - time_t time = mktime(&tm); - if (time < 0) { - return GS_ERROR_DATA; - } - - return_time->tv_sec = (uint32_t) time; - - return GS_OK; -} - -static gs_error_t gs_rtc_set(void * driver_data, const gs_timestamp_t * set_time) -{ - if (set_time == NULL) { - return GS_ERROR_ARG; - } - - int fd = open("/dev/rtc", O_RDONLY | O_CLOEXEC); - if (fd < 0) { - return gs_error(errno); - } - - const time_t now = set_time->tv_sec; - struct tm tm; - gmtime_r(&now, &tm); - int res = ioctl(fd, RTC_SET_TIME, &tm); - close(fd); - if (res < 0) { - return gs_error(errno); - } - - return GS_OK; -} - -gs_error_t gs_rtc_register_linux(bool get, bool set) -{ - static gs_rtc_driver_t rtc_driver; - if (get) { - rtc_driver.get_time = gs_rtc_get; - } - if (set) { - rtc_driver.set_time = gs_rtc_set; - } - return gs_rtc_register(&rtc_driver, NULL); -} diff --git a/gomspace/libutil/src/linux/sem.c b/gomspace/libutil/src/linux/sem.c deleted file mode 100644 index b4d2c09d..00000000 --- a/gomspace/libutil/src/linux/sem.c +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include - -gs_error_t gs_sem_create(unsigned int initialValue, gs_sem_t * sem) -{ - if (sem == NULL) { - return GS_ERROR_ARG; - } - - *sem = malloc(sizeof(sem_t)); - if (*sem == NULL) { - return GS_ERROR_ALLOC; - } - - int res = sem_init(*sem, 0, initialValue); - if (res < 0) { - res = gs_error(errno); - free(*sem); - } - - return res; -} - -gs_error_t gs_sem_destroy(gs_sem_t sem) -{ - int res = GS_OK; - if (sem) { - res = sem_destroy(sem); - if (res < 0) { - res = gs_error(errno); - } - free(sem); - } - return res; -} - -gs_error_t gs_sem_wait(gs_sem_t sem, int timeout_ms) -{ - int res; - - if (timeout_ms < 0) { - res = sem_wait(sem); - } else { - struct timespec ts; - res = clock_gettime(CLOCK_REALTIME, &ts); - if (res == 0) { - const uint32_t ms = (uint32_t)timeout_ms; - uint32_t sec = ms / 1000; - uint32_t nsec = (ms - (1000 * sec)) * 1000000; - - ts.tv_sec += sec; - - if (ts.tv_nsec + nsec >= 1000000000) { - ts.tv_sec++; - } - - ts.tv_nsec = (ts.tv_nsec + nsec) % 1000000000; - - res = sem_timedwait(sem, &ts); - } - } - if (res < 0) { - res = gs_error(errno); - } - return res; -} - -gs_error_t gs_sem_post(gs_sem_t sem) -{ - int res = sem_post(sem); - if (res < 0) { - res = gs_error(errno); - } - return res; -} - -gs_error_t gs_sem_post_isr(gs_sem_t sem, gs_context_switch_t * cswitch) -{ - (void) cswitch; - int res = sem_post(sem); - if (res < 0) { - res = gs_error(errno); - } - return res; -} diff --git a/gomspace/libutil/src/linux/signal.c b/gomspace/libutil/src/linux/signal.c deleted file mode 100644 index 826bc325..00000000 --- a/gomspace/libutil/src/linux/signal.c +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -static void gs_signal_default_handler(int signo, siginfo_t *si, void *context) -{ - exit(GS_EXITCODE_SIGNAL(signo)); // ensure atexit are invoked -} - -gs_error_t gs_signal_catch(int signal, gs_signal_handler handler) -{ - if (handler == NULL) { - handler = gs_signal_default_handler; - } - struct sigaction sa = { .sa_flags = SA_SIGINFO, - .sa_sigaction = handler}; - if (sigemptyset(&sa.sa_mask)) { - return GS_ERROR_UNKNOWN; - } - if (sigaction(signal, &sa, NULL)) { - return GS_ERROR_UNKNOWN; - } - return GS_OK; -} - -gs_error_t gs_signal_ignore(int signal) -{ - struct sigaction sa = { .sa_flags = 0, - .sa_handler = SIG_IGN}; // handle signal by ignoring - if (sigemptyset(&sa.sa_mask)) { - return GS_ERROR_UNKNOWN; - } - if (sigaction(signal, &sa, NULL)) { - return GS_ERROR_UNKNOWN; - } - return GS_OK; -} diff --git a/gomspace/libutil/src/linux/stdio.c b/gomspace/libutil/src/linux/stdio.c deleted file mode 100644 index 0fa052b7..00000000 --- a/gomspace/libutil/src/linux/stdio.c +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -gs_error_t gs_stdio_putchar(int ch) -{ - const int res = putchar(ch); - if (res < 0) { - return GS_ERROR_IO; - } - return GS_OK; -} - -gs_error_t gs_stdio_getchar_timed(int timeout_ms, int * ch) -{ - struct pollfd fds = {STDIN_FILENO, POLLIN, 0}; - const int res = poll(&fds, 1, timeout_ms); - - if (res == 0) { - return GS_ERROR_TIMEOUT; - } - - if ((res > 0) && (fds.revents & POLLIN)) { - int tmp = getchar(); - if (tmp >= 0) { - if (ch) { - *ch = tmp; - } - return GS_OK; - } - } - - return GS_ERROR_IO; -} diff --git a/gomspace/libutil/src/linux/sysfs_helper.c b/gomspace/libutil/src/linux/sysfs_helper.c deleted file mode 100644 index 2cdb390a..00000000 --- a/gomspace/libutil/src/linux/sysfs_helper.c +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -gs_error_t gs_sysfs_write_file(const char *path, const char *value) -{ - log_trace("sysfs: write %s to %s", value, path); - - int fd = open(path, O_WRONLY); - if (fd < 0) { - return GS_ERROR_HANDLE; - } - - size_t len = strlen(value); - ssize_t bytes = write(fd, value, len); - close(fd); - if (bytes < 0) { - return GS_ERROR_NO_DATA; - } - - return (len == (size_t)bytes) ? GS_OK : GS_ERROR_NO_DATA; -} - -gs_error_t gs_sysfs_read_file(const char *path, char *value, size_t len) -{ - log_trace("sysfs: read %s", path); - - int fd = open(path, O_RDONLY); - if (fd < 0) { - return GS_ERROR_HANDLE; - } - - ssize_t bytes = read(fd, value, len); - close(fd); - if (bytes < 0) { - return GS_ERROR_DATA; - } - - return GS_OK; -} diff --git a/gomspace/libutil/src/linux/thread.c b/gomspace/libutil/src/linux/thread.c deleted file mode 100644 index 43de1815..00000000 --- a/gomspace/libutil/src/linux/thread.c +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -gs_error_t gs_thread_create(const char * const name, - gs_thread_func_t func, - void * parameter, - size_t stack_size, - gs_thread_priority_t priority, - uint32_t flags, - gs_thread_t * return_handle) -{ - gs_time_uptime(); // force initialize of static offset - - pthread_attr_t attr; - int res = pthread_attr_init(&attr); - if (res) { - return GS_ERROR_ALLOC; - } - - if (flags & GS_THREAD_CREATE_JOINABLE) { - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - } else { - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - } - - gs_thread_t handle; - res = pthread_create(&handle, &attr, func, parameter); - pthread_attr_destroy(&attr); - if (res) { - return GS_ERROR_ALLOC; - } - - if (return_handle) { - *return_handle = handle; - } - - return GS_OK; -} - -gs_error_t gs_thread_create_with_stack(const char * const name, - gs_thread_func_t func, - void * parameter, - size_t stack_size, - gs_stack_type_t *stack, - gs_thread_priority_t priority, - uint32_t flags, - gs_thread_t * return_handle) -{ - return gs_thread_create(name, func, parameter, stack_size, priority, flags, return_handle); -} - -void gs_thread_exit(void * exitValue) -{ - pthread_exit(exitValue); -} - -void gs_thread_sleep_ms(uint32_t time_ms) -{ - gs_time_sleep_ms(time_ms); -} - -gs_error_t gs_thread_join(gs_thread_t thread, void ** return_retval) -{ - gs_error_t error = GS_ERROR_ARG; - void * retval = 0; - if (thread) { - int res = pthread_join(thread, &retval); - if (res == 0) { - error = GS_OK; - } else { - retval = 0; - } - } - if (return_retval) { - *return_retval = retval; - } - return error; -} - -void gs_thread_block(void) -{ - /* Wait here forever */ - for (;;) { - gs_time_sleep_ms(10000); - } -} diff --git a/gomspace/libutil/src/linux/time.c b/gomspace/libutil/src/linux/time.c deleted file mode 100644 index 46377feb..00000000 --- a/gomspace/libutil/src/linux/time.c +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -uint32_t gs_time_rel_ms(void) -{ - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { - return 0; - } - - return (uint32_t)((ts.tv_sec * 1000) + (ts.tv_nsec/1000000)); -} - -uint32_t gs_time_rel_ms_isr(void) -{ - return gs_time_rel_ms(); -} - -static uint32_t uptime_offset = 0; -uint32_t gs_time_uptime(void) -{ - uint32_t seconds; - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { - seconds = 0; - } else { - seconds = (uint32_t) ts.tv_sec; - } - if (uptime_offset == 0) { - uptime_offset = seconds; - } - return (seconds - uptime_offset); -} - -void gs_time_sleep_ns(uint64_t time_ns) -{ - struct timespec ts; - ts.tv_sec = (time_ns / GS_TIMESTAMP_NSEC_PER_SEC); - ts.tv_nsec = (time_ns % GS_TIMESTAMP_NSEC_PER_SEC); - - // improvement: check return code (INTR) and use remaining. - nanosleep(&ts, NULL); -} - -void gs_time_sleep_ms(uint32_t time_ms) -{ - uint64_t ns = time_ms; - ns *= 1000000LL; - gs_time_sleep_ns( ns); -} diff --git a/gomspace/libutil/src/lock.c b/gomspace/libutil/src/lock.c deleted file mode 100644 index 76be91bd..00000000 --- a/gomspace/libutil/src/lock.c +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (c) 2013-2019 GomSpace A/S. All rights reserved. */ - -#include "lock.h" -#include - -static gs_mutex_t gs_lock; - -gs_error_t gs_lock_init(void) -{ - if (gs_lock == NULL) { - return gs_mutex_create(&gs_lock); - } - return GS_OK; -} - -gs_error_t gs_lock_lock(void) -{ - if (gs_lock == NULL) { - gs_error_t error = gs_lock_init(); - if (error) { - return error; - } - } - return gs_mutex_lock(gs_lock); -} - -gs_error_t gs_lock_unlock(void) -{ - return gs_mutex_unlock(gs_lock); -} diff --git a/gomspace/libutil/src/lock.h b/gomspace/libutil/src/lock.h deleted file mode 100644 index b22841e8..00000000 --- a/gomspace/libutil/src/lock.h +++ /dev/null @@ -1,14 +0,0 @@ -/* Copyright (c) 2013-2019 GomSpace A/S. All rights reserved. */ -/** - @file - - Basic/core locking. - - Use for rare read/write locking, e.g. protecting register/de-regsiter functions. -*/ - -#include - -gs_error_t gs_lock_init(void); -gs_error_t gs_lock_lock(void); -gs_error_t gs_lock_unlock(void); diff --git a/gomspace/libutil/src/log/appender/console.c b/gomspace/libutil/src/log/appender/console.c deleted file mode 100644 index 818248b3..00000000 --- a/gomspace/libutil/src/log/appender/console.c +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -// generated by waf configure -> GS_LOG_ENABLE_ISR_LOGS -#include - -static gs_log_appender_console_cb_t g_console_log_cb = NULL; -static gs_mutex_t g_log_console_mutex = NULL; - -gs_error_t gs_log_console_append_init(gs_log_appender_t *appender) -{ - gs_error_t ret = GS_OK; - if (g_log_console_mutex == NULL) { - ret = gs_mutex_create(&g_log_console_mutex); - if (ret != GS_OK) { - g_log_console_mutex = NULL; - } - } - return ret; -} - -static void gs_log_console_append_isr(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) -{ - va_list my_va; - va_copy(my_va, va); - - const char * color = gs_log_level_to_color_begin(level); - const char * end_color = gs_log_level_to_color_end(); - const char clevel = gs_log_level_to_char(level); - - // print log - printf("%s%04"PRIu32".%06"PRIu32" %c %s: ", color, ts->tv_sec, ts->tv_nsec / 1000, clevel, group->name); - GS_PGM_VPRINTF(format, my_va); - printf("%s\r\n", end_color); - - va_end(my_va); -} - -static void gs_log_console_append(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) -{ - if (g_console_log_cb) - return g_console_log_cb(appender, level, group, ts, format, va); - - if (g_log_console_mutex) { - gs_mutex_lock(g_log_console_mutex); - } - - gs_log_console_append_isr(appender, level, group, ts, format, va); - - if (g_log_console_mutex) { - gs_mutex_unlock(g_log_console_mutex); - } -} - -static void gs_log_console_append_get_info(gs_log_appender_t *appender, char *info_str, uint8_t str_size) -{ - if (!info_str) { - return; - } - - snprintf(info_str, str_size, "Prints on stdout"); -} - -gs_error_t gs_log_appender_console_set_cb(gs_log_appender_console_cb_t cb) -{ - g_console_log_cb = cb; - return GS_OK; -} - -static const gs_log_appender_driver_t console_appender_driver = { - .init = gs_log_console_append_init, - .append = gs_log_console_append, -#ifdef GS_LOG_ENABLE_ISR_LOGS - .append_isr = gs_log_console_append_isr, -#else - .append_isr = 0, -#endif - .info = gs_log_console_append_get_info, -}; - -gs_log_appender_t gs_log_appender_console = { - .name = "console", - .drv = &console_appender_driver, - .drv_config = 0, - .mask = LOG_ALL_MASK, -}; diff --git a/gomspace/libutil/src/log/appender/simple_file.c b/gomspace/libutil/src/log/appender/simple_file.c deleted file mode 100644 index f74a19e7..00000000 --- a/gomspace/libutil/src/log/appender/simple_file.c +++ /dev/null @@ -1,117 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#ifndef __AVR__ -#include -#include -#include - -#include -#include - -typedef struct simple_file_drv_data { - FILE *fp; - gs_mutex_t mutex; -} simple_file_drv_data_t; - -static gs_error_t gs_log_simple_file_init(gs_log_appender_t *appender) -{ - const gs_log_appender_simple_file_config_t *config = appender->drv_config; - - if (config == NULL || gs_string_empty(config->filename)) { - return GS_ERROR_ARG; - } - - simple_file_drv_data_t *drv_data = appender->drv_data; - if (drv_data == NULL) { - drv_data = calloc(1, sizeof(*drv_data)); - if (drv_data == NULL) { - return GS_ERROR_ALLOC; - } - } - - /* If file is already open - Close it first */ - if (drv_data->fp) { - gs_mutex_lock(drv_data->mutex); - fclose(drv_data->fp); - drv_data->fp = NULL; - gs_mutex_unlock(drv_data->mutex); - gs_mutex_destroy(drv_data->mutex); - } - - const char * mode = config->truncate ? "w" : "a"; - - drv_data->fp = fopen(config->filename, mode); - if (drv_data->fp == NULL) { - log_error("%s: failed to open log-file: [%s], mode: %s", __FUNCTION__, config->filename, mode); - free(drv_data); - drv_data = 0; - return GS_ERROR_IO; - } - - gs_mutex_create(&drv_data->mutex); - appender->drv_data = drv_data; /* Set driver data on appender */ - return GS_OK; -} - -static void gs_log_simple_file_append(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t *group, const gs_timestamp_t * ts, const char * format, va_list va) -{ - va_list my_va; - va_copy(my_va, va); - - const gs_log_appender_simple_file_config_t *config = appender->drv_config; - simple_file_drv_data_t *drv_data = appender->drv_data; - if (drv_data == 0) { - va_end(my_va); - return; - } - - const char clevel = gs_log_level_to_char(level); - - const time_t t = ts->tv_sec; - struct tm result; - const char * tzone; - if (config->use_local_time) { - localtime_r(&t, &result); - tzone = ""; - } else { - gmtime_r(&t, &result); - tzone = "Z"; - } - - if (drv_data->mutex) { - gs_mutex_lock(drv_data->mutex); - } - { - fprintf(drv_data->fp, "%04d-%02d-%02d %02d:%02d:%02d.%06"PRIu32"%s %c %s: ", - result.tm_year + 1900, result.tm_mon + 1, result.tm_mday, - result.tm_hour, result.tm_min, result.tm_sec, - ts->tv_nsec / 1000, tzone, clevel, group->name); - vfprintf(drv_data->fp, format, my_va); - fprintf(drv_data->fp, "\r\n"); - fflush(drv_data->fp); - } - if (drv_data->mutex) { - gs_mutex_unlock(drv_data->mutex); - } - - va_end(my_va); -} - -static void gs_log_simple_file_append_info(gs_log_appender_t *appender, char *info_str, uint8_t str_size) -{ - if (!info_str) { - return; - } - - const gs_log_appender_simple_file_config_t *config = appender->drv_config; - snprintf(info_str, str_size, "Writes to file \"%s\"", config->filename); -} - -const gs_log_appender_driver_t gs_log_appender_simple_file_driver = { - .init = gs_log_simple_file_init, - .append = gs_log_simple_file_append, - .append_isr = 0, - .info = gs_log_simple_file_append_info, -}; - -#endif diff --git a/gomspace/libutil/src/log/commands.c b/gomspace/libutil/src/log/commands.c deleted file mode 100644 index 85ac7ae5..00000000 --- a/gomspace/libutil/src/log/commands.c +++ /dev/null @@ -1,392 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include "local.h" -#include - - -// iterator context -typedef struct { - gs_command_context_t * ctx; - gs_log_group_t * first; - gs_log_appender_t * first_appender; - bool completer; - bool detailed; -} iter_group_t; - -#define FORMAT_BUF_SIZE 10 -static const char * format_mask(uint8_t mask, char * buf) -{ - snprintf(buf, FORMAT_BUF_SIZE, "%c%c%c%c%c%c", - (mask & LOG_ERROR_MASK) ? 'E' : '.', - (mask & LOG_WARNING_MASK) ? 'W' : '.', - (mask & LOG_NOTICE_MASK) ? 'N' : '.', - (mask & LOG_INFO_MASK) ? 'I' : '.', - (mask & LOG_DEBUG_MASK) ? 'D' : '.', - (mask & LOG_TRACE_MASK) ? 'T' : '.'); - return buf; -} - -static bool iter_print_group_appenders(void * ctx_in, gs_log_appender_t * appender) -{ - gs_bytebuffer_t *bb = ctx_in; - gs_bytebuffer_printf(bb, "%s,", appender->name); - return true; -} - -static bool iter_print_group(void * ctx_in, gs_log_group_t * group) -{ - iter_group_t * ctx = ctx_in; - char level_mask[FORMAT_BUF_SIZE]; - if (!ctx->completer) { - char appender_str[128] = "\0"; - gs_bytebuffer_t bb; - gs_bytebuffer_init(&bb, appender_str, sizeof(appender_str)); - gs_log_group_appender_iterate(group, &bb, iter_print_group_appenders); - if (ctx->detailed) { - gs_command_set_output_printf(ctx->ctx, group->name, "category", "0x%08x", group->category); - gs_command_set_output_printf(ctx->ctx, group->name, "mask", "%-6s (0x%02x)", format_mask(group->mask, level_mask), group->mask); - gs_command_set_output_printf(ctx->ctx, group->name, "appenders", appender_str); - } else { - gs_command_set_output_printf(ctx->ctx, NULL, NULL, "%-15s %-6s %s", group->name, format_mask(group->mask, level_mask), appender_str); - } - } else { - fprintf(ctx->ctx->out, " %-15s %-6s\r\n", - group->name, - format_mask(group->mask, level_mask)); - } - return true; -} - -static int cmd_log_group_list(gs_command_context_t * ctx) -{ - iter_group_t iter = {.ctx = ctx, .completer = false}; - - if (ctx->argc > 1) { - iter.detailed = true; - gs_log_group_iterate(ctx->argv[1], &iter, iter_print_group); - } else { - fprintf(ctx->out, "Group Mask Appenders\r\n"); - gs_log_group_iterate("*", &iter, iter_print_group); - } - return GS_OK; -} - -static bool iter_print_appender(void * ctx_in, gs_log_appender_t * appender) -{ - iter_group_t * ctx = ctx_in; - char level_mask[FORMAT_BUF_SIZE]; - if (!ctx->completer) { - if (ctx->detailed) { - gs_command_set_output_printf(ctx->ctx, appender->name, "mask", "%-6s (0x%02x)", format_mask(appender->mask, level_mask), appender->mask); - - if (appender->drv->info) { - char info_str[100]; - appender->drv->info(appender, info_str, sizeof(info_str)); - gs_command_set_output(ctx->ctx, appender->name, "info", info_str); - } - } else { - gs_command_set_output_printf(ctx->ctx, NULL, NULL, "%-15s %-6s", appender->name, format_mask(appender->mask, level_mask)); - } - } else { - fprintf(ctx->ctx->out, " %-15s %-6s\r\n", - appender->name, - format_mask(appender->mask, level_mask)); - } - return true; -} - -static int cmd_log_appender_list(gs_command_context_t * ctx) -{ - iter_group_t iter = {.ctx = ctx, .completer = false}; - - if (ctx->argc > 1) { - iter.detailed = true; - gs_log_appender_iterate(ctx->argv[1], &iter, iter_print_appender); - } else { - fprintf(ctx->out, "Appender Mask\r\n"); - gs_log_appender_iterate("*", &iter, iter_print_appender); - } - return GS_OK; -} - -typedef gs_error_t (*log_get_mask_t)(const char *name, uint8_t* mask); -typedef gs_error_t (*log_set_mask_t)(const char *name, uint8_t mask); - -static int cmd_log_mask_handler(gs_command_context_t * ctx, log_get_mask_t get_mask, log_set_mask_t set_mask) -{ - /* strtok writes to the string, so we need to duplicate it to avoid writing to read-only memory */ - char strbuf[100]; - GS_STRNCPY(strbuf, ctx->argv[1]); - - char * saveptr = NULL; - char * token = strtok_r(strbuf, ",", &saveptr); - gs_error_t error = GS_OK; - while (token && (error == GS_OK)) { - - uint8_t old_mask = 0; - if (gs_log_is_group_all(token) == false) { - error = get_mask(token, &old_mask); - } - if (error == GS_OK) { - uint8_t new_mask = 0; - error = gs_log_string_to_mask(ctx->argv[2], old_mask, &new_mask); - if (error == GS_OK) { - error = set_mask(token, new_mask); - } - } - - token = strtok_r(NULL, ",", &saveptr); - } - - return error; -} - -static int cmd_log_group_mask(gs_command_context_t * ctx) -{ - return cmd_log_mask_handler(ctx, gs_log_group_get_level_mask, gs_log_group_set_level_mask); -} - -static int cmd_log_appender_mask(gs_command_context_t * ctx) -{ - return cmd_log_mask_handler(ctx, gs_log_appender_get_level_mask, gs_log_appender_set_level_mask); -} - - -#ifndef __AVR__ -static bool iter_log_completer(void *ctx_in, gs_log_group_t * group) -{ - iter_group_t * ctx = ctx_in; - unsigned int hits = gs_command_completer_add_token(ctx->ctx, group->name, false); - if (hits == 1) { - ctx->first = group; - } else { - if (hits == 2) { - fprintf(ctx->ctx->out, "\r\n"); - iter_print_group(ctx, ctx->first); - } - iter_print_group(ctx, group); - } - return true; -} - -static gs_error_t cmd_log_group_completer(gs_command_context_t * ctx, int arg_to_complete) -{ - if (arg_to_complete == 1) { - iter_group_t iter = {.ctx = ctx, .completer = true}; - char name[50]; - snprintf(name, sizeof(name), "%s*", (ctx->argc > 1) ? ctx->argv[1] : ""); - gs_log_group_iterate(name, &iter, iter_log_completer); - return GS_OK; - } - return GS_ERROR_AMBIGUOUS; -} - -static bool iter_log_appender_completer(void *ctx_in, gs_log_appender_t * appender) -{ - iter_group_t * ctx = ctx_in; - unsigned int hits = gs_command_completer_add_token(ctx->ctx, appender->name, false); - if (hits == 1) { - ctx->first_appender = appender; - } else { - if (hits == 2) { - fprintf(ctx->ctx->out, "\r\n"); - iter_print_appender(ctx, ctx->first_appender); - } - iter_print_appender(ctx, appender); - } - return true; -} - -static gs_error_t cmd_log_appender_completer(gs_command_context_t * ctx, int arg_to_complete) -{ - if (arg_to_complete == 1) { - iter_group_t iter = {.ctx = ctx, .completer = true}; - char name[50]; - snprintf(name, sizeof(name), "%s*", (ctx->argc > 1) ? ctx->argv[1] : ""); - gs_log_appender_iterate(name, &iter, iter_log_appender_completer); - return GS_OK; - } - return GS_ERROR_AMBIGUOUS; -} -#endif - -typedef struct { - gs_command_context_t *cmd_ctx; - unsigned int count; -} hist_ctx_t; - -static bool appender_history_iter(void *ctx, gs_log_level_t level, const gs_timestamp_t *ts, const char *group, const char *msg) -{ - hist_ctx_t * hist_ctx = ctx; - - /* Break iteration if history record count is reached. */ - if (hist_ctx->count-- == 0) { - return false; - } - - gs_command_set_output_printf(hist_ctx->cmd_ctx, NULL, NULL, - "%s%04"PRIu32".%06"PRIu32" %c %s: %s%s", - gs_log_level_to_color_begin(level), - ts->tv_sec, ts->tv_nsec/1000, - gs_log_level_to_char(level), - group, - msg, - gs_log_level_to_color_end()); - - return true; -} - -static int cmd_log_appender_hist(gs_command_context_t * ctx) -{ - hist_ctx_t hist_ctx = {.cmd_ctx = ctx, .count = 20}; - if (ctx->argc == 3) { - hist_ctx.count = atoi(ctx->argv[2]); - } - - return gs_log_appender_history_iterate(ctx->argv[1], &hist_ctx, appender_history_iter); -} - - -static bool iter_log_group_find(void* ctx_in, gs_log_group_t *group) -{ - gs_log_group_t **grp = ctx_in; - *grp = group; - return false; -} - -static int cmd_log_insert(gs_command_context_t * ctx) -{ - gs_log_group_t *log_group = NULL; - gs_error_t error = gs_log_group_iterate(ctx->argv[1], &log_group, iter_log_group_find); - if (error != GS_OK) { - return error; - } - - gs_log_level_t level; - error = gs_log_string_to_level(ctx->argv[2], &level); - if (error == GS_OK) { - gs_log(level, log_group, GS_PGM_STR("%s"), ctx->argv[3]); - } - - return error; -} - -static int cmd_log_color(gs_command_context_t * ctx) -{ - bool color; - gs_error_t error = gs_string_to_bool(ctx->argv[1], &color); - if (error == GS_OK) { - gs_log_set_print_color(color); - } - - return error; -} - -static const gs_command_t GS_COMMAND_SUB cmd_log_group_cmds[] = { - { - .name = "list", - .help = "list log groups", - .usage = "[group]", -#ifndef __AVR__ - .completer = cmd_log_group_completer, -#endif - .handler = cmd_log_group_list, - .mandatory_args = GS_COMMAND_NO_ARGS, - .optional_args = 1, - },{ - .name = "mask", - .help = "Set log group mask(s): e|w|i|d|t|stand|all|non", - .usage = "[,group] <[+-]level>[,level]", -#ifndef __AVR__ - .completer = cmd_log_group_completer, -#endif - .handler = cmd_log_group_mask, - .mandatory_args = 2, - },{ - .name = "insert", - .help = "Log message", - .usage = " ", -#ifndef __AVR__ - .completer = cmd_log_group_completer, -#endif - .handler = cmd_log_insert, - .mandatory_args = 3, - },{ - .name = "color", - .help = "Enable/disable color logs (stdout)", - .usage = "", - .handler = cmd_log_color, - .mandatory_args = 1, - } -}; - -static const gs_command_t GS_COMMAND_SUB cmd_log_appender_cmds[] = { - { - .name = "list", - .help = "list log appenders", - .usage = "[appender]", -#ifndef __AVR__ - .completer = cmd_log_appender_completer, -#endif - .handler = cmd_log_appender_list, - .mandatory_args = GS_COMMAND_NO_ARGS, - .optional_args = 1, - }, { - .name = "mask", - .help = "Set log appender mask(s): e|w|i|d|t|stand|all|non", - .usage = "[,appender] <[+-]level>[,level]", -#ifndef __AVR__ - .completer = cmd_log_appender_completer, -#endif - .handler = cmd_log_appender_mask, - .mandatory_args = 2, - }, { - .name = "hist", - .help = "Show log appender history", - .usage = " [cnt]", -#ifndef __AVR__ - .completer = cmd_log_appender_completer, -#endif - .handler = cmd_log_appender_hist, - .mandatory_args = 1, - .optional_args = 1, - } -}; - -static const gs_command_t GS_COMMAND_SUB cmd_log_cmds[] = { - { - .name = "group", - .help = "log group commands", - .chain = GS_COMMAND_INIT_CHAIN(cmd_log_group_cmds), - }, { - .name = "appender", - .help = "log appender commands", - .chain = GS_COMMAND_INIT_CHAIN(cmd_log_appender_cmds), - } -}; - -static const gs_command_t GS_COMMAND_ROOT cmd_log[] = { - { - .name = "log", - .help = "log: Log system", - .chain = GS_COMMAND_INIT_CHAIN(cmd_log_cmds) - },{ - .name = "debug", - .help = "Set Log group mask(s): e|w|n|i|d|t|stand|all|off", - .usage = "[,group] <[+-]level>[,level]", -#ifndef __AVR__ - .completer = cmd_log_group_completer, -#endif - .handler = cmd_log_group_mask, - .mandatory_args = 2, - }, -}; - -gs_error_t gs_log_register_commands(void) -{ - return GS_COMMAND_REGISTER(cmd_log); -} diff --git a/gomspace/libutil/src/log/local.h b/gomspace/libutil/src/log/local.h deleted file mode 100644 index 654577c8..00000000 --- a/gomspace/libutil/src/log/local.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -struct gs_log_list { - union { - gs_log_group_t * group; - gs_log_appender_t *appender; - } data; - struct gs_log_list * next; -}; - -/** - De-register appender for the given log group. - - @note The de-register function is not safe when logging is active, this function - is mostly for test and should only be used in product code with extreme caution. - If logging is still not active, this function can be used safely. - - @param[in] group_name Name of the group. - @param[in] appender_name Name of appender to de-register for this group. - @return gs_error_t -*/ -gs_error_t gs_log_group_deregister_appender(const char * group_name, const char * appender_name); - -bool gs_log_is_group_all(const char * name); diff --git a/gomspace/libutil/src/log/log.c b/gomspace/libutil/src/log/log.c deleted file mode 100644 index 16865900..00000000 --- a/gomspace/libutil/src/log/log.c +++ /dev/null @@ -1,705 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include "local.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "../lock.h" -#include - -#define MASK_SET 0 -#define MASK_AND 1 -#define MASK_OR 2 - -// use color in log print -static bool g_print_no_color; - -// Log Group list -GS_STATIC gs_log_list_t g_log_groups = { .data = { .group = 0} }; - -// Log Appender list -GS_STATIC gs_log_list_t g_log_appenders = { .data = { .appender = 0} }; - -// Root Log Appenders - used for holding a appender list -GS_STATIC gs_log_group_t g_log_group_root = {.name = GS_LOG_GROUP_ROOT}; - -// Default log group - always present. -GS_LOG_GROUP(LOG_DEFAULT, "default", GS_LOG_CAT_DEFAULT, LOG_ERROR_MASK | LOG_WARNING_MASK | LOG_NOTICE_MASK | LOG_INFO_MASK); - -bool gs_log_is_group_all(const char * name) -{ - return (name && ((strcasecmp(name, "*") == 0) || (strcasecmp(name, "all") == 0))); -} - -static bool iter_set_level_mask(void * ctx_in, gs_log_group_t * group) -{ - uint8_t * level_mask = ctx_in; - group->mask = *level_mask; - return true; -} - -gs_error_t gs_log_group_set_level_mask(const char * group_name, uint8_t mask) -{ - if (gs_string_empty(group_name)) { - return GS_ERROR_HANDLE; - } - - return gs_log_group_iterate(group_name, &mask, iter_set_level_mask); -} - -static bool iter_get_level_mask(void * ctx_in, gs_log_group_t * group) -{ - uint8_t * level_mask = ctx_in; - *level_mask = group->mask; - return true; -} - -gs_error_t gs_log_group_get_level_mask(const char * group_name, uint8_t *mask) -{ - if (gs_string_empty(group_name)) { - return GS_ERROR_HANDLE; - } - - gs_error_t error = gs_log_group_iterate(group_name, mask, iter_get_level_mask); - return error; -} - -gs_error_t gs_log_string_to_level(const char * str, gs_log_level_t * return_level) -{ - if (gs_string_empty(str)) { - return GS_ERROR_ARG; - } - - const size_t len = strlen(str); - gs_log_level_t level; - - if (strncasecmp(str, "trace", len) == 0) { - level = LOG_TRACE; - } else if (strncasecmp(str, "debug", len) == 0) { - level = LOG_DEBUG; - } else if (strncasecmp(str, "informational", len) == 0) { - level = LOG_INFO; - } else if (strncasecmp(str, "notice", len) == 0) { - level = LOG_NOTICE; - } else if (strncasecmp(str, "warning", len) == 0) { - level = LOG_WARNING; - } else if (strncasecmp(str, "error", len) == 0) { - level = LOG_ERROR; - } else { - return GS_ERROR_DATA; - } - - if (return_level) { - *return_level = level; - } - - return GS_OK; -} - -char gs_log_level_to_char(gs_log_level_t level) -{ - switch (level) { - case LOG_TRACE: return 'T'; - case LOG_DEBUG: return 'D'; - case LOG_INFO: return 'I'; - case LOG_NOTICE: return 'N'; - case LOG_WARNING: return 'W'; - case LOG_ERROR: return 'E'; - default: return '?'; - } -} - -gs_error_t gs_log_string_to_mask(const char *str, uint8_t old, uint8_t * return_mask) -{ - GS_CHECK_ARG(gs_string_empty(str) == false); - - char strbuf[50]; // copy buf, coz strtok will mess it up - GS_STRNCPY(strbuf, str); - - char *saveptr = NULL; - char *token = strtok_r(strbuf, ",", &saveptr); - while (token) { - // check for +xxx (add), -xxxx (remove), xxxx (set) - int op = MASK_SET; - if (*token == '+') { - op = MASK_OR; - token++; - } else if (*token == '-') { - op = MASK_AND; - token++; - } - - const unsigned int token_length = strlen(token); - if (token_length < 1) { - return GS_ERROR_DATA; - } - - /* Check mask */ - uint8_t mask; - gs_log_level_t level; - if (gs_log_string_to_level(token, &level) == GS_OK) { - // actual level - if (op == MASK_SET) { - // set all level bits equal or lover - mask = LOG_ALL_MASK & ~((1 << level) - 1); - } else { - mask = (1 << level); - } - } else if (!strncasecmp(token, "default", token_length)) { // legacy - conflicts with 'de(bug)' - mask = LOG_DEFAULT_MASK; - op = MASK_SET; - } else if (!strncasecmp(token, "standard", token_length)) { - mask = LOG_DEFAULT_MASK; - op = MASK_SET; - } else if (!strncasecmp(token, "all", token_length)) { - mask = LOG_ALL_MASK; - op = MASK_SET; - } else if (!strncasecmp(token, "off", token_length)) { - mask = 0; - op = MASK_SET; - } else if (!strncasecmp(token, "none", token_length)) { // legacy - conflicts with 'no(tice)' - mask = 0; - op = MASK_SET; - } else if (gs_string_to_uint8(token, &mask) == GS_OK) { - op = MASK_SET; - } else { - return GS_ERROR_DATA; - } - - /* Apply operation */ - if (op == MASK_OR) { - old |= mask; - } else if (op == MASK_AND) { - old &= ~mask; - } else if (op == MASK_SET) { - old = mask; - } - - token = strtok_r(NULL, ",", &saveptr); - } - - if (return_mask) { - *return_mask = old; - } - - return GS_OK; -} - -/** - All functions must call this initialization function, to ensure log is initialized. -*/ -static gs_error_t gs_log_init_internal(void) -{ - if (g_log_groups.data.group == NULL) { - return gs_log_init(true); - } - return GS_OK; -} - -gs_error_t gs_log_group_iterate(const char * group_name, void * ctx, gs_log_group_iterator_t iter) -{ - const bool all = (gs_string_empty(group_name) || gs_log_is_group_all(group_name)); - bool found = false; - - for (gs_log_list_t *node = &g_log_groups; node; node = node->next) { - if (node->data.group) { - if (all || gs_string_match(group_name, node->data.group->name)) { - found = true; - bool cont = iter(ctx, node->data.group); - if (cont == false) { - return GS_OK; - } - } - } - } - - return found ? GS_OK : GS_ERROR_NOT_FOUND; -} - -static gs_error_t gs_log_group_register_internal(gs_log_group_t *group) -{ - // check if appender is already in the list and find last node - gs_log_list_t * parent = &g_log_groups; // there will always be at least 1 group -> default - for (; parent; parent = parent->next) { - if ((parent->data.group == group) || (strcasecmp(group->name, parent->data.group->name) == 0)) { - return GS_ERROR_EXIST; - } - if (parent->next == NULL) { - break; - } - } - - gs_log_list_t * new_group_node = calloc(1, sizeof(*new_group_node)); - if (new_group_node == NULL) { - return GS_ERROR_ALLOC; - } - - new_group_node->data.group = group; - - // add to list - must be done last, iterating list can be done without locking - parent->next = new_group_node; - - return GS_OK; -} - -gs_error_t gs_log_group_register(gs_log_group_t *group) -{ - GS_CHECK_ARG(group != NULL); - GS_CHECK_ARG(gs_string_empty(group->name) == false); - - gs_log_init_internal(); - - gs_lock_lock(); - gs_error_t error = gs_log_group_register_internal(group); - gs_lock_unlock(); - - return error; -} - - -bool gs_log_group_is_level_enabled(gs_log_group_t *group, gs_log_level_t level) -{ - return ((group->mask & level) > 0); -} - -gs_error_t gs_log_appender_iterate(const char * name, void * ctx, gs_log_appender_iterator_t iter) -{ - const bool all = (gs_string_empty(name) || gs_log_is_group_all(name)); - bool found = false; - - /* Iterate the dynamically registered log appenders: */ - for (gs_log_list_t *node = &g_log_appenders; node; node = node->next) { - if (node->data.appender) { - if (all || gs_string_match(name, node->data.appender->name)) { - found = true; - bool cont = iter(ctx, node->data.appender); - if (cont == false) { - return GS_OK; - } - } - } - } - - return found ? GS_OK : GS_ERROR_NOT_FOUND; -} - -struct gs_log_history_ctx { - gs_log_record_iterator_t iter; - void *ctx; -}; - -static bool gs_log_history_iterator(void* ctx, gs_log_appender_t *appender) -{ - struct gs_log_history_ctx *hist_ctx = ctx; - if (appender->drv->hist) { - appender->drv->hist(appender, hist_ctx->ctx, hist_ctx->iter); - } - return true; -} - -gs_error_t gs_log_appender_history_iterate(const char * name, void * ctx, gs_log_record_iterator_t iter) -{ - struct gs_log_history_ctx hist_ctx = {.iter=iter, .ctx = ctx}; - - return gs_log_appender_iterate(name, &hist_ctx, gs_log_history_iterator); -} - -static gs_error_t gs_log_appender_register_internal(gs_log_appender_t *appender) -{ - if (g_log_appenders.data.appender == NULL) { - // first appender - g_log_appenders.data.appender = appender; - - if (appender->drv->init) { - gs_error_t error = appender->drv->init(appender); - if (error) { - g_log_appenders.data.appender = NULL; - return error; - } - } - - return GS_OK; - } - - // check if appender is already in the list and find last node - gs_log_list_t * parent = &g_log_appenders; - for (; parent; parent = parent->next) { - if ((parent->data.appender == appender) || (strcasecmp(parent->data.appender->name, appender->name) == 0)) { - return GS_ERROR_EXIST; - } - if (parent->next == NULL) { - break; - } - } - - gs_log_list_t *new_appender = calloc(1, sizeof(*new_appender)); - if (new_appender == NULL) { - return GS_ERROR_ALLOC; - } - - new_appender->data.appender = appender; - - if (appender->drv->init) { - gs_error_t error = appender->drv->init(appender); - if (error) { - free(new_appender); - return error; - } - } - - // add to list - must be done last, iterating list can be done without locking - parent->next = new_appender; - - return GS_OK; -} - -gs_error_t gs_log_appender_register(gs_log_appender_t *appender) -{ - GS_CHECK_ARG(appender != NULL); - GS_CHECK_ARG(gs_string_empty(appender->name) == false); - GS_CHECK_ARG(appender->drv != NULL); - GS_CHECK_ARG(appender->drv->append != NULL); - - gs_log_init_internal(); - - gs_lock_lock(); - gs_error_t error = gs_log_appender_register_internal(appender); - gs_lock_unlock(); - - return error; -} - -gs_error_t gs_log_appender_add(gs_log_appender_t *appender, uint16_t count) -{ - GS_CHECK_ARG(appender != NULL); - GS_CHECK_ARG(count != 0); - - gs_error_t error = GS_OK; - for (uint16_t i = 0; i < count; i++) { - gs_error_t tmp_error = gs_log_appender_register(&appender[i]); - if ((error == GS_OK) && tmp_error) { - error = tmp_error; - } - } - - return error; -} - -static bool iter_set_appender_level_mask(void * ctx_in, gs_log_appender_t * appender) -{ - uint8_t * level_mask = ctx_in; - appender->mask = *level_mask; - return true; -} - -gs_error_t gs_log_appender_set_level_mask(const char * appender_name, uint8_t mask) -{ - if (gs_string_empty(appender_name)) { - return GS_ERROR_HANDLE; - } - - return gs_log_appender_iterate(appender_name, &mask, iter_set_appender_level_mask); -} - -static bool iter_get_appender_level_mask(void * ctx_in, gs_log_appender_t * appender) -{ - uint8_t * level_mask = ctx_in; - *level_mask = appender->mask; - return true; -} - -gs_error_t gs_log_appender_get_level_mask(const char * appender_name, uint8_t *mask) -{ - if (gs_string_empty(appender_name)) { - return GS_ERROR_HANDLE; - } - - return gs_log_appender_iterate(appender_name, mask, iter_get_appender_level_mask); -} - -// Appender register/de-register iterator context -typedef struct { - gs_log_appender_t *appender; - gs_error_t ret; -} iter_group_appender_t; - -static bool iter_log_appender_add(void *ctx, gs_log_group_t *group) -{ - iter_group_appender_t* in = ctx; - - gs_log_list_t * last_elem = group->appenders; - for (gs_log_list_t *elem = group->appenders; elem; elem = elem->next) { - last_elem = elem; - if (elem->data.appender == in->appender) { - in->ret = GS_ERROR_EXIST; - return true; - } - } - - in->ret = GS_ERROR_ALLOC; - gs_log_list_t *new_appender = calloc(1, sizeof(*new_appender)); - if (new_appender) { - new_appender->data.appender = in->appender; - new_appender->next = 0; - if (last_elem != NULL) { - last_elem->next = new_appender; - } else { - group->appenders = new_appender; - } - in->ret = GS_OK; - } - - return true; -} - -gs_error_t gs_log_group_register_appender(const char * group_name, const char * appender_name) -{ - gs_log_appender_t *appender = NULL; - for (gs_log_list_t *elem = &g_log_appenders; elem; elem = elem->next) { - if (elem->data.appender) { - if (strcasecmp(elem->data.appender->name, appender_name) == 0) { - appender = elem->data.appender; - break; - } - } - } - if (NULL == appender) { - return GS_ERROR_NOT_FOUND; - } - - iter_group_appender_t ctx = {.appender = appender, .ret = GS_OK}; - - gs_error_t ret = GS_OK; - if (strcasecmp(group_name, GS_LOG_GROUP_ROOT) == 0) { - iter_log_appender_add(&ctx, &g_log_group_root); - } else { - ret = gs_log_group_iterate(group_name, &ctx, iter_log_appender_add); - } - - if (ret == GS_OK) { - ret = ctx.ret; - } - - return ret; -} - -static bool iter_log_appender_remove(void *ctx, gs_log_group_t *group) -{ - iter_group_appender_t* in = ctx; - in->ret = GS_ERROR_NOT_FOUND; - - gs_log_list_t * last_elem = group->appenders; - for (gs_log_list_t *elem = group->appenders; elem; elem = elem->next) { - if (elem->data.appender == in->appender) { - if (elem == group->appenders) { - group->appenders = elem->next; - } - last_elem->next = elem->next; - free(elem); - in->ret = GS_OK; - break; - } - last_elem = elem; - } - - return true; -} - -gs_error_t gs_log_group_deregister_appender(const char * group_name, const char * appender_name) -{ - gs_log_appender_t *appender = NULL; - for (gs_log_list_t *elem = &g_log_appenders; elem; elem = elem->next) { - if (elem->data.appender) { - if (strcasecmp(elem->data.appender->name, appender_name) == 0) { - appender = elem->data.appender; - break; - } - } - } - if (NULL == appender) { - return GS_ERROR_NOT_FOUND; - } - - iter_group_appender_t ctx = {.appender = appender, .ret = GS_OK}; - - gs_error_t ret; - if (strcasecmp(group_name, GS_LOG_GROUP_ROOT) == 0) { - ret = iter_log_appender_remove(&ctx, &g_log_group_root); - } else { - ret = gs_log_group_iterate(group_name, &ctx, iter_log_appender_remove); - } - - if (ret == GS_OK) { - ret = ctx.ret; - } - - return ret; -} - -gs_error_t gs_log_group_appender_iterate(gs_log_group_t * group, void * ctx, gs_log_appender_iterator_t iter) -{ - GS_CHECK_ARG(group != NULL); - - bool found = false; - for (gs_log_list_t *elem = group->appenders; elem; elem = elem->next) { - found = true; - iter(ctx, elem->data.appender); - } - - /* Iterate root appenders */ - for (gs_log_list_t *elem = g_log_group_root.appenders; elem; elem = elem->next) { - found = true; - iter(ctx, elem->data.appender); - } - - return found ? GS_OK : GS_ERROR_NOT_FOUND; -} - -static inline void gs_log_process_appenders(const gs_log_list_t * it, gs_log_level_t level, - const gs_log_group_t * group, gs_timestamp_t* ts, bool from_isr, const char * format, va_list va) -{ - for (; it; it = it->next) { - gs_log_appender_t* appender = it->data.appender; - - if ((appender->mask & (1 << level)) == 0) { - continue; - } - - if (from_isr == false) { - // log from none ISR context - appender->drv->append(appender, level, group, ts, format, va); - - } else if (appender->drv->append_isr) { - // log from ISR (Interrupt Service Routine) context - appender->drv->append_isr(appender, level, group, ts, format, va); - } - } -} - -static inline void gs_log_common_va(gs_log_level_t level, gs_log_group_t * group, bool from_isr, const char * format, va_list va) -{ - // get time as soon as possible - gs_timestamp_t ts; - gs_clock_get_time(&ts); - - // only needed if someone call function directly - otherwise the log macro has set it to a valid group - if (group == NULL) { - group = LOG_DEFAULT; - } - - // check level mask for current group (this will nearly always be true, because the log macro has done the checking - if (group->mask & (1 << level)) { - - // legacy - if log hasn't been initialized, this will initialize with console output enabled. - gs_log_init_internal(); - - if (group->appenders) { - gs_log_process_appenders(group->appenders, level, group, &ts, from_isr, format, va); - } - - if (group->additivity) { - /* Call root appenders */ - gs_log_process_appenders(g_log_group_root.appenders, level, group, &ts, from_isr, format, va); - } - } -} - -void gs_log(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) -{ - va_list va_args; - va_start(va_args, format); - gs_log_common_va(level, group, false, format, va_args); - va_end(va_args); -} - -void gs_log_isr(gs_log_level_t level, gs_log_group_t * group, const char * format, ...) -{ - va_list va_args; - va_start(va_args, format); - gs_log_common_va(level, group, true, format, va_args); - va_end(va_args); -} - -void gs_log_va(gs_log_level_t level, gs_log_group_t * group, const char * format, va_list args) -{ - gs_log_common_va(level, group, false, format, args); -} - -void gs_log_set_print_color(bool color) -{ - g_print_no_color = (color == false); -} - -const char * gs_log_level_to_color_begin(gs_log_level_t level) -{ - if (g_print_no_color) { - return ""; - } - - switch (level) { - case LOG_ERROR: return "\E[1;31m"; // Red - case LOG_WARNING: return "\E[0;33m"; // Yellow - case LOG_NOTICE: - case LOG_INFO: return "\E[0;32m"; // Green - case LOG_DEBUG: return "\E[0;34m"; // Blue - default: - case LOG_TRACE: return "\E[0;35m"; // Magenta - } -} - -const char * gs_log_level_to_color_end(void) -{ - if (g_print_no_color) { - return ""; - } - - return "\E[0m"; -} - -uint8_t gs_log_level_to_mask(gs_log_level_t level) -{ - /* Enable all levels with priority above the set level */ - uint8_t level_mask = (0xFF << level) & LOG_ALL_MASK; - return level_mask; -} - -static bool iter_flush_appender(void * ctx_in, gs_log_appender_t * appender) -{ - if (appender->drv->flush) { - appender->drv->flush(appender); - } - return true; -} - -gs_error_t gs_log_appender_flush_all() -{ - return gs_log_appender_iterate("", NULL, iter_flush_appender); -} - -gs_error_t gs_log_init(bool with_console_appender) -{ - gs_error_t error = GS_OK; - - gs_lock_init(); // ignore result, this is the log system - - if (g_log_groups.data.group == NULL) { - - // default log group -> mark log as initialized - g_log_groups.data.group = LOG_DEFAULT; - - // register console log appender - if (with_console_appender) { - error = gs_log_appender_register(&gs_log_appender_console); - if (error == GS_OK) { - error = gs_log_group_register_appender(GS_LOG_GROUP_ROOT, gs_log_appender_console.name); - } - } - } - - return error; -} diff --git a/gomspace/libutil/src/rtc.c b/gomspace/libutil/src/rtc.c deleted file mode 100644 index 160df778..00000000 --- a/gomspace/libutil/src/rtc.c +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include - -static const gs_rtc_driver_t * rtc_driver; -static void * rtc_driver_data; - -gs_error_t gs_rtc_register(const gs_rtc_driver_t * driver, void * driver_data) -{ - rtc_driver = driver; - rtc_driver_data = driver_data; - return GS_OK; -} - -gs_error_t gs_rtc_supported(void) -{ - return rtc_driver ? GS_OK : GS_ERROR_NOT_SUPPORTED; -} - -gs_error_t gs_rtc_get_time(gs_timestamp_t * time) -{ - if (time == NULL) { - return GS_ERROR_ARG; - } - - if (rtc_driver && rtc_driver->get_time) { - return rtc_driver->get_time(rtc_driver_data, time); - } - return GS_ERROR_NOT_SUPPORTED; -} - -gs_error_t gs_rtc_set_time(const gs_timestamp_t * time) -{ - if (time == NULL) { - return GS_ERROR_ARG; - } - - if (rtc_driver && rtc_driver->set_time) { - return rtc_driver->set_time(rtc_driver_data, time); - } - return GS_ERROR_NOT_SUPPORTED; -} diff --git a/gomspace/libutil/src/stdio.c b/gomspace/libutil/src/stdio.c deleted file mode 100644 index c723f8fe..00000000 --- a/gomspace/libutil/src/stdio.c +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include - -gs_error_t gs_stdio_get(char * buf, size_t len) -{ - while (len > 0) { - int ch; - gs_error_t error = gs_stdio_getchar(&ch); - if (error) { - return error; - } - *buf++ = ch; - --len; - } - - return GS_OK; -} - -gs_error_t gs_stdio_put(const char * buf, size_t len, bool text) -{ - while (len > 0) { - if ((*buf == '\n') && text) { - gs_stdio_putchar('\r'); - } - gs_stdio_putchar(*buf++); - --len; - } - - return GS_OK; -} - -void gs_color_printf(gs_color_printf_t color_arg, const char * format, ...) -{ - va_list args; - va_start(args, format); - - if ((color_arg & GS_COLOR_ATTRS) == GS_COLOR_BOLD) { - printf("\033[1;"); - } else { - printf("\033[0;"); - } - - switch(color_arg & GS_COLOR_COLORS) { - case GS_COLOR_NONE: - printf("0m"); - break; - case GS_COLOR_BLACK: - printf("30m"); - break; - case GS_COLOR_RED: - printf("31m"); - break; - case GS_COLOR_GREEN: - printf("32m"); - break; - case GS_COLOR_YELLOW: - printf("33m"); - break; - case GS_COLOR_BLUE: - printf("34m"); - break; - case GS_COLOR_MAGENTA: - printf("35m"); - break; - case GS_COLOR_CYAN: - printf("36m"); - break; - case GS_COLOR_WHITE: - printf("37m"); - break; - default: - break; - } - - vprintf(format, args); - printf("\033[0m"); - - va_end(args); -} diff --git a/gomspace/libutil/src/string.c b/gomspace/libutil/src/string.c deleted file mode 100644 index 31419fd0..00000000 --- a/gomspace/libutil/src/string.c +++ /dev/null @@ -1,746 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include -#include -#if (__AVR__ == 0) -#include -#endif - -#ifndef GS_STRING_GET_SUBOPTION_UNIT_TEST -#define GS_STRING_GET_SUBOPTION_UNIT_TEST 0 -#endif - -const char * gs_string_skip_leading_spaces(const char * string) -{ - if (string) { - for (; *string == ' '; ++string); - } - return string; -} - -gs_error_t gs_string_to_int32(const char * string, int32_t * return_value) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (!(isdigit((int)string[0]) || (string[0] == '-'))) { - return GS_ERROR_DATA; - } - - int32_t tmp; - uint8_t base = 10; - - // check for hexadecimal notation - if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) - { - base = 16; - } - - const char *desired_end = string + strlen(string); - // The desired end should point to that last non-space char in the string - while ((isspace((int)desired_end[0]) || (desired_end[0] == '\0')) && (desired_end > string)) - { - desired_end--; - } - char *end; - gs_error_t err = GS_OK; - tmp = gs_string_strto32int(string, &end, base, &err); - if (err != GS_OK) - { - return err; - } - if (desired_end != end-1) - { - return GS_ERROR_DATA; - } - - if (return_value) - { - *return_value = tmp; - } - - return GS_OK; -} - -gs_error_t gs_string_to_int8(const char * string, int8_t * return_value) -{ - int32_t value; - gs_error_t error = gs_string_to_int32(string, &value); - if (error == GS_OK) { - if ((value >= INT8_MIN) && (value <= INT8_MAX)) { - if (return_value) { - *return_value = (int8_t) value; - } - } else { - error = GS_ERROR_OVERFLOW; - } - } - return error; -} - -gs_error_t gs_string_to_uint8(const char * string, uint8_t * return_value) -{ - uint32_t value; - gs_error_t error = gs_string_to_uint32(string, &value); - if (error == GS_OK) { - if (value <= UINT8_MAX) { - if (return_value) { - *return_value = (uint8_t) value; - } - } else { - error = GS_ERROR_OVERFLOW; - } - } - return error; -} - -gs_error_t gs_string_to_int16(const char * string, int16_t * return_value) -{ - int32_t value; - gs_error_t error = gs_string_to_int32(string, &value); - if (error == GS_OK) { - if ((value >= INT16_MIN) && (value <= INT16_MAX)) { - if (return_value) { - *return_value = (int16_t) value; - } - } else { - error = GS_ERROR_OVERFLOW; - } - } - return error; -} - -gs_error_t gs_string_to_uint16(const char * string, uint16_t * return_value) -{ - uint32_t value; - gs_error_t error = gs_string_to_uint32(string, &value); - if (error == GS_OK) { - if (value <= UINT16_MAX) { - if (return_value) { - *return_value = (uint16_t) value; - } - } else { - error = GS_ERROR_OVERFLOW; - } - } - return error; -} - -gs_error_t gs_string_to_uint32(const char * string, uint32_t * return_value) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (!isdigit((int)string[0])) { - return GS_ERROR_DATA; - } - - uint32_t tmp; - uint8_t base = 10; - - // check for hexadecimal notation - if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) - { - base = 16; - } - const char *desired_end = string + strlen(string); - // The desired end should point to that last non-space char in the string - while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) - { - desired_end--; - } - char *end; - gs_error_t err = GS_OK; - tmp = gs_string_strto32uint(string, &end, base, &err); - - if (err != GS_OK) - { - return err; - } - if (desired_end != end-1) - { - return GS_ERROR_DATA; - } - - - if (return_value) { - *return_value = tmp; - } - - return GS_OK; -} - -gs_error_t gs_string_to_uint64(const char * string, uint64_t * return_value) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (!isdigit((int)string[0])) - { - return GS_ERROR_DATA; - } - - uint64_t tmp; - uint8_t base = 10; - - // check for hexadecimal notation - if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) { - base = 16; - } - const char *desired_end = string + strlen(string); - // The desired end should point to that last non-space char in the string - while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) - { - desired_end--; - } - char *end; - gs_error_t err = GS_OK; - tmp = gs_string_strto64uint(string, &end, base, &err); - if (err != GS_OK) - { - return err; - } - - if (desired_end != end-1) - { - return GS_ERROR_DATA; - } - - - if (return_value) { - *return_value = tmp; - } - - return GS_OK; -} - -gs_error_t gs_string_to_int64(const char * string, int64_t * return_value) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (!(isdigit((int)string[0]) || (string[0] == '-'))) - { - return GS_ERROR_DATA; - } - - int64_t tmp; - uint8_t base = 10; - - // check for hexadecimal notation - if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) { - base = 16; - } - const char *desired_end = string + strlen(string); - // The desired end should point to that last non-space char in the string - while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) - { - desired_end--; - } - char *end; - gs_error_t err = GS_OK; - tmp = gs_string_strto64int(string, &end, base, &err); - if (err != GS_OK) - { - return err; - } - - if (desired_end != end-1) - { - return GS_ERROR_DATA; - } - - - if (return_value) { - *return_value = tmp; - } - - return GS_OK; -} - -gs_error_t gs_string_hex_to_uint32(const char * string, uint32_t * return_value) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (!isxdigit((int)string[0])) { - return GS_ERROR_DATA; - } - - const char *desired_end = string + strlen(string); - // The desired end should point to that last non-space char in the string - while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) - { - desired_end--; - } - char *end; - gs_error_t err = GS_OK; - uint32_t tmp = gs_string_strto32uint(string, &end, 16, &err); - - if (err != GS_OK) - { - return err; - } - if (desired_end != end-1) - { - return GS_ERROR_DATA; - } - - if (return_value) { - *return_value = tmp; - } - - return GS_OK; -} - -gs_error_t gs_string_hex_to_uint64(const char * string, uint64_t * return_value) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (!isxdigit((int)string[0])) - { - return GS_ERROR_DATA; - } - - const char *desired_end = string + strlen(string); - // The desired end should point to that last non-space char in the string - while ((isspace((int)desired_end[0]) || desired_end[0] == 0) && (desired_end > string)) - { - desired_end--; - } - char *end; - gs_error_t err = GS_OK; - uint64_t tmp = gs_string_strto64uint(string, &end, 16, &err); - if (err != GS_OK) - { - return err; - } - - if (desired_end != end-1) - { - return GS_ERROR_DATA; - } - - if (return_value) { - *return_value = tmp; - } - - return GS_OK; -} - -#if (__AVR__ == 0) -gs_error_t gs_string_to_float(const char * string, float * pvalue) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (gs_string_empty(string)) { - return GS_ERROR_DATA; - } - - // float strtof(const char *nptr, char **endptr); - char * endp = NULL; - float tmp = strtof(string, &endp); - //if ((endp == NULL) || (gs_string_empty(gs_string_skip_leading_spaces(endp)) == false) || (string == endp)) { - if ((endp == NULL) || (gs_string_empty(gs_string_skip_leading_spaces(endp)) == false) || (string == endp) || isinf(tmp)) { - return GS_ERROR_DATA; - } - - if (pvalue) { - *pvalue = tmp; - } - - return GS_OK; -} - -gs_error_t gs_string_to_double(const char * string, double * pvalue) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - - if (gs_string_empty(string)) { - return GS_ERROR_DATA; - } - - // double strtod(const char *nptr, char **endptr); - char * endp = NULL; - double tmp = strtod(string, &endp); - if ((endp == NULL) || (gs_string_empty(gs_string_skip_leading_spaces(endp)) == false) || isinf(tmp)) { - return GS_ERROR_DATA; - } - - if (pvalue) { - *pvalue = tmp; - } - - return GS_OK; -} -#endif - -#define GS_STRING_BOOL_TRUE "true" -#define GS_STRING_BOOL_FALSE "false" - -const char * gs_string_from_bool(bool value) -{ - if (value) { - return GS_STRING_BOOL_TRUE; - } else { - return GS_STRING_BOOL_FALSE; - } -} - -gs_error_t gs_string_to_bool(const char * string, bool * return_value) -{ - string = gs_string_skip_leading_spaces(string); - if (string == NULL) { - return GS_ERROR_ARG; - } - if (string[0] == 0) { - return GS_ERROR_DATA; - } - - bool value = false; - if (strcasecmp(string, GS_STRING_BOOL_TRUE) == 0) { - value = true; - } else if (strcasecmp(string, GS_STRING_BOOL_FALSE) == 0) { - value = false; - } else if (strcasecmp(string, "on") == 0) { - value = true; - } else if (strcasecmp(string, "off") == 0) { - value = false; - } else if (strcasecmp(string, "1") == 0) { - value = true; - } else if (strcasecmp(string, "0") == 0) { - value = false; - } else if (strcasecmp(string, "yes") == 0) { - value = true; - } else if (strcasecmp(string, "no") == 0) { - value = false; - } else { - return GS_ERROR_DATA; - } - - if (return_value) { - *return_value = value; - } - - return GS_OK; -} - -char * gs_string_bytesize(long n, char *buf, size_t buf_size) -{ - char postfix = 'B'; - double size = (double) n; - if (n >= 1048576) { - size /= 1048576.0; - postfix = 'M'; - } else if (n >= 1024) { - size /= 1024.0; - postfix = 'K'; - } - snprintf(buf, buf_size, "%.1f%c", size, postfix); - return buf; -} - -gs_error_t gs_string_to_pointer(const char * string, void ** value) -{ -#if __LP64__ - uint64_t tmp; - gs_error_t error = gs_string_to_uint64(string, &tmp); - if ((error == GS_OK) && value) { - *value = GS_TYPES_UINT2PTR(tmp); - } - return error; -#else - uint32_t tmp; - gs_error_t error = gs_string_to_uint32(string, &tmp); - if ((error == GS_OK) && value) { - *value = GS_TYPES_UINT2PTR(tmp); - } - return error; -#endif -} - -bool gs_string_empty(const char * string) -{ - if ((string == NULL) || (string[0] == 0)) { - return true; - } - return false; -} - -bool gs_string_match(const char * pattern, const char * string) -{ - if (string && pattern) { - while (*string || *pattern) { - int p = tolower((int)*pattern); - int s = tolower((int)*string); - - if (*pattern == '*') { - ++pattern; - p = tolower((int)*pattern); - for (; *string && (tolower((int)*string) != p); ++string); - s = tolower((int)*string); - } - - if (s != p) { - return false; - } - - if (s) { - ++string; - } - if (p) { - ++pattern; - } - } - if ((*string == 0) && (*pattern == 0)) { - return true; - } - } - return false; -} - -bool gs_string_has_wildcards(const char * string) -{ - if (strchr(string, '*')) { - return true; - } - // future wildcard - //if (strchr(str, '?')) { - // return true; - //} - return false; -} - -void gs_string_trim(char * buffer, size_t buffer_size) -{ - // remove trailing stuff - int len = strnlen(buffer, buffer_size); - if (len) { - for (int i = (len - 1); i >= 0; --i) { - if (isspace((int)buffer[i])) { - buffer[i] = 0; - } else { - break; - } - } - } - - char * start; - for (start = buffer; *start && isspace((int)*start); ++start); - if (*start && (start != buffer)) { - // move chars up - for (; *start; ++start) { - *buffer++ = *start; - } - *buffer = 0; - } -} - -bool gs_string_endswith(const char * string, const char * endswith) -{ - if (string == NULL || endswith == NULL) { - return false; - } - - int str_len = strlen(string); - int endswith_len = strlen(endswith); - - return (str_len >= endswith_len) && - (0 == strcmp(string + (str_len-endswith_len), endswith)); -} - -static size_t suboption_len(const char * ref, const char * end) -{ - if (ref) { - size_t len = (end) ? ((size_t)(end - ref)) : strlen(ref); - for (; len && (ref[len - 1] == ' '); --len); - return len; - } - return 0; -} - -static gs_error_t suboption_copy(const char * data, size_t len, char * buf, size_t buf_size, gs_error_t error) -{ - if (len >= buf_size) { - error = GS_ERROR_OVERFLOW; - len = (buf_size - 1); - } - - if (data == NULL) { - len = 0; - } else { - strncpy(buf, data, len); - } - - buf[len] = 0; - - return error; -} - -gs_error_t gs_string_get_suboption(const char * options, const char * suboption, char * buf, size_t buf_size) -{ - GS_CHECK_ARG(options != NULL); - GS_CHECK_ARG((buf != NULL) && (buf_size > 0)); - - const char * next = options; - for (;next;) { - const char * key = next; - if (*key == ',') { - key = NULL; // no key-value - } - next = strchr(next, ','); - - const char * value = NULL; - if (key) { - for (; *key == ' '; ++key); - - value = strchr(key, '='); - if (value == NULL) { - // no value - } else if (next && (value >= next)) { - // no value - value = NULL; - } - } - - const unsigned int key_len = suboption_len(key, value ? value : next); - - if (value) { - if (*value == '=') { - ++value; - } - for (; *value == ' '; ++value); - } - - const unsigned int value_len = suboption_len(value, next); - - if (GS_STRING_GET_SUBOPTION_UNIT_TEST) { // -> #define - printf(" key=[%.*s], len=%u, value=[%.*s], len=%u, next=[%s]\n", - key_len, key ? key : "", key_len, - value_len, value ? value : "", value_len, - next ? next : ""); - } - - // if suboption is empty, it means get value of first element - ignoring any key - if (gs_string_empty(suboption)) { - if (value) { - return suboption_copy(value, value_len, buf, buf_size, GS_OK); - } - if (key) { - return suboption_copy(key, key_len, buf, buf_size, GS_OK); - } - return suboption_copy(NULL, 0, buf, buf_size, GS_OK); // empty - } - - if ((key_len == strlen(suboption)) && (strncasecmp(key, suboption, key_len) == 0)) { - return suboption_copy(value, value_len, buf, buf_size, GS_OK); - } - - if (next) { - ++next; - if (next[0] == 0) { - next = NULL; - } - } - } - - // not found - return default - return suboption_copy(NULL, 0, buf, buf_size, GS_ERROR_NOT_FOUND); -} - -static const char * _suboption_name(const char * suboption) -{ - if (gs_string_empty(suboption)) { - return "first suboption"; - } - return suboption; -} - -#define _get_suboption(_type) \ - char buf[20]; \ - gs_error_t error = gs_string_get_suboption(options, suboption, buf, sizeof(buf)); \ - if (error == GS_OK) { \ - error = gs_string_to_##_type(buf, value); \ - } \ - if (error) { \ - if (error == GS_ERROR_NOT_FOUND) { \ - error = GS_OK; \ - } else { \ - log_error("Failed to extract suboption [%s] from [%s], error: %d", _suboption_name(suboption), options, error); \ - } \ - *value = def; \ - } \ - return error; \ - -gs_error_t gs_string_get_suboption_uint8(const char * options, const char * suboption, uint8_t def, uint8_t * value) -{ - _get_suboption(uint8) -} - -gs_error_t gs_string_get_suboption_uint16(const char * options, const char * suboption, uint16_t def, uint16_t * value) -{ - _get_suboption(uint16) -} - -gs_error_t gs_string_get_suboption_uint32(const char * options, const char * suboption, uint32_t def, uint32_t * value) -{ - _get_suboption(uint32) -} - -gs_error_t gs_string_get_suboption_string(const char * options, const char * suboption, const char * def, char * buf, size_t buf_size) -{ - gs_error_t error = gs_string_get_suboption(options, suboption, buf, buf_size); - if (error) { - if (error == GS_ERROR_NOT_FOUND) { - error = GS_OK; - } - error = suboption_copy(def, def ? strlen(def) : 0, buf, buf_size, error); - } - return error; -} - -gs_error_t gs_string_get_suboption_bool(const char * options, const char * suboption, bool def, bool * value) -{ - char buf[20]; - gs_error_t error = gs_string_get_suboption(options, suboption, buf, sizeof(buf)); - if (error == GS_OK) { - if (gs_string_empty(buf) || (suboption && (strcasecmp(suboption, buf) == 0))) { - // this means 'true', a=21,active,a=22 - *value = true; - } else { - error = gs_string_to_bool(buf, value); - } - } - if (error) { - if (error == GS_ERROR_NOT_FOUND) { - error = GS_OK; - } else { - log_error("Failed to extract suboption [%s] from [%s], error: %d", _suboption_name(suboption), options, error); - } - *value = def; - } - return error; -} diff --git a/gomspace/libutil/src/strtoint.c b/gomspace/libutil/src/strtoint.c deleted file mode 100644 index 152eff39..00000000 --- a/gomspace/libutil/src/strtoint.c +++ /dev/null @@ -1,399 +0,0 @@ -/*- - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * 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. [rescinded 22 July 1999] - * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. - */ - -/* - -@deftypefn Supplemental {long int} strtol (const char *@var{string}, @ - char **@var{endptr}, int @var{base}) -@deftypefnx Supplemental {unsigned long int} strtoul (const char *@var{string}, @ - char **@var{endptr}, int @var{base}) - -The @code{strtol} function converts the string in @var{string} to a -long integer value according to the given @var{base}, which must be -between 2 and 36 inclusive, or be the special value 0. If @var{base} -is 0, @code{strtol} will look for the prefixes @code{0} and @code{0x} -to indicate bases 8 and 16, respectively, else default to base 10. -When the base is 16 (either explicitly or implicitly), a prefix of -@code{0x} is allowed. The handling of @var{endptr} is as that of -@code{strtod} above. The @code{strtoul} function is the same, except -that the converted value is unsigned. - -@end deftypefn - -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#ifdef HAVE_LIMITS_H -#include -#endif -#ifdef HAVE_SYS_PARAM_H -#include -#endif -#include -#include -#include - -/* - * Convert a string to a long integer. - * - * Ignores `locale' stuff. Assumes that the upper and lower case - * alphabets and digits are each contiguous. - */ -int32_t gs_string_strto32int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) -{ - register const char *s = nptr; - register uint32_t acc; - register int c; - register uint32_t cutoff; - register int neg = 0, any, cutlim; - - /* - * Skip white space and pick up leading +/- sign if any. - * If base is 0, allow 0x for hex and 0 for octal, else - * assume decimal; if base is already 16, allow 0x. - */ - do - { - c = *s++; - } while (isspace(c)); - if (c == '-') - { - neg = 1; - c = *s++; - } else if (c == '+') - { - c = *s++; - } - if ((base == 0 || base == 16) && - c == '0' && (*s == 'x' || *s == 'X')) - { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - { - base = c == '0' ? 8 : 10; - } - - /* - * Compute the cutoff value between legal numbers and illegal - * numbers. That is the largest legal value, divided by the - * base. An input number that is greater than this value, if - * followed by a legal input character, is too big. One that - * is equal to this value may be valid or not; the limit - * between valid and invalid numbers is then based on the last - * digit. For instance, if the range for longs is - * [-2147483648..2147483647] and the input base is 10, - * cutoff will be set to 214748364 and cutlim to either - * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated - * a value > 214748364, or equal but the next digit is > 7 (or 8), - * the number is too big, and we will return a range error. - * - * Set any if any `digits' consumed; make it negative to indicate - * overflow. - */ - cutoff = neg ? -(uint32_t)INT32_MIN : INT32_MAX; - cutlim = cutoff % (uint32_t)base; - cutoff /= (uint32_t)base; - for (acc = 0, any = 0;; c = *s++) - { - if (isdigit(c)) - { - c -= '0'; - } - else if (isalpha(c)) - { - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - } - else - { - break; - } - if (c >= base) - { - break; - } - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - { - any = -1; - } - else - { - any = 1; - acc *= base; - acc += c; - } - } - if (any < 0) - { - acc = neg ? INT32_MIN : INT32_MAX; - *err = GS_ERROR_OVERFLOW; - } else if (neg) - { - acc = -acc; - } - if (endptr != 0) - { - *endptr = (char *) (any ? s - 1 : nptr); - } - return (acc); -} - - -/* - * Convert a string to an unsigned long integer. - * - * Ignores `locale' stuff. Assumes that the upper and lower case - * alphabets and digits are each contiguous. - */ -uint32_t gs_string_strto32uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) -{ - register const char *s = nptr; - register uint32_t acc; - register int32_t c; - register uint32_t cutoff; - register int32_t neg = 0, any, cutlim; - - /* - * See strtol for comments as to the logic used. - */ - do - { - c = *s++; - } while (isspace(c)); - if (c == '-') - { - neg = 1; - c = *s++; - } else if (c == '+') - { - c = *s++; - } - if ((base == 0 || base == 16) && - c == '0' && (*s == 'x' || *s == 'X')) - { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - { - base = c == '0' ? 8 : 10; - } - cutoff = (uint32_t)UINT32_MAX / (uint32_t)base; - cutlim = (uint32_t)UINT32_MAX % (uint32_t)base; - for (acc = 0, any = 0;; c = *s++) - { - if (isdigit(c)) - { - c -= '0'; - } - else if (isalpha(c)) - { - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - } - else - { - break; - } - if (c >= base) - { - break; - } - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - { - any = -1; - } - else - { - any = 1; - acc *= base; - acc += c; - } - } - if (any < 0) - { - acc = UINT32_MAX; - *err = GS_ERROR_OVERFLOW; - } else if (neg) - { - acc = -acc; - } - if (endptr != 0) - { - *endptr = (char *) (any ? s - 1 : nptr); - } - return (acc); -} - - -int64_t gs_string_strto64int(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) -{ - register const char *s = nptr; - register uint64_t acc; - register int32_t c; - register uint64_t cutoff; - register int32_t neg = 0, any, cutlim; - - /* - * Skip white space and pick up leading +/- sign if any. - * If base is 0, allow 0x for hex and 0 for octal, else - * assume decimal; if base is already 16, allow 0x. - */ - do { - c = *s++; - } while (isspace(c)); - if (c == '-') { - neg = 1; - c = *s++; - } else if (c == '+') - c = *s++; - if ((base == 0 || base == 16) && - c == '0' && (*s == 'x' || *s == 'X')) { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - base = c == '0' ? 8 : 10; - - /* - * Compute the cutoff value between legal numbers and illegal - * numbers. That is the largest legal value, divided by the - * base. An input number that is greater than this value, if - * followed by a legal input character, is too big. One that - * is equal to this value may be valid or not; the limit - * between valid and invalid numbers is then based on the last - * digit. For instance, if the range for longs is - * [-2147483648..2147483647] and the input base is 10, - * cutoff will be set to 214748364 and cutlim to either - * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated - * a value > 214748364, or equal but the next digit is > 7 (or 8), - * the number is too big, and we will return a range error. - * - * Set any if any `digits' consumed; make it negative to indicate - * overflow. - */ - cutoff = neg ? -(uint64_t)INT64_MIN : INT64_MAX; - cutlim = cutoff % (uint64_t)base; - cutoff /= (uint64_t)base; - for (acc = 0, any = 0;; c = *s++) { - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else - break; - if (c >= base) - break; - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else { - any = 1; - acc *= base; - acc += c; - } - } - if (any < 0) { - acc = neg ? INT64_MIN : INT64_MAX; - *err = GS_ERROR_OVERFLOW; - } else if (neg) - acc = -acc; - if (endptr != 0) - *endptr = (char *) (any ? s - 1 : nptr); - return (acc); -} - - -/* - * Convert a string to an unsigned long integer. - * - * Ignores `locale' stuff. Assumes that the upper and lower case - * alphabets and digits are each contiguous. - */ - -uint64_t gs_string_strto64uint(const char *nptr, char **endptr, uint8_t base, gs_error_t * err) -{ - register const char *s = nptr; - register uint64_t acc; - register int32_t c; - register uint64_t cutoff; - register int32_t neg = 0, any, cutlim; - - /* - * See strtol for comments as to the logic used. - */ - do { - c = *s++; - } while (isspace(c)); - if (c == '-') { - neg = 1; - c = *s++; - } else if (c == '+') - c = *s++; - if ((base == 0 || base == 16) && - c == '0' && (*s == 'x' || *s == 'X')) { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - base = c == '0' ? 8 : 10; - cutoff = (uint64_t)UINT64_MAX / (uint64_t)base; - cutlim = (uint64_t)UINT64_MAX % (uint64_t)base; - for (acc = 0, any = 0;; c = *s++) { - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else - break; - if (c >= base) - break; - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else { - any = 1; - acc *= base; - acc += c; - } - } - if (any < 0) { - acc = UINT64_MAX; - *err = GS_ERROR_OVERFLOW; - } else if (neg) - acc = -acc; - if (endptr != 0) - *endptr = (char *) (any ? s - 1 : nptr); - return (acc); -} diff --git a/gomspace/libutil/src/test/cmocka.c b/gomspace/libutil/src/test/cmocka.c deleted file mode 100644 index c3c5d171..00000000 --- a/gomspace/libutil/src/test/cmocka.c +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -void cm_print_error(const char * const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); - -#define EQUAL_TO_STRING(equal) (equal ? "!=" : "==") - -void _gs_assert_int_equal(const intptr_t left, const intptr_t right, bool equal, const char * const file, const int line) -{ - const bool cmp_equal = left == right; - if (cmp_equal != equal) { - cm_print_error("%ld %s %ld\n", left, EQUAL_TO_STRING(equal), right); - - _fail(file, line); - } -} - -void _gs_assert_uint_equal(const uintptr_t left, const uintptr_t right, bool equal, bool hex, const char * const file, const int line) -{ - const bool cmp_equal = left == right; - if (cmp_equal != equal) { - if(hex) { - cm_print_error("0x%lx %s 0x%lx\n", left, EQUAL_TO_STRING(equal), right); - } else { - cm_print_error("%lu %s %lu\n", left, EQUAL_TO_STRING(equal), right); - } - - _fail(file, line); - } -} - -void _gs_assert_error_equal(const int left, const int right, bool equal, const char * const file, const int line) -{ - const bool cmp_equal = left == right; - if (cmp_equal != equal) { - cm_print_error("%d(%s) %s %d(%s)\n", left, gs_error_string(left), EQUAL_TO_STRING(equal), right, gs_error_string(right)); - - _fail(file, line); - } -} - -void _gs_assert_float_equal(const float left, const float right, const float diff, bool equal, const char * const file, const int line) -{ - const bool cmp_equal = (fabsf(left - right) < diff); - if (cmp_equal != equal) { - cm_print_error("%e %s %e\n", left, EQUAL_TO_STRING(equal), right); - - _fail(file, line); - } -} - -void _gs_assert_double_equal(const double left, const double right, const double diff, bool equal, const char * const file, const int line) -{ - const bool cmp_equal = (fabsf(left - right) < diff); - if (cmp_equal != equal) { - cm_print_error("%e %s %e\n", left, EQUAL_TO_STRING(equal), right); - - _fail(file, line); - } -} diff --git a/gomspace/libutil/src/test/command.c b/gomspace/libutil/src/test/command.c deleted file mode 100644 index e9678523..00000000 --- a/gomspace/libutil/src/test/command.c +++ /dev/null @@ -1,176 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include -#include - -void cm_print_error(const char * const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); - -struct results { - char group[32]; - char key[32]; - char value[128]; -}; - -static FILE* g_output_file = 0; -static char g_stdout_buf[10000]; -static char g_stdin_buf[1000]; -static uint16_t g_stdin_idx; - -static struct results g_results[100]; -static uint32_t g_results_count = 0; - - -static gs_error_t test_set_result(gs_command_context_t *ctx, const char *group, const char *key, const char *value) -{ - if (g_results_count >= GS_ARRAY_SIZE(g_results)) { - return GS_ERROR_ALLOC; - } - - if (group) { - strncpy(g_results[g_results_count].group, group, sizeof(g_results[0].group)); - } - if (key) { - strncpy(g_results[g_results_count].key, key, sizeof(g_results[0].key)); - } - if (value) { - strncpy(g_results[g_results_count].value, value, sizeof(g_results[0].value)); - } - g_results_count++; - return GS_OK; -} - -static gs_error_t test_flush(gs_command_context_t *ctx) -{ - fflush(ctx->out); - return GS_OK; -} - -static gs_error_t test_wait_for_key(gs_command_context_t *ctx, int *ch, int timeout_ms) -{ - if (g_stdin_buf[g_stdin_idx] == 0) { - gs_time_sleep_ms(timeout_ms); - return GS_ERROR_TIMEOUT; - } - - *ch = g_stdin_buf[g_stdin_idx]; - g_stdin_idx++; - return GS_OK; -} - -static gs_command_io_functions_t g_test_io_functions = { - .set_result = test_set_result, - .flush = test_flush, - .wait_for_key = test_wait_for_key, -}; - - -static gs_error_t prepare_validation(const char *input) -{ - g_results_count = 0; - memset(g_stdout_buf, 0, sizeof(g_stdout_buf)); - memset(g_stdin_buf, 0, sizeof(g_stdin_buf)); - g_stdin_idx = 0; - - if (input != NULL) { - memcpy(g_stdin_buf, input, strlen(input)); - } - - g_output_file = fmemopen(g_stdout_buf, sizeof(g_stdout_buf) - 1, "w"); - if (!g_output_file) { - return GS_ERROR_ALLOC; - } - - return GS_OK; -} - -static bool match(const char *first, const char * second) -{ - return (fnmatch(first, second, 0) == 0); -} - -static gs_error_t do_validation(const char *expected) -{ - fclose(g_output_file); - - if (expected == NULL) - return GS_OK; - - if (!match(expected, g_stdout_buf)) - { - return GS_ERROR_DATA; - } - return GS_OK; -} - - -void _gs_assert_command_validate(const char *cmd, gs_error_t ret, gs_error_t cmd_ret, const char *std_in, const char *std_out, - const char * const file, const int line) -{ - if (prepare_validation(std_in) != GS_OK) - { - cm_print_error("Validation function failed to allocate it's resources\n"); - _fail(file, line); - } - - gs_error_t _ret; - gs_error_t _command_ret = GS_OK; - _ret = gs_command_execute(cmd, &_command_ret, g_output_file, &g_test_io_functions, NULL); - - if (_ret != ret) { - cm_print_error("Return: %d(%s) != %d(%s)\n", _ret, gs_error_string(_ret), ret, gs_error_string(ret)); - _fail(file, line); - } - - if (_ret == GS_OK) /* Only check CMD return if command execution succeeded */ - { - if (_command_ret != cmd_ret) { - cm_print_error("Command return: %d(%s) != %d(%s)\n", _command_ret, gs_error_string(_command_ret), - cmd_ret, gs_error_string(cmd_ret)); - _fail(file, line); - } - } - - if (do_validation(std_out) != GS_OK) - { - //cm_print_error("Stdout != : \n%s\n!=\n%s\n", g_stdout_buf, std_out); - printf("Stdout != : \n%s\n!=\n%s\n", g_stdout_buf, std_out); - _fail(file, line); - } - - return; -} - -void _gs_assert_command_validate_last_result(unsigned int no, const char *group, const char *key, const char *value, - const char * const file, const int line) -{ - if (no >= g_results_count) - { - cm_print_error("Result no: %d not available. Only %d results returned from command\n", no, g_results_count); - _fail(file, line); - } - - if (group) { - if (!match(group, g_results[no].group)) { - cm_print_error("group: %s != %s\n", group, g_results[no].group); - _fail(file, line); - } - } - if (key) { - if (!match(key, g_results[no].key)) { - cm_print_error("key: %s != %s\n", key, g_results[no].key); - _fail(file, line); - } - } - if (value) { - if (!match(value, g_results[no].value)) { - cm_print_error("value: %s != %s\n", value, g_results[no].value); - _fail(file, line); - } - } - - return; -} diff --git a/gomspace/libutil/src/test/log.c b/gomspace/libutil/src/test/log.c deleted file mode 100644 index ba7671e1..00000000 --- a/gomspace/libutil/src/test/log.c +++ /dev/null @@ -1,165 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// cmocka -void cm_print_error(const char * const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); - -static gs_mutex_t g_lock; - -#define GS_TEST_LOG_MAX_LEVELS 6 -#define GS_TEST_LOG_MAX_LOG_MESSAGES 200 - -typedef struct { - // Overall count per log level. - unsigned int count[GS_TEST_LOG_MAX_LEVELS]; - // Log messages. - struct { - // Level. - gs_log_level_t level; - // Format log message. - char msg[150]; - } logs[GS_TEST_LOG_MAX_LOG_MESSAGES]; - // Index of next entry in \a logs. - unsigned int next_log; -} gs_test_log_stats_t; - -static gs_test_log_stats_t gs_test_log_stats; - -static void log_callback(gs_log_appender_t *appender, gs_log_level_t level, const gs_log_group_t * group, const gs_timestamp_t * ts, const char * format, va_list va) -{ - gs_mutex_lock(g_lock); - gs_test_log_stats.count[level]++; - - { - gs_bytebuffer_t bb; - gs_bytebuffer_init(&bb, - gs_test_log_stats.logs[gs_test_log_stats.next_log].msg, - sizeof(gs_test_log_stats.logs[gs_test_log_stats.next_log].msg)); - - va_list my_va; - va_copy(my_va, va); - gs_bytebuffer_printf(&bb, "%s: ", group->name); - gs_bytebuffer_vprintf(&bb, format, my_va); - va_end(my_va); - gs_bytebuffer_get_as_string(&bb, NULL); // ensure NUL termination - gs_test_log_stats.logs[gs_test_log_stats.next_log].level = level; - - ++gs_test_log_stats.next_log; - if (gs_test_log_stats.next_log >= GS_TEST_LOG_MAX_LOG_MESSAGES) { - gs_test_log_stats.next_log = 0; - } - gs_test_log_stats.logs[gs_test_log_stats.next_log].msg[0] = 0; // clear next entry - gs_test_log_stats.logs[gs_test_log_stats.next_log].level = GS_TEST_LOG_MAX_LEVELS; - } - - gs_mutex_unlock(g_lock); -} - -static gs_log_appender_driver_t g_log_test_appender_driver = { - .init = 0, - .append = log_callback, - .append_isr = log_callback, -}; - -static gs_log_appender_t g_log_test_appender = { - .name = "test_appender", - .drv = &g_log_test_appender_driver, - .drv_config = NULL, - .drv_data = NULL, - .mask = LOG_ALL_MASK, -}; - -void gs_test_log_init(bool verbose) -{ - gs_log_init(true); - - if (g_lock == NULL) { - GS_ASSERT_ERROR_EQUAL(gs_mutex_create(&g_lock), GS_OK); - - /* Add/Register appender - Only first time that init is called. */ - gs_log_appender_add(&g_log_test_appender, 1); - gs_log_group_register_appender("root", "test_appender"); - } - if (verbose) { - gs_log_appender_set_level_mask("console", LOG_ALL_MASK); - } else { - gs_log_appender_set_level_mask("console", 0); - } - - gs_test_log_clear(); -} - -void gs_test_log_clear(void) -{ - gs_mutex_lock(g_lock); - memset(&gs_test_log_stats, 0, sizeof(gs_test_log_stats)); - gs_mutex_unlock(g_lock); -} - -void gs_assert_log_count(int level, unsigned int count, const char * file, int line) -{ - if (level < 0) { - unsigned int tot = 0; - for (int i = 0; i < GS_TEST_LOG_MAX_LEVELS; ++i) { - tot += gs_test_log_stats.count[i]; - } - if (tot != count) { - cm_print_error("Unexpected total log count: %u != %u\n", tot, count); - _fail(file, line); - } - } else if (level >= GS_TEST_LOG_MAX_LEVELS) { - cm_print_error("Unknown log level: %d - valid levels 0 - %d\n", level, GS_TEST_LOG_MAX_LEVELS - 1); - _fail(file, line); - } else if (gs_test_log_stats.count[level] != count) { - cm_print_error("Unexpected log count: %u != %u\n", gs_test_log_stats.count[level], count); - _fail(file, line); - } -} - -void gs_assert_log(unsigned int stack_index, unsigned int count, gs_log_level_t level, const char * pattern, const char * file, int line) -{ - if (stack_index == UINT32_MAX) { - // loop through all logs - unsigned int next = gs_test_log_stats.next_log; - unsigned int hits = 0; - for (unsigned int i = next - 1; i != next; --i) { - if (i >= GS_TEST_LOG_MAX_LOG_MESSAGES) { - i = (GS_TEST_LOG_MAX_LOG_MESSAGES - 1); - } - if ((gs_test_log_stats.logs[i].level == level) && (gs_test_log_stats.logs[i].msg[0])) { - if (fnmatch(pattern, gs_test_log_stats.logs[i].msg, 0) == 0) { - ++hits; - } - } - } - if (hits != count) { - cm_print_error("Unexpected log count: %u != %u\n", hits, count); - _fail(file, line); - } - } else if (stack_index >= GS_TEST_LOG_MAX_LOG_MESSAGES) { - cm_print_error("Invalid stack_index: %u - valid 0 - %d\n", stack_index, GS_TEST_LOG_MAX_LOG_MESSAGES - 1); - _fail(file, line); - } else { - unsigned int i = (((gs_test_log_stats.next_log + GS_TEST_LOG_MAX_LOG_MESSAGES) - 1 - stack_index) % GS_TEST_LOG_MAX_LOG_MESSAGES); - if ((gs_test_log_stats.logs[i].level == level) && - (gs_test_log_stats.logs[i].msg[0]) && - (fnmatch(pattern, gs_test_log_stats.logs[i].msg, 0) == 0)) { - // match - } else { - cm_print_error("[%c][%s] != [%c][%s]\n", - gs_log_level_to_char(gs_test_log_stats.logs[i].level), gs_test_log_stats.logs[i].msg, - gs_log_level_to_char(level), pattern); - _fail(file, line); - } - } -} diff --git a/gomspace/libutil/src/time.c b/gomspace/libutil/src/time.c deleted file mode 100644 index 123f5994..00000000 --- a/gomspace/libutil/src/time.c +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include - -uint32_t gs_time_diff_ms(uint32_t ref_ms, uint32_t now_ms) -{ - if (now_ms >= ref_ms) { - return (now_ms - ref_ms); - } - - // assuming time wrapped at max uint32_t - return ((UINT32_MAX - ref_ms) + now_ms); -} - -bool gs_time_sleep_until_ms(uint32_t * ref_ms, uint32_t sleep_ms) -{ - const uint32_t now = gs_time_rel_ms(); - *ref_ms += sleep_ms; // this is expected to be in the future - uint32_t ms = gs_time_diff_ms(now, *ref_ms); - if (ms > sleep_ms) { - // we are behind - catch up, could be bad seed or too long processing - *ref_ms = now; - gs_time_sleep_ms(0); // yield - let others have a go - return true; - } - gs_time_sleep_ms(ms); - return false; -} diff --git a/gomspace/libutil/src/timestamp.c b/gomspace/libutil/src/timestamp.c deleted file mode 100644 index 2f7ee913..00000000 --- a/gomspace/libutil/src/timestamp.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include - -int timestamp_add(gs_timestamp_t * base, const gs_timestamp_t * add) -{ - if (!base || !add) - return -1; - - base->tv_sec += add->tv_sec; - if (base->tv_nsec + add->tv_nsec >= GS_TIMESTAMP_NSEC_PER_SEC) { - base->tv_sec++; - base->tv_nsec = (base->tv_nsec + add->tv_nsec) % GS_TIMESTAMP_NSEC_PER_SEC; - } else { - base->tv_nsec += add->tv_nsec; - } - - return 0; -} - -int timestamp_diff(gs_timestamp_t * base, const gs_timestamp_t * diff) -{ - if (!base || !diff) - return -1; - - base->tv_sec -= diff->tv_sec; - if (base->tv_nsec >= diff->tv_nsec) { - base->tv_nsec -= diff->tv_nsec; - } else { - base->tv_sec--; - base->tv_nsec = (base->tv_nsec + GS_TIMESTAMP_NSEC_PER_SEC) - diff->tv_nsec; - } - - return 0; -} - -/* Test is timestamp is greater or equal */ -int timestamp_ge(const gs_timestamp_t * base, const gs_timestamp_t * test) -{ - if (!base || !test) - return -1; - - if (test->tv_sec > base->tv_sec || - (test->tv_sec == base->tv_sec && - test->tv_nsec > base->tv_nsec)) { - return 1; - } - - return 0; -} - -int timestamp_copy(const gs_timestamp_t * from, gs_timestamp_t * to) -{ - if (!from || !to) - return -1; - - to->tv_sec = from->tv_sec; - to->tv_nsec = from->tv_nsec; - - return 0; -} diff --git a/gomspace/libutil/src/vmem/commands.c b/gomspace/libutil/src/vmem/commands.c deleted file mode 100644 index 06a37af4..00000000 --- a/gomspace/libutil/src/vmem/commands.c +++ /dev/null @@ -1,123 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include - -static int cmd_vmem_read(gs_command_context_t * ctx) -{ - if (gs_vmem_get_map() == NULL) { - return GS_ERROR_NOT_FOUND; - } - - void * addr; - if (gs_string_to_pointer(ctx->argv[1], &addr)) { - return GS_ERROR_ARG; - } - - uint32_t length; - if (gs_string_to_uint32(ctx->argv[2], &length)) { - return GS_ERROR_ARG; - } - - char data[length]; - void* to = gs_vmem_cpy(data, addr, length); - if (to == NULL) { - return GS_ERROR_ARG; - } - - gs_hexdump_to_stream(data, length, addr, ctx->out); - - return GS_OK; -} - -static unsigned int to_int(char c) -{ - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'A' && c <= 'F') return 10 + c - 'A'; - if (c >= 'a' && c <= 'f') return 10 + c - 'a'; - return -1; -} - -static int cmd_vmem_write(gs_command_context_t * ctx) -{ - if (gs_vmem_get_map() == NULL) { - return GS_ERROR_NOT_FOUND; - } - - void * addr; - if (gs_string_to_pointer(ctx->argv[1], &addr)) { - return GS_ERROR_ARG; - } - - int len = strlen(ctx->argv[2]) / 2; - char data[len]; - - for (int i = 0; (i < len); ++i) { - data[i] = 16 * to_int(ctx->argv[2][2*i]) + to_int(ctx->argv[2][2*i+1]); - } - - gs_vmem_cpy(addr, data, len); - return GS_OK; -} - -static int cmd_vmem_list(gs_command_context_t * ctx) -{ - return gs_vmem_list(ctx->out); -} - -static int cmd_vmem_lock(gs_command_context_t * context) -{ - return gs_vmem_lock_by_name(context->argv[1], true); -} - -static int cmd_vmem_unlock(gs_command_context_t * context) -{ - return gs_vmem_lock_by_name(context->argv[1], false); -} - -static const gs_command_t GS_COMMAND_SUB cmd_vmem_sub[] = { - { - .name = "read", - .help = "Read from virtual memory", - .usage = " ", - .handler = cmd_vmem_read, - .mandatory_args = 2, - },{ - .name = "write", - .help = "Write to virtual memory", - .usage = " ", - .handler = cmd_vmem_write, - .mandatory_args = 2, - },{ - .name = "lock", - .help = "Lock the virtual memory", - .usage = "", - .handler = cmd_vmem_lock, - .mandatory_args = 1, - },{ - .name = "unlock", - .help = "Unlock the virtual memory", - .usage = "", - .handler = cmd_vmem_unlock, - .mandatory_args = 1, - },{ - .name = "list", - .help = "Show virtual memory mappings", - .handler = cmd_vmem_list, - .mandatory_args = GS_COMMAND_NO_ARGS, - } -}; - -static const gs_command_t GS_COMMAND_ROOT cmd_vmem[] = { - { - .name = "vmem", - .help = "Virtual memory", - .chain = GS_COMMAND_INIT_CHAIN(cmd_vmem_sub), - }, -}; - -gs_error_t gs_vmem_register_commands(void) -{ - return GS_COMMAND_REGISTER(cmd_vmem); -} diff --git a/gomspace/libutil/src/vmem/vmem.c b/gomspace/libutil/src/vmem/vmem.c deleted file mode 100644 index 30068a01..00000000 --- a/gomspace/libutil/src/vmem/vmem.c +++ /dev/null @@ -1,143 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include - -static const gs_vmem_t * g_vmem_map; - -gs_error_t gs_vmem_set_map(const gs_vmem_t * map) -{ - g_vmem_map = map; - return GS_OK; -} - -const gs_vmem_t * gs_vmem_get_map(void) -{ - return g_vmem_map; -} - -gs_error_t gs_vmem_list(FILE * out) -{ - const gs_vmem_t * mem = g_vmem_map; - if (mem) { - unsigned int found = 0; - for (; mem->name; ++mem) { - if (found == 0) { - fprintf(out, "%-20s %-10s %-6s %-6s %s\r\n", "name", "virt.", "phys.", "size", "size"); - } - fprintf(out, "%-20s %p 0x%04x 0x%04x %5u\r\n", mem->name, mem->virtmem.p, (unsigned int) mem->physmem.u, (unsigned int) mem->size, (unsigned int) mem->size); - ++found; - } - if (found) { - return GS_OK; - } - } - return GS_ERROR_NOT_FOUND; -} - -const gs_vmem_t * gs_vmem_get_by_name(const char * name) -{ - if (name) { - const gs_vmem_t * mem = g_vmem_map; - if (mem) { - for (; mem->name; ++mem) { - if (strcasecmp(name, mem->name) == 0) { - return mem; - } - } - } - } - return NULL; -} - -gs_error_t gs_vmem_lock_by_name(const char * name, bool on) -{ - const gs_vmem_t * mem = gs_vmem_get_by_name(name); - if (mem) { - if (mem->drv && mem->drv->lock) { - return (mem->drv->lock)(mem, on); - } - return GS_ERROR_NOT_SUPPORTED; - } - return GS_ERROR_NOT_FOUND; -} - -gs_error_t gs_vmem_lock_all(bool on) -{ - const gs_vmem_t * mem = g_vmem_map; - if (mem) { - unsigned int locked = 0; - for (; mem->name; ++mem) { - if (mem->drv && mem->drv->lock) { - (mem->drv->lock)(mem, on); - ++locked; - } - } - if (locked) { - return GS_OK; - } - } - return GS_ERROR_NOT_FOUND; -} - -/** - @note NO LOGGING - currently the log system uses this interface, and logging can therefor create circular/forever loops. -*/ -void * gs_vmem_cpy(void* to, const void* from, size_t size) -{ - /* Search memories */ - const gs_vmem_t *vmem_from = NULL; - const gs_vmem_t *vmem_to = NULL; - const gs_vmem_t *mem = g_vmem_map; - const gs_address_t _to = {.p = to}; - const gs_address_t _from = {.p = (void*) from}; - - if (mem) { - while(mem->size != 0) { - //printf("0x%lx 0x%lx %"PRIu32" %lu %lu\r\n", mem->start, mem->physmem_start, mem->size, to, from); - if ((_to.u >= mem->virtmem.u) && (_to.u < mem->virtmem.u + mem->size)) { - vmem_to = mem; - } - if ((_from.u >= mem->virtmem.u) && (_from.u < mem->virtmem.u + mem->size)) { - vmem_from = mem; - } - mem++; - } - } - - // VMEM -> VMEM - if (vmem_to && vmem_from) { - printf("%s: VMEM to VMEM is not supported\r\n", __FUNCTION__); - return NULL; - } - - // RAM -> VMEM - if (vmem_to) { - if ((vmem_to->drv == NULL) || (vmem_to->drv->write == NULL)) { - printf("%s: Writting to VMEM %p is not supported\r\n", __FUNCTION__, to); - return NULL; - } - gs_address_t physaddr = {.u = (_to.u - vmem_to->virtmem.u) + vmem_to->physmem.u}; - //printf("Copying from ram 0x%lx to physaddr 0x%lx %u\r\n", from, physaddr, (unsigned int) size); - vmem_to->drv->write(vmem_to, physaddr.p, from, size); - return to; - } - - // VMEM -> RAM - if (vmem_from) { - if (vmem_from->drv == NULL || (vmem_from->drv->read == NULL)) { - printf("%s: Reading from VMEM %p is not supported\r\n", __FUNCTION__, from); - return NULL; - } - gs_address_t physaddr = {.u = (_from.u - vmem_from->virtmem.u) + vmem_from->physmem.u}; - //printf("Copying from mem physaddr 0x%lx to 0x%lx %u\r\n", physaddr, to, (unsigned int) size); - vmem_from->drv->read(vmem_from, to, physaddr.p, size); - return to; - } - - // RAM -> RAM (no VMEM mapping found) - return memcpy(to, from, size); -} diff --git a/gomspace/libutil/src/watchdog/local.h b/gomspace/libutil/src/watchdog/local.h deleted file mode 100644 index 1dc2e0de..00000000 --- a/gomspace/libutil/src/watchdog/local.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include - -typedef struct { - gs_thread_t task; - bool is_running; - bool do_stop; -} gs_swwd_monitor_task_t; - -// Return monitor task instance -gs_swwd_monitor_task_t * gs_swwd_get_monitor_task(void); - -GS_LOG_GROUP_EXTERN(gs_swwd_log); -#define LOG_DEFAULT gs_swwd_log diff --git a/gomspace/libutil/src/watchdog/monitor_task.c b/gomspace/libutil/src/watchdog/monitor_task.c deleted file mode 100644 index 54d7e668..00000000 --- a/gomspace/libutil/src/watchdog/monitor_task.c +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include "local.h" -#include -#include -#include - -#define GS_SWWD_CHECK_INTERVAL_MS 1000 /* Check every 1 sec. */ - -static void * gs_swwd_monitor_task(void* parameter) -{ - gs_swwd_monitor_task_t * monitor = parameter; - - log_info("monitor task started"); - - monitor->is_running = true; - - while(!monitor->do_stop) { - - gs_time_sleep_ms(GS_SWWD_CHECK_INTERVAL_MS); - - gs_swwd_check_expired_clients(NULL); - } - - monitor->is_running = false; - - log_info("monitor task exiting"); - - return NULL; -} - -gs_error_t gs_swwd_monitor_task_start(void) -{ - gs_swwd_monitor_task_t * monitor = gs_swwd_get_monitor_task(); - GS_CHECK_SUPPORTED(monitor != NULL); /* SWWD must be initialized */ - GS_CHECK_SUPPORTED(monitor->is_running == false); /* SWWD task must not already be running */ - - /* Start the monitor task */ - gs_error_t error = gs_thread_create("SWWD", gs_swwd_monitor_task, monitor, 4000, GS_THREAD_PRIORITY_HIGH, 0, &monitor->task); - if (error) { - log_error("%s: gs_thread_create() failed, error: %s", __FUNCTION__, gs_error_string(error)); - } - return error; -} - -gs_error_t gs_swwd_monitor_task_stop(uint32_t timeout_s) -{ - gs_swwd_monitor_task_t * monitor = gs_swwd_get_monitor_task(); - GS_CHECK_SUPPORTED(monitor != NULL); /* SWWD must be initialized */ - - /* Signal the task to stop */ - monitor->do_stop = true; - - /* Wait for the task to stop */ - const uint32_t timeout = GS_SWWD_CHECK_INTERVAL_MS + (timeout_s * 1000); - uint32_t tm = 0; - while(monitor->is_running && (tm < timeout)) { - gs_thread_sleep_ms(100); - tm += 100; - } - - if (monitor->is_running) { - return GS_ERROR_BUSY; - } - - return GS_OK; -} - diff --git a/gomspace/libutil/src/watchdog/watchdog.c b/gomspace/libutil/src/watchdog/watchdog.c deleted file mode 100644 index 867601b1..00000000 --- a/gomspace/libutil/src/watchdog/watchdog.c +++ /dev/null @@ -1,292 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include "local.h" -#include -#include -#include -#include -#include - -#define GS_SWWD_DEFAULT_TIMEOUT 30 /* 30 second timeout */ - -// define log group and make it default -GS_LOG_GROUP(gs_swwd_log, "swwd", GS_LOG_CAT_DEFAULT, GS_LOG_DEFAULT_MASK); - -// watchdog state -typedef enum { - GS_SWWD_STATE_FREE = 0, - GS_SWWD_STATE_ACTIVE = 1, - GS_SWWD_STATE_EXPIRED = 2, -} gs_swwd_state_t; - -// watchdog client instance -struct gs_swwd_hdl { - // State - gs_swwd_state_t state; - // Last 'user' touch value - used for detecting if watchdog has been touched (avoid race condition) - uint32_t last_touch; - // Last detected touch time - uint32_t last_touch_ms; - - // User 'set' attributes - struct { - // Name - const char* name; - // Timeout - converted from seconds (given to API) to mS - uint32_t timeout_ms; - // Action when/if timeout occurs - gs_swwd_timeout_action_t action; - // callback - gs_swwd_callback_function_t cb; - // user data (for callback) - void * cb_userdata; - // Touch - incremented on each touch - uint32_t touch; - } user; -}; - -typedef struct gs_swwd { - gs_watchdog_device_t *wdev; - gs_mutex_t lock; - gs_swwd_monitor_task_t monitor; - uint32_t num_clients; - gs_swwd_hdl_t clients[0]; -} gs_swwd_t; - -static gs_swwd_t* g_swwd = NULL; - -gs_swwd_monitor_task_t * gs_swwd_get_monitor_task(void) -{ - if (g_swwd) { - return &g_swwd->monitor; - } - return NULL; -} - -gs_error_t gs_swwd_create(uint32_t max_clients, gs_watchdog_device_t * wdev) -{ - GS_CHECK_SUPPORTED(g_swwd == NULL); /* SWWD must not be initialized more than once */ - GS_CHECK_ARG(max_clients > 0); - if (wdev) { - // ping is the only mandatory - GS_CHECK_ARG((wdev->ops != NULL) && (wdev->ops->ping != NULL)); - } - - gs_log_group_register(LOG_DEFAULT); - - gs_swwd_t *swwd_obj = calloc(1, sizeof(*swwd_obj) + (sizeof(swwd_obj->clients[0]) * max_clients)); - if (swwd_obj == NULL) { - return GS_ERROR_ALLOC; - } - - if (gs_mutex_create(&(swwd_obj->lock))) { - free(swwd_obj); - return GS_ERROR_ALLOC; - } - - swwd_obj->num_clients = max_clients; - swwd_obj->wdev = wdev; - - if (wdev) { - if (wdev->ops->set_timeout) { - wdev->ops->set_timeout(wdev, (wdev->timeout > 0) ? wdev->timeout : GS_SWWD_DEFAULT_TIMEOUT); - } - if (wdev->ops->set_pretimeout) { - wdev->ops->set_pretimeout(wdev, (wdev->pretimeout > 0) ? wdev->pretimeout : (GS_SWWD_DEFAULT_TIMEOUT - (GS_SWWD_DEFAULT_TIMEOUT/10))); - } - if (wdev->ops->start) { - wdev->ops->start(wdev); - } - wdev->ops->ping(wdev); - - } else { - log_warning("%s: no watchdog device specifed - cannot reset system!", __FUNCTION__); - } - - g_swwd = swwd_obj; /* Set the task handle as the last operation */ - return GS_OK; -} - -gs_error_t gs_swwd_destroy(uint32_t timeout_s) -{ - GS_CHECK_SUPPORTED(g_swwd != NULL); - - if (gs_swwd_monitor_task_stop(timeout_s) != GS_OK) { - return GS_ERROR_BUSY; - } - - if (g_swwd->wdev && g_swwd->wdev->ops->stop) { - g_swwd->wdev->ops->stop(g_swwd->wdev); - } - - gs_mutex_destroy(g_swwd->lock); - free(g_swwd); - g_swwd = NULL; - - return GS_OK; -} - -static const char * get_action(gs_swwd_timeout_action_t action) -{ - switch (action) { - case GS_SWWD_TIMEOUT_ACTION_RESET: - return "reset"; - case GS_SWWD_TIMEOUT_ACTION_LOG: - return "log"; - } - return "unknown"; -} - -gs_error_t gs_swwd_check_expired_clients(uint32_t *num_expired) -{ - GS_CHECK_SUPPORTED(g_swwd != NULL); /* SWWD must be initialized */ - - uint32_t expired_clients_reset = 0; - uint32_t expired_clients_log = 0; - - gs_mutex_lock(g_swwd->lock); - for (uint32_t idx = 0; idx < g_swwd->num_clients; idx++) { - gs_swwd_hdl_t * wd = &g_swwd->clients[idx]; - - uint32_t now_ms = gs_time_rel_ms(); - if (wd->state == GS_SWWD_STATE_ACTIVE) { - if (wd->last_touch != wd->user.touch) { - // watchdog has been touched since last we checked - update touch time - wd->last_touch = wd->user.touch; - wd->last_touch_ms = now_ms; - } else { - const uint32_t elapsed_ms = gs_time_diff_ms(wd->last_touch_ms, now_ms); - if (elapsed_ms >= wd->user.timeout_ms) { - wd->state = GS_SWWD_STATE_EXPIRED; - - char logbuf[100]; - snprintf(logbuf, sizeof(logbuf), - "[%s] expired -> %s (elapsed %"PRIu32" mS, timeout %"PRIu32" mS)", - wd->user.name, - get_action(wd->user.action), - elapsed_ms, - wd->user.timeout_ms); - - gs_swwd_callback_function_t cb = wd->user.cb; - void * cb_userdata = wd->user.cb_userdata; - - // Unlock while doing log and callback - // - we accept the tiny risk, that client has deregistered and will be called with invalid data - gs_mutex_unlock(g_swwd->lock); - { - log_error("%s", logbuf); - if (cb) { - (cb)(cb_userdata); - } - } - gs_mutex_lock(g_swwd->lock); - } - } - } - if (wd->state == GS_SWWD_STATE_EXPIRED) { - switch (wd->user.action) { - case GS_SWWD_TIMEOUT_ACTION_RESET: - ++expired_clients_reset; - break; - case GS_SWWD_TIMEOUT_ACTION_LOG: - if (wd->last_touch != wd->user.touch) { - // its alive - reactive watchdog - wd->state = GS_SWWD_STATE_ACTIVE; - wd->last_touch = wd->user.touch; - wd->last_touch_ms = now_ms; - } else { - ++expired_clients_log; - } - break; - } - } - } - gs_mutex_unlock(g_swwd->lock); - - if ((expired_clients_reset == 0) && g_swwd->wdev) { - g_swwd->wdev->ops->ping(g_swwd->wdev); - } - - if (num_expired) { - *num_expired = (expired_clients_reset + expired_clients_log); - } - - return GS_OK; -} - -gs_error_t gs_swwd_register_with_action(gs_swwd_hdl_t ** user_wd, - uint32_t timeout_seconds, - gs_swwd_callback_function_t callback, void * userdata, - const char * name, - gs_swwd_timeout_action_t action) -{ - GS_CHECK_ARG(gs_string_empty(name) == false); - GS_CHECK_ARG(timeout_seconds > 0); - GS_CHECK_ARG(user_wd != NULL); - GS_CHECK_SUPPORTED(g_swwd != NULL); /* SWWD must be initialized */ - - gs_swwd_hdl_t * wd = NULL; - gs_mutex_lock(g_swwd->lock); - { - for (unsigned int idx = 0; idx < g_swwd->num_clients; idx++) { - if (g_swwd->clients[idx].state == GS_SWWD_STATE_FREE) { - wd = &g_swwd->clients[idx]; - memset(wd, 0, sizeof(*wd)); - - // set user stuff - wd->user.name = name; - wd->user.timeout_ms = (timeout_seconds * 1000); - wd->user.cb = callback; - wd->user.cb_userdata = userdata; - wd->user.action = action; - - // set internal stuff - wd->state = GS_SWWD_STATE_ACTIVE; - wd->last_touch_ms = gs_time_rel_ms(); - break; - } - } - } - gs_mutex_unlock(g_swwd->lock); - - *user_wd = wd; - - if (wd == NULL) { - log_error("[%s] cannot create instance due to no available handles", name); - return GS_ERROR_FULL; - } - - return GS_OK; -} - -gs_error_t gs_swwd_deregister(gs_swwd_hdl_t ** wd) -{ - GS_CHECK_SUPPORTED(g_swwd != NULL); /* SWWD must be initialized */ - GS_CHECK_ARG(wd != NULL); - GS_CHECK_HANDLE(*wd != NULL); - - gs_mutex_lock(g_swwd->lock); - memset((*wd), 0, sizeof(**wd)); - gs_mutex_unlock(g_swwd->lock); - *wd = NULL; - - return GS_OK; -} - -gs_error_t gs_swwd_touch(gs_swwd_hdl_t * wd) -{ - GS_CHECK_HANDLE(wd != NULL); - - ++wd->user.touch; - return GS_OK; -} - -gs_error_t gs_swwd_set_timeout(gs_swwd_hdl_t * wd, uint32_t timeout_seconds) -{ - GS_CHECK_ARG(timeout_seconds > 0); - GS_CHECK_HANDLE(wd != NULL); - - ++wd->user.touch; - wd->user.timeout_ms = (timeout_seconds * 1000); - return GS_OK; -} diff --git a/gomspace/libutil/src/zip/cppcheck-suppress.txt b/gomspace/libutil/src/zip/cppcheck-suppress.txt deleted file mode 100644 index b23b687d..00000000 --- a/gomspace/libutil/src/zip/cppcheck-suppress.txt +++ /dev/null @@ -1,5 +0,0 @@ -// we don't wanna change 3rd part code for none-critical issue -localtimeCalled:src/zip/miniz/miniz.c -utimeCalled:src/zip/miniz/miniz.c -assignIfError:src/zip/miniz/miniz.c -unreadVariable:src/zip/miniz/miniz.c diff --git a/gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES b/gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES deleted file mode 100644 index cb7adb22..00000000 --- a/gomspace/libutil/src/zip/miniz/LIST_OF_CHANGES +++ /dev/null @@ -1,9429 +0,0 @@ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -diff --git a/src/zip/miniz/miniz.h b/src/zip/miniz/miniz.h -index 86fac4c..f92f14e 100644 ---- a/src/zip/miniz/miniz.h -+++ b/src/zip/miniz/miniz.h -@@ -447,7 +447,7 @@ typedef void *const voidpc; - #define inflate mz_inflate - #define inflateEnd mz_inflateEnd - #define uncompress mz_uncompress --#define crc32 mz_crc32 -+// #define crc32 mz_crc32 - #define adler32 mz_adler32 - #define MAX_WBITS 15 - #define MAX_MEM_LEVEL 9 - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - -diff --git a/src/zip/miniz/miniz.c b/src/zip/miniz/miniz.c -index 67318cc..960f07c 100644 ---- a/src/zip/miniz/miniz.c -+++ b/src/zip/miniz/miniz.c -@@ -1936,6 +1936,7 @@ tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_fun - d->m_pSrc = NULL; - d->m_src_buf_left = 0; - d->m_out_buf_ofs = 0; -+ memset(d->m_dict, 0, sizeof(d->m_dict)); // Initialize array to 0's - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - return TDEFL_STATUS_OKAY; -@@ -2464,7 +2465,7 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_nex - } - r->m_table_sizes[2] = 19; - } -- for (; (int)r->m_type >= 0; r->m_type--) -+ for (; ((int)r->m_type) >= 0; r->m_type--) - { - int tree_next, tree_cur; - tinfl_huff_table *pTable; -@@ -3025,7 +3026,7 @@ static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) - #define MZ_DELETE_FILE remove - - #else --#pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") -+// #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") - #ifndef MINIZ_NO_TIME - #include - #endif -@@ -3267,12 +3268,12 @@ static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) - } - - #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS --static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) -+static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) - { - #ifdef _MSC_VER - struct tm tm_struct; - struct tm *tm = &tm_struct; -- errno_t err = localtime_s(tm, &time); -+ errno_t err = localtime_s(tm, &time_); - if (err) - { - *pDOS_date = 0; -@@ -3280,7 +3281,7 @@ static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_u - return; - } - #else -- struct tm *tm = localtime(&time); -+ struct tm *tm = localtime(&time_); - #endif /* #ifdef _MSC_VER */ - - *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); -@@ -3874,7 +3875,10 @@ mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, - /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ - - if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -+ { -+ MZ_FCLOSE(pFile); - return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -+ } - - if (!mz_zip_reader_init_internal(pZip, flags)) - { -@@ -4134,7 +4138,7 @@ static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_inde - - pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); - pField_data += sizeof(mz_uint64); -- field_data_remaining -= sizeof(mz_uint64); -+ // field_data_remaining -= sizeof(mz_uint64); - } - - break; -@@ -4219,11 +4223,11 @@ static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char - - int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) - { -- mz_uint32 index; -- if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index)) -+ mz_uint32 index_; -+ if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) - return -1; - else -- return (int)index; -+ return (int)index_; - } - - mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) -@@ -5332,12 +5336,12 @@ mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) - if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) - { - mz_uint32 found_index; -- mz_zip_archive_file_stat stat; -+ mz_zip_archive_file_stat stat_; - -- if (!mz_zip_reader_file_stat(pZip, i, &stat)) -+ if (!mz_zip_reader_file_stat(pZip, i, &stat_)) - return MZ_FALSE; - -- if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index)) -+ if (!mz_zip_reader_locate_file_v2(pZip, stat_.m_filename, NULL, 0, &found_index)) - return MZ_FALSE; - - /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ -@@ -6011,6 +6015,11 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n - mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, - const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) - { -+ if(!pZip) -+ { -+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+ } -+ - mz_uint16 method = 0, dos_time = 0, dos_date = 0; - mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; - mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; -@@ -6035,7 +6044,7 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n - level = level_and_flags & 0xF; - store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); - -- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -+ if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - pState = pZip->m_pState; -@@ -6296,6 +6305,11 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n - mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, - const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) - { -+ if(!pZip) -+ { -+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+ } -+ - mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; - mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; - mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; -@@ -6315,7 +6329,7 @@ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, - level = level_and_flags & 0xF; - - /* Sanity checks */ -- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -+ if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - pState = pZip->m_pState; -@@ -6828,7 +6842,7 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * - - if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) - { -- const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); -+ // const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); - - if (field_data_size < sizeof(mz_uint64) * 2) - { -@@ -6836,8 +6850,8 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - } - -- local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); -- local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ -+ // local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); -+ // local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ - - found_zip64_ext_data_in_ldir = MZ_TRUE; - break; -@@ -6966,7 +6980,7 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * - return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - } - -- cur_src_file_ofs += n; -+ // cur_src_file_ofs += n; - cur_dst_file_ofs += n; - } - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - -diff --git a/src/zip/miniz/miniz.h b/src/zip/miniz/miniz.h -index 68f903c..e517263 100644 ---- a/src/zip/miniz/miniz.h -+++ b/src/zip/miniz/miniz.h -@@ -203,7 +203,7 @@ mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); - - #define MZ_CRC32_INIT (0) - /* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ --mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); -+// mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); - - /* Compression strategies. */ - enum -@@ -301,7 +301,7 @@ typedef struct mz_stream_s - typedef mz_stream *mz_streamp; - - /* Returns the version string of miniz.c. */ --const char *mz_version(void); -+// const char *mz_version(void); - - /* mz_deflateInit() initializes a compressor with default options: */ - /* Parameters: */ -@@ -324,7 +324,7 @@ int mz_deflateInit(mz_streamp pStream, int level); - int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); - - /* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ --int mz_deflateReset(mz_streamp pStream); -+// int mz_deflateReset(mz_streamp pStream); - - /* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */ - /* Parameters: */ -@@ -345,7 +345,7 @@ int mz_deflate(mz_streamp pStream, int flush); - int mz_deflateEnd(mz_streamp pStream); - - /* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ --mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); -+// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); - - /* Single-call compression functions mz_compress() and mz_compress2(): */ - /* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ -@@ -353,7 +353,7 @@ int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char * - int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); - - /* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */ --mz_ulong mz_compressBound(mz_ulong source_len); -+// mz_ulong mz_compressBound(mz_ulong source_len); - - /* Initializes a decompressor. */ - int mz_inflateInit(mz_streamp pStream); -@@ -386,7 +386,7 @@ int mz_inflateEnd(mz_streamp pStream); - int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); - - /* Returns a string description of the specified error code, or NULL if the error code is invalid. */ --const char *mz_error(int err); -+// const char *mz_error(int err); - - /* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */ - /* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ -@@ -436,13 +436,13 @@ typedef void *const voidpc; - #define z_stream mz_stream - #define deflateInit mz_deflateInit - #define deflateInit2 mz_deflateInit2 --#define deflateReset mz_deflateReset -+// #define deflateReset mz_deflateReset - #define deflate mz_deflate - #define deflateEnd mz_deflateEnd --#define deflateBound mz_deflateBound -+// #define deflateBound mz_deflateBound - #define compress mz_compress - #define compress2 mz_compress2 --#define compressBound mz_compressBound -+// #define compressBound mz_compressBound - #define inflateInit mz_inflateInit - #define inflateInit2 mz_inflateInit2 - #define inflate mz_inflate -@@ -452,15 +452,15 @@ typedef void *const voidpc; - #define adler32 mz_adler32 - #define MAX_WBITS 15 - #define MAX_MEM_LEVEL 9 --#define zError mz_error -+// #define zError mz_error - #define ZLIB_VERSION MZ_VERSION - #define ZLIB_VERNUM MZ_VERNUM - #define ZLIB_VER_MAJOR MZ_VER_MAJOR - #define ZLIB_VER_MINOR MZ_VER_MINOR - #define ZLIB_VER_REVISION MZ_VER_REVISION - #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION --#define zlibVersion mz_version --#define zlib_version mz_version() -+// #define zlibVersion mz_version -+// #define zlib_version mz_version() - #endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ - - #endif /* MINIZ_NO_ZLIB_APIS */ -@@ -501,15 +501,15 @@ typedef int mz_bool; - #define MZ_FILE FILE - #endif /* #ifdef MINIZ_NO_STDIO */ - --#ifdef MINIZ_NO_TIME --typedef struct mz_dummy_time_t_tag --{ -- int m_dummy; --} mz_dummy_time_t; --#define MZ_TIME_T mz_dummy_time_t --#else --#define MZ_TIME_T time_t --#endif -+// #ifdef MINIZ_NO_TIME -+// typedef struct mz_dummy_time_t_tag -+// { -+// int m_dummy; -+// } mz_dummy_time_t; -+// #define MZ_TIME_T mz_dummy_time_t -+// #else -+// #define MZ_TIME_T time_t -+// #endif - - #define MZ_ASSERT(x) assert(x) - -@@ -551,7 +551,7 @@ extern "C" { - - extern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); - extern void miniz_def_free_func(void *opaque, void *address); --extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); -+// extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); - - #define MZ_UINT16_MAX (0xFFFFU) - #define MZ_UINT32_MAX (0xFFFFFFFFU) -@@ -609,11 +609,11 @@ enum - /* Function returns a pointer to the compressed data, or NULL on failure. */ - /* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */ - /* The caller must free() the returned block when it's no longer needed. */ --void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); -+// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - - /* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ - /* Returns 0 on failure. */ --size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); -+// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - - /* Compresses an image to a compressed PNG file in memory. */ - /* On entry: */ -@@ -625,14 +625,14 @@ size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void - /* Function returns a pointer to the compressed data, or NULL on failure. */ - /* *pLen_out will be set to the size of the PNG image file. */ - /* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */ --void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); --void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); -+// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); -+// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); - - /* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ - typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); - - /* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */ --mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); -+// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - - enum - { -@@ -727,9 +727,9 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI - - /* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ - /* tdefl_compress_buffer() always consumes the entire input buffer. */ --tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); -+// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); - --tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); -+// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); - mz_uint32 tdefl_get_adler32(tdefl_compressor *d); - - /* Create tdefl_compress() flags given zlib-style compression parameters. */ -@@ -741,8 +741,8 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int - /* Allocate the tdefl_compressor structure in C so that */ - /* non-C language bindings to tdefl_ API don't need to worry about */ - /* structure size and allocation mechanism. */ --tdefl_compressor *tdefl_compressor_alloc(); --void tdefl_compressor_free(tdefl_compressor *pComp); -+// tdefl_compressor *tdefl_compressor_alloc(); -+// void tdefl_compressor_free(tdefl_compressor *pComp); - - #ifdef __cplusplus - } -@@ -775,17 +775,17 @@ enum - /* Function returns a pointer to the decompressed data, or NULL on failure. */ - /* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */ - /* The caller must call mz_free() on the returned block when it's no longer needed. */ --void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); -+// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - - /* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ - /* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ - #define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) --size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); -+// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - - /* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */ - /* Returns 1 on success or 0 on failure. */ - typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); --int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); -+// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - - struct tinfl_decompressor_tag; - typedef struct tinfl_decompressor_tag tinfl_decompressor; -@@ -794,8 +794,8 @@ typedef struct tinfl_decompressor_tag tinfl_decompressor; - /* non-C language bindings to tinfl_ API don't need to worry about */ - /* structure size and allocation mechanism. */ - --tinfl_decompressor *tinfl_decompressor_alloc(); --void tinfl_decompressor_free(tinfl_decompressor *pDecomp); -+// tinfl_decompressor *tinfl_decompressor_alloc(); -+// void tinfl_decompressor_free(tinfl_decompressor *pDecomp); - - /* Max size of LZ dictionary. */ - #define TINFL_LZ_DICT_SIZE 32768 -@@ -896,319 +896,319 @@ struct tinfl_decompressor_tag - - /* ------------------- ZIP archive reading/writing */ - --#ifndef MINIZ_NO_ARCHIVE_APIS -+// #ifndef MINIZ_NO_ARCHIVE_APIS - --#ifdef __cplusplus --extern "C" { --#endif -+// #ifdef __cplusplus -+// extern "C" { -+// #endif - --enum --{ -+// enum -+// { - /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ -- MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, -- MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, -- MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 --}; -- --typedef struct --{ -- /* Central directory file index. */ -- mz_uint32 m_file_index; -+// MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, -+// MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, -+// MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 -+// }; -+ -+// typedef struct -+// { -+// /* Central directory file index. */ -+// mz_uint32 m_file_index; -+ -+// /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ -+// mz_uint64 m_central_dir_ofs; -+ -+// /* These fields are copied directly from the zip's central dir. */ -+// mz_uint16 m_version_made_by; -+// mz_uint16 m_version_needed; -+// mz_uint16 m_bit_flag; -+// mz_uint16 m_method; -+ -+// #ifndef MINIZ_NO_TIME -+// MZ_TIME_T m_time; -+// #endif - -- /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ -- mz_uint64 m_central_dir_ofs; -+// /* CRC-32 of uncompressed data. */ -+// mz_uint32 m_crc32; - -- /* These fields are copied directly from the zip's central dir. */ -- mz_uint16 m_version_made_by; -- mz_uint16 m_version_needed; -- mz_uint16 m_bit_flag; -- mz_uint16 m_method; -+// /* File's compressed size. */ -+// mz_uint64 m_comp_size; - --#ifndef MINIZ_NO_TIME -- MZ_TIME_T m_time; --#endif -+// /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ -+// mz_uint64 m_uncomp_size; - -- /* CRC-32 of uncompressed data. */ -- mz_uint32 m_crc32; -+// /* Zip internal and external file attributes. */ -+// mz_uint16 m_internal_attr; -+// mz_uint32 m_external_attr; - -- /* File's compressed size. */ -- mz_uint64 m_comp_size; -+// /* Entry's local header file offset in bytes. */ -+// mz_uint64 m_local_header_ofs; - -- /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ -- mz_uint64 m_uncomp_size; -+// /* Size of comment in bytes. */ -+// mz_uint32 m_comment_size; - -- /* Zip internal and external file attributes. */ -- mz_uint16 m_internal_attr; -- mz_uint32 m_external_attr; -+// /* MZ_TRUE if the entry appears to be a directory. */ -+// mz_bool m_is_directory; - -- /* Entry's local header file offset in bytes. */ -- mz_uint64 m_local_header_ofs; -+// /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ -+// mz_bool m_is_encrypted; - -- /* Size of comment in bytes. */ -- mz_uint32 m_comment_size; -+// /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ -+// mz_bool m_is_supported; - -- /* MZ_TRUE if the entry appears to be a directory. */ -- mz_bool m_is_directory; -+// /* Filename. If string ends in '/' it's a subdirectory entry. */ -+// /* Guaranteed to be zero terminated, may be truncated to fit. */ -+// char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; - -- /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ -- mz_bool m_is_encrypted; -+// /* Comment field. */ -+// /* Guaranteed to be zero terminated, may be truncated to fit. */ -+// char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; - -- /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ -- mz_bool m_is_supported; -+// } mz_zip_archive_file_stat; - -- /* Filename. If string ends in '/' it's a subdirectory entry. */ -- /* Guaranteed to be zero terminated, may be truncated to fit. */ -- char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; -+// typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); -+// typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); -+// typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); - -- /* Comment field. */ -- /* Guaranteed to be zero terminated, may be truncated to fit. */ -- char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; -+// struct mz_zip_internal_state_tag; -+// typedef struct mz_zip_internal_state_tag mz_zip_internal_state; - --} mz_zip_archive_file_stat; -+// typedef enum { -+// MZ_ZIP_MODE_INVALID = 0, -+// MZ_ZIP_MODE_READING = 1, -+// MZ_ZIP_MODE_WRITING = 2, -+// MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 -+// } mz_zip_mode; - --typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); --typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); --typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); -+// typedef enum { -+// MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, -+// MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, -+// MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, -+// MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, -+ // MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ -+ // MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ -+ // MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ -+// MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, -+// MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 -+// } mz_zip_flags; - --struct mz_zip_internal_state_tag; --typedef struct mz_zip_internal_state_tag mz_zip_internal_state; -- --typedef enum { -- MZ_ZIP_MODE_INVALID = 0, -- MZ_ZIP_MODE_READING = 1, -- MZ_ZIP_MODE_WRITING = 2, -- MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 --} mz_zip_mode; -- --typedef enum { -- MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, -- MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, -- MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, -- MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, -- MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ -- MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ -- MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ -- MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, -- MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 --} mz_zip_flags; -- --typedef enum { -- MZ_ZIP_TYPE_INVALID = 0, -- MZ_ZIP_TYPE_USER, -- MZ_ZIP_TYPE_MEMORY, -- MZ_ZIP_TYPE_HEAP, -- MZ_ZIP_TYPE_FILE, -- MZ_ZIP_TYPE_CFILE, -- MZ_ZIP_TOTAL_TYPES --} mz_zip_type; -+// typedef enum { -+// MZ_ZIP_TYPE_INVALID = 0, -+// MZ_ZIP_TYPE_USER, -+// MZ_ZIP_TYPE_MEMORY, -+// MZ_ZIP_TYPE_HEAP, -+// MZ_ZIP_TYPE_FILE, -+// MZ_ZIP_TYPE_CFILE, -+// MZ_ZIP_TOTAL_TYPES -+// } mz_zip_type; - - /* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ --typedef enum { -- MZ_ZIP_NO_ERROR = 0, -- MZ_ZIP_UNDEFINED_ERROR, -- MZ_ZIP_TOO_MANY_FILES, -- MZ_ZIP_FILE_TOO_LARGE, -- MZ_ZIP_UNSUPPORTED_METHOD, -- MZ_ZIP_UNSUPPORTED_ENCRYPTION, -- MZ_ZIP_UNSUPPORTED_FEATURE, -- MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, -- MZ_ZIP_NOT_AN_ARCHIVE, -- MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, -- MZ_ZIP_UNSUPPORTED_MULTIDISK, -- MZ_ZIP_DECOMPRESSION_FAILED, -- MZ_ZIP_COMPRESSION_FAILED, -- MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, -- MZ_ZIP_CRC_CHECK_FAILED, -- MZ_ZIP_UNSUPPORTED_CDIR_SIZE, -- MZ_ZIP_ALLOC_FAILED, -- MZ_ZIP_FILE_OPEN_FAILED, -- MZ_ZIP_FILE_CREATE_FAILED, -- MZ_ZIP_FILE_WRITE_FAILED, -- MZ_ZIP_FILE_READ_FAILED, -- MZ_ZIP_FILE_CLOSE_FAILED, -- MZ_ZIP_FILE_SEEK_FAILED, -- MZ_ZIP_FILE_STAT_FAILED, -- MZ_ZIP_INVALID_PARAMETER, -- MZ_ZIP_INVALID_FILENAME, -- MZ_ZIP_BUF_TOO_SMALL, -- MZ_ZIP_INTERNAL_ERROR, -- MZ_ZIP_FILE_NOT_FOUND, -- MZ_ZIP_ARCHIVE_TOO_LARGE, -- MZ_ZIP_VALIDATION_FAILED, -- MZ_ZIP_WRITE_CALLBACK_FAILED, -- MZ_ZIP_TOTAL_ERRORS --} mz_zip_error; -- --typedef struct --{ -- mz_uint64 m_archive_size; -- mz_uint64 m_central_directory_file_ofs; -- -- /* We only support up to UINT32_MAX files in zip64 mode. */ -- mz_uint32 m_total_files; -- mz_zip_mode m_zip_mode; -- mz_zip_type m_zip_type; -- mz_zip_error m_last_error; -- -- mz_uint64 m_file_offset_alignment; -- -- mz_alloc_func m_pAlloc; -- mz_free_func m_pFree; -- mz_realloc_func m_pRealloc; -- void *m_pAlloc_opaque; -- -- mz_file_read_func m_pRead; -- mz_file_write_func m_pWrite; -- mz_file_needs_keepalive m_pNeeds_keepalive; -- void *m_pIO_opaque; -- -- mz_zip_internal_state *m_pState; -- --} mz_zip_archive; -- --typedef struct --{ -- mz_zip_archive *pZip; -- mz_uint flags; -- -- int status; --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- mz_uint file_crc32; --#endif -- mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; -- mz_zip_archive_file_stat file_stat; -- void *pRead_buf; -- void *pWrite_buf; -+// typedef enum { -+// MZ_ZIP_NO_ERROR = 0, -+// MZ_ZIP_UNDEFINED_ERROR, -+// MZ_ZIP_TOO_MANY_FILES, -+// MZ_ZIP_FILE_TOO_LARGE, -+// MZ_ZIP_UNSUPPORTED_METHOD, -+// MZ_ZIP_UNSUPPORTED_ENCRYPTION, -+// MZ_ZIP_UNSUPPORTED_FEATURE, -+// MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, -+// MZ_ZIP_NOT_AN_ARCHIVE, -+// MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, -+// MZ_ZIP_UNSUPPORTED_MULTIDISK, -+// MZ_ZIP_DECOMPRESSION_FAILED, -+// MZ_ZIP_COMPRESSION_FAILED, -+// MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, -+// MZ_ZIP_CRC_CHECK_FAILED, -+// MZ_ZIP_UNSUPPORTED_CDIR_SIZE, -+// MZ_ZIP_ALLOC_FAILED, -+// MZ_ZIP_FILE_OPEN_FAILED, -+// MZ_ZIP_FILE_CREATE_FAILED, -+// MZ_ZIP_FILE_WRITE_FAILED, -+// MZ_ZIP_FILE_READ_FAILED, -+// MZ_ZIP_FILE_CLOSE_FAILED, -+// MZ_ZIP_FILE_SEEK_FAILED, -+// MZ_ZIP_FILE_STAT_FAILED, -+// MZ_ZIP_INVALID_PARAMETER, -+// MZ_ZIP_INVALID_FILENAME, -+// MZ_ZIP_BUF_TOO_SMALL, -+// MZ_ZIP_INTERNAL_ERROR, -+// MZ_ZIP_FILE_NOT_FOUND, -+// MZ_ZIP_ARCHIVE_TOO_LARGE, -+// MZ_ZIP_VALIDATION_FAILED, -+// MZ_ZIP_WRITE_CALLBACK_FAILED, -+// MZ_ZIP_TOTAL_ERRORS -+// } mz_zip_error; -+ -+// typedef struct -+// { -+// mz_uint64 m_archive_size; -+// mz_uint64 m_central_directory_file_ofs; -+ -+// /* We only support up to UINT32_MAX files in zip64 mode. */ -+// mz_uint32 m_total_files; -+// mz_zip_mode m_zip_mode; -+// mz_zip_type m_zip_type; -+// mz_zip_error m_last_error; -+ -+// mz_uint64 m_file_offset_alignment; -+ -+// mz_alloc_func m_pAlloc; -+// mz_free_func m_pFree; -+// mz_realloc_func m_pRealloc; -+// void *m_pAlloc_opaque; -+ -+// mz_file_read_func m_pRead; -+// mz_file_write_func m_pWrite; -+// mz_file_needs_keepalive m_pNeeds_keepalive; -+// void *m_pIO_opaque; -+ -+// mz_zip_internal_state *m_pState; -+ -+// } mz_zip_archive; -+ -+// typedef struct -+// { -+// mz_zip_archive *pZip; -+// mz_uint flags; -+ -+// int status; -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// mz_uint file_crc32; -+// #endif -+// mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; -+// mz_zip_archive_file_stat file_stat; -+// void *pRead_buf; -+// void *pWrite_buf; - -- size_t out_blk_remain; -+// size_t out_blk_remain; - -- tinfl_decompressor inflator; -+// tinfl_decompressor inflator; - --} mz_zip_reader_extract_iter_state; -+// } mz_zip_reader_extract_iter_state; - - /* -------- ZIP reading */ - - /* Inits a ZIP archive reader. */ - /* These functions read and validate the archive's central directory. */ --mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); -+// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); - --mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); -+// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); - --#ifndef MINIZ_NO_STDIO -+// #ifndef MINIZ_NO_STDIO - /* Read a archive from a disk file. */ - /* file_start_ofs is the file offset where the archive actually begins, or 0. */ - /* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */ --mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); --mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); -+// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); -+// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); - - /* Read an archive from an already opened FILE, beginning at the current file position. */ - /* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */ - /* The FILE will NOT be closed when mz_zip_reader_end() is called. */ --mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); --#endif -+// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); -+// #endif - - /* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */ --mz_bool mz_zip_reader_end(mz_zip_archive *pZip); -+// mz_bool mz_zip_reader_end(mz_zip_archive *pZip); - - /* -------- ZIP reading or writing */ - - /* Clears a mz_zip_archive struct to all zeros. */ - /* Important: This must be done before passing the struct to any mz_zip functions. */ --void mz_zip_zero_struct(mz_zip_archive *pZip); -+// void mz_zip_zero_struct(mz_zip_archive *pZip); - --mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); --mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); -+// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); -+// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); - - /* Returns the total number of files in the archive. */ --mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); -+// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); - --mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); --mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); --MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); -+// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); -+// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); -+// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); - - /* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ --size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); -+// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); - - /* Attempts to locates a file in the archive's central directory. */ - /* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ - /* Returns -1 if the file cannot be found. */ --int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); -+// int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); - /* Returns MZ_FALSE if the file cannot be found. */ --mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex); -+// mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex); - - /* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */ - /* Note that the m_last_error functionality is not thread safe. */ --mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); --mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); --mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); --mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); --const char *mz_zip_get_error_string(mz_zip_error mz_err); -+// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); -+// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); -+// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); -+// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); -+// const char *mz_zip_get_error_string(mz_zip_error mz_err); - - /* MZ_TRUE if the archive file entry is a directory entry. */ --mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); -+// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); - - /* MZ_TRUE if the file is encrypted/strong encrypted. */ --mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); -+// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); - - /* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */ --mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); -+// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); - - /* Retrieves the filename of an archive file entry. */ - /* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */ --mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); -+// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); - - /* Attempts to locates a file in the archive's central directory. */ - /* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ - /* Returns -1 if the file cannot be found. */ --int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); --int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); -+// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); -+// int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); - - /* Returns detailed information about an archive file entry. */ --mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); -+// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); - - /* MZ_TRUE if the file is in zip64 format. */ - /* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */ --mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); -+// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); - - /* Returns the total central directory size in bytes. */ - /* The current max supported size is <= MZ_UINT32_MAX. */ --size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); -+// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); - - /* Extracts a archive file to a memory buffer using no memory allocation. */ - /* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ --mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); --mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); -+// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); -+// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); - - /* Extracts a archive file to a memory buffer. */ --mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); --mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); -+// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); -+// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); - - /* Extracts a archive file to a dynamically allocated heap buffer. */ - /* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ - /* Returns NULL and sets the last error on failure. */ --void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); --void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); -+// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); -+// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); - - /* Extracts a archive file using a callback function to output the file's data. */ --mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); --mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); -+// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); -+// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); - - /* Extract a file iteratively */ --mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); --mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); --size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); --mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); -+// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); -+// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); -+// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); -+// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); - --#ifndef MINIZ_NO_STDIO -+// #ifndef MINIZ_NO_STDIO - /* Extracts a archive file to a disk file and sets its last accessed and modified times. */ - /* This function only extracts files, not archive directory records. */ --mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); --mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); -+// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); -+// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); - - /* Extracts a archive file starting at the current position in the destination FILE stream. */ --mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); --mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); --#endif -+// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); -+// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); -+// #endif - - #if 0 - /* TODO */ -@@ -1233,26 +1233,26 @@ mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pA - // mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); - - /* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ --mz_bool mz_zip_end(mz_zip_archive *pZip); -+// mz_bool mz_zip_end(mz_zip_archive *pZip); - - /* -------- ZIP writing */ - --#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -+// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - - /* Inits a ZIP archive writer. */ - /*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ - /*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ --mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); --mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); -+// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); -+// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); - --mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); --mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); -+// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); -+// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); - --#ifndef MINIZ_NO_STDIO --mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); --mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); --mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); --#endif -+// #ifndef MINIZ_NO_STDIO -+// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); -+// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); -+// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); -+// #endif - - /* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */ - /* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ -@@ -1260,33 +1260,33 @@ mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint f - /* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */ - /* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */ - /* the archive is finalized the file's central directory will be hosed. */ --mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); --mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); -+// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); -+// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); - - /* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */ - /* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ - /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ --mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); -+// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); - - /* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */ - /* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ --mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -- mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); -+// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -+// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); - --mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -- mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, -- const char *user_extra_data_central, mz_uint user_extra_data_central_len); -+// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -+// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, -+// const char *user_extra_data_central, mz_uint user_extra_data_central_len); - --#ifndef MINIZ_NO_STDIO -+// #ifndef MINIZ_NO_STDIO - /* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */ - /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ --mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); -+// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - - /* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ --mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, -- const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, -- const char *user_extra_data_central, mz_uint user_extra_data_central_len); --#endif -+// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, -+// const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, -+// const char *user_extra_data_central, mz_uint user_extra_data_central_len); -+// #endif - - /* Adds a file to an archive by fully cloning the data from another archive. */ - /* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */ -@@ -1295,15 +1295,15 @@ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, - /* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ - /* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ - /* An archive must be manually finalized by calling this function for it to be valid. */ --mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); -+// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); - - /* Finalizes a heap archive, returning a poiner to the heap block and its size. */ - /* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ --mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); -+// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); - - /* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ - /* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */ --mz_bool mz_zip_writer_end(mz_zip_archive *pZip); -+// mz_bool mz_zip_writer_end(mz_zip_archive *pZip); - - /* -------- Misc. high-level helper functions: */ - -@@ -1311,19 +1311,19 @@ mz_bool mz_zip_writer_end(mz_zip_archive *pZip); - /* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */ - /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ - /* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */ --mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); --mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); -+// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); -+// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); - - /* Reads a single file from an archive into a heap block. */ - /* If pComment is not NULL, only the file with the specified comment will be extracted. */ - /* Returns NULL on failure. */ --void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); --void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); -+// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); -+// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); - --#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ -+// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ - --#ifdef __cplusplus --} --#endif -+// #ifdef __cplusplus -+// } -+// #endif - --#endif /* MINIZ_NO_ARCHIVE_APIS */ -+// #endif /* MINIZ_NO_ARCHIVE_APIS */ - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - -diff --git a/src/zip/miniz/miniz.c b/src/zip/miniz/miniz.c -index 9ee7635..910d4b1 100644 ---- a/src/zip/miniz/miniz.c -+++ b/src/zip/miniz/miniz.c -@@ -65,92 +65,92 @@ mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) - } - - /* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */ --#if 0 -- mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) -- { -- static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, -- 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; -- mz_uint32 crcu32 = (mz_uint32)crc; -- if (!ptr) -- return MZ_CRC32_INIT; -- crcu32 = ~crcu32; -- while (buf_len--) -- { -- mz_uint8 b = *ptr++; -- crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; -- crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; -- } -- return ~crcu32; -- } --#else -+// #if 0 -+// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) -+// { -+// static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, -+// 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; -+// mz_uint32 crcu32 = (mz_uint32)crc; -+// if (!ptr) -+// return MZ_CRC32_INIT; -+// crcu32 = ~crcu32; -+// while (buf_len--) -+// { -+// mz_uint8 b = *ptr++; -+// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; -+// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; -+// } -+// return ~crcu32; -+// } -+// #else - /* Faster, but larger CPU cache footprint. - */ --mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) --{ -- static const mz_uint32 s_crc_table[256] = -- { -- 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, -- 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, -- 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, -- 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, -- 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, -- 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, -- 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, -- 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, -- 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, -- 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, -- 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, -- 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, -- 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, -- 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, -- 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, -- 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, -- 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, -- 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, -- 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, -- 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, -- 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, -- 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, -- 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, -- 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, -- 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, -- 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, -- 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, -- 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, -- 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, -- 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, -- 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, -- 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, -- 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, -- 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, -- 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, -- 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, -- 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -- }; -- -- mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; -- const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; -- -- while (buf_len >= 4) -- { -- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; -- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; -- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; -- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; -- pByte_buf += 4; -- buf_len -= 4; -- } -+// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) -+// { -+// static const mz_uint32 s_crc_table[256] = -+// { -+// 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, -+// 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, -+// 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, -+// 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, -+// 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, -+// 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, -+// 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, -+// 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, -+// 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, -+// 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, -+// 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, -+// 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, -+// 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, -+// 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, -+// 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, -+// 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, -+// 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, -+// 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, -+// 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, -+// 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, -+// 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, -+// 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, -+// 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, -+// 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, -+// 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, -+// 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, -+// 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, -+// 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, -+// 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, -+// 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, -+// 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, -+// 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, -+// 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, -+// 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, -+// 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, -+// 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, -+// 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -+// }; -+ -+// mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; -+// const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; -+ -+// while (buf_len >= 4) -+// { -+// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; -+// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; -+// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; -+// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; -+// pByte_buf += 4; -+// buf_len -= 4; -+// } - -- while (buf_len) -- { -- crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; -- ++pByte_buf; -- --buf_len; -- } -+// while (buf_len) -+// { -+// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; -+// ++pByte_buf; -+// --buf_len; -+// } - -- return ~crc32; --} --#endif -+// return ~crc32; -+// } -+// #endif - - void mz_free(void *p) - { -@@ -167,16 +167,16 @@ void miniz_def_free_func(void *opaque, void *address) - (void)opaque, (void)address; - MZ_FREE(address); - } --void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) --{ -- (void)opaque, (void)address, (void)items, (void)size; -- return MZ_REALLOC(address, items * size); --} -+// void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) -+// { -+// (void)opaque, (void)address, (void)items, (void)size; -+// return MZ_REALLOC(address, items * size); -+// } - --const char *mz_version(void) --{ -- return MZ_VERSION; --} -+// const char *mz_version(void) -+// { -+// return MZ_VERSION; -+// } - - #ifndef MINIZ_NO_ZLIB_APIS - -@@ -221,14 +221,14 @@ int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, - return MZ_OK; - } - --int mz_deflateReset(mz_streamp pStream) --{ -- if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) -- return MZ_STREAM_ERROR; -- pStream->total_in = pStream->total_out = 0; -- tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); -- return MZ_OK; --} -+// int mz_deflateReset(mz_streamp pStream) -+// { -+// if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) -+// return MZ_STREAM_ERROR; -+// pStream->total_in = pStream->total_out = 0; -+// tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); -+// return MZ_OK; -+// } - - int mz_deflate(mz_streamp pStream, int flush) - { -@@ -300,12 +300,12 @@ int mz_deflateEnd(mz_streamp pStream) - return MZ_OK; - } - --mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) --{ -- (void)pStream; -- /* This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) */ -- return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); --} -+// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) -+// { -+// (void)pStream; -+// This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) -+// return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); -+// } - - int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) - { -@@ -342,10 +342,10 @@ int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char * - return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); - } - --mz_ulong mz_compressBound(mz_ulong source_len) --{ -- return mz_deflateBound(NULL, source_len); --} -+// mz_ulong mz_compressBound(mz_ulong source_len) -+// { -+// return mz_deflateBound(NULL, source_len); -+// } - - typedef struct - { -@@ -551,22 +551,22 @@ int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char - return mz_inflateEnd(&stream); - } - --const char *mz_error(int err) --{ -- static struct -- { -- int m_err; -- const char *m_pDesc; -- } s_error_descs[] = -- { -- { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } -- }; -- mz_uint i; -- for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) -- if (s_error_descs[i].m_err == err) -- return s_error_descs[i].m_pDesc; -- return NULL; --} -+// const char *mz_error(int err) -+// { -+// static struct -+// { -+// int m_err; -+// const char *m_pDesc; -+// } s_error_descs[] = -+// { -+// { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } -+// }; -+// mz_uint i; -+// for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) -+// if (s_error_descs[i].m_err == err) -+// return s_error_descs[i].m_pDesc; -+// return NULL; -+// } - - #endif /*MINIZ_NO_ZLIB_APIS */ - -@@ -1049,7 +1049,7 @@ static void tdefl_start_static_block(tdefl_compressor *d) - TDEFL_PUT_BITS(1, 2); - } - --static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; -+static const mz_uint16 mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; - - #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS - static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) -@@ -1358,7 +1358,6 @@ static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p) - #endif - static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) - { -- printf("\n--------------------------------------------------- DEBUG ---------------------------------------\n"); - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; - mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; -@@ -1456,176 +1455,176 @@ static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahe - } - #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ - --#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN --static mz_bool tdefl_compress_fast(tdefl_compressor *d) --{ -- /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ -- mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; -- mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; -- mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; -+// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -+// static mz_bool tdefl_compress_fast(tdefl_compressor *d) -+// { -+// /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ -+// mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; -+// mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; -+// mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - -- while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) -- { -- const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; -- mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; -- mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); -- d->m_src_buf_left -= num_bytes_to_process; -- lookahead_size += num_bytes_to_process; -+// while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) -+// { -+// const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; -+// mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; -+// mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); -+// d->m_src_buf_left -= num_bytes_to_process; -+// lookahead_size += num_bytes_to_process; - -- while (num_bytes_to_process) -- { -- mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); -- memcpy(d->m_dict + dst_pos, d->m_pSrc, n); -- if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) -- memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); -- d->m_pSrc += n; -- dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; -- num_bytes_to_process -= n; -- } -+// while (num_bytes_to_process) -+// { -+// mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); -+// memcpy(d->m_dict + dst_pos, d->m_pSrc, n); -+// if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) -+// memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); -+// d->m_pSrc += n; -+// dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; -+// num_bytes_to_process -= n; -+// } - -- dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); -- if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) -- break; -+// dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); -+// if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) -+// break; - -- while (lookahead_size >= 4) -- { -- mz_uint cur_match_dist, cur_match_len = 1; -- mz_uint8 *pCur_dict = d->m_dict + cur_pos; -- mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; -- mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; -- mz_uint probe_pos = d->m_hash[hash]; -- d->m_hash[hash] = (mz_uint16)lookahead_pos; -- -- if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) -- { -- const mz_uint16 *p = (const mz_uint16 *)pCur_dict; -- const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); -- mz_uint32 probe_len = 32; -- do -- { -- } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && -- (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); -- cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); -- if (!probe_len) -- cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; -+// while (lookahead_size >= 4) -+// { -+// mz_uint cur_match_dist, cur_match_len = 1; -+// mz_uint8 *pCur_dict = d->m_dict + cur_pos; -+// mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; -+// mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; -+// mz_uint probe_pos = d->m_hash[hash]; -+// d->m_hash[hash] = (mz_uint16)lookahead_pos; -+ -+// if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) -+// { -+// const mz_uint16 *p = (const mz_uint16 *)pCur_dict; -+// const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); -+// mz_uint32 probe_len = 32; -+// do -+// { -+// } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && -+// (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); -+// cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); -+// if (!probe_len) -+// cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; - -- if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) -- { -- cur_match_len = 1; -- *pLZ_code_buf++ = (mz_uint8)first_trigram; -- *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -- d->m_huff_count[0][(mz_uint8)first_trigram]++; -- } -- else -- { -- mz_uint32 s0, s1; -- cur_match_len = MZ_MIN(cur_match_len, lookahead_size); -+// if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) -+// { -+// cur_match_len = 1; -+// *pLZ_code_buf++ = (mz_uint8)first_trigram; -+// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -+// d->m_huff_count[0][(mz_uint8)first_trigram]++; -+// } -+// else -+// { -+// mz_uint32 s0, s1; -+// cur_match_len = MZ_MIN(cur_match_len, lookahead_size); - -- MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); -+// MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); - -- cur_match_dist--; -+// cur_match_dist--; - -- pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); -- *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; -- pLZ_code_buf += 3; -- *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); -+// pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); -+// *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; -+// pLZ_code_buf += 3; -+// *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); - -- s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; -- s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; -- d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; -+// s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; -+// s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; -+// d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; - -- d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; -- } -- } -- else -- { -- *pLZ_code_buf++ = (mz_uint8)first_trigram; -- *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -- d->m_huff_count[0][(mz_uint8)first_trigram]++; -- } -+// d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; -+// } -+// } -+// else -+// { -+// *pLZ_code_buf++ = (mz_uint8)first_trigram; -+// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -+// d->m_huff_count[0][(mz_uint8)first_trigram]++; -+// } - -- if (--num_flags_left == 0) -- { -- num_flags_left = 8; -- pLZ_flags = pLZ_code_buf++; -- } -+// if (--num_flags_left == 0) -+// { -+// num_flags_left = 8; -+// pLZ_flags = pLZ_code_buf++; -+// } - -- total_lz_bytes += cur_match_len; -- lookahead_pos += cur_match_len; -- dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); -- cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; -- MZ_ASSERT(lookahead_size >= cur_match_len); -- lookahead_size -= cur_match_len; -+// total_lz_bytes += cur_match_len; -+// lookahead_pos += cur_match_len; -+// dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); -+// cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; -+// MZ_ASSERT(lookahead_size >= cur_match_len); -+// lookahead_size -= cur_match_len; - -- if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) -- { -- int n; -- d->m_lookahead_pos = lookahead_pos; -- d->m_lookahead_size = lookahead_size; -- d->m_dict_size = dict_size; -- d->m_total_lz_bytes = total_lz_bytes; -- d->m_pLZ_code_buf = pLZ_code_buf; -- d->m_pLZ_flags = pLZ_flags; -- d->m_num_flags_left = num_flags_left; -- if ((n = tdefl_flush_block(d, 0)) != 0) -- return (n < 0) ? MZ_FALSE : MZ_TRUE; -- total_lz_bytes = d->m_total_lz_bytes; -- pLZ_code_buf = d->m_pLZ_code_buf; -- pLZ_flags = d->m_pLZ_flags; -- num_flags_left = d->m_num_flags_left; -- } -- } -+// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) -+// { -+// int n; -+// d->m_lookahead_pos = lookahead_pos; -+// d->m_lookahead_size = lookahead_size; -+// d->m_dict_size = dict_size; -+// d->m_total_lz_bytes = total_lz_bytes; -+// d->m_pLZ_code_buf = pLZ_code_buf; -+// d->m_pLZ_flags = pLZ_flags; -+// d->m_num_flags_left = num_flags_left; -+// if ((n = tdefl_flush_block(d, 0)) != 0) -+// return (n < 0) ? MZ_FALSE : MZ_TRUE; -+// total_lz_bytes = d->m_total_lz_bytes; -+// pLZ_code_buf = d->m_pLZ_code_buf; -+// pLZ_flags = d->m_pLZ_flags; -+// num_flags_left = d->m_num_flags_left; -+// } -+// } - -- while (lookahead_size) -- { -- mz_uint8 lit = d->m_dict[cur_pos]; -+// while (lookahead_size) -+// { -+// mz_uint8 lit = d->m_dict[cur_pos]; - -- total_lz_bytes++; -- *pLZ_code_buf++ = lit; -- *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -- if (--num_flags_left == 0) -- { -- num_flags_left = 8; -- pLZ_flags = pLZ_code_buf++; -- } -+// total_lz_bytes++; -+// *pLZ_code_buf++ = lit; -+// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -+// if (--num_flags_left == 0) -+// { -+// num_flags_left = 8; -+// pLZ_flags = pLZ_code_buf++; -+// } - -- d->m_huff_count[0][lit]++; -+// d->m_huff_count[0][lit]++; - -- lookahead_pos++; -- dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); -- cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; -- lookahead_size--; -+// lookahead_pos++; -+// dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); -+// cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; -+// lookahead_size--; - -- if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) -- { -- int n; -- d->m_lookahead_pos = lookahead_pos; -- d->m_lookahead_size = lookahead_size; -- d->m_dict_size = dict_size; -- d->m_total_lz_bytes = total_lz_bytes; -- d->m_pLZ_code_buf = pLZ_code_buf; -- d->m_pLZ_flags = pLZ_flags; -- d->m_num_flags_left = num_flags_left; -- if ((n = tdefl_flush_block(d, 0)) != 0) -- return (n < 0) ? MZ_FALSE : MZ_TRUE; -- total_lz_bytes = d->m_total_lz_bytes; -- pLZ_code_buf = d->m_pLZ_code_buf; -- pLZ_flags = d->m_pLZ_flags; -- num_flags_left = d->m_num_flags_left; -- } -- } -- } -+// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) -+// { -+// int n; -+// d->m_lookahead_pos = lookahead_pos; -+// d->m_lookahead_size = lookahead_size; -+// d->m_dict_size = dict_size; -+// d->m_total_lz_bytes = total_lz_bytes; -+// d->m_pLZ_code_buf = pLZ_code_buf; -+// d->m_pLZ_flags = pLZ_flags; -+// d->m_num_flags_left = num_flags_left; -+// if ((n = tdefl_flush_block(d, 0)) != 0) -+// return (n < 0) ? MZ_FALSE : MZ_TRUE; -+// total_lz_bytes = d->m_total_lz_bytes; -+// pLZ_code_buf = d->m_pLZ_code_buf; -+// pLZ_flags = d->m_pLZ_flags; -+// num_flags_left = d->m_num_flags_left; -+// } -+// } -+// } - -- d->m_lookahead_pos = lookahead_pos; -- d->m_lookahead_size = lookahead_size; -- d->m_dict_size = dict_size; -- d->m_total_lz_bytes = total_lz_bytes; -- d->m_pLZ_code_buf = pLZ_code_buf; -- d->m_pLZ_flags = pLZ_flags; -- d->m_num_flags_left = num_flags_left; -- return MZ_TRUE; --} --#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ -+// d->m_lookahead_pos = lookahead_pos; -+// d->m_lookahead_size = lookahead_size; -+// d->m_dict_size = dict_size; -+// d->m_total_lz_bytes = total_lz_bytes; -+// d->m_pLZ_code_buf = pLZ_code_buf; -+// d->m_pLZ_flags = pLZ_flags; -+// d->m_num_flags_left = num_flags_left; -+// return MZ_TRUE; -+// } -+// #endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ - - static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) - { -@@ -1870,16 +1869,16 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI - if ((d->m_output_flush_remaining) || (d->m_finished)) - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); - --#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -- if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && -- ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && -- ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) -- { -- if (!tdefl_compress_fast(d)) -- return d->m_prev_return_status; -- } -- else --#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ -+// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -+// if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && -+// ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && -+// ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) -+// { -+// if (!tdefl_compress_fast(d)) -+// return d->m_prev_return_status; -+// } -+// else -+// #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ - { - if (!tdefl_compress_normal(d)) - return d->m_prev_return_status; -@@ -1904,11 +1903,11 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); - } - --tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) --{ -- MZ_ASSERT(d->m_pPut_buf_func); -- return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); --} -+// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) -+// { -+// MZ_ASSERT(d->m_pPut_buf_func); -+// return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); -+// } - - tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) - { -@@ -1944,92 +1943,92 @@ tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_fun - return TDEFL_STATUS_OKAY; - } - --tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) --{ -- return d->m_prev_return_status; --} -+// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) -+// { -+// return d->m_prev_return_status; -+// } - - mz_uint32 tdefl_get_adler32(tdefl_compressor *d) - { - return d->m_adler32; - } - --mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) --{ -- tdefl_compressor *pComp; -- mz_bool succeeded; -- if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) -- return MZ_FALSE; -- pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -- if (!pComp) -- return MZ_FALSE; -- succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); -- succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); -- MZ_FREE(pComp); -- return succeeded; --} -+// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -+// { -+// tdefl_compressor *pComp; -+// mz_bool succeeded; -+// if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) -+// return MZ_FALSE; -+// pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -+// if (!pComp) -+// return MZ_FALSE; -+// succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); -+// succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); -+// MZ_FREE(pComp); -+// return succeeded; -+// } - --typedef struct --{ -- size_t m_size, m_capacity; -- mz_uint8 *m_pBuf; -- mz_bool m_expandable; --} tdefl_output_buffer; -+// typedef struct -+// { -+// size_t m_size, m_capacity; -+// mz_uint8 *m_pBuf; -+// mz_bool m_expandable; -+// } tdefl_output_buffer; - --static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) --{ -- tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; -- size_t new_size = p->m_size + len; -- if (new_size > p->m_capacity) -- { -- size_t new_capacity = p->m_capacity; -- mz_uint8 *pNew_buf; -- if (!p->m_expandable) -- return MZ_FALSE; -- do -- { -- new_capacity = MZ_MAX(128U, new_capacity << 1U); -- } while (new_size > new_capacity); -- pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); -- if (!pNew_buf) -- return MZ_FALSE; -- p->m_pBuf = pNew_buf; -- p->m_capacity = new_capacity; -- } -- memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); -- p->m_size = new_size; -- return MZ_TRUE; --} -+// static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) -+// { -+// tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; -+// size_t new_size = p->m_size + len; -+// if (new_size > p->m_capacity) -+// { -+// size_t new_capacity = p->m_capacity; -+// mz_uint8 *pNew_buf; -+// if (!p->m_expandable) -+// return MZ_FALSE; -+// do -+// { -+// new_capacity = MZ_MAX(128U, new_capacity << 1U); -+// } while (new_size > new_capacity); -+// pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); -+// if (!pNew_buf) -+// return MZ_FALSE; -+// p->m_pBuf = pNew_buf; -+// p->m_capacity = new_capacity; -+// } -+// memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); -+// p->m_size = new_size; -+// return MZ_TRUE; -+// } - --void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) --{ -- tdefl_output_buffer out_buf; -- MZ_CLEAR_OBJ(out_buf); -- if (!pOut_len) -- return MZ_FALSE; -- else -- *pOut_len = 0; -- out_buf.m_expandable = MZ_TRUE; -- if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) -- return NULL; -- *pOut_len = out_buf.m_size; -- return out_buf.m_pBuf; --} -+// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -+// { -+// tdefl_output_buffer out_buf; -+// MZ_CLEAR_OBJ(out_buf); -+// if (!pOut_len) -+// return MZ_FALSE; -+// else -+// *pOut_len = 0; -+// out_buf.m_expandable = MZ_TRUE; -+// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) -+// return NULL; -+// *pOut_len = out_buf.m_size; -+// return out_buf.m_pBuf; -+// } - --size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) --{ -- tdefl_output_buffer out_buf; -- MZ_CLEAR_OBJ(out_buf); -- if (!pOut_buf) -- return 0; -- out_buf.m_pBuf = (mz_uint8 *)pOut_buf; -- out_buf.m_capacity = out_buf_len; -- if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) -- return 0; -- return out_buf.m_size; --} -+// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -+// { -+// tdefl_output_buffer out_buf; -+// MZ_CLEAR_OBJ(out_buf); -+// if (!pOut_buf) -+// return 0; -+// out_buf.m_pBuf = (mz_uint8 *)pOut_buf; -+// out_buf.m_capacity = out_buf_len; -+// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) -+// return 0; -+// return out_buf.m_size; -+// } - --static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; -+static const mz_uint16 s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; - - /* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */ - mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) -@@ -2060,102 +2059,102 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int - /* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at - http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. - This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ --void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) --{ -- /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ -- static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; -- tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -- tdefl_output_buffer out_buf; -- int i, bpl = w * num_chans, y, z; -- mz_uint32 c; -- *pLen_out = 0; -- if (!pComp) -- return NULL; -- MZ_CLEAR_OBJ(out_buf); -- out_buf.m_expandable = MZ_TRUE; -- out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); -- if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) -- { -- MZ_FREE(pComp); -- return NULL; -- } -- /* write dummy header */ -- for (z = 41; z; --z) -- tdefl_output_buffer_putter(&z, 1, &out_buf); -- /* compress image data */ -- tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); -- for (y = 0; y < h; ++y) -- { -- tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); -- tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); -- } -- if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) -- { -- MZ_FREE(pComp); -- MZ_FREE(out_buf.m_pBuf); -- return NULL; -- } -- /* write real header */ -- *pLen_out = out_buf.m_size - 41; -- { -- static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; -- mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, -- 0x0a, 0x1a, 0x0a, 0x00, 0x00, -- 0x00, 0x0d, 0x49, 0x48, 0x44, -- 0x52, 0x00, 0x00, 0x00, 0x00, -- 0x00, 0x00, 0x00, 0x00, 0x08, -- 0x00, 0x00, 0x00, 0x00, 0x00, -- 0x00, 0x00, 0x00, 0x00, 0x00, -- 0x00, 0x00, 0x49, 0x44, 0x41, -- 0x54 }; -- pnghdr[18] = (mz_uint8)(w >> 8); -- pnghdr[19] = (mz_uint8)w; -- pnghdr[22] = (mz_uint8)(h >> 8); -- pnghdr[23] = (mz_uint8)h; -- pnghdr[25] = chans[num_chans]; -- pnghdr[33] = (mz_uint8)(*pLen_out >> 24); -- pnghdr[34] = (mz_uint8)(*pLen_out >> 16); -- pnghdr[35] = (mz_uint8)(*pLen_out >> 8); -- pnghdr[36] = (mz_uint8)*pLen_out; -- c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); -- for (i = 0; i < 4; ++i, c <<= 8) -- ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); -- memcpy(out_buf.m_pBuf, pnghdr, 41); -- } -- /* write footer (IDAT CRC-32, followed by IEND chunk) */ -- if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) -- { -- *pLen_out = 0; -- MZ_FREE(pComp); -- MZ_FREE(out_buf.m_pBuf); -- return NULL; -- } -- c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); -- for (i = 0; i < 4; ++i, c <<= 8) -- (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); -- /* compute final size of file, grab compressed data buffer and return */ -- *pLen_out += 57; -- MZ_FREE(pComp); -- return out_buf.m_pBuf; --} --void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) --{ -+// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) -+// { -+// /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ -+// static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; -+// tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -+// tdefl_output_buffer out_buf; -+// int i, bpl = w * num_chans, y, z; -+// mz_uint32 c; -+// *pLen_out = 0; -+// if (!pComp) -+// return NULL; -+// MZ_CLEAR_OBJ(out_buf); -+// out_buf.m_expandable = MZ_TRUE; -+// out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); -+// if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) -+// { -+// MZ_FREE(pComp); -+// return NULL; -+// } -+// /* write dummy header */ -+// for (z = 41; z; --z) -+// tdefl_output_buffer_putter(&z, 1, &out_buf); -+// /* compress image data */ -+// tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); -+// for (y = 0; y < h; ++y) -+// { -+// tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); -+// tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); -+// } -+// if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) -+// { -+// MZ_FREE(pComp); -+// MZ_FREE(out_buf.m_pBuf); -+// return NULL; -+// } -+// /* write real header */ -+// *pLen_out = out_buf.m_size - 41; -+// { -+// static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; -+// mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, -+// 0x0a, 0x1a, 0x0a, 0x00, 0x00, -+// 0x00, 0x0d, 0x49, 0x48, 0x44, -+// 0x52, 0x00, 0x00, 0x00, 0x00, -+// 0x00, 0x00, 0x00, 0x00, 0x08, -+// 0x00, 0x00, 0x00, 0x00, 0x00, -+// 0x00, 0x00, 0x00, 0x00, 0x00, -+// 0x00, 0x00, 0x49, 0x44, 0x41, -+// 0x54 }; -+// pnghdr[18] = (mz_uint8)(w >> 8); -+// pnghdr[19] = (mz_uint8)w; -+// pnghdr[22] = (mz_uint8)(h >> 8); -+// pnghdr[23] = (mz_uint8)h; -+// pnghdr[25] = chans[num_chans]; -+// pnghdr[33] = (mz_uint8)(*pLen_out >> 24); -+// pnghdr[34] = (mz_uint8)(*pLen_out >> 16); -+// pnghdr[35] = (mz_uint8)(*pLen_out >> 8); -+// pnghdr[36] = (mz_uint8)*pLen_out; -+// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); -+// for (i = 0; i < 4; ++i, c <<= 8) -+// ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); -+// memcpy(out_buf.m_pBuf, pnghdr, 41); -+// } -+// /* write footer (IDAT CRC-32, followed by IEND chunk) */ -+// if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) -+// { -+// *pLen_out = 0; -+// MZ_FREE(pComp); -+// MZ_FREE(out_buf.m_pBuf); -+// return NULL; -+// } -+// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); -+// for (i = 0; i < 4; ++i, c <<= 8) -+// (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); -+// /* compute final size of file, grab compressed data buffer and return */ -+// *pLen_out += 57; -+// MZ_FREE(pComp); -+// return out_buf.m_pBuf; -+// } -+// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) -+// { - /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */ -- return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); --} -+// return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); -+// } - - /* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ - /* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ - /* structure size and allocation mechanism. */ --tdefl_compressor *tdefl_compressor_alloc() --{ -- return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); --} -+// tdefl_compressor *tdefl_compressor_alloc() -+// { -+// return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -+// } - --void tdefl_compressor_free(tdefl_compressor *pComp) --{ -- MZ_FREE(pComp); --} -+// void tdefl_compressor_free(tdefl_compressor *pComp) -+// { -+// MZ_FREE(pComp); -+// } - - #ifdef _MSC_VER - #pragma warning(pop) -@@ -2339,12 +2338,12 @@ extern "C" { - - tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) - { -- static const int s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; -- static const int s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; -- static const int s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; -- static const int s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; -+ static const mz_uint16 s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; -+ static const mz_uint8 s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; -+ static const mz_uint16 s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; -+ static const mz_uint8 s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; - static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; -- static const int s_min_table_sizes[3] = { 257, 1, 4 }; -+ static const mz_uint16 s_min_table_sizes[3] = { 257, 1, 4 }; - - tinfl_status status = TINFL_STATUS_FAILED; - mz_uint32 num_bits, dist, counter, num_extra; -@@ -2805,94 +2804,94 @@ common_exit: - } - - /* Higher level helper functions. */ --void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) --{ -- tinfl_decompressor decomp; -- void *pBuf = NULL, *pNew_buf; -- size_t src_buf_ofs = 0, out_buf_capacity = 0; -- *pOut_len = 0; -- tinfl_init(&decomp); -- for (;;) -- { -- size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; -- tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, -- (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); -- if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) -- { -- MZ_FREE(pBuf); -- *pOut_len = 0; -- return NULL; -- } -- src_buf_ofs += src_buf_size; -- *pOut_len += dst_buf_size; -- if (status == TINFL_STATUS_DONE) -- break; -- new_out_buf_capacity = out_buf_capacity * 2; -- if (new_out_buf_capacity < 128) -- new_out_buf_capacity = 128; -- pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); -- if (!pNew_buf) -- { -- MZ_FREE(pBuf); -- *pOut_len = 0; -- return NULL; -- } -- pBuf = pNew_buf; -- out_buf_capacity = new_out_buf_capacity; -- } -- return pBuf; --} -+// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -+// { -+// tinfl_decompressor decomp; -+// void *pBuf = NULL, *pNew_buf; -+// size_t src_buf_ofs = 0, out_buf_capacity = 0; -+// *pOut_len = 0; -+// tinfl_init(&decomp); -+// for (;;) -+// { -+// size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; -+// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, -+// (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); -+// if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) -+// { -+// MZ_FREE(pBuf); -+// *pOut_len = 0; -+// return NULL; -+// } -+// src_buf_ofs += src_buf_size; -+// *pOut_len += dst_buf_size; -+// if (status == TINFL_STATUS_DONE) -+// break; -+// new_out_buf_capacity = out_buf_capacity * 2; -+// if (new_out_buf_capacity < 128) -+// new_out_buf_capacity = 128; -+// pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); -+// if (!pNew_buf) -+// { -+// MZ_FREE(pBuf); -+// *pOut_len = 0; -+// return NULL; -+// } -+// pBuf = pNew_buf; -+// out_buf_capacity = new_out_buf_capacity; -+// } -+// return pBuf; -+// } - --size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) --{ -- tinfl_decompressor decomp; -- tinfl_status status; -- tinfl_init(&decomp); -- status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); -- return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; --} -+// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -+// { -+// tinfl_decompressor decomp; -+// tinfl_status status; -+// tinfl_init(&decomp); -+// status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); -+// return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; -+// } - --int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) --{ -- int result = 0; -- tinfl_decompressor decomp; -- mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); -- size_t in_buf_ofs = 0, dict_ofs = 0; -- if (!pDict) -- return TINFL_STATUS_FAILED; -- tinfl_init(&decomp); -- for (;;) -- { -- size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; -- tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, -- (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); -- in_buf_ofs += in_buf_size; -- if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) -- break; -- if (status != TINFL_STATUS_HAS_MORE_OUTPUT) -- { -- result = (status == TINFL_STATUS_DONE); -- break; -- } -- dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); -- } -- MZ_FREE(pDict); -- *pIn_buf_size = in_buf_ofs; -- return result; --} -+// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -+// { -+// int result = 0; -+// tinfl_decompressor decomp; -+// mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); -+// size_t in_buf_ofs = 0, dict_ofs = 0; -+// if (!pDict) -+// return TINFL_STATUS_FAILED; -+// tinfl_init(&decomp); -+// for (;;) -+// { -+// size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; -+// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, -+// (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); -+// in_buf_ofs += in_buf_size; -+// if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) -+// break; -+// if (status != TINFL_STATUS_HAS_MORE_OUTPUT) -+// { -+// result = (status == TINFL_STATUS_DONE); -+// break; -+// } -+// dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); -+// } -+// MZ_FREE(pDict); -+// *pIn_buf_size = in_buf_ofs; -+// return result; -+// } - --tinfl_decompressor *tinfl_decompressor_alloc() --{ -- tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); -- if (pDecomp) -- tinfl_init(pDecomp); -- return pDecomp; --} -+// tinfl_decompressor *tinfl_decompressor_alloc() -+// { -+// tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); -+// if (pDecomp) -+// tinfl_init(pDecomp); -+// return pDecomp; -+// } - --void tinfl_decompressor_free(tinfl_decompressor *pDecomp) --{ -- MZ_FREE(pDecomp); --} -+// void tinfl_decompressor_free(tinfl_decompressor *pDecomp) -+// { -+// MZ_FREE(pDecomp); -+// } - - #ifdef __cplusplus - } -@@ -2925,461 +2924,461 @@ void tinfl_decompressor_free(tinfl_decompressor *pDecomp) - **************************************************************************/ - - --#ifndef MINIZ_NO_ARCHIVE_APIS -+// #ifndef MINIZ_NO_ARCHIVE_APIS - --#ifdef __cplusplus --extern "C" { --#endif -+// #ifdef __cplusplus -+// extern "C" { -+// #endif - - /* ------------------- .ZIP archive reading */ - --#ifdef MINIZ_NO_STDIO --#define MZ_FILE void * --#else --#include -+// #ifdef MINIZ_NO_STDIO -+// #define MZ_FILE void * -+// #else -+// #include - --#if defined(_MSC_VER) || defined(__MINGW64__) --static FILE *mz_fopen(const char *pFilename, const char *pMode) --{ -- FILE *pFile = NULL; -- fopen_s(&pFile, pFilename, pMode); -- return pFile; --} --static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) --{ -- FILE *pFile = NULL; -- if (freopen_s(&pFile, pPath, pMode, pStream)) -- return NULL; -- return pFile; --} --#ifndef MINIZ_NO_TIME --#include --#endif --#define MZ_FOPEN mz_fopen --#define MZ_FCLOSE fclose --#define MZ_FREAD fread --#define MZ_FWRITE fwrite --#define MZ_FTELL64 _ftelli64 --#define MZ_FSEEK64 _fseeki64 --#define MZ_FILE_STAT_STRUCT _stat --#define MZ_FILE_STAT _stat --#define MZ_FFLUSH fflush --#define MZ_FREOPEN mz_freopen --#define MZ_DELETE_FILE remove --#elif defined(__MINGW32__) --#ifndef MINIZ_NO_TIME --#include --#endif --#define MZ_FOPEN(f, m) fopen(f, m) --#define MZ_FCLOSE fclose --#define MZ_FREAD fread --#define MZ_FWRITE fwrite --#define MZ_FTELL64 ftello64 --#define MZ_FSEEK64 fseeko64 --#define MZ_FILE_STAT_STRUCT _stat --#define MZ_FILE_STAT _stat --#define MZ_FFLUSH fflush --#define MZ_FREOPEN(f, m, s) freopen(f, m, s) --#define MZ_DELETE_FILE remove --#elif defined(__TINYC__) --#ifndef MINIZ_NO_TIME --#include --#endif --#define MZ_FOPEN(f, m) fopen(f, m) --#define MZ_FCLOSE fclose --#define MZ_FREAD fread --#define MZ_FWRITE fwrite --#define MZ_FTELL64 ftell --#define MZ_FSEEK64 fseek --#define MZ_FILE_STAT_STRUCT stat --#define MZ_FILE_STAT stat --#define MZ_FFLUSH fflush --#define MZ_FREOPEN(f, m, s) freopen(f, m, s) --#define MZ_DELETE_FILE remove --#elif defined(__GNUC__) && _LARGEFILE64_SOURCE --#ifndef MINIZ_NO_TIME --#include --#endif --#define MZ_FOPEN(f, m) fopen64(f, m) --#define MZ_FCLOSE fclose --#define MZ_FREAD fread --#define MZ_FWRITE fwrite --#define MZ_FTELL64 ftello64 --#define MZ_FSEEK64 fseeko64 --#define MZ_FILE_STAT_STRUCT stat64 --#define MZ_FILE_STAT stat64 --#define MZ_FFLUSH fflush --#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) --#define MZ_DELETE_FILE remove --#elif defined(__APPLE__) && _LARGEFILE64_SOURCE --#ifndef MINIZ_NO_TIME --#include --#endif --#define MZ_FOPEN(f, m) fopen(f, m) --#define MZ_FCLOSE fclose --#define MZ_FREAD fread --#define MZ_FWRITE fwrite --#define MZ_FTELL64 ftello --#define MZ_FSEEK64 fseeko --#define MZ_FILE_STAT_STRUCT stat --#define MZ_FILE_STAT stat --#define MZ_FFLUSH fflush --#define MZ_FREOPEN(p, m, s) freopen(p, m, s) --#define MZ_DELETE_FILE remove -+// #if defined(_MSC_VER) || defined(__MINGW64__) -+// static FILE *mz_fopen(const char *pFilename, const char *pMode) -+// { -+// FILE *pFile = NULL; -+// fopen_s(&pFile, pFilename, pMode); -+// return pFile; -+// } -+// static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) -+// { -+// FILE *pFile = NULL; -+// if (freopen_s(&pFile, pPath, pMode, pStream)) -+// return NULL; -+// return pFile; -+// } -+// #ifndef MINIZ_NO_TIME -+// #include -+// #endif -+// #define MZ_FOPEN mz_fopen -+// #define MZ_FCLOSE fclose -+// #define MZ_FREAD fread -+// #define MZ_FWRITE fwrite -+// #define MZ_FTELL64 _ftelli64 -+// #define MZ_FSEEK64 _fseeki64 -+// #define MZ_FILE_STAT_STRUCT _stat -+// #define MZ_FILE_STAT _stat -+// #define MZ_FFLUSH fflush -+// #define MZ_FREOPEN mz_freopen -+// #define MZ_DELETE_FILE remove -+// #elif defined(__MINGW32__) -+// #ifndef MINIZ_NO_TIME -+// #include -+// #endif -+// #define MZ_FOPEN(f, m) fopen(f, m) -+// #define MZ_FCLOSE fclose -+// #define MZ_FREAD fread -+// #define MZ_FWRITE fwrite -+// #define MZ_FTELL64 ftello64 -+// #define MZ_FSEEK64 fseeko64 -+// #define MZ_FILE_STAT_STRUCT _stat -+// #define MZ_FILE_STAT _stat -+// #define MZ_FFLUSH fflush -+// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) -+// #define MZ_DELETE_FILE remove -+// #elif defined(__TINYC__) -+// #ifndef MINIZ_NO_TIME -+// #include -+// #endif -+// #define MZ_FOPEN(f, m) fopen(f, m) -+// #define MZ_FCLOSE fclose -+// #define MZ_FREAD fread -+// #define MZ_FWRITE fwrite -+// #define MZ_FTELL64 ftell -+// #define MZ_FSEEK64 fseek -+// #define MZ_FILE_STAT_STRUCT stat -+// #define MZ_FILE_STAT stat -+// #define MZ_FFLUSH fflush -+// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) -+// #define MZ_DELETE_FILE remove -+// #elif defined(__GNUC__) && _LARGEFILE64_SOURCE -+// #ifndef MINIZ_NO_TIME -+// #include -+// #endif -+// #define MZ_FOPEN(f, m) fopen64(f, m) -+// #define MZ_FCLOSE fclose -+// #define MZ_FREAD fread -+// #define MZ_FWRITE fwrite -+// #define MZ_FTELL64 ftello64 -+// #define MZ_FSEEK64 fseeko64 -+// #define MZ_FILE_STAT_STRUCT stat64 -+// #define MZ_FILE_STAT stat64 -+// #define MZ_FFLUSH fflush -+// #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) -+// #define MZ_DELETE_FILE remove -+// #elif defined(__APPLE__) && _LARGEFILE64_SOURCE -+// #ifndef MINIZ_NO_TIME -+// #include -+// #endif -+// #define MZ_FOPEN(f, m) fopen(f, m) -+// #define MZ_FCLOSE fclose -+// #define MZ_FREAD fread -+// #define MZ_FWRITE fwrite -+// #define MZ_FTELL64 ftello -+// #define MZ_FSEEK64 fseeko -+// #define MZ_FILE_STAT_STRUCT stat -+// #define MZ_FILE_STAT stat -+// #define MZ_FFLUSH fflush -+// #define MZ_FREOPEN(p, m, s) freopen(p, m, s) -+// #define MZ_DELETE_FILE remove -+ -+// #else -+// // #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") -+// #ifndef MINIZ_NO_TIME -+// #include -+// #endif -+// #define MZ_FOPEN(f, m) fopen(f, m) -+// #define MZ_FCLOSE fclose -+// #define MZ_FREAD fread -+// #define MZ_FWRITE fwrite -+// #ifdef __STRICT_ANSI__ -+// #define MZ_FTELL64 ftell -+// #define MZ_FSEEK64 fseek -+// #else -+// #define MZ_FTELL64 ftello -+// #define MZ_FSEEK64 fseeko -+// #endif -+// #define MZ_FILE_STAT_STRUCT stat -+// #define MZ_FILE_STAT stat -+// #define MZ_FFLUSH fflush -+// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) -+// #define MZ_DELETE_FILE remove -+// #endif /* #ifdef _MSC_VER */ -+// #endif /* #ifdef MINIZ_NO_STDIO */ -+ -+// #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) - --#else --// #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") --#ifndef MINIZ_NO_TIME --#include --#endif --#define MZ_FOPEN(f, m) fopen(f, m) --#define MZ_FCLOSE fclose --#define MZ_FREAD fread --#define MZ_FWRITE fwrite --#ifdef __STRICT_ANSI__ --#define MZ_FTELL64 ftell --#define MZ_FSEEK64 fseek --#else --#define MZ_FTELL64 ftello --#define MZ_FSEEK64 fseeko --#endif --#define MZ_FILE_STAT_STRUCT stat --#define MZ_FILE_STAT stat --#define MZ_FFLUSH fflush --#define MZ_FREOPEN(f, m, s) freopen(f, m, s) --#define MZ_DELETE_FILE remove --#endif /* #ifdef _MSC_VER */ --#endif /* #ifdef MINIZ_NO_STDIO */ -+/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ -+// enum -+// { -+// /* ZIP archive identifiers and record sizes */ -+// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, -+// MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, -+// MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, -+// MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, -+// MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, -+// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, -+ -+// /* ZIP64 archive identifier and record sizes */ -+// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, -+// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, -+// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, -+// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, -+// MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, -+// MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, -+// MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, -+// MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, -+ -+// /* Central directory header record offsets */ -+// MZ_ZIP_CDH_SIG_OFS = 0, -+// MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, -+// MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, -+// MZ_ZIP_CDH_BIT_FLAG_OFS = 8, -+// MZ_ZIP_CDH_METHOD_OFS = 10, -+// MZ_ZIP_CDH_FILE_TIME_OFS = 12, -+// MZ_ZIP_CDH_FILE_DATE_OFS = 14, -+// MZ_ZIP_CDH_CRC32_OFS = 16, -+// MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, -+// MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, -+// MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, -+// MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, -+// MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, -+// MZ_ZIP_CDH_DISK_START_OFS = 34, -+// MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, -+// MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, -+// MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, -+ -+// /* Local directory header offsets */ -+// MZ_ZIP_LDH_SIG_OFS = 0, -+// MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, -+// MZ_ZIP_LDH_BIT_FLAG_OFS = 6, -+// MZ_ZIP_LDH_METHOD_OFS = 8, -+// MZ_ZIP_LDH_FILE_TIME_OFS = 10, -+// MZ_ZIP_LDH_FILE_DATE_OFS = 12, -+// MZ_ZIP_LDH_CRC32_OFS = 14, -+// MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, -+// MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, -+// MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, -+// MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, -+// MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, -+ -+// /* End of central directory offsets */ -+// MZ_ZIP_ECDH_SIG_OFS = 0, -+// MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, -+// MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, -+// MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, -+// MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, -+// MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, -+// MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, -+// MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, -+ -+// /* ZIP64 End of central directory locator offsets */ -+// MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ -+// MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ -+// MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ -+// MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ -+ -+// /* ZIP64 End of central directory header offsets */ -+// MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ -+// MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ -+// MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ -+// MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ -+// MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ -+// MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ -+// MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ -+// MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ -+// MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ -+// MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ -+// MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, -+// MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, -+// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, -+// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, -+// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, -+// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, -+// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 -+// }; -+ -+// typedef struct -+// { -+// void *m_p; -+// size_t m_size, m_capacity; -+// mz_uint m_element_size; -+// } mz_zip_array; - --#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) -+// struct mz_zip_internal_state_tag -+// { -+// mz_zip_array m_central_dir; -+// mz_zip_array m_central_dir_offsets; -+// mz_zip_array m_sorted_central_dir_offsets; - --/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ --enum --{ -- /* ZIP archive identifiers and record sizes */ -- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, -- MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, -- MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, -- MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, -- MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, -- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, -- -- /* ZIP64 archive identifier and record sizes */ -- MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, -- MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, -- MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, -- MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, -- MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, -- MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, -- MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, -- MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, -- -- /* Central directory header record offsets */ -- MZ_ZIP_CDH_SIG_OFS = 0, -- MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, -- MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, -- MZ_ZIP_CDH_BIT_FLAG_OFS = 8, -- MZ_ZIP_CDH_METHOD_OFS = 10, -- MZ_ZIP_CDH_FILE_TIME_OFS = 12, -- MZ_ZIP_CDH_FILE_DATE_OFS = 14, -- MZ_ZIP_CDH_CRC32_OFS = 16, -- MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, -- MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, -- MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, -- MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, -- MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, -- MZ_ZIP_CDH_DISK_START_OFS = 34, -- MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, -- MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, -- MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, -- -- /* Local directory header offsets */ -- MZ_ZIP_LDH_SIG_OFS = 0, -- MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, -- MZ_ZIP_LDH_BIT_FLAG_OFS = 6, -- MZ_ZIP_LDH_METHOD_OFS = 8, -- MZ_ZIP_LDH_FILE_TIME_OFS = 10, -- MZ_ZIP_LDH_FILE_DATE_OFS = 12, -- MZ_ZIP_LDH_CRC32_OFS = 14, -- MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, -- MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, -- MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, -- MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, -- MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, -- -- /* End of central directory offsets */ -- MZ_ZIP_ECDH_SIG_OFS = 0, -- MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, -- MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, -- MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, -- MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, -- MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, -- MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, -- MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, -- -- /* ZIP64 End of central directory locator offsets */ -- MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ -- MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ -- MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ -- MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ -- -- /* ZIP64 End of central directory header offsets */ -- MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ -- MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ -- MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ -- MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ -- MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ -- MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ -- MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ -- MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ -- MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ -- MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ -- MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, -- MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, -- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, -- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, -- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, -- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, -- MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 --}; -+// /* The flags passed in when the archive is initially opened. */ -+// uint32_t m_init_flags; - --typedef struct --{ -- void *m_p; -- size_t m_size, m_capacity; -- mz_uint m_element_size; --} mz_zip_array; -+// /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ -+// mz_bool m_zip64; - --struct mz_zip_internal_state_tag --{ -- mz_zip_array m_central_dir; -- mz_zip_array m_central_dir_offsets; -- mz_zip_array m_sorted_central_dir_offsets; -+// /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ -+// mz_bool m_zip64_has_extended_info_fields; - -- /* The flags passed in when the archive is initially opened. */ -- uint32_t m_init_flags; -+// /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ -+// MZ_FILE *m_pFile; -+// mz_uint64 m_file_archive_start_ofs; - -- /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ -- mz_bool m_zip64; -+// void *m_pMem; -+// size_t m_mem_size; -+// size_t m_mem_capacity; -+// }; - -- /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ -- mz_bool m_zip64_has_extended_info_fields; -+// #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size - -- /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ -- MZ_FILE *m_pFile; -- mz_uint64 m_file_archive_start_ofs; -+// #if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) -+// static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) -+// { -+// MZ_ASSERT(index < pArray->m_size); -+// return index; -+// } -+// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] -+// #else -+// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] -+// #endif - -- void *m_pMem; -- size_t m_mem_size; -- size_t m_mem_capacity; --}; -+// static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) -+// { -+// memset(pArray, 0, sizeof(mz_zip_array)); -+// pArray->m_element_size = element_size; -+// } - --#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size -+// static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); -+// memset(pArray, 0, sizeof(mz_zip_array)); -+// } - --#if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) --static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) --{ -- MZ_ASSERT(index < pArray->m_size); -- return index; --} --#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] --#else --#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] --#endif -+// static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) -+// { -+// void *pNew_p; -+// size_t new_capacity = min_new_capacity; -+// MZ_ASSERT(pArray->m_element_size); -+// if (pArray->m_capacity >= min_new_capacity) -+// return MZ_TRUE; -+// if (growing) -+// { -+// new_capacity = MZ_MAX(1, pArray->m_capacity); -+// while (new_capacity < min_new_capacity) -+// new_capacity *= 2; -+// } -+// if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) -+// return MZ_FALSE; -+// pArray->m_p = pNew_p; -+// pArray->m_capacity = new_capacity; -+// return MZ_TRUE; -+// } - --static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) --{ -- memset(pArray, 0, sizeof(mz_zip_array)); -- pArray->m_element_size = element_size; --} -+// static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) -+// { -+// if (new_capacity > pArray->m_capacity) -+// { -+// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) -+// return MZ_FALSE; -+// } -+// return MZ_TRUE; -+// } - --static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) --{ -- pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); -- memset(pArray, 0, sizeof(mz_zip_array)); --} -+// static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) -+// { -+// if (new_size > pArray->m_capacity) -+// { -+// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) -+// return MZ_FALSE; -+// } -+// pArray->m_size = new_size; -+// return MZ_TRUE; -+// } - --static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) --{ -- void *pNew_p; -- size_t new_capacity = min_new_capacity; -- MZ_ASSERT(pArray->m_element_size); -- if (pArray->m_capacity >= min_new_capacity) -- return MZ_TRUE; -- if (growing) -- { -- new_capacity = MZ_MAX(1, pArray->m_capacity); -- while (new_capacity < min_new_capacity) -- new_capacity *= 2; -- } -- if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) -- return MZ_FALSE; -- pArray->m_p = pNew_p; -- pArray->m_capacity = new_capacity; -- return MZ_TRUE; --} -+// static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) -+// { -+// return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); -+// } - --static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) --{ -- if (new_capacity > pArray->m_capacity) -- { -- if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) -- return MZ_FALSE; -- } -- return MZ_TRUE; --} -+// static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) -+// { -+// size_t orig_size = pArray->m_size; -+// if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) -+// return MZ_FALSE; -+// memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); -+// return MZ_TRUE; -+// } - --static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) --{ -- if (new_size > pArray->m_capacity) -- { -- if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) -- return MZ_FALSE; -- } -- pArray->m_size = new_size; -- return MZ_TRUE; --} -+// #ifndef MINIZ_NO_TIME -+// static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) -+// { -+// struct tm tm; -+// memset(&tm, 0, sizeof(tm)); -+// tm.tm_isdst = -1; -+// tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; -+// tm.tm_mon = ((dos_date >> 5) & 15) - 1; -+// tm.tm_mday = dos_date & 31; -+// tm.tm_hour = (dos_time >> 11) & 31; -+// tm.tm_min = (dos_time >> 5) & 63; -+// tm.tm_sec = (dos_time << 1) & 62; -+// return mktime(&tm); -+// } - --static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) --{ -- return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); --} -+// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -+// static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) -+// { -+// #ifdef _MSC_VER -+// struct tm tm_struct; -+// struct tm *tm = &tm_struct; -+// errno_t err = localtime_s(tm, &time_); -+// if (err) -+// { -+// *pDOS_date = 0; -+// *pDOS_time = 0; -+// return; -+// } -+// #else -+// struct tm *tm = localtime(&time_); -+// #endif /* #ifdef _MSC_VER */ - --static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) --{ -- size_t orig_size = pArray->m_size; -- if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) -- return MZ_FALSE; -- memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); -- return MZ_TRUE; --} -+// *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); -+// *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); -+// } -+// #endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ - --#ifndef MINIZ_NO_TIME --static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) --{ -- struct tm tm; -- memset(&tm, 0, sizeof(tm)); -- tm.tm_isdst = -1; -- tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; -- tm.tm_mon = ((dos_date >> 5) & 15) - 1; -- tm.tm_mday = dos_date & 31; -- tm.tm_hour = (dos_time >> 11) & 31; -- tm.tm_min = (dos_time >> 5) & 63; -- tm.tm_sec = (dos_time << 1) & 62; -- return mktime(&tm); --} -+// #ifndef MINIZ_NO_STDIO -+// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -+// static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) -+// { -+// struct MZ_FILE_STAT_STRUCT file_stat; - --#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS --static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) --{ --#ifdef _MSC_VER -- struct tm tm_struct; -- struct tm *tm = &tm_struct; -- errno_t err = localtime_s(tm, &time_); -- if (err) -- { -- *pDOS_date = 0; -- *pDOS_time = 0; -- return; -- } --#else -- struct tm *tm = localtime(&time_); --#endif /* #ifdef _MSC_VER */ -+// /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ -+// if (MZ_FILE_STAT(pFilename, &file_stat) != 0) -+// return MZ_FALSE; - -- *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); -- *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); --} --#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ -+// *pTime = file_stat.st_mtime; - --#ifndef MINIZ_NO_STDIO --#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS --static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) --{ -- struct MZ_FILE_STAT_STRUCT file_stat; -+// return MZ_TRUE; -+// } -+// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ - -- /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ -- if (MZ_FILE_STAT(pFilename, &file_stat) != 0) -- return MZ_FALSE; -+// static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) -+// { -+// struct utimbuf t; - -- *pTime = file_stat.st_mtime; -+// memset(&t, 0, sizeof(t)); -+// t.actime = access_time; -+// t.modtime = modified_time; - -- return MZ_TRUE; --} --#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ -+// return !utime(pFilename, &t); -+// } -+// #endif /* #ifndef MINIZ_NO_STDIO */ -+// #endif /* #ifndef MINIZ_NO_TIME */ - --static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) --{ -- struct utimbuf t; -+// static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) -+// { -+// if (pZip) -+// pZip->m_last_error = err_num; -+// return MZ_FALSE; -+// } - -- memset(&t, 0, sizeof(t)); -- t.actime = access_time; -- t.modtime = modified_time; -+// static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) -+// { -+// (void)flags; -+// if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- return !utime(pFilename, &t); --} --#endif /* #ifndef MINIZ_NO_STDIO */ --#endif /* #ifndef MINIZ_NO_TIME */ -+// if (!pZip->m_pAlloc) -+// pZip->m_pAlloc = miniz_def_alloc_func; -+// if (!pZip->m_pFree) -+// pZip->m_pFree = miniz_def_free_func; -+// if (!pZip->m_pRealloc) -+// pZip->m_pRealloc = miniz_def_realloc_func; - --static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) --{ -- if (pZip) -- pZip->m_last_error = err_num; -- return MZ_FALSE; --} -+// pZip->m_archive_size = 0; -+// pZip->m_central_directory_file_ofs = 0; -+// pZip->m_total_files = 0; -+// pZip->m_last_error = MZ_ZIP_NO_ERROR; - --static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) --{ -- (void)flags; -- if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- -- if (!pZip->m_pAlloc) -- pZip->m_pAlloc = miniz_def_alloc_func; -- if (!pZip->m_pFree) -- pZip->m_pFree = miniz_def_free_func; -- if (!pZip->m_pRealloc) -- pZip->m_pRealloc = miniz_def_realloc_func; -- -- pZip->m_archive_size = 0; -- pZip->m_central_directory_file_ofs = 0; -- pZip->m_total_files = 0; -- pZip->m_last_error = MZ_ZIP_NO_ERROR; -- -- if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- -- memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); -- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); -- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); -- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); -- pZip->m_pState->m_init_flags = flags; -- pZip->m_pState->m_zip64 = MZ_FALSE; -- pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; -- -- pZip->m_zip_mode = MZ_ZIP_MODE_READING; -+// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -- return MZ_TRUE; --} -+// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); -+// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); -+// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); -+// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); -+// pZip->m_pState->m_init_flags = flags; -+// pZip->m_pState->m_zip64 = MZ_FALSE; -+// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; - --static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) --{ -- const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; -- const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); -- mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); -- mz_uint8 l = 0, r = 0; -- pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -- pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -- pE = pL + MZ_MIN(l_len, r_len); -- while (pL < pE) -- { -- if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) -- break; -- pL++; -- pR++; -- } -- return (pL == pE) ? (l_len < r_len) : (l < r); --} -+// pZip->m_zip_mode = MZ_ZIP_MODE_READING; -+ -+// return MZ_TRUE; -+// } - -+// static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) -+// { -+// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; -+// const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); -+// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// mz_uint8 l = 0, r = 0; -+// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -+// pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -+// pE = pL + MZ_MIN(l_len, r_len); -+// while (pL < pE) -+// { -+// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) -+// break; -+// pL++; -+// pR++; -+// } -+// return (pL == pE) ? (l_len < r_len) : (l < r); -+// } -+/* - #define MZ_SWAP_UINT32(a, b) \ - do \ - { \ -@@ -3388,1708 +3387,1708 @@ static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pC - b = t; \ - } \ - MZ_MACRO_END -- -+*/ - /* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */ --static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) --{ -- mz_zip_internal_state *pState = pZip->m_pState; -- const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; -- const mz_zip_array *pCentral_dir = &pState->m_central_dir; -- mz_uint32 *pIndices; -- mz_uint32 start, end; -- const mz_uint32 size = pZip->m_total_files; -- -- if (size <= 1U) -- return; -+// static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) -+// { -+// mz_zip_internal_state *pState = pZip->m_pState; -+// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; -+// const mz_zip_array *pCentral_dir = &pState->m_central_dir; -+// mz_uint32 *pIndices; -+// mz_uint32 start, end; -+// const mz_uint32 size = pZip->m_total_files; - -- pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); -+// if (size <= 1U) -+// return; - -- start = (size - 2U) >> 1U; -- for (;;) -- { -- mz_uint64 child, root = start; -- for (;;) -- { -- if ((child = (root << 1U) + 1U) >= size) -- break; -- child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); -- if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) -- break; -- MZ_SWAP_UINT32(pIndices[root], pIndices[child]); -- root = child; -- } -- if (!start) -- break; -- start--; -- } -+// pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); - -- end = size - 1; -- while (end > 0) -- { -- mz_uint64 child, root = 0; -- MZ_SWAP_UINT32(pIndices[end], pIndices[0]); -- for (;;) -- { -- if ((child = (root << 1U) + 1U) >= end) -- break; -- child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); -- if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) -- break; -- MZ_SWAP_UINT32(pIndices[root], pIndices[child]); -- root = child; -- } -- end--; -- } --} -+// start = (size - 2U) >> 1U; -+// for (;;) -+// { -+// mz_uint64 child, root = start; -+// for (;;) -+// { -+// if ((child = (root << 1U) + 1U) >= size) -+// break; -+// child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); -+// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) -+// break; -+// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); -+// root = child; -+// } -+// if (!start) -+// break; -+// start--; -+// } - --static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) --{ -- mz_int64 cur_file_ofs; -- mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; -- mz_uint8 *pBuf = (mz_uint8 *)buf_u32; -+// end = size - 1; -+// while (end > 0) -+// { -+// mz_uint64 child, root = 0; -+// MZ_SWAP_UINT32(pIndices[end], pIndices[0]); -+// for (;;) -+// { -+// if ((child = (root << 1U) + 1U) >= end) -+// break; -+// child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); -+// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) -+// break; -+// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); -+// root = child; -+// } -+// end--; -+// } -+// } - -- /* Basic sanity checks - reject files which are too small */ -- if (pZip->m_archive_size < record_size) -- return MZ_FALSE; -+// static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) -+// { -+// mz_int64 cur_file_ofs; -+// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; -+// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; - -- /* Find the record by scanning the file from the end towards the beginning. */ -- cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); -- for (;;) -- { -- int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); -+// /* Basic sanity checks - reject files which are too small */ -+// if (pZip->m_archive_size < record_size) -+// return MZ_FALSE; - -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) -- return MZ_FALSE; -+// /* Find the record by scanning the file from the end towards the beginning. */ -+// cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); -+// for (;;) -+// { -+// int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); - -- for (i = n - 4; i >= 0; --i) -- { -- mz_uint s = MZ_READ_LE32(pBuf + i); -- if (s == record_sig) -- { -- if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) -- break; -- } -- } -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) -+// return MZ_FALSE; - -- if (i >= 0) -- { -- cur_file_ofs += i; -- break; -- } -+// for (i = n - 4; i >= 0; --i) -+// { -+// mz_uint s = MZ_READ_LE32(pBuf + i); -+// if (s == record_sig) -+// { -+// if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) -+// break; -+// } -+// } - -- /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ -- if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) -- return MZ_FALSE; -+// if (i >= 0) -+// { -+// cur_file_ofs += i; -+// break; -+// } - -- cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); -- } -+// /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ -+// if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) -+// return MZ_FALSE; - -- *pOfs = cur_file_ofs; -- return MZ_TRUE; --} -+// cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); -+// } - --static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) --{ -- mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; -- mz_uint64 cdir_ofs = 0; -- mz_int64 cur_file_ofs = 0; -- const mz_uint8 *p; -+// *pOfs = cur_file_ofs; -+// return MZ_TRUE; -+// } - -- mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; -- mz_uint8 *pBuf = (mz_uint8 *)buf_u32; -- mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); -- mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -- mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; -+// static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) -+// { -+// mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; -+// mz_uint64 cdir_ofs = 0; -+// mz_int64 cur_file_ofs = 0; -+// const mz_uint8 *p; - -- mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -- mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; -+// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; -+// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; -+// mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); -+// mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -+// mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; - -- mz_uint64 zip64_end_of_central_dir_ofs = 0; -+// mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -+// mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; - -- /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ -- if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -+// mz_uint64 zip64_end_of_central_dir_ofs = 0; - -- if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) -- return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); -+// /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ -+// if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -- /* Read and verify the end of central directory record. */ -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); - -- if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) -- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -+// /* Read and verify the end of central directory record. */ -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -- if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) -- { -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) -- { -- if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) -- { -- zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); -- if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) -- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -+// if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) -+// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -- if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) -- { -- if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) -- { -- pZip->m_pState->m_zip64 = MZ_TRUE; -- } -- } -- } -- } -- } -+// if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) -+// { -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) -+// { -+// if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) -+// { -+// zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); -+// if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) -+// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -- pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); -- cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); -- num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); -- cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); -- cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); -- cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); -+// if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// { -+// if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) -+// { -+// pZip->m_pState->m_zip64 = MZ_TRUE; -+// } -+// } -+// } -+// } -+// } - -- if (pZip->m_pState->m_zip64) -- { -- mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); -- mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); -- mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); -- mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); -- mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); -+// pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); -+// cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); -+// num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); -+// cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); -+// cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); -+// cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); - -- if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// if (pZip->m_pState->m_zip64) -+// { -+// mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); -+// mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); -+// mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); -+// mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); -+// mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); - -- if (zip64_total_num_of_disks != 1U) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); -+// if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- /* Check for miniz's practical limits */ -- if (zip64_cdir_total_entries > MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// if (zip64_total_num_of_disks != 1U) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -- pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; -+// /* Check for miniz's practical limits */ -+// if (zip64_cdir_total_entries > MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - -- if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; - -- cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; -+// if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - -- /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ -- if (zip64_size_of_central_directory > MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); -+// cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; - -- cdir_size = (mz_uint32)zip64_size_of_central_directory; -+// /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ -+// if (zip64_size_of_central_directory > MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -- num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); -+// cdir_size = (mz_uint32)zip64_size_of_central_directory; - -- cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); -+// num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); - -- cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); -- } -+// cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); - -- if (pZip->m_total_files != cdir_entries_on_this_disk) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); -+// cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); -+// } - -- if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); -+// if (pZip->m_total_files != cdir_entries_on_this_disk) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -- if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -- if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- pZip->m_central_directory_file_ofs = cdir_ofs; -+// if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (pZip->m_total_files) -- { -- mz_uint i, n; -- /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ -- if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || -- (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// pZip->m_central_directory_file_ofs = cdir_ofs; - -- if (sort_central_dir) -- { -- if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- } -+// if (pZip->m_total_files) -+// { -+// mz_uint i, n; -+// /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ -+// if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || -+// (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -- if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// if (sort_central_dir) -+// { -+// if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// } - -- /* Now create an index into the central directory file records, do some basic sanity checking on each record */ -- p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; -- for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) -- { -- mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; -- mz_uint64 comp_size, decomp_size, local_header_ofs; -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -- if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// /* Now create an index into the central directory file records, do some basic sanity checking on each record */ -+// p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; -+// for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) -+// { -+// mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; -+// mz_uint64 comp_size, decomp_size, local_header_ofs; - -- MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); -+// if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (sort_central_dir) -- MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; -+// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); - -- comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -- decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); -- local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); -- filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -- ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); -+// if (sort_central_dir) -+// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; - -- if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && -- (ext_data_size) && -- (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) -- { -- /* Attempt to find zip64 extended information field in the entry's extra data */ -- mz_uint32 extra_size_remaining = ext_data_size; -+// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -+// decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); -+// local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); -+// filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); - -- if (extra_size_remaining) -- { -- const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; -+// if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && -+// (ext_data_size) && -+// (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) -+// { -+// /* Attempt to find zip64 extended information field in the entry's extra data */ -+// mz_uint32 extra_size_remaining = ext_data_size; - -- do -- { -- mz_uint32 field_id; -- mz_uint32 field_data_size; -+// if (extra_size_remaining) -+// { -+// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; - -- if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// do -+// { -+// mz_uint32 field_id; -+// mz_uint32 field_data_size; - -- field_id = MZ_READ_LE16(pExtra_data); -- field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); -+// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// field_id = MZ_READ_LE16(pExtra_data); -+// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); - -- if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -- { -- /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ -- pZip->m_pState->m_zip64 = MZ_TRUE; -- pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; -- break; -- } -+// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; -- extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; -- } while (extra_size_remaining); -- } -- } -+// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -+// { -+// /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ -+// pZip->m_pState->m_zip64 = MZ_TRUE; -+// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; -+// break; -+// } - -- /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ -- if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) -- { -- if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- } -+// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; -+// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; -+// } while (extra_size_remaining); -+// } -+// } - -- disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); -- if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); -+// /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ -+// if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) -+// { -+// if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// } - -- if (comp_size != MZ_UINT32_MAX) -- { -- if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- } -+// disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); -+// if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -- bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -- if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -+// if (comp_size != MZ_UINT32_MAX) -+// { -+// if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// } - -- if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -+// if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - -- n -= total_header_size; -- p += total_header_size; -- } -- } -+// if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (sort_central_dir) -- mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); -+// n -= total_header_size; -+// p += total_header_size; -+// } -+// } - -- return MZ_TRUE; --} -+// if (sort_central_dir) -+// mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); - --void mz_zip_zero_struct(mz_zip_archive *pZip) --{ -- if (pZip) -- MZ_CLEAR_OBJ(*pZip); --} -+// return MZ_TRUE; -+// } - --static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) --{ -- mz_bool status = MZ_TRUE; -+// void mz_zip_zero_struct(mz_zip_archive *pZip) -+// { -+// if (pZip) -+// MZ_CLEAR_OBJ(*pZip); -+// } - -- if (!pZip) -- return MZ_FALSE; -+// static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) -+// { -+// mz_bool status = MZ_TRUE; - -- if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) -- { -- if (set_last_error) -- pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; -+// if (!pZip) -+// return MZ_FALSE; - -- return MZ_FALSE; -- } -+// if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) -+// { -+// if (set_last_error) -+// pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; - -- if (pZip->m_pState) -- { -- mz_zip_internal_state *pState = pZip->m_pState; -- pZip->m_pState = NULL; -+// return MZ_FALSE; -+// } - -- mz_zip_array_clear(pZip, &pState->m_central_dir); -- mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); -- mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); -+// if (pZip->m_pState) -+// { -+// mz_zip_internal_state *pState = pZip->m_pState; -+// pZip->m_pState = NULL; - --#ifndef MINIZ_NO_STDIO -- if (pState->m_pFile) -- { -- if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -- { -- if (MZ_FCLOSE(pState->m_pFile) == EOF) -- { -- if (set_last_error) -- pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; -- status = MZ_FALSE; -- } -- } -- pState->m_pFile = NULL; -- } --#endif /* #ifndef MINIZ_NO_STDIO */ -+// mz_zip_array_clear(pZip, &pState->m_central_dir); -+// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); -+// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); - -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- } -- pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; -+// #ifndef MINIZ_NO_STDIO -+// if (pState->m_pFile) -+// { -+// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -+// { -+// if (MZ_FCLOSE(pState->m_pFile) == EOF) -+// { -+// if (set_last_error) -+// pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; -+// status = MZ_FALSE; -+// } -+// } -+// pState->m_pFile = NULL; -+// } -+// #endif /* #ifndef MINIZ_NO_STDIO */ - -- return status; --} -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// } -+// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; - --mz_bool mz_zip_reader_end(mz_zip_archive *pZip) --{ -- return mz_zip_reader_end_internal(pZip, MZ_TRUE); --} --mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) --{ -- if ((!pZip) || (!pZip->m_pRead)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return status; -+// } - -- if (!mz_zip_reader_init_internal(pZip, flags)) -- return MZ_FALSE; -+// mz_bool mz_zip_reader_end(mz_zip_archive *pZip) -+// { -+// return mz_zip_reader_end_internal(pZip, MZ_TRUE); -+// } -+// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) -+// { -+// if ((!pZip) || (!pZip->m_pRead)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- pZip->m_zip_type = MZ_ZIP_TYPE_USER; -- pZip->m_archive_size = size; -+// if (!mz_zip_reader_init_internal(pZip, flags)) -+// return MZ_FALSE; - -- if (!mz_zip_reader_read_central_dir(pZip, flags)) -- { -- mz_zip_reader_end_internal(pZip, MZ_FALSE); -- return MZ_FALSE; -- } -+// pZip->m_zip_type = MZ_ZIP_TYPE_USER; -+// pZip->m_archive_size = size; - -- return MZ_TRUE; --} -+// if (!mz_zip_reader_read_central_dir(pZip, flags)) -+// { -+// mz_zip_reader_end_internal(pZip, MZ_FALSE); -+// return MZ_FALSE; -+// } - --static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) --{ -- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -- size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); -- memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); -- return s; --} -+// return MZ_TRUE; -+// } - --mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) --{ -- if (!pMem) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -+// { -+// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -+// size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); -+// memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); -+// return s; -+// } - -- if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -+// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) -+// { -+// if (!pMem) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if (!mz_zip_reader_init_internal(pZip, flags)) -- return MZ_FALSE; -+// if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -- pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; -- pZip->m_archive_size = size; -- pZip->m_pRead = mz_zip_mem_read_func; -- pZip->m_pIO_opaque = pZip; -- pZip->m_pNeeds_keepalive = NULL; -+// if (!mz_zip_reader_init_internal(pZip, flags)) -+// return MZ_FALSE; - --#ifdef __cplusplus -- pZip->m_pState->m_pMem = const_cast(pMem); --#else -- pZip->m_pState->m_pMem = (void *)pMem; --#endif -+// pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; -+// pZip->m_archive_size = size; -+// pZip->m_pRead = mz_zip_mem_read_func; -+// pZip->m_pIO_opaque = pZip; -+// pZip->m_pNeeds_keepalive = NULL; - -- pZip->m_pState->m_mem_size = size; -+// #ifdef __cplusplus -+// pZip->m_pState->m_pMem = const_cast(pMem); -+// #else -+// pZip->m_pState->m_pMem = (void *)pMem; -+// #endif - -- if (!mz_zip_reader_read_central_dir(pZip, flags)) -- { -- mz_zip_reader_end_internal(pZip, MZ_FALSE); -- return MZ_FALSE; -- } -+// pZip->m_pState->m_mem_size = size; - -- return MZ_TRUE; --} -+// if (!mz_zip_reader_read_central_dir(pZip, flags)) -+// { -+// mz_zip_reader_end_internal(pZip, MZ_FALSE); -+// return MZ_FALSE; -+// } - --#ifndef MINIZ_NO_STDIO --static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) --{ -- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -- mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); -+// return MZ_TRUE; -+// } - -- file_ofs += pZip->m_pState->m_file_archive_start_ofs; -+// #ifndef MINIZ_NO_STDIO -+// static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -+// { -+// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -+// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - -- if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) -- return 0; -+// file_ofs += pZip->m_pState->m_file_archive_start_ofs; - -- return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); --} -+// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) -+// return 0; - --mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) --{ -- return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); --} -+// return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); -+// } - --mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) --{ -- mz_uint64 file_size; -- MZ_FILE *pFile; -+// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) -+// { -+// return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); -+// } - -- if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) -+// { -+// mz_uint64 file_size; -+// MZ_FILE *pFile; - -- pFile = MZ_FOPEN(pFilename, "rb"); -- if (!pFile) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -+// if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- file_size = archive_size; -- if (!file_size) -- { -- if (MZ_FSEEK64(pFile, 0, SEEK_END)) -- { -- MZ_FCLOSE(pFile); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); -- } -+// pFile = MZ_FOPEN(pFilename, "rb"); -+// if (!pFile) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -- file_size = MZ_FTELL64(pFile); -- } -+// file_size = archive_size; -+// if (!file_size) -+// { -+// if (MZ_FSEEK64(pFile, 0, SEEK_END)) -+// { -+// MZ_FCLOSE(pFile); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); -+// } - -- /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ -+// file_size = MZ_FTELL64(pFile); -+// } - -- if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -- { -- MZ_FCLOSE(pFile); -- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -- } -+// /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ - -- if (!mz_zip_reader_init_internal(pZip, flags)) -- { -- MZ_FCLOSE(pFile); -- return MZ_FALSE; -- } -+// if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// { -+// MZ_FCLOSE(pFile); -+// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -+// } - -- pZip->m_zip_type = MZ_ZIP_TYPE_FILE; -- pZip->m_pRead = mz_zip_file_read_func; -- pZip->m_pIO_opaque = pZip; -- pZip->m_pState->m_pFile = pFile; -- pZip->m_archive_size = file_size; -- pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; -+// if (!mz_zip_reader_init_internal(pZip, flags)) -+// { -+// MZ_FCLOSE(pFile); -+// return MZ_FALSE; -+// } - -- if (!mz_zip_reader_read_central_dir(pZip, flags)) -- { -- mz_zip_reader_end_internal(pZip, MZ_FALSE); -- return MZ_FALSE; -- } -+// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; -+// pZip->m_pRead = mz_zip_file_read_func; -+// pZip->m_pIO_opaque = pZip; -+// pZip->m_pState->m_pFile = pFile; -+// pZip->m_archive_size = file_size; -+// pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; - -- return MZ_TRUE; --} -+// if (!mz_zip_reader_read_central_dir(pZip, flags)) -+// { -+// mz_zip_reader_end_internal(pZip, MZ_FALSE); -+// return MZ_FALSE; -+// } - --mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) --{ -- mz_uint64 cur_file_ofs; -+// return MZ_TRUE; -+// } - -- if ((!pZip) || (!pFile)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -+// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) -+// { -+// mz_uint64 cur_file_ofs; - -- cur_file_ofs = MZ_FTELL64(pFile); -+// if ((!pZip) || (!pFile)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -- if (!archive_size) -- { -- if (MZ_FSEEK64(pFile, 0, SEEK_END)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); -+// cur_file_ofs = MZ_FTELL64(pFile); - -- archive_size = MZ_FTELL64(pFile) - cur_file_ofs; -+// if (!archive_size) -+// { -+// if (MZ_FSEEK64(pFile, 0, SEEK_END)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); - -- if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -- } -+// archive_size = MZ_FTELL64(pFile) - cur_file_ofs; - -- if (!mz_zip_reader_init_internal(pZip, flags)) -- return MZ_FALSE; -+// if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -+// } - -- pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; -- pZip->m_pRead = mz_zip_file_read_func; -+// if (!mz_zip_reader_init_internal(pZip, flags)) -+// return MZ_FALSE; - -- pZip->m_pIO_opaque = pZip; -- pZip->m_pState->m_pFile = pFile; -- pZip->m_archive_size = archive_size; -- pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; -+// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; -+// pZip->m_pRead = mz_zip_file_read_func; - -- if (!mz_zip_reader_read_central_dir(pZip, flags)) -- { -- mz_zip_reader_end_internal(pZip, MZ_FALSE); -- return MZ_FALSE; -- } -+// pZip->m_pIO_opaque = pZip; -+// pZip->m_pState->m_pFile = pFile; -+// pZip->m_archive_size = archive_size; -+// pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; - -- return MZ_TRUE; --} -+// if (!mz_zip_reader_read_central_dir(pZip, flags)) -+// { -+// mz_zip_reader_end_internal(pZip, MZ_FALSE); -+// return MZ_FALSE; -+// } - --#endif /* #ifndef MINIZ_NO_STDIO */ -+// return MZ_TRUE; -+// } - --static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) --{ -- if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) -- return NULL; -- return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); --} -+// #endif /* #ifndef MINIZ_NO_STDIO */ - --mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) --{ -- mz_uint m_bit_flag; -- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -- if (!p) -- { -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- return MZ_FALSE; -- } -+// static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) -+// { -+// if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) -+// return NULL; -+// return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); -+// } - -- m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -- return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; --} -+// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) -+// { -+// mz_uint m_bit_flag; -+// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -+// if (!p) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return MZ_FALSE; -+// } - --mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) --{ -- mz_uint bit_flag; -- mz_uint method; -+// m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -+// return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; -+// } - -- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -- if (!p) -- { -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- return MZ_FALSE; -- } -+// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) -+// { -+// mz_uint bit_flag; -+// mz_uint method; - -- method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); -- bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -+// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -+// if (!p) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return MZ_FALSE; -+// } - -- if ((method != 0) && (method != MZ_DEFLATED)) -- { -- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -- return MZ_FALSE; -- } -+// method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); -+// bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); - -- if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) -- { -- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -- return MZ_FALSE; -- } -+// if ((method != 0) && (method != MZ_DEFLATED)) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -+// return MZ_FALSE; -+// } - -- if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) -- { -- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); -- return MZ_FALSE; -- } -+// if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -+// return MZ_FALSE; -+// } - -- return MZ_TRUE; --} -+// if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); -+// return MZ_FALSE; -+// } - --mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) --{ -- mz_uint filename_len, attribute_mapping_id, external_attr; -- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -- if (!p) -- { -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- return MZ_FALSE; -- } -+// return MZ_TRUE; -+// } - -- filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -- if (filename_len) -- { -- if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') -- return MZ_TRUE; -- } -+// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) -+// { -+// mz_uint filename_len, attribute_mapping_id, external_attr; -+// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -+// if (!p) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return MZ_FALSE; -+// } -+ -+// filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// if (filename_len) -+// { -+// if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') -+// return MZ_TRUE; -+// } - - /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */ - /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */ - /* FIXME: Remove this check? Is it necessary - we already check the filename. */ -- attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; -- (void)attribute_mapping_id; -+// attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; -+// (void)attribute_mapping_id; - -- external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); -- if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) -- { -- return MZ_TRUE; -- } -+// external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); -+// if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) -+// { -+// return MZ_TRUE; -+// } - -- return MZ_FALSE; --} -+// return MZ_FALSE; -+// } - --static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) --{ -- mz_uint n; -- const mz_uint8 *p = pCentral_dir_header; -- -- if (pFound_zip64_extra_data) -- *pFound_zip64_extra_data = MZ_FALSE; -- -- if ((!p) || (!pStat)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- -- /* Extract fields from the central directory record. */ -- pStat->m_file_index = file_index; -- pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); -- pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); -- pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); -- pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -- pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); --#ifndef MINIZ_NO_TIME -- pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); --#endif -- pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); -- pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -- pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); -- pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); -- pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); -- pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); -- -- /* Copy as much of the filename and comment as possible. */ -- n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -- n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); -- memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); -- pStat->m_filename[n] = '\0'; -- -- n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); -- n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); -- pStat->m_comment_size = n; -- memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); -- pStat->m_comment[n] = '\0'; -- -- /* Set some flags for convienance */ -- pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); -- pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); -- pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); -- -- /* See if we need to read any zip64 extended information fields. */ -- /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ -- if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) -- { -- /* Attempt to find zip64 extended information field in the entry's extra data */ -- mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); -+// static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) -+// { -+// mz_uint n; -+// const mz_uint8 *p = pCentral_dir_header; - -- if (extra_size_remaining) -- { -- const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// if (pFound_zip64_extra_data) -+// *pFound_zip64_extra_data = MZ_FALSE; - -- do -- { -- mz_uint32 field_id; -- mz_uint32 field_data_size; -+// if ((!p) || (!pStat)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// /* Extract fields from the central directory record. */ -+// pStat->m_file_index = file_index; -+// pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); -+// pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); -+// pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); -+// pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -+// pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); -+// #ifndef MINIZ_NO_TIME -+// pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); -+// #endif -+// pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); -+// pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -+// pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); -+// pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); -+// pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); -+// pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); -+ -+// /* Copy as much of the filename and comment as possible. */ -+// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); -+// memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); -+// pStat->m_filename[n] = '\0'; -+ -+// n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); -+// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); -+// pStat->m_comment_size = n; -+// memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); -+// pStat->m_comment[n] = '\0'; -+ -+// /* Set some flags for convienance */ -+// pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); -+// pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); -+// pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); -+ -+// /* See if we need to read any zip64 extended information fields. */ -+// /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ -+// if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) -+// { -+// /* Attempt to find zip64 extended information field in the entry's extra data */ -+// mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); - -- field_id = MZ_READ_LE16(pExtra_data); -- field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); -+// if (extra_size_remaining) -+// { -+// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - -- if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// do -+// { -+// mz_uint32 field_id; -+// mz_uint32 field_data_size; - -- if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -- { -- const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; -- mz_uint32 field_data_remaining = field_data_size; -+// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (pFound_zip64_extra_data) -- *pFound_zip64_extra_data = MZ_TRUE; -+// field_id = MZ_READ_LE16(pExtra_data); -+// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); - -- if (pStat->m_uncomp_size == MZ_UINT32_MAX) -- { -- if (field_data_remaining < sizeof(mz_uint64)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- pStat->m_uncomp_size = MZ_READ_LE64(pField_data); -- pField_data += sizeof(mz_uint64); -- field_data_remaining -= sizeof(mz_uint64); -- } -+// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -+// { -+// const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; -+// mz_uint32 field_data_remaining = field_data_size; -+ -+// if (pFound_zip64_extra_data) -+// *pFound_zip64_extra_data = MZ_TRUE; -+ -+// if (pStat->m_uncomp_size == MZ_UINT32_MAX) -+// { -+// if (field_data_remaining < sizeof(mz_uint64)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+ -+// pStat->m_uncomp_size = MZ_READ_LE64(pField_data); -+// pField_data += sizeof(mz_uint64); -+// field_data_remaining -= sizeof(mz_uint64); -+// } -+ -+// if (pStat->m_comp_size == MZ_UINT32_MAX) -+// { -+// if (field_data_remaining < sizeof(mz_uint64)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+ -+// pStat->m_comp_size = MZ_READ_LE64(pField_data); -+// pField_data += sizeof(mz_uint64); -+// field_data_remaining -= sizeof(mz_uint64); -+// } -+ -+// if (pStat->m_local_header_ofs == MZ_UINT32_MAX) -+// { -+// if (field_data_remaining < sizeof(mz_uint64)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+ -+// pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); -+// pField_data += sizeof(mz_uint64); -+// // field_data_remaining -= sizeof(mz_uint64); -+// } -+ -+// break; -+// } - -- if (pStat->m_comp_size == MZ_UINT32_MAX) -- { -- if (field_data_remaining < sizeof(mz_uint64)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; -+// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; -+// } while (extra_size_remaining); -+// } -+// } - -- pStat->m_comp_size = MZ_READ_LE64(pField_data); -- pField_data += sizeof(mz_uint64); -- field_data_remaining -= sizeof(mz_uint64); -- } -+// return MZ_TRUE; -+// } - -- if (pStat->m_local_header_ofs == MZ_UINT32_MAX) -- { -- if (field_data_remaining < sizeof(mz_uint64)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) -+// { -+// mz_uint i; -+// if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) -+// return 0 == memcmp(pA, pB, len); -+// for (i = 0; i < len; ++i) -+// if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) -+// return MZ_FALSE; -+// return MZ_TRUE; -+// } - -- pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); -- pField_data += sizeof(mz_uint64); -- // field_data_remaining -= sizeof(mz_uint64); -- } -+// static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) -+// { -+// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; -+// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// mz_uint8 l = 0, r = 0; -+// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -+// pE = pL + MZ_MIN(l_len, r_len); -+// while (pL < pE) -+// { -+// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) -+// break; -+// pL++; -+// pR++; -+// } -+// return (pL == pE) ? (int)(l_len - r_len) : (l - r); -+// } - -- break; -- } -+// static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) -+// { -+// mz_zip_internal_state *pState = pZip->m_pState; -+// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; -+// const mz_zip_array *pCentral_dir = &pState->m_central_dir; -+// mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); -+// const uint32_t size = pZip->m_total_files; -+// const mz_uint filename_len = (mz_uint)strlen(pFilename); - -- pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; -- extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; -- } while (extra_size_remaining); -- } -- } -+// if (pIndex) -+// *pIndex = 0; - -- return MZ_TRUE; --} -+// if (size) -+// { -+// /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ -+// /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ -+// mz_int64 l = 0, h = (mz_int64)size - 1; - --static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) --{ -- mz_uint i; -- if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) -- return 0 == memcmp(pA, pB, len); -- for (i = 0; i < len; ++i) -- if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) -- return MZ_FALSE; -- return MZ_TRUE; --} -+// while (l <= h) -+// { -+// mz_int64 m = l + ((h - l) >> 1); -+// uint32_t file_index = pIndices[(uint32_t)m]; - --static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) --{ -- const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; -- mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); -- mz_uint8 l = 0, r = 0; -- pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -- pE = pL + MZ_MIN(l_len, r_len); -- while (pL < pE) -- { -- if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) -- break; -- pL++; -- pR++; -- } -- return (pL == pE) ? (int)(l_len - r_len) : (l - r); --} -+// int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); -+// if (!comp) -+// { -+// if (pIndex) -+// *pIndex = file_index; -+// return MZ_TRUE; -+// } -+// else if (comp < 0) -+// l = m + 1; -+// else -+// h = m - 1; -+// } -+// } - --static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) --{ -- mz_zip_internal_state *pState = pZip->m_pState; -- const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; -- const mz_zip_array *pCentral_dir = &pState->m_central_dir; -- mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); -- const uint32_t size = pZip->m_total_files; -- const mz_uint filename_len = (mz_uint)strlen(pFilename); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); -+// } - -- if (pIndex) -- *pIndex = 0; -+// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) -+// { -+// mz_uint32 index_; -+// if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) -+// return -1; -+// else -+// return (int)index_; -+// } - -- if (size) -- { -- /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ -- /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ -- mz_int64 l = 0, h = (mz_int64)size - 1; -+// mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) -+// { -+// mz_uint file_index; -+// size_t name_len, comment_len; - -- while (l <= h) -- { -- mz_int64 m = l + ((h - l) >> 1); -- uint32_t file_index = pIndices[(uint32_t)m]; -+// if (pIndex) -+// *pIndex = 0; - -- int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); -- if (!comp) -- { -- if (pIndex) -- *pIndex = file_index; -- return MZ_TRUE; -- } -- else if (comp < 0) -- l = m + 1; -- else -- h = m - 1; -- } -- } -+// if ((!pZip) || (!pZip->m_pState) || (!pName)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); --} -+// /* See if we can use a binary search */ -+// if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && -+// (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && -+// ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) -+// { -+// return mz_zip_locate_file_binary_search(pZip, pName, pIndex); -+// } - --int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) --{ -- mz_uint32 index_; -- if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) -- return -1; -- else -- return (int)index_; --} -+// /* Locate the entry by scanning the entire central directory */ -+// name_len = strlen(pName); -+// if (name_len > MZ_UINT16_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - --mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) --{ -- mz_uint file_index; -- size_t name_len, comment_len; -+// comment_len = pComment ? strlen(pComment) : 0; -+// if (comment_len > MZ_UINT16_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if (pIndex) -- *pIndex = 0; -+// for (file_index = 0; file_index < pZip->m_total_files; file_index++) -+// { -+// const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); -+// mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -+// if (filename_len < name_len) -+// continue; -+// if (comment_len) -+// { -+// mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); -+// const char *pFile_comment = pFilename + filename_len + file_extra_len; -+// if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) -+// continue; -+// } -+// if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) -+// { -+// int ofs = filename_len - 1; -+// do -+// { -+// if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) -+// break; -+// } while (--ofs >= 0); -+// ofs++; -+// pFilename += ofs; -+// filename_len -= ofs; -+// } -+// if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) -+// { -+// if (pIndex) -+// *pIndex = file_index; -+// return MZ_TRUE; -+// } -+// } - -- if ((!pZip) || (!pZip->m_pState) || (!pName)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); -+// } - -- /* See if we can use a binary search */ -- if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && -- (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && -- ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) -- { -- return mz_zip_locate_file_binary_search(pZip, pName, pIndex); -- } -+// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -+// { -+// int status = TINFL_STATUS_DONE; -+// mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; -+// mz_zip_archive_file_stat file_stat; -+// void *pRead_buf; -+// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -+// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -+// tinfl_decompressor inflator; - -- /* Locate the entry by scanning the entire central directory */ -- name_len = strlen(pName); -- if (name_len > MZ_UINT16_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- comment_len = pComment ? strlen(pComment) : 0; -- if (comment_len > MZ_UINT16_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -+// return MZ_FALSE; - -- for (file_index = 0; file_index < pZip->m_total_files; file_index++) -- { -- const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); -- mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); -- const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -- if (filename_len < name_len) -- continue; -- if (comment_len) -- { -- mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); -- const char *pFile_comment = pFilename + filename_len + file_extra_len; -- if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) -- continue; -- } -- if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) -- { -- int ofs = filename_len - 1; -- do -- { -- if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) -- break; -- } while (--ofs >= 0); -- ofs++; -- pFilename += ofs; -- filename_len -= ofs; -- } -- if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) -- { -- if (pIndex) -- *pIndex = file_index; -- return MZ_TRUE; -- } -- } -+// /* A directory or zero length file */ -+// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) -+// return MZ_TRUE; - -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); --} -+// /* Encryption and patch files are not supported. */ -+// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - --mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) --{ -- int status = TINFL_STATUS_DONE; -- mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; -- mz_zip_archive_file_stat file_stat; -- void *pRead_buf; -- mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -- mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -- tinfl_decompressor inflator; -- -- if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- -- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -- return MZ_FALSE; -- -- /* A directory or zero length file */ -- if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) -- return MZ_TRUE; -- -- /* Encryption and patch files are not supported. */ -- if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -- -- /* This function only supports decompressing stored and deflate. */ -- if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -- -- /* Ensure supplied output buffer is large enough. */ -- needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; -- if (buf_size < needed_size) -- return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); -- -- /* Read and parse the local directory entry. */ -- cur_file_ofs = file_stat.m_local_header_ofs; -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -- -- if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- -- cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -- if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- -- if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) -- { -- /* The file is stored or the caller has requested the compressed data. */ -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// /* This function only supports decompressing stored and deflate. */ -+// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); - --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) -- { -- if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) -- return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); -- } --#endif -+// /* Ensure supplied output buffer is large enough. */ -+// needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; -+// if (buf_size < needed_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); - -- return MZ_TRUE; -- } -+// /* Read and parse the local directory entry. */ -+// cur_file_ofs = file_stat.m_local_header_ofs; -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -- /* Decompress the file either directly from memory or from a file input buffer. */ -- tinfl_init(&inflator); -+// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (pZip->m_pState->m_pMem) -- { -- /* Read directly from the archive in memory. */ -- pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; -- read_buf_size = read_buf_avail = file_stat.m_comp_size; -- comp_remaining = 0; -- } -- else if (pUser_read_buf) -- { -- /* Use a user provided read buffer. */ -- if (!user_read_buf_size) -- return MZ_FALSE; -- pRead_buf = (mz_uint8 *)pUser_read_buf; -- read_buf_size = user_read_buf_size; -- read_buf_avail = 0; -- comp_remaining = file_stat.m_comp_size; -- } -- else -- { -- /* Temporarily allocate a read buffer. */ -- read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -- if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -+// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) -+// { -+// /* The file is stored or the caller has requested the compressed data. */ -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -- read_buf_avail = 0; -- comp_remaining = file_stat.m_comp_size; -- } -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) -+// { -+// if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) -+// return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); -+// } -+// #endif - -- do -- { -- /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ -- size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); -- if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) -- { -- read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -- { -- status = TINFL_STATUS_FAILED; -- mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -- break; -- } -- cur_file_ofs += read_buf_avail; -- comp_remaining -= read_buf_avail; -- read_buf_ofs = 0; -- } -- in_buf_size = (size_t)read_buf_avail; -- status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); -- read_buf_avail -= in_buf_size; -- read_buf_ofs += in_buf_size; -- out_buf_ofs += out_buf_size; -- } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); -- -- if (status == TINFL_STATUS_DONE) -- { -- /* Make sure the entire file was decompressed, and check its CRC. */ -- if (out_buf_ofs != file_stat.m_uncomp_size) -- { -- mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -- status = TINFL_STATUS_FAILED; -- } --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) -- { -- mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); -- status = TINFL_STATUS_FAILED; -- } --#endif -- } -+// return MZ_TRUE; -+// } - -- if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) -- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -+// /* Decompress the file either directly from memory or from a file input buffer. */ -+// tinfl_init(&inflator); - -- return status == TINFL_STATUS_DONE; --} -+// if (pZip->m_pState->m_pMem) -+// { -+// /* Read directly from the archive in memory. */ -+// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; -+// read_buf_size = read_buf_avail = file_stat.m_comp_size; -+// comp_remaining = 0; -+// } -+// else if (pUser_read_buf) -+// { -+// /* Use a user provided read buffer. */ -+// if (!user_read_buf_size) -+// return MZ_FALSE; -+// pRead_buf = (mz_uint8 *)pUser_read_buf; -+// read_buf_size = user_read_buf_size; -+// read_buf_avail = 0; -+// comp_remaining = file_stat.m_comp_size; -+// } -+// else -+// { -+// /* Temporarily allocate a read buffer. */ -+// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -+// if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - --mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) --{ -- mz_uint32 file_index; -- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -- return MZ_FALSE; -- return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); --} -+// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - --mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) --{ -- return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); --} -+// read_buf_avail = 0; -+// comp_remaining = file_stat.m_comp_size; -+// } - --mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) --{ -- return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); --} -+// do -+// { -+// /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ -+// size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); -+// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) -+// { -+// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -+// { -+// status = TINFL_STATUS_FAILED; -+// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -+// break; -+// } -+// cur_file_ofs += read_buf_avail; -+// comp_remaining -= read_buf_avail; -+// read_buf_ofs = 0; -+// } -+// in_buf_size = (size_t)read_buf_avail; -+// status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); -+// read_buf_avail -= in_buf_size; -+// read_buf_ofs += in_buf_size; -+// out_buf_ofs += out_buf_size; -+// } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); -+ -+// if (status == TINFL_STATUS_DONE) -+// { -+// /* Make sure the entire file was decompressed, and check its CRC. */ -+// if (out_buf_ofs != file_stat.m_uncomp_size) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -+// status = TINFL_STATUS_FAILED; -+// } -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); -+// status = TINFL_STATUS_FAILED; -+// } -+// #endif -+// } - --void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) --{ -- mz_uint64 comp_size, uncomp_size, alloc_size; -- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -- void *pBuf; -+// if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - -- if (pSize) -- *pSize = 0; -+// return status == TINFL_STATUS_DONE; -+// } - -- if (!p) -- { -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- return NULL; -- } -+// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -+// { -+// mz_uint32 file_index; -+// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -+// return MZ_FALSE; -+// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); -+// } - -- comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -- uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); -+// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) -+// { -+// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); -+// } - -- alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; -- if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) -- { -- mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -- return NULL; -- } -+// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) -+// { -+// return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); -+// } - -- if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) -- { -- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- return NULL; -- } -+// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) -+// { -+// mz_uint64 comp_size, uncomp_size, alloc_size; -+// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -+// void *pBuf; - -- if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -- return NULL; -- } -+// if (pSize) -+// *pSize = 0; - -- if (pSize) -- *pSize = (size_t)alloc_size; -- return pBuf; --} -+// if (!p) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return NULL; -+// } - --void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) --{ -- mz_uint32 file_index; -- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -- { -- if (pSize) -- *pSize = 0; -- return MZ_FALSE; -- } -- return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); --} -+// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -+// uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - --mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) --{ -- int status = TINFL_STATUS_DONE; -- mz_uint file_crc32 = MZ_CRC32_INIT; -- mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; -- mz_zip_archive_file_stat file_stat; -- void *pRead_buf = NULL; -- void *pWrite_buf = NULL; -- mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -- mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -- -- if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- -- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -- return MZ_FALSE; -- -- /* A directory or zero length file */ -- if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) -- return MZ_TRUE; -- -- /* Encryption and patch files are not supported. */ -- if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -- -- /* This function only supports decompressing stored and deflate. */ -- if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -- -- /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ -- cur_file_ofs = file_stat.m_local_header_ofs; -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -- -- if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- -- cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -- if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- -- /* Decompress the file either directly from memory or from a file input buffer. */ -- if (pZip->m_pState->m_pMem) -- { -- pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; -- read_buf_size = read_buf_avail = file_stat.m_comp_size; -- comp_remaining = 0; -- } -- else -- { -- read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -- if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; -+// if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// return NULL; -+// } - -- read_buf_avail = 0; -- comp_remaining = file_stat.m_comp_size; -- } -+// if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// return NULL; -+// } - -- if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) -- { -- /* The file is stored or the caller has requested the compressed data. */ -- if (pZip->m_pState->m_pMem) -- { -- if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -+// return NULL; -+// } - -- if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) -- { -- mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -- status = TINFL_STATUS_FAILED; -- } -- else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -- { --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); --#endif -- } -+// if (pSize) -+// *pSize = (size_t)alloc_size; -+// return pBuf; -+// } - -- cur_file_ofs += file_stat.m_comp_size; -- out_buf_ofs += file_stat.m_comp_size; -- comp_remaining = 0; -- } -- else -- { -- while (comp_remaining) -- { -- read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -- { -- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -- status = TINFL_STATUS_FAILED; -- break; -- } -+// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) -+// { -+// mz_uint32 file_index; -+// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -+// { -+// if (pSize) -+// *pSize = 0; -+// return MZ_FALSE; -+// } -+// return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); -+// } - --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -- { -- file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); -- } --#endif -+// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -+// { -+// int status = TINFL_STATUS_DONE; -+// mz_uint file_crc32 = MZ_CRC32_INIT; -+// mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; -+// mz_zip_archive_file_stat file_stat; -+// void *pRead_buf = NULL; -+// void *pWrite_buf = NULL; -+// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -+// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - -- if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -- { -- mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -- status = TINFL_STATUS_FAILED; -- break; -- } -+// if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- cur_file_ofs += read_buf_avail; -- out_buf_ofs += read_buf_avail; -- comp_remaining -= read_buf_avail; -- } -- } -- } -- else -- { -- tinfl_decompressor inflator; -- tinfl_init(&inflator); -+// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -+// return MZ_FALSE; - -- if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) -- { -- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- status = TINFL_STATUS_FAILED; -- } -- else -- { -- do -- { -- mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -- size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -- if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) -- { -- read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -- { -- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -- status = TINFL_STATUS_FAILED; -- break; -- } -- cur_file_ofs += read_buf_avail; -- comp_remaining -= read_buf_avail; -- read_buf_ofs = 0; -- } -+// /* A directory or zero length file */ -+// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) -+// return MZ_TRUE; - -- in_buf_size = (size_t)read_buf_avail; -- status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); -- read_buf_avail -= in_buf_size; -- read_buf_ofs += in_buf_size; -+// /* Encryption and patch files are not supported. */ -+// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - -- if (out_buf_size) -- { -- if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) -- { -- mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -- status = TINFL_STATUS_FAILED; -- break; -- } -+// /* This function only supports decompressing stored and deflate. */ -+// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); - --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); --#endif -- if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) -- { -- mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -- status = TINFL_STATUS_FAILED; -- break; -- } -- } -- } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); -- } -- } -+// /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ -+// cur_file_ofs = file_stat.m_local_header_ofs; -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -- if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -- { -- /* Make sure the entire file was decompressed, and check its CRC. */ -- if (out_buf_ofs != file_stat.m_uncomp_size) -- { -- mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -- status = TINFL_STATUS_FAILED; -- } --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- else if (file_crc32 != file_stat.m_crc32) -- { -- mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -- status = TINFL_STATUS_FAILED; -- } --#endif -- } -+// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (!pZip->m_pState->m_pMem) -- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -+// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -+// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -- if (pWrite_buf) -- pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); -+// /* Decompress the file either directly from memory or from a file input buffer. */ -+// if (pZip->m_pState->m_pMem) -+// { -+// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; -+// read_buf_size = read_buf_avail = file_stat.m_comp_size; -+// comp_remaining = 0; -+// } -+// else -+// { -+// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -+// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -- return status == TINFL_STATUS_DONE; --} -+// read_buf_avail = 0; -+// comp_remaining = file_stat.m_comp_size; -+// } - --mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) --{ -- mz_uint32 file_index; -- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -- return MZ_FALSE; -+// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) -+// { -+// /* The file is stored or the caller has requested the compressed data. */ -+// if (pZip->m_pState->m_pMem) -+// { -+// if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -- return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); --} -+// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -+// status = TINFL_STATUS_FAILED; -+// } -+// else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -+// { -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); -+// #endif -+// } - --mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) --{ -- mz_zip_reader_extract_iter_state *pState; -- mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -- mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -+// cur_file_ofs += file_stat.m_comp_size; -+// out_buf_ofs += file_stat.m_comp_size; -+// comp_remaining = 0; -+// } -+// else -+// { -+// while (comp_remaining) -+// { -+// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// status = TINFL_STATUS_FAILED; -+// break; -+// } - -- /* Argument sanity check */ -- if ((!pZip) || (!pZip->m_pState)) -- return NULL; -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -+// { -+// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); -+// } -+// #endif - -- /* Allocate an iterator status structure */ -- pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); -- if (!pState) -- { -- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- return NULL; -- } -+// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -+// status = TINFL_STATUS_FAILED; -+// break; -+// } - -- /* Fetch file details */ -- if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -+// cur_file_ofs += read_buf_avail; -+// out_buf_ofs += read_buf_avail; -+// comp_remaining -= read_buf_avail; -+// } -+// } -+// } -+// else -+// { -+// tinfl_decompressor inflator; -+// tinfl_init(&inflator); - -- /* Encryption and patch files are not supported. */ -- if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -- { -- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -+// if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// status = TINFL_STATUS_FAILED; -+// } -+// else -+// { -+// do -+// { -+// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -+// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -+// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) -+// { -+// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -+// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// status = TINFL_STATUS_FAILED; -+// break; -+// } -+// cur_file_ofs += read_buf_avail; -+// comp_remaining -= read_buf_avail; -+// read_buf_ofs = 0; -+// } - -- /* This function only supports decompressing stored and deflate. */ -- if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) -- { -- mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -+// in_buf_size = (size_t)read_buf_avail; -+// status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); -+// read_buf_avail -= in_buf_size; -+// read_buf_ofs += in_buf_size; - -- /* Init state - save args */ -- pState->pZip = pZip; -- pState->flags = flags; -+// if (out_buf_size) -+// { -+// if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -+// status = TINFL_STATUS_FAILED; -+// break; -+// } -+ -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); -+// #endif -+// if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -+// status = TINFL_STATUS_FAILED; -+// break; -+// } -+// } -+// } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); -+// } -+// } - -- /* Init state - reset variables to defaults */ -- pState->status = TINFL_STATUS_DONE; --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- pState->file_crc32 = MZ_CRC32_INIT; --#endif -- pState->read_buf_ofs = 0; -- pState->out_buf_ofs = 0; -- pState->pRead_buf = NULL; -- pState->pWrite_buf = NULL; -- pState->out_blk_remain = 0; -- -- /* Read and parse the local directory entry. */ -- pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; -- if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -- { -- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -+// if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -+// { -+// /* Make sure the entire file was decompressed, and check its CRC. */ -+// if (out_buf_ofs != file_stat.m_uncomp_size) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -+// status = TINFL_STATUS_FAILED; -+// } -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// else if (file_crc32 != file_stat.m_crc32) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -+// status = TINFL_STATUS_FAILED; -+// } -+// #endif -+// } - -- if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -- { -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -+// if (!pZip->m_pState->m_pMem) -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - -- pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -- if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) -- { -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -+// if (pWrite_buf) -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); - -- /* Decompress the file either directly from memory or from a file input buffer. */ -- if (pZip->m_pState->m_pMem) -- { -- pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; -- pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; -- pState->comp_remaining = pState->file_stat.m_comp_size; -- } -- else -- { -- if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) -- { -- /* Decompression required, therefore intermediate read buffer required */ -- pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); -- if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) -- { -- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -- } -- else -- { -- /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ -- pState->read_buf_size = 0; -- } -- pState->read_buf_avail = 0; -- pState->comp_remaining = pState->file_stat.m_comp_size; -- } -+// return status == TINFL_STATUS_DONE; -+// } -+ -+// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -+// { -+// mz_uint32 file_index; -+// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -+// return MZ_FALSE; -+ -+// return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); -+// } -+ -+// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) -+// { -+// mz_zip_reader_extract_iter_state *pState; -+// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -+// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -+ -+// /* Argument sanity check */ -+// if ((!pZip) || (!pZip->m_pState)) -+// return NULL; -+ -+// /* Allocate an iterator status structure */ -+// pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); -+// if (!pState) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// return NULL; -+// } -+ -+// /* Fetch file details */ -+// if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } -+ -+// /* Encryption and patch files are not supported. */ -+// if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } -+ -+// /* This function only supports decompressing stored and deflate. */ -+// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } -+ -+// /* Init state - save args */ -+// pState->pZip = pZip; -+// pState->flags = flags; -+ -+// /* Init state - reset variables to defaults */ -+// pState->status = TINFL_STATUS_DONE; -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// pState->file_crc32 = MZ_CRC32_INIT; -+// #endif -+// pState->read_buf_ofs = 0; -+// pState->out_buf_ofs = 0; -+// pState->pRead_buf = NULL; -+// pState->pWrite_buf = NULL; -+// pState->out_blk_remain = 0; -+ -+// /* Read and parse the local directory entry. */ -+// pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; -+// if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } -+ -+// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } -+ -+// pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -+// if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } - -- if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) -- { -- /* Decompression required, init decompressor */ -- tinfl_init( &pState->inflator ); -+// /* Decompress the file either directly from memory or from a file input buffer. */ -+// if (pZip->m_pState->m_pMem) -+// { -+// pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; -+// pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; -+// pState->comp_remaining = pState->file_stat.m_comp_size; -+// } -+// else -+// { -+// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) -+// { -+// /* Decompression required, therefore intermediate read buffer required */ -+// pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); -+// if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } -+// } -+// else -+// { -+// /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ -+// pState->read_buf_size = 0; -+// } -+// pState->read_buf_avail = 0; -+// pState->comp_remaining = pState->file_stat.m_comp_size; -+// } - -- /* Allocate write buffer */ -- if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) -- { -- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- if (pState->pRead_buf) -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- return NULL; -- } -- } -+// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) -+// { -+// /* Decompression required, init decompressor */ -+// tinfl_init( &pState->inflator ); - -- return pState; --} -+// /* Allocate write buffer */ -+// if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// if (pState->pRead_buf) -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// return NULL; -+// } -+// } - --mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) --{ -- mz_uint32 file_index; -+// return pState; -+// } - -- /* Locate file index by name */ -- if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -- return NULL; -+// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) -+// { -+// mz_uint32 file_index; - -- /* Construct iterator */ -- return mz_zip_reader_extract_iter_new(pZip, file_index, flags); --} -+// /* Locate file index by name */ -+// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -+// return NULL; - --size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) --{ -- size_t copied_to_caller = 0; -+// /* Construct iterator */ -+// return mz_zip_reader_extract_iter_new(pZip, file_index, flags); -+// } - -- /* Argument sanity check */ -- if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) -- return 0; -+// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) -+// { -+// size_t copied_to_caller = 0; - -- if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) -- { -- /* The file is stored or the caller has requested the compressed data, calc amount to return. */ -- copied_to_caller = MZ_MIN( buf_size, pState->comp_remaining ); -+// /* Argument sanity check */ -+// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) -+// return 0; - -- /* Zip is in memory....or requires reading from a file? */ -- if (pState->pZip->m_pState->m_pMem) -- { -- /* Copy data to caller's buffer */ -- memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); -- pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; -- } -- else -- { -- /* Read directly into caller's buffer */ -- if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) -- { -- /* Failed to read all that was asked for, flag failure and alert user */ -- mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); -- pState->status = TINFL_STATUS_FAILED; -- copied_to_caller = 0; -- } -- } -+// if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) -+// { -+// /* The file is stored or the caller has requested the compressed data, calc amount to return. */ -+// copied_to_caller = MZ_MIN( buf_size, pState->comp_remaining ); - --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- /* Compute CRC if not returning compressed data only */ -- if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -- pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); --#endif -+// /* Zip is in memory....or requires reading from a file? */ -+// if (pState->pZip->m_pState->m_pMem) -+// { -+// /* Copy data to caller's buffer */ -+// memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); -+// pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; -+// } -+// else -+// { -+// /* Read directly into caller's buffer */ -+// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) -+// { -+// /* Failed to read all that was asked for, flag failure and alert user */ -+// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); -+// pState->status = TINFL_STATUS_FAILED; -+// copied_to_caller = 0; -+// } -+// } - -- /* Advance offsets, dec counters */ -- pState->cur_file_ofs += copied_to_caller; -- pState->out_buf_ofs += copied_to_caller; -- pState->comp_remaining -= copied_to_caller; -- } -- else -- { -- do -- { -- /* Calc ptr to write buffer - given current output pos and block size */ -- mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// /* Compute CRC if not returning compressed data only */ -+// if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -+// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); -+// #endif - -- /* Calc max output size - given current output pos and block size */ -- size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -+// /* Advance offsets, dec counters */ -+// pState->cur_file_ofs += copied_to_caller; -+// pState->out_buf_ofs += copied_to_caller; -+// pState->comp_remaining -= copied_to_caller; -+// } -+// else -+// { -+// do -+// { -+// /* Calc ptr to write buffer - given current output pos and block size */ -+// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - -- if (!pState->out_blk_remain) -- { -- /* Read more data from file if none available (and reading from file) */ -- if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) -- { -- /* Calc read size */ -- pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); -- if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) -- { -- mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); -- pState->status = TINFL_STATUS_FAILED; -- break; -- } -+// /* Calc max output size - given current output pos and block size */ -+// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - -- /* Advance offsets, dec counters */ -- pState->cur_file_ofs += pState->read_buf_avail; -- pState->comp_remaining -= pState->read_buf_avail; -- pState->read_buf_ofs = 0; -- } -+// if (!pState->out_blk_remain) -+// { -+// /* Read more data from file if none available (and reading from file) */ -+// if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) -+// { -+// /* Calc read size */ -+// pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); -+// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) -+// { -+// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); -+// pState->status = TINFL_STATUS_FAILED; -+// break; -+// } -+ -+// /* Advance offsets, dec counters */ -+// pState->cur_file_ofs += pState->read_buf_avail; -+// pState->comp_remaining -= pState->read_buf_avail; -+// pState->read_buf_ofs = 0; -+// } - -- /* Perform decompression */ -- in_buf_size = (size_t)pState->read_buf_avail; -- pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); -- pState->read_buf_avail -= in_buf_size; -- pState->read_buf_ofs += in_buf_size; -+// /* Perform decompression */ -+// in_buf_size = (size_t)pState->read_buf_avail; -+// pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); -+// pState->read_buf_avail -= in_buf_size; -+// pState->read_buf_ofs += in_buf_size; - -- /* Update current output block size remaining */ -- pState->out_blk_remain = out_buf_size; -- } -+// /* Update current output block size remaining */ -+// pState->out_blk_remain = out_buf_size; -+// } - -- if (pState->out_blk_remain) -- { -- /* Calc amount to return. */ -- size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); -+// if (pState->out_blk_remain) -+// { -+// /* Calc amount to return. */ -+// size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); - -- /* Copy data to caller's buffer */ -- memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); -+// /* Copy data to caller's buffer */ -+// memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); - --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- /* Perform CRC */ -- pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); --#endif -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// /* Perform CRC */ -+// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); -+// #endif - -- /* Decrement data consumed from block */ -- pState->out_blk_remain -= to_copy; -+// /* Decrement data consumed from block */ -+// pState->out_blk_remain -= to_copy; - -- /* Inc output offset, while performing sanity check */ -- if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) -- { -- mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); -- pState->status = TINFL_STATUS_FAILED; -- break; -- } -+// /* Inc output offset, while performing sanity check */ -+// if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) -+// { -+// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); -+// pState->status = TINFL_STATUS_FAILED; -+// break; -+// } - -- /* Increment counter of data copied to caller */ -- copied_to_caller += to_copy; -- } -- } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); -- } -+// /* Increment counter of data copied to caller */ -+// copied_to_caller += to_copy; -+// } -+// } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); -+// } - -- /* Return how many bytes were copied into user buffer */ -- return copied_to_caller; --} -+// /* Return how many bytes were copied into user buffer */ -+// return copied_to_caller; -+// } - --mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) --{ -- int status; -+// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) -+// { -+// int status; - -- /* Argument sanity check */ -- if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) -- return MZ_FALSE; -+// /* Argument sanity check */ -+// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) -+// return MZ_FALSE; - -- /* Was decompression completed and requested? */ -- if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -- { -- /* Make sure the entire file was decompressed, and check its CRC. */ -- if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) -- { -- mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -- pState->status = TINFL_STATUS_FAILED; -- } --#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -- else if (pState->file_crc32 != pState->file_stat.m_crc32) -- { -- mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); -- pState->status = TINFL_STATUS_FAILED; -- } --#endif -- } -+// /* Was decompression completed and requested? */ -+// if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -+// { -+// /* Make sure the entire file was decompressed, and check its CRC. */ -+// if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) -+// { -+// mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -+// pState->status = TINFL_STATUS_FAILED; -+// } -+// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -+// else if (pState->file_crc32 != pState->file_stat.m_crc32) -+// { -+// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); -+// pState->status = TINFL_STATUS_FAILED; -+// } -+// #endif -+// } - -- /* Free buffers */ -- if (!pState->pZip->m_pState->m_pMem) -- pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); -- if (pState->pWrite_buf) -- pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); -+// /* Free buffers */ -+// if (!pState->pZip->m_pState->m_pMem) -+// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); -+// if (pState->pWrite_buf) -+// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); - -- /* Save status */ -- status = pState->status; -+// /* Save status */ -+// status = pState->status; - -- /* Free context */ -- pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); -+// /* Free context */ -+// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); - -- return status == TINFL_STATUS_DONE; --} -+// return status == TINFL_STATUS_DONE; -+// } - --#ifndef MINIZ_NO_STDIO --static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) --{ -- (void)ofs; -+// #ifndef MINIZ_NO_STDIO -+// static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) -+// { -+// (void)ofs; - -- return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); --} -+// return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); -+// } - --mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) --{ -- mz_bool status; -- mz_zip_archive_file_stat file_stat; -- MZ_FILE *pFile; -+// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) -+// { -+// mz_bool status; -+// mz_zip_archive_file_stat file_stat; -+// MZ_FILE *pFile; - -- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -- return MZ_FALSE; -+// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -+// return MZ_FALSE; - -- if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); -+// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); - -- pFile = MZ_FOPEN(pDst_filename, "wb"); -- if (!pFile) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -+// pFile = MZ_FOPEN(pDst_filename, "wb"); -+// if (!pFile) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -- status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); -+// status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); - -- if (MZ_FCLOSE(pFile) == EOF) -- { -- if (status) -- mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); -+// if (MZ_FCLOSE(pFile) == EOF) -+// { -+// if (status) -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); - -- status = MZ_FALSE; -- } -+// status = MZ_FALSE; -+// } - --#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) -- if (status) -- mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); --#endif -+// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) -+// if (status) -+// mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); -+// #endif - -- return status; --} -+// return status; -+// } - --mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) --{ -- mz_uint32 file_index; -- if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) -- return MZ_FALSE; -+// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) -+// { -+// mz_uint32 file_index; -+// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) -+// return MZ_FALSE; - -- return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); --} -+// return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); -+// } - --mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) --{ -- mz_zip_archive_file_stat file_stat; -+// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) -+// { -+// mz_zip_archive_file_stat file_stat; - -- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -- return MZ_FALSE; -+// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -+// return MZ_FALSE; - -- if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); -+// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); - -- return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); --} -+// return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); -+// } - --mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) --{ -- mz_uint32 file_index; -- if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) -- return MZ_FALSE; -+// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) -+// { -+// mz_uint32 file_index; -+// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) -+// return MZ_FALSE; - -- return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); --} --#endif /* #ifndef MINIZ_NO_STDIO */ -+// return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); -+// } -+// #endif /* #ifndef MINIZ_NO_STDIO */ - - // static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) - // { -@@ -5444,1202 +5443,1202 @@ mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pA - - /* ------------------- .ZIP archive writing */ - --#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -+// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - --static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) --{ -- p[0] = (mz_uint8)v; -- p[1] = (mz_uint8)(v >> 8); --} --static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) --{ -- p[0] = (mz_uint8)v; -- p[1] = (mz_uint8)(v >> 8); -- p[2] = (mz_uint8)(v >> 16); -- p[3] = (mz_uint8)(v >> 24); --} --static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) --{ -- mz_write_le32(p, (mz_uint32)v); -- mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); --} -+// static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) -+// { -+// p[0] = (mz_uint8)v; -+// p[1] = (mz_uint8)(v >> 8); -+// } -+// static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) -+// { -+// p[0] = (mz_uint8)v; -+// p[1] = (mz_uint8)(v >> 8); -+// p[2] = (mz_uint8)(v >> 16); -+// p[3] = (mz_uint8)(v >> 24); -+// } -+// static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) -+// { -+// mz_write_le32(p, (mz_uint32)v); -+// mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); -+// } - --#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) --#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) --#define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) -+// #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) -+// #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) -+// #define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) - --static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) --{ -- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -- mz_zip_internal_state *pState = pZip->m_pState; -- mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); -+// static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -+// { -+// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -+// mz_zip_internal_state *pState = pZip->m_pState; -+// mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); - -- if (!n) -- return 0; -+// if (!n) -+// return 0; - -- /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ -- if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) -- { -- mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -- return 0; -- } -+// /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ -+// if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -+// return 0; -+// } - -- if (new_size > pState->m_mem_capacity) -- { -- void *pNew_block; -- size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); -+// if (new_size > pState->m_mem_capacity) -+// { -+// void *pNew_block; -+// size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); - -- while (new_capacity < new_size) -- new_capacity *= 2; -+// while (new_capacity < new_size) -+// new_capacity *= 2; - -- if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) -- { -- mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- return 0; -- } -+// if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// return 0; -+// } - -- pState->m_pMem = pNew_block; -- pState->m_mem_capacity = new_capacity; -- } -- memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); -- pState->m_mem_size = (size_t)new_size; -- return n; --} -+// pState->m_pMem = pNew_block; -+// pState->m_mem_capacity = new_capacity; -+// } -+// memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); -+// pState->m_mem_size = (size_t)new_size; -+// return n; -+// } - --static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) --{ -- mz_zip_internal_state *pState; -- mz_bool status = MZ_TRUE; -+// static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) -+// { -+// mz_zip_internal_state *pState; -+// mz_bool status = MZ_TRUE; - -- if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) -- { -- if (set_last_error) -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- return MZ_FALSE; -- } -+// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) -+// { -+// if (set_last_error) -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return MZ_FALSE; -+// } - -- pState = pZip->m_pState; -- pZip->m_pState = NULL; -- mz_zip_array_clear(pZip, &pState->m_central_dir); -- mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); -- mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); -+// pState = pZip->m_pState; -+// pZip->m_pState = NULL; -+// mz_zip_array_clear(pZip, &pState->m_central_dir); -+// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); -+// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); - --#ifndef MINIZ_NO_STDIO -- if (pState->m_pFile) -- { -- if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -- { -- if (MZ_FCLOSE(pState->m_pFile) == EOF) -- { -- if (set_last_error) -- mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); -- status = MZ_FALSE; -- } -- } -+// #ifndef MINIZ_NO_STDIO -+// if (pState->m_pFile) -+// { -+// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -+// { -+// if (MZ_FCLOSE(pState->m_pFile) == EOF) -+// { -+// if (set_last_error) -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); -+// status = MZ_FALSE; -+// } -+// } - -- pState->m_pFile = NULL; -- } --#endif /* #ifndef MINIZ_NO_STDIO */ -+// pState->m_pFile = NULL; -+// } -+// #endif /* #ifndef MINIZ_NO_STDIO */ - -- if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); -- pState->m_pMem = NULL; -- } -+// if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); -+// pState->m_pMem = NULL; -+// } - -- pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -- pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; -- return status; --} -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -+// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; -+// return status; -+// } - --mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) --{ -- mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; -+// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) -+// { -+// mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; - -- if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -- { -- if (!pZip->m_pRead) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- } -+// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -+// { -+// if (!pZip->m_pRead) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// } - -- if (pZip->m_file_offset_alignment) -- { -- /* Ensure user specified file offset alignment is a power of 2. */ -- if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- } -+// if (pZip->m_file_offset_alignment) -+// { -+// /* Ensure user specified file offset alignment is a power of 2. */ -+// if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// } - -- if (!pZip->m_pAlloc) -- pZip->m_pAlloc = miniz_def_alloc_func; -- if (!pZip->m_pFree) -- pZip->m_pFree = miniz_def_free_func; -- if (!pZip->m_pRealloc) -- pZip->m_pRealloc = miniz_def_realloc_func; -+// if (!pZip->m_pAlloc) -+// pZip->m_pAlloc = miniz_def_alloc_func; -+// if (!pZip->m_pFree) -+// pZip->m_pFree = miniz_def_free_func; -+// if (!pZip->m_pRealloc) -+// pZip->m_pRealloc = miniz_def_realloc_func; - -- pZip->m_archive_size = existing_size; -- pZip->m_central_directory_file_ofs = 0; -- pZip->m_total_files = 0; -+// pZip->m_archive_size = existing_size; -+// pZip->m_central_directory_file_ofs = 0; -+// pZip->m_total_files = 0; - -- if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -- memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); -+// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); - -- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); -- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); -- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); -+// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); -+// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); -+// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); - -- pZip->m_pState->m_zip64 = zip64; -- pZip->m_pState->m_zip64_has_extended_info_fields = zip64; -+// pZip->m_pState->m_zip64 = zip64; -+// pZip->m_pState->m_zip64_has_extended_info_fields = zip64; - -- pZip->m_zip_type = MZ_ZIP_TYPE_USER; -- pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; -+// pZip->m_zip_type = MZ_ZIP_TYPE_USER; -+// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - -- return MZ_TRUE; --} -+// return MZ_TRUE; -+// } - --mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) --{ -- return mz_zip_writer_init_v2(pZip, existing_size, 0); --} -+// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) -+// { -+// return mz_zip_writer_init_v2(pZip, existing_size, 0); -+// } - --mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) --{ -- pZip->m_pWrite = mz_zip_heap_write_func; -- pZip->m_pNeeds_keepalive = NULL; -+// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) -+// { -+// pZip->m_pWrite = mz_zip_heap_write_func; -+// pZip->m_pNeeds_keepalive = NULL; - -- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -- pZip->m_pRead = mz_zip_mem_read_func; -+// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -+// pZip->m_pRead = mz_zip_mem_read_func; - -- pZip->m_pIO_opaque = pZip; -+// pZip->m_pIO_opaque = pZip; - -- if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) -- return MZ_FALSE; -+// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) -+// return MZ_FALSE; - -- pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; -+// pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; - -- if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) -- { -- if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) -- { -- mz_zip_writer_end_internal(pZip, MZ_FALSE); -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- } -- pZip->m_pState->m_mem_capacity = initial_allocation_size; -- } -+// if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) -+// { -+// if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) -+// { -+// mz_zip_writer_end_internal(pZip, MZ_FALSE); -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// } -+// pZip->m_pState->m_mem_capacity = initial_allocation_size; -+// } - -- return MZ_TRUE; --} -+// return MZ_TRUE; -+// } - --mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) --{ -- return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); --} -+// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) -+// { -+// return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); -+// } - --#ifndef MINIZ_NO_STDIO --static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) --{ -- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -- mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); -+// #ifndef MINIZ_NO_STDIO -+// static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -+// { -+// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -+// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - -- file_ofs += pZip->m_pState->m_file_archive_start_ofs; -+// file_ofs += pZip->m_pState->m_file_archive_start_ofs; - -- if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) -- { -- mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); -- return 0; -- } -+// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); -+// return 0; -+// } - -- return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); --} -+// return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); -+// } - --mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) --{ -- return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); --} -+// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) -+// { -+// return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); -+// } - --mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) --{ -- MZ_FILE *pFile; -+// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) -+// { -+// MZ_FILE *pFile; - -- pZip->m_pWrite = mz_zip_file_write_func; -- pZip->m_pNeeds_keepalive = NULL; -+// pZip->m_pWrite = mz_zip_file_write_func; -+// pZip->m_pNeeds_keepalive = NULL; - -- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -- pZip->m_pRead = mz_zip_file_read_func; -+// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -+// pZip->m_pRead = mz_zip_file_read_func; - -- pZip->m_pIO_opaque = pZip; -+// pZip->m_pIO_opaque = pZip; -+ -+// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) -+// return MZ_FALSE; -+ -+// if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) -+// { -+// mz_zip_writer_end(pZip); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -+// } - -- if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) -- return MZ_FALSE; -+// pZip->m_pState->m_pFile = pFile; -+// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; - -- if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) -- { -- mz_zip_writer_end(pZip); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -- } -+// if (size_to_reserve_at_beginning) -+// { -+// mz_uint64 cur_ofs = 0; -+// char buf[4096]; - -- pZip->m_pState->m_pFile = pFile; -- pZip->m_zip_type = MZ_ZIP_TYPE_FILE; -+// MZ_CLEAR_OBJ(buf); - -- if (size_to_reserve_at_beginning) -- { -- mz_uint64 cur_ofs = 0; -- char buf[4096]; -+// do -+// { -+// size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) -+// { -+// mz_zip_writer_end(pZip); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// } -+// cur_ofs += n; -+// size_to_reserve_at_beginning -= n; -+// } while (size_to_reserve_at_beginning); -+// } - -- MZ_CLEAR_OBJ(buf); -+// return MZ_TRUE; -+// } - -- do -- { -- size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) -- { -- mz_zip_writer_end(pZip); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- } -- cur_ofs += n; -- size_to_reserve_at_beginning -= n; -- } while (size_to_reserve_at_beginning); -- } -+// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) -+// { -+// pZip->m_pWrite = mz_zip_file_write_func; -+// pZip->m_pNeeds_keepalive = NULL; - -- return MZ_TRUE; --} -+// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -+// pZip->m_pRead = mz_zip_file_read_func; - --mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) --{ -- pZip->m_pWrite = mz_zip_file_write_func; -- pZip->m_pNeeds_keepalive = NULL; -+// pZip->m_pIO_opaque = pZip; - -- if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -- pZip->m_pRead = mz_zip_file_read_func; -+// if (!mz_zip_writer_init_v2(pZip, 0, flags)) -+// return MZ_FALSE; - -- pZip->m_pIO_opaque = pZip; -+// pZip->m_pState->m_pFile = pFile; -+// pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); -+// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; - -- if (!mz_zip_writer_init_v2(pZip, 0, flags)) -- return MZ_FALSE; -+// return MZ_TRUE; -+// } -+// #endif /* #ifndef MINIZ_NO_STDIO */ - -- pZip->m_pState->m_pFile = pFile; -- pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); -- pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; -+// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) -+// { -+// mz_zip_internal_state *pState; - -- return MZ_TRUE; --} --#endif /* #ifndef MINIZ_NO_STDIO */ -+// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - --mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) --{ -- mz_zip_internal_state *pState; -+// if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) -+// { -+// /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ -+// if (!pZip->m_pState->m_zip64) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// } - -- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// /* No sense in trying to write to an archive that's already at the support max size */ -+// if (pZip->m_pState->m_zip64) -+// { -+// if (pZip->m_total_files == MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// } -+// else -+// { -+// if (pZip->m_total_files == MZ_UINT16_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - -- if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) -- { -- /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ -- if (!pZip->m_pState->m_zip64) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- } -+// if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -+// } - -- /* No sense in trying to write to an archive that's already at the support max size */ -- if (pZip->m_pState->m_zip64) -- { -- if (pZip->m_total_files == MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -- } -- else -- { -- if (pZip->m_total_files == MZ_UINT16_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// pState = pZip->m_pState; - -- if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -- } -+// if (pState->m_pFile) -+// { -+// #ifdef MINIZ_NO_STDIO -+// (void)pFilename; -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// #else -+// if (pZip->m_pIO_opaque != pZip) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- pState = pZip->m_pState; -+// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -+// { -+// if (!pFilename) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if (pState->m_pFile) -- { --#ifdef MINIZ_NO_STDIO -- (void)pFilename; -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); --#else -- if (pZip->m_pIO_opaque != pZip) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ -+// if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) -+// { -+// /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ -+// mz_zip_reader_end_internal(pZip, MZ_FALSE); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -+// } -+// } - -- if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -- { -- if (!pFilename) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// pZip->m_pWrite = mz_zip_file_write_func; -+// pZip->m_pNeeds_keepalive = NULL; -+// #endif /* #ifdef MINIZ_NO_STDIO */ -+// } -+// else if (pState->m_pMem) -+// { -+// /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ -+// if (pZip->m_pIO_opaque != pZip) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ -- if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) -- { -- /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ -- mz_zip_reader_end_internal(pZip, MZ_FALSE); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -- } -- } -+// pState->m_mem_capacity = pState->m_mem_size; -+// pZip->m_pWrite = mz_zip_heap_write_func; -+// pZip->m_pNeeds_keepalive = NULL; -+// } -+// /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ -+// else if (!pZip->m_pWrite) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- pZip->m_pWrite = mz_zip_file_write_func; -- pZip->m_pNeeds_keepalive = NULL; --#endif /* #ifdef MINIZ_NO_STDIO */ -- } -- else if (pState->m_pMem) -- { -- /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ -- if (pZip->m_pIO_opaque != pZip) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// /* Start writing new files at the archive's current central directory location. */ -+// /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ -+// pZip->m_archive_size = pZip->m_central_directory_file_ofs; -+// pZip->m_central_directory_file_ofs = 0; - -- pState->m_mem_capacity = pState->m_mem_size; -- pZip->m_pWrite = mz_zip_heap_write_func; -- pZip->m_pNeeds_keepalive = NULL; -- } -- /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ -- else if (!pZip->m_pWrite) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ -+// /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ -+// /* TODO: We could easily maintain the sorted central directory offsets. */ -+// mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); - -- /* Start writing new files at the archive's current central directory location. */ -- /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ -- pZip->m_archive_size = pZip->m_central_directory_file_ofs; -- pZip->m_central_directory_file_ofs = 0; -+// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - -- /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ -- /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ -- /* TODO: We could easily maintain the sorted central directory offsets. */ -- mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); -+// return MZ_TRUE; -+// } - -- pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; -+// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) -+// { -+// return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); -+// } - -- return MZ_TRUE; --} -+/* TODO: pArchive_name is a terrible name here! */ -+// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) -+// { -+// return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); -+// } - --mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) --{ -- return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); --} -+// typedef struct -+// { -+// mz_zip_archive *m_pZip; -+// mz_uint64 m_cur_archive_file_ofs; -+// mz_uint64 m_comp_size; -+// } mz_zip_writer_add_state; - --/* TODO: pArchive_name is a terrible name here! */ --mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) --{ -- return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); --} -+// static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) -+// { -+// mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; -+// if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) -+// return MZ_FALSE; - --typedef struct --{ -- mz_zip_archive *m_pZip; -- mz_uint64 m_cur_archive_file_ofs; -- mz_uint64 m_comp_size; --} mz_zip_writer_add_state; -+// pState->m_cur_archive_file_ofs += len; -+// pState->m_comp_size += len; -+// return MZ_TRUE; -+// } - --static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) --{ -- mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; -- if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) -- return MZ_FALSE; -+// #define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) -+// #define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) -+// static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) -+// { -+// mz_uint8 *pDst = pBuf; -+// mz_uint32 field_size = 0; - -- pState->m_cur_archive_file_ofs += len; -- pState->m_comp_size += len; -- return MZ_TRUE; --} -+// MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); -+// MZ_WRITE_LE16(pDst + 2, 0); -+// pDst += sizeof(mz_uint16) * 2; - --#define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) --#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) --static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) --{ -- mz_uint8 *pDst = pBuf; -- mz_uint32 field_size = 0; -+// if (pUncomp_size) -+// { -+// MZ_WRITE_LE64(pDst, *pUncomp_size); -+// pDst += sizeof(mz_uint64); -+// field_size += sizeof(mz_uint64); -+// } - -- MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); -- MZ_WRITE_LE16(pDst + 2, 0); -- pDst += sizeof(mz_uint16) * 2; -+// if (pComp_size) -+// { -+// MZ_WRITE_LE64(pDst, *pComp_size); -+// pDst += sizeof(mz_uint64); -+// field_size += sizeof(mz_uint64); -+// } - -- if (pUncomp_size) -- { -- MZ_WRITE_LE64(pDst, *pUncomp_size); -- pDst += sizeof(mz_uint64); -- field_size += sizeof(mz_uint64); -- } -+// if (pLocal_header_ofs) -+// { -+// MZ_WRITE_LE64(pDst, *pLocal_header_ofs); -+// pDst += sizeof(mz_uint64); -+// field_size += sizeof(mz_uint64); -+// } - -- if (pComp_size) -- { -- MZ_WRITE_LE64(pDst, *pComp_size); -- pDst += sizeof(mz_uint64); -- field_size += sizeof(mz_uint64); -- } -+// MZ_WRITE_LE16(pBuf + 2, field_size); - -- if (pLocal_header_ofs) -- { -- MZ_WRITE_LE64(pDst, *pLocal_header_ofs); -- pDst += sizeof(mz_uint64); -- field_size += sizeof(mz_uint64); -- } -+// return (mz_uint32)(pDst - pBuf); -+// } - -- MZ_WRITE_LE16(pBuf + 2, field_size); -+// static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) -+// { -+// (void)pZip; -+// memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); -+// return MZ_TRUE; -+// } - -- return (mz_uint32)(pDst - pBuf); --} -+// static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, -+// mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, -+// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, -+// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, -+// mz_uint64 local_header_ofs, mz_uint32 ext_attributes) -+// { -+// (void)pZip; -+// memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); -+// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); -+// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); -+// return MZ_TRUE; -+// } - --static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) --{ -- (void)pZip; -- memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); -- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); -- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); -- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); -- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); -- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); -- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); -- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); -- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); -- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); -- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); -- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); -- return MZ_TRUE; --} -+// static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, -+// const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, -+// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, -+// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, -+// mz_uint64 local_header_ofs, mz_uint32 ext_attributes, -+// const char *user_extra_data, mz_uint user_extra_data_len) -+// { -+// mz_zip_internal_state *pState = pZip->m_pState; -+// mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; -+// size_t orig_central_dir_size = pState->m_central_dir.m_size; -+// mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; - --static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, -- mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, -- mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, -- mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, -- mz_uint64 local_header_ofs, mz_uint32 ext_attributes) --{ -- (void)pZip; -- memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); -- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); -- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); -- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); -- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); -- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); -- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); -- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); -- return MZ_TRUE; --} -+// if (!pZip->m_pState->m_zip64) -+// { -+// if (local_header_ofs > 0xFFFFFFFF) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -+// } - --static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, -- const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, -- mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, -- mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, -- mz_uint64 local_header_ofs, mz_uint32 ext_attributes, -- const char *user_extra_data, mz_uint user_extra_data_len) --{ -- mz_zip_internal_state *pState = pZip->m_pState; -- mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; -- size_t orig_central_dir_size = pState->m_central_dir.m_size; -- mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; -+// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -+// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -- if (!pZip->m_pState->m_zip64) -- { -- if (local_header_ofs > 0xFFFFFFFF) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -- } -+// if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size + user_extra_data_len, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -- /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -- if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); -+// if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || -+// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || -+// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || -+// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || -+// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || -+// (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) -+// { -+// /* Try to resize the central directory array back into its original state. */ -+// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// } - -- if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size + user_extra_data_len, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// return MZ_TRUE; -+// } - -- if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || -- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || -- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || -- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || -- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || -- (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) -- { -- /* Try to resize the central directory array back into its original state. */ -- mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- } -+// static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) -+// { -+// /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ -+// if (*pArchive_name == '/') -+// return MZ_FALSE; - -- return MZ_TRUE; --} -+// while (*pArchive_name) -+// { -+// if ((*pArchive_name == '\\') || (*pArchive_name == ':')) -+// return MZ_FALSE; - --static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) --{ -- /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ -- if (*pArchive_name == '/') -- return MZ_FALSE; -+// pArchive_name++; -+// } - -- while (*pArchive_name) -- { -- if ((*pArchive_name == '\\') || (*pArchive_name == ':')) -- return MZ_FALSE; -+// return MZ_TRUE; -+// } - -- pArchive_name++; -- } -+// static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) -+// { -+// mz_uint32 n; -+// if (!pZip->m_file_offset_alignment) -+// return 0; -+// n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); -+// return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); -+// } - -- return MZ_TRUE; --} -+// static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) -+// { -+// char buf[4096]; -+// memset(buf, 0, MZ_MIN(sizeof(buf), n)); -+// while (n) -+// { -+// mz_uint32 s = MZ_MIN(sizeof(buf), n); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - --static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) --{ -- mz_uint32 n; -- if (!pZip->m_file_offset_alignment) -- return 0; -- n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); -- return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); --} -+// cur_file_ofs += s; -+// n -= s; -+// } -+// return MZ_TRUE; -+// } - --static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) --{ -- char buf[4096]; -- memset(buf, 0, MZ_MIN(sizeof(buf), n)); -- while (n) -- { -- mz_uint32 s = MZ_MIN(sizeof(buf), n); -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -+// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) -+// { -+// return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); -+// } - -- cur_file_ofs += s; -- n -= s; -- } -- return MZ_TRUE; --} -+// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, -+// mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, -+// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) -+// { -+// if(!pZip) -+// { -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// } - --mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -- mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) --{ -- return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); --} -+// mz_uint16 method = 0, dos_time = 0, dos_date = 0; -+// mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; -+// mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; -+// size_t archive_name_size; -+// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; -+// tdefl_compressor *pComp = NULL; -+// mz_bool store_data_uncompressed; -+// mz_zip_internal_state *pState; -+// mz_uint8 *pExtra_data = NULL; -+// mz_uint32 extra_size = 0; -+// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; -+// mz_uint16 bit_flags = 0; - --mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, -- mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, -- const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) --{ -- if(!pZip) -- { -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- } -+// if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -+// bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; - -- mz_uint16 method = 0, dos_time = 0, dos_date = 0; -- mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; -- mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; -- size_t archive_name_size; -- mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; -- tdefl_compressor *pComp = NULL; -- mz_bool store_data_uncompressed; -- mz_zip_internal_state *pState; -- mz_uint8 *pExtra_data = NULL; -- mz_uint32 extra_size = 0; -- mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; -- mz_uint16 bit_flags = 0; -+// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) -+// bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; - -- if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -- bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; -+// if ((int)level_and_flags < 0) -+// level_and_flags = MZ_DEFAULT_LEVEL; -+// level = level_and_flags & 0xF; -+// store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); - -- if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) -- bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; -+// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if ((int)level_and_flags < 0) -- level_and_flags = MZ_DEFAULT_LEVEL; -- level = level_and_flags & 0xF; -- store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); -+// pState = pZip->m_pState; - -- if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if (pState->m_zip64) -+// { -+// if (pZip->m_total_files == MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// } -+// else -+// { -+// if (pZip->m_total_files == MZ_UINT16_MAX) -+// { -+// pState->m_zip64 = MZ_TRUE; -+// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ -+// } -+// if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) -+// { -+// pState->m_zip64 = MZ_TRUE; -+// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -+// } -+// } - -- pState = pZip->m_pState; -+// if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if (pState->m_zip64) -- { -- if (pZip->m_total_files == MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -- } -- else -- { -- if (pZip->m_total_files == MZ_UINT16_MAX) -- { -- pState->m_zip64 = MZ_TRUE; -- /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ -- } -- if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) -- { -- pState->m_zip64 = MZ_TRUE; -- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -- } -- } -+// if (!mz_zip_writer_validate_archive_name(pArchive_name)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - -- if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// #ifndef MINIZ_NO_TIME -+// if (last_modified != NULL) -+// { -+// mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); -+// } -+// else -+// { -+// MZ_TIME_T cur_time; -+// time(&cur_time); -+// mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); -+// } -+// #endif /* #ifndef MINIZ_NO_TIME */ - -- if (!mz_zip_writer_validate_archive_name(pArchive_name)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); -+// archive_name_size = strlen(pArchive_name); -+// if (archive_name_size > MZ_UINT16_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - --#ifndef MINIZ_NO_TIME -- if (last_modified != NULL) -- { -- mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); -- } -- else -- { -- MZ_TIME_T cur_time; -- time(&cur_time); -- mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); -- } --#endif /* #ifndef MINIZ_NO_TIME */ -+// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - -- archive_name_size = strlen(pArchive_name); -- if (archive_name_size > MZ_UINT16_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); -+// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -+// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -- num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); -+// if (!pState->m_zip64) -+// { -+// /* Bail early if the archive would obviously become too large */ -+// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size -+// + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + -+// pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len -+// + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) -+// { -+// pState->m_zip64 = MZ_TRUE; -+// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -+// } -+// } - -- /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -- if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); -+// if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) -+// { -+// /* Set DOS Subdirectory attribute bit. */ -+// ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; - -- if (!pState->m_zip64) -- { -- /* Bail early if the archive would obviously become too large */ -- if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size -- + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + -- pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len -- + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) -- { -- pState->m_zip64 = MZ_TRUE; -- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -- } -- } -+// /* Subdirectories cannot contain data. */ -+// if ((buf_size) || (uncomp_size)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// } - -- if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) -- { -- /* Set DOS Subdirectory attribute bit. */ -- ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; -+// /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ -+// if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -- /* Subdirectories cannot contain data. */ -- if ((buf_size) || (uncomp_size)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- } -+// if ((!store_data_uncompressed) && (buf_size)) -+// { -+// if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// } - -- /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ -- if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// return MZ_FALSE; -+// } - -- if ((!store_data_uncompressed) && (buf_size)) -- { -- if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- } -+// local_dir_header_ofs += num_alignment_padding_bytes; -+// if (pZip->m_file_offset_alignment) -+// { -+// MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); -+// } -+// cur_archive_file_ofs += num_alignment_padding_bytes; - -- if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -- return MZ_FALSE; -- } -+// MZ_CLEAR_OBJ(local_dir_header); - -- local_dir_header_ofs += num_alignment_padding_bytes; -- if (pZip->m_file_offset_alignment) -- { -- MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); -- } -- cur_archive_file_ofs += num_alignment_padding_bytes; -+// if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -+// { -+// method = MZ_DEFLATED; -+// } - -- MZ_CLEAR_OBJ(local_dir_header); -+// if (pState->m_zip64) -+// { -+// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) -+// { -+// pExtra_data = extra_data; -+// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -+// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -+// } - -- if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -- { -- method = MZ_DEFLATED; -- } -+// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -- if (pState->m_zip64) -- { -- if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) -- { -- pExtra_data = extra_data; -- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -- } -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// cur_archive_file_ofs += sizeof(local_dir_header); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// } -+// cur_archive_file_ofs += archive_name_size; - -- cur_archive_file_ofs += sizeof(local_dir_header); -+// if (pExtra_data != NULL) -+// { -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- } -- cur_archive_file_ofs += archive_name_size; -+// cur_archive_file_ofs += extra_size; -+// } -+// } -+// else -+// { -+// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) -+// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -+// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -- if (pExtra_data != NULL) -- { -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- cur_archive_file_ofs += extra_size; -- } -- } -- else -- { -- if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) -- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// cur_archive_file_ofs += sizeof(local_dir_header); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// } -+// cur_archive_file_ofs += archive_name_size; -+// } - -- cur_archive_file_ofs += sizeof(local_dir_header); -+// if (user_extra_data_len > 0) -+// { -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- } -- cur_archive_file_ofs += archive_name_size; -- } -+// cur_archive_file_ofs += user_extra_data_len; -+// } - -- if (user_extra_data_len > 0) -- { -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -+// { -+// uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); -+// uncomp_size = buf_size; -+// if (uncomp_size <= 3) -+// { -+// level = 0; -+// store_data_uncompressed = MZ_TRUE; -+// } -+// } - -- cur_archive_file_ofs += user_extra_data_len; -- } -+// if (store_data_uncompressed) -+// { -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// } - -- if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -- { -- uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); -- uncomp_size = buf_size; -- if (uncomp_size <= 3) -- { -- level = 0; -- store_data_uncompressed = MZ_TRUE; -- } -- } -+// cur_archive_file_ofs += buf_size; -+// comp_size = buf_size; -+// } -+// else if (buf_size) -+// { -+// mz_zip_writer_add_state state; - -- if (store_data_uncompressed) -- { -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- } -+// state.m_pZip = pZip; -+// state.m_cur_archive_file_ofs = cur_archive_file_ofs; -+// state.m_comp_size = 0; - -- cur_archive_file_ofs += buf_size; -- comp_size = buf_size; -- } -- else if (buf_size) -- { -- mz_zip_writer_add_state state; -+// if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || -+// (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); -+// } - -- state.m_pZip = pZip; -- state.m_cur_archive_file_ofs = cur_archive_file_ofs; -- state.m_comp_size = 0; -+// comp_size = state.m_comp_size; -+// cur_archive_file_ofs = state.m_cur_archive_file_ofs; -+// } - -- if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || -- (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -- return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); -- } -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// pComp = NULL; - -- comp_size = state.m_comp_size; -- cur_archive_file_ofs = state.m_cur_archive_file_ofs; -- } -+// if (uncomp_size) -+// { -+// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; -+// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; - -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -- pComp = NULL; -+// MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); - -- if (uncomp_size) -- { -- mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; -- mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; -+// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); -+// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); -+// if (pExtra_data == NULL) -+// { -+// if (comp_size > MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -- MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); -+// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); -+// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); -+// } -+// else -+// { -+// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); -+// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); -+// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; -+// } - -- MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); -- MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); -- if (pExtra_data == NULL) -- { -- if (comp_size > MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) -+// return MZ_FALSE; - -- MZ_WRITE_LE32(local_dir_footer + 8, comp_size); -- MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); -- } -- else -- { -- MZ_WRITE_LE64(local_dir_footer + 8, comp_size); -- MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); -- local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; -- } -+// cur_archive_file_ofs += local_dir_footer_size; -+// } - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) -- return MZ_FALSE; -+// if (pExtra_data != NULL) -+// { -+// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -+// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -+// } - -- cur_archive_file_ofs += local_dir_footer_size; -- } -+// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, -+// comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, -+// user_extra_data_central, user_extra_data_central_len)) -+// return MZ_FALSE; - -- if (pExtra_data != NULL) -- { -- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -- } -+// pZip->m_total_files++; -+// pZip->m_archive_size = cur_archive_file_ofs; - -- if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, -- comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, -- user_extra_data_central, user_extra_data_central_len)) -- return MZ_FALSE; -+// return MZ_TRUE; -+// } - -- pZip->m_total_files++; -- pZip->m_archive_size = cur_archive_file_ofs; -+// #ifndef MINIZ_NO_STDIO -+// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -+// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) -+// { -+// if(!pZip) -+// { -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// } - -- return MZ_TRUE; --} -+// mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; -+// mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; -+// mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; -+// mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; -+// size_t archive_name_size; -+// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; -+// mz_uint8 *pExtra_data = NULL; -+// mz_uint32 extra_size = 0; -+// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; -+// mz_zip_internal_state *pState; - --#ifndef MINIZ_NO_STDIO --mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -- const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) --{ -- if(!pZip) -- { -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- } -+// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) -+// gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; - -- mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; -- mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; -- mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; -- mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; -- size_t archive_name_size; -- mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; -- mz_uint8 *pExtra_data = NULL; -- mz_uint32 extra_size = 0; -- mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; -- mz_zip_internal_state *pState; -+// if ((int)level_and_flags < 0) -+// level_and_flags = MZ_DEFAULT_LEVEL; -+// level = level_and_flags & 0xF; - -- if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) -- gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; -+// /* Sanity checks */ -+// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if ((int)level_and_flags < 0) -- level_and_flags = MZ_DEFAULT_LEVEL; -- level = level_and_flags & 0xF; -+// pState = pZip->m_pState; - -- /* Sanity checks */ -- if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) -+// { -+// /* Source file is too large for non-zip64 */ -+// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -+// pState->m_zip64 = MZ_TRUE; -+// } - -- pState = pZip->m_pState; -+// /* We could support this, but why? */ -+// if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) -- { -- /* Source file is too large for non-zip64 */ -- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -- pState->m_zip64 = MZ_TRUE; -- } -+// if (!mz_zip_writer_validate_archive_name(pArchive_name)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - -- /* We could support this, but why? */ -- if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if (pState->m_zip64) -+// { -+// if (pZip->m_total_files == MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// } -+// else -+// { -+// if (pZip->m_total_files == MZ_UINT16_MAX) -+// { -+// pState->m_zip64 = MZ_TRUE; -+// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ -+// } -+// } - -- if (!mz_zip_writer_validate_archive_name(pArchive_name)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); -+// archive_name_size = strlen(pArchive_name); -+// if (archive_name_size > MZ_UINT16_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - -- if (pState->m_zip64) -- { -- if (pZip->m_total_files == MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -- } -- else -- { -- if (pZip->m_total_files == MZ_UINT16_MAX) -- { -- pState->m_zip64 = MZ_TRUE; -- /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ -- } -- } -+// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - -- archive_name_size = strlen(pArchive_name); -- if (archive_name_size > MZ_UINT16_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); -+// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -+// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -- num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); -+// if (!pState->m_zip64) -+// { -+// /* Bail early if the archive would obviously become too large */ -+// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE -+// + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 -+// + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) -+// { -+// pState->m_zip64 = MZ_TRUE; -+// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -+// } -+// } - -- /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -- if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); -+// #ifndef MINIZ_NO_TIME -+// if (pFile_time) -+// { -+// mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); -+// } -+// #endif - -- if (!pState->m_zip64) -- { -- /* Bail early if the archive would obviously become too large */ -- if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE -- + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 -- + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) -- { -- pState->m_zip64 = MZ_TRUE; -- /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -- } -- } -+// if (uncomp_size <= 3) -+// level = 0; - --#ifndef MINIZ_NO_TIME -- if (pFile_time) -- { -- mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); -- } --#endif -+// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) -+// { -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// } - -- if (uncomp_size <= 3) -- level = 0; -+// cur_archive_file_ofs += num_alignment_padding_bytes; -+// local_dir_header_ofs = cur_archive_file_ofs; - -- if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) -- { -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- } -+// if (pZip->m_file_offset_alignment) -+// { -+// MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); -+// } - -- cur_archive_file_ofs += num_alignment_padding_bytes; -- local_dir_header_ofs = cur_archive_file_ofs; -+// if (uncomp_size && level) -+// { -+// method = MZ_DEFLATED; -+// } - -- if (pZip->m_file_offset_alignment) -- { -- MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); -- } -+// MZ_CLEAR_OBJ(local_dir_header); -+// if (pState->m_zip64) -+// { -+// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) -+// { -+// pExtra_data = extra_data; -+// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -+// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -+// } - -- if (uncomp_size && level) -- { -- method = MZ_DEFLATED; -- } -+// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -- MZ_CLEAR_OBJ(local_dir_header); -- if (pState->m_zip64) -- { -- if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) -- { -- pExtra_data = extra_data; -- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -- } -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// cur_archive_file_ofs += sizeof(local_dir_header); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -+// { -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// } - -- cur_archive_file_ofs += sizeof(local_dir_header); -+// cur_archive_file_ofs += archive_name_size; - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -- { -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- } -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- cur_archive_file_ofs += archive_name_size; -+// cur_archive_file_ofs += extra_size; -+// } -+// else -+// { -+// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) -+// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -+// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- cur_archive_file_ofs += extra_size; -- } -- else -- { -- if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) -- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -- if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// cur_archive_file_ofs += sizeof(local_dir_header); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -+// { -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// } - -- cur_archive_file_ofs += sizeof(local_dir_header); -+// cur_archive_file_ofs += archive_name_size; -+// } - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -- { -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- } -+// if (user_extra_data_len > 0) -+// { -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- cur_archive_file_ofs += archive_name_size; -- } -+// cur_archive_file_ofs += user_extra_data_len; -+// } - -- if (user_extra_data_len > 0) -- { -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// if (uncomp_size) -+// { -+// mz_uint64 uncomp_remaining = uncomp_size; -+// void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); -+// if (!pRead_buf) -+// { -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// } - -- cur_archive_file_ofs += user_extra_data_len; -- } -+// if (!level) -+// { -+// while (uncomp_remaining) -+// { -+// mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); -+// if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// } -+// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); -+// uncomp_remaining -= n; -+// cur_archive_file_ofs += n; -+// } -+// comp_size = uncomp_size; -+// } -+// else -+// { -+// mz_bool result = MZ_FALSE; -+// mz_zip_writer_add_state state; -+// tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); -+// if (!pComp) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -+// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -+// } - -- if (uncomp_size) -- { -- mz_uint64 uncomp_remaining = uncomp_size; -- void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); -- if (!pRead_buf) -- { -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- } -+// state.m_pZip = pZip; -+// state.m_cur_archive_file_ofs = cur_archive_file_ofs; -+// state.m_comp_size = 0; - -- if (!level) -- { -- while (uncomp_remaining) -- { -- mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); -- if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -- } -- uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); -- uncomp_remaining -= n; -- cur_archive_file_ofs += n; -- } -- comp_size = uncomp_size; -- } -- else -- { -- mz_bool result = MZ_FALSE; -- mz_zip_writer_add_state state; -- tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); -- if (!pComp) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -- return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -- } -+// if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -+// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -+// } - -- state.m_pZip = pZip; -- state.m_cur_archive_file_ofs = cur_archive_file_ofs; -- state.m_comp_size = 0; -+// for (;;) -+// { -+// size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -+// tdefl_status status; -+// tdefl_flush flush = TDEFL_NO_FLUSH; - -- if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -- return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -- } -+// if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -+// break; -+// } - -- for (;;) -- { -- size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -- tdefl_status status; -- tdefl_flush flush = TDEFL_NO_FLUSH; -+// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); -+// uncomp_remaining -= in_buf_size; - -- if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) -- { -- mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -- break; -- } -+// if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) -+// flush = TDEFL_FULL_FLUSH; - -- uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); -- uncomp_remaining -= in_buf_size; -+// status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); -+// if (status == TDEFL_STATUS_DONE) -+// { -+// result = MZ_TRUE; -+// break; -+// } -+// else if (status != TDEFL_STATUS_OKAY) -+// { -+// mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); -+// break; -+// } -+// } - -- if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) -- flush = TDEFL_FULL_FLUSH; -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - -- status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); -- if (status == TDEFL_STATUS_DONE) -- { -- result = MZ_TRUE; -- break; -- } -- else if (status != TDEFL_STATUS_OKAY) -- { -- mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); -- break; -- } -- } -+// if (!result) -+// { -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -+// return MZ_FALSE; -+// } - -- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -+// comp_size = state.m_comp_size; -+// cur_archive_file_ofs = state.m_cur_archive_file_ofs; -+// } - -- if (!result) -- { -- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -- return MZ_FALSE; -- } -+// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -+// } - -- comp_size = state.m_comp_size; -- cur_archive_file_ofs = state.m_cur_archive_file_ofs; -- } -+// { -+// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; -+// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; - -- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -- } -+// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); -+// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); -+// if (pExtra_data == NULL) -+// { -+// if (comp_size > MZ_UINT32_MAX) -+// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -- { -- mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; -- mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; -+// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); -+// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); -+// } -+// else -+// { -+// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); -+// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); -+// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; -+// } - -- MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); -- MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); -- if (pExtra_data == NULL) -- { -- if (comp_size > MZ_UINT32_MAX) -- return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) -+// return MZ_FALSE; - -- MZ_WRITE_LE32(local_dir_footer + 8, comp_size); -- MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); -- } -- else -- { -- MZ_WRITE_LE64(local_dir_footer + 8, comp_size); -- MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); -- local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; -- } -+// cur_archive_file_ofs += local_dir_footer_size; -+// } - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) -- return MZ_FALSE; -+// if (pExtra_data != NULL) -+// { -+// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -+// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -+// } - -- cur_archive_file_ofs += local_dir_footer_size; -- } -+// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, -+// uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, -+// user_extra_data_central, user_extra_data_central_len)) -+// return MZ_FALSE; - -- if (pExtra_data != NULL) -- { -- extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -- (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -- } -+// pZip->m_total_files++; -+// pZip->m_archive_size = cur_archive_file_ofs; - -- if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, -- uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, -- user_extra_data_central, user_extra_data_central_len)) -- return MZ_FALSE; -+// return MZ_TRUE; -+// } - -- pZip->m_total_files++; -- pZip->m_archive_size = cur_archive_file_ofs; -+// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -+// { -+// MZ_FILE *pSrc_file = NULL; -+// mz_uint64 uncomp_size = 0; -+// MZ_TIME_T file_modified_time; -+// MZ_TIME_T *pFile_time = NULL; -+// mz_bool status; - -- return MZ_TRUE; --} -+// memset(&file_modified_time, 0, sizeof(file_modified_time)); - --mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) --{ -- MZ_FILE *pSrc_file = NULL; -- mz_uint64 uncomp_size = 0; -- MZ_TIME_T file_modified_time; -- MZ_TIME_T *pFile_time = NULL; -- mz_bool status; -- -- memset(&file_modified_time, 0, sizeof(file_modified_time)); -- --#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) -- pFile_time = &file_modified_time; -- if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); --#endif -+// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) -+// pFile_time = &file_modified_time; -+// if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); -+// #endif - -- pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); -- if (!pSrc_file) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -+// pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); -+// if (!pSrc_file) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -- MZ_FSEEK64(pSrc_file, 0, SEEK_END); -- uncomp_size = MZ_FTELL64(pSrc_file); -- MZ_FSEEK64(pSrc_file, 0, SEEK_SET); -+// MZ_FSEEK64(pSrc_file, 0, SEEK_END); -+// uncomp_size = MZ_FTELL64(pSrc_file); -+// MZ_FSEEK64(pSrc_file, 0, SEEK_SET); - -- status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); -+// status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); - -- MZ_FCLOSE(pSrc_file); -+// MZ_FCLOSE(pSrc_file); - -- return status; --} --#endif /* #ifndef MINIZ_NO_STDIO */ -+// return status; -+// } -+// #endif /* #ifndef MINIZ_NO_STDIO */ - - // static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) - // { -@@ -7083,491 +7082,491 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, - // return MZ_TRUE; - // } - --mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) --{ -- mz_zip_internal_state *pState; -- mz_uint64 central_dir_ofs, central_dir_size; -- mz_uint8 hdr[256]; -+// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) -+// { -+// mz_zip_internal_state *pState; -+// mz_uint64 central_dir_ofs, central_dir_size; -+// mz_uint8 hdr[256]; - -- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- pState = pZip->m_pState; -+// pState = pZip->m_pState; - -- if (pState->m_zip64) -- { -- if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -- } -- else -- { -- if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) -- return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -- } -+// if (pState->m_zip64) -+// { -+// if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// } -+// else -+// { -+// if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) -+// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -+// } - -- central_dir_ofs = 0; -- central_dir_size = 0; -- if (pZip->m_total_files) -- { -- /* Write central directory */ -- central_dir_ofs = pZip->m_archive_size; -- central_dir_size = pState->m_central_dir.m_size; -- pZip->m_central_directory_file_ofs = central_dir_ofs; -- if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- -- pZip->m_archive_size += central_dir_size; -- } -+// central_dir_ofs = 0; -+// central_dir_size = 0; -+// if (pZip->m_total_files) -+// { -+// /* Write central directory */ -+// central_dir_ofs = pZip->m_archive_size; -+// central_dir_size = pState->m_central_dir.m_size; -+// pZip->m_central_directory_file_ofs = central_dir_ofs; -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- if (pState->m_zip64) -- { -- /* Write zip64 end of central directory header */ -- mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; -- -- MZ_CLEAR_OBJ(hdr); -- MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); -- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); -- MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ -- MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); -- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); -- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); -- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); -- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); -- if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- -- pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; -- -- /* Write zip64 end of central directory locator */ -- MZ_CLEAR_OBJ(hdr); -- MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); -- MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); -- MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); -- if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -- -- pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; -- } -+// pZip->m_archive_size += central_dir_size; -+// } - -- /* Write end of central directory record */ -- MZ_CLEAR_OBJ(hdr); -- MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); -- MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); -- MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); -- MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); -- MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); -+// if (pState->m_zip64) -+// { -+// /* Write zip64 end of central directory header */ -+// mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; -+ -+// MZ_CLEAR_OBJ(hdr); -+// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); -+// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); -+// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ -+// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); -+// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); -+// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); -+// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); -+// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -+// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; - --#ifndef MINIZ_NO_STDIO -- if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) -- return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); --#endif /* #ifndef MINIZ_NO_STDIO */ -+// /* Write zip64 end of central directory locator */ -+// MZ_CLEAR_OBJ(hdr); -+// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); -+// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); -+// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; -+// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; -+// } - -- pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; -- return MZ_TRUE; --} -+// /* Write end of central directory record */ -+// MZ_CLEAR_OBJ(hdr); -+// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); -+// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); -+// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); -+// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); -+// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); - --mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) --{ -- if ((!ppBuf) || (!pSize)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -- *ppBuf = NULL; -- *pSize = 0; -+// #ifndef MINIZ_NO_STDIO -+// if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) -+// return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); -+// #endif /* #ifndef MINIZ_NO_STDIO */ - -- if ((!pZip) || (!pZip->m_pState)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; - -- if (pZip->m_pWrite != mz_zip_heap_write_func) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; -+// return MZ_TRUE; -+// } - -- if (!mz_zip_writer_finalize_archive(pZip)) -- return MZ_FALSE; -+// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) -+// { -+// if ((!ppBuf) || (!pSize)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- *ppBuf = pZip->m_pState->m_pMem; -- *pSize = pZip->m_pState->m_mem_size; -- pZip->m_pState->m_pMem = NULL; -- pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; -+// *ppBuf = NULL; -+// *pSize = 0; - -- return MZ_TRUE; --} -+// if ((!pZip) || (!pZip->m_pState)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - --mz_bool mz_zip_writer_end(mz_zip_archive *pZip) --{ -- return mz_zip_writer_end_internal(pZip, MZ_TRUE); --} -+// if (pZip->m_pWrite != mz_zip_heap_write_func) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - --#ifndef MINIZ_NO_STDIO --mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) --{ -- return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); --} -+// if (!mz_zip_writer_finalize_archive(pZip)) -+// return MZ_FALSE; - --mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) --{ -- mz_bool status, created_new_archive = MZ_FALSE; -- mz_zip_archive zip_archive; -- struct MZ_FILE_STAT_STRUCT file_stat; -- mz_zip_error actual_err = MZ_ZIP_NO_ERROR; -+// *ppBuf = pZip->m_pState->m_pMem; -+// *pSize = pZip->m_pState->m_mem_size; -+// pZip->m_pState->m_pMem = NULL; -+// pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; - -- mz_zip_zero_struct(&zip_archive); -- if ((int)level_and_flags < 0) -- level_and_flags = MZ_DEFAULT_LEVEL; -+// return MZ_TRUE; -+// } - -- if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) -- { -- if (pErr) -- *pErr = MZ_ZIP_INVALID_PARAMETER; -- return MZ_FALSE; -- } -+// mz_bool mz_zip_writer_end(mz_zip_archive *pZip) -+// { -+// return mz_zip_writer_end_internal(pZip, MZ_TRUE); -+// } - -- if (!mz_zip_writer_validate_archive_name(pArchive_name)) -- { -- if (pErr) -- *pErr = MZ_ZIP_INVALID_FILENAME; -- return MZ_FALSE; -- } -+// #ifndef MINIZ_NO_STDIO -+// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -+// { -+// return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); -+// } - -- /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ -- /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ -- if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) -- { -- /* Create a new archive. */ -- if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) -- { -- if (pErr) -- *pErr = zip_archive.m_last_error; -- return MZ_FALSE; -- } -+// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) -+// { -+// mz_bool status, created_new_archive = MZ_FALSE; -+// mz_zip_archive zip_archive; -+// struct MZ_FILE_STAT_STRUCT file_stat; -+// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; - -- created_new_archive = MZ_TRUE; -- } -- else -- { -- /* Append to an existing archive. */ -- if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) -- { -- if (pErr) -- *pErr = zip_archive.m_last_error; -- return MZ_FALSE; -- } -+// mz_zip_zero_struct(&zip_archive); -+// if ((int)level_and_flags < 0) -+// level_and_flags = MZ_DEFAULT_LEVEL; - -- if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) -- { -- if (pErr) -- *pErr = zip_archive.m_last_error; -+// if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) -+// { -+// if (pErr) -+// *pErr = MZ_ZIP_INVALID_PARAMETER; -+// return MZ_FALSE; -+// } - -- mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); -+// if (!mz_zip_writer_validate_archive_name(pArchive_name)) -+// { -+// if (pErr) -+// *pErr = MZ_ZIP_INVALID_FILENAME; -+// return MZ_FALSE; -+// } - -- return MZ_FALSE; -- } -- } -+// /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ -+// /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ -+// if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) -+// { -+// /* Create a new archive. */ -+// if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) -+// { -+// if (pErr) -+// *pErr = zip_archive.m_last_error; -+// return MZ_FALSE; -+// } - -- status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); -- actual_err = zip_archive.m_last_error; -+// created_new_archive = MZ_TRUE; -+// } -+// else -+// { -+// /* Append to an existing archive. */ -+// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) -+// { -+// if (pErr) -+// *pErr = zip_archive.m_last_error; -+// return MZ_FALSE; -+// } - -- /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ -- if (!mz_zip_writer_finalize_archive(&zip_archive)) -- { -- if (!actual_err) -- actual_err = zip_archive.m_last_error; -+// if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) -+// { -+// if (pErr) -+// *pErr = zip_archive.m_last_error; - -- status = MZ_FALSE; -- } -+// mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); - -- if (!mz_zip_writer_end_internal(&zip_archive, status)) -- { -- if (!actual_err) -- actual_err = zip_archive.m_last_error; -+// return MZ_FALSE; -+// } -+// } - -- status = MZ_FALSE; -- } -+// status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); -+// actual_err = zip_archive.m_last_error; - -- if ((!status) && (created_new_archive)) -- { -- /* It's a new archive and something went wrong, so just delete it. */ -- int ignoredStatus = MZ_DELETE_FILE(pZip_filename); -- (void)ignoredStatus; -- } -+// /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ -+// if (!mz_zip_writer_finalize_archive(&zip_archive)) -+// { -+// if (!actual_err) -+// actual_err = zip_archive.m_last_error; - -- if (pErr) -- *pErr = actual_err; -+// status = MZ_FALSE; -+// } - -- return status; --} -+// if (!mz_zip_writer_end_internal(&zip_archive, status)) -+// { -+// if (!actual_err) -+// actual_err = zip_archive.m_last_error; - --void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) --{ -- mz_uint32 file_index; -- mz_zip_archive zip_archive; -- void *p = NULL; -+// status = MZ_FALSE; -+// } - -- if (pSize) -- *pSize = 0; -+// if ((!status) && (created_new_archive)) -+// { -+// /* It's a new archive and something went wrong, so just delete it. */ -+// int ignoredStatus = MZ_DELETE_FILE(pZip_filename); -+// (void)ignoredStatus; -+// } - -- if ((!pZip_filename) || (!pArchive_name)) -- { -- if (pErr) -- *pErr = MZ_ZIP_INVALID_PARAMETER; -+// if (pErr) -+// *pErr = actual_err; - -- return NULL; -- } -+// return status; -+// } - -- mz_zip_zero_struct(&zip_archive); -- if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) -- { -- if (pErr) -- *pErr = zip_archive.m_last_error; -+// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) -+// { -+// mz_uint32 file_index; -+// mz_zip_archive zip_archive; -+// void *p = NULL; - -- return NULL; -- } -+// if (pSize) -+// *pSize = 0; - -- if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) -- { -- p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); -- } -+// if ((!pZip_filename) || (!pArchive_name)) -+// { -+// if (pErr) -+// *pErr = MZ_ZIP_INVALID_PARAMETER; - -- mz_zip_reader_end_internal(&zip_archive, p != NULL); -+// return NULL; -+// } - -- if (pErr) -- *pErr = zip_archive.m_last_error; -+// mz_zip_zero_struct(&zip_archive); -+// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) -+// { -+// if (pErr) -+// *pErr = zip_archive.m_last_error; - -- return p; --} -+// return NULL; -+// } - --void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) --{ -- return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); --} -+// if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) -+// { -+// p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); -+// } -+ -+// mz_zip_reader_end_internal(&zip_archive, p != NULL); -+ -+// if (pErr) -+// *pErr = zip_archive.m_last_error; -+ -+// return p; -+// } -+ -+// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) -+// { -+// return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); -+// } - --#endif /* #ifndef MINIZ_NO_STDIO */ -+// #endif /* #ifndef MINIZ_NO_STDIO */ - --#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ -+// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ - - /* ------------------- Misc utils */ - --mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) --{ -- return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; --} -+// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) -+// { -+// return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; -+// } - --mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) --{ -- return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; --} -+// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) -+// { -+// return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; -+// } - --mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) --{ -- mz_zip_error prev_err; -+// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) -+// { -+// mz_zip_error prev_err; - -- if (!pZip) -- return MZ_ZIP_INVALID_PARAMETER; -+// if (!pZip) -+// return MZ_ZIP_INVALID_PARAMETER; - -- prev_err = pZip->m_last_error; -+// prev_err = pZip->m_last_error; - -- pZip->m_last_error = err_num; -- return prev_err; --} -+// pZip->m_last_error = err_num; -+// return prev_err; -+// } - --mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) --{ -- if (!pZip) -- return MZ_ZIP_INVALID_PARAMETER; -+// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) -+// { -+// if (!pZip) -+// return MZ_ZIP_INVALID_PARAMETER; - -- return pZip->m_last_error; --} -+// return pZip->m_last_error; -+// } - --mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) --{ -- return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); --} -+// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) -+// { -+// return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); -+// } - --mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) --{ -- mz_zip_error prev_err; -+// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) -+// { -+// mz_zip_error prev_err; - -- if (!pZip) -- return MZ_ZIP_INVALID_PARAMETER; -+// if (!pZip) -+// return MZ_ZIP_INVALID_PARAMETER; - -- prev_err = pZip->m_last_error; -+// prev_err = pZip->m_last_error; - -- pZip->m_last_error = MZ_ZIP_NO_ERROR; -- return prev_err; --} -+// pZip->m_last_error = MZ_ZIP_NO_ERROR; -+// return prev_err; -+// } - --const char *mz_zip_get_error_string(mz_zip_error mz_err) --{ -- switch (mz_err) -- { -- case MZ_ZIP_NO_ERROR: -- return "no error"; -- case MZ_ZIP_UNDEFINED_ERROR: -- return "undefined error"; -- case MZ_ZIP_TOO_MANY_FILES: -- return "too many files"; -- case MZ_ZIP_FILE_TOO_LARGE: -- return "file too large"; -- case MZ_ZIP_UNSUPPORTED_METHOD: -- return "unsupported method"; -- case MZ_ZIP_UNSUPPORTED_ENCRYPTION: -- return "unsupported encryption"; -- case MZ_ZIP_UNSUPPORTED_FEATURE: -- return "unsupported feature"; -- case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: -- return "failed finding central directory"; -- case MZ_ZIP_NOT_AN_ARCHIVE: -- return "not a ZIP archive"; -- case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: -- return "invalid header or archive is corrupted"; -- case MZ_ZIP_UNSUPPORTED_MULTIDISK: -- return "unsupported multidisk archive"; -- case MZ_ZIP_DECOMPRESSION_FAILED: -- return "decompression failed or archive is corrupted"; -- case MZ_ZIP_COMPRESSION_FAILED: -- return "compression failed"; -- case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: -- return "unexpected decompressed size"; -- case MZ_ZIP_CRC_CHECK_FAILED: -- return "CRC-32 check failed"; -- case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: -- return "unsupported central directory size"; -- case MZ_ZIP_ALLOC_FAILED: -- return "allocation failed"; -- case MZ_ZIP_FILE_OPEN_FAILED: -- return "file open failed"; -- case MZ_ZIP_FILE_CREATE_FAILED: -- return "file create failed"; -- case MZ_ZIP_FILE_WRITE_FAILED: -- return "file write failed"; -- case MZ_ZIP_FILE_READ_FAILED: -- return "file read failed"; -- case MZ_ZIP_FILE_CLOSE_FAILED: -- return "file close failed"; -- case MZ_ZIP_FILE_SEEK_FAILED: -- return "file seek failed"; -- case MZ_ZIP_FILE_STAT_FAILED: -- return "file stat failed"; -- case MZ_ZIP_INVALID_PARAMETER: -- return "invalid parameter"; -- case MZ_ZIP_INVALID_FILENAME: -- return "invalid filename"; -- case MZ_ZIP_BUF_TOO_SMALL: -- return "buffer too small"; -- case MZ_ZIP_INTERNAL_ERROR: -- return "internal error"; -- case MZ_ZIP_FILE_NOT_FOUND: -- return "file not found"; -- case MZ_ZIP_ARCHIVE_TOO_LARGE: -- return "archive is too large"; -- case MZ_ZIP_VALIDATION_FAILED: -- return "validation failed"; -- case MZ_ZIP_WRITE_CALLBACK_FAILED: -- return "write calledback failed"; -- default: -- break; -- } -+// const char *mz_zip_get_error_string(mz_zip_error mz_err) -+// { -+// switch (mz_err) -+// { -+// case MZ_ZIP_NO_ERROR: -+// return "no error"; -+// case MZ_ZIP_UNDEFINED_ERROR: -+// return "undefined error"; -+// case MZ_ZIP_TOO_MANY_FILES: -+// return "too many files"; -+// case MZ_ZIP_FILE_TOO_LARGE: -+// return "file too large"; -+// case MZ_ZIP_UNSUPPORTED_METHOD: -+// return "unsupported method"; -+// case MZ_ZIP_UNSUPPORTED_ENCRYPTION: -+// return "unsupported encryption"; -+// case MZ_ZIP_UNSUPPORTED_FEATURE: -+// return "unsupported feature"; -+// case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: -+// return "failed finding central directory"; -+// case MZ_ZIP_NOT_AN_ARCHIVE: -+// return "not a ZIP archive"; -+// case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: -+// return "invalid header or archive is corrupted"; -+// case MZ_ZIP_UNSUPPORTED_MULTIDISK: -+// return "unsupported multidisk archive"; -+// case MZ_ZIP_DECOMPRESSION_FAILED: -+// return "decompression failed or archive is corrupted"; -+// case MZ_ZIP_COMPRESSION_FAILED: -+// return "compression failed"; -+// case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: -+// return "unexpected decompressed size"; -+// case MZ_ZIP_CRC_CHECK_FAILED: -+// return "CRC-32 check failed"; -+// case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: -+// return "unsupported central directory size"; -+// case MZ_ZIP_ALLOC_FAILED: -+// return "allocation failed"; -+// case MZ_ZIP_FILE_OPEN_FAILED: -+// return "file open failed"; -+// case MZ_ZIP_FILE_CREATE_FAILED: -+// return "file create failed"; -+// case MZ_ZIP_FILE_WRITE_FAILED: -+// return "file write failed"; -+// case MZ_ZIP_FILE_READ_FAILED: -+// return "file read failed"; -+// case MZ_ZIP_FILE_CLOSE_FAILED: -+// return "file close failed"; -+// case MZ_ZIP_FILE_SEEK_FAILED: -+// return "file seek failed"; -+// case MZ_ZIP_FILE_STAT_FAILED: -+// return "file stat failed"; -+// case MZ_ZIP_INVALID_PARAMETER: -+// return "invalid parameter"; -+// case MZ_ZIP_INVALID_FILENAME: -+// return "invalid filename"; -+// case MZ_ZIP_BUF_TOO_SMALL: -+// return "buffer too small"; -+// case MZ_ZIP_INTERNAL_ERROR: -+// return "internal error"; -+// case MZ_ZIP_FILE_NOT_FOUND: -+// return "file not found"; -+// case MZ_ZIP_ARCHIVE_TOO_LARGE: -+// return "archive is too large"; -+// case MZ_ZIP_VALIDATION_FAILED: -+// return "validation failed"; -+// case MZ_ZIP_WRITE_CALLBACK_FAILED: -+// return "write calledback failed"; -+// default: -+// break; -+// } - -- return "unknown error"; --} -+// return "unknown error"; -+// } - - /* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */ --mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) --{ -- if ((!pZip) || (!pZip->m_pState)) -- return MZ_FALSE; -+// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) -+// { -+// if ((!pZip) || (!pZip->m_pState)) -+// return MZ_FALSE; - -- return pZip->m_pState->m_zip64; --} -+// return pZip->m_pState->m_zip64; -+// } - --size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) --{ -- if ((!pZip) || (!pZip->m_pState)) -- return 0; -+// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) -+// { -+// if ((!pZip) || (!pZip->m_pState)) -+// return 0; - -- return pZip->m_pState->m_central_dir.m_size; --} -+// return pZip->m_pState->m_central_dir.m_size; -+// } - --mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) --{ -- return pZip ? pZip->m_total_files : 0; --} -+// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) -+// { -+// return pZip ? pZip->m_total_files : 0; -+// } - --mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) --{ -- if (!pZip) -- return 0; -- return pZip->m_archive_size; --} -+// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) -+// { -+// if (!pZip) -+// return 0; -+// return pZip->m_archive_size; -+// } - --mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) --{ -- if ((!pZip) || (!pZip->m_pState)) -- return 0; -- return pZip->m_pState->m_file_archive_start_ofs; --} -+// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) -+// { -+// if ((!pZip) || (!pZip->m_pState)) -+// return 0; -+// return pZip->m_pState->m_file_archive_start_ofs; -+// } - --MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) --{ -- if ((!pZip) || (!pZip->m_pState)) -- return 0; -- return pZip->m_pState->m_pFile; --} -+// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) -+// { -+// if ((!pZip) || (!pZip->m_pState)) -+// return 0; -+// return pZip->m_pState->m_pFile; -+// } - --size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) --{ -- if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) -- return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) -+// { -+// if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) -+// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -- return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); --} -+// return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); -+// } - --mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) --{ -- mz_uint n; -- const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -- if (!p) -- { -- if (filename_buf_size) -- pFilename[0] = '\0'; -- mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -- return 0; -- } -- n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -- if (filename_buf_size) -- { -- n = MZ_MIN(n, filename_buf_size - 1); -- memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); -- pFilename[n] = '\0'; -- } -- return n + 1; --} -+// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) -+// { -+// mz_uint n; -+// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -+// if (!p) -+// { -+// if (filename_buf_size) -+// pFilename[0] = '\0'; -+// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -+// return 0; -+// } -+// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -+// if (filename_buf_size) -+// { -+// n = MZ_MIN(n, filename_buf_size - 1); -+// memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); -+// pFilename[n] = '\0'; -+// } -+// return n + 1; -+// } - --mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) --{ -- return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); --} -+// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) -+// { -+// return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); -+// } - --mz_bool mz_zip_end(mz_zip_archive *pZip) --{ -- if (!pZip) -- return MZ_FALSE; -- -- if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) -- return mz_zip_reader_end(pZip); --#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -- else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) -- return mz_zip_writer_end(pZip); --#endif -+// mz_bool mz_zip_end(mz_zip_archive *pZip) -+// { -+// if (!pZip) -+// return MZ_FALSE; - -- return MZ_FALSE; --} -+// if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) -+// return mz_zip_reader_end(pZip); -+// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -+// else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) -+// return mz_zip_writer_end(pZip); -+// #endif - --#ifdef __cplusplus --} --#endif -+// return MZ_FALSE; -+// } -+ -+// #ifdef __cplusplus -+// } -+// #endif - --#endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ -+// #endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ diff --git a/gomspace/libutil/src/zip/miniz/miniz.c b/gomspace/libutil/src/zip/miniz/miniz.c deleted file mode 100644 index 910d4b1f..00000000 --- a/gomspace/libutil/src/zip/miniz/miniz.c +++ /dev/null @@ -1,7572 +0,0 @@ -/************************************************************************** - * - * Copyright 2013-2014 RAD Game Tools and Valve Software - * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ - -#include "miniz.h" - -typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; -typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; -typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------- zlib-style API's */ - -mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) -{ - mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); - size_t block_len = buf_len % 5552; - if (!ptr) - return MZ_ADLER32_INIT; - while (buf_len) - { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) - { - s1 += ptr[0], s2 += s1; - s1 += ptr[1], s2 += s1; - s1 += ptr[2], s2 += s1; - s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; - s1 += ptr[5], s2 += s1; - s1 += ptr[6], s2 += s1; - s1 += ptr[7], s2 += s1; - } - for (; i < block_len; ++i) - s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; - buf_len -= block_len; - block_len = 5552; - } - return (s2 << 16) + s1; -} - -/* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */ -// #if 0 -// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) -// { -// static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, -// 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; -// mz_uint32 crcu32 = (mz_uint32)crc; -// if (!ptr) -// return MZ_CRC32_INIT; -// crcu32 = ~crcu32; -// while (buf_len--) -// { -// mz_uint8 b = *ptr++; -// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; -// crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; -// } -// return ~crcu32; -// } -// #else -/* Faster, but larger CPU cache footprint. - */ -// mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) -// { -// static const mz_uint32 s_crc_table[256] = -// { -// 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, -// 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, -// 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, -// 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, -// 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, -// 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, -// 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, -// 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, -// 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, -// 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, -// 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, -// 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, -// 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, -// 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, -// 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, -// 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, -// 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, -// 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, -// 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, -// 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, -// 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, -// 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, -// 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, -// 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, -// 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, -// 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, -// 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, -// 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, -// 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, -// 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, -// 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, -// 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, -// 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, -// 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, -// 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, -// 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, -// 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -// }; - -// mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; -// const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; - -// while (buf_len >= 4) -// { -// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; -// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; -// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; -// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; -// pByte_buf += 4; -// buf_len -= 4; -// } - -// while (buf_len) -// { -// crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; -// ++pByte_buf; -// --buf_len; -// } - -// return ~crc32; -// } -// #endif - -void mz_free(void *p) -{ - MZ_FREE(p); -} - -void *miniz_def_alloc_func(void *opaque, size_t items, size_t size) -{ - (void)opaque, (void)items, (void)size; - return MZ_MALLOC(items * size); -} -void miniz_def_free_func(void *opaque, void *address) -{ - (void)opaque, (void)address; - MZ_FREE(address); -} -// void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) -// { -// (void)opaque, (void)address, (void)items, (void)size; -// return MZ_REALLOC(address, items * size); -// } - -// const char *mz_version(void) -// { -// return MZ_VERSION; -// } - -#ifndef MINIZ_NO_ZLIB_APIS - -int mz_deflateInit(mz_streamp pStream, int level) -{ - return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); -} - -int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) -{ - tdefl_compressor *pComp; - mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); - - if (!pStream) - return MZ_STREAM_ERROR; - if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) - return MZ_PARAM_ERROR; - - pStream->data_type = 0; - pStream->adler = MZ_ADLER32_INIT; - pStream->msg = NULL; - pStream->reserved = 0; - pStream->total_in = 0; - pStream->total_out = 0; - if (!pStream->zalloc) - pStream->zalloc = miniz_def_alloc_func; - if (!pStream->zfree) - pStream->zfree = miniz_def_free_func; - - pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); - if (!pComp) - return MZ_MEM_ERROR; - - pStream->state = (struct mz_internal_state *)pComp; - - if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) - { - mz_deflateEnd(pStream); - return MZ_PARAM_ERROR; - } - - return MZ_OK; -} - -// int mz_deflateReset(mz_streamp pStream) -// { -// if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) -// return MZ_STREAM_ERROR; -// pStream->total_in = pStream->total_out = 0; -// tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); -// return MZ_OK; -// } - -int mz_deflate(mz_streamp pStream, int flush) -{ - size_t in_bytes, out_bytes; - mz_ulong orig_total_in, orig_total_out; - int mz_status = MZ_OK; - - if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) - return MZ_STREAM_ERROR; - if (!pStream->avail_out) - return MZ_BUF_ERROR; - - if (flush == MZ_PARTIAL_FLUSH) - flush = MZ_SYNC_FLUSH; - - if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) - return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; - - orig_total_in = pStream->total_in; - orig_total_out = pStream->total_out; - for (;;) - { - tdefl_status defl_status; - in_bytes = pStream->avail_in; - out_bytes = pStream->avail_out; - - defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); - pStream->next_in += (mz_uint)in_bytes; - pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; - pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); - - pStream->next_out += (mz_uint)out_bytes; - pStream->avail_out -= (mz_uint)out_bytes; - pStream->total_out += (mz_uint)out_bytes; - - if (defl_status < 0) - { - mz_status = MZ_STREAM_ERROR; - break; - } - else if (defl_status == TDEFL_STATUS_DONE) - { - mz_status = MZ_STREAM_END; - break; - } - else if (!pStream->avail_out) - break; - else if ((!pStream->avail_in) && (flush != MZ_FINISH)) - { - if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) - break; - return MZ_BUF_ERROR; /* Can't make forward progress without some input. - */ - } - } - return mz_status; -} - -int mz_deflateEnd(mz_streamp pStream) -{ - if (!pStream) - return MZ_STREAM_ERROR; - if (pStream->state) - { - pStream->zfree(pStream->opaque, pStream->state); - pStream->state = NULL; - } - return MZ_OK; -} - -// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) -// { -// (void)pStream; -// This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) -// return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); -// } - -int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) -{ - int status; - mz_stream stream; - memset(&stream, 0, sizeof(stream)); - - /* In case mz_ulong is 64-bits (argh I hate longs). */ - if ((source_len | *pDest_len) > 0xFFFFFFFFU) - return MZ_PARAM_ERROR; - - stream.next_in = pSource; - stream.avail_in = (mz_uint32)source_len; - stream.next_out = pDest; - stream.avail_out = (mz_uint32)*pDest_len; - - status = mz_deflateInit(&stream, level); - if (status != MZ_OK) - return status; - - status = mz_deflate(&stream, MZ_FINISH); - if (status != MZ_STREAM_END) - { - mz_deflateEnd(&stream); - return (status == MZ_OK) ? MZ_BUF_ERROR : status; - } - - *pDest_len = stream.total_out; - return mz_deflateEnd(&stream); -} - -int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) -{ - return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); -} - -// mz_ulong mz_compressBound(mz_ulong source_len) -// { -// return mz_deflateBound(NULL, source_len); -// } - -typedef struct -{ - tinfl_decompressor m_decomp; - mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; - int m_window_bits; - mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; - tinfl_status m_last_status; -} inflate_state; - -int mz_inflateInit2(mz_streamp pStream, int window_bits) -{ - inflate_state *pDecomp; - if (!pStream) - return MZ_STREAM_ERROR; - if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) - return MZ_PARAM_ERROR; - - pStream->data_type = 0; - pStream->adler = 0; - pStream->msg = NULL; - pStream->total_in = 0; - pStream->total_out = 0; - pStream->reserved = 0; - if (!pStream->zalloc) - pStream->zalloc = miniz_def_alloc_func; - if (!pStream->zfree) - pStream->zfree = miniz_def_free_func; - - pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); - if (!pDecomp) - return MZ_MEM_ERROR; - - pStream->state = (struct mz_internal_state *)pDecomp; - - tinfl_init(&pDecomp->m_decomp); - pDecomp->m_dict_ofs = 0; - pDecomp->m_dict_avail = 0; - pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; - pDecomp->m_first_call = 1; - pDecomp->m_has_flushed = 0; - pDecomp->m_window_bits = window_bits; - - return MZ_OK; -} - -int mz_inflateInit(mz_streamp pStream) -{ - return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); -} - -int mz_inflate(mz_streamp pStream, int flush) -{ - inflate_state *pState; - mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; - size_t in_bytes, out_bytes, orig_avail_in; - tinfl_status status; - - if ((!pStream) || (!pStream->state)) - return MZ_STREAM_ERROR; - if (flush == MZ_PARTIAL_FLUSH) - flush = MZ_SYNC_FLUSH; - if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) - return MZ_STREAM_ERROR; - - pState = (inflate_state *)pStream->state; - if (pState->m_window_bits > 0) - decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; - orig_avail_in = pStream->avail_in; - - first_call = pState->m_first_call; - pState->m_first_call = 0; - if (pState->m_last_status < 0) - return MZ_DATA_ERROR; - - if (pState->m_has_flushed && (flush != MZ_FINISH)) - return MZ_STREAM_ERROR; - pState->m_has_flushed |= (flush == MZ_FINISH); - - if ((flush == MZ_FINISH) && (first_call)) - { - /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */ - decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - in_bytes = pStream->avail_in; - out_bytes = pStream->avail_out; - status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); - pState->m_last_status = status; - pStream->next_in += (mz_uint)in_bytes; - pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; - pStream->adler = tinfl_get_adler32(&pState->m_decomp); - pStream->next_out += (mz_uint)out_bytes; - pStream->avail_out -= (mz_uint)out_bytes; - pStream->total_out += (mz_uint)out_bytes; - - if (status < 0) - return MZ_DATA_ERROR; - else if (status != TINFL_STATUS_DONE) - { - pState->m_last_status = TINFL_STATUS_FAILED; - return MZ_BUF_ERROR; - } - return MZ_STREAM_END; - } - /* flush != MZ_FINISH then we must assume there's more input. */ - if (flush != MZ_FINISH) - decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; - - if (pState->m_dict_avail) - { - n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); - memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); - pStream->next_out += n; - pStream->avail_out -= n; - pStream->total_out += n; - pState->m_dict_avail -= n; - pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); - return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; - } - - for (;;) - { - in_bytes = pStream->avail_in; - out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; - - status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); - pState->m_last_status = status; - - pStream->next_in += (mz_uint)in_bytes; - pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; - pStream->adler = tinfl_get_adler32(&pState->m_decomp); - - pState->m_dict_avail = (mz_uint)out_bytes; - - n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); - memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); - pStream->next_out += n; - pStream->avail_out -= n; - pStream->total_out += n; - pState->m_dict_avail -= n; - pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); - - if (status < 0) - return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */ - else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) - return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */ - else if (flush == MZ_FINISH) - { - /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */ - if (status == TINFL_STATUS_DONE) - return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; - /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */ - else if (!pStream->avail_out) - return MZ_BUF_ERROR; - } - else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) - break; - } - - return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; -} - -int mz_inflateEnd(mz_streamp pStream) -{ - if (!pStream) - return MZ_STREAM_ERROR; - if (pStream->state) - { - pStream->zfree(pStream->opaque, pStream->state); - pStream->state = NULL; - } - return MZ_OK; -} - -int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) -{ - mz_stream stream; - int status; - memset(&stream, 0, sizeof(stream)); - - /* In case mz_ulong is 64-bits (argh I hate longs). */ - if ((source_len | *pDest_len) > 0xFFFFFFFFU) - return MZ_PARAM_ERROR; - - stream.next_in = pSource; - stream.avail_in = (mz_uint32)source_len; - stream.next_out = pDest; - stream.avail_out = (mz_uint32)*pDest_len; - - status = mz_inflateInit(&stream); - if (status != MZ_OK) - return status; - - status = mz_inflate(&stream, MZ_FINISH); - if (status != MZ_STREAM_END) - { - mz_inflateEnd(&stream); - return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; - } - *pDest_len = stream.total_out; - - return mz_inflateEnd(&stream); -} - -// const char *mz_error(int err) -// { -// static struct -// { -// int m_err; -// const char *m_pDesc; -// } s_error_descs[] = -// { -// { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } -// }; -// mz_uint i; -// for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) -// if (s_error_descs[i].m_err == err) -// return s_error_descs[i].m_pDesc; -// return NULL; -// } - -#endif /*MINIZ_NO_ZLIB_APIS */ - -#ifdef __cplusplus -} -#endif - -/* - This is free and unencumbered software released into the public domain. - - Anyone is free to copy, modify, publish, use, compile, sell, or - distribute this software, either in source code form or as a compiled - binary, for any purpose, commercial or non-commercial, and by any - means. - - In jurisdictions that recognize copyright laws, the author or authors - of this software dedicate any and all copyright interest in the - software to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and - successors. We intend this dedication to be an overt act of - relinquishment in perpetuity of all present and future rights to this - software under copyright law. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - For more information, please refer to -*/ -/************************************************************************** - * - * Copyright 2013-2014 RAD Game Tools and Valve Software - * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ - - - - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------- Low-level Compression (independent from all decompression API's) */ - -/* Purposely making these tables static for faster init and thread safety. */ -static const mz_uint16 s_tdefl_len_sym[256] = - { - 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, - 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, - 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, - 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, - 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285 - }; - -static const mz_uint8 s_tdefl_len_extra[256] = - { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 - }; - -static const mz_uint8 s_tdefl_small_dist_sym[512] = - { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 - }; - -static const mz_uint8 s_tdefl_small_dist_extra[512] = - { - 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7 - }; - -static const mz_uint8 s_tdefl_large_dist_sym[128] = - { - 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 - }; - -static const mz_uint8 s_tdefl_large_dist_extra[128] = - { - 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 - }; - -/* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. */ -typedef struct -{ - mz_uint16 m_key, m_sym_index; -} tdefl_sym_freq; -static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) -{ - mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; - tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; - MZ_CLEAR_OBJ(hist); - for (i = 0; i < num_syms; i++) - { - mz_uint freq = pSyms0[i].m_key; - hist[freq & 0xFF]++; - hist[256 + ((freq >> 8) & 0xFF)]++; - } - while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) - total_passes--; - for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) - { - const mz_uint32 *pHist = &hist[pass << 8]; - mz_uint offsets[256], cur_ofs = 0; - for (i = 0; i < 256; i++) - { - offsets[i] = cur_ofs; - cur_ofs += pHist[i]; - } - for (i = 0; i < num_syms; i++) - pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; - { - tdefl_sym_freq *t = pCur_syms; - pCur_syms = pNew_syms; - pNew_syms = t; - } - } - return pCur_syms; -} - -/* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */ -static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) -{ - int root, leaf, next, avbl, used, dpth; - if (n == 0) - return; - else if (n == 1) - { - A[0].m_key = 1; - return; - } - A[0].m_key += A[1].m_key; - root = 0; - leaf = 2; - for (next = 1; next < n - 1; next++) - { - if (leaf >= n || A[root].m_key < A[leaf].m_key) - { - A[next].m_key = A[root].m_key; - A[root++].m_key = (mz_uint16)next; - } - else - A[next].m_key = A[leaf++].m_key; - if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) - { - A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); - A[root++].m_key = (mz_uint16)next; - } - else - A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); - } - A[n - 2].m_key = 0; - for (next = n - 3; next >= 0; next--) - A[next].m_key = A[A[next].m_key].m_key + 1; - avbl = 1; - used = dpth = 0; - root = n - 2; - next = n - 1; - while (avbl > 0) - { - while (root >= 0 && (int)A[root].m_key == dpth) - { - used++; - root--; - } - while (avbl > used) - { - A[next--].m_key = (mz_uint16)(dpth); - avbl--; - } - avbl = 2 * used; - dpth++; - used = 0; - } -} - -/* Limits canonical Huffman code table's max code size. */ -enum -{ - TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 -}; -static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) -{ - int i; - mz_uint32 total = 0; - if (code_list_len <= 1) - return; - for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) - pNum_codes[max_code_size] += pNum_codes[i]; - for (i = max_code_size; i > 0; i--) - total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); - while (total != (1UL << max_code_size)) - { - pNum_codes[max_code_size]--; - for (i = max_code_size - 1; i > 0; i--) - if (pNum_codes[i]) - { - pNum_codes[i]--; - pNum_codes[i + 1] += 2; - break; - } - total--; - } -} - -static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) -{ - int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; - mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; - MZ_CLEAR_OBJ(num_codes); - if (static_table) - { - for (i = 0; i < table_len; i++) - num_codes[d->m_huff_code_sizes[table_num][i]]++; - } - else - { - tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; - int num_used_syms = 0; - const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; - for (i = 0; i < table_len; i++) - if (pSym_count[i]) - { - syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; - syms0[num_used_syms++].m_sym_index = (mz_uint16)i; - } - - pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); - tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); - - for (i = 0; i < num_used_syms; i++) - num_codes[pSyms[i].m_key]++; - - tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); - - MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); - MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); - for (i = 1, j = num_used_syms; i <= code_size_limit; i++) - for (l = num_codes[i]; l > 0; l--) - d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); - } - - next_code[1] = 0; - for (j = 0, i = 2; i <= code_size_limit; i++) - next_code[i] = j = ((j + num_codes[i - 1]) << 1); - - for (i = 0; i < table_len; i++) - { - mz_uint rev_code = 0, code, code_size; - if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) - continue; - code = next_code[code_size]++; - for (l = code_size; l > 0; l--, code >>= 1) - rev_code = (rev_code << 1) | (code & 1); - d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; - } -} - -#define TDEFL_PUT_BITS(b, l) \ - do \ - { \ - mz_uint bits = b; \ - mz_uint len = l; \ - MZ_ASSERT(bits <= ((1U << len) - 1U)); \ - d->m_bit_buffer |= (bits << d->m_bits_in); \ - d->m_bits_in += len; \ - while (d->m_bits_in >= 8) \ - { \ - if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ - *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ - d->m_bit_buffer >>= 8; \ - d->m_bits_in -= 8; \ - } \ - } \ - MZ_MACRO_END - -#define TDEFL_RLE_PREV_CODE_SIZE() \ - { \ - if (rle_repeat_count) \ - { \ - if (rle_repeat_count < 3) \ - { \ - d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ - while (rle_repeat_count--) \ - packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ - } \ - else \ - { \ - d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ - packed_code_sizes[num_packed_code_sizes++] = 16; \ - packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ - } \ - rle_repeat_count = 0; \ - } \ - } - -#define TDEFL_RLE_ZERO_CODE_SIZE() \ - { \ - if (rle_z_count) \ - { \ - if (rle_z_count < 3) \ - { \ - d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ - while (rle_z_count--) \ - packed_code_sizes[num_packed_code_sizes++] = 0; \ - } \ - else if (rle_z_count <= 10) \ - { \ - d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ - packed_code_sizes[num_packed_code_sizes++] = 17; \ - packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ - } \ - else \ - { \ - d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ - packed_code_sizes[num_packed_code_sizes++] = 18; \ - packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ - } \ - rle_z_count = 0; \ - } \ - } - -static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - -static void tdefl_start_dynamic_block(tdefl_compressor *d) -{ - int num_lit_codes, num_dist_codes, num_bit_lengths; - mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; - mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; - - d->m_huff_count[0][256] = 1; - - tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); - tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); - - for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) - if (d->m_huff_code_sizes[0][num_lit_codes - 1]) - break; - for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) - if (d->m_huff_code_sizes[1][num_dist_codes - 1]) - break; - - memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); - memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); - total_code_sizes_to_pack = num_lit_codes + num_dist_codes; - num_packed_code_sizes = 0; - rle_z_count = 0; - rle_repeat_count = 0; - - memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); - for (i = 0; i < total_code_sizes_to_pack; i++) - { - mz_uint8 code_size = code_sizes_to_pack[i]; - if (!code_size) - { - TDEFL_RLE_PREV_CODE_SIZE(); - if (++rle_z_count == 138) - { - TDEFL_RLE_ZERO_CODE_SIZE(); - } - } - else - { - TDEFL_RLE_ZERO_CODE_SIZE(); - if (code_size != prev_code_size) - { - TDEFL_RLE_PREV_CODE_SIZE(); - d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); - packed_code_sizes[num_packed_code_sizes++] = code_size; - } - else if (++rle_repeat_count == 6) - { - TDEFL_RLE_PREV_CODE_SIZE(); - } - } - prev_code_size = code_size; - } - if (rle_repeat_count) - { - TDEFL_RLE_PREV_CODE_SIZE(); - } - else - { - TDEFL_RLE_ZERO_CODE_SIZE(); - } - - tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); - - TDEFL_PUT_BITS(2, 2); - - TDEFL_PUT_BITS(num_lit_codes - 257, 5); - TDEFL_PUT_BITS(num_dist_codes - 1, 5); - - for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) - if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) - break; - num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); - TDEFL_PUT_BITS(num_bit_lengths - 4, 4); - for (i = 0; (int)i < num_bit_lengths; i++) - TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); - - for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;) - { - mz_uint code = packed_code_sizes[packed_code_sizes_index++]; - MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); - TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); - if (code >= 16) - TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); - } -} - -static void tdefl_start_static_block(tdefl_compressor *d) -{ - mz_uint i; - mz_uint8 *p = &d->m_huff_code_sizes[0][0]; - - for (i = 0; i <= 143; ++i) - *p++ = 8; - for (; i <= 255; ++i) - *p++ = 9; - for (; i <= 279; ++i) - *p++ = 7; - for (; i <= 287; ++i) - *p++ = 8; - - memset(d->m_huff_code_sizes[1], 5, 32); - - tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); - tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); - - TDEFL_PUT_BITS(1, 2); -} - -static const mz_uint16 mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS -static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) -{ - mz_uint flags; - mz_uint8 *pLZ_codes; - mz_uint8 *pOutput_buf = d->m_pOutput_buf; - mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; - mz_uint64 bit_buffer = d->m_bit_buffer; - mz_uint bits_in = d->m_bits_in; - -#define TDEFL_PUT_BITS_FAST(b, l) \ - { \ - bit_buffer |= (((mz_uint64)(b)) << bits_in); \ - bits_in += (l); \ - } - - flags = 1; - for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) - { - if (flags == 1) - flags = *pLZ_codes++ | 0x100; - - if (flags & 1) - { - mz_uint s0, s1, n0, n1, sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); - pLZ_codes += 3; - - MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); - - /* This sequence coaxes MSVC into using cmov's vs. jmp's. */ - s0 = s_tdefl_small_dist_sym[match_dist & 511]; - n0 = s_tdefl_small_dist_extra[match_dist & 511]; - s1 = s_tdefl_large_dist_sym[match_dist >> 8]; - n1 = s_tdefl_large_dist_extra[match_dist >> 8]; - sym = (match_dist < 512) ? s0 : s1; - num_extra_bits = (match_dist < 512) ? n0 : n1; - - MZ_ASSERT(d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); - } - else - { - mz_uint lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) - { - flags >>= 1; - lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) - { - flags >>= 1; - lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - } - } - } - - if (pOutput_buf >= d->m_pOutput_buf_end) - return MZ_FALSE; - - *(mz_uint64 *)pOutput_buf = bit_buffer; - pOutput_buf += (bits_in >> 3); - bit_buffer >>= (bits_in & ~7); - bits_in &= 7; - } - -#undef TDEFL_PUT_BITS_FAST - - d->m_pOutput_buf = pOutput_buf; - d->m_bits_in = 0; - d->m_bit_buffer = 0; - - while (bits_in) - { - mz_uint32 n = MZ_MIN(bits_in, 16); - TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); - bit_buffer >>= n; - bits_in -= n; - } - - TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); - - return (d->m_pOutput_buf < d->m_pOutput_buf_end); -} -#else -static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) -{ - mz_uint flags; - mz_uint8 *pLZ_codes; - - flags = 1; - for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) - { - if (flags == 1) - flags = *pLZ_codes++ | 0x100; - if (flags & 1) - { - mz_uint sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); - pLZ_codes += 3; - - MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); - - if (match_dist < 512) - { - sym = s_tdefl_small_dist_sym[match_dist]; - num_extra_bits = s_tdefl_small_dist_extra[match_dist]; - } - else - { - sym = s_tdefl_large_dist_sym[match_dist >> 8]; - num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; - } - MZ_ASSERT(d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); - } - else - { - mz_uint lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - } - } - - TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); - - return (d->m_pOutput_buf < d->m_pOutput_buf_end); -} -#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS */ - -static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) -{ - if (static_block) - tdefl_start_static_block(d); - else - tdefl_start_dynamic_block(d); - return tdefl_compress_lz_codes(d); -} - -static int tdefl_flush_block(tdefl_compressor *d, int flush) -{ - mz_uint saved_bit_buf, saved_bits_in; - mz_uint8 *pSaved_output_buf; - mz_bool comp_block_succeeded = MZ_FALSE; - int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; - mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; - - d->m_pOutput_buf = pOutput_buf_start; - d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; - - MZ_ASSERT(!d->m_output_flush_remaining); - d->m_output_flush_ofs = 0; - d->m_output_flush_remaining = 0; - - *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); - d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); - - if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) - { - TDEFL_PUT_BITS(0x78, 8); - TDEFL_PUT_BITS(0x01, 8); - } - - TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); - - pSaved_output_buf = d->m_pOutput_buf; - saved_bit_buf = d->m_bit_buffer; - saved_bits_in = d->m_bits_in; - - if (!use_raw_block) - comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); - - /* If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. */ - if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && - ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) - { - mz_uint i; - d->m_pOutput_buf = pSaved_output_buf; - d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; - TDEFL_PUT_BITS(0, 2); - if (d->m_bits_in) - { - TDEFL_PUT_BITS(0, 8 - d->m_bits_in); - } - for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) - { - TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); - } - for (i = 0; i < d->m_total_lz_bytes; ++i) - { - TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); - } - } - /* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. */ - else if (!comp_block_succeeded) - { - d->m_pOutput_buf = pSaved_output_buf; - d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; - tdefl_compress_block(d, MZ_TRUE); - } - - if (flush) - { - if (flush == TDEFL_FINISH) - { - if (d->m_bits_in) - { - TDEFL_PUT_BITS(0, 8 - d->m_bits_in); - } - if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) - { - mz_uint i, a = d->m_adler32; - for (i = 0; i < 4; i++) - { - TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); - a <<= 8; - } - } - } - else - { - mz_uint i, z = 0; - TDEFL_PUT_BITS(0, 3); - if (d->m_bits_in) - { - TDEFL_PUT_BITS(0, 8 - d->m_bits_in); - } - for (i = 2; i; --i, z ^= 0xFFFF) - { - TDEFL_PUT_BITS(z & 0xFFFF, 16); - } - } - } - - MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); - - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; - d->m_pLZ_flags = d->m_lz_code_buf; - d->m_num_flags_left = 8; - d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; - d->m_total_lz_bytes = 0; - d->m_block_index++; - - if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) - { - if (d->m_pPut_buf_func) - { - *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; - if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) - return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); - } - else if (pOutput_buf_start == d->m_output_buf) - { - int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); - d->m_out_buf_ofs += bytes_to_copy; - if ((n -= bytes_to_copy) != 0) - { - d->m_output_flush_ofs = bytes_to_copy; - d->m_output_flush_remaining = n; - } - } - else - { - d->m_out_buf_ofs += n; - } - } - - return d->m_output_flush_remaining; -} - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES -#ifdef MINIZ_UNALIGNED_USE_MEMCPY -static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8* p) -{ - mz_uint16 ret; - memcpy(&ret, p, sizeof(mz_uint16)); - return ret; -} -static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p) -{ - mz_uint16 ret; - memcpy(&ret, p, sizeof(mz_uint16)); - return ret; -} -#else -#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) -#define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p) -#endif -static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) -{ - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; - mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; - mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); - mz_uint16 s01 = TDEFL_READ_UNALIGNED_WORD2(s); - MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); - if (max_match_len <= match_len) - return; - for (;;) - { - for (;;) - { - if (--num_probes_left == 0) - return; -#define TDEFL_PROBE \ - next_probe_pos = d->m_next[probe_pos]; \ - if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ - return; \ - probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ - if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ - break; - TDEFL_PROBE; - TDEFL_PROBE; - TDEFL_PROBE; - } - if (!dist) - break; - q = (const mz_uint16 *)(d->m_dict + probe_pos); - if (TDEFL_READ_UNALIGNED_WORD2(q) != s01) - continue; - p = s; - probe_len = 32; - do - { - } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && - (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); - if (!probe_len) - { - *pMatch_dist = dist; - *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN); - break; - } - else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len) - { - *pMatch_dist = dist; - if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) - break; - c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); - } - } -} -#else -static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) -{ - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; - mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint8 *s = d->m_dict + pos, *p, *q; - mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; - MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); - if (max_match_len <= match_len) - return; - for (;;) - { - for (;;) - { - if (--num_probes_left == 0) - return; -#define TDEFL_PROBE \ - next_probe_pos = d->m_next[probe_pos]; \ - if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ - return; \ - probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ - if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \ - break; - TDEFL_PROBE; - TDEFL_PROBE; - TDEFL_PROBE; - } - if (!dist) - break; - p = s; - q = d->m_dict + probe_pos; - for (probe_len = 0; probe_len < max_match_len; probe_len++) - if (*p++ != *q++) - break; - if (probe_len > match_len) - { - *pMatch_dist = dist; - if ((*pMatch_len = match_len = probe_len) == max_match_len) - return; - c0 = d->m_dict[pos + match_len]; - c1 = d->m_dict[pos + match_len - 1]; - } - } -} -#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ - -// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -// static mz_bool tdefl_compress_fast(tdefl_compressor *d) -// { -// /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ -// mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; -// mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; -// mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - -// while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) -// { -// const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; -// mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; -// mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); -// d->m_src_buf_left -= num_bytes_to_process; -// lookahead_size += num_bytes_to_process; - -// while (num_bytes_to_process) -// { -// mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); -// memcpy(d->m_dict + dst_pos, d->m_pSrc, n); -// if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) -// memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); -// d->m_pSrc += n; -// dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; -// num_bytes_to_process -= n; -// } - -// dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); -// if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) -// break; - -// while (lookahead_size >= 4) -// { -// mz_uint cur_match_dist, cur_match_len = 1; -// mz_uint8 *pCur_dict = d->m_dict + cur_pos; -// mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; -// mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; -// mz_uint probe_pos = d->m_hash[hash]; -// d->m_hash[hash] = (mz_uint16)lookahead_pos; - -// if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) -// { -// const mz_uint16 *p = (const mz_uint16 *)pCur_dict; -// const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); -// mz_uint32 probe_len = 32; -// do -// { -// } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && -// (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); -// cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); -// if (!probe_len) -// cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; - -// if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) -// { -// cur_match_len = 1; -// *pLZ_code_buf++ = (mz_uint8)first_trigram; -// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -// d->m_huff_count[0][(mz_uint8)first_trigram]++; -// } -// else -// { -// mz_uint32 s0, s1; -// cur_match_len = MZ_MIN(cur_match_len, lookahead_size); - -// MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); - -// cur_match_dist--; - -// pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); -// *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; -// pLZ_code_buf += 3; -// *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); - -// s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; -// s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; -// d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; - -// d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; -// } -// } -// else -// { -// *pLZ_code_buf++ = (mz_uint8)first_trigram; -// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -// d->m_huff_count[0][(mz_uint8)first_trigram]++; -// } - -// if (--num_flags_left == 0) -// { -// num_flags_left = 8; -// pLZ_flags = pLZ_code_buf++; -// } - -// total_lz_bytes += cur_match_len; -// lookahead_pos += cur_match_len; -// dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); -// cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; -// MZ_ASSERT(lookahead_size >= cur_match_len); -// lookahead_size -= cur_match_len; - -// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) -// { -// int n; -// d->m_lookahead_pos = lookahead_pos; -// d->m_lookahead_size = lookahead_size; -// d->m_dict_size = dict_size; -// d->m_total_lz_bytes = total_lz_bytes; -// d->m_pLZ_code_buf = pLZ_code_buf; -// d->m_pLZ_flags = pLZ_flags; -// d->m_num_flags_left = num_flags_left; -// if ((n = tdefl_flush_block(d, 0)) != 0) -// return (n < 0) ? MZ_FALSE : MZ_TRUE; -// total_lz_bytes = d->m_total_lz_bytes; -// pLZ_code_buf = d->m_pLZ_code_buf; -// pLZ_flags = d->m_pLZ_flags; -// num_flags_left = d->m_num_flags_left; -// } -// } - -// while (lookahead_size) -// { -// mz_uint8 lit = d->m_dict[cur_pos]; - -// total_lz_bytes++; -// *pLZ_code_buf++ = lit; -// *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); -// if (--num_flags_left == 0) -// { -// num_flags_left = 8; -// pLZ_flags = pLZ_code_buf++; -// } - -// d->m_huff_count[0][lit]++; - -// lookahead_pos++; -// dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); -// cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; -// lookahead_size--; - -// if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) -// { -// int n; -// d->m_lookahead_pos = lookahead_pos; -// d->m_lookahead_size = lookahead_size; -// d->m_dict_size = dict_size; -// d->m_total_lz_bytes = total_lz_bytes; -// d->m_pLZ_code_buf = pLZ_code_buf; -// d->m_pLZ_flags = pLZ_flags; -// d->m_num_flags_left = num_flags_left; -// if ((n = tdefl_flush_block(d, 0)) != 0) -// return (n < 0) ? MZ_FALSE : MZ_TRUE; -// total_lz_bytes = d->m_total_lz_bytes; -// pLZ_code_buf = d->m_pLZ_code_buf; -// pLZ_flags = d->m_pLZ_flags; -// num_flags_left = d->m_num_flags_left; -// } -// } -// } - -// d->m_lookahead_pos = lookahead_pos; -// d->m_lookahead_size = lookahead_size; -// d->m_dict_size = dict_size; -// d->m_total_lz_bytes = total_lz_bytes; -// d->m_pLZ_code_buf = pLZ_code_buf; -// d->m_pLZ_flags = pLZ_flags; -// d->m_num_flags_left = num_flags_left; -// return MZ_TRUE; -// } -// #endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ - -static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) -{ - d->m_total_lz_bytes++; - *d->m_pLZ_code_buf++ = lit; - *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); - if (--d->m_num_flags_left == 0) - { - d->m_num_flags_left = 8; - d->m_pLZ_flags = d->m_pLZ_code_buf++; - } - d->m_huff_count[0][lit]++; -} - -static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) -{ - mz_uint32 s0, s1; - - MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); - - d->m_total_lz_bytes += match_len; - - d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); - - match_dist -= 1; - d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); - d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); - d->m_pLZ_code_buf += 3; - - *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); - if (--d->m_num_flags_left == 0) - { - d->m_num_flags_left = 8; - d->m_pLZ_flags = d->m_pLZ_code_buf++; - } - - s0 = s_tdefl_small_dist_sym[match_dist & 511]; - s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; - d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; - - if (match_len >= TDEFL_MIN_MATCH_LEN) - d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; -} - -static mz_bool tdefl_compress_normal(tdefl_compressor *d) -{ - const mz_uint8 *pSrc = d->m_pSrc; - size_t src_buf_left = d->m_src_buf_left; - tdefl_flush flush = d->m_flush; - - while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) - { - mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; - /* Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. */ - if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) - { - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; - mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; - mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); - const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; - src_buf_left -= num_bytes_to_process; - d->m_lookahead_size += num_bytes_to_process; - while (pSrc != pSrc_end) - { - mz_uint8 c = *pSrc++; - d->m_dict[dst_pos] = c; - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; - d->m_hash[hash] = (mz_uint16)(ins_pos); - dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; - ins_pos++; - } - } - else - { - while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) - { - mz_uint8 c = *pSrc++; - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; - src_buf_left--; - d->m_dict[dst_pos] = c; - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) - { - mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; - mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; - d->m_hash[hash] = (mz_uint16)(ins_pos); - } - } - } - d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); - if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) - break; - - /* Simple lazy/greedy parsing state machine. */ - len_to_move = 1; - cur_match_dist = 0; - cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); - cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) - { - if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) - { - mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; - cur_match_len = 0; - while (cur_match_len < d->m_lookahead_size) - { - if (d->m_dict[cur_pos + cur_match_len] != c) - break; - cur_match_len++; - } - if (cur_match_len < TDEFL_MIN_MATCH_LEN) - cur_match_len = 0; - else - cur_match_dist = 1; - } - } - else - { - tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); - } - if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) - { - cur_match_dist = cur_match_len = 0; - } - if (d->m_saved_match_len) - { - if (cur_match_len > d->m_saved_match_len) - { - tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); - if (cur_match_len >= 128) - { - tdefl_record_match(d, cur_match_len, cur_match_dist); - d->m_saved_match_len = 0; - len_to_move = cur_match_len; - } - else - { - d->m_saved_lit = d->m_dict[cur_pos]; - d->m_saved_match_dist = cur_match_dist; - d->m_saved_match_len = cur_match_len; - } - } - else - { - tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); - len_to_move = d->m_saved_match_len - 1; - d->m_saved_match_len = 0; - } - } - else if (!cur_match_dist) - tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); - else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) - { - tdefl_record_match(d, cur_match_len, cur_match_dist); - len_to_move = cur_match_len; - } - else - { - d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; - d->m_saved_match_dist = cur_match_dist; - d->m_saved_match_len = cur_match_len; - } - /* Move the lookahead forward by len_to_move bytes. */ - d->m_lookahead_pos += len_to_move; - MZ_ASSERT(d->m_lookahead_size >= len_to_move); - d->m_lookahead_size -= len_to_move; - d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); - /* Check if it's time to flush the current LZ codes to the internal output buffer. */ - if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || - ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) - { - int n; - d->m_pSrc = pSrc; - d->m_src_buf_left = src_buf_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - } - } - - d->m_pSrc = pSrc; - d->m_src_buf_left = src_buf_left; - return MZ_TRUE; -} - -static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) -{ - if (d->m_pIn_buf_size) - { - *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; - } - - if (d->m_pOut_buf_size) - { - size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); - d->m_output_flush_ofs += (mz_uint)n; - d->m_output_flush_remaining -= (mz_uint)n; - d->m_out_buf_ofs += n; - - *d->m_pOut_buf_size = d->m_out_buf_ofs; - } - - return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; -} - -tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) -{ - if (!d) - { - if (pIn_buf_size) - *pIn_buf_size = 0; - if (pOut_buf_size) - *pOut_buf_size = 0; - return TDEFL_STATUS_BAD_PARAM; - } - - d->m_pIn_buf = pIn_buf; - d->m_pIn_buf_size = pIn_buf_size; - d->m_pOut_buf = pOut_buf; - d->m_pOut_buf_size = pOut_buf_size; - d->m_pSrc = (const mz_uint8 *)(pIn_buf); - d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; - d->m_out_buf_ofs = 0; - d->m_flush = flush; - - if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || - (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) - { - if (pIn_buf_size) - *pIn_buf_size = 0; - if (pOut_buf_size) - *pOut_buf_size = 0; - return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); - } - d->m_wants_to_finish |= (flush == TDEFL_FINISH); - - if ((d->m_output_flush_remaining) || (d->m_finished)) - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); - -// #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -// if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && -// ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && -// ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) -// { -// if (!tdefl_compress_fast(d)) -// return d->m_prev_return_status; -// } -// else -// #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ - { - if (!tdefl_compress_normal(d)) - return d->m_prev_return_status; - } - - if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) - d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); - - if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) - { - if (tdefl_flush_block(d, flush) < 0) - return d->m_prev_return_status; - d->m_finished = (flush == TDEFL_FINISH); - if (flush == TDEFL_FULL_FLUSH) - { - MZ_CLEAR_OBJ(d->m_hash); - MZ_CLEAR_OBJ(d->m_next); - d->m_dict_size = 0; - } - } - - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); -} - -// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) -// { -// MZ_ASSERT(d->m_pPut_buf_func); -// return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); -// } - -tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - d->m_pPut_buf_func = pPut_buf_func; - d->m_pPut_buf_user = pPut_buf_user; - d->m_flags = (mz_uint)(flags); - d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; - d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; - d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; - if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) - MZ_CLEAR_OBJ(d->m_hash); - d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; - d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; - d->m_pLZ_flags = d->m_lz_code_buf; - d->m_num_flags_left = 8; - d->m_pOutput_buf = d->m_output_buf; - d->m_pOutput_buf_end = d->m_output_buf; - d->m_prev_return_status = TDEFL_STATUS_OKAY; - d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; - d->m_adler32 = 1; - d->m_pIn_buf = NULL; - d->m_pOut_buf = NULL; - d->m_pIn_buf_size = NULL; - d->m_pOut_buf_size = NULL; - d->m_flush = TDEFL_NO_FLUSH; - d->m_pSrc = NULL; - d->m_src_buf_left = 0; - d->m_out_buf_ofs = 0; - memset(d->m_dict, 0, sizeof(d->m_dict)); // Initialize array to 0's - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - return TDEFL_STATUS_OKAY; -} - -// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) -// { -// return d->m_prev_return_status; -// } - -mz_uint32 tdefl_get_adler32(tdefl_compressor *d) -{ - return d->m_adler32; -} - -// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -// { -// tdefl_compressor *pComp; -// mz_bool succeeded; -// if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) -// return MZ_FALSE; -// pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -// if (!pComp) -// return MZ_FALSE; -// succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); -// succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); -// MZ_FREE(pComp); -// return succeeded; -// } - -// typedef struct -// { -// size_t m_size, m_capacity; -// mz_uint8 *m_pBuf; -// mz_bool m_expandable; -// } tdefl_output_buffer; - -// static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) -// { -// tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; -// size_t new_size = p->m_size + len; -// if (new_size > p->m_capacity) -// { -// size_t new_capacity = p->m_capacity; -// mz_uint8 *pNew_buf; -// if (!p->m_expandable) -// return MZ_FALSE; -// do -// { -// new_capacity = MZ_MAX(128U, new_capacity << 1U); -// } while (new_size > new_capacity); -// pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); -// if (!pNew_buf) -// return MZ_FALSE; -// p->m_pBuf = pNew_buf; -// p->m_capacity = new_capacity; -// } -// memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); -// p->m_size = new_size; -// return MZ_TRUE; -// } - -// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -// { -// tdefl_output_buffer out_buf; -// MZ_CLEAR_OBJ(out_buf); -// if (!pOut_len) -// return MZ_FALSE; -// else -// *pOut_len = 0; -// out_buf.m_expandable = MZ_TRUE; -// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) -// return NULL; -// *pOut_len = out_buf.m_size; -// return out_buf.m_pBuf; -// } - -// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -// { -// tdefl_output_buffer out_buf; -// MZ_CLEAR_OBJ(out_buf); -// if (!pOut_buf) -// return 0; -// out_buf.m_pBuf = (mz_uint8 *)pOut_buf; -// out_buf.m_capacity = out_buf_len; -// if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) -// return 0; -// return out_buf.m_size; -// } - -static const mz_uint16 s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; - -/* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */ -mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) -{ - mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); - if (window_bits > 0) - comp_flags |= TDEFL_WRITE_ZLIB_HEADER; - - if (!level) - comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; - else if (strategy == MZ_FILTERED) - comp_flags |= TDEFL_FILTER_MATCHES; - else if (strategy == MZ_HUFFMAN_ONLY) - comp_flags &= ~TDEFL_MAX_PROBES_MASK; - else if (strategy == MZ_FIXED) - comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; - else if (strategy == MZ_RLE) - comp_flags |= TDEFL_RLE_MATCHES; - - return comp_flags; -} - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) */ -#endif - -/* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at - http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. - This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ -// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) -// { -// /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ -// static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; -// tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -// tdefl_output_buffer out_buf; -// int i, bpl = w * num_chans, y, z; -// mz_uint32 c; -// *pLen_out = 0; -// if (!pComp) -// return NULL; -// MZ_CLEAR_OBJ(out_buf); -// out_buf.m_expandable = MZ_TRUE; -// out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); -// if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) -// { -// MZ_FREE(pComp); -// return NULL; -// } -// /* write dummy header */ -// for (z = 41; z; --z) -// tdefl_output_buffer_putter(&z, 1, &out_buf); -// /* compress image data */ -// tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); -// for (y = 0; y < h; ++y) -// { -// tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); -// tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); -// } -// if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) -// { -// MZ_FREE(pComp); -// MZ_FREE(out_buf.m_pBuf); -// return NULL; -// } -// /* write real header */ -// *pLen_out = out_buf.m_size - 41; -// { -// static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; -// mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, -// 0x0a, 0x1a, 0x0a, 0x00, 0x00, -// 0x00, 0x0d, 0x49, 0x48, 0x44, -// 0x52, 0x00, 0x00, 0x00, 0x00, -// 0x00, 0x00, 0x00, 0x00, 0x08, -// 0x00, 0x00, 0x00, 0x00, 0x00, -// 0x00, 0x00, 0x00, 0x00, 0x00, -// 0x00, 0x00, 0x49, 0x44, 0x41, -// 0x54 }; -// pnghdr[18] = (mz_uint8)(w >> 8); -// pnghdr[19] = (mz_uint8)w; -// pnghdr[22] = (mz_uint8)(h >> 8); -// pnghdr[23] = (mz_uint8)h; -// pnghdr[25] = chans[num_chans]; -// pnghdr[33] = (mz_uint8)(*pLen_out >> 24); -// pnghdr[34] = (mz_uint8)(*pLen_out >> 16); -// pnghdr[35] = (mz_uint8)(*pLen_out >> 8); -// pnghdr[36] = (mz_uint8)*pLen_out; -// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); -// for (i = 0; i < 4; ++i, c <<= 8) -// ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); -// memcpy(out_buf.m_pBuf, pnghdr, 41); -// } -// /* write footer (IDAT CRC-32, followed by IEND chunk) */ -// if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) -// { -// *pLen_out = 0; -// MZ_FREE(pComp); -// MZ_FREE(out_buf.m_pBuf); -// return NULL; -// } -// c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); -// for (i = 0; i < 4; ++i, c <<= 8) -// (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); -// /* compute final size of file, grab compressed data buffer and return */ -// *pLen_out += 57; -// MZ_FREE(pComp); -// return out_buf.m_pBuf; -// } -// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) -// { - /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */ -// return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); -// } - -/* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ -/* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ -/* structure size and allocation mechanism. */ -// tdefl_compressor *tdefl_compressor_alloc() -// { -// return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -// } - -// void tdefl_compressor_free(tdefl_compressor *pComp) -// { -// MZ_FREE(pComp); -// } - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#ifdef __cplusplus -} -#endif -/************************************************************************** - * - * Copyright 2013-2014 RAD Game Tools and Valve Software - * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ - - - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------- Low-level Decompression (completely independent from all compression API's) */ - -#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) -#define TINFL_MEMSET(p, c, l) memset(p, c, l) - -#define TINFL_CR_BEGIN \ - switch (r->m_state) \ - { \ - case 0: -#define TINFL_CR_RETURN(state_index, result) \ - do \ - { \ - status = result; \ - r->m_state = state_index; \ - goto common_exit; \ - case state_index:; \ - } \ - MZ_MACRO_END -#define TINFL_CR_RETURN_FOREVER(state_index, result) \ - do \ - { \ - for (;;) \ - { \ - TINFL_CR_RETURN(state_index, result); \ - } \ - } \ - MZ_MACRO_END -#define TINFL_CR_FINISH } - -#define TINFL_GET_BYTE(state_index, c) \ - do \ - { \ - while (pIn_buf_cur >= pIn_buf_end) \ - { \ - TINFL_CR_RETURN(state_index, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \ - } \ - c = *pIn_buf_cur++; \ - } \ - MZ_MACRO_END - -#define TINFL_NEED_BITS(state_index, n) \ - do \ - { \ - mz_uint c; \ - TINFL_GET_BYTE(state_index, c); \ - bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ - num_bits += 8; \ - } while (num_bits < (mz_uint)(n)) -#define TINFL_SKIP_BITS(state_index, n) \ - do \ - { \ - if (num_bits < (mz_uint)(n)) \ - { \ - TINFL_NEED_BITS(state_index, n); \ - } \ - bit_buf >>= (n); \ - num_bits -= (n); \ - } \ - MZ_MACRO_END -#define TINFL_GET_BITS(state_index, b, n) \ - do \ - { \ - if (num_bits < (mz_uint)(n)) \ - { \ - TINFL_NEED_BITS(state_index, n); \ - } \ - b = bit_buf & ((1 << (n)) - 1); \ - bit_buf >>= (n); \ - num_bits -= (n); \ - } \ - MZ_MACRO_END - -/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */ -/* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */ -/* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */ -/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */ -#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ - do \ - { \ - temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ - if (temp >= 0) \ - { \ - code_len = temp >> 9; \ - if ((code_len) && (num_bits >= code_len)) \ - break; \ - } \ - else if (num_bits > TINFL_FAST_LOOKUP_BITS) \ - { \ - code_len = TINFL_FAST_LOOKUP_BITS; \ - do \ - { \ - temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ - } while ((temp < 0) && (num_bits >= (code_len + 1))); \ - if (temp >= 0) \ - break; \ - } \ - TINFL_GET_BYTE(state_index, c); \ - bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ - num_bits += 8; \ - } while (num_bits < 15); - -/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */ -/* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */ -/* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */ -/* The slow path is only executed at the very end of the input buffer. */ -/* v1.16: The original macro handled the case at the very end of the passed-in input buffer, but we also need to handle the case where the user passes in 1+zillion bytes */ -/* following the deflate data and our non-conservative read-ahead path won't kick in here on this code. This is much trickier. */ -#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \ - do \ - { \ - int temp; \ - mz_uint code_len, c; \ - if (num_bits < 15) \ - { \ - if ((pIn_buf_end - pIn_buf_cur) < 2) \ - { \ - TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ - } \ - else \ - { \ - bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ - pIn_buf_cur += 2; \ - num_bits += 16; \ - } \ - } \ - if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ - code_len = temp >> 9, temp &= 511; \ - else \ - { \ - code_len = TINFL_FAST_LOOKUP_BITS; \ - do \ - { \ - temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ - } while (temp < 0); \ - } \ - sym = temp; \ - bit_buf >>= code_len; \ - num_bits -= code_len; \ - } \ - MZ_MACRO_END - -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) -{ - static const mz_uint16 s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; - static const mz_uint8 s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; - static const mz_uint16 s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; - static const mz_uint8 s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; - static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - static const mz_uint16 s_min_table_sizes[3] = { 257, 1, 4 }; - - tinfl_status status = TINFL_STATUS_FAILED; - mz_uint32 num_bits, dist, counter, num_extra; - tinfl_bit_buf_t bit_buf; - const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; - mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; - size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; - - /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */ - if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) - { - *pIn_buf_size = *pOut_buf_size = 0; - return TINFL_STATUS_BAD_PARAM; - } - - num_bits = r->m_num_bits; - bit_buf = r->m_bit_buf; - dist = r->m_dist; - counter = r->m_counter; - num_extra = r->m_num_extra; - dist_from_out_buf_start = r->m_dist_from_out_buf_start; - TINFL_CR_BEGIN - - bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; - r->m_z_adler32 = r->m_check_adler32 = 1; - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - TINFL_GET_BYTE(1, r->m_zhdr0); - TINFL_GET_BYTE(2, r->m_zhdr1); - counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); - if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) - counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); - if (counter) - { - TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); - } - } - - do - { - TINFL_GET_BITS(3, r->m_final, 3); - r->m_type = r->m_final >> 1; - if (r->m_type == 0) - { - TINFL_SKIP_BITS(5, num_bits & 7); - for (counter = 0; counter < 4; ++counter) - { - if (num_bits) - TINFL_GET_BITS(6, r->m_raw_header[counter], 8); - else - TINFL_GET_BYTE(7, r->m_raw_header[counter]); - } - if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) - { - TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); - } - while ((counter) && (num_bits)) - { - TINFL_GET_BITS(51, dist, 8); - while (pOut_buf_cur >= pOut_buf_end) - { - TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); - } - *pOut_buf_cur++ = (mz_uint8)dist; - counter--; - } - while (counter) - { - size_t n; - while (pOut_buf_cur >= pOut_buf_end) - { - TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); - } - while (pIn_buf_cur >= pIn_buf_end) - { - TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); - } - n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); - TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); - pIn_buf_cur += n; - pOut_buf_cur += n; - counter -= (mz_uint)n; - } - } - else if (r->m_type == 3) - { - TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); - } - else - { - if (r->m_type == 1) - { - mz_uint8 *p = r->m_tables[0].m_code_size; - mz_uint i; - r->m_table_sizes[0] = 288; - r->m_table_sizes[1] = 32; - TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); - for (i = 0; i <= 143; ++i) - *p++ = 8; - for (; i <= 255; ++i) - *p++ = 9; - for (; i <= 279; ++i) - *p++ = 7; - for (; i <= 287; ++i) - *p++ = 8; - } - else - { - for (counter = 0; counter < 3; counter++) - { - TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); - r->m_table_sizes[counter] += s_min_table_sizes[counter]; - } - MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); - for (counter = 0; counter < r->m_table_sizes[2]; counter++) - { - mz_uint s; - TINFL_GET_BITS(14, s, 3); - r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; - } - r->m_table_sizes[2] = 19; - } - for (; ((int)r->m_type) >= 0; r->m_type--) - { - int tree_next, tree_cur; - tinfl_huff_table *pTable; - mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; - pTable = &r->m_tables[r->m_type]; - MZ_CLEAR_OBJ(total_syms); - MZ_CLEAR_OBJ(pTable->m_look_up); - MZ_CLEAR_OBJ(pTable->m_tree); - for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) - total_syms[pTable->m_code_size[i]]++; - used_syms = 0, total = 0; - next_code[0] = next_code[1] = 0; - for (i = 1; i <= 15; ++i) - { - used_syms += total_syms[i]; - next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); - } - if ((65536 != total) && (used_syms > 1)) - { - TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); - } - for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) - { - mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; - if (!code_size) - continue; - cur_code = next_code[code_size]++; - for (l = code_size; l > 0; l--, cur_code >>= 1) - rev_code = (rev_code << 1) | (cur_code & 1); - if (code_size <= TINFL_FAST_LOOKUP_BITS) - { - mz_int16 k = (mz_int16)((code_size << 9) | sym_index); - while (rev_code < TINFL_FAST_LOOKUP_SIZE) - { - pTable->m_look_up[rev_code] = k; - rev_code += (1 << code_size); - } - continue; - } - if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) - { - pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; - tree_cur = tree_next; - tree_next -= 2; - } - rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); - for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) - { - tree_cur -= ((rev_code >>= 1) & 1); - if (!pTable->m_tree[-tree_cur - 1]) - { - pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; - tree_cur = tree_next; - tree_next -= 2; - } - else - tree_cur = pTable->m_tree[-tree_cur - 1]; - } - tree_cur -= ((rev_code >>= 1) & 1); - pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; - } - if (r->m_type == 2) - { - for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) - { - mz_uint s; - TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); - if (dist < 16) - { - r->m_len_codes[counter++] = (mz_uint8)dist; - continue; - } - if ((dist == 16) && (!counter)) - { - TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); - } - num_extra = "\02\03\07"[dist - 16]; - TINFL_GET_BITS(18, s, num_extra); - s += "\03\03\013"[dist - 16]; - TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); - counter += s; - } - if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) - { - TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); - } - TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); - TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); - } - } - for (;;) - { - mz_uint8 *pSrc; - for (;;) - { - if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) - { - TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); - if (counter >= 256) - break; - while (pOut_buf_cur >= pOut_buf_end) - { - TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); - } - *pOut_buf_cur++ = (mz_uint8)counter; - } - else - { - int sym2; - mz_uint code_len; -#if TINFL_USE_64BIT_BITBUF - if (num_bits < 30) - { - bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); - pIn_buf_cur += 4; - num_bits += 32; - } -#else - if (num_bits < 15) - { - bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); - pIn_buf_cur += 2; - num_bits += 16; - } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; - do - { - sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; - } while (sym2 < 0); - } - counter = sym2; - bit_buf >>= code_len; - num_bits -= code_len; - if (counter & 256) - break; - -#if !TINFL_USE_64BIT_BITBUF - if (num_bits < 15) - { - bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); - pIn_buf_cur += 2; - num_bits += 16; - } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; - do - { - sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; - } while (sym2 < 0); - } - bit_buf >>= code_len; - num_bits -= code_len; - - pOut_buf_cur[0] = (mz_uint8)counter; - if (sym2 & 256) - { - pOut_buf_cur++; - counter = sym2; - break; - } - pOut_buf_cur[1] = (mz_uint8)sym2; - pOut_buf_cur += 2; - } - } - if ((counter &= 511) == 256) - break; - - num_extra = s_length_extra[counter - 257]; - counter = s_length_base[counter - 257]; - if (num_extra) - { - mz_uint extra_bits; - TINFL_GET_BITS(25, extra_bits, num_extra); - counter += extra_bits; - } - - TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); - num_extra = s_dist_extra[dist]; - dist = s_dist_base[dist]; - if (num_extra) - { - mz_uint extra_bits; - TINFL_GET_BITS(27, extra_bits, num_extra); - dist += extra_bits; - } - - dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; - if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) - { - TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); - } - - pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); - - if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) - { - while (counter--) - { - while (pOut_buf_cur >= pOut_buf_end) - { - TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); - } - *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; - } - continue; - } -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES - else if ((counter >= 9) && (counter <= dist)) - { - const mz_uint8 *pSrc_end = pSrc + (counter & ~7); - do - { - ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; - ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; - pOut_buf_cur += 8; - } while ((pSrc += 8) < pSrc_end); - if ((counter &= 7) < 3) - { - if (counter) - { - pOut_buf_cur[0] = pSrc[0]; - if (counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - continue; - } - } -#endif - do - { - pOut_buf_cur[0] = pSrc[0]; - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur[2] = pSrc[2]; - pOut_buf_cur += 3; - pSrc += 3; - } while ((int)(counter -= 3) > 2); - if ((int)counter > 0) - { - pOut_buf_cur[0] = pSrc[0]; - if ((int)counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - } - } - } while (!(r->m_final & 1)); - - /* Ensure byte alignment and put back any bytes from the bitbuf if we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ - /* I'm being super conservative here. A number of simplifications can be made to the byte alignment part, and the Adler32 check shouldn't ever need to worry about reading from the bitbuf now. */ - TINFL_SKIP_BITS(32, num_bits & 7); - while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) - { - --pIn_buf_cur; - num_bits -= 8; - } - bit_buf &= (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); - MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */ - - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - for (counter = 0; counter < 4; ++counter) - { - mz_uint s; - if (num_bits) - TINFL_GET_BITS(41, s, 8); - else - TINFL_GET_BYTE(42, s); - r->m_z_adler32 = (r->m_z_adler32 << 8) | s; - } - } - TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); - - TINFL_CR_FINISH - -common_exit: - /* As long as we aren't telling the caller that we NEED more input to make forward progress: */ - /* Put back any bytes from the bitbuf in case we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ - /* We need to be very careful here to NOT push back any bytes we definitely know we need to make forward progress, though, or we'll lock the caller up into an inf loop. */ - if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) && (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS)) - { - while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) - { - --pIn_buf_cur; - num_bits -= 8; - } - } - r->m_num_bits = num_bits; - r->m_bit_buf = bit_buf & (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); - r->m_dist = dist; - r->m_counter = counter; - r->m_num_extra = num_extra; - r->m_dist_from_out_buf_start = dist_from_out_buf_start; - *pIn_buf_size = pIn_buf_cur - pIn_buf_next; - *pOut_buf_size = pOut_buf_cur - pOut_buf_next; - if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) - { - const mz_uint8 *ptr = pOut_buf_next; - size_t buf_len = *pOut_buf_size; - mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; - size_t block_len = buf_len % 5552; - while (buf_len) - { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) - { - s1 += ptr[0], s2 += s1; - s1 += ptr[1], s2 += s1; - s1 += ptr[2], s2 += s1; - s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; - s1 += ptr[5], s2 += s1; - s1 += ptr[6], s2 += s1; - s1 += ptr[7], s2 += s1; - } - for (; i < block_len; ++i) - s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; - buf_len -= block_len; - block_len = 5552; - } - r->m_check_adler32 = (s2 << 16) + s1; - if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) - status = TINFL_STATUS_ADLER32_MISMATCH; - } - return status; -} - -/* Higher level helper functions. */ -// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -// { -// tinfl_decompressor decomp; -// void *pBuf = NULL, *pNew_buf; -// size_t src_buf_ofs = 0, out_buf_capacity = 0; -// *pOut_len = 0; -// tinfl_init(&decomp); -// for (;;) -// { -// size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; -// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, -// (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); -// if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) -// { -// MZ_FREE(pBuf); -// *pOut_len = 0; -// return NULL; -// } -// src_buf_ofs += src_buf_size; -// *pOut_len += dst_buf_size; -// if (status == TINFL_STATUS_DONE) -// break; -// new_out_buf_capacity = out_buf_capacity * 2; -// if (new_out_buf_capacity < 128) -// new_out_buf_capacity = 128; -// pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); -// if (!pNew_buf) -// { -// MZ_FREE(pBuf); -// *pOut_len = 0; -// return NULL; -// } -// pBuf = pNew_buf; -// out_buf_capacity = new_out_buf_capacity; -// } -// return pBuf; -// } - -// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -// { -// tinfl_decompressor decomp; -// tinfl_status status; -// tinfl_init(&decomp); -// status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); -// return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; -// } - -// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -// { -// int result = 0; -// tinfl_decompressor decomp; -// mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); -// size_t in_buf_ofs = 0, dict_ofs = 0; -// if (!pDict) -// return TINFL_STATUS_FAILED; -// tinfl_init(&decomp); -// for (;;) -// { -// size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; -// tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, -// (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); -// in_buf_ofs += in_buf_size; -// if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) -// break; -// if (status != TINFL_STATUS_HAS_MORE_OUTPUT) -// { -// result = (status == TINFL_STATUS_DONE); -// break; -// } -// dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); -// } -// MZ_FREE(pDict); -// *pIn_buf_size = in_buf_ofs; -// return result; -// } - -// tinfl_decompressor *tinfl_decompressor_alloc() -// { -// tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); -// if (pDecomp) -// tinfl_init(pDecomp); -// return pDecomp; -// } - -// void tinfl_decompressor_free(tinfl_decompressor *pDecomp) -// { -// MZ_FREE(pDecomp); -// } - -#ifdef __cplusplus -} -#endif -/************************************************************************** - * - * Copyright 2013-2014 RAD Game Tools and Valve Software - * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - * Copyright 2016 Martin Raiber - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ - - -// #ifndef MINIZ_NO_ARCHIVE_APIS - -// #ifdef __cplusplus -// extern "C" { -// #endif - -/* ------------------- .ZIP archive reading */ - -// #ifdef MINIZ_NO_STDIO -// #define MZ_FILE void * -// #else -// #include - -// #if defined(_MSC_VER) || defined(__MINGW64__) -// static FILE *mz_fopen(const char *pFilename, const char *pMode) -// { -// FILE *pFile = NULL; -// fopen_s(&pFile, pFilename, pMode); -// return pFile; -// } -// static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) -// { -// FILE *pFile = NULL; -// if (freopen_s(&pFile, pPath, pMode, pStream)) -// return NULL; -// return pFile; -// } -// #ifndef MINIZ_NO_TIME -// #include -// #endif -// #define MZ_FOPEN mz_fopen -// #define MZ_FCLOSE fclose -// #define MZ_FREAD fread -// #define MZ_FWRITE fwrite -// #define MZ_FTELL64 _ftelli64 -// #define MZ_FSEEK64 _fseeki64 -// #define MZ_FILE_STAT_STRUCT _stat -// #define MZ_FILE_STAT _stat -// #define MZ_FFLUSH fflush -// #define MZ_FREOPEN mz_freopen -// #define MZ_DELETE_FILE remove -// #elif defined(__MINGW32__) -// #ifndef MINIZ_NO_TIME -// #include -// #endif -// #define MZ_FOPEN(f, m) fopen(f, m) -// #define MZ_FCLOSE fclose -// #define MZ_FREAD fread -// #define MZ_FWRITE fwrite -// #define MZ_FTELL64 ftello64 -// #define MZ_FSEEK64 fseeko64 -// #define MZ_FILE_STAT_STRUCT _stat -// #define MZ_FILE_STAT _stat -// #define MZ_FFLUSH fflush -// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) -// #define MZ_DELETE_FILE remove -// #elif defined(__TINYC__) -// #ifndef MINIZ_NO_TIME -// #include -// #endif -// #define MZ_FOPEN(f, m) fopen(f, m) -// #define MZ_FCLOSE fclose -// #define MZ_FREAD fread -// #define MZ_FWRITE fwrite -// #define MZ_FTELL64 ftell -// #define MZ_FSEEK64 fseek -// #define MZ_FILE_STAT_STRUCT stat -// #define MZ_FILE_STAT stat -// #define MZ_FFLUSH fflush -// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) -// #define MZ_DELETE_FILE remove -// #elif defined(__GNUC__) && _LARGEFILE64_SOURCE -// #ifndef MINIZ_NO_TIME -// #include -// #endif -// #define MZ_FOPEN(f, m) fopen64(f, m) -// #define MZ_FCLOSE fclose -// #define MZ_FREAD fread -// #define MZ_FWRITE fwrite -// #define MZ_FTELL64 ftello64 -// #define MZ_FSEEK64 fseeko64 -// #define MZ_FILE_STAT_STRUCT stat64 -// #define MZ_FILE_STAT stat64 -// #define MZ_FFLUSH fflush -// #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) -// #define MZ_DELETE_FILE remove -// #elif defined(__APPLE__) && _LARGEFILE64_SOURCE -// #ifndef MINIZ_NO_TIME -// #include -// #endif -// #define MZ_FOPEN(f, m) fopen(f, m) -// #define MZ_FCLOSE fclose -// #define MZ_FREAD fread -// #define MZ_FWRITE fwrite -// #define MZ_FTELL64 ftello -// #define MZ_FSEEK64 fseeko -// #define MZ_FILE_STAT_STRUCT stat -// #define MZ_FILE_STAT stat -// #define MZ_FFLUSH fflush -// #define MZ_FREOPEN(p, m, s) freopen(p, m, s) -// #define MZ_DELETE_FILE remove - -// #else -// // #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") -// #ifndef MINIZ_NO_TIME -// #include -// #endif -// #define MZ_FOPEN(f, m) fopen(f, m) -// #define MZ_FCLOSE fclose -// #define MZ_FREAD fread -// #define MZ_FWRITE fwrite -// #ifdef __STRICT_ANSI__ -// #define MZ_FTELL64 ftell -// #define MZ_FSEEK64 fseek -// #else -// #define MZ_FTELL64 ftello -// #define MZ_FSEEK64 fseeko -// #endif -// #define MZ_FILE_STAT_STRUCT stat -// #define MZ_FILE_STAT stat -// #define MZ_FFLUSH fflush -// #define MZ_FREOPEN(f, m, s) freopen(f, m, s) -// #define MZ_DELETE_FILE remove -// #endif /* #ifdef _MSC_VER */ -// #endif /* #ifdef MINIZ_NO_STDIO */ - -// #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) - -/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ -// enum -// { -// /* ZIP archive identifiers and record sizes */ -// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, -// MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, -// MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, -// MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, -// MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, -// MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, - -// /* ZIP64 archive identifier and record sizes */ -// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, -// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, -// MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, -// MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, -// MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, -// MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, -// MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, -// MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, - -// /* Central directory header record offsets */ -// MZ_ZIP_CDH_SIG_OFS = 0, -// MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, -// MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, -// MZ_ZIP_CDH_BIT_FLAG_OFS = 8, -// MZ_ZIP_CDH_METHOD_OFS = 10, -// MZ_ZIP_CDH_FILE_TIME_OFS = 12, -// MZ_ZIP_CDH_FILE_DATE_OFS = 14, -// MZ_ZIP_CDH_CRC32_OFS = 16, -// MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, -// MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, -// MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, -// MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, -// MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, -// MZ_ZIP_CDH_DISK_START_OFS = 34, -// MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, -// MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, -// MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, - -// /* Local directory header offsets */ -// MZ_ZIP_LDH_SIG_OFS = 0, -// MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, -// MZ_ZIP_LDH_BIT_FLAG_OFS = 6, -// MZ_ZIP_LDH_METHOD_OFS = 8, -// MZ_ZIP_LDH_FILE_TIME_OFS = 10, -// MZ_ZIP_LDH_FILE_DATE_OFS = 12, -// MZ_ZIP_LDH_CRC32_OFS = 14, -// MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, -// MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, -// MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, -// MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, -// MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, - -// /* End of central directory offsets */ -// MZ_ZIP_ECDH_SIG_OFS = 0, -// MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, -// MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, -// MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, -// MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, -// MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, -// MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, -// MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, - -// /* ZIP64 End of central directory locator offsets */ -// MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ -// MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ -// MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ -// MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ - -// /* ZIP64 End of central directory header offsets */ -// MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ -// MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ -// MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ -// MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ -// MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ -// MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ -// MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ -// MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ -// MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ -// MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ -// MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, -// MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, -// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, -// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, -// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, -// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, -// MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 -// }; - -// typedef struct -// { -// void *m_p; -// size_t m_size, m_capacity; -// mz_uint m_element_size; -// } mz_zip_array; - -// struct mz_zip_internal_state_tag -// { -// mz_zip_array m_central_dir; -// mz_zip_array m_central_dir_offsets; -// mz_zip_array m_sorted_central_dir_offsets; - -// /* The flags passed in when the archive is initially opened. */ -// uint32_t m_init_flags; - -// /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ -// mz_bool m_zip64; - -// /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ -// mz_bool m_zip64_has_extended_info_fields; - -// /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ -// MZ_FILE *m_pFile; -// mz_uint64 m_file_archive_start_ofs; - -// void *m_pMem; -// size_t m_mem_size; -// size_t m_mem_capacity; -// }; - -// #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size - -// #if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) -// static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) -// { -// MZ_ASSERT(index < pArray->m_size); -// return index; -// } -// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] -// #else -// #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] -// #endif - -// static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) -// { -// memset(pArray, 0, sizeof(mz_zip_array)); -// pArray->m_element_size = element_size; -// } - -// static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); -// memset(pArray, 0, sizeof(mz_zip_array)); -// } - -// static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) -// { -// void *pNew_p; -// size_t new_capacity = min_new_capacity; -// MZ_ASSERT(pArray->m_element_size); -// if (pArray->m_capacity >= min_new_capacity) -// return MZ_TRUE; -// if (growing) -// { -// new_capacity = MZ_MAX(1, pArray->m_capacity); -// while (new_capacity < min_new_capacity) -// new_capacity *= 2; -// } -// if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) -// return MZ_FALSE; -// pArray->m_p = pNew_p; -// pArray->m_capacity = new_capacity; -// return MZ_TRUE; -// } - -// static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) -// { -// if (new_capacity > pArray->m_capacity) -// { -// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) -// return MZ_FALSE; -// } -// return MZ_TRUE; -// } - -// static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) -// { -// if (new_size > pArray->m_capacity) -// { -// if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) -// return MZ_FALSE; -// } -// pArray->m_size = new_size; -// return MZ_TRUE; -// } - -// static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) -// { -// return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); -// } - -// static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) -// { -// size_t orig_size = pArray->m_size; -// if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) -// return MZ_FALSE; -// memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); -// return MZ_TRUE; -// } - -// #ifndef MINIZ_NO_TIME -// static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) -// { -// struct tm tm; -// memset(&tm, 0, sizeof(tm)); -// tm.tm_isdst = -1; -// tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; -// tm.tm_mon = ((dos_date >> 5) & 15) - 1; -// tm.tm_mday = dos_date & 31; -// tm.tm_hour = (dos_time >> 11) & 31; -// tm.tm_min = (dos_time >> 5) & 63; -// tm.tm_sec = (dos_time << 1) & 62; -// return mktime(&tm); -// } - -// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -// static void mz_zip_time_t_to_dos_time(MZ_TIME_T time_, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) -// { -// #ifdef _MSC_VER -// struct tm tm_struct; -// struct tm *tm = &tm_struct; -// errno_t err = localtime_s(tm, &time_); -// if (err) -// { -// *pDOS_date = 0; -// *pDOS_time = 0; -// return; -// } -// #else -// struct tm *tm = localtime(&time_); -// #endif /* #ifdef _MSC_VER */ - -// *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); -// *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); -// } -// #endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ - -// #ifndef MINIZ_NO_STDIO -// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -// static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) -// { -// struct MZ_FILE_STAT_STRUCT file_stat; - -// /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ -// if (MZ_FILE_STAT(pFilename, &file_stat) != 0) -// return MZ_FALSE; - -// *pTime = file_stat.st_mtime; - -// return MZ_TRUE; -// } -// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ - -// static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) -// { -// struct utimbuf t; - -// memset(&t, 0, sizeof(t)); -// t.actime = access_time; -// t.modtime = modified_time; - -// return !utime(pFilename, &t); -// } -// #endif /* #ifndef MINIZ_NO_STDIO */ -// #endif /* #ifndef MINIZ_NO_TIME */ - -// static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) -// { -// if (pZip) -// pZip->m_last_error = err_num; -// return MZ_FALSE; -// } - -// static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) -// { -// (void)flags; -// if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (!pZip->m_pAlloc) -// pZip->m_pAlloc = miniz_def_alloc_func; -// if (!pZip->m_pFree) -// pZip->m_pFree = miniz_def_free_func; -// if (!pZip->m_pRealloc) -// pZip->m_pRealloc = miniz_def_realloc_func; - -// pZip->m_archive_size = 0; -// pZip->m_central_directory_file_ofs = 0; -// pZip->m_total_files = 0; -// pZip->m_last_error = MZ_ZIP_NO_ERROR; - -// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); -// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); -// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); -// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); -// pZip->m_pState->m_init_flags = flags; -// pZip->m_pState->m_zip64 = MZ_FALSE; -// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; - -// pZip->m_zip_mode = MZ_ZIP_MODE_READING; - -// return MZ_TRUE; -// } - -// static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) -// { -// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; -// const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); -// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// mz_uint8 l = 0, r = 0; -// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -// pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -// pE = pL + MZ_MIN(l_len, r_len); -// while (pL < pE) -// { -// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) -// break; -// pL++; -// pR++; -// } -// return (pL == pE) ? (l_len < r_len) : (l < r); -// } -/* -#define MZ_SWAP_UINT32(a, b) \ - do \ - { \ - mz_uint32 t = a; \ - a = b; \ - b = t; \ - } \ - MZ_MACRO_END -*/ -/* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */ -// static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) -// { -// mz_zip_internal_state *pState = pZip->m_pState; -// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; -// const mz_zip_array *pCentral_dir = &pState->m_central_dir; -// mz_uint32 *pIndices; -// mz_uint32 start, end; -// const mz_uint32 size = pZip->m_total_files; - -// if (size <= 1U) -// return; - -// pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); - -// start = (size - 2U) >> 1U; -// for (;;) -// { -// mz_uint64 child, root = start; -// for (;;) -// { -// if ((child = (root << 1U) + 1U) >= size) -// break; -// child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); -// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) -// break; -// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); -// root = child; -// } -// if (!start) -// break; -// start--; -// } - -// end = size - 1; -// while (end > 0) -// { -// mz_uint64 child, root = 0; -// MZ_SWAP_UINT32(pIndices[end], pIndices[0]); -// for (;;) -// { -// if ((child = (root << 1U) + 1U) >= end) -// break; -// child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); -// if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) -// break; -// MZ_SWAP_UINT32(pIndices[root], pIndices[child]); -// root = child; -// } -// end--; -// } -// } - -// static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) -// { -// mz_int64 cur_file_ofs; -// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; -// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; - -// /* Basic sanity checks - reject files which are too small */ -// if (pZip->m_archive_size < record_size) -// return MZ_FALSE; - -// /* Find the record by scanning the file from the end towards the beginning. */ -// cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); -// for (;;) -// { -// int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); - -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) -// return MZ_FALSE; - -// for (i = n - 4; i >= 0; --i) -// { -// mz_uint s = MZ_READ_LE32(pBuf + i); -// if (s == record_sig) -// { -// if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) -// break; -// } -// } - -// if (i >= 0) -// { -// cur_file_ofs += i; -// break; -// } - -// /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ -// if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) -// return MZ_FALSE; - -// cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); -// } - -// *pOfs = cur_file_ofs; -// return MZ_TRUE; -// } - -// static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) -// { -// mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; -// mz_uint64 cdir_ofs = 0; -// mz_int64 cur_file_ofs = 0; -// const mz_uint8 *p; - -// mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; -// mz_uint8 *pBuf = (mz_uint8 *)buf_u32; -// mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); -// mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -// mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; - -// mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -// mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; - -// mz_uint64 zip64_end_of_central_dir_ofs = 0; - -// /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ -// if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -// if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) -// return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); - -// /* Read and verify the end of central directory record. */ -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -// if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) -// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -// if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) -// { -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) -// { -// if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) -// { -// zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); -// if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) -// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -// if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) -// { -// if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) -// { -// pZip->m_pState->m_zip64 = MZ_TRUE; -// } -// } -// } -// } -// } - -// pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); -// cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); -// num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); -// cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); -// cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); -// cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); - -// if (pZip->m_pState->m_zip64) -// { -// mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); -// mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); -// mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); -// mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); -// mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); - -// if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if (zip64_total_num_of_disks != 1U) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -// /* Check for miniz's practical limits */ -// if (zip64_cdir_total_entries > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - -// pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; - -// if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - -// cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; - -// /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ -// if (zip64_size_of_central_directory > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -// cdir_size = (mz_uint32)zip64_size_of_central_directory; - -// num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); - -// cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); - -// cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); -// } - -// if (pZip->m_total_files != cdir_entries_on_this_disk) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -// if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -// if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// pZip->m_central_directory_file_ofs = cdir_ofs; - -// if (pZip->m_total_files) -// { -// mz_uint i, n; -// /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ -// if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || -// (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// if (sort_central_dir) -// { -// if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -// /* Now create an index into the central directory file records, do some basic sanity checking on each record */ -// p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; -// for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) -// { -// mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; -// mz_uint64 comp_size, decomp_size, local_header_ofs; - -// if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); - -// if (sort_central_dir) -// MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; - -// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -// decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); -// local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); -// filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); - -// if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && -// (ext_data_size) && -// (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) -// { -// /* Attempt to find zip64 extended information field in the entry's extra data */ -// mz_uint32 extra_size_remaining = ext_data_size; - -// if (extra_size_remaining) -// { -// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; - -// do -// { -// mz_uint32 field_id; -// mz_uint32 field_data_size; - -// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// field_id = MZ_READ_LE16(pExtra_data); -// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); - -// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -// { -// /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ -// pZip->m_pState->m_zip64 = MZ_TRUE; -// pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; -// break; -// } - -// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; -// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; -// } while (extra_size_remaining); -// } -// } - -// /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ -// if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) -// { -// if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// } - -// disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); -// if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - -// if (comp_size != MZ_UINT32_MAX) -// { -// if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// } - -// bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -// if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - -// if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// n -= total_header_size; -// p += total_header_size; -// } -// } - -// if (sort_central_dir) -// mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); - -// return MZ_TRUE; -// } - -// void mz_zip_zero_struct(mz_zip_archive *pZip) -// { -// if (pZip) -// MZ_CLEAR_OBJ(*pZip); -// } - -// static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) -// { -// mz_bool status = MZ_TRUE; - -// if (!pZip) -// return MZ_FALSE; - -// if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) -// { -// if (set_last_error) -// pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; - -// return MZ_FALSE; -// } - -// if (pZip->m_pState) -// { -// mz_zip_internal_state *pState = pZip->m_pState; -// pZip->m_pState = NULL; - -// mz_zip_array_clear(pZip, &pState->m_central_dir); -// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); -// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); - -// #ifndef MINIZ_NO_STDIO -// if (pState->m_pFile) -// { -// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -// { -// if (MZ_FCLOSE(pState->m_pFile) == EOF) -// { -// if (set_last_error) -// pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; -// status = MZ_FALSE; -// } -// } -// pState->m_pFile = NULL; -// } -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// } -// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; - -// return status; -// } - -// mz_bool mz_zip_reader_end(mz_zip_archive *pZip) -// { -// return mz_zip_reader_end_internal(pZip, MZ_TRUE); -// } -// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) -// { -// if ((!pZip) || (!pZip->m_pRead)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (!mz_zip_reader_init_internal(pZip, flags)) -// return MZ_FALSE; - -// pZip->m_zip_type = MZ_ZIP_TYPE_USER; -// pZip->m_archive_size = size; - -// if (!mz_zip_reader_read_central_dir(pZip, flags)) -// { -// mz_zip_reader_end_internal(pZip, MZ_FALSE); -// return MZ_FALSE; -// } - -// return MZ_TRUE; -// } - -// static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -// { -// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -// size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); -// memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); -// return s; -// } - -// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) -// { -// if (!pMem) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - -// if (!mz_zip_reader_init_internal(pZip, flags)) -// return MZ_FALSE; - -// pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; -// pZip->m_archive_size = size; -// pZip->m_pRead = mz_zip_mem_read_func; -// pZip->m_pIO_opaque = pZip; -// pZip->m_pNeeds_keepalive = NULL; - -// #ifdef __cplusplus -// pZip->m_pState->m_pMem = const_cast(pMem); -// #else -// pZip->m_pState->m_pMem = (void *)pMem; -// #endif - -// pZip->m_pState->m_mem_size = size; - -// if (!mz_zip_reader_read_central_dir(pZip, flags)) -// { -// mz_zip_reader_end_internal(pZip, MZ_FALSE); -// return MZ_FALSE; -// } - -// return MZ_TRUE; -// } - -// #ifndef MINIZ_NO_STDIO -// static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -// { -// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - -// file_ofs += pZip->m_pState->m_file_archive_start_ofs; - -// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) -// return 0; - -// return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); -// } - -// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) -// { -// return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); -// } - -// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) -// { -// mz_uint64 file_size; -// MZ_FILE *pFile; - -// if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pFile = MZ_FOPEN(pFilename, "rb"); -// if (!pFile) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -// file_size = archive_size; -// if (!file_size) -// { -// if (MZ_FSEEK64(pFile, 0, SEEK_END)) -// { -// MZ_FCLOSE(pFile); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); -// } - -// file_size = MZ_FTELL64(pFile); -// } - -// /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ - -// if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -// { -// MZ_FCLOSE(pFile); -// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -// } - -// if (!mz_zip_reader_init_internal(pZip, flags)) -// { -// MZ_FCLOSE(pFile); -// return MZ_FALSE; -// } - -// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; -// pZip->m_pRead = mz_zip_file_read_func; -// pZip->m_pIO_opaque = pZip; -// pZip->m_pState->m_pFile = pFile; -// pZip->m_archive_size = file_size; -// pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; - -// if (!mz_zip_reader_read_central_dir(pZip, flags)) -// { -// mz_zip_reader_end_internal(pZip, MZ_FALSE); -// return MZ_FALSE; -// } - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) -// { -// mz_uint64 cur_file_ofs; - -// if ((!pZip) || (!pFile)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -// cur_file_ofs = MZ_FTELL64(pFile); - -// if (!archive_size) -// { -// if (MZ_FSEEK64(pFile, 0, SEEK_END)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); - -// archive_size = MZ_FTELL64(pFile) - cur_file_ofs; - -// if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); -// } - -// if (!mz_zip_reader_init_internal(pZip, flags)) -// return MZ_FALSE; - -// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; -// pZip->m_pRead = mz_zip_file_read_func; - -// pZip->m_pIO_opaque = pZip; -// pZip->m_pState->m_pFile = pFile; -// pZip->m_archive_size = archive_size; -// pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; - -// if (!mz_zip_reader_read_central_dir(pZip, flags)) -// { -// mz_zip_reader_end_internal(pZip, MZ_FALSE); -// return MZ_FALSE; -// } - -// return MZ_TRUE; -// } - -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) -// { -// if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) -// return NULL; -// return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); -// } - -// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) -// { -// mz_uint m_bit_flag; -// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -// if (!p) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// return MZ_FALSE; -// } - -// m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -// return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; -// } - -// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) -// { -// mz_uint bit_flag; -// mz_uint method; - -// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -// if (!p) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// return MZ_FALSE; -// } - -// method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); -// bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); - -// if ((method != 0) && (method != MZ_DEFLATED)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -// return MZ_FALSE; -// } - -// if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -// return MZ_FALSE; -// } - -// if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) -// { -// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); -// return MZ_FALSE; -// } - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) -// { -// mz_uint filename_len, attribute_mapping_id, external_attr; -// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -// if (!p) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// return MZ_FALSE; -// } - -// filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// if (filename_len) -// { -// if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') -// return MZ_TRUE; -// } - - /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */ - /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */ - /* FIXME: Remove this check? Is it necessary - we already check the filename. */ -// attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; -// (void)attribute_mapping_id; - -// external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); -// if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) -// { -// return MZ_TRUE; -// } - -// return MZ_FALSE; -// } - -// static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) -// { -// mz_uint n; -// const mz_uint8 *p = pCentral_dir_header; - -// if (pFound_zip64_extra_data) -// *pFound_zip64_extra_data = MZ_FALSE; - -// if ((!p) || (!pStat)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// /* Extract fields from the central directory record. */ -// pStat->m_file_index = file_index; -// pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); -// pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); -// pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); -// pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); -// pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); -// #ifndef MINIZ_NO_TIME -// pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); -// #endif -// pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); -// pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -// pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); -// pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); -// pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); -// pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); - -// /* Copy as much of the filename and comment as possible. */ -// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); -// memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); -// pStat->m_filename[n] = '\0'; - -// n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); -// n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); -// pStat->m_comment_size = n; -// memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); -// pStat->m_comment[n] = '\0'; - -// /* Set some flags for convienance */ -// pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); -// pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); -// pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); - -// /* See if we need to read any zip64 extended information fields. */ -// /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ -// if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) -// { -// /* Attempt to find zip64 extended information field in the entry's extra data */ -// mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); - -// if (extra_size_remaining) -// { -// const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - -// do -// { -// mz_uint32 field_id; -// mz_uint32 field_data_size; - -// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// field_id = MZ_READ_LE16(pExtra_data); -// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); - -// if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -// { -// const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; -// mz_uint32 field_data_remaining = field_data_size; - -// if (pFound_zip64_extra_data) -// *pFound_zip64_extra_data = MZ_TRUE; - -// if (pStat->m_uncomp_size == MZ_UINT32_MAX) -// { -// if (field_data_remaining < sizeof(mz_uint64)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// pStat->m_uncomp_size = MZ_READ_LE64(pField_data); -// pField_data += sizeof(mz_uint64); -// field_data_remaining -= sizeof(mz_uint64); -// } - -// if (pStat->m_comp_size == MZ_UINT32_MAX) -// { -// if (field_data_remaining < sizeof(mz_uint64)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// pStat->m_comp_size = MZ_READ_LE64(pField_data); -// pField_data += sizeof(mz_uint64); -// field_data_remaining -= sizeof(mz_uint64); -// } - -// if (pStat->m_local_header_ofs == MZ_UINT32_MAX) -// { -// if (field_data_remaining < sizeof(mz_uint64)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); -// pField_data += sizeof(mz_uint64); -// // field_data_remaining -= sizeof(mz_uint64); -// } - -// break; -// } - -// pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; -// extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; -// } while (extra_size_remaining); -// } -// } - -// return MZ_TRUE; -// } - -// static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) -// { -// mz_uint i; -// if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) -// return 0 == memcmp(pA, pB, len); -// for (i = 0; i < len; ++i) -// if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) -// return MZ_FALSE; -// return MZ_TRUE; -// } - -// static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) -// { -// const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; -// mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// mz_uint8 l = 0, r = 0; -// pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -// pE = pL + MZ_MIN(l_len, r_len); -// while (pL < pE) -// { -// if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) -// break; -// pL++; -// pR++; -// } -// return (pL == pE) ? (int)(l_len - r_len) : (l - r); -// } - -// static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) -// { -// mz_zip_internal_state *pState = pZip->m_pState; -// const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; -// const mz_zip_array *pCentral_dir = &pState->m_central_dir; -// mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); -// const uint32_t size = pZip->m_total_files; -// const mz_uint filename_len = (mz_uint)strlen(pFilename); - -// if (pIndex) -// *pIndex = 0; - -// if (size) -// { -// /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ -// /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ -// mz_int64 l = 0, h = (mz_int64)size - 1; - -// while (l <= h) -// { -// mz_int64 m = l + ((h - l) >> 1); -// uint32_t file_index = pIndices[(uint32_t)m]; - -// int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); -// if (!comp) -// { -// if (pIndex) -// *pIndex = file_index; -// return MZ_TRUE; -// } -// else if (comp < 0) -// l = m + 1; -// else -// h = m - 1; -// } -// } - -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); -// } - -// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) -// { -// mz_uint32 index_; -// if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index_)) -// return -1; -// else -// return (int)index_; -// } - -// mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) -// { -// mz_uint file_index; -// size_t name_len, comment_len; - -// if (pIndex) -// *pIndex = 0; - -// if ((!pZip) || (!pZip->m_pState) || (!pName)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// /* See if we can use a binary search */ -// if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && -// (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && -// ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) -// { -// return mz_zip_locate_file_binary_search(pZip, pName, pIndex); -// } - -// /* Locate the entry by scanning the entire central directory */ -// name_len = strlen(pName); -// if (name_len > MZ_UINT16_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// comment_len = pComment ? strlen(pComment) : 0; -// if (comment_len > MZ_UINT16_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// for (file_index = 0; file_index < pZip->m_total_files; file_index++) -// { -// const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); -// mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; -// if (filename_len < name_len) -// continue; -// if (comment_len) -// { -// mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); -// const char *pFile_comment = pFilename + filename_len + file_extra_len; -// if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) -// continue; -// } -// if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) -// { -// int ofs = filename_len - 1; -// do -// { -// if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) -// break; -// } while (--ofs >= 0); -// ofs++; -// pFilename += ofs; -// filename_len -= ofs; -// } -// if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) -// { -// if (pIndex) -// *pIndex = file_index; -// return MZ_TRUE; -// } -// } - -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); -// } - -// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -// { -// int status = TINFL_STATUS_DONE; -// mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; -// mz_zip_archive_file_stat file_stat; -// void *pRead_buf; -// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -// tinfl_decompressor inflator; - -// if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -// return MZ_FALSE; - -// /* A directory or zero length file */ -// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) -// return MZ_TRUE; - -// /* Encryption and patch files are not supported. */ -// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - -// /* This function only supports decompressing stored and deflate. */ -// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); - -// /* Ensure supplied output buffer is large enough. */ -// needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; -// if (buf_size < needed_size) -// return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); - -// /* Read and parse the local directory entry. */ -// cur_file_ofs = file_stat.m_local_header_ofs; -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) -// { -// /* The file is stored or the caller has requested the compressed data. */ -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) -// { -// if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) -// return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); -// } -// #endif - -// return MZ_TRUE; -// } - -// /* Decompress the file either directly from memory or from a file input buffer. */ -// tinfl_init(&inflator); - -// if (pZip->m_pState->m_pMem) -// { -// /* Read directly from the archive in memory. */ -// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; -// read_buf_size = read_buf_avail = file_stat.m_comp_size; -// comp_remaining = 0; -// } -// else if (pUser_read_buf) -// { -// /* Use a user provided read buffer. */ -// if (!user_read_buf_size) -// return MZ_FALSE; -// pRead_buf = (mz_uint8 *)pUser_read_buf; -// read_buf_size = user_read_buf_size; -// read_buf_avail = 0; -// comp_remaining = file_stat.m_comp_size; -// } -// else -// { -// /* Temporarily allocate a read buffer. */ -// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -// if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// read_buf_avail = 0; -// comp_remaining = file_stat.m_comp_size; -// } - -// do -// { -// /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ -// size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); -// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) -// { -// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -// { -// status = TINFL_STATUS_FAILED; -// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -// break; -// } -// cur_file_ofs += read_buf_avail; -// comp_remaining -= read_buf_avail; -// read_buf_ofs = 0; -// } -// in_buf_size = (size_t)read_buf_avail; -// status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); -// read_buf_avail -= in_buf_size; -// read_buf_ofs += in_buf_size; -// out_buf_ofs += out_buf_size; -// } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); - -// if (status == TINFL_STATUS_DONE) -// { -// /* Make sure the entire file was decompressed, and check its CRC. */ -// if (out_buf_ofs != file_stat.m_uncomp_size) -// { -// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -// status = TINFL_STATUS_FAILED; -// } -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) -// { -// mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); -// status = TINFL_STATUS_FAILED; -// } -// #endif -// } - -// if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) -// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - -// return status == TINFL_STATUS_DONE; -// } - -// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -// { -// mz_uint32 file_index; -// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -// return MZ_FALSE; -// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); -// } - -// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) -// { -// return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); -// } - -// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) -// { -// return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); -// } - -// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) -// { -// mz_uint64 comp_size, uncomp_size, alloc_size; -// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -// void *pBuf; - -// if (pSize) -// *pSize = 0; - -// if (!p) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// return NULL; -// } - -// comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); -// uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - -// alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; -// if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -// return NULL; -// } - -// if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) -// { -// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// return NULL; -// } - -// if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -// return NULL; -// } - -// if (pSize) -// *pSize = (size_t)alloc_size; -// return pBuf; -// } - -// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) -// { -// mz_uint32 file_index; -// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -// { -// if (pSize) -// *pSize = 0; -// return MZ_FALSE; -// } -// return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); -// } - -// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -// { -// int status = TINFL_STATUS_DONE; -// mz_uint file_crc32 = MZ_CRC32_INIT; -// mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; -// mz_zip_archive_file_stat file_stat; -// void *pRead_buf = NULL; -// void *pWrite_buf = NULL; -// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - -// if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -// return MZ_FALSE; - -// /* A directory or zero length file */ -// if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) -// return MZ_TRUE; - -// /* Encryption and patch files are not supported. */ -// if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - -// /* This function only supports decompressing stored and deflate. */ -// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); - -// /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ -// cur_file_ofs = file_stat.m_local_header_ofs; -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -// if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// /* Decompress the file either directly from memory or from a file input buffer. */ -// if (pZip->m_pState->m_pMem) -// { -// pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; -// read_buf_size = read_buf_avail = file_stat.m_comp_size; -// comp_remaining = 0; -// } -// else -// { -// read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -// if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// read_buf_avail = 0; -// comp_remaining = file_stat.m_comp_size; -// } - -// if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) -// { -// /* The file is stored or the caller has requested the compressed data. */ -// if (pZip->m_pState->m_pMem) -// { -// if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) -// { -// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -// status = TINFL_STATUS_FAILED; -// } -// else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -// { -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); -// #endif -// } - -// cur_file_ofs += file_stat.m_comp_size; -// out_buf_ofs += file_stat.m_comp_size; -// comp_remaining = 0; -// } -// else -// { -// while (comp_remaining) -// { -// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// status = TINFL_STATUS_FAILED; -// break; -// } - -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -// { -// file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); -// } -// #endif - -// if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -// { -// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -// status = TINFL_STATUS_FAILED; -// break; -// } - -// cur_file_ofs += read_buf_avail; -// out_buf_ofs += read_buf_avail; -// comp_remaining -= read_buf_avail; -// } -// } -// } -// else -// { -// tinfl_decompressor inflator; -// tinfl_init(&inflator); - -// if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) -// { -// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// status = TINFL_STATUS_FAILED; -// } -// else -// { -// do -// { -// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); -// if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) -// { -// read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); -// if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// status = TINFL_STATUS_FAILED; -// break; -// } -// cur_file_ofs += read_buf_avail; -// comp_remaining -= read_buf_avail; -// read_buf_ofs = 0; -// } - -// in_buf_size = (size_t)read_buf_avail; -// status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); -// read_buf_avail -= in_buf_size; -// read_buf_ofs += in_buf_size; - -// if (out_buf_size) -// { -// if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) -// { -// mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); -// status = TINFL_STATUS_FAILED; -// break; -// } - -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); -// #endif -// if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) -// { -// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -// status = TINFL_STATUS_FAILED; -// break; -// } -// } -// } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); -// } -// } - -// if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -// { -// /* Make sure the entire file was decompressed, and check its CRC. */ -// if (out_buf_ofs != file_stat.m_uncomp_size) -// { -// mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -// status = TINFL_STATUS_FAILED; -// } -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// else if (file_crc32 != file_stat.m_crc32) -// { -// mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); -// status = TINFL_STATUS_FAILED; -// } -// #endif -// } - -// if (!pZip->m_pState->m_pMem) -// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - -// if (pWrite_buf) -// pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); - -// return status == TINFL_STATUS_DONE; -// } - -// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -// { -// mz_uint32 file_index; -// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -// return MZ_FALSE; - -// return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); -// } - -// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) -// { -// mz_zip_reader_extract_iter_state *pState; -// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - -// /* Argument sanity check */ -// if ((!pZip) || (!pZip->m_pState)) -// return NULL; - -// /* Allocate an iterator status structure */ -// pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); -// if (!pState) -// { -// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// return NULL; -// } - -// /* Fetch file details */ -// if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } - -// /* Encryption and patch files are not supported. */ -// if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } - -// /* This function only supports decompressing stored and deflate. */ -// if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } - -// /* Init state - save args */ -// pState->pZip = pZip; -// pState->flags = flags; - -// /* Init state - reset variables to defaults */ -// pState->status = TINFL_STATUS_DONE; -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// pState->file_crc32 = MZ_CRC32_INIT; -// #endif -// pState->read_buf_ofs = 0; -// pState->out_buf_ofs = 0; -// pState->pRead_buf = NULL; -// pState->pWrite_buf = NULL; -// pState->out_blk_remain = 0; - -// /* Read and parse the local directory entry. */ -// pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; -// if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } - -// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } - -// pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -// if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } - -// /* Decompress the file either directly from memory or from a file input buffer. */ -// if (pZip->m_pState->m_pMem) -// { -// pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; -// pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; -// pState->comp_remaining = pState->file_stat.m_comp_size; -// } -// else -// { -// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) -// { -// /* Decompression required, therefore intermediate read buffer required */ -// pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); -// if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) -// { -// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } -// } -// else -// { -// /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ -// pState->read_buf_size = 0; -// } -// pState->read_buf_avail = 0; -// pState->comp_remaining = pState->file_stat.m_comp_size; -// } - -// if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) -// { -// /* Decompression required, init decompressor */ -// tinfl_init( &pState->inflator ); - -// /* Allocate write buffer */ -// if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) -// { -// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// if (pState->pRead_buf) -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// return NULL; -// } -// } - -// return pState; -// } - -// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) -// { -// mz_uint32 file_index; - -// /* Locate file index by name */ -// if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) -// return NULL; - -// /* Construct iterator */ -// return mz_zip_reader_extract_iter_new(pZip, file_index, flags); -// } - -// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) -// { -// size_t copied_to_caller = 0; - -// /* Argument sanity check */ -// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) -// return 0; - -// if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) -// { -// /* The file is stored or the caller has requested the compressed data, calc amount to return. */ -// copied_to_caller = MZ_MIN( buf_size, pState->comp_remaining ); - -// /* Zip is in memory....or requires reading from a file? */ -// if (pState->pZip->m_pState->m_pMem) -// { -// /* Copy data to caller's buffer */ -// memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); -// pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; -// } -// else -// { -// /* Read directly into caller's buffer */ -// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) -// { -// /* Failed to read all that was asked for, flag failure and alert user */ -// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); -// pState->status = TINFL_STATUS_FAILED; -// copied_to_caller = 0; -// } -// } - -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// /* Compute CRC if not returning compressed data only */ -// if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); -// #endif - -// /* Advance offsets, dec counters */ -// pState->cur_file_ofs += copied_to_caller; -// pState->out_buf_ofs += copied_to_caller; -// pState->comp_remaining -= copied_to_caller; -// } -// else -// { -// do -// { -// /* Calc ptr to write buffer - given current output pos and block size */ -// mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - -// /* Calc max output size - given current output pos and block size */ -// size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - -// if (!pState->out_blk_remain) -// { -// /* Read more data from file if none available (and reading from file) */ -// if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) -// { -// /* Calc read size */ -// pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); -// if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) -// { -// mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); -// pState->status = TINFL_STATUS_FAILED; -// break; -// } - -// /* Advance offsets, dec counters */ -// pState->cur_file_ofs += pState->read_buf_avail; -// pState->comp_remaining -= pState->read_buf_avail; -// pState->read_buf_ofs = 0; -// } - -// /* Perform decompression */ -// in_buf_size = (size_t)pState->read_buf_avail; -// pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); -// pState->read_buf_avail -= in_buf_size; -// pState->read_buf_ofs += in_buf_size; - -// /* Update current output block size remaining */ -// pState->out_blk_remain = out_buf_size; -// } - -// if (pState->out_blk_remain) -// { -// /* Calc amount to return. */ -// size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); - -// /* Copy data to caller's buffer */ -// memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); - -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// /* Perform CRC */ -// pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); -// #endif - -// /* Decrement data consumed from block */ -// pState->out_blk_remain -= to_copy; - -// /* Inc output offset, while performing sanity check */ -// if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) -// { -// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); -// pState->status = TINFL_STATUS_FAILED; -// break; -// } - -// /* Increment counter of data copied to caller */ -// copied_to_caller += to_copy; -// } -// } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); -// } - -// /* Return how many bytes were copied into user buffer */ -// return copied_to_caller; -// } - -// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) -// { -// int status; - -// /* Argument sanity check */ -// if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) -// return MZ_FALSE; - -// /* Was decompression completed and requested? */ -// if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -// { -// /* Make sure the entire file was decompressed, and check its CRC. */ -// if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) -// { -// mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); -// pState->status = TINFL_STATUS_FAILED; -// } -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// else if (pState->file_crc32 != pState->file_stat.m_crc32) -// { -// mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); -// pState->status = TINFL_STATUS_FAILED; -// } -// #endif -// } - -// /* Free buffers */ -// if (!pState->pZip->m_pState->m_pMem) -// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); -// if (pState->pWrite_buf) -// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); - -// /* Save status */ -// status = pState->status; - -// /* Free context */ -// pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); - -// return status == TINFL_STATUS_DONE; -// } - -// #ifndef MINIZ_NO_STDIO -// static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) -// { -// (void)ofs; - -// return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); -// } - -// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) -// { -// mz_bool status; -// mz_zip_archive_file_stat file_stat; -// MZ_FILE *pFile; - -// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -// return MZ_FALSE; - -// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); - -// pFile = MZ_FOPEN(pDst_filename, "wb"); -// if (!pFile) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -// status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); - -// if (MZ_FCLOSE(pFile) == EOF) -// { -// if (status) -// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); - -// status = MZ_FALSE; -// } - -// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) -// if (status) -// mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); -// #endif - -// return status; -// } - -// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) -// { -// mz_uint32 file_index; -// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) -// return MZ_FALSE; - -// return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); -// } - -// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) -// { -// mz_zip_archive_file_stat file_stat; - -// if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) -// return MZ_FALSE; - -// if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); - -// return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); -// } - -// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) -// { -// mz_uint32 file_index; -// if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) -// return MZ_FALSE; - -// return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); -// } -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -// { -// mz_uint32 *p = (mz_uint32 *)pOpaque; -// (void)file_ofs; -// *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n); -// return n; -// } - -// mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) -// { -// mz_zip_archive_file_stat file_stat; -// mz_zip_internal_state *pState; -// const mz_uint8 *pCentral_dir_header; -// mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE; -// mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; -// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -// mz_uint64 local_header_ofs = 0; -// mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32; -// mz_uint64 local_header_comp_size, local_header_uncomp_size; -// mz_uint32 uncomp_crc32 = MZ_CRC32_INIT; -// mz_bool has_data_descriptor; -// mz_uint32 local_header_bit_flags; - -// mz_zip_array file_data_array; -// mz_zip_array_init(&file_data_array, 1); - -// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (file_index > pZip->m_total_files) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pState = pZip->m_pState; - -// pCentral_dir_header = mz_zip_get_cdh(pZip, file_index); - -// if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir)) -// return MZ_FALSE; - -// /* A directory or zero length file */ -// if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size)) -// return MZ_TRUE; - -// /* Encryption and patch files are not supported. */ -// if (file_stat.m_is_encrypted) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); - -// /* This function only supports stored and deflate. */ -// if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); - -// if (!file_stat.m_is_supported) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); - -// /* Read and parse the local directory entry. */ -// local_header_ofs = file_stat.m_local_header_ofs; -// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); -// local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -// local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); -// local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); -// local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS); -// local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); -// has_data_descriptor = (local_header_bit_flags & 8) != 0; - -// if (local_header_filename_len != strlen(file_stat.m_filename)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size) > pZip->m_archive_size) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if (!mz_zip_array_resize(pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE)) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// if (local_header_filename_len) -// { -// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE, file_data_array.m_p, local_header_filename_len) != local_header_filename_len) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// goto handle_failure; -// } - -// /* I've seen 1 archive that had the same pathname, but used backslashes in the local dir and forward slashes in the central dir. Do we care about this? For now, this case will fail validation. */ -// if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0) -// { -// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); -// goto handle_failure; -// } -// } - -// if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) -// { -// mz_uint32 extra_size_remaining = local_header_extra_len; -// const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p; - -// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// goto handle_failure; -// } - -// do -// { -// mz_uint32 field_id, field_data_size, field_total_size; - -// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// field_id = MZ_READ_LE16(pExtra_data); -// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); -// field_total_size = field_data_size + sizeof(mz_uint16) * 2; - -// if (field_total_size > extra_size_remaining) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -// { -// const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); - -// if (field_data_size < sizeof(mz_uint64) * 2) -// { -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// goto handle_failure; -// } - -// local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); -// local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); - -// found_zip64_ext_data_in_ldir = MZ_TRUE; -// break; -// } - -// pExtra_data += field_total_size; -// extra_size_remaining -= field_total_size; -// } while (extra_size_remaining); -// } - -// /* TODO: parse local header extra data when local_header_comp_size is 0xFFFFFFFF! (big_descriptor.zip) */ -// /* I've seen zips in the wild with the data descriptor bit set, but proper local header values and bogus data descriptors */ -// if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32)) -// { -// mz_uint8 descriptor_buf[32]; -// mz_bool has_id; -// const mz_uint8 *pSrc; -// mz_uint32 file_crc32; -// mz_uint64 comp_size = 0, uncomp_size = 0; - -// mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4; - -// if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size, descriptor_buf, sizeof(mz_uint32) * num_descriptor_uint32s) != (sizeof(mz_uint32) * num_descriptor_uint32s)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// goto handle_failure; -// } - -// has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID); -// pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf; - -// file_crc32 = MZ_READ_LE32(pSrc); - -// if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) -// { -// comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32)); -// uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64)); -// } -// else -// { -// comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32)); -// uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32)); -// } - -// if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); -// goto handle_failure; -// } -// } -// else -// { -// if ((local_header_crc32 != file_stat.m_crc32) || (local_header_comp_size != file_stat.m_comp_size) || (local_header_uncomp_size != file_stat.m_uncomp_size)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); -// goto handle_failure; -// } -// } - -// mz_zip_array_clear(pZip, &file_data_array); - -// if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0) -// { -// if (!mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0)) -// return MZ_FALSE; - -// /* 1 more check to be sure, although the extract checks too. */ -// if (uncomp_crc32 != file_stat.m_crc32) -// { -// mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); -// return MZ_FALSE; -// } -// } - -// return MZ_TRUE; - -// handle_failure: -// mz_zip_array_clear(pZip, &file_data_array); -// return MZ_FALSE; -// } - -// mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) -// { -// mz_zip_internal_state *pState; -// uint32_t i; - -// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pState = pZip->m_pState; - -// /* Basic sanity checks */ -// if (!pState->m_zip64) -// { -// if (pZip->m_total_files > MZ_UINT16_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -// if (pZip->m_archive_size > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -// } -// else -// { -// if (pZip->m_total_files >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -// if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -// } - -// for (i = 0; i < pZip->m_total_files; i++) -// { -// if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) -// { -// mz_uint32 found_index; -// mz_zip_archive_file_stat stat_; - -// if (!mz_zip_reader_file_stat(pZip, i, &stat_)) -// return MZ_FALSE; - -// if (!mz_zip_reader_locate_file_v2(pZip, stat_.m_filename, NULL, 0, &found_index)) -// return MZ_FALSE; - -// /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ -// if (found_index != i) -// return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); -// } - -// if (!mz_zip_validate_file(pZip, i, flags)) -// return MZ_FALSE; -// } - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr) -// { -// mz_bool success = MZ_TRUE; -// mz_zip_archive zip; -// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; - -// if ((!pMem) || (!size)) -// { -// if (pErr) -// *pErr = MZ_ZIP_INVALID_PARAMETER; -// return MZ_FALSE; -// } - -// mz_zip_zero_struct(&zip); - -// if (!mz_zip_reader_init_mem(&zip, pMem, size, flags)) -// { -// if (pErr) -// *pErr = zip.m_last_error; -// return MZ_FALSE; -// } - -// if (!mz_zip_validate_archive(&zip, flags)) -// { -// actual_err = zip.m_last_error; -// success = MZ_FALSE; -// } - -// if (!mz_zip_reader_end_internal(&zip, success)) -// { -// if (!actual_err) -// actual_err = zip.m_last_error; -// success = MZ_FALSE; -// } - -// if (pErr) -// *pErr = actual_err; - -// return success; -// } - -// #ifndef MINIZ_NO_STDIO -// mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr) -// { -// mz_bool success = MZ_TRUE; -// mz_zip_archive zip; -// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; - -// if (!pFilename) -// { -// if (pErr) -// *pErr = MZ_ZIP_INVALID_PARAMETER; -// return MZ_FALSE; -// } - -// mz_zip_zero_struct(&zip); - -// if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0)) -// { -// if (pErr) -// *pErr = zip.m_last_error; -// return MZ_FALSE; -// } - -// if (!mz_zip_validate_archive(&zip, flags)) -// { -// actual_err = zip.m_last_error; -// success = MZ_FALSE; -// } - -// if (!mz_zip_reader_end_internal(&zip, success)) -// { -// if (!actual_err) -// actual_err = zip.m_last_error; -// success = MZ_FALSE; -// } - -// if (pErr) -// *pErr = actual_err; - -// return success; -// } -// #endif /* #ifndef MINIZ_NO_STDIO */ - -/* ------------------- .ZIP archive writing */ - -// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - -// static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) -// { -// p[0] = (mz_uint8)v; -// p[1] = (mz_uint8)(v >> 8); -// } -// static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) -// { -// p[0] = (mz_uint8)v; -// p[1] = (mz_uint8)(v >> 8); -// p[2] = (mz_uint8)(v >> 16); -// p[3] = (mz_uint8)(v >> 24); -// } -// static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) -// { -// mz_write_le32(p, (mz_uint32)v); -// mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); -// } - -// #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) -// #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) -// #define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) - -// static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -// { -// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -// mz_zip_internal_state *pState = pZip->m_pState; -// mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); - -// if (!n) -// return 0; - -// /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ -// if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -// return 0; -// } - -// if (new_size > pState->m_mem_capacity) -// { -// void *pNew_block; -// size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); - -// while (new_capacity < new_size) -// new_capacity *= 2; - -// if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) -// { -// mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// return 0; -// } - -// pState->m_pMem = pNew_block; -// pState->m_mem_capacity = new_capacity; -// } -// memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); -// pState->m_mem_size = (size_t)new_size; -// return n; -// } - -// static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) -// { -// mz_zip_internal_state *pState; -// mz_bool status = MZ_TRUE; - -// if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) -// { -// if (set_last_error) -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// return MZ_FALSE; -// } - -// pState = pZip->m_pState; -// pZip->m_pState = NULL; -// mz_zip_array_clear(pZip, &pState->m_central_dir); -// mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); -// mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); - -// #ifndef MINIZ_NO_STDIO -// if (pState->m_pFile) -// { -// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -// { -// if (MZ_FCLOSE(pState->m_pFile) == EOF) -// { -// if (set_last_error) -// mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); -// status = MZ_FALSE; -// } -// } - -// pState->m_pFile = NULL; -// } -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); -// pState->m_pMem = NULL; -// } - -// pZip->m_pFree(pZip->m_pAlloc_opaque, pState); -// pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; -// return status; -// } - -// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) -// { -// mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; - -// if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -// { -// if (!pZip->m_pRead) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// } - -// if (pZip->m_file_offset_alignment) -// { -// /* Ensure user specified file offset alignment is a power of 2. */ -// if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// } - -// if (!pZip->m_pAlloc) -// pZip->m_pAlloc = miniz_def_alloc_func; -// if (!pZip->m_pFree) -// pZip->m_pFree = miniz_def_free_func; -// if (!pZip->m_pRealloc) -// pZip->m_pRealloc = miniz_def_realloc_func; - -// pZip->m_archive_size = existing_size; -// pZip->m_central_directory_file_ofs = 0; -// pZip->m_total_files = 0; - -// if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); - -// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); -// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); -// MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); - -// pZip->m_pState->m_zip64 = zip64; -// pZip->m_pState->m_zip64_has_extended_info_fields = zip64; - -// pZip->m_zip_type = MZ_ZIP_TYPE_USER; -// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) -// { -// return mz_zip_writer_init_v2(pZip, existing_size, 0); -// } - -// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) -// { -// pZip->m_pWrite = mz_zip_heap_write_func; -// pZip->m_pNeeds_keepalive = NULL; - -// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -// pZip->m_pRead = mz_zip_mem_read_func; - -// pZip->m_pIO_opaque = pZip; - -// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) -// return MZ_FALSE; - -// pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; - -// if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) -// { -// if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) -// { -// mz_zip_writer_end_internal(pZip, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } -// pZip->m_pState->m_mem_capacity = initial_allocation_size; -// } - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) -// { -// return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); -// } - -// #ifndef MINIZ_NO_STDIO -// static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -// { -// mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; -// mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - -// file_ofs += pZip->m_pState->m_file_archive_start_ofs; - -// if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); -// return 0; -// } - -// return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); -// } - -// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) -// { -// return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); -// } - -// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) -// { -// MZ_FILE *pFile; - -// pZip->m_pWrite = mz_zip_file_write_func; -// pZip->m_pNeeds_keepalive = NULL; - -// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -// pZip->m_pRead = mz_zip_file_read_func; - -// pZip->m_pIO_opaque = pZip; - -// if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) -// return MZ_FALSE; - -// if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) -// { -// mz_zip_writer_end(pZip); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -// } - -// pZip->m_pState->m_pFile = pFile; -// pZip->m_zip_type = MZ_ZIP_TYPE_FILE; - -// if (size_to_reserve_at_beginning) -// { -// mz_uint64 cur_ofs = 0; -// char buf[4096]; - -// MZ_CLEAR_OBJ(buf); - -// do -// { -// size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) -// { -// mz_zip_writer_end(pZip); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } -// cur_ofs += n; -// size_to_reserve_at_beginning -= n; -// } while (size_to_reserve_at_beginning); -// } - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) -// { -// pZip->m_pWrite = mz_zip_file_write_func; -// pZip->m_pNeeds_keepalive = NULL; - -// if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) -// pZip->m_pRead = mz_zip_file_read_func; - -// pZip->m_pIO_opaque = pZip; - -// if (!mz_zip_writer_init_v2(pZip, 0, flags)) -// return MZ_FALSE; - -// pZip->m_pState->m_pFile = pFile; -// pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); -// pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; - -// return MZ_TRUE; -// } -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) -// { -// mz_zip_internal_state *pState; - -// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) -// { -// /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ -// if (!pZip->m_pState->m_zip64) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// } - -// /* No sense in trying to write to an archive that's already at the support max size */ -// if (pZip->m_pState->m_zip64) -// { -// if (pZip->m_total_files == MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -// } -// else -// { -// if (pZip->m_total_files == MZ_UINT16_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - -// if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -// } - -// pState = pZip->m_pState; - -// if (pState->m_pFile) -// { -// #ifdef MINIZ_NO_STDIO -// (void)pFilename; -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// #else -// if (pZip->m_pIO_opaque != pZip) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) -// { -// if (!pFilename) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ -// if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) -// { -// /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ -// mz_zip_reader_end_internal(pZip, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); -// } -// } - -// pZip->m_pWrite = mz_zip_file_write_func; -// pZip->m_pNeeds_keepalive = NULL; -// #endif /* #ifdef MINIZ_NO_STDIO */ -// } -// else if (pState->m_pMem) -// { -// /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ -// if (pZip->m_pIO_opaque != pZip) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pState->m_mem_capacity = pState->m_mem_size; -// pZip->m_pWrite = mz_zip_heap_write_func; -// pZip->m_pNeeds_keepalive = NULL; -// } -// /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ -// else if (!pZip->m_pWrite) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// /* Start writing new files at the archive's current central directory location. */ -// /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ -// pZip->m_archive_size = pZip->m_central_directory_file_ofs; -// pZip->m_central_directory_file_ofs = 0; - -// /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ -// /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ -// /* TODO: We could easily maintain the sorted central directory offsets. */ -// mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); - -// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) -// { -// return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); -// } - -/* TODO: pArchive_name is a terrible name here! */ -// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) -// { -// return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); -// } - -// typedef struct -// { -// mz_zip_archive *m_pZip; -// mz_uint64 m_cur_archive_file_ofs; -// mz_uint64 m_comp_size; -// } mz_zip_writer_add_state; - -// static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) -// { -// mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; -// if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) -// return MZ_FALSE; - -// pState->m_cur_archive_file_ofs += len; -// pState->m_comp_size += len; -// return MZ_TRUE; -// } - -// #define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) -// #define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) -// static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) -// { -// mz_uint8 *pDst = pBuf; -// mz_uint32 field_size = 0; - -// MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); -// MZ_WRITE_LE16(pDst + 2, 0); -// pDst += sizeof(mz_uint16) * 2; - -// if (pUncomp_size) -// { -// MZ_WRITE_LE64(pDst, *pUncomp_size); -// pDst += sizeof(mz_uint64); -// field_size += sizeof(mz_uint64); -// } - -// if (pComp_size) -// { -// MZ_WRITE_LE64(pDst, *pComp_size); -// pDst += sizeof(mz_uint64); -// field_size += sizeof(mz_uint64); -// } - -// if (pLocal_header_ofs) -// { -// MZ_WRITE_LE64(pDst, *pLocal_header_ofs); -// pDst += sizeof(mz_uint64); -// field_size += sizeof(mz_uint64); -// } - -// MZ_WRITE_LE16(pBuf + 2, field_size); - -// return (mz_uint32)(pDst - pBuf); -// } - -// static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) -// { -// (void)pZip; -// memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); -// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); -// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); -// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); -// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); -// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); -// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); -// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); -// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); -// MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); -// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); -// MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); -// return MZ_TRUE; -// } - -// static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, -// mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, -// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, -// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, -// mz_uint64 local_header_ofs, mz_uint32 ext_attributes) -// { -// (void)pZip; -// memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); -// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); -// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); -// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); -// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); -// MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); -// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); -// MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); -// return MZ_TRUE; -// } - -// static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, -// const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, -// mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, -// mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, -// mz_uint64 local_header_ofs, mz_uint32 ext_attributes, -// const char *user_extra_data, mz_uint user_extra_data_len) -// { -// mz_zip_internal_state *pState = pZip->m_pState; -// mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; -// size_t orig_central_dir_size = pState->m_central_dir.m_size; -// mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; - -// if (!pZip->m_pState->m_zip64) -// { -// if (local_header_ofs > 0xFFFFFFFF) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); -// } - -// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -// if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size + user_extra_data_len, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -// if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || -// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || -// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || -// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || -// (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || -// (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) -// { -// /* Try to resize the central directory array back into its original state. */ -// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// return MZ_TRUE; -// } - -// static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) -// { -// /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ -// if (*pArchive_name == '/') -// return MZ_FALSE; - -// while (*pArchive_name) -// { -// if ((*pArchive_name == '\\') || (*pArchive_name == ':')) -// return MZ_FALSE; - -// pArchive_name++; -// } - -// return MZ_TRUE; -// } - -// static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) -// { -// mz_uint32 n; -// if (!pZip->m_file_offset_alignment) -// return 0; -// n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); -// return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); -// } - -// static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) -// { -// char buf[4096]; -// memset(buf, 0, MZ_MIN(sizeof(buf), n)); -// while (n) -// { -// mz_uint32 s = MZ_MIN(sizeof(buf), n); -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_file_ofs += s; -// n -= s; -// } -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) -// { -// return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); -// } - -// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, -// mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, -// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) -// { -// if(!pZip) -// { -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// } - -// mz_uint16 method = 0, dos_time = 0, dos_date = 0; -// mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; -// mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; -// size_t archive_name_size; -// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; -// tdefl_compressor *pComp = NULL; -// mz_bool store_data_uncompressed; -// mz_zip_internal_state *pState; -// mz_uint8 *pExtra_data = NULL; -// mz_uint32 extra_size = 0; -// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; -// mz_uint16 bit_flags = 0; - -// if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) -// bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; - -// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) -// bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; - -// if ((int)level_and_flags < 0) -// level_and_flags = MZ_DEFAULT_LEVEL; -// level = level_and_flags & 0xF; -// store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); - -// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pState = pZip->m_pState; - -// if (pState->m_zip64) -// { -// if (pZip->m_total_files == MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -// } -// else -// { -// if (pZip->m_total_files == MZ_UINT16_MAX) -// { -// pState->m_zip64 = MZ_TRUE; -// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ -// } -// if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) -// { -// pState->m_zip64 = MZ_TRUE; -// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -// } -// } - -// if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (!mz_zip_writer_validate_archive_name(pArchive_name)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - -// #ifndef MINIZ_NO_TIME -// if (last_modified != NULL) -// { -// mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); -// } -// else -// { -// MZ_TIME_T cur_time; -// time(&cur_time); -// mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); -// } -// #endif /* #ifndef MINIZ_NO_TIME */ - -// archive_name_size = strlen(pArchive_name); -// if (archive_name_size > MZ_UINT16_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - -// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - -// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -// if (!pState->m_zip64) -// { -// /* Bail early if the archive would obviously become too large */ -// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size -// + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + -// pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len -// + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) -// { -// pState->m_zip64 = MZ_TRUE; -// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -// } -// } - -// if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) -// { -// /* Set DOS Subdirectory attribute bit. */ -// ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; - -// /* Subdirectories cannot contain data. */ -// if ((buf_size) || (uncomp_size)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// } - -// /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ -// if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// if ((!store_data_uncompressed) && (buf_size)) -// { -// if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -// return MZ_FALSE; -// } - -// local_dir_header_ofs += num_alignment_padding_bytes; -// if (pZip->m_file_offset_alignment) -// { -// MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); -// } -// cur_archive_file_ofs += num_alignment_padding_bytes; - -// MZ_CLEAR_OBJ(local_dir_header); - -// if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -// { -// method = MZ_DEFLATED; -// } - -// if (pState->m_zip64) -// { -// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) -// { -// pExtra_data = extra_data; -// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -// } - -// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += sizeof(local_dir_header); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } -// cur_archive_file_ofs += archive_name_size; - -// if (pExtra_data != NULL) -// { -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += extra_size; -// } -// } -// else -// { -// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += sizeof(local_dir_header); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } -// cur_archive_file_ofs += archive_name_size; -// } - -// if (user_extra_data_len > 0) -// { -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += user_extra_data_len; -// } - -// if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) -// { -// uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); -// uncomp_size = buf_size; -// if (uncomp_size <= 3) -// { -// level = 0; -// store_data_uncompressed = MZ_TRUE; -// } -// } - -// if (store_data_uncompressed) -// { -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } - -// cur_archive_file_ofs += buf_size; -// comp_size = buf_size; -// } -// else if (buf_size) -// { -// mz_zip_writer_add_state state; - -// state.m_pZip = pZip; -// state.m_cur_archive_file_ofs = cur_archive_file_ofs; -// state.m_comp_size = 0; - -// if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || -// (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -// return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); -// } - -// comp_size = state.m_comp_size; -// cur_archive_file_ofs = state.m_cur_archive_file_ofs; -// } - -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -// pComp = NULL; - -// if (uncomp_size) -// { -// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; -// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; - -// MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); - -// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); -// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); -// if (pExtra_data == NULL) -// { -// if (comp_size > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); -// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); -// } -// else -// { -// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); -// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); -// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; -// } - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) -// return MZ_FALSE; - -// cur_archive_file_ofs += local_dir_footer_size; -// } - -// if (pExtra_data != NULL) -// { -// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -// } - -// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, -// comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, -// user_extra_data_central, user_extra_data_central_len)) -// return MZ_FALSE; - -// pZip->m_total_files++; -// pZip->m_archive_size = cur_archive_file_ofs; - -// return MZ_TRUE; -// } - -// #ifndef MINIZ_NO_STDIO -// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -// const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) -// { -// if(!pZip) -// { -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// } - -// mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; -// mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; -// mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; -// mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; -// size_t archive_name_size; -// mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; -// mz_uint8 *pExtra_data = NULL; -// mz_uint32 extra_size = 0; -// mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; -// mz_zip_internal_state *pState; - -// if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) -// gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; - -// if ((int)level_and_flags < 0) -// level_and_flags = MZ_DEFAULT_LEVEL; -// level = level_and_flags & 0xF; - -// /* Sanity checks */ -// if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pState = pZip->m_pState; - -// if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) -// { -// /* Source file is too large for non-zip64 */ -// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -// pState->m_zip64 = MZ_TRUE; -// } - -// /* We could support this, but why? */ -// if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (!mz_zip_writer_validate_archive_name(pArchive_name)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - -// if (pState->m_zip64) -// { -// if (pZip->m_total_files == MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -// } -// else -// { -// if (pZip->m_total_files == MZ_UINT16_MAX) -// { -// pState->m_zip64 = MZ_TRUE; -// /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ -// } -// } - -// archive_name_size = strlen(pArchive_name); -// if (archive_name_size > MZ_UINT16_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); - -// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - -// /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ -// if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -// if (!pState->m_zip64) -// { -// /* Bail early if the archive would obviously become too large */ -// if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE -// + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 -// + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) -// { -// pState->m_zip64 = MZ_TRUE; -// /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ -// } -// } - -// #ifndef MINIZ_NO_TIME -// if (pFile_time) -// { -// mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); -// } -// #endif - -// if (uncomp_size <= 3) -// level = 0; - -// if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) -// { -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } - -// cur_archive_file_ofs += num_alignment_padding_bytes; -// local_dir_header_ofs = cur_archive_file_ofs; - -// if (pZip->m_file_offset_alignment) -// { -// MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); -// } - -// if (uncomp_size && level) -// { -// method = MZ_DEFLATED; -// } - -// MZ_CLEAR_OBJ(local_dir_header); -// if (pState->m_zip64) -// { -// if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) -// { -// pExtra_data = extra_data; -// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -// } - -// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += sizeof(local_dir_header); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -// { -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } - -// cur_archive_file_ofs += archive_name_size; - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += extra_size; -// } -// else -// { -// if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -// if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += sizeof(local_dir_header); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) -// { -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } - -// cur_archive_file_ofs += archive_name_size; -// } - -// if (user_extra_data_len > 0) -// { -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_archive_file_ofs += user_extra_data_len; -// } - -// if (uncomp_size) -// { -// mz_uint64 uncomp_remaining = uncomp_size; -// void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); -// if (!pRead_buf) -// { -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if (!level) -// { -// while (uncomp_remaining) -// { -// mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); -// if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// } -// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); -// uncomp_remaining -= n; -// cur_archive_file_ofs += n; -// } -// comp_size = uncomp_size; -// } -// else -// { -// mz_bool result = MZ_FALSE; -// mz_zip_writer_add_state state; -// tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); -// if (!pComp) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// state.m_pZip = pZip; -// state.m_cur_archive_file_ofs = cur_archive_file_ofs; -// state.m_comp_size = 0; - -// if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); -// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -// return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); -// } - -// for (;;) -// { -// size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); -// tdefl_status status; -// tdefl_flush flush = TDEFL_NO_FLUSH; - -// if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) -// { -// mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// break; -// } - -// uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); -// uncomp_remaining -= in_buf_size; - -// if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) -// flush = TDEFL_FULL_FLUSH; - -// status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); -// if (status == TDEFL_STATUS_DONE) -// { -// result = MZ_TRUE; -// break; -// } -// else if (status != TDEFL_STATUS_OKAY) -// { -// mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); -// break; -// } -// } - -// pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - -// if (!result) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -// return MZ_FALSE; -// } - -// comp_size = state.m_comp_size; -// cur_archive_file_ofs = state.m_cur_archive_file_ofs; -// } - -// pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); -// } - -// { -// mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; -// mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; - -// MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); -// MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); -// if (pExtra_data == NULL) -// { -// if (comp_size > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -// MZ_WRITE_LE32(local_dir_footer + 8, comp_size); -// MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); -// } -// else -// { -// MZ_WRITE_LE64(local_dir_footer + 8, comp_size); -// MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); -// local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; -// } - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) -// return MZ_FALSE; - -// cur_archive_file_ofs += local_dir_footer_size; -// } - -// if (pExtra_data != NULL) -// { -// extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, -// (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); -// } - -// if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, -// uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, -// user_extra_data_central, user_extra_data_central_len)) -// return MZ_FALSE; - -// pZip->m_total_files++; -// pZip->m_archive_size = cur_archive_file_ofs; - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -// { -// MZ_FILE *pSrc_file = NULL; -// mz_uint64 uncomp_size = 0; -// MZ_TIME_T file_modified_time; -// MZ_TIME_T *pFile_time = NULL; -// mz_bool status; - -// memset(&file_modified_time, 0, sizeof(file_modified_time)); - -// #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) -// pFile_time = &file_modified_time; -// if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); -// #endif - -// pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); -// if (!pSrc_file) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - -// MZ_FSEEK64(pSrc_file, 0, SEEK_END); -// uncomp_size = MZ_FTELL64(pSrc_file); -// MZ_FSEEK64(pSrc_file, 0, SEEK_SET); - -// status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); - -// MZ_FCLOSE(pSrc_file); - -// return status; -// } -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) -// { -// /* + 64 should be enough for any new zip64 data */ -// if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE)) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE); - -// if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start)) -// { -// mz_uint8 new_ext_block[64]; -// mz_uint8 *pDst = new_ext_block; -// mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); -// mz_write_le16(pDst + sizeof(mz_uint16), 0); -// pDst += sizeof(mz_uint16) * 2; - -// if (pUncomp_size) -// { -// mz_write_le64(pDst, *pUncomp_size); -// pDst += sizeof(mz_uint64); -// } - -// if (pComp_size) -// { -// mz_write_le64(pDst, *pComp_size); -// pDst += sizeof(mz_uint64); -// } - -// if (pLocal_header_ofs) -// { -// mz_write_le64(pDst, *pLocal_header_ofs); -// pDst += sizeof(mz_uint64); -// } - -// if (pDisk_start) -// { -// mz_write_le32(pDst, *pDisk_start); -// pDst += sizeof(mz_uint32); -// } - -// mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2)); - -// if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block)) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if ((pExt) && (ext_len)) -// { -// mz_uint32 extra_size_remaining = ext_len; -// const mz_uint8 *pExtra_data = pExt; - -// do -// { -// mz_uint32 field_id, field_data_size, field_total_size; - -// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// field_id = MZ_READ_LE16(pExtra_data); -// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); -// field_total_size = field_data_size + sizeof(mz_uint16) * 2; - -// if (field_total_size > extra_size_remaining) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -// { -// if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size)) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// pExtra_data += field_total_size; -// extra_size_remaining -= field_total_size; -// } while (extra_size_remaining); -// } - -// return MZ_TRUE; -// } - -/* TODO: This func is now pretty freakin complex due to zip64, split it up? */ -// mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index) -// { -// mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size; -// mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs; -// mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; -// mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; -// mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; -// mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; -// size_t orig_central_dir_size; -// mz_zip_internal_state *pState; -// void *pBuf; -// const mz_uint8 *pSrc_central_header; -// mz_zip_archive_file_stat src_file_stat; -// mz_uint32 src_filename_len, src_comment_len, src_ext_len; -// mz_uint32 local_header_filename_size, local_header_extra_len; -// mz_uint64 local_header_comp_size, local_header_uncomp_size; -// mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; - -// /* Sanity checks */ -// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pState = pZip->m_pState; - -// /* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */ -// if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// /* Get pointer to the source central dir header and crack it */ -// if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index))) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); -// src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS); -// src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len; - -// /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32 fudge factor in case we need to add more extra data) */ -// if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); - -// num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - -// if (!pState->m_zip64) -// { -// if (pZip->m_total_files == MZ_UINT16_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -// } -// else -// { -// /* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */ -// if (pZip->m_total_files == MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -// } - -// if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL)) -// return MZ_FALSE; - -// cur_src_file_ofs = src_file_stat.m_local_header_ofs; -// cur_dst_file_ofs = pZip->m_archive_size; - -// /* Read the source archive's local dir header */ -// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); - -// if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - -// cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; - -// /* Compute the total size we need to copy (filename+extra data+compressed data) */ -// local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); -// local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); -// local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); -// local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); -// src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size; - -// /* Try to find a zip64 extended information field */ -// if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) -// { -// mz_zip_array file_data_array; -// const mz_uint8 *pExtra_data; -// mz_uint32 extra_size_remaining = local_header_extra_len; - -// mz_zip_array_init(&file_data_array, 1); -// if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE)) -// { -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, src_file_stat.m_local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_size, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) -// { -// mz_zip_array_clear(pZip, &file_data_array); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// } - -// pExtra_data = (const mz_uint8 *)file_data_array.m_p; - -// do -// { -// mz_uint32 field_id, field_data_size, field_total_size; - -// if (extra_size_remaining < (sizeof(mz_uint16) * 2)) -// { -// mz_zip_array_clear(pZip, &file_data_array); -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// } - -// field_id = MZ_READ_LE16(pExtra_data); -// field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); -// field_total_size = field_data_size + sizeof(mz_uint16) * 2; - -// if (field_total_size > extra_size_remaining) -// { -// mz_zip_array_clear(pZip, &file_data_array); -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// } - -// if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) -// { -// // const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); - -// if (field_data_size < sizeof(mz_uint64) * 2) -// { -// mz_zip_array_clear(pZip, &file_data_array); -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); -// } - -// // local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); -// // local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ - -// found_zip64_ext_data_in_ldir = MZ_TRUE; -// break; -// } - -// pExtra_data += field_total_size; -// extra_size_remaining -= field_total_size; -// } while (extra_size_remaining); - -// mz_zip_array_clear(pZip, &file_data_array); -// } - -// if (!pState->m_zip64) -// { -// /* Try to detect if the new archive will most likely wind up too big and bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which could be present, +64 is a fudge factor). */ -// /* We also check when the archive is finalized so this doesn't need to be perfect. */ -// mz_uint64 approx_new_archive_size = cur_dst_file_ofs + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining + (sizeof(mz_uint32) * 4) + -// pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64; - -// if (approx_new_archive_size >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); -// } - -// /* Write dest archive padding */ -// if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) -// return MZ_FALSE; - -// cur_dst_file_ofs += num_alignment_padding_bytes; - -// local_dir_header_ofs = cur_dst_file_ofs; -// if (pZip->m_file_offset_alignment) -// { -// MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); -// } - -// /* The original zip's local header+ext block doesn't change, even with zip64, so we can just copy it over to the dest zip */ -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; - -// /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */ -// if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining))))) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// while (src_archive_bytes_remaining) -// { -// n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining); -// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// } -// cur_src_file_ofs += n; - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } -// cur_dst_file_ofs += n; - -// src_archive_bytes_remaining -= n; -// } - -// /* Now deal with the optional data descriptor */ -// bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); -// if (bit_flags & 8) -// { -// /* Copy data descriptor */ -// if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir)) -// { -// /* src is zip64, dest must be zip64 */ - -// /* name uint32_t's */ -// /* id 1 (optional in zip64?) */ -// /* crc 1 */ -// /* comp_size 2 */ -// /* uncomp_size 2 */ -// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6)) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// } - -// n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5); -// } -// else -// { -// /* src is NOT zip64 */ -// mz_bool has_id; - -// if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); -// } - -// has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID); - -// if (pZip->m_pState->m_zip64) -// { -// /* dest is zip64, so upgrade the data descriptor */ -// const mz_uint32 *pSrc_descriptor = (const mz_uint32 *)((const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0)); -// const mz_uint32 src_crc32 = pSrc_descriptor[0]; -// const mz_uint64 src_comp_size = pSrc_descriptor[1]; -// const mz_uint64 src_uncomp_size = pSrc_descriptor[2]; - -// mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID); -// mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32); -// mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size); -// mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size); - -// n = sizeof(mz_uint32) * 6; -// } -// else -// { -// /* dest is NOT zip64, just copy it as-is */ -// n = sizeof(mz_uint32) * (has_id ? 4 : 3); -// } -// } - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) -// { -// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); -// } - -// // cur_src_file_ofs += n; -// cur_dst_file_ofs += n; -// } -// pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - -// /* Finally, add the new central dir header */ -// orig_central_dir_size = pState->m_central_dir.m_size; - -// memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); - -// if (pState->m_zip64) -// { -// /* This is the painful part: We need to write a new central dir header + ext block with updated zip64 fields, and ensure the old fields (if any) are not included. */ -// const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len; -// mz_zip_array new_ext_block; - -// mz_zip_array_init(&new_ext_block, sizeof(mz_uint8)); - -// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX); -// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX); -// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX); - -// if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL)) -// { -// mz_zip_array_clear(pZip, &new_ext_block); -// return MZ_FALSE; -// } - -// MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size); - -// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) -// { -// mz_zip_array_clear(pZip, &new_ext_block); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len)) -// { -// mz_zip_array_clear(pZip, &new_ext_block); -// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size)) -// { -// mz_zip_array_clear(pZip, &new_ext_block); -// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len + src_ext_len, src_comment_len)) -// { -// mz_zip_array_clear(pZip, &new_ext_block); -// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// mz_zip_array_clear(pZip, &new_ext_block); -// } -// else -// { -// /* sanity checks */ -// if (cur_dst_file_ofs > MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -// if (local_dir_header_ofs >= MZ_UINT32_MAX) -// return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); - -// MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); - -// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); - -// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_central_dir_following_data_size)) -// { -// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } -// } - -// /* This shouldn't trigger unless we screwed up during the initial sanity checks */ -// if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) -// { -// /* TODO: Support central dirs >= 32-bits in size */ -// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); -// } - -// n = (mz_uint32)orig_central_dir_size; -// if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) -// { -// mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); -// return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); -// } - -// pZip->m_total_files++; -// pZip->m_archive_size = cur_dst_file_ofs; - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) -// { -// mz_zip_internal_state *pState; -// mz_uint64 central_dir_ofs, central_dir_size; -// mz_uint8 hdr[256]; - -// if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// pState = pZip->m_pState; - -// if (pState->m_zip64) -// { -// if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -// } -// else -// { -// if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) -// return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); -// } - -// central_dir_ofs = 0; -// central_dir_size = 0; -// if (pZip->m_total_files) -// { -// /* Write central directory */ -// central_dir_ofs = pZip->m_archive_size; -// central_dir_size = pState->m_central_dir.m_size; -// pZip->m_central_directory_file_ofs = central_dir_ofs; -// if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// pZip->m_archive_size += central_dir_size; -// } - -// if (pState->m_zip64) -// { -// /* Write zip64 end of central directory header */ -// mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; - -// MZ_CLEAR_OBJ(hdr); -// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); -// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); -// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ -// MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); -// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); -// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); -// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); -// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); -// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; - -// /* Write zip64 end of central directory locator */ -// MZ_CLEAR_OBJ(hdr); -// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); -// MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); -// MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); -// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; -// } - -// /* Write end of central directory record */ -// MZ_CLEAR_OBJ(hdr); -// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); -// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); -// MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); -// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); -// MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); - -// if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); - -// #ifndef MINIZ_NO_STDIO -// if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) -// return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; - -// pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) -// { -// if ((!ppBuf) || (!pSize)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// *ppBuf = NULL; -// *pSize = 0; - -// if ((!pZip) || (!pZip->m_pState)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (pZip->m_pWrite != mz_zip_heap_write_func) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// if (!mz_zip_writer_finalize_archive(pZip)) -// return MZ_FALSE; - -// *ppBuf = pZip->m_pState->m_pMem; -// *pSize = pZip->m_pState->m_mem_size; -// pZip->m_pState->m_pMem = NULL; -// pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; - -// return MZ_TRUE; -// } - -// mz_bool mz_zip_writer_end(mz_zip_archive *pZip) -// { -// return mz_zip_writer_end_internal(pZip, MZ_TRUE); -// } - -// #ifndef MINIZ_NO_STDIO -// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -// { -// return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); -// } - -// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) -// { -// mz_bool status, created_new_archive = MZ_FALSE; -// mz_zip_archive zip_archive; -// struct MZ_FILE_STAT_STRUCT file_stat; -// mz_zip_error actual_err = MZ_ZIP_NO_ERROR; - -// mz_zip_zero_struct(&zip_archive); -// if ((int)level_and_flags < 0) -// level_and_flags = MZ_DEFAULT_LEVEL; - -// if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) -// { -// if (pErr) -// *pErr = MZ_ZIP_INVALID_PARAMETER; -// return MZ_FALSE; -// } - -// if (!mz_zip_writer_validate_archive_name(pArchive_name)) -// { -// if (pErr) -// *pErr = MZ_ZIP_INVALID_FILENAME; -// return MZ_FALSE; -// } - -// /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ -// /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ -// if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) -// { -// /* Create a new archive. */ -// if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) -// { -// if (pErr) -// *pErr = zip_archive.m_last_error; -// return MZ_FALSE; -// } - -// created_new_archive = MZ_TRUE; -// } -// else -// { -// /* Append to an existing archive. */ -// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) -// { -// if (pErr) -// *pErr = zip_archive.m_last_error; -// return MZ_FALSE; -// } - -// if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) -// { -// if (pErr) -// *pErr = zip_archive.m_last_error; - -// mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); - -// return MZ_FALSE; -// } -// } - -// status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); -// actual_err = zip_archive.m_last_error; - -// /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ -// if (!mz_zip_writer_finalize_archive(&zip_archive)) -// { -// if (!actual_err) -// actual_err = zip_archive.m_last_error; - -// status = MZ_FALSE; -// } - -// if (!mz_zip_writer_end_internal(&zip_archive, status)) -// { -// if (!actual_err) -// actual_err = zip_archive.m_last_error; - -// status = MZ_FALSE; -// } - -// if ((!status) && (created_new_archive)) -// { -// /* It's a new archive and something went wrong, so just delete it. */ -// int ignoredStatus = MZ_DELETE_FILE(pZip_filename); -// (void)ignoredStatus; -// } - -// if (pErr) -// *pErr = actual_err; - -// return status; -// } - -// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) -// { -// mz_uint32 file_index; -// mz_zip_archive zip_archive; -// void *p = NULL; - -// if (pSize) -// *pSize = 0; - -// if ((!pZip_filename) || (!pArchive_name)) -// { -// if (pErr) -// *pErr = MZ_ZIP_INVALID_PARAMETER; - -// return NULL; -// } - -// mz_zip_zero_struct(&zip_archive); -// if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) -// { -// if (pErr) -// *pErr = zip_archive.m_last_error; - -// return NULL; -// } - -// if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) -// { -// p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); -// } - -// mz_zip_reader_end_internal(&zip_archive, p != NULL); - -// if (pErr) -// *pErr = zip_archive.m_last_error; - -// return p; -// } - -// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) -// { -// return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); -// } - -// #endif /* #ifndef MINIZ_NO_STDIO */ - -// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ - -/* ------------------- Misc utils */ - -// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) -// { -// return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; -// } - -// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) -// { -// return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; -// } - -// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) -// { -// mz_zip_error prev_err; - -// if (!pZip) -// return MZ_ZIP_INVALID_PARAMETER; - -// prev_err = pZip->m_last_error; - -// pZip->m_last_error = err_num; -// return prev_err; -// } - -// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) -// { -// if (!pZip) -// return MZ_ZIP_INVALID_PARAMETER; - -// return pZip->m_last_error; -// } - -// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) -// { -// return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); -// } - -// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) -// { -// mz_zip_error prev_err; - -// if (!pZip) -// return MZ_ZIP_INVALID_PARAMETER; - -// prev_err = pZip->m_last_error; - -// pZip->m_last_error = MZ_ZIP_NO_ERROR; -// return prev_err; -// } - -// const char *mz_zip_get_error_string(mz_zip_error mz_err) -// { -// switch (mz_err) -// { -// case MZ_ZIP_NO_ERROR: -// return "no error"; -// case MZ_ZIP_UNDEFINED_ERROR: -// return "undefined error"; -// case MZ_ZIP_TOO_MANY_FILES: -// return "too many files"; -// case MZ_ZIP_FILE_TOO_LARGE: -// return "file too large"; -// case MZ_ZIP_UNSUPPORTED_METHOD: -// return "unsupported method"; -// case MZ_ZIP_UNSUPPORTED_ENCRYPTION: -// return "unsupported encryption"; -// case MZ_ZIP_UNSUPPORTED_FEATURE: -// return "unsupported feature"; -// case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: -// return "failed finding central directory"; -// case MZ_ZIP_NOT_AN_ARCHIVE: -// return "not a ZIP archive"; -// case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: -// return "invalid header or archive is corrupted"; -// case MZ_ZIP_UNSUPPORTED_MULTIDISK: -// return "unsupported multidisk archive"; -// case MZ_ZIP_DECOMPRESSION_FAILED: -// return "decompression failed or archive is corrupted"; -// case MZ_ZIP_COMPRESSION_FAILED: -// return "compression failed"; -// case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: -// return "unexpected decompressed size"; -// case MZ_ZIP_CRC_CHECK_FAILED: -// return "CRC-32 check failed"; -// case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: -// return "unsupported central directory size"; -// case MZ_ZIP_ALLOC_FAILED: -// return "allocation failed"; -// case MZ_ZIP_FILE_OPEN_FAILED: -// return "file open failed"; -// case MZ_ZIP_FILE_CREATE_FAILED: -// return "file create failed"; -// case MZ_ZIP_FILE_WRITE_FAILED: -// return "file write failed"; -// case MZ_ZIP_FILE_READ_FAILED: -// return "file read failed"; -// case MZ_ZIP_FILE_CLOSE_FAILED: -// return "file close failed"; -// case MZ_ZIP_FILE_SEEK_FAILED: -// return "file seek failed"; -// case MZ_ZIP_FILE_STAT_FAILED: -// return "file stat failed"; -// case MZ_ZIP_INVALID_PARAMETER: -// return "invalid parameter"; -// case MZ_ZIP_INVALID_FILENAME: -// return "invalid filename"; -// case MZ_ZIP_BUF_TOO_SMALL: -// return "buffer too small"; -// case MZ_ZIP_INTERNAL_ERROR: -// return "internal error"; -// case MZ_ZIP_FILE_NOT_FOUND: -// return "file not found"; -// case MZ_ZIP_ARCHIVE_TOO_LARGE: -// return "archive is too large"; -// case MZ_ZIP_VALIDATION_FAILED: -// return "validation failed"; -// case MZ_ZIP_WRITE_CALLBACK_FAILED: -// return "write calledback failed"; -// default: -// break; -// } - -// return "unknown error"; -// } - -/* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */ -// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) -// { -// if ((!pZip) || (!pZip->m_pState)) -// return MZ_FALSE; - -// return pZip->m_pState->m_zip64; -// } - -// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) -// { -// if ((!pZip) || (!pZip->m_pState)) -// return 0; - -// return pZip->m_pState->m_central_dir.m_size; -// } - -// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) -// { -// return pZip ? pZip->m_total_files : 0; -// } - -// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) -// { -// if (!pZip) -// return 0; -// return pZip->m_archive_size; -// } - -// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) -// { -// if ((!pZip) || (!pZip->m_pState)) -// return 0; -// return pZip->m_pState->m_file_archive_start_ofs; -// } - -// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) -// { -// if ((!pZip) || (!pZip->m_pState)) -// return 0; -// return pZip->m_pState->m_pFile; -// } - -// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) -// { -// if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) -// return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - -// return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); -// } - -// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) -// { -// mz_uint n; -// const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); -// if (!p) -// { -// if (filename_buf_size) -// pFilename[0] = '\0'; -// mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -// return 0; -// } -// n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); -// if (filename_buf_size) -// { -// n = MZ_MIN(n, filename_buf_size - 1); -// memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); -// pFilename[n] = '\0'; -// } -// return n + 1; -// } - -// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) -// { -// return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); -// } - -// mz_bool mz_zip_end(mz_zip_archive *pZip) -// { -// if (!pZip) -// return MZ_FALSE; - -// if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) -// return mz_zip_reader_end(pZip); -// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -// else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) -// return mz_zip_writer_end(pZip); -// #endif - -// return MZ_FALSE; -// } - -// #ifdef __cplusplus -// } -// #endif - -// #endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ diff --git a/gomspace/libutil/src/zip/miniz/miniz.h b/gomspace/libutil/src/zip/miniz/miniz.h deleted file mode 100644 index e5172634..00000000 --- a/gomspace/libutil/src/zip/miniz/miniz.h +++ /dev/null @@ -1,1329 +0,0 @@ -/* miniz.c 2.0.6 beta - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing - See "unlicense" statement at the end of this file. - Rich Geldreich , last updated Oct. 13, 2013 - Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt - - Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define - MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). - - * Low-level Deflate/Inflate implementation notes: - - Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or - greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses - approximately as well as zlib. - - Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function - coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory - block large enough to hold the entire file. - - The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. - - * zlib-style API notes: - - miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in - zlib replacement in many apps: - The z_stream struct, optional memory allocation callbacks - deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound - inflateInit/inflateInit2/inflate/inflateEnd - compress, compress2, compressBound, uncompress - CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. - Supports raw deflate streams or standard zlib streams with adler-32 checking. - - Limitations: - The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. - I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but - there are no guarantees that miniz.c pulls this off perfectly. - - * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by - Alex Evans. Supports 1-4 bytes/pixel images. - - * ZIP archive API notes: - - The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to - get the job done with minimal fuss. There are simple API's to retrieve file information, read files from - existing archives, create new archives, append new files to existing archives, or clone archive data from - one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), - or you can specify custom file read/write callbacks. - - - Archive reading: Just call this function to read a single file from a disk archive: - - void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, - size_t *pSize, mz_uint zip_flags); - - For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central - directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. - - - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: - - int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); - - The locate operation can optionally check file comments too, which (as one example) can be used to identify - multiple versions of the same file in an archive. This function uses a simple linear search through the central - directory, so it's not very fast. - - Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and - retrieve detailed info on each file by calling mz_zip_reader_file_stat(). - - - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data - to disk and builds an exact image of the central directory in memory. The central directory image is written - all at once at the end of the archive file when the archive is finalized. - - The archive writer can optionally align each file's local header and file data to any power of 2 alignment, - which can be useful when the archive will be read from optical media. Also, the writer supports placing - arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still - readable by any ZIP tool. - - - Archive appending: The simple way to add a single file to an archive is to call this function: - - mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, - const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - - The archive will be created if it doesn't already exist, otherwise it'll be appended to. - Note the appending is done in-place and is not an atomic operation, so if something goes wrong - during the operation it's possible the archive could be left without a central directory (although the local - file headers and file data will be fine, so the archive will be recoverable). - - For more complex archive modification scenarios: - 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to - preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the - compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and - you're done. This is safe but requires a bunch of temporary disk space or heap memory. - - 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), - append new files as needed, then finalize the archive which will write an updated central directory to the - original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a - possibility that the archive's central directory could be lost with this method if anything goes wrong, though. - - - ZIP archive support limitations: - No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. - Requires streams capable of seeking. - - * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the - below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. - - * Important: For best perf. be sure to customize the below macros for your target platform: - #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 - #define MINIZ_LITTLE_ENDIAN 1 - #define MINIZ_HAS_64BIT_REGISTERS 1 - - * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz - uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files - (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). -*/ -#pragma once - - - - - -/* Defines to completely disable specific portions of miniz.c: - If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. */ - -/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */ -/*#define MINIZ_NO_STDIO */ - -/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */ -/* get/set file times, and the C run-time funcs that get/set times won't be called. */ -/* The current downside is the times written to your archives will be from 1979. */ -#define MINIZ_NO_TIME - -/* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */ -/*#define MINIZ_NO_ARCHIVE_APIS */ - -/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */ -/*#define MINIZ_NO_ARCHIVE_WRITING_APIS */ - -/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */ -/*#define MINIZ_NO_ZLIB_APIS */ - -/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */ -/*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ - -/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. - Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc - callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user - functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */ -/*#define MINIZ_NO_MALLOC */ - -#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) -/* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux */ -#define MINIZ_NO_TIME -#endif - -#include - -#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) -#include -#endif - -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) -/* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */ -#define MINIZ_X86_OR_X64_CPU 1 -#else -#define MINIZ_X86_OR_X64_CPU 0 -#endif - -#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU -/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ -#define MINIZ_LITTLE_ENDIAN 1 -#else -#define MINIZ_LITTLE_ENDIAN 0 -#endif - -// #if MINIZ_X86_OR_X64_CPU -/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */ -// #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 -// #else -// #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 -// #endif -#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 - -#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) -/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). */ -#define MINIZ_HAS_64BIT_REGISTERS 1 -#else -#define MINIZ_HAS_64BIT_REGISTERS 0 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------- zlib-style API Definitions. */ - -/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */ -typedef unsigned long mz_ulong; - -/* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. */ -void mz_free(void *p); - -#define MZ_ADLER32_INIT (1) -/* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */ -mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); - -#define MZ_CRC32_INIT (0) -/* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ -// mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); - -/* Compression strategies. */ -enum -{ - MZ_DEFAULT_STRATEGY = 0, - MZ_FILTERED = 1, - MZ_HUFFMAN_ONLY = 2, - MZ_RLE = 3, - MZ_FIXED = 4 -}; - -/* Method */ -#define MZ_DEFLATED 8 - -/* Heap allocation callbacks. -Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. */ -typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); -typedef void (*mz_free_func)(void *opaque, void *address); -typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); - -/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */ -enum -{ - MZ_NO_COMPRESSION = 0, - MZ_BEST_SPEED = 1, - MZ_BEST_COMPRESSION = 9, - MZ_UBER_COMPRESSION = 10, - MZ_DEFAULT_LEVEL = 6, - MZ_DEFAULT_COMPRESSION = -1 -}; - -#define MZ_VERSION "10.0.1" -#define MZ_VERNUM 0xA010 -#define MZ_VER_MAJOR 10 -#define MZ_VER_MINOR 0 -#define MZ_VER_REVISION 1 -#define MZ_VER_SUBREVISION 0 - -#ifndef MINIZ_NO_ZLIB_APIS - -/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). */ -enum -{ - MZ_NO_FLUSH = 0, - MZ_PARTIAL_FLUSH = 1, - MZ_SYNC_FLUSH = 2, - MZ_FULL_FLUSH = 3, - MZ_FINISH = 4, - MZ_BLOCK = 5 -}; - -/* Return status codes. MZ_PARAM_ERROR is non-standard. */ -enum -{ - MZ_OK = 0, - MZ_STREAM_END = 1, - MZ_NEED_DICT = 2, - MZ_ERRNO = -1, - MZ_STREAM_ERROR = -2, - MZ_DATA_ERROR = -3, - MZ_MEM_ERROR = -4, - MZ_BUF_ERROR = -5, - MZ_VERSION_ERROR = -6, - MZ_PARAM_ERROR = -10000 -}; - -/* Window bits */ -#define MZ_DEFAULT_WINDOW_BITS 15 - -struct mz_internal_state; - -/* Compression/decompression stream struct. */ -typedef struct mz_stream_s -{ - const unsigned char *next_in; /* pointer to next byte to read */ - unsigned int avail_in; /* number of bytes available at next_in */ - mz_ulong total_in; /* total number of bytes consumed so far */ - - unsigned char *next_out; /* pointer to next byte to write */ - unsigned int avail_out; /* number of bytes that can be written to next_out */ - mz_ulong total_out; /* total number of bytes produced so far */ - - char *msg; /* error msg (unused) */ - struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */ - - mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */ - mz_free_func zfree; /* optional heap free function (defaults to free) */ - void *opaque; /* heap alloc function user pointer */ - - int data_type; /* data_type (unused) */ - mz_ulong adler; /* adler32 of the source or uncompressed data */ - mz_ulong reserved; /* not used */ -} mz_stream; - -typedef mz_stream *mz_streamp; - -/* Returns the version string of miniz.c. */ -// const char *mz_version(void); - -/* mz_deflateInit() initializes a compressor with default options: */ -/* Parameters: */ -/* pStream must point to an initialized mz_stream struct. */ -/* level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */ -/* level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. */ -/* (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */ -/* Return values: */ -/* MZ_OK on success. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -/* MZ_PARAM_ERROR if the input parameters are bogus. */ -/* MZ_MEM_ERROR on out of memory. */ -int mz_deflateInit(mz_streamp pStream, int level); - -/* mz_deflateInit2() is like mz_deflate(), except with more control: */ -/* Additional parameters: */ -/* method must be MZ_DEFLATED */ -/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */ -/* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */ -int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); - -/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ -// int mz_deflateReset(mz_streamp pStream); - -/* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */ -/* Parameters: */ -/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ -/* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */ -/* Return values: */ -/* MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). */ -/* MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -/* MZ_PARAM_ERROR if one of the parameters is invalid. */ -/* MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) */ -int mz_deflate(mz_streamp pStream, int flush); - -/* mz_deflateEnd() deinitializes a compressor: */ -/* Return values: */ -/* MZ_OK on success. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -int mz_deflateEnd(mz_streamp pStream); - -/* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ -// mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); - -/* Single-call compression functions mz_compress() and mz_compress2(): */ -/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ -int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); -int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); - -/* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */ -// mz_ulong mz_compressBound(mz_ulong source_len); - -/* Initializes a decompressor. */ -int mz_inflateInit(mz_streamp pStream); - -/* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: */ -/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */ -int mz_inflateInit2(mz_streamp pStream, int window_bits); - -/* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. */ -/* Parameters: */ -/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ -/* flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */ -/* On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). */ -/* MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. */ -/* Return values: */ -/* MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. */ -/* MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -/* MZ_DATA_ERROR if the deflate stream is invalid. */ -/* MZ_PARAM_ERROR if one of the parameters is invalid. */ -/* MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again */ -/* with more input data, or with more room in the output buffer (except when using single call decompression, described above). */ -int mz_inflate(mz_streamp pStream, int flush); - -/* Deinitializes a decompressor. */ -int mz_inflateEnd(mz_streamp pStream); - -/* Single-call decompression. */ -/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */ -int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); - -/* Returns a string description of the specified error code, or NULL if the error code is invalid. */ -// const char *mz_error(int err); - -/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */ -/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ -#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES -typedef unsigned char Byte; -typedef unsigned int uInt; -typedef mz_ulong uLong; -typedef Byte Bytef; -typedef uInt uIntf; -typedef char charf; -typedef int intf; -typedef void *voidpf; -typedef uLong uLongf; -typedef void *voidp; -typedef void *const voidpc; -#define Z_NULL 0 -#define Z_NO_FLUSH MZ_NO_FLUSH -#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH -#define Z_SYNC_FLUSH MZ_SYNC_FLUSH -#define Z_FULL_FLUSH MZ_FULL_FLUSH -#define Z_FINISH MZ_FINISH -#define Z_BLOCK MZ_BLOCK -#define Z_OK MZ_OK -#define Z_STREAM_END MZ_STREAM_END -#define Z_NEED_DICT MZ_NEED_DICT -#define Z_ERRNO MZ_ERRNO -#define Z_STREAM_ERROR MZ_STREAM_ERROR -#define Z_DATA_ERROR MZ_DATA_ERROR -#define Z_MEM_ERROR MZ_MEM_ERROR -#define Z_BUF_ERROR MZ_BUF_ERROR -#define Z_VERSION_ERROR MZ_VERSION_ERROR -#define Z_PARAM_ERROR MZ_PARAM_ERROR -#define Z_NO_COMPRESSION MZ_NO_COMPRESSION -#define Z_BEST_SPEED MZ_BEST_SPEED -#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION -#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION -#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY -#define Z_FILTERED MZ_FILTERED -#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY -#define Z_RLE MZ_RLE -#define Z_FIXED MZ_FIXED -#define Z_DEFLATED MZ_DEFLATED -#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS -#define alloc_func mz_alloc_func -#define free_func mz_free_func -#define internal_state mz_internal_state -#define z_stream mz_stream -#define deflateInit mz_deflateInit -#define deflateInit2 mz_deflateInit2 -// #define deflateReset mz_deflateReset -#define deflate mz_deflate -#define deflateEnd mz_deflateEnd -// #define deflateBound mz_deflateBound -#define compress mz_compress -#define compress2 mz_compress2 -// #define compressBound mz_compressBound -#define inflateInit mz_inflateInit -#define inflateInit2 mz_inflateInit2 -#define inflate mz_inflate -#define inflateEnd mz_inflateEnd -#define uncompress mz_uncompress -// #define crc32 mz_crc32 -#define adler32 mz_adler32 -#define MAX_WBITS 15 -#define MAX_MEM_LEVEL 9 -// #define zError mz_error -#define ZLIB_VERSION MZ_VERSION -#define ZLIB_VERNUM MZ_VERNUM -#define ZLIB_VER_MAJOR MZ_VER_MAJOR -#define ZLIB_VER_MINOR MZ_VER_MINOR -#define ZLIB_VER_REVISION MZ_VER_REVISION -#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION -// #define zlibVersion mz_version -// #define zlib_version mz_version() -#endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ - -#endif /* MINIZ_NO_ZLIB_APIS */ - -#ifdef __cplusplus -} -#endif -#pragma once -#include -#include -#include -#include - -/* ------------------- Types and macros */ -typedef unsigned char mz_uint8; -typedef signed short mz_int16; -typedef unsigned short mz_uint16; -typedef unsigned int mz_uint32; -typedef unsigned int mz_uint; -typedef int64_t mz_int64; -typedef uint64_t mz_uint64; -typedef int mz_bool; - -#define MZ_FALSE (0) -#define MZ_TRUE (1) - -/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */ -#ifdef _MSC_VER -#define MZ_MACRO_END while (0, 0) -#else -#define MZ_MACRO_END while (0) -#endif - -#ifdef MINIZ_NO_STDIO -#define MZ_FILE void * -#else -#include -#define MZ_FILE FILE -#endif /* #ifdef MINIZ_NO_STDIO */ - -// #ifdef MINIZ_NO_TIME -// typedef struct mz_dummy_time_t_tag -// { -// int m_dummy; -// } mz_dummy_time_t; -// #define MZ_TIME_T mz_dummy_time_t -// #else -// #define MZ_TIME_T time_t -// #endif - -#define MZ_ASSERT(x) assert(x) - -#ifdef MINIZ_NO_MALLOC -#define MZ_MALLOC(x) NULL -#define MZ_FREE(x) (void)x, ((void)0) -#define MZ_REALLOC(p, x) NULL -#else -#define MZ_MALLOC(x) malloc(x) -#define MZ_FREE(x) free(x) -#define MZ_REALLOC(p, x) realloc(p, x) -#endif - -#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) -#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) -#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) -#else -#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) -#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) -#endif - -#define MZ_READ_LE64(p) (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U)) - -#ifdef _MSC_VER -#define MZ_FORCEINLINE __forceinline -#elif defined(__GNUC__) -#define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__)) -#else -#define MZ_FORCEINLINE inline -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -extern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); -extern void miniz_def_free_func(void *opaque, void *address); -// extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); - -#define MZ_UINT16_MAX (0xFFFFU) -#define MZ_UINT32_MAX (0xFFFFFFFFU) - -#ifdef __cplusplus -} -#endif -#pragma once - - -#ifdef __cplusplus -extern "C" { -#endif -/* ------------------- Low-level Compression API Definitions */ - -/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). */ -#define TDEFL_LESS_MEMORY 0 - -/* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): */ -/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */ -enum -{ - TDEFL_HUFFMAN_ONLY = 0, - TDEFL_DEFAULT_MAX_PROBES = 128, - TDEFL_MAX_PROBES_MASK = 0xFFF -}; - -/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. */ -/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */ -/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */ -/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). */ -/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */ -/* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */ -/* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */ -/* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */ -/* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). */ -enum -{ - TDEFL_WRITE_ZLIB_HEADER = 0x01000, - TDEFL_COMPUTE_ADLER32 = 0x02000, - TDEFL_GREEDY_PARSING_FLAG = 0x04000, - TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, - TDEFL_RLE_MATCHES = 0x10000, - TDEFL_FILTER_MATCHES = 0x20000, - TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, - TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 -}; - -/* High level compression functions: */ -/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */ -/* On entry: */ -/* pSrc_buf, src_buf_len: Pointer and size of source block to compress. */ -/* flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. */ -/* On return: */ -/* Function returns a pointer to the compressed data, or NULL on failure. */ -/* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */ -/* The caller must free() the returned block when it's no longer needed. */ -// void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - -/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ -/* Returns 0 on failure. */ -// size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - -/* Compresses an image to a compressed PNG file in memory. */ -/* On entry: */ -/* pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */ -/* The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. */ -/* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */ -/* If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */ -/* On return: */ -/* Function returns a pointer to the compressed data, or NULL on failure. */ -/* *pLen_out will be set to the size of the PNG image file. */ -/* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */ -// void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); -// void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); - -/* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ -typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); - -/* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */ -// mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -enum -{ - TDEFL_MAX_HUFF_TABLES = 3, - TDEFL_MAX_HUFF_SYMBOLS_0 = 288, - TDEFL_MAX_HUFF_SYMBOLS_1 = 32, - TDEFL_MAX_HUFF_SYMBOLS_2 = 19, - TDEFL_LZ_DICT_SIZE = 32768, - TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, - TDEFL_MIN_MATCH_LEN = 3, - TDEFL_MAX_MATCH_LEN = 258 -}; - -/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). */ -#if TDEFL_LESS_MEMORY -enum -{ - TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, - TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, - TDEFL_MAX_HUFF_SYMBOLS = 288, - TDEFL_LZ_HASH_BITS = 12, - TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, - TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, - TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS -}; -#else -enum -{ - TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, - TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, - TDEFL_MAX_HUFF_SYMBOLS = 288, - TDEFL_LZ_HASH_BITS = 15, - TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, - TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, - TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS -}; -#endif - -/* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. */ -typedef enum { - TDEFL_STATUS_BAD_PARAM = -2, - TDEFL_STATUS_PUT_BUF_FAILED = -1, - TDEFL_STATUS_OKAY = 0, - TDEFL_STATUS_DONE = 1 -} tdefl_status; - -/* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */ -typedef enum { - TDEFL_NO_FLUSH = 0, - TDEFL_SYNC_FLUSH = 2, - TDEFL_FULL_FLUSH = 3, - TDEFL_FINISH = 4 -} tdefl_flush; - -/* tdefl's compression state structure. */ -typedef struct -{ - tdefl_put_buf_func_ptr m_pPut_buf_func; - void *m_pPut_buf_user; - mz_uint m_flags, m_max_probes[2]; - int m_greedy_parsing; - mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; - mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; - mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; - mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; - tdefl_status m_prev_return_status; - const void *m_pIn_buf; - void *m_pOut_buf; - size_t *m_pIn_buf_size, *m_pOut_buf_size; - tdefl_flush m_flush; - const mz_uint8 *m_pSrc; - size_t m_src_buf_left, m_out_buf_ofs; - mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; - mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; - mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; - mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; - mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; -} tdefl_compressor; - -/* Initializes the compressor. */ -/* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */ -/* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. */ -/* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */ -/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */ -tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -/* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. */ -tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); - -/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ -/* tdefl_compress_buffer() always consumes the entire input buffer. */ -// tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); - -// tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); -mz_uint32 tdefl_get_adler32(tdefl_compressor *d); - -/* Create tdefl_compress() flags given zlib-style compression parameters. */ -/* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */ -/* window_bits may be -15 (raw deflate) or 15 (zlib) */ -/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */ -mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); - -/* Allocate the tdefl_compressor structure in C so that */ -/* non-C language bindings to tdefl_ API don't need to worry about */ -/* structure size and allocation mechanism. */ -// tdefl_compressor *tdefl_compressor_alloc(); -// void tdefl_compressor_free(tdefl_compressor *pComp); - -#ifdef __cplusplus -} -#endif -#pragma once - -/* ------------------- Low-level Decompression API Definitions */ - -#ifdef __cplusplus -extern "C" { -#endif -/* Decompression flags used by tinfl_decompress(). */ -/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. */ -/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. */ -/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */ -/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */ -enum -{ - TINFL_FLAG_PARSE_ZLIB_HEADER = 1, - TINFL_FLAG_HAS_MORE_INPUT = 2, - TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, - TINFL_FLAG_COMPUTE_ADLER32 = 8 -}; - -/* High level decompression functions: */ -/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */ -/* On entry: */ -/* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */ -/* On return: */ -/* Function returns a pointer to the decompressed data, or NULL on failure. */ -/* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */ -/* The caller must call mz_free() on the returned block when it's no longer needed. */ -// void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - -/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ -/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ -#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) -// size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - -/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */ -/* Returns 1 on success or 0 on failure. */ -typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); -// int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -struct tinfl_decompressor_tag; -typedef struct tinfl_decompressor_tag tinfl_decompressor; - -/* Allocate the tinfl_decompressor structure in C so that */ -/* non-C language bindings to tinfl_ API don't need to worry about */ -/* structure size and allocation mechanism. */ - -// tinfl_decompressor *tinfl_decompressor_alloc(); -// void tinfl_decompressor_free(tinfl_decompressor *pDecomp); - -/* Max size of LZ dictionary. */ -#define TINFL_LZ_DICT_SIZE 32768 - -/* Return status. */ -typedef enum { - /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is indicating that no more are available. The compressed data */ - /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input but this is a BAD sign (either the data is corrupted or you called it incorrectly). */ - /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */ - TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4, - - /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, but if you get this error the calling code is wrong.) */ - TINFL_STATUS_BAD_PARAM = -3, - - /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you call it again it'll return TINFL_STATUS_DONE. */ - TINFL_STATUS_ADLER32_MISMATCH = -2, - - /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */ - TINFL_STATUS_FAILED = -1, - - /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */ - - /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte that it needed, has successfully reached the end of the deflate stream, and */ - /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If you call it again you'll just get TINFL_STATUS_DONE over and over again. */ - TINFL_STATUS_DONE = 0, - - /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */ - /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also possible (but unlikely) for the inflator to keep on demanding input to */ - /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */ - TINFL_STATUS_NEEDS_MORE_INPUT = 1, - - /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write this data into the output buffer. */ - /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed data to the caller. I've been assuming you know how much uncompressed data to expect */ - /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure streaming scenarios where you have no idea how many bytes to expect this may not be possible */ - /* so I may need to add some code to address this. */ - TINFL_STATUS_HAS_MORE_OUTPUT = 2 -} tinfl_status; - -/* Initializes the decompressor to its initial state. */ -#define tinfl_init(r) \ - do \ - { \ - (r)->m_state = 0; \ - } \ - MZ_MACRO_END -#define tinfl_get_adler32(r) (r)->m_check_adler32 - -/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */ -/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */ -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); - -/* Internal/private bits follow. */ -enum -{ - TINFL_MAX_HUFF_TABLES = 3, - TINFL_MAX_HUFF_SYMBOLS_0 = 288, - TINFL_MAX_HUFF_SYMBOLS_1 = 32, - TINFL_MAX_HUFF_SYMBOLS_2 = 19, - TINFL_FAST_LOOKUP_BITS = 10, - TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS -}; - -typedef struct -{ - mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; - mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; -} tinfl_huff_table; - -#if MINIZ_HAS_64BIT_REGISTERS -#define TINFL_USE_64BIT_BITBUF 1 -#else -#define TINFL_USE_64BIT_BITBUF 0 -#endif - -#if TINFL_USE_64BIT_BITBUF -typedef mz_uint64 tinfl_bit_buf_t; -#define TINFL_BITBUF_SIZE (64) -#else -typedef mz_uint32 tinfl_bit_buf_t; -#define TINFL_BITBUF_SIZE (32) -#endif - -struct tinfl_decompressor_tag -{ - mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; - tinfl_bit_buf_t m_bit_buf; - size_t m_dist_from_out_buf_start; - tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; - mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; -}; - -#ifdef __cplusplus -} -#endif - -#pragma once - - -/* ------------------- ZIP archive reading/writing */ - -// #ifndef MINIZ_NO_ARCHIVE_APIS - -// #ifdef __cplusplus -// extern "C" { -// #endif - -// enum -// { - /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ -// MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, -// MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, -// MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 -// }; - -// typedef struct -// { -// /* Central directory file index. */ -// mz_uint32 m_file_index; - -// /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ -// mz_uint64 m_central_dir_ofs; - -// /* These fields are copied directly from the zip's central dir. */ -// mz_uint16 m_version_made_by; -// mz_uint16 m_version_needed; -// mz_uint16 m_bit_flag; -// mz_uint16 m_method; - -// #ifndef MINIZ_NO_TIME -// MZ_TIME_T m_time; -// #endif - -// /* CRC-32 of uncompressed data. */ -// mz_uint32 m_crc32; - -// /* File's compressed size. */ -// mz_uint64 m_comp_size; - -// /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ -// mz_uint64 m_uncomp_size; - -// /* Zip internal and external file attributes. */ -// mz_uint16 m_internal_attr; -// mz_uint32 m_external_attr; - -// /* Entry's local header file offset in bytes. */ -// mz_uint64 m_local_header_ofs; - -// /* Size of comment in bytes. */ -// mz_uint32 m_comment_size; - -// /* MZ_TRUE if the entry appears to be a directory. */ -// mz_bool m_is_directory; - -// /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ -// mz_bool m_is_encrypted; - -// /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ -// mz_bool m_is_supported; - -// /* Filename. If string ends in '/' it's a subdirectory entry. */ -// /* Guaranteed to be zero terminated, may be truncated to fit. */ -// char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; - -// /* Comment field. */ -// /* Guaranteed to be zero terminated, may be truncated to fit. */ -// char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; - -// } mz_zip_archive_file_stat; - -// typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); -// typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); -// typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); - -// struct mz_zip_internal_state_tag; -// typedef struct mz_zip_internal_state_tag mz_zip_internal_state; - -// typedef enum { -// MZ_ZIP_MODE_INVALID = 0, -// MZ_ZIP_MODE_READING = 1, -// MZ_ZIP_MODE_WRITING = 2, -// MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 -// } mz_zip_mode; - -// typedef enum { -// MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, -// MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, -// MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, -// MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, - // MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ - // MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ - // MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ -// MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, -// MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 -// } mz_zip_flags; - -// typedef enum { -// MZ_ZIP_TYPE_INVALID = 0, -// MZ_ZIP_TYPE_USER, -// MZ_ZIP_TYPE_MEMORY, -// MZ_ZIP_TYPE_HEAP, -// MZ_ZIP_TYPE_FILE, -// MZ_ZIP_TYPE_CFILE, -// MZ_ZIP_TOTAL_TYPES -// } mz_zip_type; - -/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ -// typedef enum { -// MZ_ZIP_NO_ERROR = 0, -// MZ_ZIP_UNDEFINED_ERROR, -// MZ_ZIP_TOO_MANY_FILES, -// MZ_ZIP_FILE_TOO_LARGE, -// MZ_ZIP_UNSUPPORTED_METHOD, -// MZ_ZIP_UNSUPPORTED_ENCRYPTION, -// MZ_ZIP_UNSUPPORTED_FEATURE, -// MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, -// MZ_ZIP_NOT_AN_ARCHIVE, -// MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, -// MZ_ZIP_UNSUPPORTED_MULTIDISK, -// MZ_ZIP_DECOMPRESSION_FAILED, -// MZ_ZIP_COMPRESSION_FAILED, -// MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, -// MZ_ZIP_CRC_CHECK_FAILED, -// MZ_ZIP_UNSUPPORTED_CDIR_SIZE, -// MZ_ZIP_ALLOC_FAILED, -// MZ_ZIP_FILE_OPEN_FAILED, -// MZ_ZIP_FILE_CREATE_FAILED, -// MZ_ZIP_FILE_WRITE_FAILED, -// MZ_ZIP_FILE_READ_FAILED, -// MZ_ZIP_FILE_CLOSE_FAILED, -// MZ_ZIP_FILE_SEEK_FAILED, -// MZ_ZIP_FILE_STAT_FAILED, -// MZ_ZIP_INVALID_PARAMETER, -// MZ_ZIP_INVALID_FILENAME, -// MZ_ZIP_BUF_TOO_SMALL, -// MZ_ZIP_INTERNAL_ERROR, -// MZ_ZIP_FILE_NOT_FOUND, -// MZ_ZIP_ARCHIVE_TOO_LARGE, -// MZ_ZIP_VALIDATION_FAILED, -// MZ_ZIP_WRITE_CALLBACK_FAILED, -// MZ_ZIP_TOTAL_ERRORS -// } mz_zip_error; - -// typedef struct -// { -// mz_uint64 m_archive_size; -// mz_uint64 m_central_directory_file_ofs; - -// /* We only support up to UINT32_MAX files in zip64 mode. */ -// mz_uint32 m_total_files; -// mz_zip_mode m_zip_mode; -// mz_zip_type m_zip_type; -// mz_zip_error m_last_error; - -// mz_uint64 m_file_offset_alignment; - -// mz_alloc_func m_pAlloc; -// mz_free_func m_pFree; -// mz_realloc_func m_pRealloc; -// void *m_pAlloc_opaque; - -// mz_file_read_func m_pRead; -// mz_file_write_func m_pWrite; -// mz_file_needs_keepalive m_pNeeds_keepalive; -// void *m_pIO_opaque; - -// mz_zip_internal_state *m_pState; - -// } mz_zip_archive; - -// typedef struct -// { -// mz_zip_archive *pZip; -// mz_uint flags; - -// int status; -// #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -// mz_uint file_crc32; -// #endif -// mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; -// mz_zip_archive_file_stat file_stat; -// void *pRead_buf; -// void *pWrite_buf; - -// size_t out_blk_remain; - -// tinfl_decompressor inflator; - -// } mz_zip_reader_extract_iter_state; - -/* -------- ZIP reading */ - -/* Inits a ZIP archive reader. */ -/* These functions read and validate the archive's central directory. */ -// mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); - -// mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); - -// #ifndef MINIZ_NO_STDIO -/* Read a archive from a disk file. */ -/* file_start_ofs is the file offset where the archive actually begins, or 0. */ -/* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */ -// mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); -// mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); - -/* Read an archive from an already opened FILE, beginning at the current file position. */ -/* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */ -/* The FILE will NOT be closed when mz_zip_reader_end() is called. */ -// mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); -// #endif - -/* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */ -// mz_bool mz_zip_reader_end(mz_zip_archive *pZip); - -/* -------- ZIP reading or writing */ - -/* Clears a mz_zip_archive struct to all zeros. */ -/* Important: This must be done before passing the struct to any mz_zip functions. */ -// void mz_zip_zero_struct(mz_zip_archive *pZip); - -// mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); -// mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); - -/* Returns the total number of files in the archive. */ -// mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); - -// mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); -// mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); -// MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); - -/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ -// size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); - -/* Attempts to locates a file in the archive's central directory. */ -/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ -/* Returns -1 if the file cannot be found. */ -// int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); -/* Returns MZ_FALSE if the file cannot be found. */ -// mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex); - -/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */ -/* Note that the m_last_error functionality is not thread safe. */ -// mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); -// mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); -// mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); -// mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); -// const char *mz_zip_get_error_string(mz_zip_error mz_err); - -/* MZ_TRUE if the archive file entry is a directory entry. */ -// mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); - -/* MZ_TRUE if the file is encrypted/strong encrypted. */ -// mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); - -/* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */ -// mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); - -/* Retrieves the filename of an archive file entry. */ -/* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */ -// mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); - -/* Attempts to locates a file in the archive's central directory. */ -/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ -/* Returns -1 if the file cannot be found. */ -// int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); -// int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); - -/* Returns detailed information about an archive file entry. */ -// mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); - -/* MZ_TRUE if the file is in zip64 format. */ -/* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */ -// mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); - -/* Returns the total central directory size in bytes. */ -/* The current max supported size is <= MZ_UINT32_MAX. */ -// size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); - -/* Extracts a archive file to a memory buffer using no memory allocation. */ -/* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ -// mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); -// mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); - -/* Extracts a archive file to a memory buffer. */ -// mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); -// mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); - -/* Extracts a archive file to a dynamically allocated heap buffer. */ -/* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ -/* Returns NULL and sets the last error on failure. */ -// void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); -// void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); - -/* Extracts a archive file using a callback function to output the file's data. */ -// mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); -// mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); - -/* Extract a file iteratively */ -// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); -// mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); -// size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); -// mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); - -// #ifndef MINIZ_NO_STDIO -/* Extracts a archive file to a disk file and sets its last accessed and modified times. */ -/* This function only extracts files, not archive directory records. */ -// mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); -// mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); - -/* Extracts a archive file starting at the current position in the destination FILE stream. */ -// mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); -// mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); -// #endif - -#if 0 -/* TODO */ - typedef void *mz_zip_streaming_extract_state_ptr; - mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); - uint64_t mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); - uint64_t mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); - mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, uint64_t new_ofs); - size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size); - mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); -#endif - -/* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */ -/* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */ -// mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); - -/* Validates an entire archive by calling mz_zip_validate_file() on each file. */ -// mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags); - -/* Misc utils/helpers, valid for ZIP reading or writing */ -// mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr); -// mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); - -/* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ -// mz_bool mz_zip_end(mz_zip_archive *pZip); - -/* -------- ZIP writing */ - -// #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - -/* Inits a ZIP archive writer. */ -/*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ -/*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ -// mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); -// mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); - -// mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); -// mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); - -// #ifndef MINIZ_NO_STDIO -// mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); -// mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); -// mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); -// #endif - -/* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */ -/* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ -/* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). */ -/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */ -/* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */ -/* the archive is finalized the file's central directory will be hosed. */ -// mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); -// mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); - -/* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */ -/* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ -/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ -// mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); - -/* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */ -/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ -// mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); - -// mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, -// mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, -// const char *user_extra_data_central, mz_uint user_extra_data_central_len); - -// #ifndef MINIZ_NO_STDIO -/* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */ -/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ -// mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - -/* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ -// mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, -// const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, -// const char *user_extra_data_central, mz_uint user_extra_data_central_len); -// #endif - -/* Adds a file to an archive by fully cloning the data from another archive. */ -/* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */ -// mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index); - -/* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ -/* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ -/* An archive must be manually finalized by calling this function for it to be valid. */ -// mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); - -/* Finalizes a heap archive, returning a poiner to the heap block and its size. */ -/* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ -// mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); - -/* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ -/* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */ -// mz_bool mz_zip_writer_end(mz_zip_archive *pZip); - -/* -------- Misc. high-level helper functions: */ - -/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */ -/* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */ -/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ -/* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */ -// mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); -// mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); - -/* Reads a single file from an archive into a heap block. */ -/* If pComment is not NULL, only the file with the specified comment will be extracted. */ -/* Returns NULL on failure. */ -// void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); -// void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); - -// #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ - -// #ifdef __cplusplus -// } -// #endif - -// #endif /* MINIZ_NO_ARCHIVE_APIS */ diff --git a/gomspace/libutil/src/zip/zip.c b/gomspace/libutil/src/zip/zip.c deleted file mode 100644 index b7fd00fc..00000000 --- a/gomspace/libutil/src/zip/zip.c +++ /dev/null @@ -1,357 +0,0 @@ -/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */ - -#include "gs/util/zip/zip.h" -#include "miniz/miniz.h" - -#include -#include -#include - -#include - -static void cleanup(FILE *pInfile, FILE *pOutfile, uint8_t *stream_inbuf, uint8_t *stream_outbuf) -{ - if(pInfile) - fclose(pInfile); - - if(pOutfile) - fclose(pOutfile); - - if(stream_inbuf) - free(stream_inbuf); - - if(stream_outbuf) - free(stream_outbuf); -} - -int gs_zip_compress_file(const char *src, const char *dest) -{ - FILE *pInfile, *pOutfile; - uint32_t infile_size; - long file_loc; - - // Open input file. - pInfile = fopen(src, "rb"); - if (!pInfile) - { - log_error("Zip compress: Failed opening input file!"); - return GS_ERROR_IO; - } - - // Determine input file's size. - fseek(pInfile, 0, SEEK_END); - file_loc = ftell(pInfile); - fseek(pInfile, 0, SEEK_SET); - - if((file_loc < 0) || ((unsigned long)file_loc > UINT_MAX)) - { - log_error("Zip compress: File is too large to be processed."); - fclose(pInfile); - - return GS_ERROR_IO; - } - - infile_size = (uint32_t)file_loc; - uint32_t buffer_size = infile_size; - - // Allocate input buffer memory - uint8_t *stream_inbuf = malloc(buffer_size); - if (stream_inbuf == NULL) - { - log_error("Zip compress: Failed to allocate input buffer memory"); - fclose(pInfile); - - return GS_ERROR_IO; - } - - // Allocate output buffer memory - uint8_t *stream_outbuf = malloc(buffer_size); - if (stream_outbuf == NULL) - { - log_error("Zip compress: Failed to allocate output buffer memory"); - cleanup(pInfile, NULL, stream_inbuf, NULL); - - return GS_ERROR_IO; - } - - // Open output file. - pOutfile = fopen(dest, "wb"); - if (!pOutfile) - { - log_error("Zip compress: Failed opening output file!"); - cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); - - return GS_ERROR_IO; - } - - // Init the z_stream - z_stream stream; - memset(&stream, 0, sizeof(stream)); - stream.next_in = stream_inbuf; - stream.avail_in = 0; - stream.next_out = stream_outbuf; - stream.avail_out = buffer_size; - - // Compression. - uint32_t infile_remaining = infile_size; - - if(deflateInit(&stream, Z_BEST_COMPRESSION) != Z_OK) - { - log_error("Zip compress: deflateInit() failed!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_DATA; - } - - for( ; ; ) - { - int status; - if(!stream.avail_in) - { - // Input buffer is empty, so read more bytes from input file. - uint32_t n = gs_min((uint32_t)buffer_size, infile_remaining); - - if (fread(stream_inbuf, 1, n, pInfile) != n) - { - log_error("Zip compress: Failed reading from input file!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_IO; - } - - stream.next_in = stream_inbuf; - stream.avail_in = n; - - infile_remaining -= n; - } - - status = deflate(&stream, infile_remaining ? Z_NO_FLUSH : Z_FINISH); - - if((status == Z_STREAM_END) || (!stream.avail_out)) - { - // Output buffer is full, or compression is done, so write buffer to output file. - uint32_t n = buffer_size - stream.avail_out; - if (fwrite(stream_outbuf, 1, n, pOutfile) != n) - { - log_error("Zip compress: Failed writing to output file!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_IO; - } - - stream.next_out = stream_outbuf; - stream.avail_out = buffer_size; - } - - if(status == Z_STREAM_END) - { - break; - } - else if(status != Z_OK) - { - log_error("Zip compress: deflate() failed with status %i!", status); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_DATA; - } - } - - if(deflateEnd(&stream) != Z_OK) - { - log_error("Zip compress: deflateEnd() failed!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_DATA; - } - - - cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); - if(EOF == fclose(pOutfile)) - { - log_error("Zip compress: Failed writing to output file!"); - return GS_ERROR_IO; - } - - log_debug("Total input bytes: %u\n", (mz_uint32)stream.total_in); - log_debug("Total output bytes: %u\n", (mz_uint32)stream.total_out); - log_debug("Success.\n"); - - return GS_OK; -} - -int gs_zip_decompress_file(const char *src, const char *dest) -{ - FILE *pInfile, *pOutfile; - uint32_t infile_size; - long file_loc; - - // Open input file. - pInfile = fopen(src, "rb"); - if (!pInfile) - { - log_error("Zip decompress: Failed opening input file!"); - return GS_ERROR_IO; - } - - // Determine input file's size. - fseek(pInfile, 0, SEEK_END); - file_loc = ftell(pInfile); - fseek(pInfile, 0, SEEK_SET); - - if((file_loc < 0) || ((unsigned long)file_loc > UINT_MAX)) - { - log_error("Zip decompress: File is too large to be processed."); - fclose(pInfile); - - return GS_ERROR_IO; - } - - infile_size = (uint32_t)file_loc; - uint32_t buffer_size = infile_size; - - // Allocate input buffer memory - uint8_t *stream_inbuf = malloc(buffer_size); - if (stream_inbuf == NULL) - { - log_error("Zip decompress: Failed to allocate input buffer memory"); - fclose(pInfile); - - return GS_ERROR_IO; - } - - // Allocate output buffer memory - uint8_t *stream_outbuf = malloc(buffer_size); - if (stream_outbuf == NULL) - { - log_error("Zip decompress: Failed to allocate output buffer memory"); - cleanup(pInfile, NULL, stream_inbuf, NULL); - - return GS_ERROR_IO; - } - - // Open output file. - pOutfile = fopen(dest, "wb"); - if (!pOutfile) - { - log_error("Zip decompress: Failed opening output file!"); - cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); - - return GS_ERROR_IO; - } - - // Init the z_stream - z_stream stream; - memset(&stream, 0, sizeof(stream)); - stream.next_in = stream_inbuf; - stream.avail_in = 0; - stream.next_out = stream_outbuf; - stream.avail_out = buffer_size; - - // Decompression. - uint32_t infile_remaining = infile_size; - - if(inflateInit(&stream)) - { - log_error("Zip decompress: inflateInit() failed!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_DATA; - } - - for( ; ; ) - { - int status; - if(!stream.avail_in) - { - // Input buffer is empty, so read more bytes from input file. - uint32_t n = gs_min((uint32_t)buffer_size, infile_remaining); - - if(fread(stream_inbuf, 1, n, pInfile) != n) - { - log_error("Zip decompress: Failed reading from input file!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_IO; - } - - stream.next_in = stream_inbuf; - stream.avail_in = n; - - infile_remaining -= n; - } - - status = inflate(&stream, Z_SYNC_FLUSH); - - if((status == Z_STREAM_END) || (!stream.avail_out)) - { - // Output buffer is full, or decompression is done, so write buffer to output file. - uint32_t n = buffer_size - stream.avail_out; - if(fwrite(stream_outbuf, 1, n, pOutfile) != n) - { - log_error("Zip decompress: Failed writing to output file!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_IO; - } - stream.next_out = stream_outbuf; - stream.avail_out = buffer_size; - } - - if(status == Z_STREAM_END) - { - break; - } - else if(status != Z_OK) - { - log_error("Zip decompress: inflate() failed with status %i!", status); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_DATA; - } - } - - if(inflateEnd(&stream) != Z_OK) - { - log_error("Zip decompress: inflateEnd() failed!"); - cleanup(pInfile, pOutfile, stream_inbuf, stream_outbuf); - - return GS_ERROR_DATA; - } - - cleanup(pInfile, NULL, stream_inbuf, stream_outbuf); - if(EOF == fclose(pOutfile)) - { - log_error("Zip decompress: Failed writing to output file!"); - return GS_ERROR_IO; - } - - log_debug("Total input bytes: %u", (mz_uint32)stream.total_in); - log_debug("Total output bytes: %u", (mz_uint32)stream.total_out); - log_debug("Success.\n"); - - return GS_OK; -} - -int gs_zip_compress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t *dest_len) -{ - mz_ulong cmp_len = src_len; - if(compress(dest, &cmp_len, src, (mz_ulong)src_len) != MZ_OK) - { - return GS_ERROR_DATA; - } - - *dest_len = cmp_len; - - return GS_OK; -} - -int gs_zip_decompress_data(const unsigned char *src, uint32_t src_len, unsigned char *dest, uint32_t dest_len, uint32_t *decomp_len) -{ - mz_ulong tmp = dest_len; - if(uncompress(dest, &tmp, src, (mz_ulong)src_len) != MZ_OK) - return GS_ERROR_DATA; - - *decomp_len = tmp; - - return GS_OK; -} diff --git a/gomspace/libutil/wscript b/gomspace/libutil/wscript deleted file mode 100644 index 48421e39..00000000 --- a/gomspace/libutil/wscript +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -# Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. - -import gs_gcc -import gs_doc -import gs_dist -from waflib.Build import BuildContext - -APPNAME = 'util' - - -def options(ctx): - ctx.load('gs_gcc gs_doc') - gs_gcc.gs_recurse(ctx) - - gr = ctx.add_option_group('libutil options') - gr.add_option('--console-history-len', metavar='LEN', default=10, type=int, help='Command history length, 0=none') - gr.add_option('--console-input-len', metavar='LEN', default=100, type=int, help='Command input length') - gr.add_option('--util-enable-isr-logs', action='store_true', help='Enable ISR logs') - - -def configure(ctx): - ctx.load('gs_gcc gs_doc') - - ctx.env.append_unique('FILES_LIBUTIL', ['src/*.c', - 'src/gosh/**/*.c', - 'src/log/**/*.c', - 'src/vmem/**/*.c', - 'src/watchdog/**/*.c', - 'src/drivers/**/*.c']) - - if ctx.env.GS_ARCH not in ['avr8']: - ctx.env.append_unique('FILES_LIBUTIL', ['src/zip/**/*.c']) - - if ctx.gs_is_linux(): - ctx.env.append_unique('FILES_LIBUTIL', ['src/linux/**/*.c']) - - ctx.env.GS_UTIL_CMOCKA = ctx.check_cfg(package='cmocka', args='--cflags --libs', - atleast_version='1.0.1', mandatory=False) - - # Check compiler endianness - avr32 GCC doesn't support endian defines - endianness = ctx.check_endianness() - ctx.define_cond('UTIL_LITTLE_ENDIAN', endianness == 'little') - ctx.define_cond('UTIL_BIG_ENDIAN', endianness == 'big') - - ctx.define('GS_CONSOLE_HISTORY_LEN', ctx.options.console_history_len) - ctx.define('GS_CONSOLE_INPUT_LEN', ctx.options.console_input_len) - ctx.define_cond('GS_LOG_ENABLE_ISR_LOGS', ctx.options.util_enable_isr_logs) - - ctx.gs_write_config_header('include/conf_util.h', remove=True) - - ctx.gs_add_doxygen(example=['tst'], exclude=['*/include/gs/uthash/*', - '*/include/gs/util/zip/*', - '*/include/deprecated/util/*', - '*/include/deprecated/gs/gosh/*']) - - ctx.gs_register_handler(function='command_gen_4_0', filepath='./tools/waf_command.py') - - gs_gcc.gs_recurse(ctx) - - -def build(ctx): - gs_gcc.gs_recurse(ctx) - - public_include = ctx.gs_include(name=APPNAME, - includes=['include', 'include/gs', - 'include/deprecated', 'include/deprecated/gs/gosh/'], - config_header=['include/conf_util.h']) - - ctx.gs_objects(source=ctx.path.ant_glob(ctx.env.FILES_LIBUTIL), - target=APPNAME, - includes=['src'], - use=ctx.env.USE_LIBUTIL + [public_include]) - - ctx.gs_shlib(source=ctx.path.ant_glob(ctx.env.FILES_LIBUTIL), - target=APPNAME, - includes=['src'], - gs_use_shlib=ctx.env.USE_LIBUTIL, - use=[public_include], - lib=['pthread']) - - ctx.gs_python_bindings(source=ctx.path.ant_glob('src/bindings/python/*.c'), - target=APPNAME, - gs_use_shlib=ctx.env.USE_LIBUTIL + [APPNAME], - use=[public_include], - package='libutil') - - if ctx.env.GS_UTIL_CMOCKA: - ctx.gs_stlib(source=ctx.path.ant_glob('src/test/*.c'), - name=APPNAME + '_cmocka', # overwrite default naming - target=APPNAME + '_cmocka', - includes=['include']) - - -def doc(ctx): - gs_doc.gs_library_doc(ctx, keyvalues={ - 'gs_prod_name': 'lib'+APPNAME, - 'gs_prod_desc': 'Low level APIs and utilities', - 'gs_sphinx_exclude': ['CHANGELOG.rst'], - }) - - -class Doc(BuildContext): - cmd = fun = 'doc' - - -def gs_dist(ctx): - ctx.add_default_files(source_module=True) diff --git a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock.h b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock.h deleted file mode 100644 index 0a4477ba..00000000 --- a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef P60DOCK_H_ -#define P60DOCK_H_ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include - -#include - -#include -#include -#include -#include -#include - -/** FRAM MEMORY MAP */ -#define P60DOCK_FRAM_PARAM 0x0400 -#define P60DOCK_FRAM_CAL 0x0800 -#define P60DOCK_FRAM_HK 0x0C00 - -#define P60DOCK_FRAM_GNDWDT 0x1F00 - -/** FRAM FILENAMES */ -#define P60DOCK_FNO_PARAM 1 -#define P60DOCK_FNO_PARAM_DFL 5 -#define P60DOCK_FNO_CAL 2 -#define P60DOCK_FNO_CAL_DFL 6 - -/** PARAM INDEX MAP */ -/* Index 0 is reserved for board param */ -#define P60DOCK_PARAM 1 -#define P60DOCK_CAL 2 -#define P60DOCK_SCRATCH 3 -#define P60DOCK_HK 4 - -#define P60DOCK_BATT_PACK_OTHER 0 -#define P60DOCK_BATT_PACK_BP2 1 -#define P60DOCK_BATT_PACK_BP4 2 -#define P60DOCK_BATT_PACK_BPX 3 - -int p60dock_get_hk(param_index_t * mem, uint8_t node, uint32_t timeout); -int p60dock_gndwdt_clear(uint8_t node, uint32_t timeout); -int p60dock_output_get(uint8_t node, char * ch_name, uint8_t * mode, uint8_t * ch_no); -int p60dock_output_set(uint8_t node, char * ch_name, uint8_t mode, uint8_t * ch_no); - -void cmd_p60dock_setup(void); - -#endif /* P60DOCK_H_ */ diff --git a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_cal.h b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_cal.h deleted file mode 100644 index 905bc3db..00000000 --- a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_cal.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef P60DOCK_CAL_H_ -#define P60DOCK_CAL_H_ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -/** - * Define memory space - */ - -#define P60DOCK_CAL_GAIN_V_OUT(i) (0x00 + (4 * i)) /* 13 * float */ -#define P60DOCK_CAL_GAIN_C_OUT(i) (0x34 + (4 * i)) /* 13 * float */ -#define P60DOCK_CAL_OFFSET_C_OUT(i) (0x68 + (2 * i)) /* 13 * uint16_t */ -#define P60DOCK_CAL_VREF 0x82 -#define P60DOCK_CAL_GAIN_VBAT_V 0x84 -#define P60DOCK_CAL_GAIN_VCC_C 0x88 -#define P60DOCK_CAL_OFFSET_VCC_C 0x8C -#define P60DOCK_CAL_GAIN_AUX1 0x90 -#define P60DOCK_CAL_GAIN_AUX2 0x94 -#define P60DOCK_CAL_OFFSET_AUX1 0x98 -#define P60DOCK_CAL_OFFSET_AUX2 0x9A -#define P60DOCK_CAL_GAIN_BATT_V 0x9C -#define P60DOCK_CAL_GAIN_BATT_CHRG 0xA0 -#define P60DOCK_CAL_OFFS_BATT_CHRG 0xA4 -#define P60DOCK_CAL_GAIN_BATT_DIS 0xA8 -#define P60DOCK_CAL_OFFS_BATT_DIS 0xAC - -/** Define the memory size */ -#define P60DOCK_CAL_SIZE 0xAE - -extern const param_table_t p60dock_calibration[]; -extern const int p60dock_cal_count; - -#endif /* P60DOCK_CAL_H_ */ diff --git a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h deleted file mode 100644 index b9c9f17a..00000000 --- a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_hk.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef P60DOCK_HK_H_ -#define P60DOCK_HK_H_ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -/** - * Define memory space - */ -#define P60DOCK_HK_C_OUT(i) (0x00 + (2 * i)) /* 13 * int16_t */ -#define P60DOCK_HK_V_OUT(i) (0x1A + (2 * i)) /* 13 * uint16_t */ -#define P60DOCK_HK_OUT_EN(i) (0x34 + (i)) /* 13 * uint8_t */ -#define P60DOCK_HK_TEMP(i) (0x44 + (2 * i)) /* 2 * int16_t */ -#define P60DOCK_HK_BOOT_CAUSE 0x48 -#define P60DOCK_HK_BOOT_COUNTER 0x4C -#define P60DOCK_HK_UPTIME 0x50 -#define P60DOCK_HK_RESET_CAUSE 0x54 -#define P60DOCK_HK_BATT_MODE 0x56 -#define P60DOCK_HK_HEATER_ON 0x57 -#define P60DOCK_HK_CONV_5V0_EN 0x58 - -#define P60DOCK_HK_LATCHUP(i) (0x5A + (2 * i)) /* 13 * uint16_t */ -#define P60DOCK_HK_VBAT_V 0x74 -#define P60DOCK_HK_VCC_C 0x76 -#define P60DOCK_HK_BATTERY_C 0x78 -#define P60DOCK_HK_BATTERY_V 0x7A -#define P60DOCK_HK_BP_TEMP(i) (0x7C + (2 * i)) /* 2 * int16_t */ -#define P60DOCK_HK_DEVICE_TYPE(i) (0x80 + (i)) /* 8 * uint8_t */ -#define P60DOCK_HK_DEVICE_STATUS(i) (0x88 + (i)) /* 8 * uint8_t */ -#define P60DOCK_HK_DEARM_STATUS 0x90 -#define P60DOCK_HK_CNT_WDTGND 0x94 -#define P60DOCK_HK_CNT_WDTI2C 0x98 -#define P60DOCK_HK_CNT_WDTCAN 0x9C -#define P60DOCK_HK_CNT_WDTCSP(i) (0xA0 + (4 * i)) /* 2 * uint32_t */ -#define P60DOCK_HK_WDTGND_LEFT 0xA8 -#define P60DOCK_HK_WDTI2C_LEFT 0xAC -#define P60DOCK_HK_WDTCAN_LEFT 0xB0 -#define P60DOCK_HK_WDTCSP_LEFT(i) (0xB4 + (i)) /* 2 * uint8_t */ -#define P60DOCK_HK_BATT_C_CHRG 0xB6 /* int16_t */ -#define P60DOCK_HK_BATT_C_DISCHRG 0xB8 /* int16_t */ -#define P60DOCK_HK_ANT6_DEPL 0xBA /* int8_t */ -#define P60DOCK_HK_AR6_DEPL 0xBB /* int8_t */ - -#define P60DOCK_HK_SIZE 0xBC - -extern const param_table_t p60dock_hk[]; -extern const int p60dock_hk_count; - -#endif /* P60DOCK_HK_H_ */ diff --git a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_param.h b/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_param.h deleted file mode 100644 index 05dac011..00000000 --- a/gomspace/p60-dock_client/include/gs/p60-dock/param/p60dock_param.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef P60DOCK_PARAM_H_ -#define P60DOCK_PARAM_H_ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include - -/** - * Define memory space - */ -#define P60DOCK_NAME_SIZE 8 - -#define P60DOCK_OUT_NAME(i) (0x00 + (P60DOCK_NAME_SIZE * i)) /* 13 * 8 */ -#define P60DOCK_OUT_EN(i) (0x68 + (i)) /* 13 * uint8_t */ -#define P60DOCK_OUT_ON_CNT(i) (0x76 + (2 * i)) /* 13 * uint16_t */ -#define P60DOCK_OUT_OFF_CNT(i) (0x90 + (2 * i)) /* 13 * uint16_t */ - -#define P60DOCK_INIT_OUT_NORM(i) (0xAA + (i)) /* 13 * uint8_t */ -#define P60DOCK_INIT_OUT_SAFE(i) (0xB7 + (i)) /* 13 * uint8_t */ -#define P60DOCK_INIT_ON_DELAY(i) (0xC4 + (2 * i)) /* 13 * uint16_t */ -#define P60DOCK_INIT_OFF_DELAY(i) (0xDE + (2 * i)) /* 13 * uint16_t */ - -#define P60DOCK_CUR_LU_LIM(i) (0xF8 + (2 * i)) /* 13 * uint16_t */ -#define P60DOCK_CUR_LIM(i) (0x112 + (2 * i)) /* 13 * uint16_t */ -#define P60DOCK_CUR_EMA(i) (0x12C + (2 * i)) /* 13 * uint16_t */ -#define P60DOCK_CUR_EMA_GAIN 0x148 - -#define P60DOCK_VCC_LINK(i) (0x14C + (i)) /* 4 * uint8_t */ -#define P60DOCK_VCC_VBAT_LINK(i) (0x150 + (i)) /* 4 * uint8_t */ - -#define P60DOCK_BATTERY_PACK 0x154 - -#define P60DOCK_BATT_HWMAX 0x156 -#define P60DOCK_BATT_MAX 0x158 -#define P60DOCK_BATT_NORM 0x15A -#define P60DOCK_BATT_SAFE 0x15C -#define P60DOCK_BATT_CRIT 0x15E - -#define P60DOCK_BP_HEATERMODE 0x160 -#define P60DOCK_BP_HEATER_LOW 0x162 -#define P60DOCK_BP_HEATER_HIGH 0x164 - -#define P60DOCK_WDTI2C_RST 0x166 -#define P60DOCK_WDTCAN_RST 0x167 -#define P60DOCK_WDTI2C 0x168 -#define P60DOCK_WDTCAN 0x16C -#define P60DOCK_WDTCSP(i) (0x170 + (4 * i)) /* 2 * uint32_t */ -#define P60DOCK_WDTCSP_PING_FAIL(i) (0x178 + (i)) /* 2 * uint8_t */ -#define P60DOCK_WDTCSP_CHAN(i) (0x17A + (i)) /* 2 * uint8_t */ -#define P60DOCK_WDTCSP_ADDR(i) (0x17C + (i)) /* 2 * uint8_t */ - -#define P60DOCK_P60ACU_CHAN(i) (0x17E + (i)) /* 2 * uint8_t */ -#define P60DOCK_P60ACU_ADDR(i) (0x180 + (i)) /* 2 * uint8_t */ -#define P60DOCK_P60PDU_CHAN(i) (0x182 + (i)) /* 4 * uint8_t */ -#define P60DOCK_P60PDU_ADDR(i) (0x186 + (i)) /* 4 * uint8_t */ - -#define P60DOCK_CONV_5V0_EN 0x18A - -#define P60DOCK_ANT6_ADDR(i) (0x190 + (i)) /* 2 * uint8_t */ -#define P60DOCK_AR6_ADDR(i) (0x194 + (i)) /* 4 * uint8_t */ -#define P60DOCK_DEPL_DELAY 0x198 /* uint32_t*/ - -/** Define the memory size */ -#define P60DOCK_PARAM_SIZE 0x19C - -extern const param_table_t p60dock_config[]; -extern const int p60dock_config_count; - -#endif /* P60DOCK_PARAM_H_ */ diff --git a/gomspace/p60-dock_client/src/p60dock_client.c b/gomspace/p60-dock_client/src/p60dock_client.c deleted file mode 100644 index 2fa3232b..00000000 --- a/gomspace/p60-dock_client/src/p60dock_client.c +++ /dev/null @@ -1,147 +0,0 @@ -/* Copyright (c) 2013-2018 GomSpace A/S. All rights reserved. */ - -#include -#include -#include -#include -#include -#include - -/** - * Setup info about config parameters - */ -const param_table_t p60dock_config[] = { - {.name = "out_name", .addr = P60DOCK_OUT_NAME(0), .type = PARAM_STRING, .size = P60DOCK_NAME_SIZE, .count = 13}, - {.name = "out_en", .addr = P60DOCK_OUT_EN(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 13}, - {.name = "out_on_cnt", .addr = P60DOCK_OUT_ON_CNT(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, - {.name = "out_off_cnt", .addr = P60DOCK_OUT_OFF_CNT(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, - - {.name = "init_out_norm", .addr = P60DOCK_INIT_OUT_NORM(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 13}, - {.name = "init_out_safe", .addr = P60DOCK_INIT_OUT_SAFE(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 13}, - {.name = "init_on_dly", .addr = P60DOCK_INIT_ON_DELAY(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, - {.name = "init_off_dly", .addr = P60DOCK_INIT_OFF_DELAY(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, - - {.name = "cur_lu_lim", .addr = P60DOCK_CUR_LU_LIM(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, - {.name = "cur_lim", .addr = P60DOCK_CUR_LIM(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, - {.name = "cur_ema", .addr = P60DOCK_CUR_EMA(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, - {.name = "cur_ema_gain", .addr = P60DOCK_CUR_EMA_GAIN, .type = PARAM_FLOAT, .size = sizeof(float)}, - - {.name = "vcc_vbat_link", .addr = P60DOCK_VCC_VBAT_LINK(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 4}, - {.name = "vcc_link", .addr = P60DOCK_VCC_LINK(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 4}, - - {.name = "batt_pack", .addr = P60DOCK_BATTERY_PACK, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - - {.name = "batt_hwmax", .addr = P60DOCK_BATT_HWMAX, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, - {.name = "batt_max", .addr = P60DOCK_BATT_MAX, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, - {.name = "batt_norm", .addr = P60DOCK_BATT_NORM, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, - {.name = "batt_safe", .addr = P60DOCK_BATT_SAFE, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, - {.name = "batt_crit", .addr = P60DOCK_BATT_CRIT, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, - - {.name = "bp_heat_mode", .addr = P60DOCK_BP_HEATERMODE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "bp_heat_low", .addr = P60DOCK_BP_HEATER_LOW, .type = PARAM_INT16, .size = sizeof(int16_t)}, - {.name = "bp_heat_high", .addr = P60DOCK_BP_HEATER_HIGH, .type = PARAM_INT16, .size = sizeof(int16_t)}, - - {.name = "wdt_i2c_rst", .addr = P60DOCK_WDTI2C_RST, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "wdt_can_rst", .addr = P60DOCK_WDTCAN_RST, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "wdt_i2c", .addr = P60DOCK_WDTI2C, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, - {.name = "wdt_can", .addr = P60DOCK_WDTCAN, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, - {.name = "wdt_csp", .addr = P60DOCK_WDTCSP(0), .type = PARAM_UINT32, .size = sizeof(uint32_t), .count = 2}, - {.name = "wdt_csp_ping", .addr = P60DOCK_WDTCSP_PING_FAIL(0),.type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 2}, - {.name = "wdt_csp_chan", .addr = P60DOCK_WDTCSP_CHAN(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 2}, - {.name = "wdt_csp_addr", .addr = P60DOCK_WDTCSP_ADDR(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 2}, - - {.name = "p60acu_chan", .addr = P60DOCK_P60ACU_CHAN(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 2}, - {.name = "p60acu_addr", .addr = P60DOCK_P60ACU_ADDR(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 2}, - {.name = "p60pdu_chan", .addr = P60DOCK_P60PDU_CHAN(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 4}, - {.name = "p60pdu_addr", .addr = P60DOCK_P60PDU_ADDR(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 4}, - - {.name = "conv_5v_en", .addr = P60DOCK_CONV_5V0_EN, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - - {.name = "ant6_addr", .addr = P60DOCK_ANT6_ADDR(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 2}, - {.name = "ar6_addr", .addr = P60DOCK_AR6_ADDR(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 4}, - - {.name = "depl_delay", .addr = P60DOCK_DEPL_DELAY, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, -}; - -const int p60dock_config_count = sizeof(p60dock_config) / sizeof(p60dock_config[0]); - -/** - * Setup info about calibration parameters - */ -const param_table_t p60dock_calibration[] = { - {.name = "gain_v_out", .addr = P60DOCK_CAL_GAIN_V_OUT(0), .type = PARAM_FLOAT, .size = sizeof(float), .count = 13}, - {.name = "gain_c_out", .addr = P60DOCK_CAL_GAIN_C_OUT(0), .type = PARAM_FLOAT, .size = sizeof(float), .count = 13}, - {.name = "offs_c_out", .addr = P60DOCK_CAL_OFFSET_C_OUT(0),.type = PARAM_INT16, .size = sizeof(int16_t), .count = 13}, - {.name = "vref", .addr = P60DOCK_CAL_VREF, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, - {.name = "gain_vbat_v", .addr = P60DOCK_CAL_GAIN_VBAT_V, .type = PARAM_FLOAT, .size = sizeof(float)}, - {.name = "gain_vcc_c", .addr = P60DOCK_CAL_GAIN_VCC_C, .type = PARAM_FLOAT, .size = sizeof(float)}, - {.name = "offs_vcc_c", .addr = P60DOCK_CAL_OFFSET_VCC_C, .type = PARAM_INT16, .size = sizeof(int16_t)}, - {.name = "gain_aux1", .addr = P60DOCK_CAL_GAIN_AUX1, .type = PARAM_FLOAT, .size = sizeof(float)}, - {.name = "gain_aux2", .addr = P60DOCK_CAL_GAIN_AUX2, .type = PARAM_FLOAT, .size = sizeof(float)}, - {.name = "offs_aux1", .addr = P60DOCK_CAL_OFFSET_AUX1, .type = PARAM_INT16, .size = sizeof(int16_t)}, - {.name = "offs_aux2", .addr = P60DOCK_CAL_OFFSET_AUX2, .type = PARAM_INT16, .size = sizeof(int16_t)}, - {.name = "gain_batt_v", .addr = P60DOCK_CAL_GAIN_BATT_V, .type = PARAM_FLOAT, .size = sizeof(float)}, - {.name = "gain_batt_chg", .addr = P60DOCK_CAL_GAIN_BATT_CHRG, .type = PARAM_FLOAT, .size = sizeof(float)}, - {.name = "offs_batt_chg", .addr = P60DOCK_CAL_OFFS_BATT_CHRG, .type = PARAM_INT16, .size = sizeof(int16_t)}, - {.name = "gain_batt_dis", .addr = P60DOCK_CAL_GAIN_BATT_DIS, .type = PARAM_FLOAT, .size = sizeof(float)}, - {.name = "offs_batt_dis", .addr = P60DOCK_CAL_OFFS_BATT_DIS, .type = PARAM_INT16, .size = sizeof(int16_t)}, -}; - -const int p60dock_cal_count = sizeof(p60dock_calibration) / sizeof(p60dock_calibration[0]); - -/** - * Setup info about hk parameters - */ -const param_table_t p60dock_hk[] = { - {.name = "c_out", .addr = P60DOCK_HK_C_OUT(0), .type = PARAM_INT16, .size = sizeof(int16_t), .count = 13}, - {.name = "v_out", .addr = P60DOCK_HK_V_OUT(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13}, - {.name = "out_en", .addr = P60DOCK_HK_OUT_EN(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 13}, - {.name = "temp", .addr = P60DOCK_HK_TEMP(0), .type = PARAM_INT16, .size = sizeof(int16_t), .count = 2}, - {.name = "bootcause", .addr = P60DOCK_HK_BOOT_CAUSE, .type = PARAM_UINT32, .size = sizeof(uint32_t), .flags = PARAM_F_READONLY}, - {.name = "bootcnt", .addr = P60DOCK_HK_BOOT_COUNTER, .type = PARAM_UINT32, .size = sizeof(uint32_t), .flags = PARAM_F_PERSIST}, - {.name = "uptime", .addr = P60DOCK_HK_UPTIME, .type = PARAM_UINT32, .size = sizeof(uint32_t), .flags = PARAM_F_READONLY}, - {.name = "resetcause", .addr = P60DOCK_HK_RESET_CAUSE, .type = PARAM_UINT16, .size = sizeof(uint16_t), .flags = PARAM_F_PERSIST}, - {.name = "batt_mode", .addr = P60DOCK_HK_BATT_MODE, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "heater_on", .addr = P60DOCK_HK_HEATER_ON, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "conv_5v_en", .addr = P60DOCK_HK_CONV_5V0_EN, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "latchup", .addr = P60DOCK_HK_LATCHUP(0), .type = PARAM_UINT16, .size = sizeof(uint16_t), .count = 13, .flags = PARAM_F_PERSIST}, - {.name = "vbat_v", .addr = P60DOCK_HK_VBAT_V, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, - {.name = "vcc_c", .addr = P60DOCK_HK_VCC_C, .type = PARAM_INT16, .size = sizeof(int16_t)}, - {.name = "batt_c", .addr = P60DOCK_HK_BATTERY_C, .type = PARAM_INT16, .size = sizeof(int16_t)}, - {.name = "batt_v", .addr = P60DOCK_HK_BATTERY_V, .type = PARAM_UINT16, .size = sizeof(uint16_t)}, - {.name = "batt_temp", .addr = P60DOCK_HK_BP_TEMP(0), .type = PARAM_INT16, .size = sizeof(int16_t), .count = 2}, - {.name = "device_type", .addr = P60DOCK_HK_DEVICE_TYPE(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 8}, - {.name = "device_status", .addr = P60DOCK_HK_DEVICE_STATUS(0),.type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 8}, - {.name = "dearm_status", .addr = P60DOCK_HK_DEARM_STATUS, .type = PARAM_UINT8, .size = sizeof(uint8_t)}, - {.name = "wdt_cnt_gnd", .addr = P60DOCK_HK_CNT_WDTGND, .type = PARAM_UINT32, .size = sizeof(uint32_t), .flags = PARAM_F_PERSIST}, - {.name = "wdt_cnt_i2c", .addr = P60DOCK_HK_CNT_WDTI2C, .type = PARAM_UINT32, .size = sizeof(uint32_t), .flags = PARAM_F_PERSIST}, - {.name = "wdt_cnt_can", .addr = P60DOCK_HK_CNT_WDTCAN, .type = PARAM_UINT32, .size = sizeof(uint32_t), .flags = PARAM_F_PERSIST}, - {.name = "wdt_cnt_csp", .addr = P60DOCK_HK_CNT_WDTCSP(0), .type = PARAM_UINT32, .size = sizeof(uint32_t), .count = 2, .flags = PARAM_F_PERSIST}, - {.name = "wdt_gnd_left", .addr = P60DOCK_HK_WDTGND_LEFT, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, - {.name = "wdt_i2c_left", .addr = P60DOCK_HK_WDTI2C_LEFT, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, - {.name = "wdt_can_left", .addr = P60DOCK_HK_WDTCAN_LEFT, .type = PARAM_UINT32, .size = sizeof(uint32_t)}, - {.name = "wdt_csp_left", .addr = P60DOCK_HK_WDTCSP_LEFT(0), .type = PARAM_UINT8, .size = sizeof(uint8_t), .count = 2}, - {.name = "batt_chrg", .addr = P60DOCK_HK_BATT_C_CHRG, .type = PARAM_INT16, .size = sizeof(int16_t)}, - {.name = "batt_dischrg", .addr = P60DOCK_HK_BATT_C_DISCHRG, .type = PARAM_INT16, .size = sizeof(int16_t)}, - {.name = "ant6_depl", .addr = P60DOCK_HK_ANT6_DEPL, .type = PARAM_INT8, .size = sizeof(int8_t)}, - {.name = "ar6_depl", .addr = P60DOCK_HK_AR6_DEPL, .type = PARAM_INT8, .size = sizeof(int8_t)}, -}; - -const int p60dock_hk_count = sizeof(p60dock_hk) / sizeof(p60dock_hk[0]); - -int p60dock_get_hk(param_index_t * mem, uint8_t node, uint32_t timeout) { - - mem->table = p60dock_hk; - mem->mem_id = P60DOCK_HK; - mem->count = p60dock_hk_count; - mem->size = P60DOCK_HK_SIZE; - int result = rparam_get_full_table(mem, node, P60_PORT_RPARAM, mem->mem_id, timeout); - - return (result == 0); - -} - -int p60dock_gndwdt_clear(uint8_t node, uint32_t timeout) { - uint8_t magic = 0x78; - return csp_transaction(CSP_PRIO_HIGH, node, P60_PORT_GNDWDT_RESET, timeout, &magic, 1, NULL, 0); -} diff --git a/gomspace/p60-dock_client/wscript b/gomspace/p60-dock_client/wscript deleted file mode 100644 index 8fdf39d6..00000000 --- a/gomspace/p60-dock_client/wscript +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. -# encoding: utf-8 - -import gs_gcc - -APPNAME = 'p60-dock_client' - - -def options(ctx): - gr = ctx.add_option_group('NanoPower-P60 Dock client options') - gr.add_option('--disable-p60-dock-cmd', action='store_true', help='Disable client cmd code for NanoPower-P60 Dock') - - -def configure(ctx): - ctx.env.append_unique('FILES_P60_DOCK_CLIENT', ['src/p60dock_client.c']) - if not ctx.options.disable_p60_dock_cmd: - ctx.env.append_unique('FILES_P60_DOCK_CLIENT', ['src/p60dock_cmd.c']) - - -def build(ctx): - gs_gcc.gs_call_handler(ctx, handler='param_gen_4_3', name=APPNAME, prefix='p60-dock', - generate_rst=True) - - public_include = APPNAME + '_h' - ctx(export_includes=['include', 'include/gs/p60-dock/param'], name=public_include) - - ctx.objects(source=ctx.path.ant_glob(ctx.env.FILES_P60_DOCK_CLIENT), - target=APPNAME, - use=['csp', 'gosh', 'param', 'param_client', 'p60_client', public_include]) - - -def gs_dist(ctx): - ctx.add_default_files(source_module=True) diff --git a/gomspace/libcsp/bindings/python/libcsp/__init__.py b/libcsp/bindings/python/libcsp/__init__.py similarity index 100% rename from gomspace/libcsp/bindings/python/libcsp/__init__.py rename to libcsp/bindings/python/libcsp/__init__.py diff --git a/gomspace/libcsp/doc/example.rst b/libcsp/doc/example.rst similarity index 100% rename from gomspace/libcsp/doc/example.rst rename to libcsp/doc/example.rst diff --git a/gomspace/libcsp/doc/history.rst b/libcsp/doc/history.rst similarity index 100% rename from gomspace/libcsp/doc/history.rst rename to libcsp/doc/history.rst diff --git a/gomspace/libcsp/doc/interfaces.rst b/libcsp/doc/interfaces.rst similarity index 100% rename from gomspace/libcsp/doc/interfaces.rst rename to libcsp/doc/interfaces.rst diff --git a/gomspace/libcsp/doc/libcsp.rst b/libcsp/doc/libcsp.rst similarity index 100% rename from gomspace/libcsp/doc/libcsp.rst rename to libcsp/doc/libcsp.rst diff --git a/gomspace/libcsp/doc/memory.rst b/libcsp/doc/memory.rst similarity index 100% rename from gomspace/libcsp/doc/memory.rst rename to libcsp/doc/memory.rst diff --git a/gomspace/libcsp/doc/mtu.rst b/libcsp/doc/mtu.rst similarity index 100% rename from gomspace/libcsp/doc/mtu.rst rename to libcsp/doc/mtu.rst diff --git a/gomspace/libcsp/doc/protocolstack.rst b/libcsp/doc/protocolstack.rst similarity index 100% rename from gomspace/libcsp/doc/protocolstack.rst rename to libcsp/doc/protocolstack.rst diff --git a/gomspace/libcsp/doc/structure.rst b/libcsp/doc/structure.rst similarity index 100% rename from gomspace/libcsp/doc/structure.rst rename to libcsp/doc/structure.rst diff --git a/gomspace/libcsp/doc/topology.rst b/libcsp/doc/topology.rst similarity index 100% rename from gomspace/libcsp/doc/topology.rst rename to libcsp/doc/topology.rst diff --git a/gomspace/libcsp/examples/csp_if_fifo.c b/libcsp/examples/csp_if_fifo.c similarity index 100% rename from gomspace/libcsp/examples/csp_if_fifo.c rename to libcsp/examples/csp_if_fifo.c diff --git a/gomspace/libcsp/examples/csp_if_fifo_windows.c b/libcsp/examples/csp_if_fifo_windows.c similarity index 100% rename from gomspace/libcsp/examples/csp_if_fifo_windows.c rename to libcsp/examples/csp_if_fifo_windows.c diff --git a/gomspace/libcsp/examples/kiss.c b/libcsp/examples/kiss.c similarity index 100% rename from gomspace/libcsp/examples/kiss.c rename to libcsp/examples/kiss.c diff --git a/gomspace/libcsp/examples/python_bindings_example_client.py b/libcsp/examples/python_bindings_example_client.py similarity index 100% rename from gomspace/libcsp/examples/python_bindings_example_client.py rename to libcsp/examples/python_bindings_example_client.py diff --git a/gomspace/libcsp/examples/python_bindings_example_client_can.py b/libcsp/examples/python_bindings_example_client_can.py similarity index 100% rename from gomspace/libcsp/examples/python_bindings_example_client_can.py rename to libcsp/examples/python_bindings_example_client_can.py diff --git a/gomspace/libcsp/examples/python_bindings_example_server.py b/libcsp/examples/python_bindings_example_server.py similarity index 100% rename from gomspace/libcsp/examples/python_bindings_example_server.py rename to libcsp/examples/python_bindings_example_server.py diff --git a/gomspace/libcsp/examples/simple.c b/libcsp/examples/simple.c similarity index 100% rename from gomspace/libcsp/examples/simple.c rename to libcsp/examples/simple.c diff --git a/gomspace/libcsp/examples/zmqproxy.c b/libcsp/examples/zmqproxy.c similarity index 100% rename from gomspace/libcsp/examples/zmqproxy.c rename to libcsp/examples/zmqproxy.c diff --git a/gomspace/libcsp/include/csp/arch/csp_clock.h b/libcsp/include/csp/arch/csp_clock.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/csp_clock.h rename to libcsp/include/csp/arch/csp_clock.h diff --git a/gomspace/libcsp/include/csp/arch/csp_malloc.h b/libcsp/include/csp/arch/csp_malloc.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/csp_malloc.h rename to libcsp/include/csp/arch/csp_malloc.h diff --git a/gomspace/libcsp/include/csp/arch/csp_queue.h b/libcsp/include/csp/arch/csp_queue.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/csp_queue.h rename to libcsp/include/csp/arch/csp_queue.h diff --git a/gomspace/libcsp/include/csp/arch/csp_semaphore.h b/libcsp/include/csp/arch/csp_semaphore.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/csp_semaphore.h rename to libcsp/include/csp/arch/csp_semaphore.h diff --git a/gomspace/libcsp/include/csp/arch/csp_system.h b/libcsp/include/csp/arch/csp_system.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/csp_system.h rename to libcsp/include/csp/arch/csp_system.h diff --git a/gomspace/libcsp/include/csp/arch/csp_thread.h b/libcsp/include/csp/arch/csp_thread.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/csp_thread.h rename to libcsp/include/csp/arch/csp_thread.h diff --git a/gomspace/libcsp/include/csp/arch/csp_time.h b/libcsp/include/csp/arch/csp_time.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/csp_time.h rename to libcsp/include/csp/arch/csp_time.h diff --git a/gomspace/libcsp/include/csp/arch/posix/pthread_queue.h b/libcsp/include/csp/arch/posix/pthread_queue.h similarity index 100% rename from gomspace/libcsp/include/csp/arch/posix/pthread_queue.h rename to libcsp/include/csp/arch/posix/pthread_queue.h diff --git a/gomspace/libcsp/include/csp/crypto/csp_hmac.h b/libcsp/include/csp/crypto/csp_hmac.h similarity index 100% rename from gomspace/libcsp/include/csp/crypto/csp_hmac.h rename to libcsp/include/csp/crypto/csp_hmac.h diff --git a/gomspace/libcsp/include/csp/crypto/csp_sha1.h b/libcsp/include/csp/crypto/csp_sha1.h similarity index 100% rename from gomspace/libcsp/include/csp/crypto/csp_sha1.h rename to libcsp/include/csp/crypto/csp_sha1.h diff --git a/gomspace/libcsp/include/csp/crypto/csp_xtea.h b/libcsp/include/csp/crypto/csp_xtea.h similarity index 100% rename from gomspace/libcsp/include/csp/crypto/csp_xtea.h rename to libcsp/include/csp/crypto/csp_xtea.h diff --git a/gomspace/libcsp/include/csp/csp.h b/libcsp/include/csp/csp.h similarity index 100% rename from gomspace/libcsp/include/csp/csp.h rename to libcsp/include/csp/csp.h diff --git a/gomspace/libcsp/include/csp/csp_autoconfig.h b/libcsp/include/csp/csp_autoconfig.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_autoconfig.h rename to libcsp/include/csp/csp_autoconfig.h diff --git a/gomspace/libcsp/include/csp/csp_buffer.h b/libcsp/include/csp/csp_buffer.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_buffer.h rename to libcsp/include/csp/csp_buffer.h diff --git a/gomspace/libcsp/include/csp/csp_cmp.h b/libcsp/include/csp/csp_cmp.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_cmp.h rename to libcsp/include/csp/csp_cmp.h diff --git a/gomspace/libcsp/include/csp/csp_crc32.h b/libcsp/include/csp/csp_crc32.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_crc32.h rename to libcsp/include/csp/csp_crc32.h diff --git a/gomspace/libcsp/include/csp/csp_debug.h b/libcsp/include/csp/csp_debug.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_debug.h rename to libcsp/include/csp/csp_debug.h diff --git a/gomspace/libcsp/include/csp/csp_endian.h b/libcsp/include/csp/csp_endian.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_endian.h rename to libcsp/include/csp/csp_endian.h diff --git a/gomspace/libcsp/include/csp/csp_error.h b/libcsp/include/csp/csp_error.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_error.h rename to libcsp/include/csp/csp_error.h diff --git a/gomspace/libcsp/include/csp/csp_iflist.h b/libcsp/include/csp/csp_iflist.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_iflist.h rename to libcsp/include/csp/csp_iflist.h diff --git a/gomspace/libcsp/include/csp/csp_interface.h b/libcsp/include/csp/csp_interface.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_interface.h rename to libcsp/include/csp/csp_interface.h diff --git a/gomspace/libcsp/include/csp/csp_platform.h b/libcsp/include/csp/csp_platform.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_platform.h rename to libcsp/include/csp/csp_platform.h diff --git a/gomspace/libcsp/include/csp/csp_rtable.h b/libcsp/include/csp/csp_rtable.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_rtable.h rename to libcsp/include/csp/csp_rtable.h diff --git a/gomspace/libcsp/include/csp/csp_types.h b/libcsp/include/csp/csp_types.h similarity index 100% rename from gomspace/libcsp/include/csp/csp_types.h rename to libcsp/include/csp/csp_types.h diff --git a/gomspace/libcsp/include/csp/drivers/can_socketcan.h b/libcsp/include/csp/drivers/can_socketcan.h similarity index 100% rename from gomspace/libcsp/include/csp/drivers/can_socketcan.h rename to libcsp/include/csp/drivers/can_socketcan.h diff --git a/gomspace/libcsp/include/csp/drivers/i2c.h b/libcsp/include/csp/drivers/i2c.h similarity index 100% rename from gomspace/libcsp/include/csp/drivers/i2c.h rename to libcsp/include/csp/drivers/i2c.h diff --git a/gomspace/libcsp/include/csp/drivers/usart.h b/libcsp/include/csp/drivers/usart.h similarity index 100% rename from gomspace/libcsp/include/csp/drivers/usart.h rename to libcsp/include/csp/drivers/usart.h diff --git a/gomspace/libcsp/include/csp/interfaces/csp_if_can.h b/libcsp/include/csp/interfaces/csp_if_can.h similarity index 100% rename from gomspace/libcsp/include/csp/interfaces/csp_if_can.h rename to libcsp/include/csp/interfaces/csp_if_can.h diff --git a/gomspace/libcsp/include/csp/interfaces/csp_if_i2c.h b/libcsp/include/csp/interfaces/csp_if_i2c.h similarity index 100% rename from gomspace/libcsp/include/csp/interfaces/csp_if_i2c.h rename to libcsp/include/csp/interfaces/csp_if_i2c.h diff --git a/gomspace/libcsp/include/csp/interfaces/csp_if_kiss.h b/libcsp/include/csp/interfaces/csp_if_kiss.h similarity index 100% rename from gomspace/libcsp/include/csp/interfaces/csp_if_kiss.h rename to libcsp/include/csp/interfaces/csp_if_kiss.h diff --git a/gomspace/libcsp/include/csp/interfaces/csp_if_lo.h b/libcsp/include/csp/interfaces/csp_if_lo.h similarity index 100% rename from gomspace/libcsp/include/csp/interfaces/csp_if_lo.h rename to libcsp/include/csp/interfaces/csp_if_lo.h diff --git a/gomspace/libcsp/include/csp/interfaces/csp_if_zmqhub.h b/libcsp/include/csp/interfaces/csp_if_zmqhub.h similarity index 100% rename from gomspace/libcsp/include/csp/interfaces/csp_if_zmqhub.h rename to libcsp/include/csp/interfaces/csp_if_zmqhub.h diff --git a/libcsp/libcsp.mk b/libcsp/libcsp.mk new file mode 100644 index 00000000..af27f9f1 --- /dev/null +++ b/libcsp/libcsp.mk @@ -0,0 +1,12 @@ +CSRC += $(wildcard $(CURRENTPATH)/src/drivers/can/*.c) +CSRC += $(wildcard $(CURRENTPATH)/src/*.c) +CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/interfaces/*.c) +CSRC += $(wildcard $(CURRENTPATH)/src/rtable/csp_rtable_cidr.c) +CSRC += $(wildcard $(CURRENTPATH)/src/crypto/*.c) +CSRC += $(wildcard $(CURRENTPATH)/src/arch/posix/*.c) +CSRC += $(wildcard $(CURRENTPATH)/src/transport/*.c) + +INCLUDES += $(CURRENTPATH)/include +INCLUDES += $(CURRENTPATH)/include/csp +INCLUDES += $(CURRENTPATH)/include/csp/crypto +INCLUDES += $(CURRENTPATH) \ No newline at end of file diff --git a/gomspace/libcsp/src/arch/freertos/csp_malloc.c b/libcsp/src/arch/freertos/csp_malloc.c similarity index 100% rename from gomspace/libcsp/src/arch/freertos/csp_malloc.c rename to libcsp/src/arch/freertos/csp_malloc.c diff --git a/gomspace/libcsp/src/arch/freertos/csp_queue.c b/libcsp/src/arch/freertos/csp_queue.c similarity index 100% rename from gomspace/libcsp/src/arch/freertos/csp_queue.c rename to libcsp/src/arch/freertos/csp_queue.c diff --git a/gomspace/libcsp/src/arch/freertos/csp_semaphore.c b/libcsp/src/arch/freertos/csp_semaphore.c similarity index 100% rename from gomspace/libcsp/src/arch/freertos/csp_semaphore.c rename to libcsp/src/arch/freertos/csp_semaphore.c diff --git a/gomspace/libcsp/src/arch/freertos/csp_system.c b/libcsp/src/arch/freertos/csp_system.c similarity index 100% rename from gomspace/libcsp/src/arch/freertos/csp_system.c rename to libcsp/src/arch/freertos/csp_system.c diff --git a/gomspace/libcsp/src/arch/freertos/csp_thread.c b/libcsp/src/arch/freertos/csp_thread.c similarity index 100% rename from gomspace/libcsp/src/arch/freertos/csp_thread.c rename to libcsp/src/arch/freertos/csp_thread.c diff --git a/gomspace/libcsp/src/arch/freertos/csp_time.c b/libcsp/src/arch/freertos/csp_time.c similarity index 100% rename from gomspace/libcsp/src/arch/freertos/csp_time.c rename to libcsp/src/arch/freertos/csp_time.c diff --git a/gomspace/libcsp/src/arch/macosx/csp_malloc.c b/libcsp/src/arch/macosx/csp_malloc.c similarity index 100% rename from gomspace/libcsp/src/arch/macosx/csp_malloc.c rename to libcsp/src/arch/macosx/csp_malloc.c diff --git a/gomspace/libcsp/src/arch/macosx/csp_queue.c b/libcsp/src/arch/macosx/csp_queue.c similarity index 100% rename from gomspace/libcsp/src/arch/macosx/csp_queue.c rename to libcsp/src/arch/macosx/csp_queue.c diff --git a/gomspace/libcsp/src/arch/macosx/csp_semaphore.c b/libcsp/src/arch/macosx/csp_semaphore.c similarity index 100% rename from gomspace/libcsp/src/arch/macosx/csp_semaphore.c rename to libcsp/src/arch/macosx/csp_semaphore.c diff --git a/gomspace/libcsp/src/arch/macosx/csp_system.c b/libcsp/src/arch/macosx/csp_system.c similarity index 100% rename from gomspace/libcsp/src/arch/macosx/csp_system.c rename to libcsp/src/arch/macosx/csp_system.c diff --git a/gomspace/libcsp/src/arch/macosx/csp_thread.c b/libcsp/src/arch/macosx/csp_thread.c similarity index 100% rename from gomspace/libcsp/src/arch/macosx/csp_thread.c rename to libcsp/src/arch/macosx/csp_thread.c diff --git a/gomspace/libcsp/src/arch/macosx/csp_time.c b/libcsp/src/arch/macosx/csp_time.c similarity index 100% rename from gomspace/libcsp/src/arch/macosx/csp_time.c rename to libcsp/src/arch/macosx/csp_time.c diff --git a/gomspace/libcsp/src/arch/macosx/pthread_queue.c b/libcsp/src/arch/macosx/pthread_queue.c similarity index 100% rename from gomspace/libcsp/src/arch/macosx/pthread_queue.c rename to libcsp/src/arch/macosx/pthread_queue.c diff --git a/gomspace/libcsp/src/arch/posix/csp_malloc.c b/libcsp/src/arch/posix/csp_malloc.c similarity index 100% rename from gomspace/libcsp/src/arch/posix/csp_malloc.c rename to libcsp/src/arch/posix/csp_malloc.c diff --git a/gomspace/libcsp/src/arch/posix/csp_queue.c b/libcsp/src/arch/posix/csp_queue.c similarity index 100% rename from gomspace/libcsp/src/arch/posix/csp_queue.c rename to libcsp/src/arch/posix/csp_queue.c diff --git a/gomspace/libcsp/src/arch/posix/csp_semaphore.c b/libcsp/src/arch/posix/csp_semaphore.c similarity index 100% rename from gomspace/libcsp/src/arch/posix/csp_semaphore.c rename to libcsp/src/arch/posix/csp_semaphore.c diff --git a/gomspace/libcsp/src/arch/posix/csp_system.c b/libcsp/src/arch/posix/csp_system.c similarity index 100% rename from gomspace/libcsp/src/arch/posix/csp_system.c rename to libcsp/src/arch/posix/csp_system.c diff --git a/gomspace/libcsp/src/arch/posix/csp_thread.c b/libcsp/src/arch/posix/csp_thread.c similarity index 100% rename from gomspace/libcsp/src/arch/posix/csp_thread.c rename to libcsp/src/arch/posix/csp_thread.c diff --git a/gomspace/libcsp/src/arch/posix/csp_time.c b/libcsp/src/arch/posix/csp_time.c similarity index 100% rename from gomspace/libcsp/src/arch/posix/csp_time.c rename to libcsp/src/arch/posix/csp_time.c diff --git a/gomspace/libcsp/src/arch/posix/pthread_queue.c b/libcsp/src/arch/posix/pthread_queue.c similarity index 100% rename from gomspace/libcsp/src/arch/posix/pthread_queue.c rename to libcsp/src/arch/posix/pthread_queue.c diff --git a/gomspace/libcsp/src/arch/windows/README b/libcsp/src/arch/windows/README similarity index 100% rename from gomspace/libcsp/src/arch/windows/README rename to libcsp/src/arch/windows/README diff --git a/gomspace/libcsp/src/arch/windows/csp_malloc.c b/libcsp/src/arch/windows/csp_malloc.c similarity index 100% rename from gomspace/libcsp/src/arch/windows/csp_malloc.c rename to libcsp/src/arch/windows/csp_malloc.c diff --git a/gomspace/libcsp/src/arch/windows/csp_queue.c b/libcsp/src/arch/windows/csp_queue.c similarity index 100% rename from gomspace/libcsp/src/arch/windows/csp_queue.c rename to libcsp/src/arch/windows/csp_queue.c diff --git a/gomspace/libcsp/src/arch/windows/csp_semaphore.c b/libcsp/src/arch/windows/csp_semaphore.c similarity index 100% rename from gomspace/libcsp/src/arch/windows/csp_semaphore.c rename to libcsp/src/arch/windows/csp_semaphore.c diff --git a/gomspace/libcsp/src/arch/windows/csp_system.c b/libcsp/src/arch/windows/csp_system.c similarity index 100% rename from gomspace/libcsp/src/arch/windows/csp_system.c rename to libcsp/src/arch/windows/csp_system.c diff --git a/gomspace/libcsp/src/arch/windows/csp_thread.c b/libcsp/src/arch/windows/csp_thread.c similarity index 100% rename from gomspace/libcsp/src/arch/windows/csp_thread.c rename to libcsp/src/arch/windows/csp_thread.c diff --git a/gomspace/libcsp/src/arch/windows/csp_time.c b/libcsp/src/arch/windows/csp_time.c similarity index 100% rename from gomspace/libcsp/src/arch/windows/csp_time.c rename to libcsp/src/arch/windows/csp_time.c diff --git a/gomspace/libcsp/src/arch/windows/windows_glue.h b/libcsp/src/arch/windows/windows_glue.h similarity index 100% rename from gomspace/libcsp/src/arch/windows/windows_glue.h rename to libcsp/src/arch/windows/windows_glue.h diff --git a/gomspace/libcsp/src/arch/windows/windows_queue.c b/libcsp/src/arch/windows/windows_queue.c similarity index 100% rename from gomspace/libcsp/src/arch/windows/windows_queue.c rename to libcsp/src/arch/windows/windows_queue.c diff --git a/gomspace/libcsp/src/arch/windows/windows_queue.h b/libcsp/src/arch/windows/windows_queue.h similarity index 100% rename from gomspace/libcsp/src/arch/windows/windows_queue.h rename to libcsp/src/arch/windows/windows_queue.h diff --git a/gomspace/libcsp/src/bindings/python/pycsp.c b/libcsp/src/bindings/python/pycsp.c similarity index 100% rename from gomspace/libcsp/src/bindings/python/pycsp.c rename to libcsp/src/bindings/python/pycsp.c diff --git a/gomspace/libcsp/src/crypto/csp_hmac.c b/libcsp/src/crypto/csp_hmac.c similarity index 100% rename from gomspace/libcsp/src/crypto/csp_hmac.c rename to libcsp/src/crypto/csp_hmac.c diff --git a/gomspace/libcsp/src/crypto/csp_sha1.c b/libcsp/src/crypto/csp_sha1.c similarity index 100% rename from gomspace/libcsp/src/crypto/csp_sha1.c rename to libcsp/src/crypto/csp_sha1.c diff --git a/gomspace/libcsp/src/crypto/csp_xtea.c b/libcsp/src/crypto/csp_xtea.c similarity index 100% rename from gomspace/libcsp/src/crypto/csp_xtea.c rename to libcsp/src/crypto/csp_xtea.c diff --git a/gomspace/libcsp/src/csp_bridge.c b/libcsp/src/csp_bridge.c similarity index 100% rename from gomspace/libcsp/src/csp_bridge.c rename to libcsp/src/csp_bridge.c diff --git a/gomspace/libcsp/src/csp_buffer.c b/libcsp/src/csp_buffer.c similarity index 100% rename from gomspace/libcsp/src/csp_buffer.c rename to libcsp/src/csp_buffer.c diff --git a/gomspace/libcsp/src/csp_conn.c b/libcsp/src/csp_conn.c similarity index 100% rename from gomspace/libcsp/src/csp_conn.c rename to libcsp/src/csp_conn.c diff --git a/gomspace/libcsp/src/csp_conn.h b/libcsp/src/csp_conn.h similarity index 100% rename from gomspace/libcsp/src/csp_conn.h rename to libcsp/src/csp_conn.h diff --git a/gomspace/libcsp/src/csp_crc32.c b/libcsp/src/csp_crc32.c similarity index 100% rename from gomspace/libcsp/src/csp_crc32.c rename to libcsp/src/csp_crc32.c diff --git a/gomspace/libcsp/src/csp_debug.c b/libcsp/src/csp_debug.c similarity index 100% rename from gomspace/libcsp/src/csp_debug.c rename to libcsp/src/csp_debug.c diff --git a/gomspace/libcsp/src/csp_dedup.c b/libcsp/src/csp_dedup.c similarity index 100% rename from gomspace/libcsp/src/csp_dedup.c rename to libcsp/src/csp_dedup.c diff --git a/gomspace/libcsp/src/csp_dedup.h b/libcsp/src/csp_dedup.h similarity index 100% rename from gomspace/libcsp/src/csp_dedup.h rename to libcsp/src/csp_dedup.h diff --git a/gomspace/libcsp/src/csp_endian.c b/libcsp/src/csp_endian.c similarity index 100% rename from gomspace/libcsp/src/csp_endian.c rename to libcsp/src/csp_endian.c diff --git a/gomspace/libcsp/src/csp_hex_dump.c b/libcsp/src/csp_hex_dump.c similarity index 100% rename from gomspace/libcsp/src/csp_hex_dump.c rename to libcsp/src/csp_hex_dump.c diff --git a/gomspace/libcsp/src/csp_iflist.c b/libcsp/src/csp_iflist.c similarity index 100% rename from gomspace/libcsp/src/csp_iflist.c rename to libcsp/src/csp_iflist.c diff --git a/gomspace/libcsp/src/csp_io.c b/libcsp/src/csp_io.c similarity index 100% rename from gomspace/libcsp/src/csp_io.c rename to libcsp/src/csp_io.c diff --git a/gomspace/libcsp/src/csp_io.h b/libcsp/src/csp_io.h similarity index 100% rename from gomspace/libcsp/src/csp_io.h rename to libcsp/src/csp_io.h diff --git a/gomspace/libcsp/src/csp_port.c b/libcsp/src/csp_port.c similarity index 100% rename from gomspace/libcsp/src/csp_port.c rename to libcsp/src/csp_port.c diff --git a/gomspace/libcsp/src/csp_port.h b/libcsp/src/csp_port.h similarity index 100% rename from gomspace/libcsp/src/csp_port.h rename to libcsp/src/csp_port.h diff --git a/gomspace/libcsp/src/csp_promisc.c b/libcsp/src/csp_promisc.c similarity index 100% rename from gomspace/libcsp/src/csp_promisc.c rename to libcsp/src/csp_promisc.c diff --git a/gomspace/libcsp/src/csp_promisc.h b/libcsp/src/csp_promisc.h similarity index 100% rename from gomspace/libcsp/src/csp_promisc.h rename to libcsp/src/csp_promisc.h diff --git a/gomspace/libcsp/src/csp_qfifo.c b/libcsp/src/csp_qfifo.c similarity index 100% rename from gomspace/libcsp/src/csp_qfifo.c rename to libcsp/src/csp_qfifo.c diff --git a/gomspace/libcsp/src/csp_qfifo.h b/libcsp/src/csp_qfifo.h similarity index 100% rename from gomspace/libcsp/src/csp_qfifo.h rename to libcsp/src/csp_qfifo.h diff --git a/gomspace/libcsp/src/csp_route.c b/libcsp/src/csp_route.c similarity index 100% rename from gomspace/libcsp/src/csp_route.c rename to libcsp/src/csp_route.c diff --git a/gomspace/libcsp/src/csp_route.h b/libcsp/src/csp_route.h similarity index 100% rename from gomspace/libcsp/src/csp_route.h rename to libcsp/src/csp_route.h diff --git a/gomspace/libcsp/src/csp_service_handler.c b/libcsp/src/csp_service_handler.c similarity index 100% rename from gomspace/libcsp/src/csp_service_handler.c rename to libcsp/src/csp_service_handler.c diff --git a/gomspace/libcsp/src/csp_services.c b/libcsp/src/csp_services.c similarity index 100% rename from gomspace/libcsp/src/csp_services.c rename to libcsp/src/csp_services.c diff --git a/gomspace/libcsp/src/csp_sfp.c b/libcsp/src/csp_sfp.c similarity index 100% rename from gomspace/libcsp/src/csp_sfp.c rename to libcsp/src/csp_sfp.c diff --git a/gomspace/libcsp/src/drivers/can/can_socketcan.c b/libcsp/src/drivers/can/can_socketcan.c similarity index 100% rename from gomspace/libcsp/src/drivers/can/can_socketcan.c rename to libcsp/src/drivers/can/can_socketcan.c diff --git a/gomspace/libcsp/src/drivers/usart/usart_linux.c b/libcsp/src/drivers/usart/usart_linux.c similarity index 100% rename from gomspace/libcsp/src/drivers/usart/usart_linux.c rename to libcsp/src/drivers/usart/usart_linux.c diff --git a/gomspace/libcsp/src/drivers/usart/usart_windows.c b/libcsp/src/drivers/usart/usart_windows.c similarity index 100% rename from gomspace/libcsp/src/drivers/usart/usart_windows.c rename to libcsp/src/drivers/usart/usart_windows.c diff --git a/gomspace/libcsp/src/interfaces/csp_if_can.c b/libcsp/src/interfaces/csp_if_can.c similarity index 100% rename from gomspace/libcsp/src/interfaces/csp_if_can.c rename to libcsp/src/interfaces/csp_if_can.c diff --git a/gomspace/libcsp/src/interfaces/csp_if_can_pbuf.c b/libcsp/src/interfaces/csp_if_can_pbuf.c similarity index 100% rename from gomspace/libcsp/src/interfaces/csp_if_can_pbuf.c rename to libcsp/src/interfaces/csp_if_can_pbuf.c diff --git a/gomspace/libcsp/src/interfaces/csp_if_can_pbuf.h b/libcsp/src/interfaces/csp_if_can_pbuf.h similarity index 100% rename from gomspace/libcsp/src/interfaces/csp_if_can_pbuf.h rename to libcsp/src/interfaces/csp_if_can_pbuf.h diff --git a/gomspace/libcsp/src/interfaces/csp_if_i2c.c b/libcsp/src/interfaces/csp_if_i2c.c similarity index 100% rename from gomspace/libcsp/src/interfaces/csp_if_i2c.c rename to libcsp/src/interfaces/csp_if_i2c.c diff --git a/gomspace/libcsp/src/interfaces/csp_if_kiss.c b/libcsp/src/interfaces/csp_if_kiss.c similarity index 100% rename from gomspace/libcsp/src/interfaces/csp_if_kiss.c rename to libcsp/src/interfaces/csp_if_kiss.c diff --git a/gomspace/libcsp/src/interfaces/csp_if_lo.c b/libcsp/src/interfaces/csp_if_lo.c similarity index 100% rename from gomspace/libcsp/src/interfaces/csp_if_lo.c rename to libcsp/src/interfaces/csp_if_lo.c diff --git a/gomspace/libcsp/src/rtable/csp_rtable_cidr.c b/libcsp/src/rtable/csp_rtable_cidr.c similarity index 100% rename from gomspace/libcsp/src/rtable/csp_rtable_cidr.c rename to libcsp/src/rtable/csp_rtable_cidr.c diff --git a/gomspace/libcsp/src/rtable/csp_rtable_static.c b/libcsp/src/rtable/csp_rtable_static.c similarity index 100% rename from gomspace/libcsp/src/rtable/csp_rtable_static.c rename to libcsp/src/rtable/csp_rtable_static.c diff --git a/gomspace/libcsp/src/transport/csp_rdp.c b/libcsp/src/transport/csp_rdp.c similarity index 100% rename from gomspace/libcsp/src/transport/csp_rdp.c rename to libcsp/src/transport/csp_rdp.c diff --git a/gomspace/libcsp/src/transport/csp_transport.h b/libcsp/src/transport/csp_transport.h similarity index 100% rename from gomspace/libcsp/src/transport/csp_transport.h rename to libcsp/src/transport/csp_transport.h diff --git a/gomspace/libcsp/src/transport/csp_udp.c b/libcsp/src/transport/csp_udp.c similarity index 100% rename from gomspace/libcsp/src/transport/csp_udp.c rename to libcsp/src/transport/csp_udp.c diff --git a/gomspace/libcsp/utils/cfpsplit.py b/libcsp/utils/cfpsplit.py similarity index 100% rename from gomspace/libcsp/utils/cfpsplit.py rename to libcsp/utils/cfpsplit.py diff --git a/gomspace/libcsp/utils/cspsplit.py b/libcsp/utils/cspsplit.py similarity index 100% rename from gomspace/libcsp/utils/cspsplit.py rename to libcsp/utils/cspsplit.py diff --git a/mission/core/GenericFactory.cpp b/mission/core/GenericFactory.cpp index 2964e0d3..c1c65802 100644 --- a/mission/core/GenericFactory.cpp +++ b/mission/core/GenericFactory.cpp @@ -20,13 +20,13 @@ #include #include #include -#include #include #include +#include "mission/devices/GomspaceDeviceHandler.h" +#include "mission/devices/devicedefinitions/GomspaceDefinitions.h" #if ADD_TEST_CODE == 1 //#include -#include #endif void ObjectFactory::produceGenericObjects() { @@ -90,15 +90,15 @@ void ObjectFactory::produceGenericObjects() { addresses::P60DOCK); /* Communication interfaces */ - new CspComIF(objects::P60_DOCK_COM_IF); + new CspComIF(objects::CSP_COM_IF); /* Device Handler */ - new P60DockHandler(objects::P60DOCK_HANDLER, objects::P60_DOCK_COM_IF, - p60DockCspCookie); + new GomspaceDeviceHandler(objects::P60DOCK_HANDLER, objects::CSP_COM_IF, + p60DockCspCookie, P60Dock::MAX_CONFIGTABLE_ADDRESS, + P60Dock::MAX_HKTABLE_ADDRESS); /* Test Device Handler */ #if ADD_TEST_CODE == 1 // new TestTask(objects::TEST_TASK); - new P60DockTestTask(objects::P60DOCK_TEST_TASK); #endif } diff --git a/mission/devices/GomspaceDeviceHandler.cpp b/mission/devices/GomspaceDeviceHandler.cpp new file mode 100644 index 00000000..906ce78f --- /dev/null +++ b/mission/devices/GomspaceDeviceHandler.cpp @@ -0,0 +1,323 @@ +#include +#include + +GomspaceDeviceHandler::GomspaceDeviceHandler(object_id_t objectId, object_id_t comIF, + CookieIF * comCookie, uint16_t maxConfigTableAddress, + uint16_t maxHkTableAddress) : + DeviceHandlerBase(objectId, comIF, comCookie), maxConfigTableAddress( + maxConfigTableAddress), maxHkTableAddress(maxHkTableAddress) { + mode = MODE_NORMAL; + if (comCookie == NULL) { + sif::error << "GomspaceDeviceHandler invalid com cookie" << std::endl; + } +} + +GomspaceDeviceHandler::~GomspaceDeviceHandler() { +} + + +void GomspaceDeviceHandler::doStartUp(){ +} + +void GomspaceDeviceHandler::doShutDown(){ + +} + +ReturnValue_t GomspaceDeviceHandler::buildNormalDeviceCommand( + DeviceCommandId_t * id) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GomspaceDeviceHandler::buildTransitionDeviceCommand( + DeviceCommandId_t * id){ + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GomspaceDeviceHandler::buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t * commandData, + size_t commandDataLen) { + ReturnValue_t result; + switch(deviceCommand) { + case(PING): { + result = generatePingCommand(commandData, commandDataLen); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + break; + } + case(REBOOT): { + generateRebootCommand(); + break; + } + case(PARAM_SET):{ + result = generateSetParamCommand(commandData, commandDataLen); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + break; + } + case(PARAM_GET):{ + result = generateGetParamCommand(commandData, commandDataLen); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + break; + } + case(GNDWDT_RESET): { + result = generateResetWatchdogCmd(); + if(result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + } + default: + break; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void GomspaceDeviceHandler::fillCommandAndReplyMap(){ + this->insertInCommandAndReplyMap(PING, 3); + this->insertInCommandMap(REBOOT); + this->insertInCommandAndReplyMap(PARAM_SET, 3); + this->insertInCommandAndReplyMap(PARAM_GET, 3); + this->insertInCommandMap(GNDWDT_RESET); +} + +ReturnValue_t GomspaceDeviceHandler::scanForReply(const uint8_t *start, + size_t remainingSize, DeviceCommandId_t *foundId, size_t *foundLen) { + switch(rememberCommandId) { + case(PING): + *foundId = PING; + *foundLen = PING_REPLY_SIZE; + rememberCommandId = NONE; + break; + case(PARAM_GET): { + *foundId = PARAM_GET; + *foundLen = rememberRequestedSize + CspGetParamReply::GS_HDR_LENGTH; + rememberCommandId = NONE; + break; + } + case(PARAM_SET): { + *foundId = PARAM_SET; + *foundLen = rememberRequestedSize; + rememberCommandId = NONE; + break; + } + default: + return IGNORE_REPLY_DATA; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GomspaceDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) { + switch(id) { + //todo: check replies + case(PING): { + SerializeElement replyTime = *packet; + handleDeviceTM(&replyTime, id, true); + break; + } + case(PARAM_GET): { + // -2 to subtract address size from gomspace parameter reply packet + uint16_t payloadLength = (*(packet + 2) << 8 | *(packet + 3)) - 2; + uint8_t tempPayloadBuffer[payloadLength]; + /* Extract information from received data */ + CspGetParamReply cspGetParamReply(tempPayloadBuffer, payloadLength); + size_t size = CspGetParamReply::GS_HDR_LENGTH + payloadLength; + ReturnValue_t result = cspGetParamReply.deSerialize(&packet, &size, + SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "GomspaceDeviceHandler: Failed to deserialize get parameter" + << "message" << std::endl; + } + uint8_t action = cspGetParamReply.getAction(); + uint8_t tableId = cspGetParamReply.getTableId(); + uint16_t address = cspGetParamReply.getAddress(); + /* Pack relevant information into a tm reply packet */ + ParamReply paramReply(action, tableId, address, payloadLength, + tempPayloadBuffer); + handleDeviceTM(¶mReply, id, true); + break; + } + case(PARAM_SET): { + /* When setting a parameter, the p60dock sends back the state of the + * operation */ + if(*packet != PARAM_SET_OK){ + return HasReturnvaluesIF::RETURN_FAILED; + } + break; + } + default: + break; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void GomspaceDeviceHandler::setNormalDatapoolEntriesInvalid(){ + +} + +ReturnValue_t GomspaceDeviceHandler::generateSetParamCommand( + const uint8_t * commandData, size_t commandDataLen) { + SetParamMessageUnpacker setParamMessageUnpacker; + ReturnValue_t result = setParamMessageUnpacker.deSerialize(&commandData, + &commandDataLen, SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "GomspaceDeviceHandler: Failed to deserialize set parameter " + "message" << std::endl; + return FAILED_DESERIALIZATION; + } + /* Get and check address */ + uint16_t address = setParamMessageUnpacker.getAddress(); + if(address > maxConfigTableAddress){ + sif::error << "GomspaceDeviceHandler: Invalid address for set parameter " + << "action" << std::endl; + return INVALID_ADDRESS; + } + uint16_t checksum = GOMSPACE::IGNORE_CHECKSUM; + uint16_t seq = 0; + uint16_t total = 0; + /* CSP reply only contains the transaction state */ + uint16_t querySize = 1; + const uint8_t* parameterPtr = setParamMessageUnpacker.getParameter(); + uint8_t parameterSize = setParamMessageUnpacker.getParameterSize(); + uint16_t payloadlength = sizeof(address) + parameterSize; + + /* Generate command for CspComIF */ + CspSetParamCommand setParamCmd(querySize, payloadlength, checksum, seq, + total, address, parameterPtr, parameterSize); + size_t cspPacketLen = 0; + uint8_t* buffer = cspPacket; + result = setParamCmd.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), + SerializeIF::Endianness::BIG); + + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "GomspaceDeviceHandler: Failed to serialize command for " + << "CspComIF" << std::endl; + return FAILED_SERIALIZATION; + } + if(cspPacketLen > MAX_PACKET_LEN){ + sif::error << "GomspaceDeviceHandler: Invalid length of set parameter " + "command" << std::endl; + return PACKET_TOO_LONG; + } + rawPacket = cspPacket; + rawPacketLen = cspPacketLen; + rememberRequestedSize = querySize; + rememberCommandId = PARAM_SET; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GomspaceDeviceHandler::generateGetParamCommand( + const uint8_t * commandData, size_t commandDataLen){ + ReturnValue_t result; + /* Unpack the received action message */ + GetParamMessageUnpacker getParamMessage; + result = getParamMessage.deSerialize(&commandData, &commandDataLen, + SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "Failed to deserialize message to extract information " + "from get parameter message" << std::endl; + return FAILED_SERIALIZATION; + } + uint8_t tableId = getParamMessage.getTableId(); + if(CONFIG_TABLE_ID != 1 && HK_TABLE_ID != 4){ + sif::error << "GomspaceDeviceHandler: Invalid table id received " + << "for getting a paramter" << std::endl; + return INVALID_TABLE_ID; + } + /* Get and check address */ + uint16_t address = getParamMessage.getAddress(); + if(address > maxHkTableAddress && tableId == HK_TABLE_ID){ + sif::error << "GomspaceDeviceHandler: Invalid address to get parameter from " + << "housekeeping table" << std::endl; + return INVALID_ADDRESS; + } + if(address > maxConfigTableAddress && tableId == CONFIG_TABLE_ID){ + sif::error << "GomspaceDeviceHandler: Invalid address to get parameter from " + << "configuration table" << std::endl; + return INVALID_ADDRESS; + } + uint16_t length = sizeof(address); + uint16_t checksum = GOMSPACE::IGNORE_CHECKSUM; + uint16_t seq = 0; + uint16_t total = 0; + uint16_t querySize = getParamMessage.getParameterSize() + + CspGetParamCommand::GS_HDR_LENGTH; + + /* Generate the CSP command to send to the P60 Dock */ + CspGetParamCommand getParamCmd(querySize, tableId, length, + checksum, seq, total, address); + size_t cspPacketLen = 0; + uint8_t* buffer = cspPacket; + result = getParamCmd.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), + SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "GomspaceDeviceHandler: Failed to serialize command to " + << "get parameter" << std::endl; + } + if(cspPacketLen > MAX_PACKET_LEN){ + sif::error << "GomspaceDeviceHandler: Received invalid get parameter " + "command" << std::endl; + return PACKET_TOO_LONG; + } + rawPacket = cspPacket; + rawPacketLen = cspPacketLen; + rememberRequestedSize = querySize; + rememberCommandId = PARAM_GET; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GomspaceDeviceHandler::generatePingCommand( + const uint8_t * commandData, size_t commandDataLen) { + CspPingCommand cspPingCommand(commandData, commandDataLen); + size_t cspPacketLen = 0; + uint8_t* buffer = cspPacket; + ReturnValue_t result = cspPingCommand.serialize(&buffer, &cspPacketLen, + sizeof(cspPacket), + SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "GomspaceDeviceHandler: Failed to serialize ping command" + << std::endl; + return FAILED_SERIALIZATION; + } + if(cspPacketLen > MAX_PACKET_LEN){ + sif::error << "GomspaceDeviceHandler: Received invalid ping message" + << std::endl; + return PACKET_TOO_LONG; + } + rawPacket = cspPacket; + rawPacketLen = cspPacketLen; + rememberCommandId = PING; + return HasReturnvaluesIF::RETURN_OK; +} + +void GomspaceDeviceHandler::generateRebootCommand(){ + uint8_t cspPort = GOMSPACE::REBOOT_PORT; + uint16_t querySize = 0; + *cspPacket = GOMSPACE::REBOOT_PORT; + *(cspPacket + 1) = querySize; + size_t cspPacketLen = sizeof(cspPort) + sizeof(cspPacketLen); + rawPacket = cspPacket; + rawPacketLen = cspPacketLen; +} + +ReturnValue_t GomspaceDeviceHandler::generateResetWatchdogCmd(){ + WatchdogResetCommand watchdogResetCommand; + size_t cspPacketLen = 0; + uint8_t* buffer = cspPacket; + ReturnValue_t result = watchdogResetCommand.serialize(&buffer, + &cspPacketLen, sizeof(cspPacket), SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "GomspaceDeviceHandler: Failed to serialize watchdog reset " + << "command" << std::endl; + return FAILED_SERIALIZATION; + } + rawPacket = cspPacket; + rawPacketLen = cspPacketLen; + rememberRequestedSize = 0; // No bytes will be queried with the ground + // watchdog command. + rememberCommandId = GNDWDT_RESET; + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/mission/devices/GomspaceDeviceHandler.h b/mission/devices/GomspaceDeviceHandler.h new file mode 100644 index 00000000..09957c91 --- /dev/null +++ b/mission/devices/GomspaceDeviceHandler.h @@ -0,0 +1,108 @@ +#ifndef MISSION_DEVICES_GOMSPACEDEVICEHANDLER_H_ +#define MISSION_DEVICES_GOMSPACEDEVICEHANDLER_H_ + +#include + +/** + * @brief This is the device handler class for all gomspace devices. + * + * @details All gomspace devices are similar with respect to commanding. Thus + * most of the functionality to command a gomspace device can be + * accommodated in one class. For device specific functions, a new + * class could be created by inheriting from the GomspaceDeviceHandler. + */ +class GomspaceDeviceHandler: public DeviceHandlerBase { +public: + + static const ReturnValue_t FAILED_DESERIALIZATION = MAKE_RETURN_CODE(0xE0); + static const ReturnValue_t FAILED_SERIALIZATION = MAKE_RETURN_CODE(0xE1); + static const ReturnValue_t PACKET_TOO_LONG = MAKE_RETURN_CODE(0xE2); + static const ReturnValue_t INVALID_TABLE_ID = MAKE_RETURN_CODE(0xE3); + static const ReturnValue_t INVALID_ADDRESS = MAKE_RETURN_CODE(0xE4); + + /** + * @brief Constructor + * + * @param maxConfigTableAddress The maximum memory address of the configu- + * ration table of a gomspace device. + * @param maxHkTableAddress The maximum memory address of a value in the + * houskeeping (telemetry) table of a gomspace + * device. + */ + GomspaceDeviceHandler(object_id_t objectId, object_id_t comIF, + CookieIF * comCookie, uint16_t maxConfigTableAddress, + uint16_t maxHkTableAddress); + virtual ~GomspaceDeviceHandler(); + +protected: + void doStartUp() override; + void doShutDown() override; + ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) override; + ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t * id) override; + void fillCommandAndReplyMap() override; + ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, + const uint8_t * commandData,size_t commandDataLen) override; + ReturnValue_t scanForReply(const uint8_t *start, size_t remainingSize, + DeviceCommandId_t *foundId, size_t *foundLen) override; + ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) override; + void setNormalDatapoolEntriesInvalid() override; + +private: + + static const uint8_t MAX_PACKET_LEN = 36; + static const uint8_t PARAM_SET_OK = 1; + static const uint8_t PING_REPLY_SIZE = 2; + static const uint8_t CONFIG_TABLE_ID = 1; + static const uint8_t HK_TABLE_ID = 4; + /* Device commands are derived from the rparam.h of the gomspace lib */ + static const DeviceCommandId_t PING = 0x1; //!< [EXPORT] : [COMMAND] + static const DeviceCommandId_t NONE = 0x2; // Set when no command is pending + static const DeviceCommandId_t REBOOT = 0x4; //!< [EXPORT] : [COMMAND] + static const DeviceCommandId_t GNDWDT_RESET = 0x9; //!< [EXPORT] : [COMMAND] + static const DeviceCommandId_t PARAM_GET = 0x00; //!< [EXPORT] : [COMMAND] + static const DeviceCommandId_t PARAM_SET = 0xFF; //!< [EXPORT] : [COMMAND] + + uint8_t rememberRequestedSize = 0; + uint8_t rememberCommandId = NONE; + uint8_t cspPacket[MAX_PACKET_LEN]; + + uint16_t maxConfigTableAddress; + uint16_t maxHkTableAddress; + + /** + * @brief Function to generate the command to set a parameter. Command + * will be sent to the ComIF over the rawPacket buffer. + */ + ReturnValue_t generateSetParamCommand(const uint8_t * commandData, + size_t commandDataLen); + + /** + * @brief Function to generate the command to get a parameter from a + * gomspace device. Command will be sent to the ComIF over the + * rawPacket buffer. + */ + ReturnValue_t generateGetParamCommand(const uint8_t * commandData, + size_t commandDataLen); + + /** + * @brief Function to generate the ping command for the ComIF. + */ + ReturnValue_t generatePingCommand(const uint8_t * commandData, + size_t commandDataLen); + + /** + * @brief Function to generate the command to reboot a gomspace device + * via the ComIF. + */ + void generateRebootCommand(); + + /** + * @brief Function to generate the command to force a ground watchdog + * reset in a gomspace device. + */ + ReturnValue_t generateResetWatchdogCmd(); + +}; + +#endif /* MISSION_DEVICES_GOMSPACEDEVICEHANDLER_H_ */ diff --git a/mission/devices/P60DockHandler.cpp b/mission/devices/P60DockHandler.cpp deleted file mode 100644 index c6cff969..00000000 --- a/mission/devices/P60DockHandler.cpp +++ /dev/null @@ -1,225 +0,0 @@ -#include -#include - -P60DockHandler::P60DockHandler(object_id_t objectId, object_id_t comIF, - CookieIF * comCookie):DeviceHandlerBase(objectId, comIF, comCookie) { - mode = MODE_NORMAL; - if(comCookie == NULL){ - sif::error << "P60DockHandler invalid com cookie" << std::endl; - } -} - -P60DockHandler::~P60DockHandler() { -} - - -void P60DockHandler::doStartUp(){ -} - -void P60DockHandler::doShutDown(){ - -} - -ReturnValue_t P60DockHandler::buildNormalDeviceCommand(DeviceCommandId_t * id){ - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t P60DockHandler::buildTransitionDeviceCommand( - DeviceCommandId_t * id){ - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t P60DockHandler::buildCommandFromCommand( - DeviceCommandId_t deviceCommand, const uint8_t * commandData, - size_t commandDataLen) { - switch(deviceCommand) { - case(PING): { - const uint8_t* pingData = commandData; - uint8_t pingDataSz = commandDataLen; - CspPingCommand cspPingCommand(pingData, pingDataSz); - size_t cspPacketLen = 0; - uint8_t* buffer = cspPacket; - cspPingCommand.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), - SerializeIF::Endianness::BIG); - if(cspPacketLen > MAX_PACKET_LEN){ - sif::error << "P60DockHandler: Received invalid ping message" - << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - rawPacket = cspPacket; - rawPacketLen = cspPacketLen; - rememberCommandId = PING; - break; - } - case(REBOOT): { - uint8_t cspPort = GOMSPACE::REBOOT_PORT; - uint16_t querySize = 0; - *cspPacket = GOMSPACE::REBOOT_PORT; - *(cspPacket + 1) = querySize; - size_t cspPacketLen = sizeof(cspPort) + sizeof(cspPacketLen); - rawPacket = cspPacket; - rawPacketLen = cspPacketLen; - break; - } - case(PARAM_SET):{ - SetParamMessageUnpacker setParamMessageUnpacker(commandData, - commandDataLen); - uint8_t tableId = setParamMessageUnpacker.getTableId(); - uint16_t address = setParamMessageUnpacker.getAddress(); - uint16_t checksum = GOMSPACE::IGNORE_CHECKSUM; - uint16_t seq = 0; - uint16_t total = 0; - /* Reply only comprises the transaction state */ - uint16_t querySize = 1; - const uint8_t* parameterPtr = setParamMessageUnpacker.getParameter(); - uint8_t parameterSize = setParamMessageUnpacker.getParameterSize(); - uint16_t payloadlength = sizeof(address) + parameterSize; - CspSetParamCommand setParamCmd(querySize, PARAM_SET, tableId, payloadlength, - checksum, seq, total, address, parameterPtr, - parameterSize); - size_t cspPacketLen = 0; - uint8_t* buffer = cspPacket; - setParamCmd.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), - SerializeIF::Endianness::BIG); - if(cspPacketLen > MAX_PACKET_LEN){ - sif::error << "P60DockHandler: Received invalid set parameter " - "command" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - rawPacket = cspPacket; - rawPacketLen = cspPacketLen; - rememberRequestedSize = querySize; - rememberCommandId = PARAM_SET; - break; - } - case(PARAM_GET):{ - /* Unpack the received action message */ - GetParamMessageUnpacker getParamMessage(commandData, commandDataLen); - uint8_t tableId = getParamMessage.getTableId(); - uint16_t address = getParamMessage.getAddress(); - uint16_t length = sizeof(address); - uint16_t checksum = GOMSPACE::IGNORE_CHECKSUM; - uint16_t seq = 0; - uint16_t total = 0; - uint16_t querySize = getParamMessage.getParameterSize() - + CspGetParamCommand::GS_HDR_LENGTH; - /* Generate the CSP command to send to the P60 Dock */ - CspGetParamCommand getParamCmd(querySize, PARAM_GET, tableId, length, - checksum, seq, total, address); - size_t cspPacketLen = 0; - uint8_t* buffer = cspPacket; - getParamCmd.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), - SerializeIF::Endianness::BIG); - if(cspPacketLen > MAX_PACKET_LEN){ - sif::error << "P60DockHandler: Received invalid get parameter " - "command" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - rawPacket = cspPacket; - rawPacketLen = cspPacketLen; - rememberRequestedSize = querySize; - rememberCommandId = PARAM_GET; - break; - } - case(GNDWDT_RESET): { - WatchdogResetCommand watchdogResetCommand; - size_t cspPacketLen = 0; - uint8_t* buffer = cspPacket; - watchdogResetCommand.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), - SerializeIF::Endianness::BIG); - if(cspPacketLen > MAX_PACKET_LEN){ - sif::error << "P60DockHandler: Received invalid ground watchdog" - "reset command" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - rawPacket = cspPacket; - rawPacketLen = cspPacketLen; - rememberRequestedSize = 0; // No bytes will be queried with the ground - // watchdog command. - rememberCommandId = GNDWDT_RESET; - } - default: - break; - } - return HasReturnvaluesIF::RETURN_OK; -} - -void P60DockHandler::fillCommandAndReplyMap(){ - this->insertInCommandAndReplyMap(PING, 3); - this->insertInCommandMap(REBOOT); - this->insertInCommandAndReplyMap(PARAM_SET, 3); - this->insertInCommandAndReplyMap(PARAM_GET, 3); - this->insertInCommandMap(GNDWDT_RESET); -} - -ReturnValue_t P60DockHandler::scanForReply(const uint8_t *start, - size_t remainingSize, DeviceCommandId_t *foundId, size_t *foundLen) { - switch(rememberCommandId) { - case(PING): - *foundId = PING; - *foundLen = PING_REPLY_SIZE; - rememberCommandId = NONE; - break; - case(PARAM_GET): { - *foundId = PARAM_GET; - *foundLen = rememberRequestedSize + CspGetParamReply::GS_HDR_LENGTH; - rememberCommandId = NONE; - break; - } - case(PARAM_SET): { - *foundId = PARAM_SET; - *foundLen = rememberRequestedSize; - rememberCommandId = NONE; - break; - } - default: - return IGNORE_REPLY_DATA; - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t P60DockHandler::interpretDeviceReply(DeviceCommandId_t id, - const uint8_t *packet) { - switch(id) { - case(PING): { - SerializeElement replyTime = *packet; - handleDeviceTM(&replyTime, id, true); - break; - } - case(PARAM_GET): { - // -2 to subtract address size from gomspace parameter reply packet - uint16_t payloadLength = (*(packet + 2) << 8 | *(packet + 3)) - 2; - uint8_t tempPayloadBuffer[payloadLength]; - /* Extract information from received data */ - CspGetParamReply cspGetParamReply(tempPayloadBuffer, payloadLength); - size_t size = CspGetParamReply::GS_HDR_LENGTH + payloadLength; - cspGetParamReply.deSerialize(&packet, &size, - SerializeIF::Endianness::BIG); - uint8_t action = cspGetParamReply.getAction(); - uint8_t tableId = cspGetParamReply.getTableId(); - uint16_t address = cspGetParamReply.getAddress(); - /* Pack relevant information into a tm reply packet */ - ParamReply paramReply(action, tableId, address, payloadLength, - tempPayloadBuffer); - handleDeviceTM(¶mReply, id, true); - break; - } - case(PARAM_SET): { - /* When setting a parameter, the p60dock sends back the state of the - * operation */ - if(*packet != PARAM_SET_OK){ - return HasReturnvaluesIF::RETURN_FAILED; - } - break; - } - default: - break; - } - return HasReturnvaluesIF::RETURN_OK; -} - -void P60DockHandler::setNormalDatapoolEntriesInvalid(){ - -} - - diff --git a/mission/devices/P60DockHandler.h b/mission/devices/P60DockHandler.h deleted file mode 100644 index 8f3a2f77..00000000 --- a/mission/devices/P60DockHandler.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef MISSION_DEVICES_P60DOCKHANDLER_H_ -#define MISSION_DEVICES_P60DOCKHANDLER_H_ - -#include -#include - -namespace P60Dock{ - /* The maximum size of a reply from the P60 dock. Maximum size is reached - * when retrieving the full parameter configuration table. 412 bytes of - * payload data and 12 bytes of CSP header data. */ - static const uint16_t MAX_REPLY_LENGTH = 424; -} - -class P60DockHandler: public DeviceHandlerBase { -public: - P60DockHandler(object_id_t objectId, object_id_t comIF, - CookieIF * comCookie); - virtual ~P60DockHandler(); - -protected: - void doStartUp() override; - void doShutDown() override; - ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) override; - ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t * id) override; - void fillCommandAndReplyMap() override; - ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, - const uint8_t * commandData,size_t commandDataLen) override; - ReturnValue_t scanForReply(const uint8_t *start, size_t remainingSize, - DeviceCommandId_t *foundId, size_t *foundLen) override; - ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, - const uint8_t *packet) override; - void setNormalDatapoolEntriesInvalid() override; - -private: - - static const uint8_t MAX_PACKET_LEN = 36; - static const uint8_t PARAM_SET_OK = 1; - static const uint8_t PING_REPLY_SIZE = 2; - /* Device commands are derived from the rparam.h of the gomspace lib */ - static const DeviceCommandId_t PING = 0x1; //!< [EXPORT] : [COMMAND] - static const DeviceCommandId_t NONE = 0x2; // Set when no command is pending - static const DeviceCommandId_t REBOOT = 0x4; //!< [EXPORT] : [COMMAND] - static const DeviceCommandId_t GNDWDT_RESET = 0x9; //!< [EXPORT] : [COMMAND] - static const DeviceCommandId_t PARAM_GET = 0x00; //!< [EXPORT] : [COMMAND] - static const DeviceCommandId_t PARAM_SET = 0xFF; //!< [EXPORT] : [COMMAND] - - uint8_t rememberRequestedSize = 0; - uint8_t rememberCommandId = NONE; - uint8_t cspPacket[MAX_PACKET_LEN]; -}; - -#endif /* MISSION_DEVICES_P60DOCKHANDLER_H_ */ diff --git a/mission/devices/devicedefinitions/GomSpacePackets.h b/mission/devices/devicedefinitions/GomSpacePackets.h index e41ea162..6c3509f8 100644 --- a/mission/devices/devicedefinitions/GomSpacePackets.h +++ b/mission/devices/devicedefinitions/GomSpacePackets.h @@ -4,6 +4,7 @@ #include "fsfw/serialize/SerialBufferAdapter.h" #include "fsfw/serialize/SerializeElement.h" #include "fsfw/serialize/SerialLinkedListAdapter.h" +#include "fsfw/serialize/SerialFixedArrayListAdapter.h" namespace GOMSPACE{ static const uint16_t IGNORE_CHECKSUM = 0xbb0; @@ -93,14 +94,12 @@ public: static const uint8_t GS_HDR_LENGTH = 12; - CspSetParamCommand(uint16_t querySize_, uint8_t action_, uint8_t tableId_, - uint16_t payloadlength_, uint16_t checksum_, uint16_t seq_, - uint16_t total_, uint16_t addr_, const uint8_t* parameter_, - uint8_t parameterCount_) : - querySize(querySize_), action(action_), tableId(tableId_), payloadlength( + CspSetParamCommand(uint16_t querySize_, uint16_t payloadlength_, + uint16_t checksum_, uint16_t seq_, uint16_t total_, uint16_t addr_, + const uint8_t* parameter_, uint8_t parameterCount_) : + querySize(querySize_), payloadlength( payloadlength_), checksum(checksum_), seq(seq_), total( - total_), addr(addr_), parameter(parameter_, - parameterCount_) { + total_), addr(addr_), parameter(parameter_, parameterCount_) { setLinks(); } @@ -121,8 +120,10 @@ private: SerializeElement cspPort = GOMSPACE::PARAM_PORT; /* Only a parameter will be set. No data will be queried with this command */ SerializeElement querySize; - SerializeElement action; - SerializeElement tableId; + SerializeElement action = 0xFF; // param set + /* We will never set a parameter in a table other than the configuration + * table */ + SerializeElement tableId = 1; SerializeElement payloadlength; SerializeElement checksum; SerializeElement seq; @@ -145,10 +146,10 @@ public: /* The size of the header of a gomspace CSP packet. */ static const uint8_t GS_HDR_LENGTH = 12; - CspGetParamCommand(uint16_t querySize_, uint8_t action_, uint8_t tableId_, + CspGetParamCommand(uint16_t querySize_, uint8_t tableId_, uint16_t addresslength_, uint16_t checksum_, uint16_t seq_, uint16_t total_, uint16_t addr_) : - querySize(querySize_), action(action_), tableId(tableId_), addresslength( + querySize(querySize_), tableId(tableId_), addresslength( addresslength_), checksum(checksum_), seq(seq_), total( total_), addr(addr_) { fixedValuesInit(); @@ -175,7 +176,7 @@ private: SerializeElement querySize; // size of bytes to query /* Following information will also be physically transmitted to the target * device*/ - SerializeElement action; + SerializeElement action = 0x00; // get param SerializeElement tableId; SerializeElement addresslength; // size of address SerializeElement checksum; @@ -284,45 +285,39 @@ private: }; /** - * @brief This class helps to unpack information from an action messages + * @brief This class helps to unpack information from an action message * to set a parameter in gomspace devices. The action message can be * for example received from the PUS Service 8. */ class SetParamMessageUnpacker: public SerialLinkedListAdapter { public: + /* Largest parameter is a uint32_t */ + static const uint32_t MAX_SIZE = 4; - SetParamMessageUnpacker(const uint8_t* commandData, size_t commandDataLen) { - SerializeAdapter::deSerialize(&tableId, &commandData, &commandDataLen, - SerializeIF::Endianness::BIG); - SerializeAdapter::deSerialize(&address, &commandData, &commandDataLen, - SerializeIF::Endianness::BIG); - parameter = commandData; - parameterSize = commandDataLen; + SetParamMessageUnpacker() { + setLinks(); } - uint8_t getTableId() const { - return tableId; - } - - uint16_t getAddress() const { + uint16_t getAddress() { return address; } - const uint8_t* getParameter() { - return parameter; + uint8_t* getParameter() { + return parameter->front(); } uint8_t getParameterSize(){ - return parameterSize; + return parameter->size; } - private: + void setLinks() { + setStart(&address); + address.setNext(¶meter); + } SetParamMessageUnpacker(const SetParamMessageUnpacker &message); - uint8_t tableId; - uint16_t address; - const uint8_t * parameter; - uint8_t parameterSize; + SerializeElement address; + SerializeElement> parameter; }; @@ -334,20 +329,15 @@ private: class GetParamMessageUnpacker: public SerialLinkedListAdapter { public: - GetParamMessageUnpacker(const uint8_t* commandData, size_t commandDataLen) { - SerializeAdapter::deSerialize(&tableId, &commandData, &commandDataLen, - SerializeIF::Endianness::BIG); - SerializeAdapter::deSerialize(&address, &commandData, &commandDataLen, - SerializeIF::Endianness::BIG); - SerializeAdapter::deSerialize(¶meterSize, &commandData, &commandDataLen, - SerializeIF::Endianness::BIG); + GetParamMessageUnpacker() { + setLinks(); } - uint8_t getTableId() const { + uint8_t getTableId() { return tableId; } - uint16_t getAddress() const { + uint16_t getAddress() { return address; } @@ -358,10 +348,15 @@ public: private: GetParamMessageUnpacker(const GetParamMessageUnpacker &message); - uint8_t tableId; - uint16_t address; //The memory address offset within the table + void setLinks() { + setStart(&tableId); + tableId.setNext(&address); + address.setNext(¶meterSize); + } + SerializeElement tableId; + SerializeElement address; //The memory address offset within the table /* The size of the requested value (e.g. temperature is a uint16_t value) */ - uint8_t parameterSize; + SerializeElement parameterSize; }; #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEPACKETS_H_ */ diff --git a/mission/devices/devicedefinitions/GomspaceDefinitions.h b/mission/devices/devicedefinitions/GomspaceDefinitions.h new file mode 100644 index 00000000..5d2671ef --- /dev/null +++ b/mission/devices/devicedefinitions/GomspaceDefinitions.h @@ -0,0 +1,24 @@ +/* + * GomspaceDefinitions.h + * + * @brief This file holds all definitions specific for devices from gomspace. + * @date 20.12.2020 + * @author J. Meier + */ + +#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEDEFINITIONS_H_ +#define MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEDEFINITIONS_H_ + + +namespace P60Dock{ + /* The maximum size of a reply from the P60 dock. Maximum size is reached + * when retrieving the full parameter configuration table. 412 bytes of + * payload data and 12 bytes of CSP header data. */ + static const uint16_t MAX_REPLY_LENGTH = 424; + + static const uint16_t MAX_CONFIGTABLE_ADDRESS = 408; + static const uint16_t MAX_HKTABLE_ADDRESS = 187; +} + + +#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEDEFINITIONS_H_ */ diff --git a/mission/devices/devicedefinitions/P60DockHandlerDefinitions.h b/mission/devices/devicedefinitions/P60DockHandlerDefinitions.h deleted file mode 100644 index 756c52bd..00000000 --- a/mission/devices/devicedefinitions/P60DockHandlerDefinitions.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_P60DOCKHANDLERDEFINITIONS_H_ -#define MISSION_DEVICES_DEVICEDEFINITIONS_P60DOCKHANDLERDEFINITIONS_H_ - -/** - * @brief This class helps to serialize and deserialze the P60 dock packet - * holding information about the module configuration. The parameters - * of this table are described in the gs-man-nanopower-p60-dock-2.2.9.pdf - * on page 16. - */ -//class ModuleConfigTable : public SerialLinkedListAdapter { //!< [EXPORT] : [SUBSERVICE] 2 -//public: -// typedef char dataBufferType; -// typedef uint8_t typeOfMaxData; -// -// ModuleConfigTable() { -// setStart(&objectId); -// objectId.setNext(&sizeOfRepositoryPath); -// sizeOfRepositoryPath.setNext(&repositoryPath); -// repositoryPath.setNext(&sizeOfFilename); -// sizeOfFilename.setNext(&filename); -// /* Add string terminator to filename and repository path */ -// repositoryPath.entry.insert('\0'); -// filename.entry.insert('\0'); -// } -// -// uint32_t getSizeOfRepositoryPath() { -// return sizeOfRepositoryPath; -// } -// -// uint32_t getSizeOfFilename() { -// return sizeOfFilename; -// } -// -// uint8_t * getRepositoryPath() { -// return repositoryPath.entry.front(); -// } -// -// uint8_t getFilename() { -// return filename.entry.front(); -// } -// -//private: -// /* Prevent object copying */ -// ModuleConfigTable(const ModuleConfigTable &obj); -// -// SerializeElement> out_name; -// SerializeElement> out_en; -// SerializeElement> out_on_cnt; -// SerializeElement> out_on_cnt; -// SerializeElement sizeOfRepositoryPath; -// SerializeElement> repositoryPath; -// SerializeElement sizeOfFilename; -// SerializeElement> filename; -//}; - -/** - * @brief A serial linked list adapter implementation of the gs_rparam_query_t struct - * defined in rparam.h - */ -class GetParamCommand: public SerialLinkedListAdapter { //!< [EXPORT] : [SUBSERVICE] 130 -public: - typedef uint16_t typeOfMaxDataSize; - static const uint16_t MAX_DATA_LENGTH = sizeof(typeOfMaxDataSize); - GetParamCommand(uint8_t objectId_, ActionId_t actionId_, - const uint8_t * replyDataBuffer_ = NULL, uint16_t replyDataSize_ = 0): - objectId(objectId_), actionId(actionId_), replyData(replyDataBuffer_,replyDataSize_){ - setLinks(); - } - -private: - GetParamCommand(const GetParamCommand &reply); - void setLinks() { - setStart(&action); - action.setNext(&tableId); - tableId.setNext(&length); - lenght.setNext(&checksum); - checksum.setNext(&seq); - checksum.setNext(&addr); - } - SerializeElement cspPort = 7; - SerializeElement action; - SerializeElement tableId; - SerializeElement length; - SerializeElement checksum; - SerializeElement seq; - SerializeElement total; - SerializeElement addr; -}; - -#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_P60DOCKHANDLERDEFINITIONS_H_ */ diff --git a/test/testtasks/P60DockTestTask.cpp b/test/testtasks/P60DockTestTask.cpp deleted file mode 100644 index 985e69a3..00000000 --- a/test/testtasks/P60DockTestTask.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * P60DockTestTask.cpp - * - * Created on: 18.11.2020 - * Author: Jakob Meier - */ - -#include -#include "P60DockTestTask.h" - -#include - -P60DockTestTask::P60DockTestTask(object_id_t objectId_): -SystemObject(objectId_){ - if(initializeCSPStack() != HasReturnvaluesIF::RETURN_OK){ - sif::error << "P60DockTestTask creation failed" << std::endl; - } -} - - -ReturnValue_t P60DockTestTask::performOperation(uint8_t operationCode) { - - if(pingP60dock() != HasReturnvaluesIF::RETURN_OK){ - return HasReturnvaluesIF::RETURN_FAILED; - } - - if(getParameters() != HasReturnvaluesIF::RETURN_OK){ - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - - -ReturnValue_t P60DockTestTask::pingP60dock(void){ - uint32_t timeout = 1000; - unsigned int pingSize = 100; // 100 bytes - uint32_t replyTime = csp_ping(p60dockAddress, timeout, pingSize, CSP_O_NONE); - sif::info << "Ping address: " << p60dockAddress << ", reply after " - << replyTime << " ms" << std::endl; - return HasReturnvaluesIF::RETURN_OK; -} - - -ReturnValue_t P60DockTestTask::getParameters(void) { - uint32_t timeout = 1000; - node_hk.rows = (gs_param_table_row_t*)p60dock_hk; - node_hk.id = P60DOCK_HK; - node_hk.row_count = p60dock_hk_count; - node_hk.memory_size = P60DOCK_HK_SIZE; - node_hk.memory = hkMem; - /* Retriev all houskeeping data from the P60 dock and store it in hkMem - * array */ - int result = gs_rparam_get_full_table(&node_hk, p60dockAddress, node_hk.id, - GS_RPARAM_MAGIC_CHECKSUM, timeout); - - if (result != 0) { - sif::info << "Error retrieving P60 Dock housekeeping" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } else { - uint8_t tableOffsetTemperature = 0x44; - int16_t temperature; - size_t parameterSize = sizeof(temperature); - uint32_t flags = 0; - result = gs_param_get_data((gs_param_table_instance_t*) &node_hk, - tableOffsetTemperature, &temperature, parameterSize, flags); - sif::info << "P60 Dock Temperature: " << temperature << std::endl; - - uint16_t vbat_v; - parameterSize = sizeof(vbat_v); - uint8_t vbat_v_offset = 0x74; - result = gs_param_get_data((gs_param_table_instance_t*) &node_hk, - vbat_v_offset, &vbat_v, parameterSize, flags); - sif::info << "VBAT_V: " << vbat_v << std::endl; - } - return HasReturnvaluesIF::RETURN_OK; -} - - -ReturnValue_t P60DockTestTask::initializeCSPStack(void){ - /* Init CSP and CSP buffer system */ - if (csp_init(cspClientAddress) != CSP_ERR_NONE - || csp_buffer_init(10, 300) != CSP_ERR_NONE) { - sif::error << "Failed to init CSP\r\n" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - - csp_iface_t *csp_if_ptr = &csp_if; - csp_if_ptr = csp_can_socketcan_init("can0", bitrate, promisc); - - /* Set default route and start router */ - int result = csp_rtable_set(CSP_DEFAULT_ROUTE, 0, csp_if_ptr, CSP_NODE_MAC); - if(result != CSP_ERR_NONE){ - sif::error << "Failed to add can interface to router table" - << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - result = csp_route_start_task(500, 0); - if(result != CSP_ERR_NONE){ - sif::error << "Failed to start route task" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - - -P60DockTestTask::~P60DockTestTask() { - // TODO Auto-generated destructor stub -} - diff --git a/test/testtasks/P60DockTestTask.h b/test/testtasks/P60DockTestTask.h deleted file mode 100644 index f631c18c..00000000 --- a/test/testtasks/P60DockTestTask.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * P60DockTestTask.h - * - * Created on: 18.11.2020 - * Author: Jakob Meier - */ - -#ifndef TEST_TESTTASKS_P60DOCKTESTTASK_H_ -#define TEST_TESTTASKS_P60DOCKTESTTASK_H_ - -#include -#include -#include - -#include -#include -#include -#include - - -class P60DockTestTask: public SystemObject, - public ExecutableObjectIF, - public HasReturnvaluesIF { -public: - P60DockTestTask(object_id_t objectId_); - virtual ~P60DockTestTask(); - - virtual ReturnValue_t performOperation(uint8_t operationCode = 0); - -private: - /* Interface struct for csp protocol stack */ - csp_iface_t csp_if; - /* CSP address of P60 dock */ - uint8_t p60dockAddress = 4; - /* Client CSP address */ - uint8_t cspClientAddress = 1; - /* CAN interface used by CSP */ - const char* canIf = "can0"; - int bitrate = 1000; // bitrate of can - int promisc = 0; // set to 0 to enable filter mode - /* P60 Dock houskeeping parameters will be stored in this buffer */ - uint8_t hkMem[P60DOCK_HK_SIZE]; - gs_param_table_instance_t node_hk; - /* Port of CSP ping requests on P60 dock */ - uint8_t CSP_PING = 1; - - /* Sends ping request and receives ping reply */ - ReturnValue_t pingP60dock(void); - ReturnValue_t initializeCSPStack(void); - /* Temperature and raw battery voltage are read from the P60 dock by this - * function */ - ReturnValue_t getParameters(void); -}; - -#endif /* TEST_TESTTASKS_P60DOCKTESTTASK_H_ */ From 468c36f82f947c15b0866f6926cc773e148d31f9 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Sun, 20 Dec 2020 17:35:03 +0100 Subject: [PATCH 053/360] working pdu2handler --- bsp_linux/comIF/CspComIF.cpp | 64 ++++++++++--------- bsp_linux/comIF/CspComIF.h | 11 ++-- bsp_linux/comIF/cookies/CspCookie.cpp | 8 --- bsp_linux/comIF/cookies/CspCookie.h | 4 -- fsfwconfig/objects/systemObjectList.h | 3 +- .../PollingSequenceFactory.cpp | 16 +++++ libcsp/libcsp.mk | 2 +- mission/core/GenericFactory.cpp | 10 +++ mission/devices/GomspaceDeviceHandler.cpp | 37 +++++++---- mission/devices/GomspaceDeviceHandler.h | 10 +-- .../devicedefinitions/GomspaceDefinitions.h | 15 +++++ 11 files changed, 113 insertions(+), 67 deletions(-) diff --git a/bsp_linux/comIF/CspComIF.cpp b/bsp_linux/comIF/CspComIF.cpp index 224ae2d4..fbd0b7e5 100644 --- a/bsp_linux/comIF/CspComIF.cpp +++ b/bsp_linux/comIF/CspComIF.cpp @@ -21,40 +21,42 @@ ReturnValue_t CspComIF::initializeInterface(CookieIF *cookie) { if(cspCookie == nullptr) { return NULLPOINTER; } - char* canInterface = cspCookie->getCanIf(); - int bitrate = cspCookie->getBitrate(); - /* Define the memory to allocate for the CSP stack */ - int buf_count = 10; - int buf_size = 300; - /* Init CSP and CSP buffer system */ - if (csp_init(cspClientAddress) != CSP_ERR_NONE - || csp_buffer_init(buf_count, buf_size) != CSP_ERR_NONE) { - sif::error << "Failed to init CSP\r\n" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - int promisc = 0; // Set filter mode on - csp_iface_t *csp_if_ptr = &csp_if; - csp_if_ptr = csp_can_socketcan_init(canInterface, bitrate, promisc); + /* Perform CAN and CSP initialization only once */ + if(cspDeviceMap.empty()){ + /* Define the memory to allocate for the CSP stack */ + int buf_count = 10; + int buf_size = 300; + /* Init CSP and CSP buffer system */ + if (csp_init(cspClientAddress) != CSP_ERR_NONE + || csp_buffer_init(buf_count, buf_size) != CSP_ERR_NONE) { + sif::error << "Failed to init CSP\r\n" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } - /* Set default route and start router */ - uint8_t address = CSP_DEFAULT_ROUTE; - uint8_t netmask = 0; - uint8_t mac = CSP_NODE_MAC; - int result = csp_rtable_set(address, netmask, csp_if_ptr, mac); - if(result != CSP_ERR_NONE){ - sif::error << "Failed to add can interface to router table" - << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } + int promisc = 0; // Set filter mode on + csp_iface_t *csp_if_ptr = &csp_if; + csp_if_ptr = csp_can_socketcan_init(canInterface, bitrate, promisc); - /* Start the route task */ - unsigned int task_stack_size = 500; - unsigned int priority = 0; - result = csp_route_start_task(task_stack_size, priority); - if(result != CSP_ERR_NONE){ - sif::error << "Failed to start csp route task" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; + /* Set default route and start router */ + uint8_t address = CSP_DEFAULT_ROUTE; + uint8_t netmask = 0; + uint8_t mac = CSP_NODE_MAC; + int result = csp_rtable_set(address, netmask, csp_if_ptr, mac); + if(result != CSP_ERR_NONE){ + sif::error << "Failed to add can interface to router table" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + /* Start the route task */ + unsigned int task_stack_size = 500; + unsigned int priority = 0; + result = csp_route_start_task(task_stack_size, priority); + if(result != CSP_ERR_NONE){ + sif::error << "Failed to start csp route task" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } } uint8_t cspAddress = cspCookie->getCspAddress(); diff --git a/bsp_linux/comIF/CspComIF.h b/bsp_linux/comIF/CspComIF.h index c1a27f19..626b466c 100644 --- a/bsp_linux/comIF/CspComIF.h +++ b/bsp_linux/comIF/CspComIF.h @@ -10,10 +10,10 @@ #include /** - * @brief This class is serves as the communication interface to devices - * supporting the CSP protocol. For now as physical interface only - * CAN is supported by this CSP implementation. - * @author Jakob Meier + * @brief This class serves as the communication interface to devices + * supporting the CSP protocol. As physical layer can0 is used + * in this implementation. + * @author J. Meier */ class CspComIF: public DeviceCommunicationIF, public SystemObject { public: @@ -70,6 +70,9 @@ private: /* Interface struct for csp protocol stack */ csp_iface_t csp_if; + char canInterface[5] = "can0"; + int bitrate = 1000; + /** * @brief Function to extract the csp port and the query size from the * command buffer. diff --git a/bsp_linux/comIF/cookies/CspCookie.cpp b/bsp_linux/comIF/cookies/CspCookie.cpp index 64c160f5..18cfabd2 100644 --- a/bsp_linux/comIF/cookies/CspCookie.cpp +++ b/bsp_linux/comIF/cookies/CspCookie.cpp @@ -14,11 +14,3 @@ uint16_t CspCookie::getMaxReplyLength(){ uint8_t CspCookie::getCspAddress(){ return cspAddress; } - -char* CspCookie::getCanIf(){ - return canInterface; -} - -int CspCookie::getBitrate(){ - return bitrate; -} diff --git a/bsp_linux/comIF/cookies/CspCookie.h b/bsp_linux/comIF/cookies/CspCookie.h index 5dfebfc0..128926e5 100644 --- a/bsp_linux/comIF/cookies/CspCookie.h +++ b/bsp_linux/comIF/cookies/CspCookie.h @@ -17,15 +17,11 @@ public: uint16_t getMaxReplyLength(); uint8_t getCspAddress(); - char* getCanIf(); - int getBitrate(); private: uint16_t maxReplyLength; - char canInterface[5] = "can0"; uint8_t cspAddress; - int bitrate = 1000; }; #endif /* BSP_LINUX_COMIF_COOKIES_CSPCOOKIE_H_ */ diff --git a/fsfwconfig/objects/systemObjectList.h b/fsfwconfig/objects/systemObjectList.h index c58473cf..758e8fbc 100644 --- a/fsfwconfig/objects/systemObjectList.h +++ b/fsfwconfig/objects/systemObjectList.h @@ -35,7 +35,8 @@ namespace objects { /* 0x44 ('D') for device handlers */ P60DOCK_HANDLER = 0x44000001, - PDU2_HANDLER = 0x44000002 + PDU1_HANDLER = 0x44000002, + PDU2_HANDLER = 0x44000003 }; } diff --git a/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp b/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp index b038e0fb..3c326ac8 100644 --- a/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp +++ b/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp @@ -34,15 +34,31 @@ ReturnValue_t pst::gomspacePstInit(FixedTimeslotTaskIF *thisSequence){ thisSequence->addSlot(objects::P60DOCK_HANDLER, length * 0, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::PDU1_HANDLER, + length * 0, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::PDU2_HANDLER, + length * 0, DeviceHandlerIF::SEND_WRITE); thisSequence->addSlot(objects::P60DOCK_HANDLER, length * 0.25, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::PDU1_HANDLER, + length * 0.25, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::PDU2_HANDLER, + length * 0.25, DeviceHandlerIF::GET_WRITE); thisSequence->addSlot(objects::P60DOCK_HANDLER, length * 0.5, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::PDU1_HANDLER, + length * 0.5, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::PDU2_HANDLER, + length * 0.5, DeviceHandlerIF::SEND_READ); thisSequence->addSlot(objects::P60DOCK_HANDLER, length * 0.75, DeviceHandlerIF::GET_READ); + thisSequence->addSlot(objects::PDU1_HANDLER, + length * 0.75, DeviceHandlerIF::GET_READ); + thisSequence->addSlot(objects::PDU2_HANDLER, + length * 0.75, DeviceHandlerIF::GET_READ); if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) { return HasReturnvaluesIF::RETURN_OK; diff --git a/libcsp/libcsp.mk b/libcsp/libcsp.mk index af27f9f1..febffad7 100644 --- a/libcsp/libcsp.mk +++ b/libcsp/libcsp.mk @@ -1,6 +1,6 @@ CSRC += $(wildcard $(CURRENTPATH)/src/drivers/can/*.c) CSRC += $(wildcard $(CURRENTPATH)/src/*.c) -CSRC += $(wildcard $(CURRENTPATH)/libcsp/src/interfaces/*.c) +CSRC += $(wildcard $(CURRENTPATH)/src/interfaces/*.c) CSRC += $(wildcard $(CURRENTPATH)/src/rtable/csp_rtable_cidr.c) CSRC += $(wildcard $(CURRENTPATH)/src/crypto/*.c) CSRC += $(wildcard $(CURRENTPATH)/src/arch/posix/*.c) diff --git a/mission/core/GenericFactory.cpp b/mission/core/GenericFactory.cpp index c1c65802..77a7a1e8 100644 --- a/mission/core/GenericFactory.cpp +++ b/mission/core/GenericFactory.cpp @@ -88,6 +88,10 @@ void ObjectFactory::produceGenericObjects() { /* Cookies */ CspCookie* p60DockCspCookie = new CspCookie(P60Dock::MAX_REPLY_LENGTH, addresses::P60DOCK); + CspCookie* pdu1CspCookie = new CspCookie(PDU::MAX_REPLY_LENGTH, + addresses::PDU1); + CspCookie* pdu2CspCookie = new CspCookie(PDU::MAX_REPLY_LENGTH, + addresses::PDU2); /* Communication interfaces */ new CspComIF(objects::CSP_COM_IF); @@ -96,6 +100,12 @@ void ObjectFactory::produceGenericObjects() { new GomspaceDeviceHandler(objects::P60DOCK_HANDLER, objects::CSP_COM_IF, p60DockCspCookie, P60Dock::MAX_CONFIGTABLE_ADDRESS, P60Dock::MAX_HKTABLE_ADDRESS); + new GomspaceDeviceHandler(objects::PDU1_HANDLER, objects::CSP_COM_IF, + pdu1CspCookie, PDU::MAX_CONFIGTABLE_ADDRESS, + PDU::MAX_HKTABLE_ADDRESS); + new GomspaceDeviceHandler(objects::PDU2_HANDLER, objects::CSP_COM_IF, + pdu2CspCookie, PDU::MAX_CONFIGTABLE_ADDRESS, + PDU::MAX_HKTABLE_ADDRESS); /* Test Device Handler */ #if ADD_TEST_CODE == 1 diff --git a/mission/devices/GomspaceDeviceHandler.cpp b/mission/devices/GomspaceDeviceHandler.cpp index 906ce78f..fcb97953 100644 --- a/mission/devices/GomspaceDeviceHandler.cpp +++ b/mission/devices/GomspaceDeviceHandler.cpp @@ -112,7 +112,6 @@ ReturnValue_t GomspaceDeviceHandler::scanForReply(const uint8_t *start, ReturnValue_t GomspaceDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) { switch(id) { - //todo: check replies case(PING): { SerializeElement replyTime = *packet; handleDeviceTM(&replyTime, id, true); @@ -121,6 +120,11 @@ ReturnValue_t GomspaceDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, case(PARAM_GET): { // -2 to subtract address size from gomspace parameter reply packet uint16_t payloadLength = (*(packet + 2) << 8 | *(packet + 3)) - 2; + if(payloadLength > sizeof(uint32_t)){ + sif::error << "GomspaceDeviceHandler: PARAM_GET: Invalid payload " + << "size in reply" << std::endl; + return INVALID_PAYLOAD_SIZE; + } uint8_t tempPayloadBuffer[payloadLength]; /* Extract information from received data */ CspGetParamReply cspGetParamReply(tempPayloadBuffer, payloadLength); @@ -129,12 +133,13 @@ ReturnValue_t GomspaceDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, SerializeIF::Endianness::BIG); if(result != HasReturnvaluesIF::RETURN_OK){ sif::error << "GomspaceDeviceHandler: Failed to deserialize get parameter" - << "message" << std::endl; + << "reply" << std::endl; + return result; } uint8_t action = cspGetParamReply.getAction(); uint8_t tableId = cspGetParamReply.getTableId(); uint16_t address = cspGetParamReply.getAddress(); - /* Pack relevant information into a tm reply packet */ + /* Pack relevant information into a tm packet */ ParamReply paramReply(action, tableId, address, payloadLength, tempPayloadBuffer); handleDeviceTM(¶mReply, id, true); @@ -166,7 +171,7 @@ ReturnValue_t GomspaceDeviceHandler::generateSetParamCommand( if(result != HasReturnvaluesIF::RETURN_OK){ sif::error << "GomspaceDeviceHandler: Failed to deserialize set parameter " "message" << std::endl; - return FAILED_DESERIALIZATION; + return result; } /* Get and check address */ uint16_t address = setParamMessageUnpacker.getAddress(); @@ -195,7 +200,7 @@ ReturnValue_t GomspaceDeviceHandler::generateSetParamCommand( if(result != HasReturnvaluesIF::RETURN_OK){ sif::error << "GomspaceDeviceHandler: Failed to serialize command for " << "CspComIF" << std::endl; - return FAILED_SERIALIZATION; + return result; } if(cspPacketLen > MAX_PACKET_LEN){ sif::error << "GomspaceDeviceHandler: Invalid length of set parameter " @@ -219,12 +224,13 @@ ReturnValue_t GomspaceDeviceHandler::generateGetParamCommand( if(result != HasReturnvaluesIF::RETURN_OK) { sif::error << "Failed to deserialize message to extract information " "from get parameter message" << std::endl; - return FAILED_SERIALIZATION; + return result; } + /* Get an check table id to read from */ uint8_t tableId = getParamMessage.getTableId(); - if(CONFIG_TABLE_ID != 1 && HK_TABLE_ID != 4){ - sif::error << "GomspaceDeviceHandler: Invalid table id received " - << "for getting a paramter" << std::endl; + if(tableId != CONFIG_TABLE_ID && tableId != HK_TABLE_ID){ + sif::error << "GomspaceDeviceHandler: Invalid table id in get parameter" + " message" << std::endl; return INVALID_TABLE_ID; } /* Get and check address */ @@ -243,8 +249,13 @@ ReturnValue_t GomspaceDeviceHandler::generateGetParamCommand( uint16_t checksum = GOMSPACE::IGNORE_CHECKSUM; uint16_t seq = 0; uint16_t total = 0; - uint16_t querySize = getParamMessage.getParameterSize() - + CspGetParamCommand::GS_HDR_LENGTH; + uint8_t parameterSize = getParamMessage.getParameterSize(); + if(parameterSize > sizeof(uint32_t)) { + sif::error << "GomspaceDeviceHandler: GET_PARAM: Invalid parameter " + << "size" << std::endl; + return INVALID_PARAM_SIZE; + } + uint16_t querySize = parameterSize + CspGetParamCommand::GS_HDR_LENGTH; /* Generate the CSP command to send to the P60 Dock */ CspGetParamCommand getParamCmd(querySize, tableId, length, @@ -280,7 +291,7 @@ ReturnValue_t GomspaceDeviceHandler::generatePingCommand( if(result != HasReturnvaluesIF::RETURN_OK){ sif::error << "GomspaceDeviceHandler: Failed to serialize ping command" << std::endl; - return FAILED_SERIALIZATION; + return result; } if(cspPacketLen > MAX_PACKET_LEN){ sif::error << "GomspaceDeviceHandler: Received invalid ping message" @@ -312,7 +323,7 @@ ReturnValue_t GomspaceDeviceHandler::generateResetWatchdogCmd(){ if(result != HasReturnvaluesIF::RETURN_OK){ sif::error << "GomspaceDeviceHandler: Failed to serialize watchdog reset " << "command" << std::endl; - return FAILED_SERIALIZATION; + return result; } rawPacket = cspPacket; rawPacketLen = cspPacketLen; diff --git a/mission/devices/GomspaceDeviceHandler.h b/mission/devices/GomspaceDeviceHandler.h index 09957c91..35c89206 100644 --- a/mission/devices/GomspaceDeviceHandler.h +++ b/mission/devices/GomspaceDeviceHandler.h @@ -14,11 +14,11 @@ class GomspaceDeviceHandler: public DeviceHandlerBase { public: - static const ReturnValue_t FAILED_DESERIALIZATION = MAKE_RETURN_CODE(0xE0); - static const ReturnValue_t FAILED_SERIALIZATION = MAKE_RETURN_CODE(0xE1); - static const ReturnValue_t PACKET_TOO_LONG = MAKE_RETURN_CODE(0xE2); - static const ReturnValue_t INVALID_TABLE_ID = MAKE_RETURN_CODE(0xE3); - static const ReturnValue_t INVALID_ADDRESS = MAKE_RETURN_CODE(0xE4); + static const ReturnValue_t PACKET_TOO_LONG = MAKE_RETURN_CODE(0xE0); + static const ReturnValue_t INVALID_TABLE_ID = MAKE_RETURN_CODE(0xE1); + static const ReturnValue_t INVALID_ADDRESS = MAKE_RETURN_CODE(0xE2); + static const ReturnValue_t INVALID_PARAM_SIZE = MAKE_RETURN_CODE(0xE3); + static const ReturnValue_t INVALID_PAYLOAD_SIZE = MAKE_RETURN_CODE(0xE4); /** * @brief Constructor diff --git a/mission/devices/devicedefinitions/GomspaceDefinitions.h b/mission/devices/devicedefinitions/GomspaceDefinitions.h index 5d2671ef..a0c0cacd 100644 --- a/mission/devices/devicedefinitions/GomspaceDefinitions.h +++ b/mission/devices/devicedefinitions/GomspaceDefinitions.h @@ -21,4 +21,19 @@ namespace P60Dock{ } +namespace PDU{ + /* When retrieving full configuration parameter table */ + static const uint16_t MAX_REPLY_LENGTH = 318; + static const uint16_t MAX_CONFIGTABLE_ADDRESS = 316; + static const uint16_t MAX_HKTABLE_ADDRESS = 140; +} + + +namespace ACU{ + /* When receiving full houskeeping (telemetry) table */ + static const uint16_t MAX_REPLY_LENGTH = 124; + static const uint16_t MAX_CONFIGTABLE_ADDRESS = 26; + static const uint16_t MAX_HKTABLE_ADDRESS = 120; +} + #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEDEFINITIONS_H_ */ From 7aa00093decf7828a07c23a0d11f733ca9d595c8 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Mon, 21 Dec 2020 10:26:28 +0100 Subject: [PATCH 054/360] p60dock, acu and pdu handler completed --- fsfwconfig/devices/addresses.h | 1 + fsfwconfig/objects/systemObjectList.h | 3 ++- fsfwconfig/pollingsequence/PollingSequenceFactory.cpp | 8 ++++++++ mission/core/GenericFactory.cpp | 5 +++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/fsfwconfig/devices/addresses.h b/fsfwconfig/devices/addresses.h index 0884d4c5..37d653fa 100644 --- a/fsfwconfig/devices/addresses.h +++ b/fsfwconfig/devices/addresses.h @@ -24,6 +24,7 @@ namespace addresses { /* Addresses of devices supporting the CSP protocol */ enum cspAddresses: uint8_t { P60DOCK = 4, + ACU = 2, PDU1 = 3, /* PDU2 occupies X4 slot of P60Dock */ PDU2 = 6 diff --git a/fsfwconfig/objects/systemObjectList.h b/fsfwconfig/objects/systemObjectList.h index 758e8fbc..e1334af7 100644 --- a/fsfwconfig/objects/systemObjectList.h +++ b/fsfwconfig/objects/systemObjectList.h @@ -36,7 +36,8 @@ namespace objects { /* 0x44 ('D') for device handlers */ P60DOCK_HANDLER = 0x44000001, PDU1_HANDLER = 0x44000002, - PDU2_HANDLER = 0x44000003 + PDU2_HANDLER = 0x44000003, + ACU_HANDLER = 0x44000004 }; } diff --git a/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp b/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp index 3c326ac8..c3f5872d 100644 --- a/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp +++ b/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp @@ -38,6 +38,8 @@ ReturnValue_t pst::gomspacePstInit(FixedTimeslotTaskIF *thisSequence){ length * 0, DeviceHandlerIF::SEND_WRITE); thisSequence->addSlot(objects::PDU2_HANDLER, length * 0, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::ACU_HANDLER, + length * 0, DeviceHandlerIF::SEND_WRITE); thisSequence->addSlot(objects::P60DOCK_HANDLER, length * 0.25, DeviceHandlerIF::GET_WRITE); @@ -45,6 +47,8 @@ ReturnValue_t pst::gomspacePstInit(FixedTimeslotTaskIF *thisSequence){ length * 0.25, DeviceHandlerIF::GET_WRITE); thisSequence->addSlot(objects::PDU2_HANDLER, length * 0.25, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::ACU_HANDLER, + length * 0.25, DeviceHandlerIF::GET_WRITE); thisSequence->addSlot(objects::P60DOCK_HANDLER, length * 0.5, DeviceHandlerIF::SEND_READ); @@ -52,6 +56,8 @@ ReturnValue_t pst::gomspacePstInit(FixedTimeslotTaskIF *thisSequence){ length * 0.5, DeviceHandlerIF::SEND_READ); thisSequence->addSlot(objects::PDU2_HANDLER, length * 0.5, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::ACU_HANDLER, + length * 0.5, DeviceHandlerIF::SEND_READ); thisSequence->addSlot(objects::P60DOCK_HANDLER, length * 0.75, DeviceHandlerIF::GET_READ); @@ -59,6 +65,8 @@ ReturnValue_t pst::gomspacePstInit(FixedTimeslotTaskIF *thisSequence){ length * 0.75, DeviceHandlerIF::GET_READ); thisSequence->addSlot(objects::PDU2_HANDLER, length * 0.75, DeviceHandlerIF::GET_READ); + thisSequence->addSlot(objects::ACU_HANDLER, + length * 0.75, DeviceHandlerIF::GET_READ); if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) { return HasReturnvaluesIF::RETURN_OK; diff --git a/mission/core/GenericFactory.cpp b/mission/core/GenericFactory.cpp index 77a7a1e8..1fb7ca38 100644 --- a/mission/core/GenericFactory.cpp +++ b/mission/core/GenericFactory.cpp @@ -92,6 +92,8 @@ void ObjectFactory::produceGenericObjects() { addresses::PDU1); CspCookie* pdu2CspCookie = new CspCookie(PDU::MAX_REPLY_LENGTH, addresses::PDU2); + CspCookie* acuCspCookie = new CspCookie(ACU::MAX_REPLY_LENGTH, + addresses::ACU); /* Communication interfaces */ new CspComIF(objects::CSP_COM_IF); @@ -106,6 +108,9 @@ void ObjectFactory::produceGenericObjects() { new GomspaceDeviceHandler(objects::PDU2_HANDLER, objects::CSP_COM_IF, pdu2CspCookie, PDU::MAX_CONFIGTABLE_ADDRESS, PDU::MAX_HKTABLE_ADDRESS); + new GomspaceDeviceHandler(objects::ACU_HANDLER, objects::CSP_COM_IF, + acuCspCookie, ACU::MAX_CONFIGTABLE_ADDRESS, + ACU::MAX_HKTABLE_ADDRESS); /* Test Device Handler */ #if ADD_TEST_CODE == 1 From 17b4cee817f61436fdcd0f9ddd95ec63e02b93a3 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Mon, 21 Dec 2020 10:27:29 +0100 Subject: [PATCH 055/360] cspcomif removed commented lines --- bsp_linux/comIF/CspComIF.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/bsp_linux/comIF/CspComIF.cpp b/bsp_linux/comIF/CspComIF.cpp index fbd0b7e5..83be2864 100644 --- a/bsp_linux/comIF/CspComIF.cpp +++ b/bsp_linux/comIF/CspComIF.cpp @@ -83,20 +83,6 @@ ReturnValue_t CspComIF::sendMessage(CookieIF *cookie, /* Extract csp port and bytes to query from command buffer */ uint8_t cspPort; uint16_t querySize; -// result = SerializeAdapter::deSerialize(&cspPort, &sendData, -// &sendLen, SerializeIF::Endianness::BIG); -// if(result != HasReturnvaluesIF::RETURN_OK){ -// sif::error << "CspComIF: Failed to deserialize CSP port from command " -// << "buffer" << std::endl; -// return HasReturnvaluesIF::RETURN_FAILED; -// } -// SerializeAdapter::deSerialize(&querySize, &sendData, &sendLen, -// SerializeIF::Endianness::BIG); -// if(result != HasReturnvaluesIF::RETURN_OK){ -// sif::error << "CspComIF: Failed to deserialize querySize from command " -// << "buffer" << std::endl; -// return HasReturnvaluesIF::RETURN_FAILED; -// } result = getPortAndQuerySize(&sendData, &sendLen, &cspPort, &querySize); if(result != HasReturnvaluesIF::RETURN_OK) { return result; From f52d615196e8a766ea40c113cce508011643626c Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 21 Dec 2020 17:32:51 +0100 Subject: [PATCH 056/360] disabled LTO for host release build on windows --- Makefile-Hosted | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile-Hosted b/Makefile-Hosted index 9dff3677..807fe5ec 100644 --- a/Makefile-Hosted +++ b/Makefile-Hosted @@ -227,7 +227,6 @@ DEAD_CODE_REMOVAL = -Wl,--gc-sections # Link time is larger and size of object files can not be retrieved # but resulting binary is smaller. Could be used in mission/deployment build # Requires -ffunction-section in linker call -LINK_TIME_OPTIMIZATION = -flto OPTIMIZATION += $(PROTOTYPE_OPTIMIZATION) endif @@ -309,7 +308,10 @@ all: executable # Build target configuration release: OPTIMIZATION = -Os $(PROTOTYPE_OPTIMIZATION) $(LINK_TIME_OPTIMIZATION) +# Problematic on MinGW +ifneq ($(OS),Windows_NT) release: LINK_TIME_OPTIMIZATION = -flto +endif release: TARGET = Release release: OPTIMIZATION_MESSAGE = On with Link Time Optimization release: DEBUG_LEVEL = -g0 From 5d2da2bf60d6c3e9a1dc5f4581ec99462400a58e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 21 Dec 2020 17:52:53 +0100 Subject: [PATCH 057/360] makefile hosted update --- Makefile-Hosted | 12 ++++++++++-- tmtc | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Makefile-Hosted b/Makefile-Hosted index 807fe5ec..49460898 100644 --- a/Makefile-Hosted +++ b/Makefile-Hosted @@ -17,12 +17,12 @@ CUSTOM_DEFINES := # (can be overriden by adding CHIP=chip and BOARD=board to the command-line) BOARD_FILE_ROOT = bsp_hosted BOARD = host -OS_FSFW = host -CUSTOM_DEFINES += -D$(OS_FSFW) +DETECTED_OS := # Copied from stackoverflow, can be used to differentiate between Windows # and Linux ifeq ($(OS),Windows_NT) + DETECTED_OS = WINDOWS CUSTOM_DEFINES += -DWIN32 ifeq ($(PROCESSOR_ARCHITEW6432),AMD64) CUSTOM_DEFINES += -DAMD64 @@ -55,6 +55,14 @@ else endif endif +ifeq (${DETECTED_OS}, WINDOWS) +OS_FSFW = host +else +OS_FSFW = linux +endif + +CUSTOM_DEFINES += -D$(OS_FSFW) + # General folder paths FRAMEWORK_PATH = fsfw MISSION_PATH = mission diff --git a/tmtc b/tmtc index e0c896e6..07b6a9df 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit e0c896e62d25286d00599ca57b71d0a3495ed95f +Subproject commit 07b6a9df18baff999ca52c2f2781f8f77f8dcb65 From a6067268242604b904f2c19b8df5cd59da0309e3 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 21 Dec 2020 18:14:03 +0100 Subject: [PATCH 058/360] reparied arduino stuff --- Makefile-Hosted | 14 ++++----- bsp_hosted/comIF/ArduinoComIF.cpp | 15 ++++++---- misc/eclipse/eive-linux-host-debug.launch | 33 +++++++++++++++++++++ misc/eclipse/eive-linux-host-release.launch | 33 +++++++++++++++++++++ 4 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 misc/eclipse/eive-linux-host-debug.launch create mode 100644 misc/eclipse/eive-linux-host-release.launch diff --git a/Makefile-Hosted b/Makefile-Hosted index 49460898..3a93f625 100644 --- a/Makefile-Hosted +++ b/Makefile-Hosted @@ -187,10 +187,10 @@ $(foreach S,$(SUBDIRS),$(eval $(INCLUDE_FILE))) # VPATH += mission/pus/ -ifeq ($(DETECTED_OS), LINUX) -CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TcUnixUdpPollingTask.cpp -CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TmTcUnixUdpBridge.cpp -endif +#ifeq ($(DETECTED_OS), LINUX) +#CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TcUnixUdpPollingTask.cpp +#CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TmTcUnixUdpBridge.cpp +#endif # All C Sources included by .mk files are assigned here # Add the objects to sources so dependency handling works @@ -268,12 +268,12 @@ ASFLAGS = -Wall -g $(OPTIMIZATION) $(I_INCLUDES) -D__ASSEMBLY__ # LINK_INCLUDES specify the path to used libraries and the linker script # LINK_LIBRARIES link HCC and HAL library and enable float support LDFLAGS := -g3 -pthread $(DEAD_CODE_REMOVAL) $(OPTIMIZATION) - -LINK_INCLUDES := - LINK_LIBRARIES := + ifeq ($(OS),Windows_NT) LINK_LIBRARIES += -lwsock32 -lws2_32 +else +LINK_LIBRARIES += -lrt endif # Gnu Coverage Tools Flags diff --git a/bsp_hosted/comIF/ArduinoComIF.cpp b/bsp_hosted/comIF/ArduinoComIF.cpp index 047a60ae..2db293e6 100644 --- a/bsp_hosted/comIF/ArduinoComIF.cpp +++ b/bsp_hosted/comIF/ArduinoComIF.cpp @@ -1,5 +1,6 @@ -#include -#include +#include "ArduinoComIF.h" +#include "ArduinoCookie.h" + #include #include #include @@ -7,6 +8,8 @@ // This only works on Linux #ifdef LINUX #include +#include +#include #elif WIN32 #include #include @@ -254,7 +257,7 @@ ReturnValue_t ArduinoComIF::sendMessage(uint8_t command, encodedLen = sizeof(sendBuffer) - remainingLen; #ifdef LINUX - ssize_t writtenlen = write(serialPort, sendBuffer, encodedLen); + ssize_t writtenlen = ::write(serialPort, sendBuffer, encodedLen); if (writtenlen < 0) { //we could try to find out what happened... return RETURN_FAILED; @@ -285,7 +288,7 @@ void ArduinoComIF::handleSerialPortRx() { rxBuffer.writeData(dataFromSerial, bytesRead); - uint8_t dataReceivedSoFar[rxBuffer.maxSize()]; + uint8_t dataReceivedSoFar[rxBuffer.getMaxSize()]; uint32_t dataLenReceivedSoFar = 0; @@ -295,11 +298,11 @@ void ArduinoComIF::handleSerialPortRx() { //look for STX size_t firstSTXinRawData = 0; while ((firstSTXinRawData < dataLenReceivedSoFar) - && (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX)) { + && (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX_CHAR)) { firstSTXinRawData++; } - if (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX) { + if (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX_CHAR) { //there is no STX in our data, throw it away... rxBuffer.deleteData(dataLenReceivedSoFar); return; diff --git a/misc/eclipse/eive-linux-host-debug.launch b/misc/eclipse/eive-linux-host-debug.launch new file mode 100644 index 00000000..f5ab1ac7 --- /dev/null +++ b/misc/eclipse/eive-linux-host-debug.launch @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/eclipse/eive-linux-host-release.launch b/misc/eclipse/eive-linux-host-release.launch new file mode 100644 index 00000000..7548f831 --- /dev/null +++ b/misc/eclipse/eive-linux-host-release.launch @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 58b440109b622b23b25ca9614ddeffc19eb4fe03 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 21 Dec 2020 18:15:27 +0100 Subject: [PATCH 059/360] updated project file --- misc/eclipse/.cproject | 205 ++++++++++++++++++++++++++++++++--------- 1 file changed, 159 insertions(+), 46 deletions(-) diff --git a/misc/eclipse/.cproject b/misc/eclipse/.cproject index 776ea205..6a50d831 100644 --- a/misc/eclipse/.cproject +++ b/misc/eclipse/.cproject @@ -1,52 +1,12 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -58,16 +18,22 @@ - + + + @@ -88,6 +54,7 @@ + @@ -99,16 +66,22 @@ - + + + @@ -124,15 +97,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + @@ -141,4 +222,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 93971ad1c9a2fb7d1285e32ed174dd94548f48b4 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 21 Dec 2020 19:50:01 +0100 Subject: [PATCH 060/360] started rm3100 handler --- mission/devices/MGMHandlerRM3100.cpp | 9 ++++ mission/devices/MGMHandlerRM3100.h | 12 ++++- .../MGMHandlerRM3100Definitions.h | 46 +++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/mission/devices/MGMHandlerRM3100.cpp b/mission/devices/MGMHandlerRM3100.cpp index fbcb578d..0b18dc91 100644 --- a/mission/devices/MGMHandlerRM3100.cpp +++ b/mission/devices/MGMHandlerRM3100.cpp @@ -17,6 +17,15 @@ ReturnValue_t MGMHandlerRM3100::buildTransitionDeviceCommand( } void MGMHandlerRM3100::doStartUp() { + if(internalState == STATE_NONE) { + internalState = STATE_CONFIGURE_CMM; + } + + switch(internalState) { + case(STATE_CONFIGURE_CMM): { + + } + } } void MGMHandlerRM3100::doShutDown() { diff --git a/mission/devices/MGMHandlerRM3100.h b/mission/devices/MGMHandlerRM3100.h index d2081fa1..cf459056 100644 --- a/mission/devices/MGMHandlerRM3100.h +++ b/mission/devices/MGMHandlerRM3100.h @@ -31,9 +31,19 @@ protected: private: enum InternalState { - STATE_NONE, STATE_FIRST_CONTACT, STATE_SETUP, STATE_CHECK_REGISTERS + STATE_NONE, + STATE_CONFIGURE_CMM, + STATE_READ_CMM, + // The cycle count states are propably not going to be used because + // the default cycle count will be used. + STATE_CONFIGURE_CYCLE_COUNT, + STATE_READ_CYCLE_COUNT, + STATE_CONFIGURE_TMRC, + STATE_READ_TMRC, + STATE_NORMAL }; InternalState internalState = InternalState::STATE_NONE; + bool commandExecuted = false; }; #endif /* MISSION_DEVICEHANDLING_MGMRM3100HANDLER_H_ */ diff --git a/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h b/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h index 5bf9e8b3..5fc70cbe 100644 --- a/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h +++ b/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h @@ -1,8 +1,54 @@ #ifndef MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERRM3100DEFINITIONS_H_ #define MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERRM3100DEFINITIONS_H_ +#include + namespace RM3100 { +static constexpr uint8_t READ_MASK = 0b1000'0000; + +/*----------------------------------------------------------------------------*/ +/* CMM Register +/*----------------------------------------------------------------------------*/ +static constexpr uint8_t SET_CMM_CMZ = 1 << 6; +static constexpr uint8_t SET_CMM_CMY = 1 << 5; +static constexpr uint8_t SET_CMM_CMX = 1 << 4; +static constexpr uint8_t SET_CMM_DRDM = 1 << 2; +static constexpr uint8_t SET_CMM_START = 1; +static constexpr uint8_t CMM_REGISTER = 0x01; + +static constexpr uint8_t CMM_VALUE = SET_CMM_CMZ | SET_CMM_CMY | SET_CMM_CMX | + SET_CMM_DRDM | SET_CMM_START; + +/*----------------------------------------------------------------------------*/ +/* Cycle count register +/*----------------------------------------------------------------------------*/ +static constexpr uint8_t CYCLE_COUNT_VALUE = 0xC8; + +static constexpr uint8_t GAIN = CYCLE_COUNT_VALUE / 100 * 38; +static constexpr uint8_t CYCLE_COUNT_START_REGISTER = 0x04; + +/*----------------------------------------------------------------------------*/ +/* TMRC register +/*----------------------------------------------------------------------------*/ +static constexpr uint8_t TMRC_150HZ_VALUE = 0x94; +static constexpr uint8_t TMRC_75HZ_VALUE = 0x95; +static constexpr uint8_t TMRC_DEFAULT_37HZ_VALUE = 0x96; + +static constexpr uint8_t TMRC_REGISTER = 0x0B; +static constexpr uint8_t TMRC_DEFAULT_VALUE = TMRC_75HZ_VALUE; + +static constexpr uint8_t MEASUREMENT_REG_START = 0x24; +static constexpr uint8_t BIST_REGISTER = 0x33; +static constexpr uint8_t DATA_READY_VAL = 0b1000'0000; +static constexpr uint8_t STATUS_REGISTER = 0x34; +static constexpr uint8_t REVID_REGISTER = 0x36; + +// Range in Microtesla. 1 T equals 10000 Gauss (for comparison with LIS3 MGM) +static constexpr uint8_t RANGE = 800; + + + } From 4364ef18f3c76a7d0b9d93401cee28964de344a2 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 21 Dec 2020 19:50:50 +0100 Subject: [PATCH 061/360] type correction --- mission/devices/MGMHandlerRM3100.cpp | 11 ++++++++++- .../devicedefinitions/MGMHandlerRM3100Definitions.h | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/mission/devices/MGMHandlerRM3100.cpp b/mission/devices/MGMHandlerRM3100.cpp index 0b18dc91..7c546ffa 100644 --- a/mission/devices/MGMHandlerRM3100.cpp +++ b/mission/devices/MGMHandlerRM3100.cpp @@ -23,7 +23,16 @@ void MGMHandlerRM3100::doStartUp() { switch(internalState) { case(STATE_CONFIGURE_CMM): { - + break; + } + case(STATE_READ_CMM): { + break; + } + case(STATE_CONFIGURE_TMRC): { + break; + } + case(STATE_READ_TMRC): { + break; } } } diff --git a/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h b/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h index 5fc70cbe..dd519697 100644 --- a/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h +++ b/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h @@ -45,7 +45,7 @@ static constexpr uint8_t STATUS_REGISTER = 0x34; static constexpr uint8_t REVID_REGISTER = 0x36; // Range in Microtesla. 1 T equals 10000 Gauss (for comparison with LIS3 MGM) -static constexpr uint8_t RANGE = 800; +static constexpr uint16_t RANGE = 800; From f0b542e9cec4e0c035554c75cc011912a34c78ad Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 21 Dec 2020 19:52:00 +0100 Subject: [PATCH 062/360] rm3100 continued --- fsfw | 2 +- mission/devices/MGMHandlerLIS3MDL.cpp | 2 +- mission/devices/MGMHandlerRM3100.cpp | 60 +++++++++++++++++-- mission/devices/MGMHandlerRM3100.h | 6 ++ .../MGMHandlerRM3100Definitions.h | 7 +++ tmtc | 2 +- 6 files changed, 70 insertions(+), 9 deletions(-) diff --git a/fsfw b/fsfw index 086cbe1e..31b82975 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 086cbe1e3950cf6c904609352408a7fa48cc83ef +Subproject commit 31b82975c7ef701fa7f1ba3413cfa19cc73aa2ca diff --git a/mission/devices/MGMHandlerLIS3MDL.cpp b/mission/devices/MGMHandlerLIS3MDL.cpp index 1cc83bf8..160f43ce 100644 --- a/mission/devices/MGMHandlerLIS3MDL.cpp +++ b/mission/devices/MGMHandlerLIS3MDL.cpp @@ -283,7 +283,7 @@ ReturnValue_t MGMHandlerLIS3MDL::interpretDeviceReply(DeviceCommandId_t id, } default: { - return DeviceHandlerIF::UNKNOW_DEVICE_REPLY; + return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; } } diff --git a/mission/devices/MGMHandlerRM3100.cpp b/mission/devices/MGMHandlerRM3100.cpp index 7c546ffa..3e6fffd3 100644 --- a/mission/devices/MGMHandlerRM3100.cpp +++ b/mission/devices/MGMHandlerRM3100.cpp @@ -11,11 +11,6 @@ MGMHandlerRM3100::MGMHandlerRM3100(object_id_t objectId, MGMHandlerRM3100::~MGMHandlerRM3100() {} -ReturnValue_t MGMHandlerRM3100::buildTransitionDeviceCommand( - DeviceCommandId_t *id) { - return RETURN_OK; -} - void MGMHandlerRM3100::doStartUp() { if(internalState == STATE_NONE) { internalState = STATE_CONFIGURE_CMM; @@ -40,6 +35,27 @@ void MGMHandlerRM3100::doStartUp() { void MGMHandlerRM3100::doShutDown() { } +ReturnValue_t MGMHandlerRM3100::buildTransitionDeviceCommand( + DeviceCommandId_t *id) { + if(internalState == STATE_CONFIGURE_CMM) { + *id = RM3100::CONFIGURE_CMM; + commandBuffer[0] = RM3100::CMM_REGISTER; + commandBuffer[1] = RM3100::CMM_VALUE; + this->rawPacket = commandBuffer; + this->rawPacketLen = 2; + } + + if(internalState == STATE_READ_CMM) { + *id = RM3100::READ_CMM; + commandBuffer[0] = RM3100::CMM_REGISTER | RM3100::READ_MASK; + commandBuffer[1] = 0; + this->rawPacket = commandBuffer; + this->rawPacketLen = 2; + } + return RETURN_OK; +} + + ReturnValue_t MGMHandlerRM3100::buildNormalDeviceCommand( DeviceCommandId_t *id) { return RETURN_OK; @@ -54,10 +70,42 @@ ReturnValue_t MGMHandlerRM3100::buildCommandFromCommand( ReturnValue_t MGMHandlerRM3100::scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId, size_t *foundLen) { - return RETURN_OK; + + *foundId = this->getPendingCommand(); + *foundLen = this->rawPacketLen; + + // Data with SPI Interface has always this answer + if (start[0] == 0b11111111) { + return RETURN_OK; + } + else { + return DeviceHandlerIF::INVALID_DATA; + } } ReturnValue_t MGMHandlerRM3100::interpretDeviceReply( DeviceCommandId_t id, const uint8_t *packet) { + if(id == RM3100::CONFIGURE_CMM or id == RM3100::CONFIGURE_TMRC) { + commandExecuted = true; + } + else if(id == RM3100::READ_CMM) { + if(packet[1] == cmmRegValue) { + commandExecuted = true; + } + } + else if(id == RM3100::READ_TMRC) { + if(packet[1] == tmrcRegValue) { + commandExecuted = true; + } + else { + // Attempt reconfiguration. + internalState = STATE_CONFIGURE_TMRC; + return HasReturnvaluesIF::RETURN_FAILED; + } + } + else { + return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; + } + return RETURN_OK; } diff --git a/mission/devices/MGMHandlerRM3100.h b/mission/devices/MGMHandlerRM3100.h index cf459056..ed948560 100644 --- a/mission/devices/MGMHandlerRM3100.h +++ b/mission/devices/MGMHandlerRM3100.h @@ -44,6 +44,12 @@ private: }; InternalState internalState = InternalState::STATE_NONE; bool commandExecuted = false; + + uint8_t commandBuffer[9]; + uint8_t commandBufferLen = 0; + + uint8_t cmmRegValue = RM3100::CMM_VALUE; + uint8_t tmrcRegValue = RM3100::TMRC_DEFAULT_VALUE; }; #endif /* MISSION_DEVICEHANDLING_MGMRM3100HANDLER_H_ */ diff --git a/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h b/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h index dd519697..4f38a217 100644 --- a/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h +++ b/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h @@ -1,6 +1,7 @@ #ifndef MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERRM3100DEFINITIONS_H_ #define MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERRM3100DEFINITIONS_H_ +#include #include namespace RM3100 { @@ -47,7 +48,13 @@ static constexpr uint8_t REVID_REGISTER = 0x36; // Range in Microtesla. 1 T equals 10000 Gauss (for comparison with LIS3 MGM) static constexpr uint16_t RANGE = 800; +static constexpr DeviceCommandId_t CONFIGURE_CMM = 3; +static constexpr DeviceCommandId_t READ_CMM = 4; +//static constexpr DeviceCommandId_t CONFIGURE_CYC + +static constexpr DeviceCommandId_t CONFIGURE_TMRC = 5; +static constexpr DeviceCommandId_t READ_TMRC = 6; } diff --git a/tmtc b/tmtc index 07b6a9df..e0c896e6 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 07b6a9df18baff999ca52c2f2781f8f77f8dcb65 +Subproject commit e0c896e62d25286d00599ca57b71d0a3495ed95f From f70c767a1c25893c2dc9cbee07c18333e326fc3b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 21 Dec 2020 23:09:35 +0100 Subject: [PATCH 063/360] rm3100 continued --- bsp_hosted/InitMission.cpp | 4 +- bsp_hosted/fsfwconfig/OBSWConfig.h | 3 + .../fsfwconfig/events/subsystemIdRanges.h | 1 + bsp_hosted/fsfwconfig/fsfwconfig.mk | 10 +- bsp_hosted/fsfwconfig/returnvalues/classIds.h | 3 +- bsp_hosted/main.cpp | 5 +- fsfwconfig/OBSWConfig.h | 3 + fsfwconfig/events/subsystemIdRanges.h | 3 +- fsfwconfig/returnvalues/classIds.h | 3 +- mission/devices/MGMHandlerLIS3MDL.cpp | 2 +- mission/devices/MGMHandlerRM3100.cpp | 199 +++++++++++++++--- mission/devices/MGMHandlerRM3100.h | 20 +- .../MGMHandlerRM3100Definitions.h | 78 ++++++- 13 files changed, 282 insertions(+), 52 deletions(-) diff --git a/bsp_hosted/InitMission.cpp b/bsp_hosted/InitMission.cpp index 29101d08..cfc33db9 100644 --- a/bsp_hosted/InitMission.cpp +++ b/bsp_hosted/InitMission.cpp @@ -8,8 +8,8 @@ #include #include #include -#include -#include +#include +#include #include diff --git a/bsp_hosted/fsfwconfig/OBSWConfig.h b/bsp_hosted/fsfwconfig/OBSWConfig.h index edfa1bca..f9e76160 100644 --- a/bsp_hosted/fsfwconfig/OBSWConfig.h +++ b/bsp_hosted/fsfwconfig/OBSWConfig.h @@ -6,6 +6,9 @@ #ifndef CONFIG_OBSWCONFIG_H_ #define CONFIG_OBSWCONFIG_H_ +#include "returnvalues/classIds.h" +#include "events/subsystemIdRanges.h" + #define OBSW_ADD_TEST_CODE 0 // These defines should be disabled for mission code but are useful for diff --git a/bsp_hosted/fsfwconfig/events/subsystemIdRanges.h b/bsp_hosted/fsfwconfig/events/subsystemIdRanges.h index 2255b345..1128b26b 100644 --- a/bsp_hosted/fsfwconfig/events/subsystemIdRanges.h +++ b/bsp_hosted/fsfwconfig/events/subsystemIdRanges.h @@ -18,6 +18,7 @@ enum: uint8_t { PUS_SERVICE_8, PUS_SERVICE_23, MGM_LIS3MDL, + MGM_RM3100, DUMMY_DEVICE, }; diff --git a/bsp_hosted/fsfwconfig/fsfwconfig.mk b/bsp_hosted/fsfwconfig/fsfwconfig.mk index 105c3fba..53cb0fc7 100644 --- a/bsp_hosted/fsfwconfig/fsfwconfig.mk +++ b/bsp_hosted/fsfwconfig/fsfwconfig.mk @@ -4,12 +4,4 @@ CXXSRC += $(wildcard $(CURRENTPATH)/objects/*.cpp) CXXSRC += $(wildcard $(CURRENTPATH)/pollingsequence/*.cpp) CXXSRC += $(wildcard $(CURRENTPATH)/events/*.cpp) -INCLUDES += $(CURRENTPATH) -INCLUDES += $(CURRENTPATH)/objects -INCLUDES += $(CURRENTPATH)/ipc -INCLUDES += $(CURRENTPATH)/pollingsequence -INCLUDES += $(CURRENTPATH)/returnvalues -INCLUDES += $(CURRENTPATH)/tmtc -INCLUDES += $(CURRENTPATH)/events -INCLUDES += $(CURRENTPATH)/devices -INCLUDES += $(CURRENTPATH)/cdatapool \ No newline at end of file +INCLUDES += $(CURRENTPATH) \ No newline at end of file diff --git a/bsp_hosted/fsfwconfig/returnvalues/classIds.h b/bsp_hosted/fsfwconfig/returnvalues/classIds.h index f6427a1f..21371c15 100644 --- a/bsp_hosted/fsfwconfig/returnvalues/classIds.h +++ b/bsp_hosted/fsfwconfig/returnvalues/classIds.h @@ -11,7 +11,8 @@ namespace CLASS_ID { enum { MISSION_CLASS_ID_START = FW_CLASS_ID_COUNT, - MGM_LIS3MDL + MGM_LIS3MDL, + MGM_RM3100 }; } diff --git a/bsp_hosted/main.cpp b/bsp_hosted/main.cpp index 50d1e7f2..02d793f9 100644 --- a/bsp_hosted/main.cpp +++ b/bsp_hosted/main.cpp @@ -1,5 +1,6 @@ -#include -#include +#include "InitMission.h" + +#include #include #include diff --git a/fsfwconfig/OBSWConfig.h b/fsfwconfig/OBSWConfig.h index d8784551..7b9dfbc4 100644 --- a/fsfwconfig/OBSWConfig.h +++ b/fsfwconfig/OBSWConfig.h @@ -6,6 +6,9 @@ #ifndef FSFWCONFIG_OBSWCONFIG_H_ #define FSFWCONFIG_OBSWCONFIG_H_ +#include "returnvalues/classIds.h" +#include "events/subsystemIdRanges.h" + #define OBSW_ADD_TEST_CODE 0 // These defines should be disabled for mission code but are useful for diff --git a/fsfwconfig/events/subsystemIdRanges.h b/fsfwconfig/events/subsystemIdRanges.h index ece990b2..47e04816 100644 --- a/fsfwconfig/events/subsystemIdRanges.h +++ b/fsfwconfig/events/subsystemIdRanges.h @@ -17,7 +17,8 @@ enum: uint8_t { PUS_SERVICE_6, PUS_SERVICE_8, PUS_SERVICE_23, - MGM_LIS3MDL + MGM_LIS3MDL, + MGM_RM3100 }; } diff --git a/fsfwconfig/returnvalues/classIds.h b/fsfwconfig/returnvalues/classIds.h index b5835c84..6d68d954 100644 --- a/fsfwconfig/returnvalues/classIds.h +++ b/fsfwconfig/returnvalues/classIds.h @@ -11,7 +11,8 @@ namespace CLASS_ID { enum { MISSION_CLASS_ID_START = FW_CLASS_ID_COUNT, - MGM_LIS3MDL + MGM_LIS3MDL, + MGM_RM3100 }; } diff --git a/mission/devices/MGMHandlerLIS3MDL.cpp b/mission/devices/MGMHandlerLIS3MDL.cpp index 160f43ce..1833ef54 100644 --- a/mission/devices/MGMHandlerLIS3MDL.cpp +++ b/mission/devices/MGMHandlerLIS3MDL.cpp @@ -39,7 +39,7 @@ void MGMHandlerLIS3MDL::doStartUp() { // Set up cached registers which will be used to configure the MGM. if(commandExecuted) { commandExecuted = false; - setMode(MODE_NORMAL); + setMode(_MODE_TO_ON); } break; } diff --git a/mission/devices/MGMHandlerRM3100.cpp b/mission/devices/MGMHandlerRM3100.cpp index 3e6fffd3..2ff57d85 100644 --- a/mission/devices/MGMHandlerRM3100.cpp +++ b/mission/devices/MGMHandlerRM3100.cpp @@ -1,4 +1,5 @@ #include "MGMHandlerRM3100.h" + #include #include #include @@ -16,61 +17,115 @@ void MGMHandlerRM3100::doStartUp() { internalState = STATE_CONFIGURE_CMM; } - switch(internalState) { - case(STATE_CONFIGURE_CMM): { - break; + if(internalState == STATE_CONFIGURE_CMM) { + internalState = STATE_READ_CMM; } - case(STATE_READ_CMM): { - break; + else if(internalState == STATE_READ_CMM) { + if(commandExecuted) { + internalState = STATE_CONFIGURE_TMRC; + } } - case(STATE_CONFIGURE_TMRC): { - break; - } - case(STATE_READ_TMRC): { - break; + + if(internalState == STATE_CONFIGURE_TMRC) { + internalState = STATE_READ_TMRC; } + else if(internalState == STATE_READ_TMRC) { + if(commandExecuted) { + internalState = STATE_NORMAL; + setMode(_MODE_TO_ON); + } } } void MGMHandlerRM3100::doShutDown() { + setMode(_MODE_POWER_DOWN); } ReturnValue_t MGMHandlerRM3100::buildTransitionDeviceCommand( DeviceCommandId_t *id) { if(internalState == STATE_CONFIGURE_CMM) { *id = RM3100::CONFIGURE_CMM; - commandBuffer[0] = RM3100::CMM_REGISTER; - commandBuffer[1] = RM3100::CMM_VALUE; - this->rawPacket = commandBuffer; - this->rawPacketLen = 2; } if(internalState == STATE_READ_CMM) { *id = RM3100::READ_CMM; - commandBuffer[0] = RM3100::CMM_REGISTER | RM3100::READ_MASK; - commandBuffer[1] = 0; - this->rawPacket = commandBuffer; - this->rawPacketLen = 2; } - return RETURN_OK; -} + if(internalState == STATE_CONFIGURE_TMRC) { + *id = RM3100::CONFIGURE_TMRC; + } -ReturnValue_t MGMHandlerRM3100::buildNormalDeviceCommand( - DeviceCommandId_t *id) { - return RETURN_OK; + if(internalState == STATE_READ_TMRC) { + *id = RM3100::READ_TMRC; + } + + return buildCommandFromCommand(*id, nullptr, 0); } ReturnValue_t MGMHandlerRM3100::buildCommandFromCommand( DeviceCommandId_t deviceCommand, const uint8_t *commandData, size_t commandDataLen) { + switch(deviceCommand) { + case(RM3100::CONFIGURE_CMM): { + commandBuffer[0] = RM3100::CMM_REGISTER; + commandBuffer[1] = RM3100::CMM_VALUE; + rawPacket = commandBuffer; + rawPacketLen = 2; + break; + } + case(RM3100::READ_CMM): { + commandBuffer[0] = RM3100::CMM_REGISTER | RM3100::READ_MASK; + commandBuffer[1] = 0; + rawPacket = commandBuffer; + rawPacketLen = 2; + break; + } + case(RM3100::CONFIGURE_TMRC): { + return handleTmrcConfigCommand(deviceCommand, commandData, + commandDataLen); + } + case(RM3100::READ_TMRC): { + commandBuffer[0] = RM3100::TMRC_REGISTER | RM3100::READ_MASK; + commandBuffer[1] = 0; + rawPacket = commandBuffer; + rawPacketLen = 2; + break; + } + case(RM3100::CONFIGURE_CYCLE_COUNT): { + return handleCycleCountConfigCommand(deviceCommand, commandData, + commandDataLen); + } + case(RM3100::READ_CYCLE_COUNT): { + commandBuffer[0] = RM3100::CYCLE_COUNT_START_REGISTER | + RM3100::READ_MASK; + std::memset(commandBuffer + 1, 0, 6); + rawPacket = commandBuffer; + rawPacketLen = 7; + break; + } + case(RM3100::READ_DATA): { + commandBuffer[0] = RM3100::MEASUREMENT_REG_START | RM3100::READ_MASK; + std::memset(commandBuffer + 1, 0, 9); + rawPacketLen = 10; + break; + } + default: + return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + } return RETURN_OK; } +ReturnValue_t MGMHandlerRM3100::buildNormalDeviceCommand( + DeviceCommandId_t *id) { + *id = RM3100::READ_DATA; + return buildCommandFromCommand(*id, nullptr, 0); +} + ReturnValue_t MGMHandlerRM3100::scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId, size_t *foundLen) { + // SPI, ID will always be the one of the last sent command. *foundId = this->getPendingCommand(); *foundLen = this->rawPacketLen; @@ -85,27 +140,115 @@ ReturnValue_t MGMHandlerRM3100::scanForReply(const uint8_t *start, ReturnValue_t MGMHandlerRM3100::interpretDeviceReply( DeviceCommandId_t id, const uint8_t *packet) { - if(id == RM3100::CONFIGURE_CMM or id == RM3100::CONFIGURE_TMRC) { - commandExecuted = true; - } - else if(id == RM3100::READ_CMM) { + if(id == RM3100::READ_CMM) { if(packet[1] == cmmRegValue) { commandExecuted = true; } + else { + // Attempt reconfiguration. + internalState = STATE_CONFIGURE_CMM; + return DeviceHandlerIF::DEVICE_REPLY_INVALID; + } } else if(id == RM3100::READ_TMRC) { if(packet[1] == tmrcRegValue) { commandExecuted = true; + // Reading TMRC was commanded. + if(mode == MODE_NORMAL) { + + } } else { // Attempt reconfiguration. internalState = STATE_CONFIGURE_TMRC; - return HasReturnvaluesIF::RETURN_FAILED; + return DeviceHandlerIF::DEVICE_REPLY_INVALID; } } + else if(id == RM3100::READ_DATA) { + // analyze data here. + // Field strengths in micro Tesla + int32_t fieldStrengthX = (packet[1] << 16 | packet[2] << 8 | packet[3]) + * scaleFactorX; + int32_t fieldStrengthY = (packet[4] << 16 | packet[5] << 8 | packet[6]) + * scaleFactorY; + int32_t fieldStrengthZ = (packet[7] << 16 | packet[8] << 8 | packet[9]) + * scaleFactorZ; + } else { return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; } return RETURN_OK; } + +ReturnValue_t MGMHandlerRM3100::handleCycleCountConfigCommand( + DeviceCommandId_t deviceCommand, const uint8_t *commandData, + size_t commandDataLen) { + if(commandData == nullptr) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + // Set cycle count + if(commandDataLen == 2) { + handleCycleCommand(true, commandData, commandDataLen); + } + else if(commandDataLen == 6) { + handleCycleCommand(false, commandData, commandDataLen); + } + else { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + commandBuffer[0] = RM3100::CYCLE_COUNT_VALUE; + std::memcpy(commandBuffer + 1, &cycleCountRegValueX, 2); + std::memcpy(commandBuffer + 3, &cycleCountRegValueY, 2); + std::memcpy(commandBuffer + 5, &cycleCountRegValueZ, 2); + rawPacketLen = 7; + rawPacket = commandBuffer; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MGMHandlerRM3100::handleCycleCommand(bool oneCycleValue, + const uint8_t *commandData, size_t commandDataLen) { + RM3100::CycleCountCommand command(oneCycleValue); + ReturnValue_t result = command.deSerialize(&commandData, &commandDataLen, + SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + // Data sheet p.30 + // "while noise limits the useful upper range to ~400 cycle counts." + if(command.cycleCountX > 450 ) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + if(not oneCycleValue and + (command.cycleCountY > 450 or command.cycleCountZ > 450)) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + cycleCountRegValueX = command.cycleCountX; + cycleCountRegValueY = command.cycleCountY; + cycleCountRegValueZ = command.cycleCountZ; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MGMHandlerRM3100::handleTmrcConfigCommand( + DeviceCommandId_t deviceCommand, const uint8_t *commandData, + size_t commandDataLen) { + if(commandData == nullptr) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + if(commandDataLen != 1) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + commandBuffer[0] = RM3100::TMRC_REGISTER; + commandBuffer[1] = commandData[1]; + rawPacketLen = 2; + rawPacket = commandBuffer; + return HasReturnvaluesIF::RETURN_OK; +} + diff --git a/mission/devices/MGMHandlerRM3100.h b/mission/devices/MGMHandlerRM3100.h index ed948560..605ac890 100644 --- a/mission/devices/MGMHandlerRM3100.h +++ b/mission/devices/MGMHandlerRM3100.h @@ -4,8 +4,12 @@ #include "devicedefinitions/MGMHandlerRM3100Definitions.h" #include +#include + class MGMHandlerRM3100: public DeviceHandlerBase { public: + static const uint8_t INTERFACE_ID = CLASS_ID::MGM_RM3100; + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MGM_RM3100; MGMHandlerRM3100(object_id_t objectId, object_id_t deviceCommunication, CookieIF* comCookie); @@ -45,11 +49,25 @@ private: InternalState internalState = InternalState::STATE_NONE; bool commandExecuted = false; - uint8_t commandBuffer[9]; + uint8_t commandBuffer[10]; uint8_t commandBufferLen = 0; uint8_t cmmRegValue = RM3100::CMM_VALUE; uint8_t tmrcRegValue = RM3100::TMRC_DEFAULT_VALUE; + uint16_t cycleCountRegValueX = RM3100::CYCLE_COUNT_VALUE; + uint16_t cycleCountRegValueY = RM3100::CYCLE_COUNT_VALUE; + uint16_t cycleCountRegValueZ = RM3100::CYCLE_COUNT_VALUE; + float scaleFactorX = 1 / RM3100::DEFAULT_GAIN; + float scaleFactorY = 1 / RM3100::DEFAULT_GAIN; + float scaleFactorZ = 1 / RM3100::DEFAULT_GAIN; + + ReturnValue_t handleCycleCountConfigCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData,size_t commandDataLen); + ReturnValue_t handleCycleCommand(bool oneCycleValue, + const uint8_t *commandData, size_t commandDataLen); + + ReturnValue_t handleTmrcConfigCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData,size_t commandDataLen); }; #endif /* MISSION_DEVICEHANDLING_MGMRM3100HANDLER_H_ */ diff --git a/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h b/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h index 4f38a217..60a107d8 100644 --- a/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h +++ b/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h @@ -1,7 +1,10 @@ #ifndef MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERRM3100DEFINITIONS_H_ #define MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERRM3100DEFINITIONS_H_ +#include +#include #include +#include #include namespace RM3100 { @@ -24,9 +27,11 @@ static constexpr uint8_t CMM_VALUE = SET_CMM_CMZ | SET_CMM_CMY | SET_CMM_CMX | /*----------------------------------------------------------------------------*/ /* Cycle count register /*----------------------------------------------------------------------------*/ +// Default value (200) static constexpr uint8_t CYCLE_COUNT_VALUE = 0xC8; -static constexpr uint8_t GAIN = CYCLE_COUNT_VALUE / 100 * 38; +static constexpr float DEFAULT_GAIN = static_cast(CYCLE_COUNT_VALUE) / + 100 * 38; static constexpr uint8_t CYCLE_COUNT_START_REGISTER = 0x04; /*----------------------------------------------------------------------------*/ @@ -48,13 +53,74 @@ static constexpr uint8_t REVID_REGISTER = 0x36; // Range in Microtesla. 1 T equals 10000 Gauss (for comparison with LIS3 MGM) static constexpr uint16_t RANGE = 800; -static constexpr DeviceCommandId_t CONFIGURE_CMM = 3; -static constexpr DeviceCommandId_t READ_CMM = 4; +static constexpr DeviceCommandId_t READ_DATA = 0; -//static constexpr DeviceCommandId_t CONFIGURE_CYC +static constexpr DeviceCommandId_t CONFIGURE_CMM = 1; +static constexpr DeviceCommandId_t READ_CMM = 2; -static constexpr DeviceCommandId_t CONFIGURE_TMRC = 5; -static constexpr DeviceCommandId_t READ_TMRC = 6; +static constexpr DeviceCommandId_t CONFIGURE_TMRC = 3; +static constexpr DeviceCommandId_t READ_TMRC = 4; + +static constexpr DeviceCommandId_t CONFIGURE_CYCLE_COUNT = 5; +static constexpr DeviceCommandId_t READ_CYCLE_COUNT = 6; + +class CycleCountCommand: public SerialLinkedListAdapter { +public: + CycleCountCommand(bool oneCycleCount = true): oneCycleCount(oneCycleCount) { + setLinks(oneCycleCount); + } + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override { + ReturnValue_t result = SerialLinkedListAdapter::deSerialize(buffer, + size, streamEndianness); + if(oneCycleCount) { + cycleCountY = cycleCountX; + cycleCountZ = cycleCountX; + } + return result; + } + + SerializeElement cycleCountX; + SerializeElement cycleCountY; + SerializeElement cycleCountZ; + +private: + void setLinks(bool oneCycleCount) { + setStart(&cycleCountX); + if(not oneCycleCount) { + cycleCountX.setNext(&cycleCountY); + cycleCountY.setNext(&cycleCountZ); + } + } + + bool oneCycleCount; +}; + +static constexpr uint32_t MGM_DATASET_ID = READ_DATA; + +enum MgmPoolIds: lp_id_t { + FIELD_STRENGTH_X, + FIELD_STRENGTH_Y, + FIELD_STRENGTH_Z, +}; + +class Rm3100PrimaryDataset: public StaticLocalDataSet<3 * sizeof(float)> { +public: + Rm3100PrimaryDataset(HasLocalDataPoolIF* hkOwner): + StaticLocalDataSet(hkOwner, MGM_DATASET_ID) {} + + Rm3100PrimaryDataset(object_id_t mgmId): + StaticLocalDataSet(sid_t(mgmId, MGM_DATASET_ID)) {} + + // Field strengths in micro Tesla. + lp_var_t fieldStrengthX = lp_var_t(sid.objectId, + FIELD_STRENGTH_X, this); + lp_var_t fieldStrengthY = lp_var_t(sid.objectId, + FIELD_STRENGTH_Y, this); + lp_var_t fieldStrengthZ = lp_var_t(sid.objectId, + FIELD_STRENGTH_Z, this); +}; } From 71853fe1aa6bde8495542e533e2198d48a4f1cc2 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 22 Dec 2020 00:24:19 +0100 Subject: [PATCH 064/360] rm3100 finished, lis3 set normal datapool entries invalid removed, will be replaced by default implementation --- mission/devices/MGMHandlerLIS3MDL.cpp | 5 +- mission/devices/MGMHandlerLIS3MDL.h | 24 +++--- mission/devices/MGMHandlerRM3100.cpp | 115 ++++++++++++++++++++++---- mission/devices/MGMHandlerRM3100.h | 41 +++++++-- 4 files changed, 143 insertions(+), 42 deletions(-) diff --git a/mission/devices/MGMHandlerLIS3MDL.cpp b/mission/devices/MGMHandlerLIS3MDL.cpp index 1833ef54..35b71c79 100644 --- a/mission/devices/MGMHandlerLIS3MDL.cpp +++ b/mission/devices/MGMHandlerLIS3MDL.cpp @@ -259,6 +259,7 @@ ReturnValue_t MGMHandlerLIS3MDL::interpretDeviceReply(DeviceCommandId_t id, dataset.fieldStrengthX = mgmX; dataset.fieldStrengthY = mgmY; dataset.fieldStrengthZ = mgmZ; + dataset.setValidity(true, true); dataset.commit(20); } break; @@ -406,10 +407,6 @@ ReturnValue_t MGMHandlerLIS3MDL::prepareCtrlRegisterWrite() { return RETURN_OK; } -void MGMHandlerLIS3MDL::setNormalDatapoolEntriesInvalid() { - // TODO: use new distributed datapools here. -} - void MGMHandlerLIS3MDL::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { } diff --git a/mission/devices/MGMHandlerLIS3MDL.h b/mission/devices/MGMHandlerLIS3MDL.h index b400daee..c48b1fc2 100644 --- a/mission/devices/MGMHandlerLIS3MDL.h +++ b/mission/devices/MGMHandlerLIS3MDL.h @@ -35,28 +35,26 @@ public: protected: /** DeviceHandlerBase overrides */ - virtual void doShutDown() override; - virtual void doStartUp() override; - virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom) override; - virtual uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; - virtual ReturnValue_t buildCommandFromCommand( + void doShutDown() override; + void doStartUp() override; + void doTransition(Mode_t modeFrom, Submode_t subModeFrom) override; + uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; + ReturnValue_t buildCommandFromCommand( DeviceCommandId_t deviceCommand, const uint8_t *commandData, size_t commandDataLen) override; - virtual ReturnValue_t buildTransitionDeviceCommand( + ReturnValue_t buildTransitionDeviceCommand( DeviceCommandId_t *id) override; - virtual ReturnValue_t buildNormalDeviceCommand( + ReturnValue_t buildNormalDeviceCommand( DeviceCommandId_t *id) override; - virtual ReturnValue_t scanForReply(const uint8_t *start, size_t len, + ReturnValue_t scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId, size_t *foundLen) override; - virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) override; - virtual void fillCommandAndReplyMap() override; - virtual void modeChanged(void) override; - void setNormalDatapoolEntriesInvalid() override; + void fillCommandAndReplyMap() override; + void modeChanged(void) override; ReturnValue_t initializeLocalDataPool(LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) override; - private: MGMLIS3MDL::MgmPrimaryDataset dataset; diff --git a/mission/devices/MGMHandlerRM3100.cpp b/mission/devices/MGMHandlerRM3100.cpp index 2ff57d85..6040afad 100644 --- a/mission/devices/MGMHandlerRM3100.cpp +++ b/mission/devices/MGMHandlerRM3100.cpp @@ -7,7 +7,11 @@ MGMHandlerRM3100::MGMHandlerRM3100(object_id_t objectId, object_id_t deviceCommunication, CookieIF* comCookie): - DeviceHandlerBase(objectId, deviceCommunication, comCookie) { + DeviceHandlerBase(objectId, deviceCommunication, comCookie), + primaryDataset(this) { +#if OBSW_ENHANCED_PRINTOUT == 1 + debugDivider = new PeriodicOperationDivider(10); +#endif } MGMHandlerRM3100::~MGMHandlerRM3100() {} @@ -140,7 +144,9 @@ ReturnValue_t MGMHandlerRM3100::scanForReply(const uint8_t *start, ReturnValue_t MGMHandlerRM3100::interpretDeviceReply( DeviceCommandId_t id, const uint8_t *packet) { - if(id == RM3100::READ_CMM) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + switch(id) { + case(RM3100::READ_CMM): { if(packet[1] == cmmRegValue) { commandExecuted = true; } @@ -149,13 +155,14 @@ ReturnValue_t MGMHandlerRM3100::interpretDeviceReply( internalState = STATE_CONFIGURE_CMM; return DeviceHandlerIF::DEVICE_REPLY_INVALID; } + break; } - else if(id == RM3100::READ_TMRC) { + case(RM3100::READ_TMRC): { if(packet[1] == tmrcRegValue) { commandExecuted = true; - // Reading TMRC was commanded. - if(mode == MODE_NORMAL) { - + // Reading TMRC was commanded. Trigger event to inform ground. + if(mode != _MODE_START_UP) { + triggerEvent(tmrcSet, tmrcRegValue, 0); } } else { @@ -163,22 +170,33 @@ ReturnValue_t MGMHandlerRM3100::interpretDeviceReply( internalState = STATE_CONFIGURE_TMRC; return DeviceHandlerIF::DEVICE_REPLY_INVALID; } + break; } - else if(id == RM3100::READ_DATA) { - // analyze data here. - // Field strengths in micro Tesla - int32_t fieldStrengthX = (packet[1] << 16 | packet[2] << 8 | packet[3]) - * scaleFactorX; - int32_t fieldStrengthY = (packet[4] << 16 | packet[5] << 8 | packet[6]) - * scaleFactorY; - int32_t fieldStrengthZ = (packet[7] << 16 | packet[8] << 8 | packet[9]) - * scaleFactorZ; + case(RM3100::READ_CYCLE_COUNT): { + uint16_t cycleCountX = packet[1] << 8 | packet[2]; + uint16_t cycleCountY = packet[3] << 8 | packet[4]; + uint16_t cycleCountZ = packet[5] << 8 | packet[6]; + if(cycleCountX != cycleCountRegValueX or + cycleCountY != cycleCountRegValueY or + cycleCountZ != cycleCountRegValueZ) { + return DeviceHandlerIF::DEVICE_REPLY_INVALID; + } + // Reading TMRC was commanded. Trigger event to inform ground. + if(mode != _MODE_START_UP) { + uint32_t eventParam1 = cycleCountX << 16 | cycleCountY; + triggerEvent(cycleCountersSet, eventParam1, cycleCountZ); + } + break; } - else { + case(RM3100::READ_DATA): { + result = handleDataReadout(packet); + break; + } + default: return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; } - return RETURN_OK; + return result; } ReturnValue_t MGMHandlerRM3100::handleCycleCountConfigCommand( @@ -252,3 +270,66 @@ ReturnValue_t MGMHandlerRM3100::handleTmrcConfigCommand( return HasReturnvaluesIF::RETURN_OK; } +void MGMHandlerRM3100::fillCommandAndReplyMap() { + insertInCommandAndReplyMap(RM3100::CONFIGURE_CMM, 1); + insertInCommandAndReplyMap(RM3100::READ_CMM, 1); + + insertInCommandAndReplyMap(RM3100::CONFIGURE_TMRC, 1); + insertInCommandAndReplyMap(RM3100::READ_TMRC, 1); + + insertInCommandAndReplyMap(RM3100::CONFIGURE_CYCLE_COUNT, 1); + insertInCommandAndReplyMap(RM3100::READ_CYCLE_COUNT, 1); + + insertInCommandAndReplyMap(RM3100::READ_DATA, 1, &primaryDataset); +} + +void MGMHandlerRM3100::modeChanged(void) { + internalState = STATE_NONE; +} + +ReturnValue_t MGMHandlerRM3100::initializeLocalDataPool( + LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_X, + new PoolEntry(0.0)); + localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_Y, + new PoolEntry(0.0)); + localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_Z, + new PoolEntry(0.0)); + return HasReturnvaluesIF::RETURN_OK; +} + +uint32_t MGMHandlerRM3100::getTransitionDelayMs(Mode_t from, Mode_t to) { + return 5000; +} + +ReturnValue_t MGMHandlerRM3100::handleDataReadout(const uint8_t *packet) { + // analyze data here. + // Field strengths in micro Tesla + int32_t fieldStrengthX = (packet[1] << 16 | packet[2] << 8 | packet[3]) + * scaleFactorX; + int32_t fieldStrengthY = (packet[4] << 16 | packet[5] << 8 | packet[6]) + * scaleFactorY; + int32_t fieldStrengthZ = (packet[7] << 16 | packet[8] << 8 | packet[9]) + * scaleFactorZ; + +#if OBSW_ENHANCED_PRINTOUT == 1 + if(debugDivider->checkAndIncrement()) { + sif::info << "MGMHandlerLIS3: Magnetic field strength in" + " microtesla:" << std::endl; + // Set terminal to utf-8 if there is an issue with micro printout. + sif::info << "X: " << fieldStrengthX << " \xC2\xB5T" << std::endl; + sif::info << "Y: " << fieldStrengthY << " \xC2\xB5T" << std::endl; + sif::info << "Z: " << fieldStrengthZ << " \xC2\xB5T" << std::endl; + } +#endif + + ReturnValue_t result = primaryDataset.read(20); + if(result == HasReturnvaluesIF::RETURN_OK) { + primaryDataset.fieldStrengthX = fieldStrengthX; + primaryDataset.fieldStrengthY = fieldStrengthY; + primaryDataset.fieldStrengthZ = fieldStrengthZ; + primaryDataset.setValidity(true, true); + result = primaryDataset.commit(20); + } + return result; +} diff --git a/mission/devices/MGMHandlerRM3100.h b/mission/devices/MGMHandlerRM3100.h index 605ac890..58096a8d 100644 --- a/mission/devices/MGMHandlerRM3100.h +++ b/mission/devices/MGMHandlerRM3100.h @@ -6,10 +6,23 @@ #include +#if OBSW_ENHANCED_PRINTOUT == 1 +#include +#endif + class MGMHandlerRM3100: public DeviceHandlerBase { public: static const uint8_t INTERFACE_ID = CLASS_ID::MGM_RM3100; - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MGM_RM3100; + + //! P1: TMRC value which was set, P2: 0 + static constexpr Event tmrcSet = event::makeEvent(SUBSYSTEM_ID::MGM_RM3100, + 0x00, severity::INFO); + + //! P1: First two bytes new Cycle Count X + //! P1: Second two bytes new Cycle Count Y + //! P2: New cycle count Z + static constexpr Event cycleCountersSet = event::makeEvent( + SUBSYSTEM_ID::MGM_RM3100, 0x01, severity::INFO); MGMHandlerRM3100(object_id_t objectId, object_id_t deviceCommunication, CookieIF* comCookie); @@ -18,20 +31,26 @@ public: protected: /* DeviceHandlerBase overrides */ - virtual ReturnValue_t buildTransitionDeviceCommand( + ReturnValue_t buildTransitionDeviceCommand( DeviceCommandId_t *id) override; - virtual void doStartUp() override; - virtual void doShutDown() override; - virtual ReturnValue_t buildNormalDeviceCommand( + void doStartUp() override; + void doShutDown() override; + ReturnValue_t buildNormalDeviceCommand( DeviceCommandId_t *id) override; - virtual ReturnValue_t buildCommandFromCommand( + ReturnValue_t buildCommandFromCommand( DeviceCommandId_t deviceCommand, const uint8_t *commandData, size_t commandDataLen) override; - virtual ReturnValue_t scanForReply(const uint8_t *start, size_t len, + ReturnValue_t scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId, size_t *foundLen) override; - virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) override; + void fillCommandAndReplyMap() override; + void modeChanged(void) override; + uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; + ReturnValue_t initializeLocalDataPool(LocalDataPool &localDataPoolMap, + LocalDataPoolManager &poolManager) override; + private: enum InternalState { @@ -48,6 +67,7 @@ private: }; InternalState internalState = InternalState::STATE_NONE; bool commandExecuted = false; + RM3100::Rm3100PrimaryDataset primaryDataset; uint8_t commandBuffer[10]; uint8_t commandBufferLen = 0; @@ -68,6 +88,11 @@ private: ReturnValue_t handleTmrcConfigCommand(DeviceCommandId_t deviceCommand, const uint8_t *commandData,size_t commandDataLen); + + ReturnValue_t handleDataReadout(const uint8_t* packet); +#if OBSW_ENHANCED_PRINTOUT == 1 + PeriodicOperationDivider* debugDivider; +#endif }; #endif /* MISSION_DEVICEHANDLING_MGMRM3100HANDLER_H_ */ From 1ed82f6a4b8d984f4006cab77615a7cd3119acc7 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 22 Dec 2020 00:30:50 +0100 Subject: [PATCH 065/360] added gyro handler stub --- mission/devices/GyroHandler.cpp | 57 ++++++++++++++++++++++++++++ mission/devices/GyroHandler.h | 41 ++++++++++++++++++++ mission/devices/MGMHandlerRM3100.cpp | 6 +-- 3 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 mission/devices/GyroHandler.cpp create mode 100644 mission/devices/GyroHandler.h diff --git a/mission/devices/GyroHandler.cpp b/mission/devices/GyroHandler.cpp new file mode 100644 index 00000000..f3064ebc --- /dev/null +++ b/mission/devices/GyroHandler.cpp @@ -0,0 +1,57 @@ +#include "GyroHandler.h" + +GyroHandler::GyroHandler(object_id_t objectId, object_id_t deviceCommunication, + CookieIF *comCookie): + DeviceHandlerBase(objectId, deviceCommunication, comCookie) { +} + +GyroHandler::~GyroHandler() {} + +void GyroHandler::doStartUp() { + +} + +void GyroHandler::doShutDown() { + +} + +ReturnValue_t GyroHandler::buildTransitionDeviceCommand(DeviceCommandId_t *id) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GyroHandler::buildNormalDeviceCommand(DeviceCommandId_t *id) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GyroHandler::buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t *commandData, + size_t commandDataLen) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GyroHandler::scanForReply(const uint8_t *start, size_t len, + DeviceCommandId_t *foundId, size_t *foundLen) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GyroHandler::interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) { + return HasReturnvaluesIF::RETURN_OK; +} + +uint32_t GyroHandler::getTransitionDelayMs(Mode_t from, Mode_t to) { + return 5000; +} + +ReturnValue_t GyroHandler::initializeLocalDataPool( + LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + return HasReturnvaluesIF::RETURN_OK; +} + +void GyroHandler::fillCommandAndReplyMap() { + +} + +void GyroHandler::modeChanged() { + +} diff --git a/mission/devices/GyroHandler.h b/mission/devices/GyroHandler.h new file mode 100644 index 00000000..aa8be90c --- /dev/null +++ b/mission/devices/GyroHandler.h @@ -0,0 +1,41 @@ +#ifndef MISSION_DEVICES_GYROHANDLER_H_ +#define MISSION_DEVICES_GYROHANDLER_H_ + +#include + +class GyroHandler: public DeviceHandlerBase { +public: + GyroHandler(object_id_t objectId, object_id_t deviceCommunication, + CookieIF* comCookie); + virtual ~GyroHandler(); + +protected: + + /* DeviceHandlerBase overrides */ + ReturnValue_t buildTransitionDeviceCommand( + DeviceCommandId_t *id) override; + void doStartUp() override; + void doShutDown() override; + ReturnValue_t buildNormalDeviceCommand( + DeviceCommandId_t *id) override; + ReturnValue_t buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t *commandData, + size_t commandDataLen) override; + ReturnValue_t scanForReply(const uint8_t *start, size_t len, + DeviceCommandId_t *foundId, size_t *foundLen) override; + ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) override; + + void fillCommandAndReplyMap() override; + void modeChanged() override; + uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; + ReturnValue_t initializeLocalDataPool(LocalDataPool &localDataPoolMap, + LocalDataPoolManager &poolManager) override; + +private: + +}; + + + +#endif /* MISSION_DEVICES_GYROHANDLER_H_ */ diff --git a/mission/devices/MGMHandlerRM3100.cpp b/mission/devices/MGMHandlerRM3100.cpp index 6040afad..4051e107 100644 --- a/mission/devices/MGMHandlerRM3100.cpp +++ b/mission/devices/MGMHandlerRM3100.cpp @@ -290,11 +290,11 @@ void MGMHandlerRM3100::modeChanged(void) { ReturnValue_t MGMHandlerRM3100::initializeLocalDataPool( LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_X, - new PoolEntry(0.0)); + new PoolEntry({0.0})); localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_Y, - new PoolEntry(0.0)); + new PoolEntry({0.0})); localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_Z, - new PoolEntry(0.0)); + new PoolEntry({0.0})); return HasReturnvaluesIF::RETURN_OK; } From b55f857634d5eb3d16ac61886b87fffa1ab9173d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 22 Dec 2020 00:32:11 +0100 Subject: [PATCH 066/360] added gps handler stub --- mission/devices/GPSHandler.cpp | 57 ++++++++++++++++++++++++++++++++++ mission/devices/GPSHandler.h | 41 ++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 mission/devices/GPSHandler.cpp create mode 100644 mission/devices/GPSHandler.h diff --git a/mission/devices/GPSHandler.cpp b/mission/devices/GPSHandler.cpp new file mode 100644 index 00000000..fb549eb7 --- /dev/null +++ b/mission/devices/GPSHandler.cpp @@ -0,0 +1,57 @@ +#include "GPSHandler.h" + +GPSHandler::GPSHandler(object_id_t objectId, object_id_t deviceCommunication, + CookieIF *comCookie): + DeviceHandlerBase(objectId, deviceCommunication, comCookie) { +} + +GPSHandler::~GPSHandler() {} + +void GPSHandler::doStartUp() { + +} + +void GPSHandler::doShutDown() { + +} + +ReturnValue_t GPSHandler::buildTransitionDeviceCommand(DeviceCommandId_t *id) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GPSHandler::buildNormalDeviceCommand(DeviceCommandId_t *id) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GPSHandler::buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t *commandData, + size_t commandDataLen) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GPSHandler::scanForReply(const uint8_t *start, size_t len, + DeviceCommandId_t *foundId, size_t *foundLen) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GPSHandler::interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) { + return HasReturnvaluesIF::RETURN_OK; +} + +uint32_t GPSHandler::getTransitionDelayMs(Mode_t from, Mode_t to) { + return 5000; +} + +ReturnValue_t GPSHandler::initializeLocalDataPool( + LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + return HasReturnvaluesIF::RETURN_OK; +} + +void GPSHandler::fillCommandAndReplyMap() { + +} + +void GPSHandler::modeChanged() { + +} diff --git a/mission/devices/GPSHandler.h b/mission/devices/GPSHandler.h new file mode 100644 index 00000000..52ac25be --- /dev/null +++ b/mission/devices/GPSHandler.h @@ -0,0 +1,41 @@ +#ifndef MISSION_DEVICES_GPSHANDLER_H_ +#define MISSION_DEVICES_GPSHANDLER_H_ + +#include + +class GPSHandler: public DeviceHandlerBase { +public: + GPSHandler(object_id_t objectId, object_id_t deviceCommunication, + CookieIF* comCookie); + virtual ~GPSHandler(); + +protected: + + /* DeviceHandlerBase overrides */ + ReturnValue_t buildTransitionDeviceCommand( + DeviceCommandId_t *id) override; + void doStartUp() override; + void doShutDown() override; + ReturnValue_t buildNormalDeviceCommand( + DeviceCommandId_t *id) override; + ReturnValue_t buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t *commandData, + size_t commandDataLen) override; + ReturnValue_t scanForReply(const uint8_t *start, size_t len, + DeviceCommandId_t *foundId, size_t *foundLen) override; + ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) override; + + void fillCommandAndReplyMap() override; + void modeChanged() override; + uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; + ReturnValue_t initializeLocalDataPool(LocalDataPool &localDataPoolMap, + LocalDataPoolManager &poolManager) override; + +private: + +}; + + + +#endif /* MISSION_DEVICES_GPSHANDLER_H_ */ From 483481b44040195d2e18af04e311e75c8d98a7d0 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 22 Dec 2020 00:36:39 +0100 Subject: [PATCH 067/360] replaced last sent command with getPendingCommand() --- mission/devices/MGMHandlerLIS3MDL.cpp | 6 +----- mission/devices/MGMHandlerLIS3MDL.h | 7 ------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/mission/devices/MGMHandlerLIS3MDL.cpp b/mission/devices/MGMHandlerLIS3MDL.cpp index 35b71c79..7bb4fec1 100644 --- a/mission/devices/MGMHandlerLIS3MDL.cpp +++ b/mission/devices/MGMHandlerLIS3MDL.cpp @@ -105,13 +105,11 @@ ReturnValue_t MGMHandlerLIS3MDL::buildNormalDeviceCommand( DeviceCommandId_t *id) { // Data/config register will be read in an alternating manner. if(communicationStep == CommunicationStep::DATA) { - lastSentCommand = MGMLIS3MDL::READ_CONFIG_AND_DATA; *id = MGMLIS3MDL::READ_CONFIG_AND_DATA; communicationStep = CommunicationStep::TEMPERATURE; return buildCommandFromCommand(*id, NULL, 0); } else { - lastSentCommand = MGMLIS3MDL::READ_TEMPERATURE; *id = MGMLIS3MDL::READ_TEMPERATURE; communicationStep = CommunicationStep::DATA; return buildCommandFromCommand(*id, NULL, 0); @@ -122,7 +120,6 @@ ReturnValue_t MGMHandlerLIS3MDL::buildNormalDeviceCommand( ReturnValue_t MGMHandlerLIS3MDL::buildCommandFromCommand( DeviceCommandId_t deviceCommand, const uint8_t *commandData, size_t commandDataLen) { - lastSentCommand = deviceCommand; switch(deviceCommand) { case(MGMLIS3MDL::READ_CONFIG_AND_DATA): { std::memset(commandBuffer, 0, sizeof(commandBuffer)); @@ -154,7 +151,6 @@ ReturnValue_t MGMHandlerLIS3MDL::buildCommandFromCommand( return setOperatingMode(commandData, commandDataLen); } default: - lastSentCommand = DeviceHandlerIF::NO_COMMAND; return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; } return HasReturnvaluesIF::RETURN_FAILED; @@ -198,7 +194,7 @@ ReturnValue_t MGMHandlerLIS3MDL::scanForReply(const uint8_t *start, } else if (len == SINGLE_COMMAND_ANSWER_LEN) { *foundLen = len; - *foundId = lastSentCommand; + *foundId = getPendingCommand(); } else { return DeviceHandlerIF::INVALID_DATA; diff --git a/mission/devices/MGMHandlerLIS3MDL.h b/mission/devices/MGMHandlerLIS3MDL.h index c48b1fc2..875d453d 100644 --- a/mission/devices/MGMHandlerLIS3MDL.h +++ b/mission/devices/MGMHandlerLIS3MDL.h @@ -137,13 +137,6 @@ private: uint8_t statusRegister = 0; - - /** - * As this is a SPI Device, we get the Answer of the last sent command in - * the next read cycle, so we could check the command for identification. - */ - DeviceCommandId_t lastSentCommand = DeviceHandlerIF::NO_COMMAND; - /** * We always update all registers together, so this method updates * the rawpacket and rawpacketLen, so we just manipulate the local From afb6ee829ff3b570940795c3a2cb3ad59bf940e0 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 22 Dec 2020 13:32:40 +0100 Subject: [PATCH 068/360] added top comment --- mission/devices/MGMHandlerLIS3MDL.h | 2 +- mission/devices/MGMHandlerRM3100.h | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/mission/devices/MGMHandlerLIS3MDL.h b/mission/devices/MGMHandlerLIS3MDL.h index 875d453d..e5b29284 100644 --- a/mission/devices/MGMHandlerLIS3MDL.h +++ b/mission/devices/MGMHandlerLIS3MDL.h @@ -44,7 +44,7 @@ protected: size_t commandDataLen) override; ReturnValue_t buildTransitionDeviceCommand( DeviceCommandId_t *id) override; - ReturnValue_t buildNormalDeviceCommand( + ReturnValue_t buildNormalDeviceCommand( DeviceCommandId_t *id) override; ReturnValue_t scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId, size_t *foundLen) override; diff --git a/mission/devices/MGMHandlerRM3100.h b/mission/devices/MGMHandlerRM3100.h index 58096a8d..124fc1a2 100644 --- a/mission/devices/MGMHandlerRM3100.h +++ b/mission/devices/MGMHandlerRM3100.h @@ -10,6 +10,13 @@ #include #endif +/** + * @brief Device Handler for the RM3100 geomagnetic magnetometer sensor + * (https://www.pnicorp.com/rm3100/) + * @details + * Advanced documentation: + * https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/RM3100_MGM + */ class MGMHandlerRM3100: public DeviceHandlerBase { public: static const uint8_t INTERFACE_ID = CLASS_ID::MGM_RM3100; From 23ce7dc5c3fade02ec45de844308ad1439dcb2f6 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 22 Dec 2020 13:36:10 +0100 Subject: [PATCH 069/360] added top comment block --- mission/devices/GyroHandler.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mission/devices/GyroHandler.h b/mission/devices/GyroHandler.h index aa8be90c..5ced880e 100644 --- a/mission/devices/GyroHandler.h +++ b/mission/devices/GyroHandler.h @@ -3,6 +3,13 @@ #include +/** + * @brief Device Handler for the L3GD20H gyroscope sensor + * (https://www.st.com/en/mems-and-sensors/l3gd20h.html) + * @details + * Advanced documentation: + * https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/L3GD20H_Gyro + */ class GyroHandler: public DeviceHandlerBase { public: GyroHandler(object_id_t objectId, object_id_t deviceCommunication, From 6f3a1c845c5410f36a3ce5bc6330ef5f28c8cc39 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 22 Dec 2020 13:41:01 +0100 Subject: [PATCH 070/360] started gyro handler, renamed --- .../{GyroHandler.cpp => GyroL3GD20Handler.cpp} | 13 +++++++++++-- .../devices/{GyroHandler.h => GyroL3GD20Handler.h} | 14 +++++++++++--- .../devicedefinitions/GyroL3GD20Definitions.h | 11 +++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) rename mission/devices/{GyroHandler.cpp => GyroL3GD20Handler.cpp} (79%) rename mission/devices/{GyroHandler.h => GyroL3GD20Handler.h} (82%) create mode 100644 mission/devices/devicedefinitions/GyroL3GD20Definitions.h diff --git a/mission/devices/GyroHandler.cpp b/mission/devices/GyroL3GD20Handler.cpp similarity index 79% rename from mission/devices/GyroHandler.cpp rename to mission/devices/GyroL3GD20Handler.cpp index f3064ebc..772d0263 100644 --- a/mission/devices/GyroHandler.cpp +++ b/mission/devices/GyroL3GD20Handler.cpp @@ -1,4 +1,4 @@ -#include "GyroHandler.h" +#include GyroHandler::GyroHandler(object_id_t objectId, object_id_t deviceCommunication, CookieIF *comCookie): @@ -8,11 +8,20 @@ GyroHandler::GyroHandler(object_id_t objectId, object_id_t deviceCommunication, GyroHandler::~GyroHandler() {} void GyroHandler::doStartUp() { + if(internalState == InternalState::STATE_NONE) { + internalState = InternalState::STATE_CONFIGURE; + } + if(internalState == InternalState::STATE_CONFIGURE) { + if(commandExecuted) { + internalState = InternalState::STATE_NORMAL; + commandExecuted = false; + } + } } void GyroHandler::doShutDown() { - + setMode(_MODE_POWER_DOWN); } ReturnValue_t GyroHandler::buildTransitionDeviceCommand(DeviceCommandId_t *id) { diff --git a/mission/devices/GyroHandler.h b/mission/devices/GyroL3GD20Handler.h similarity index 82% rename from mission/devices/GyroHandler.h rename to mission/devices/GyroL3GD20Handler.h index 5ced880e..e1ced8d7 100644 --- a/mission/devices/GyroHandler.h +++ b/mission/devices/GyroL3GD20Handler.h @@ -1,5 +1,5 @@ -#ifndef MISSION_DEVICES_GYROHANDLER_H_ -#define MISSION_DEVICES_GYROHANDLER_H_ +#ifndef MISSION_DEVICES_GYROL3GD20HANDLER_H_ +#define MISSION_DEVICES_GYROL3GD20HANDLER_H_ #include @@ -41,8 +41,16 @@ protected: private: + enum InternalState { + STATE_NONE, + STATE_CONFIGURE, + STATE_NORMAL + }; + InternalState internalState = InternalState::STATE_NONE; + bool commandExecuted = false; + }; -#endif /* MISSION_DEVICES_GYROHANDLER_H_ */ +#endif /* MISSION_DEVICES_GYROL3GD20HANDLER_H_ */ diff --git a/mission/devices/devicedefinitions/GyroL3GD20Definitions.h b/mission/devices/devicedefinitions/GyroL3GD20Definitions.h new file mode 100644 index 00000000..598803fa --- /dev/null +++ b/mission/devices/devicedefinitions/GyroL3GD20Definitions.h @@ -0,0 +1,11 @@ +#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_GYROL3GD20DEFINITIONS_H_ +#define MISSION_DEVICES_DEVICEDEFINITIONS_GYROL3GD20DEFINITIONS_H_ + +namespace L3GD20H { + + +} + + + +#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_GYROL3GD20DEFINITIONS_H_ */ From e527aa52f6e950f68b69689f21a05e777c2c1e38 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 22 Dec 2020 13:44:32 +0100 Subject: [PATCH 071/360] started with l3dg20h definitions --- .../devicedefinitions/GyroL3GD20Definitions.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mission/devices/devicedefinitions/GyroL3GD20Definitions.h b/mission/devices/devicedefinitions/GyroL3GD20Definitions.h index 598803fa..d331a8d9 100644 --- a/mission/devices/devicedefinitions/GyroL3GD20Definitions.h +++ b/mission/devices/devicedefinitions/GyroL3GD20Definitions.h @@ -1,8 +1,23 @@ #ifndef MISSION_DEVICES_DEVICEDEFINITIONS_GYROL3GD20DEFINITIONS_H_ #define MISSION_DEVICES_DEVICEDEFINITIONS_GYROL3GD20DEFINITIONS_H_ +#include + namespace L3GD20H { +static constexpr uint8_t READ_MASK = 0b1000'0000; + +static constexpr uint8_t AUTO_INCREMENT_MASK = 0b0100'0000; + +static constexpr uint8_t WHO_AM_I_REG = 0b0000'1111; +static constexpr uint8_t WHO_AM_I_VAL = 0b1101'0111; + +static constexpr uint8_t CTRL_REG_1 = 0b0010'0000; +static constexpr uint8_t CTRL_REG_2 = 0b0010'0001; +static constexpr uint8_t CTRL_REG_3 = 0b0010'0010; +static constexpr uint8_t CTRL_REG_4 = 0b0010'0011; +static constexpr uint8_t CTRL_REG_5 = 0b0010'0100; + } From efd0823da2c082547526c7bf9ad506d18f78cda7 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 23 Dec 2020 20:17:39 +0100 Subject: [PATCH 072/360] gyro handler finished --- Makefile | 2 +- fsfw | 2 +- mission/devices/GyroL3GD20Handler.cpp | 163 +++++++++++++++++- mission/devices/GyroL3GD20Handler.h | 15 +- mission/devices/MGMHandlerLIS3MDL.cpp | 37 ++-- mission/devices/MGMHandlerLIS3MDL.h | 10 +- mission/devices/MGMHandlerRM3100.cpp | 62 ++++--- mission/devices/MGMHandlerRM3100.h | 2 +- .../devicedefinitions/GyroL3GD20Definitions.h | 103 +++++++++++ 9 files changed, 345 insertions(+), 51 deletions(-) diff --git a/Makefile b/Makefile index 04a263ef..5380c5da 100644 --- a/Makefile +++ b/Makefile @@ -278,7 +278,7 @@ cleanbin: -rm -rf $(BUILDPATH)/$(OUTPUT_FOLDER) # Build target configuration -release: OPTIMIZATION = -Os $(PROTOTYPE_OPTIMIZATION) $(LINK_TIME_OPTIMIZATION) +release: OPTIMIZATION = -O2 $(PROTOTYPE_OPTIMIZATION) $(LINK_TIME_OPTIMIZATION) release: LINK_TIME_OPTIMIZATION = -flto release: TARGET = Release release: OPTIMIZATION_MESSAGE = On with Link Time Optimization diff --git a/fsfw b/fsfw index 31b82975..dcc111e4 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 31b82975c7ef701fa7f1ba3413cfa19cc73aa2ca +Subproject commit dcc111e4facf39137fe52d8234361b7d99bdde06 diff --git a/mission/devices/GyroL3GD20Handler.cpp b/mission/devices/GyroL3GD20Handler.cpp index 772d0263..b6067e5b 100644 --- a/mission/devices/GyroL3GD20Handler.cpp +++ b/mission/devices/GyroL3GD20Handler.cpp @@ -2,7 +2,8 @@ GyroHandler::GyroHandler(object_id_t objectId, object_id_t deviceCommunication, CookieIF *comCookie): - DeviceHandlerBase(objectId, deviceCommunication, comCookie) { + DeviceHandlerBase(objectId, deviceCommunication, comCookie), + dataset(this) { } GyroHandler::~GyroHandler() {} @@ -25,42 +26,192 @@ void GyroHandler::doShutDown() { } ReturnValue_t GyroHandler::buildTransitionDeviceCommand(DeviceCommandId_t *id) { + switch(internalState) { + case(InternalState::STATE_NONE): + case(InternalState::STATE_NORMAL): { + return HasReturnvaluesIF::RETURN_OK; + } + case(InternalState::STATE_CONFIGURE): { + *id = L3GD20H::CONFIGURE_CTRL_REGS; + uint8_t command [5]; + command[0] = L3GD20H::CTRL_REG_1_VAL; + command[1] = L3GD20H::CTRL_REG_2_VAL; + command[2] = L3GD20H::CTRL_REG_3_VAL; + command[3] = L3GD20H::CTRL_REG_4_VAL; + command[4] = L3GD20H::CTRL_REG_5_VAL; + return buildCommandFromCommand(*id, command, 5); + break; + } + default: + // might be a configuration error. + sif::debug << "GyroHandler::buildTransitionDeviceCommand: Unknown " + << "internal state!" << std::endl; + return HasReturnvaluesIF::RETURN_OK; + } return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t GyroHandler::buildNormalDeviceCommand(DeviceCommandId_t *id) { - return HasReturnvaluesIF::RETURN_OK; + *id = L3GD20H::READ_REGS; + return buildCommandFromCommand(*id, nullptr, 0); } ReturnValue_t GyroHandler::buildCommandFromCommand( DeviceCommandId_t deviceCommand, const uint8_t *commandData, size_t commandDataLen) { + switch(deviceCommand) { + case(L3GD20H::READ_REGS): { + commandBuffer[0] = L3GD20H::READ_START | L3GD20H::AUTO_INCREMENT_MASK | + L3GD20H::READ_MASK; + + std::memset(commandBuffer + 1, 0, L3GD20H::READ_LEN); + rawPacket = commandBuffer; + rawPacketLen = L3GD20H::READ_LEN + 1; + break; + } + case(L3GD20H::CONFIGURE_CTRL_REGS): { + commandBuffer[0] = L3GD20H::CTRL_REG_1 | L3GD20H::AUTO_INCREMENT_MASK; + if(commandData == nullptr or commandDataLen != 5) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + ctrlReg1Value = commandData[0]; + ctrlReg2Value = commandData[1]; + ctrlReg3Value = commandData[2]; + ctrlReg4Value = commandData[3]; + ctrlReg5Value = commandData[4]; + + bool fsH = ctrlReg4Value & L3GD20H::SET_FS_1; + bool fsL = ctrlReg4Value & L3GD20H::SET_FS_0; + + if(not fsH and not fsL) { + scaleFactor = static_cast(L3GD20H::RANGE_DPS_00) / INT16_MAX; + } + else if(not fsH and fsL) { + scaleFactor = static_cast(L3GD20H::RANGE_DPS_01) / INT16_MAX; + } + else { + scaleFactor = static_cast(L3GD20H::RANGE_DPS_11) / INT16_MAX; + } + + commandBuffer[1] = ctrlReg1Value; + commandBuffer[2] = ctrlReg2Value; + commandBuffer[3] = ctrlReg3Value; + commandBuffer[4] = ctrlReg4Value; + commandBuffer[5] = ctrlReg5Value; + + rawPacket = commandBuffer; + rawPacketLen = 6; + break; + } + case(L3GD20H::READ_CTRL_REGS): { + commandBuffer[0] = L3GD20H::READ_START | L3GD20H::AUTO_INCREMENT_MASK | + L3GD20H::READ_MASK; + + std::memset(commandBuffer + 1, 0, 5); + rawPacket = commandBuffer; + rawPacketLen = 6; + break; + } + default: + return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + } return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t GyroHandler::scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId, size_t *foundLen) { - return HasReturnvaluesIF::RETURN_OK; + // SPI, ID will always be the one of the last sent command. + *foundId = this->getPendingCommand(); + *foundLen = this->rawPacketLen; + + // Data with SPI Interface has always this answer + if (start[0] == 0b11111111) { + return HasReturnvaluesIF::RETURN_OK; + } + return DeviceHandlerIF::INVALID_DATA; } ReturnValue_t GyroHandler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) { - return HasReturnvaluesIF::RETURN_OK; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + switch(id) { + case(L3GD20H::CONFIGURE_CTRL_REGS): { + break; + } + case(L3GD20H::READ_CTRL_REGS): { + if(packet[1] == ctrlReg1Value and packet[2] == ctrlReg2Value and + packet[3] == ctrlReg3Value and packet[4] == ctrlReg4Value and + packet[5] == ctrlReg5Value) { + commandExecuted = true; + } + else { + // Attempt reconfiguration. + internalState = InternalState::STATE_CONFIGURE; + return DeviceHandlerIF::DEVICE_REPLY_INVALID; + } + break; + } + case(L3GD20H::READ_START): { + if(packet[1] != ctrlReg1Value and packet[2] != ctrlReg2Value and + packet[3] != ctrlReg3Value and packet[4] != ctrlReg4Value and + packet[5] != ctrlReg5Value) { + return DeviceHandlerIF::DEVICE_REPLY_INVALID; + } + + statusReg = packet[L3GD20H::STATUS_IDX]; + + float angVelocX = (packet[L3GD20H::OUT_X_H] << 8 | + packet[L3GD20H::OUT_X_L]) * scaleFactor; + float angVelocY = (packet[L3GD20H::OUT_Y_H] << 8 | + packet[L3GD20H::OUT_Y_L]) * scaleFactor; + float angVelocZ = (packet[L3GD20H::OUT_Z_H] << 8 | + packet[L3GD20H::OUT_Z_L]) * scaleFactor; + + int8_t temperaturOffset = (-1) * packet[L3GD20H::TEMPERATURE_IDX]; + float temperature = 25.0 + temperaturOffset; + + ReturnValue_t result = dataset.read(20); + if(result == HasReturnvaluesIF::RETURN_OK) { + dataset.angVelocX = angVelocX; + dataset.angVelocY = angVelocX; + dataset.angVelocZ = angVelocX; + dataset.temperature = temperature; + dataset.setValidity(true, true); + result = dataset.commit(20); + } + break; + } + default: + return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + } + return result; } + uint32_t GyroHandler::getTransitionDelayMs(Mode_t from, Mode_t to) { return 5000; } ReturnValue_t GyroHandler::initializeLocalDataPool( LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + localDataPoolMap.emplace(L3GD20H::ANG_VELOC_X, + new PoolEntry({0.0})); + localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Y, + new PoolEntry({0.0})); + localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Z, + new PoolEntry({0.0})); + localDataPoolMap.emplace(L3GD20H::TEMPERATURE, + new PoolEntry({0.0})); return HasReturnvaluesIF::RETURN_OK; } void GyroHandler::fillCommandAndReplyMap() { - + insertInCommandAndReplyMap(L3GD20H::READ_REGS, 1, &dataset); + insertInCommandAndReplyMap(L3GD20H::CONFIGURE_CTRL_REGS, 1); + insertInCommandAndReplyMap(L3GD20H::READ_CTRL_REGS, 1); } void GyroHandler::modeChanged() { - + internalState = InternalState::STATE_NONE; } diff --git a/mission/devices/GyroL3GD20Handler.h b/mission/devices/GyroL3GD20Handler.h index e1ced8d7..5905b26a 100644 --- a/mission/devices/GyroL3GD20Handler.h +++ b/mission/devices/GyroL3GD20Handler.h @@ -2,6 +2,7 @@ #define MISSION_DEVICES_GYROL3GD20HANDLER_H_ #include +#include "devicedefinitions/GyroL3GD20Definitions.h" /** * @brief Device Handler for the L3GD20H gyroscope sensor @@ -40,8 +41,9 @@ protected: LocalDataPoolManager &poolManager) override; private: + L3GD20H::GyroPrimaryDataset dataset; - enum InternalState { + enum class InternalState { STATE_NONE, STATE_CONFIGURE, STATE_NORMAL @@ -49,6 +51,17 @@ private: InternalState internalState = InternalState::STATE_NONE; bool commandExecuted = false; + uint8_t statusReg = 0; + + uint8_t ctrlReg1Value = L3GD20H::CTRL_REG_1_VAL; + uint8_t ctrlReg2Value = L3GD20H::CTRL_REG_2_VAL; + uint8_t ctrlReg3Value = L3GD20H::CTRL_REG_3_VAL; + uint8_t ctrlReg4Value = L3GD20H::CTRL_REG_4_VAL; + uint8_t ctrlReg5Value = L3GD20H::CTRL_REG_5_VAL; + + uint8_t commandBuffer[L3GD20H::READ_LEN + 1]; + + float scaleFactor = static_cast(L3GD20H::RANGE_DPS_00) / INT16_MAX; }; diff --git a/mission/devices/MGMHandlerLIS3MDL.cpp b/mission/devices/MGMHandlerLIS3MDL.cpp index 7bb4fec1..64b6d855 100644 --- a/mission/devices/MGMHandlerLIS3MDL.cpp +++ b/mission/devices/MGMHandlerLIS3MDL.cpp @@ -23,19 +23,19 @@ MGMHandlerLIS3MDL::~MGMHandlerLIS3MDL() { void MGMHandlerLIS3MDL::doStartUp() { switch (internalState) { - case STATE_NONE: - internalState = STATE_FIRST_CONTACT; + case(InternalState::STATE_NONE): + internalState = InternalState::STATE_FIRST_CONTACT; break; - case STATE_FIRST_CONTACT: - internalState = STATE_SETUP; + case(InternalState::STATE_FIRST_CONTACT): + internalState = InternalState::STATE_SETUP; break; - case STATE_SETUP: - internalState = STATE_CHECK_REGISTERS; + case(InternalState::STATE_SETUP): + internalState = InternalState::STATE_CHECK_REGISTERS; break; - case STATE_CHECK_REGISTERS: { + case(InternalState::STATE_CHECK_REGISTERS): { // Set up cached registers which will be used to configure the MGM. if(commandExecuted) { commandExecuted = false; @@ -56,20 +56,27 @@ void MGMHandlerLIS3MDL::doShutDown() { ReturnValue_t MGMHandlerLIS3MDL::buildTransitionDeviceCommand( DeviceCommandId_t *id) { switch (internalState) { - case STATE_FIRST_CONTACT: + case(InternalState::STATE_NONE): + case(InternalState::STATE_NORMAL): { + return HasReturnvaluesIF::RETURN_OK; + } + case(InternalState::STATE_FIRST_CONTACT): { *id = MGMLIS3MDL::IDENTIFY_DEVICE; break; - - case STATE_SETUP: + } + case(InternalState::STATE_SETUP): { *id = MGMLIS3MDL::SETUP_MGM; break; - - case STATE_CHECK_REGISTERS: + } + case(InternalState::STATE_CHECK_REGISTERS): { *id = MGMLIS3MDL::READ_CONFIG_AND_DATA; break; - + } default: - break; + // might be a configuration error. + sif::debug << "GyroHandler::buildTransitionDeviceCommand: Unknown " + << "internal state!" << std::endl; + return HasReturnvaluesIF::RETURN_OK; } return buildCommandFromCommand(*id, NULL, 0); } @@ -412,7 +419,7 @@ uint32_t MGMHandlerLIS3MDL::getTransitionDelayMs(Mode_t from, Mode_t to) { } void MGMHandlerLIS3MDL::modeChanged(void) { - internalState = STATE_NONE; + internalState = InternalState::STATE_NONE; } ReturnValue_t MGMHandlerLIS3MDL::initializeLocalDataPool( diff --git a/mission/devices/MGMHandlerLIS3MDL.h b/mission/devices/MGMHandlerLIS3MDL.h index e5b29284..414731db 100644 --- a/mission/devices/MGMHandlerLIS3MDL.h +++ b/mission/devices/MGMHandlerLIS3MDL.h @@ -145,11 +145,15 @@ private: */ ReturnValue_t prepareCtrlRegisterWrite(); - enum InternalState { - STATE_NONE, STATE_FIRST_CONTACT, STATE_SETUP, STATE_CHECK_REGISTERS + enum class InternalState { + STATE_NONE, + STATE_FIRST_CONTACT, + STATE_SETUP, + STATE_CHECK_REGISTERS, + STATE_NORMAL }; - InternalState internalState = STATE_NONE; + InternalState internalState = InternalState::STATE_NONE; CommunicationStep communicationStep = CommunicationStep::DATA; bool commandExecuted = false; diff --git a/mission/devices/MGMHandlerRM3100.cpp b/mission/devices/MGMHandlerRM3100.cpp index 4051e107..eebbac39 100644 --- a/mission/devices/MGMHandlerRM3100.cpp +++ b/mission/devices/MGMHandlerRM3100.cpp @@ -17,25 +17,25 @@ MGMHandlerRM3100::MGMHandlerRM3100(object_id_t objectId, MGMHandlerRM3100::~MGMHandlerRM3100() {} void MGMHandlerRM3100::doStartUp() { - if(internalState == STATE_NONE) { - internalState = STATE_CONFIGURE_CMM; + if(internalState == InternalState::STATE_NONE) { + internalState = InternalState::STATE_CONFIGURE_CMM; } - if(internalState == STATE_CONFIGURE_CMM) { - internalState = STATE_READ_CMM; + if(internalState == InternalState::STATE_CONFIGURE_CMM) { + internalState = InternalState::STATE_READ_CMM; } - else if(internalState == STATE_READ_CMM) { + else if(internalState == InternalState::STATE_READ_CMM) { if(commandExecuted) { - internalState = STATE_CONFIGURE_TMRC; + internalState = InternalState::STATE_CONFIGURE_TMRC; } } - if(internalState == STATE_CONFIGURE_TMRC) { - internalState = STATE_READ_TMRC; + if(internalState == InternalState::STATE_CONFIGURE_TMRC) { + internalState = InternalState::STATE_READ_TMRC; } - else if(internalState == STATE_READ_TMRC) { + else if(internalState == InternalState::STATE_READ_TMRC) { if(commandExecuted) { - internalState = STATE_NORMAL; + internalState = InternalState::STATE_NORMAL; setMode(_MODE_TO_ON); } } @@ -47,20 +47,32 @@ void MGMHandlerRM3100::doShutDown() { ReturnValue_t MGMHandlerRM3100::buildTransitionDeviceCommand( DeviceCommandId_t *id) { - if(internalState == STATE_CONFIGURE_CMM) { + switch(internalState) { + case(InternalState::STATE_NONE): + case(InternalState::STATE_NORMAL): { + return HasReturnvaluesIF::RETURN_OK; + } + case(InternalState::STATE_CONFIGURE_CMM): { *id = RM3100::CONFIGURE_CMM; + break; } - - if(internalState == STATE_READ_CMM) { + case(InternalState::STATE_READ_CMM): { *id = RM3100::READ_CMM; + break; } - - if(internalState == STATE_CONFIGURE_TMRC) { + case(InternalState::STATE_CONFIGURE_TMRC): { *id = RM3100::CONFIGURE_TMRC; + break; } - - if(internalState == STATE_READ_TMRC) { + case(InternalState::STATE_READ_TMRC): { *id = RM3100::READ_TMRC; + break; + } + default: + // might be a configuration error. + sif::debug << "GyroHandler::buildTransitionDeviceCommand: Unknown " + << "internal state!" << std::endl; + return HasReturnvaluesIF::RETURN_OK; } return buildCommandFromCommand(*id, nullptr, 0); @@ -137,22 +149,26 @@ ReturnValue_t MGMHandlerRM3100::scanForReply(const uint8_t *start, if (start[0] == 0b11111111) { return RETURN_OK; } - else { - return DeviceHandlerIF::INVALID_DATA; - } + return DeviceHandlerIF::INVALID_DATA; } ReturnValue_t MGMHandlerRM3100::interpretDeviceReply( DeviceCommandId_t id, const uint8_t *packet) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; switch(id) { + case(RM3100::CONFIGURE_CMM): + case(RM3100::CONFIGURE_CYCLE_COUNT): + case(RM3100::CONFIGURE_TMRC): { + // We can only check whether write was sucessful with read operation. + break; + } case(RM3100::READ_CMM): { if(packet[1] == cmmRegValue) { commandExecuted = true; } else { // Attempt reconfiguration. - internalState = STATE_CONFIGURE_CMM; + internalState = InternalState::STATE_CONFIGURE_CMM; return DeviceHandlerIF::DEVICE_REPLY_INVALID; } break; @@ -167,7 +183,7 @@ ReturnValue_t MGMHandlerRM3100::interpretDeviceReply( } else { // Attempt reconfiguration. - internalState = STATE_CONFIGURE_TMRC; + internalState = InternalState::STATE_CONFIGURE_TMRC; return DeviceHandlerIF::DEVICE_REPLY_INVALID; } break; @@ -284,7 +300,7 @@ void MGMHandlerRM3100::fillCommandAndReplyMap() { } void MGMHandlerRM3100::modeChanged(void) { - internalState = STATE_NONE; + internalState = InternalState::STATE_NONE; } ReturnValue_t MGMHandlerRM3100::initializeLocalDataPool( diff --git a/mission/devices/MGMHandlerRM3100.h b/mission/devices/MGMHandlerRM3100.h index 124fc1a2..d735ca45 100644 --- a/mission/devices/MGMHandlerRM3100.h +++ b/mission/devices/MGMHandlerRM3100.h @@ -60,7 +60,7 @@ protected: private: - enum InternalState { + enum class InternalState { STATE_NONE, STATE_CONFIGURE_CMM, STATE_READ_CMM, diff --git a/mission/devices/devicedefinitions/GyroL3GD20Definitions.h b/mission/devices/devicedefinitions/GyroL3GD20Definitions.h index d331a8d9..c6042f58 100644 --- a/mission/devices/devicedefinitions/GyroL3GD20Definitions.h +++ b/mission/devices/devicedefinitions/GyroL3GD20Definitions.h @@ -1,6 +1,7 @@ #ifndef MISSION_DEVICES_DEVICEDEFINITIONS_GYROL3GD20DEFINITIONS_H_ #define MISSION_DEVICES_DEVICEDEFINITIONS_GYROL3GD20DEFINITIONS_H_ +#include #include namespace L3GD20H { @@ -12,12 +13,114 @@ static constexpr uint8_t AUTO_INCREMENT_MASK = 0b0100'0000; static constexpr uint8_t WHO_AM_I_REG = 0b0000'1111; static constexpr uint8_t WHO_AM_I_VAL = 0b1101'0111; +/*------------------------------------------------------------------------*/ +/* Control registers +/*------------------------------------------------------------------------*/ static constexpr uint8_t CTRL_REG_1 = 0b0010'0000; static constexpr uint8_t CTRL_REG_2 = 0b0010'0001; static constexpr uint8_t CTRL_REG_3 = 0b0010'0010; static constexpr uint8_t CTRL_REG_4 = 0b0010'0011; static constexpr uint8_t CTRL_REG_5 = 0b0010'0100; +// Register 1 +static constexpr uint8_t SET_DR_1 = 1 << 7; +static constexpr uint8_t SET_DR_0 = 1 << 6; +static constexpr uint8_t SET_BW_1 = 1 << 5; +static constexpr uint8_t SET_BW_0 = 1 << 4; +static constexpr uint8_t SET_POWER_NORMAL_MODE = 1 << 3; +static constexpr uint8_t SET_Z_ENABLE = 1 << 2; +static constexpr uint8_t SET_X_ENABLE = 1 << 1; +static constexpr uint8_t SET_Y_ENABLE = 1; + +static constexpr uint8_t CTRL_REG_1_VAL = SET_POWER_NORMAL_MODE | SET_Z_ENABLE | + SET_Y_ENABLE | SET_X_ENABLE; + +// Register 2 +static constexpr uint8_t EXTERNAL_EDGE_ENB = 1 << 7; +static constexpr uint8_t LEVEL_SENSITIVE_TRIGGER = 1 << 6; +static constexpr uint8_t SET_HPM_1 = 1 << 5; +static constexpr uint8_t SET_HPM_0 = 1 << 4; +static constexpr uint8_t SET_HPCF_3 = 1 << 3; +static constexpr uint8_t SET_HPCF_2 = 1 << 2; +static constexpr uint8_t SET_HPCF_1 = 1 << 1; +static constexpr uint8_t SET_HPCF_0 = 1; + +static constexpr uint8_t CTRL_REG_2_VAL = 0b0000'0000; + +// Register 3 +static constexpr uint8_t CTRL_REG_3_VAL = 0b0000'0000; + +// Register 4 +static constexpr uint8_t SET_BNU = 1 << 7; +static constexpr uint8_t SET_BLE = 1 << 6; +static constexpr uint8_t SET_FS_1 = 1 << 5; +static constexpr uint8_t SET_FS_0 = 1 << 4; +static constexpr uint8_t SET_IMP_ENB = 1 << 3; +static constexpr uint8_t SET_SELF_TEST_ENB_1 = 1 << 2; +static constexpr uint8_t SET_SELF_TEST_ENB_0 = 1 << 1; +static constexpr uint8_t SET_SPI_IF_SELECT = 1; + +static constexpr uint8_t CTRL_REG_4_VAL = 0b0000'0000; + +// Register 5 +static constexpr uint8_t SET_REBOOT_MEM = 1 << 7; +static constexpr uint8_t SET_FIFO_ENB = 1 << 6; + +static constexpr uint8_t CTRL_REG_5_VAL = 0b0000'0000; + +// In degrees per second (DPS) for now. +static constexpr uint16_t RANGE_DPS_00 = 245; +static constexpr uint16_t RANGE_DPS_01 = 500; +static constexpr uint16_t RANGE_DPS_11 = 2000; + +static constexpr uint8_t READ_START = CTRL_REG_1; +static constexpr size_t READ_LEN = 14; + +// Indexing +static constexpr uint8_t REFERENCE_IDX = 6; +static constexpr uint8_t TEMPERATURE_IDX = 7; +static constexpr uint8_t STATUS_IDX = 8; +static constexpr uint8_t OUT_X_L = 9; +static constexpr uint8_t OUT_X_H = 10; +static constexpr uint8_t OUT_Y_L = 11; +static constexpr uint8_t OUT_Y_H = 12; +static constexpr uint8_t OUT_Z_L = 13; +static constexpr uint8_t OUT_Z_H = 14; + +/*------------------------------------------------------------------------*/ +/* Device Handler specific +/*------------------------------------------------------------------------*/ +static constexpr DeviceCommandId_t READ_REGS = 0; +static constexpr DeviceCommandId_t CONFIGURE_CTRL_REGS = 1; +static constexpr DeviceCommandId_t READ_CTRL_REGS = 2; + +static constexpr uint32_t GYRO_DATASET_ID = READ_REGS; + +enum GyroPoolIds: lp_id_t { + ANG_VELOC_X, + ANG_VELOC_Y, + ANG_VELOC_Z, + TEMPERATURE +}; + +class GyroPrimaryDataset: public StaticLocalDataSet<3 * sizeof(float)> { +public: + GyroPrimaryDataset(HasLocalDataPoolIF* hkOwner): + StaticLocalDataSet(hkOwner, GYRO_DATASET_ID) {} + + GyroPrimaryDataset(object_id_t mgmId): + StaticLocalDataSet(sid_t(mgmId, GYRO_DATASET_ID)) {} + + // Angular velocities in degrees per second (DPS) + lp_var_t angVelocX = lp_var_t(sid.objectId, + ANG_VELOC_X, this); + lp_var_t angVelocY = lp_var_t(sid.objectId, + ANG_VELOC_Y, this); + lp_var_t angVelocZ = lp_var_t(sid.objectId, + ANG_VELOC_Z, this); + lp_var_t temperature = lp_var_t(sid.objectId, + TEMPERATURE, this); +}; } From 20fcebf7c88ab377ff72c547f0eeaeb04879af55 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 23 Dec 2020 20:20:22 +0100 Subject: [PATCH 073/360] fsfw update --- fsfw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsfw b/fsfw index dcc111e4..d7efa1b4 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit dcc111e4facf39137fe52d8234361b7d99bdde06 +Subproject commit d7efa1b4d717a576659044781e8520e1b9c97f7e From 1be985cb49641e6bc5d9003962b1db55ec107846 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 23 Dec 2020 20:26:37 +0100 Subject: [PATCH 074/360] valid fsfw now --- fsfw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsfw b/fsfw index d7efa1b4..dcc111e4 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit d7efa1b4d717a576659044781e8520e1b9c97f7e +Subproject commit dcc111e4facf39137fe52d8234361b7d99bdde06 From afec8e7b2df154dd8a8813a7bf87cd3b40f7aee8 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Sun, 27 Dec 2020 15:27:16 +0100 Subject: [PATCH 075/360] tmtc p60dock --- tmtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmtc b/tmtc index e0c896e6..9342f773 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit e0c896e62d25286d00599ca57b71d0a3495ed95f +Subproject commit 9342f773115856843b167225236b04a061602174 From 615ca908de888b1c0177fcae6c0818ab52353fef Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 27 Dec 2020 16:29:49 +0100 Subject: [PATCH 076/360] updated config --- fsfwconfig/FSFWConfig.h | 1 - 1 file changed, 1 deletion(-) diff --git a/fsfwconfig/FSFWConfig.h b/fsfwconfig/FSFWConfig.h index fe97ee6e..5df83705 100644 --- a/fsfwconfig/FSFWConfig.h +++ b/fsfwconfig/FSFWConfig.h @@ -1,7 +1,6 @@ #ifndef FSFWCONFIG_FSFWCONFIG_H_ #define FSFWCONFIG_FSFWCONFIG_H_ -#include #include //! Used to determine whether C++ ostreams are used From 4c5febe71f87e124fa31741b3dfd7f64f62229b4 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 27 Dec 2020 16:45:37 +0100 Subject: [PATCH 077/360] fsfwconfig fix --- fsfw | 2 +- fsfwconfig/FSFWConfig.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/fsfw b/fsfw index 086cbe1e..dcc111e4 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 086cbe1e3950cf6c904609352408a7fa48cc83ef +Subproject commit dcc111e4facf39137fe52d8234361b7d99bdde06 diff --git a/fsfwconfig/FSFWConfig.h b/fsfwconfig/FSFWConfig.h index fe97ee6e..5df83705 100644 --- a/fsfwconfig/FSFWConfig.h +++ b/fsfwconfig/FSFWConfig.h @@ -1,7 +1,6 @@ #ifndef FSFWCONFIG_FSFWCONFIG_H_ #define FSFWCONFIG_FSFWCONFIG_H_ -#include #include //! Used to determine whether C++ ostreams are used From 2f91a1e88153033ffeb0e26abd80d929f6ebba45 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 27 Dec 2020 16:46:01 +0100 Subject: [PATCH 078/360] another fix --- fsfwconfig/objects/systemObjectList.h | 1 - 1 file changed, 1 deletion(-) diff --git a/fsfwconfig/objects/systemObjectList.h b/fsfwconfig/objects/systemObjectList.h index 3b5717fb..05ed2c52 100644 --- a/fsfwconfig/objects/systemObjectList.h +++ b/fsfwconfig/objects/systemObjectList.h @@ -19,7 +19,6 @@ namespace objects { PUS_SERVICE_23 = 0x51002300, PUS_SERVICE_201 = 0x51020100, - TIME_STAMPER = 0x52000001, TM_FUNNEL = 0x52000002, /* Test Task */ From 804871ee27eee5e8f382a6a62b5d5ff8967293d0 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 27 Dec 2020 16:56:51 +0100 Subject: [PATCH 079/360] another fix --- fsfwconfig/FSFWConfig.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/fsfwconfig/FSFWConfig.h b/fsfwconfig/FSFWConfig.h index 5df83705..fdfa889a 100644 --- a/fsfwconfig/FSFWConfig.h +++ b/fsfwconfig/FSFWConfig.h @@ -2,6 +2,7 @@ #define FSFWCONFIG_FSFWCONFIG_H_ #include +#include //! Used to determine whether C++ ostreams are used //! Those can lead to code bloat. @@ -14,12 +15,6 @@ //! Can be used to enable debugging printouts for developing the FSFW #define FSFW_DEBUGGING 0 -//! Defines the FIFO depth of each commanding service base which -//! also determines how many commands a CSB service can handle in one cycle -//! simulataneously. This will increase the required RAM for -//! each CSB service ! -#define FSFW_CSB_FIFO_DEPTH 6 - //! If FSFW_OBJ_EVENT_TRANSLATION is set to one, //! additional output which requires the translation files translateObjects //! and translateEvents (and their compiled source files) @@ -48,6 +43,12 @@ static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 8; static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240; static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120; static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120; + +//! Defines the FIFO depth of each commanding service base which +//! also determines how many commands a CSB service can handle in one cycle +//! simulataneously. This will increase the required RAM for +//! each CSB service ! +static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6; } #endif /* FSFWCONFIG_FSFWCONFIG_H_ */ From 90d1b601be01658898fc886c08d407c688c41d35 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 27 Dec 2020 17:00:38 +0100 Subject: [PATCH 080/360] more fixes --- bsp_linux/InitMission.cpp | 4 ---- fsfwconfig/cdatapool/dataPoolInit.cpp | 5 ----- fsfwconfig/cdatapool/dataPoolInit.h | 13 ------------- 3 files changed, 22 deletions(-) delete mode 100644 fsfwconfig/cdatapool/dataPoolInit.cpp delete mode 100644 fsfwconfig/cdatapool/dataPoolInit.h diff --git a/bsp_linux/InitMission.cpp b/bsp_linux/InitMission.cpp index cf84ab0d..d076c680 100644 --- a/bsp_linux/InitMission.cpp +++ b/bsp_linux/InitMission.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -29,9 +28,6 @@ ServiceInterfaceStream sif::error("ERROR", true, false, true); ObjectManagerIF *objectManager = nullptr; -//Initialize Data Pool -DataPool dataPool(nullptr); - void InitMission::initMission() { sif::info << "Building global objects.." << std::endl; /* Instantiate global object manager and also create all objects */ diff --git a/fsfwconfig/cdatapool/dataPoolInit.cpp b/fsfwconfig/cdatapool/dataPoolInit.cpp deleted file mode 100644 index fd536af5..00000000 --- a/fsfwconfig/cdatapool/dataPoolInit.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include - -void datapool::dataPoolInit(std::map* poolMap) { - -} diff --git a/fsfwconfig/cdatapool/dataPoolInit.h b/fsfwconfig/cdatapool/dataPoolInit.h deleted file mode 100644 index f97fe7a3..00000000 --- a/fsfwconfig/cdatapool/dataPoolInit.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef FSFWCONFIG_CDATAPOOL_DATAPOOLINIT_H_ -#define FSFWCONFIG_CDATAPOOL_DATAPOOLINIT_H_ - -#include - -namespace datapool{ - void dataPoolInit(std::map* poolMap); - - enum datapoolvariables { - NO_PARAMETER = 0, - }; -} -#endif /* FSFWCONFIG_CDATAPOOL_DATAPOOLINIT_H_ */ From 3688b2b4659101c825e916cd4d35217bf493d77e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 27 Dec 2020 17:04:15 +0100 Subject: [PATCH 081/360] tmtc update --- tmtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmtc b/tmtc index e0c896e6..9be8713f 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit e0c896e62d25286d00599ca57b71d0a3495ed95f +Subproject commit 9be8713fa0cc6128e9469da2e635365b03146de3 From f447a1bdeff60ccba709e35c3528acca1ab66906 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 27 Dec 2020 17:14:26 +0100 Subject: [PATCH 082/360] another fix --- mission/devices/MGMHandlerLIS3MDL.cpp | 4 ++-- tmtc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mission/devices/MGMHandlerLIS3MDL.cpp b/mission/devices/MGMHandlerLIS3MDL.cpp index 1cc83bf8..5de4f719 100644 --- a/mission/devices/MGMHandlerLIS3MDL.cpp +++ b/mission/devices/MGMHandlerLIS3MDL.cpp @@ -154,7 +154,7 @@ ReturnValue_t MGMHandlerLIS3MDL::buildCommandFromCommand( return setOperatingMode(commandData, commandDataLen); } default: - lastSentCommand = DeviceHandlerIF::NO_COMMAND; + lastSentCommand = DeviceHandlerIF::NO_COMMAND_ID; return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; } return HasReturnvaluesIF::RETURN_FAILED; @@ -283,7 +283,7 @@ ReturnValue_t MGMHandlerLIS3MDL::interpretDeviceReply(DeviceCommandId_t id, } default: { - return DeviceHandlerIF::UNKNOW_DEVICE_REPLY; + return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; } } diff --git a/tmtc b/tmtc index e0c896e6..9be8713f 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit e0c896e62d25286d00599ca57b71d0a3495ed95f +Subproject commit 9be8713fa0cc6128e9469da2e635365b03146de3 From e475cc408b45eefd20f25dae16880514c9aa0d74 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 27 Dec 2020 17:15:59 +0100 Subject: [PATCH 083/360] fix --- mission/devices/MGMHandlerLIS3MDL.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mission/devices/MGMHandlerLIS3MDL.h b/mission/devices/MGMHandlerLIS3MDL.h index b400daee..a5a1cadf 100644 --- a/mission/devices/MGMHandlerLIS3MDL.h +++ b/mission/devices/MGMHandlerLIS3MDL.h @@ -144,7 +144,7 @@ private: * As this is a SPI Device, we get the Answer of the last sent command in * the next read cycle, so we could check the command for identification. */ - DeviceCommandId_t lastSentCommand = DeviceHandlerIF::NO_COMMAND; + DeviceCommandId_t lastSentCommand = DeviceHandlerIF::NO_COMMAND_ID; /** * We always update all registers together, so this method updates From 50996ef04b5b8adf884d177d55ebda47282830cf Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Mon, 28 Dec 2020 09:49:50 +0100 Subject: [PATCH 084/360] adapted GomspaceDeviceHandler to new DeviceHandlerBase --- mission/core/GenericFactory.cpp | 3 +++ mission/devices/GomspaceDeviceHandler.cpp | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mission/core/GenericFactory.cpp b/mission/core/GenericFactory.cpp index a83bfbb0..24572218 100644 --- a/mission/core/GenericFactory.cpp +++ b/mission/core/GenericFactory.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,8 @@ void ObjectFactory::produceGenericObjects() { apid::EIVE_OBSW, pus::PUS_SERVICE_1, objects::TM_FUNNEL, 20); new Service2DeviceAccess(objects::PUS_SERVICE_2_DEVICE_ACCESS, apid::EIVE_OBSW, pus::PUS_SERVICE_2, 3, 10); + new Service3Housekeeping(objects::PUS_SERVICE_3_HOUSEKEEPING, + apid::EIVE_OBSW, pus::PUS_SERVICE_3); new Service5EventReporting(objects::PUS_SERVICE_5_EVENT_REPORTING, apid::EIVE_OBSW, pus::PUS_SERVICE_5, 50); new Service8FunctionManagement(objects::PUS_SERVICE_8_FUNCTION_MGMT, diff --git a/mission/devices/GomspaceDeviceHandler.cpp b/mission/devices/GomspaceDeviceHandler.cpp index 247a6aa9..cd37abb8 100644 --- a/mission/devices/GomspaceDeviceHandler.cpp +++ b/mission/devices/GomspaceDeviceHandler.cpp @@ -333,6 +333,7 @@ ReturnValue_t GomspaceDeviceHandler::generateResetWatchdogCmd(){ return HasReturnvaluesIF::RETURN_OK; } -uint32_t GomspaceDeviceHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo){ +uint32_t GomspaceDeviceHandler::getTransitionDelayMs(Mode_t modeFrom, + Mode_t modeTo) { return 0; } From 3dcd8f09af8b3b75228b98a6dde52b5d98afa4fb Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Mon, 28 Dec 2020 11:02:24 +0100 Subject: [PATCH 085/360] added polling sequence table slot for PERFORM_OPERATION --- fsfwconfig/pollingsequence/PollingSequenceFactory.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp b/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp index c3f5872d..8a14cbb3 100644 --- a/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp +++ b/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp @@ -32,6 +32,15 @@ ReturnValue_t pst::gomspacePstInit(FixedTimeslotTaskIF *thisSequence){ uint32_t length = thisSequence->getPeriodMs(); + thisSequence->addSlot(objects::P60DOCK_HANDLER, + length * 0, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::PDU1_HANDLER, + length * 0, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::PDU2_HANDLER, + length * 0, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::ACU_HANDLER, + length * 0, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::P60DOCK_HANDLER, length * 0, DeviceHandlerIF::SEND_WRITE); thisSequence->addSlot(objects::PDU1_HANDLER, From b3047c4ab6d0af82a88ab865d238d0ce7cdf10e2 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 01:09:59 +0100 Subject: [PATCH 086/360] added cmake support --- .gitignore | 11 +- CMakeLists.txt | 153 ++++++++++++++++++ bsp_hosted/CMakeLists.txt | 10 ++ bsp_hosted/boardconfig/CMakeLists.txt | 10 ++ bsp_hosted/comIF/CMakeLists.txt | 8 + bsp_hosted/fsfwconfig/CMakeLists.txt | 10 ++ bsp_hosted/fsfwconfig/FSFWConfig.h | 12 +- bsp_hosted/fsfwconfig/OBSWConfig.h | 18 ++- .../fsfwconfig/ipc/MissionMessageTypes.h | 2 +- .../fsfwconfig/objects/systemObjectList.h | 1 - bsp_linux/CMakeLists.txt | 10 ++ bsp_linux/boardconfig/CMakeLists.txt | 6 + buildsystem/cmake/BuildType.cmake | 45 ++++++ buildsystem/cmake/HardwareOsPostConfig.cmake | 62 +++++++ buildsystem/cmake/HardwareOsPreConfig.cmake | 68 ++++++++ buildsystem/cmake/PreProjectConfig.cmake | 58 +++++++ buildsystem/cmake/RPiCrossCompileConfig.cmake | 146 +++++++++++++++++ .../inspectionProfiles/profiles_settings.xml | 6 + buildsystem/cmake/scripts/.idea/misc.xml | 4 + buildsystem/cmake/scripts/.idea/modules.xml | 8 + buildsystem/cmake/scripts/.idea/scripts.iml | 8 + buildsystem/cmake/scripts/.idea/vcs.xml | 6 + buildsystem/cmake/scripts/.idea/workspace.xml | 89 ++++++++++ .../scripts/Host/create_cmake_debug_cfg.sh | 26 +++ .../scripts/Host/create_cmake_release_cfg.sh | 26 +++ .../Host/create_cmake_relwithdeb_cfg.sh | 26 +++ .../scripts/Host/create_cmake_size_cfg.sh | 26 +++ .../scripts/Linux/create_cmake_debug_cfg.sh | 20 +++ .../scripts/Linux/create_cmake_release_cfg.sh | 20 +++ .../Linux/create_cmake_relwithdeb_cfg.sh | 20 +++ .../scripts/Linux/create_cmake_size_cfg.sh | 20 +++ .../scripts/RPi/create_cmake_debug_cfg.sh | 27 ++++ .../scripts/RPi/create_cmake_release_cfg.sh | 27 ++++ .../RPi/create_cmake_relwithdeb_cfg.sh | 27 ++++ .../scripts/RPi/create_cmake_size_cfg.sh | 27 ++++ .../cmake/scripts/RPi/rpi_path_helper.sh | 24 +++ .../cmake/scripts/RPi/rpi_path_helper_win.sh | 22 +++ .../cmake/scripts/cmake_build_config.py | 115 +++++++++++++ fsfw | 2 +- fsfwconfig/OBSWConfig.h | 20 ++- mission/CMakeLists.txt | 3 + mission/core/CMakeLists.txt | 5 + mission/devices/CMakeLists.txt | 8 + .../MGMHandlerRM3100Definitions.h | 6 +- mission/utility/CMakeLists.txt | 5 + tmtc | 2 +- 46 files changed, 1235 insertions(+), 20 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 bsp_hosted/CMakeLists.txt create mode 100644 bsp_hosted/boardconfig/CMakeLists.txt create mode 100644 bsp_hosted/comIF/CMakeLists.txt create mode 100644 bsp_hosted/fsfwconfig/CMakeLists.txt create mode 100644 bsp_linux/CMakeLists.txt create mode 100644 bsp_linux/boardconfig/CMakeLists.txt create mode 100644 buildsystem/cmake/BuildType.cmake create mode 100644 buildsystem/cmake/HardwareOsPostConfig.cmake create mode 100644 buildsystem/cmake/HardwareOsPreConfig.cmake create mode 100644 buildsystem/cmake/PreProjectConfig.cmake create mode 100644 buildsystem/cmake/RPiCrossCompileConfig.cmake create mode 100644 buildsystem/cmake/scripts/.idea/inspectionProfiles/profiles_settings.xml create mode 100644 buildsystem/cmake/scripts/.idea/misc.xml create mode 100644 buildsystem/cmake/scripts/.idea/modules.xml create mode 100644 buildsystem/cmake/scripts/.idea/scripts.iml create mode 100644 buildsystem/cmake/scripts/.idea/vcs.xml create mode 100644 buildsystem/cmake/scripts/.idea/workspace.xml create mode 100644 buildsystem/cmake/scripts/Host/create_cmake_debug_cfg.sh create mode 100644 buildsystem/cmake/scripts/Host/create_cmake_release_cfg.sh create mode 100644 buildsystem/cmake/scripts/Host/create_cmake_relwithdeb_cfg.sh create mode 100644 buildsystem/cmake/scripts/Host/create_cmake_size_cfg.sh create mode 100644 buildsystem/cmake/scripts/Linux/create_cmake_debug_cfg.sh create mode 100644 buildsystem/cmake/scripts/Linux/create_cmake_release_cfg.sh create mode 100644 buildsystem/cmake/scripts/Linux/create_cmake_relwithdeb_cfg.sh create mode 100644 buildsystem/cmake/scripts/Linux/create_cmake_size_cfg.sh create mode 100644 buildsystem/cmake/scripts/RPi/create_cmake_debug_cfg.sh create mode 100644 buildsystem/cmake/scripts/RPi/create_cmake_release_cfg.sh create mode 100644 buildsystem/cmake/scripts/RPi/create_cmake_relwithdeb_cfg.sh create mode 100644 buildsystem/cmake/scripts/RPi/create_cmake_size_cfg.sh create mode 100644 buildsystem/cmake/scripts/RPi/rpi_path_helper.sh create mode 100644 buildsystem/cmake/scripts/RPi/rpi_path_helper_win.sh create mode 100644 buildsystem/cmake/scripts/cmake_build_config.py create mode 100644 mission/CMakeLists.txt create mode 100644 mission/core/CMakeLists.txt create mode 100644 mission/devices/CMakeLists.txt create mode 100644 mission/utility/CMakeLists.txt diff --git a/.gitignore b/.gitignore index 0d0e490d..ff23c0fd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,15 @@ _obj _bin _dep +Debug +Debug* +Release +Release* +MinSizeRel +MinSizeRel* +RelWithDebInfo +RelWithDebInfo* + .settings .metadata .project @@ -9,4 +18,4 @@ _dep __pycache__ !misc/eclipse/**/.cproject -!misc/eclipse/**/.project \ No newline at end of file +!misc/eclipse/**/.project diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..98f2b5e8 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,153 @@ +################################################################################ +# CMake support for the EIVE OBSW +# +# Developed in an effort to replace Make with a modern build system. +# +# Author: R. Mueller +################################################################################ + +################################################################################ +# Pre-Project preparation +################################################################################ +cmake_minimum_required(VERSION 3.13) + +# set(CMAKE_VERBOSE TRUE) + +set(CMAKE_SCRIPT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/buildsystem/cmake") + +if(NOT OS_FSFW) + set(OS_FSFW host CACHE STRING "OS for the FSFW.") +endif() + +# Perform steps like loading toolchain files where applicable. +include(${CMAKE_SCRIPT_PATH}/PreProjectConfig.cmake) +pre_project_config() + +# Project Name +project(fsfw_example ASM C CXX) + +################################################################################ +# Pre-Sources preparation +################################################################################ + +# Specify the C++ standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +# Set names and variables +set(TARGET_NAME ${CMAKE_PROJECT_NAME}) +set(LIB_FSFW_NAME fsfw) + +# Set path names +set(FSFW_PATH fsfw) +set(MISSION_PATH mission) + +# Analyse different OS and architecture/target options, determine BSP_PATH, +# display information about compiler etc. +include (${CMAKE_SCRIPT_PATH}/HardwareOsPreConfig.cmake) +pre_source_hw_os_config() + +set(FSFW_CONFIG_PATH "${BSP_PATH}/fsfwconfig") + +################################################################################ +# Executable and Sources +################################################################################ + +# Add executable +add_executable(${TARGET_NAME}) + +# Add subdirectories +if(LIB_OS_NAME) + add_subdirectory(${LIB_OS_NAME}) +endif() +add_subdirectory(${BSP_PATH}) +add_subdirectory(${FSFW_PATH}) +add_subdirectory(${MISSION_PATH}) + +################################################################################ +# Post-Sources preparation +################################################################################ + +# Add libraries for all sources. +target_link_libraries(${TARGET_NAME} PRIVATE + ${LIB_FSFW_NAME} + ${LIB_OS_NAME} +) + +# Add include paths for all sources. +target_include_directories(${TARGET_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${FSFW_CONFIG_PATH} +) + + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(WARNING_FLAGS + -Wall + -Wextra + -Wshadow=local + -Wimplicit-fallthrough=1 + -Wno-unused-parameter + -Wno-psabi + ) + + # Remove unused sections. + target_compile_options(${TARGET_NAME} PRIVATE + "-ffunction-sections" + "-fdata-sections" + ) + + # Removed unused sections. + target_link_options(${TARGET_NAME} PRIVATE + "-Wl,--gc-sections" + ) + +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(COMPILER_FLAGS "/permissive-") +endif() + +if(CMAKE_VERBOSE) + message(STATUS "Warning flags: ${WARNING_FLAGS}") +endif() + + +# Compile options for all sources. +target_compile_options(${TARGET_NAME} PRIVATE + ${WARNING_FLAGS} +) + +if(${CMAKE_CROSSCOMPILING}) + include (${CMAKE_SCRIPT_PATH}/HardwareOsPostConfig.cmake) + post_source_hw_os_config() +endif() + +if(NOT CMAKE_SIZE) + set(CMAKE_SIZE size) + if(WIN32) + set(FILE_SUFFIX ".exe") + endif() +endif() + +if(TGT_BSP) + set(TARGET_STRING "Target BSP: ${TGT_BSP}") +else() + set(TARGET_STRING "Target BSP: Hosted") +endif() + +add_custom_command( + TARGET ${TARGET_NAME} + POST_BUILD + COMMAND echo "Build directory: ${CMAKE_BINARY_DIR}" + COMMAND echo "Target OSAL: ${OS_FSFW}" + COMMAND echo "Target Build Type: ${CMAKE_BUILD_TYPE}" + COMMAND echo "${TARGET_STRING}" + COMMAND ${CMAKE_SIZE} ${TARGET_NAME}${FILE_SUFFIX} +) + +include (${CMAKE_SCRIPT_PATH}/BuildType.cmake) +set_build_type() + + + + + diff --git a/bsp_hosted/CMakeLists.txt b/bsp_hosted/CMakeLists.txt new file mode 100644 index 00000000..7171d9d7 --- /dev/null +++ b/bsp_hosted/CMakeLists.txt @@ -0,0 +1,10 @@ +target_sources(${TARGET_NAME} PUBLIC + InitMission.cpp + main.cpp + ObjectFactory.cpp +) + +add_subdirectory(fsfwconfig) +add_subdirectory(boardconfig) + + diff --git a/bsp_hosted/boardconfig/CMakeLists.txt b/bsp_hosted/boardconfig/CMakeLists.txt new file mode 100644 index 00000000..c32b326d --- /dev/null +++ b/bsp_hosted/boardconfig/CMakeLists.txt @@ -0,0 +1,10 @@ +target_sources(${TARGET_NAME} PRIVATE + print.c +) + +target_include_directories(${TARGET_NAME} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + + + diff --git a/bsp_hosted/comIF/CMakeLists.txt b/bsp_hosted/comIF/CMakeLists.txt new file mode 100644 index 00000000..eb416f75 --- /dev/null +++ b/bsp_hosted/comIF/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${TARGET_NAME} PUBLIC + ArduinoComIF.cpp + ArduinoCookie.cpp +) + + + + diff --git a/bsp_hosted/fsfwconfig/CMakeLists.txt b/bsp_hosted/fsfwconfig/CMakeLists.txt new file mode 100644 index 00000000..a906098f --- /dev/null +++ b/bsp_hosted/fsfwconfig/CMakeLists.txt @@ -0,0 +1,10 @@ +target_sources(${TARGET_NAME} PRIVATE + ipc/MissionMessageTypes.cpp +) + +target_include_directories(${TARGET_NAME} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + + + diff --git a/bsp_hosted/fsfwconfig/FSFWConfig.h b/bsp_hosted/fsfwconfig/FSFWConfig.h index 8c6c754a..66fd276e 100644 --- a/bsp_hosted/fsfwconfig/FSFWConfig.h +++ b/bsp_hosted/fsfwconfig/FSFWConfig.h @@ -15,12 +15,6 @@ //! Can be used to enable debugging printouts for developing the FSFW #define FSFW_DEBUGGING 0 -//! Defines the FIFO depth of each commanding service base which -//! also determines how many commands a CSB service can handle in one cycle -//! simulataneously. This will increase the required RAM for -//! each CSB service ! -#define FSFW_CSB_FIFO_DEPTH 6 - //! If FSFW_OBJ_EVENT_TRANSLATION is set to one, //! additional output which requires the translation files translateObjects //! and translateEvents (and their compiled source files) @@ -49,6 +43,12 @@ static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 8; static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240; static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120; static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120; + +//! Defines the FIFO depth of each commanding service base which +//! also determines how many commands a CSB service can handle in one cycle +//! simulataneously. This will increase the required RAM for +//! each CSB service ! +static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6; } #endif /* CONFIG_FSFWCONFIG_H_ */ diff --git a/bsp_hosted/fsfwconfig/OBSWConfig.h b/bsp_hosted/fsfwconfig/OBSWConfig.h index f9e76160..fa3769b1 100644 --- a/bsp_hosted/fsfwconfig/OBSWConfig.h +++ b/bsp_hosted/fsfwconfig/OBSWConfig.h @@ -6,13 +6,25 @@ #ifndef CONFIG_OBSWCONFIG_H_ #define CONFIG_OBSWCONFIG_H_ -#include "returnvalues/classIds.h" -#include "events/subsystemIdRanges.h" - #define OBSW_ADD_TEST_CODE 0 // These defines should be disabled for mission code but are useful for // debugging. #define OBSW_ENHANCED_PRINTOUT 1 +#ifdef __cplusplus + +#include "objects/systemObjectList.h" +#include "events/subsystemIdRanges.h" +#include "returnvalues/classIds.h" + +namespace config { +#endif + +/* Add mission configuration flags here */ + +#ifdef __cplusplus +} +#endif + #endif /* CONFIG_OBSWCONFIG_H_ */ diff --git a/bsp_hosted/fsfwconfig/ipc/MissionMessageTypes.h b/bsp_hosted/fsfwconfig/ipc/MissionMessageTypes.h index 832d8e58..7e3c448f 100644 --- a/bsp_hosted/fsfwconfig/ipc/MissionMessageTypes.h +++ b/bsp_hosted/fsfwconfig/ipc/MissionMessageTypes.h @@ -11,7 +11,7 @@ class CommandMessage; * * @param message Generic Command Message */ -namespace messagetypes{ +namespace messagetypes { enum MESSAGE_TYPE { MISSION_MESSAGE_TYPE_START = FW_MESSAGES_COUNT, }; diff --git a/bsp_hosted/fsfwconfig/objects/systemObjectList.h b/bsp_hosted/fsfwconfig/objects/systemObjectList.h index 3b5717fb..05ed2c52 100644 --- a/bsp_hosted/fsfwconfig/objects/systemObjectList.h +++ b/bsp_hosted/fsfwconfig/objects/systemObjectList.h @@ -19,7 +19,6 @@ namespace objects { PUS_SERVICE_23 = 0x51002300, PUS_SERVICE_201 = 0x51020100, - TIME_STAMPER = 0x52000001, TM_FUNNEL = 0x52000002, /* Test Task */ diff --git a/bsp_linux/CMakeLists.txt b/bsp_linux/CMakeLists.txt new file mode 100644 index 00000000..8df43ca7 --- /dev/null +++ b/bsp_linux/CMakeLists.txt @@ -0,0 +1,10 @@ +target_sources(${TARGET_NAME} PUBLIC + InitMission.cpp + main.cpp + ObjectFactory.cpp +) + +add_subdirectory(boardconfig) + + + diff --git a/bsp_linux/boardconfig/CMakeLists.txt b/bsp_linux/boardconfig/CMakeLists.txt new file mode 100644 index 00000000..2a1cb58a --- /dev/null +++ b/bsp_linux/boardconfig/CMakeLists.txt @@ -0,0 +1,6 @@ +target_include_directories(${TARGET_NAME} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + + + diff --git a/buildsystem/cmake/BuildType.cmake b/buildsystem/cmake/BuildType.cmake new file mode 100644 index 00000000..e078e5c7 --- /dev/null +++ b/buildsystem/cmake/BuildType.cmake @@ -0,0 +1,45 @@ +function(set_build_type) + +message(STATUS "Used build generator: ${CMAKE_GENERATOR}") + +# Set a default build type if none was specified +set(DEFAULT_BUILD_TYPE "RelWithDebInfo") +if(EXISTS "${CMAKE_SOURCE_DIR}/.git") + set(DEFAULT_BUILD_TYPE "Debug") +endif() + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS + "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified." + ) + set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE + STRING "Choose the type of build." FORCE + ) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo" + ) +endif() + +if(${CMAKE_BUILD_TYPE} MATCHES "Debug") + message(STATUS + "Building Debug application with flags: ${CMAKE_C_FLAGS_DEBUG}" + ) +elseif(${CMAKE_BUILD_TYPE} MATCHES "RelWithDebInfo") + message(STATUS + "Building Release (Debug) application with " + "flags: ${CMAKE_C_FLAGS_RELWITHDEBINFO}" + ) +elseif(${CMAKE_BUILD_TYPE} MATCHES "MinSizeRel") + message(STATUS + "Building Release (Size) application with " + "flags: ${CMAKE_C_FLAGS_MINSIZEREL}" + ) +else() + message(STATUS + "Building Release (Speed) application with " + "flags: ${CMAKE_C_FLAGS_RELEASE}" + ) +endif() + +endfunction() diff --git a/buildsystem/cmake/HardwareOsPostConfig.cmake b/buildsystem/cmake/HardwareOsPostConfig.cmake new file mode 100644 index 00000000..c3dc3f93 --- /dev/null +++ b/buildsystem/cmake/HardwareOsPostConfig.cmake @@ -0,0 +1,62 @@ +function(post_source_hw_os_config) + +if(LINK_LWIP) + message(STATUS "Linking against ${LIB_LWIP_NAME} lwIP library") + if(LIB_LWIP_NAME) + target_link_libraries(${TARGET_NAME} PUBLIC + ${LIB_LWIP_NAME} + ) + else() + message(WARNING "lwIP library name not set!") + endif() +endif() + +if(LINK_HAL) + message(STATUS "Linking against ${LIB_HAL_NAME} HAL library") + if(LIB_HAL_NAME) + target_link_libraries(${TARGET_NAME} PUBLIC + ${LIB_HAL_NAME} + ) + else() + message(WARNING "HAL library name not set!") + endif() +endif() + +if(LINKER_SCRIPT) + target_link_options(${TARGET_NAME} PRIVATE + -T${LINKER_SCRIPT} + ) +endif() + +set(C_FLAGS "" CACHE INTERNAL "C flags") + +set(C_DEFS "" + CACHE INTERNAL + "C Defines" +) + +set(CXX_FLAGS ${C_FLAGS}) +set(CXX_DEFS ${C_DEFS}) + +if(CMAKE_VERBOSE) + message(STATUS "C Flags: ${C_FLAGS}") + message(STATUS "CXX Flags: ${CXX_FLAGS}") + message(STATUS "C Defs: ${C_DEFS}") + message(STATUS "CXX Defs: ${CXX_DEFS}") +endif() + +# Generator expression. Can be used to set different C, CXX and ASM flags. +target_compile_options(${TARGET_NAME} PRIVATE + $<$:${C_DEFS} ${C_FLAGS}> + $<$:${CXX_DEFS} ${CXX_FLAGS}> + $<$:${ASM_FLAGS}> +) + +add_custom_command( + TARGET ${TARGET_NAME} + POST_BUILD + COMMAND echo Generating binary file ${CMAKE_PROJECT_NAME}.bin.. + COMMAND ${CMAKE_OBJCOPY} -O binary ${TARGET_NAME} ${TARGET_NAME}.bin +) + +endfunction() \ No newline at end of file diff --git a/buildsystem/cmake/HardwareOsPreConfig.cmake b/buildsystem/cmake/HardwareOsPreConfig.cmake new file mode 100644 index 00000000..c2524bd7 --- /dev/null +++ b/buildsystem/cmake/HardwareOsPreConfig.cmake @@ -0,0 +1,68 @@ +function(pre_source_hw_os_config) + +# FreeRTOS +if(${OS_FSFW} MATCHES freertos) + message(FATAL_ERROR "No FreeRTOS support implemented yet.") +# RTEMS +elseif(${OS_FSFW} STREQUAL rtems) + add_definitions(-DRTEMS) + message(FATAL_ERROR "No RTEMS support implemented yet.") +elseif(${OS_FSFW} STREQUAL linux) + add_definitions(-DUNIX -DLINUX) + find_package(Threads REQUIRED) + set(BSP_PATH "bsp_linux") +# Hosted +else() + set(BSP_PATH "bsp_hosted") + if(WIN32) + add_definitions(-DWIN32) + elseif(UNIX) + find_package(Threads REQUIRED) + add_definitions(-DUNIX -DLINUX) + endif() +endif() + +# Cross-compile information +if(CMAKE_CROSSCOMPILING) + # set(CMAKE_VERBOSE TRUE) + + message(STATUS "Cross-compiling for ${TGT_BSP} target") + message(STATUS "Cross-compile gcc: ${CMAKE_C_COMPILER}") + message(STATUS "Cross-compile g++: ${CMAKE_CXX_COMPILER}") + + if(CMAKE_VERBOSE) + message(STATUS "Cross-compile linker: ${CMAKE_LINKER}") + message(STATUS "Cross-compile size utility: ${CMAKE_SIZE}") + message(STATUS "Cross-compile objcopy utility: ${CMAKE_OBJCOPY}") + message(STATUS "Cross-compile ranlib utility: ${CMAKE_RANLIB}") + message(STATUS "Cross-compile ar utility: ${CMAKE_AR}") + message(STATUS "Cross-compile nm utility: ${CMAKE_NM}") + message(STATUS "Cross-compile strip utility: ${CMAKE_STRIP}") + message(STATUS + "Cross-compile assembler: ${CMAKE_ASM_COMPILER} " + "-x assembler-with-cpp" + ) + message(STATUS "ABI flags: ${ABI_FLAGS}") + message(STATUS "Custom linker script: ${LINKER_SCRIPT}") + endif() + + set_property(CACHE TGT_BSP + PROPERTY STRINGS + "arm/raspberrypi" + ) +endif() + +if(${TGT_BSP} MATCHES "arm/raspberrypi") + +else() + + if(TGT_BSP) + message(WARNING "CMake not configured for this target!") + message(FATAL_ERROR "Target: ${TGT_BSP}!") + endif() + +endif() + +set(BSP_PATH ${BSP_PATH} PARENT_SCOPE) + +endfunction() \ No newline at end of file diff --git a/buildsystem/cmake/PreProjectConfig.cmake b/buildsystem/cmake/PreProjectConfig.cmake new file mode 100644 index 00000000..cc9fe00a --- /dev/null +++ b/buildsystem/cmake/PreProjectConfig.cmake @@ -0,0 +1,58 @@ +function(pre_project_config) + +# Basic input sanitization +if(DEFINED TGT_BSP) + if(${TGT_BSP} MATCHES "arm/raspberrypi" AND NOT ${OS_FSFW} MATCHES linux) + message(STATUS "FSFW OSAL invalid for specified target BSP ${TGT_BSP}!") + message(STATUS "Setting valid OS_FSFW: linux") + set(OS_FSFW "linux") + endif() +endif() + +# Disable compiler checks for cross-compiling. +if(${OS_FSFW} STREQUAL linux AND TGT_BSP) + + if(${TGT_BSP} MATCHES "arm/raspberrypi") + if(NOT DEFINED ENV{RASPBIAN_ROOTFS}) + if(NOT RASPBIAN_ROOTFS) + set(ENV{RASPBIAN_ROOTFS} "$ENV{HOME}/raspberrypi/rootfs") + else() + set(ENV{RASPBIAN_ROOTFS} "${RASPBIAN_ROOTFS}") + endif() + else() + message(STATUS + "RASPBIAN_ROOTFS from environmental variables used: " + "$ENV{RASPBIAN_ROOTFS}" + ) + endif() + + if(NOT DEFINED ENV{RASPBERRY_VERSION}) + if(NOT RASPBERRY_VERSION) + message(STATUS "No RASPBERRY_VERSION specified, setting to 4") + set(RASPBERRY_VERSION "4" CACHE STRING "Raspberry Pi version") + else() + message(STATUS + "Setting RASPBERRY_VERSION to ${RASPBERRY_VERSION}" + ) + set(RASPBERRY_VERSION + ${RASPBERRY_VERSION} CACHE STRING "Raspberry Pi version" + ) + set(ENV{RASPBERRY_VERSION} ${RASPBERRY_VERSION}) + endif() + else() + message(STATUS + "RASPBERRY_VERSION from environmental variables used: " + "$ENV{RASPBERRY_VERSION}" + ) + endif() + + set(CMAKE_TOOLCHAIN_FILE + "${CMAKE_SCRIPT_PATH}/RPiCrossCompileConfig.cmake" + PARENT_SCOPE + ) + else() + message(WARNING "Target BSP (TGT_BSP) ${TGT_BSP} unknown!") + endif() +endif() + +endfunction() \ No newline at end of file diff --git a/buildsystem/cmake/RPiCrossCompileConfig.cmake b/buildsystem/cmake/RPiCrossCompileConfig.cmake new file mode 100644 index 00000000..26ca5781 --- /dev/null +++ b/buildsystem/cmake/RPiCrossCompileConfig.cmake @@ -0,0 +1,146 @@ +# Based on https://github.com/Pro/raspi-toolchain but rewritten completely. + +# Adapted for the FSFW Example +if(NOT $ENV{RASPBERRY_VERSION}) + message(STATUS "Raspberry Pi version not specified, setting version 4!") + set(RASPBERRY_VERSION 4) +else() + set(RASPBERRY_VERSION $ENV{RASPBERRY_VERSION}) +endif() + + +# RASPBIAN_ROOTFS should point to the local directory which contains all the +# libraries and includes from the target raspi. +# The following command can be used to do this, replace and the +# local accordingly: +# rsync -vR --progress -rl --delete-after --safe-links pi@:/{lib,usr,opt/vc/lib} +# RASPBIAN_ROOTFS needs to be passed to the CMake command or defined in the +# application CMakeLists.txt before loading the toolchain file. + +# CROSS_COMPILE also needs to be set accordingly or passed to the CMake command + +if(NOT DEFINED ENV{RASPBIAN_ROOTFS}) + message(FATAL_ERROR + "Define the RASPBIAN_ROOTFS variable to " + "point to the raspbian rootfs." + ) +else() + set(SYSROOT_PATH "$ENV{RASPBIAN_ROOTFS}") +endif() + +if(NOT DEFINED ENV{CROSS_COMPILE}) + set(CROSS_COMPILE "arm-linux-gnueabihf") + message(STATUS + "No CROSS_COMPILE environmental variable set, using default ARM linux " + "cross compiler name ${CROSS_COMPILE}" + ) +else() + set(CROSS_COMPILE "$ENV{CROSS_COMPILE}") + message(STATUS + "Using environmental variable CROSS_COMPILE as cross-compiler: " + "$ENV{CROSS_COMPILE}" + ) +endif() + +message(STATUS "Using sysroot path: ${SYSROOT_PATH}") + +set(CROSS_COMPILE_CC "${CROSS_COMPILE}-gcc") +set(CROSS_COMPILE_CXX "${CROSS_COMPILE}-g++") +set(CROSS_COMPILE_LD "${CROSS_COMPILE}-ld") +set(CROSS_COMPILE_AR "${CROSS_COMPILE}-ar") +set(CROSS_COMPILE_RANLIB "${CROSS_COMPILE}-ranlib") +set(CROSS_COMPILE_STRIP "${CROSS_COMPILE}-strip") +set(CROSS_COMPILE_NM "${CROSS_COMPILE}-nm") +set(CROSS_COMPILE_OBJCOPY "${CROSS_COMPILE}-objcopy") +set(CROSS_COMPILE_SIZE "${CROSS_COMPILE}-size") + +# At the very least, cross compile gcc and g++ have to be set! +find_program (CROSS_COMPILE_CC_FOUND ${CROSS_COMPILE_CC} REQUIRED) +find_program (CROSS_COMPILE_CXX_FOUND ${CROSS_COMPILE_CXX} REQUIRED) + +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_SYSROOT "${SYSROOT_PATH}") + +# Define name of the target system +set(CMAKE_SYSTEM_NAME "Linux") +if(RASPBERRY_VERSION VERSION_GREATER 1) + set(CMAKE_SYSTEM_PROCESSOR "armv7") +else() + set(CMAKE_SYSTEM_PROCESSOR "arm") +endif() + +# Define the compiler +set(CMAKE_C_COMPILER ${CROSS_COMPILE_CC}) +set(CMAKE_CXX_COMPILER ${CROSS_COMPILE_CXX}) + +# List of library dirs where LD has to look. Pass them directly through gcc. +# LD_LIBRARY_PATH is not evaluated by arm-*-ld +set(LIB_DIRS + "/opt/cross-pi-gcc/arm-linux-gnueabihf/lib" + "/opt/cross-pi-gcc/lib" + "${SYSROOT_PATH}/opt/vc/lib" + "${SYSROOT_PATH}/lib/${CROSS_COMPILE}" + "${SYSROOT_PATH}/usr/local/lib" + "${SYSROOT_PATH}/usr/lib/${CROSS_COMPILE}" + "${SYSROOT_PATH}/usr/lib" + "${SYSROOT_PATH}/usr/lib/${CROSS_COMPILE}/blas" + "${SYSROOT_PATH}/usr/lib/${CROSS_COMPILE}/lapack" +) +# You can additionally check the linker paths if you add the +# flags ' -Xlinker --verbose' +set(COMMON_FLAGS "-I${SYSROOT_PATH}/usr/include") +foreach(LIB ${LIB_DIRS}) + set(COMMON_FLAGS "${COMMON_FLAGS} -L${LIB} -Wl,-rpath-link,${LIB}") +endforeach() + +set(CMAKE_PREFIX_PATH + "${CMAKE_PREFIX_PATH}" + "${SYSROOT_PATH}/usr/lib/${CROSS_COMPILE}" +) + +if(RASPBERRY_VERSION VERSION_GREATER 3) + set(CMAKE_C_FLAGS + "-mcpu=cortex-a72 -mfpu=neon-vfpv4 -mfloat-abi=hard ${COMMON_FLAGS}" + CACHE STRING "Flags for Raspberry PI 4" + ) + set(CMAKE_CXX_FLAGS + "${CMAKE_C_FLAGS}" + CACHE STRING "Flags for Raspberry PI 4" + ) +elseif(RASPBERRY_VERSION VERSION_GREATER 2) + set(CMAKE_C_FLAGS + "-mcpu=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard ${COMMON_FLAGS}" + CACHE STRING "Flags for Raspberry PI 3" + ) + set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}" + CACHE STRING "Flags for Raspberry PI 3" + ) +elseif(RASPBERRY_VERSION VERSION_GREATER 1) + set(CMAKE_C_FLAGS + "-mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard ${COMMON_FLAGS}" + CACHE STRING "Flags for Raspberry PI 2" + ) + set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}" + CACHE STRING "Flags for Raspberry PI 2" + ) +else() + set(CMAKE_C_FLAGS + "-mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard ${COMMON_FLAGS}" + CACHE STRING "Flags for Raspberry PI 1 B+ Zero" + ) + set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}" + CACHE STRING "Flags for Raspberry PI 1 B+ Zero" + ) +endif() + +set(CMAKE_FIND_ROOT_PATH + "${CMAKE_INSTALL_PREFIX};${CMAKE_PREFIX_PATH};${CMAKE_SYSROOT}" +) + + +# search for programs in the build host directories +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +# for libraries and headers in the target directories +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/buildsystem/cmake/scripts/.idea/inspectionProfiles/profiles_settings.xml b/buildsystem/cmake/scripts/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 00000000..105ce2da --- /dev/null +++ b/buildsystem/cmake/scripts/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/buildsystem/cmake/scripts/.idea/misc.xml b/buildsystem/cmake/scripts/.idea/misc.xml new file mode 100644 index 00000000..d56657ad --- /dev/null +++ b/buildsystem/cmake/scripts/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/buildsystem/cmake/scripts/.idea/modules.xml b/buildsystem/cmake/scripts/.idea/modules.xml new file mode 100644 index 00000000..bb83e262 --- /dev/null +++ b/buildsystem/cmake/scripts/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/buildsystem/cmake/scripts/.idea/scripts.iml b/buildsystem/cmake/scripts/.idea/scripts.iml new file mode 100644 index 00000000..d0876a78 --- /dev/null +++ b/buildsystem/cmake/scripts/.idea/scripts.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/buildsystem/cmake/scripts/.idea/vcs.xml b/buildsystem/cmake/scripts/.idea/vcs.xml new file mode 100644 index 00000000..c2365ab1 --- /dev/null +++ b/buildsystem/cmake/scripts/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/buildsystem/cmake/scripts/.idea/workspace.xml b/buildsystem/cmake/scripts/.idea/workspace.xml new file mode 100644 index 00000000..70a189f3 --- /dev/null +++ b/buildsystem/cmake/scripts/.idea/workspace.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1609084345199 + + + + + + + + + + + + \ No newline at end of file diff --git a/buildsystem/cmake/scripts/Host/create_cmake_debug_cfg.sh b/buildsystem/cmake/scripts/Host/create_cmake_debug_cfg.sh new file mode 100644 index 00000000..ee7b441a --- /dev/null +++ b/buildsystem/cmake/scripts/Host/create_cmake_debug_cfg.sh @@ -0,0 +1,26 @@ +#!/bin/sh +counter=0 +while [ ${counter} -lt 5 ] +do + cd .. + if [ -f "cmake_build_config.py" ];then + break + fi + counter=$((counter=counter + 1)) +done + +if [ "${counter}" -ge 5 ];then + echo "create_cmake_cfg.sh not found in upper directories!" + exit 1 +fi + +build_generator="" +os_fsfw="host" +if [ "${OS}" = "Windows_NT" ]; then + build_generator="MinGW Makefiles" +# Could be other OS but this works for now. +else + build_generator="Unix Makefiles" +fi + +python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "debug" diff --git a/buildsystem/cmake/scripts/Host/create_cmake_release_cfg.sh b/buildsystem/cmake/scripts/Host/create_cmake_release_cfg.sh new file mode 100644 index 00000000..778cde3b --- /dev/null +++ b/buildsystem/cmake/scripts/Host/create_cmake_release_cfg.sh @@ -0,0 +1,26 @@ +#!/bin/sh +counter=0 +while [ ${counter} -lt 5 ] +do + cd .. + if [ -f "cmake_build_config.py" ];then + break + fi + counter=$((counter=counter + 1)) +done + +if [ "${counter}" -ge 5 ];then + echo "create_cmake_cfg.sh not found in upper directories!" + exit 1 +fi + +build_generator="" +os_fsfw="host" +if [ "${OS}" = "Windows_NT" ]; then + build_generator="MinGW Makefiles" +# Could be other OS but this works for now. +else + build_generator="Unix Makefiles" +fi + +python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "release" diff --git a/buildsystem/cmake/scripts/Host/create_cmake_relwithdeb_cfg.sh b/buildsystem/cmake/scripts/Host/create_cmake_relwithdeb_cfg.sh new file mode 100644 index 00000000..f9321e69 --- /dev/null +++ b/buildsystem/cmake/scripts/Host/create_cmake_relwithdeb_cfg.sh @@ -0,0 +1,26 @@ +#!/bin/sh +counter=0 +while [ ${counter} -lt 5 ] +do + cd .. + if [ -f "cmake_build_config.py" ];then + break + fi + counter=$((counter=counter + 1)) +done + +if [ "${counter}" -ge 5 ];then + echo "create_cmake_cfg.sh not found in upper directories!" + exit 1 +fi + +build_generator="" +os_fsfw="host" +if [ "${OS}" = "Windows_NT" ]; then + build_generator="MinGW Makefiles" +# Could be other OS but this works for now. +else + build_generator="Unix Makefiles" +fi + +python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "reldeb" diff --git a/buildsystem/cmake/scripts/Host/create_cmake_size_cfg.sh b/buildsystem/cmake/scripts/Host/create_cmake_size_cfg.sh new file mode 100644 index 00000000..6a3cbe60 --- /dev/null +++ b/buildsystem/cmake/scripts/Host/create_cmake_size_cfg.sh @@ -0,0 +1,26 @@ +#!/bin/sh +counter=0 +while [ ${counter} -lt 5 ] +do + cd .. + if [ -f "cmake_build_config.py" ];then + break + fi + counter=$((counter=counter + 1)) +done + +if [ "${counter}" -ge 5 ];then + echo "create_cmake_cfg.sh not found in upper directories!" + exit 1 +fi + +build_generator="" +os_fsfw="host" +if [ "${OS}" = "Windows_NT" ]; then + build_generator="MinGW Makefiles" +# Could be other OS but this works for now. +else + build_generator="Unix Makefiles" +fi + +python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "size" \ No newline at end of file diff --git a/buildsystem/cmake/scripts/Linux/create_cmake_debug_cfg.sh b/buildsystem/cmake/scripts/Linux/create_cmake_debug_cfg.sh new file mode 100644 index 00000000..5dff0fc7 --- /dev/null +++ b/buildsystem/cmake/scripts/Linux/create_cmake_debug_cfg.sh @@ -0,0 +1,20 @@ +#!/bin/sh +counter=0 +while [ ${counter} -lt 5 ] +do + cd .. + if [ -f "cmake_build_config.py" ];then + break + fi + counter=$((counter=counter + 1)) +done + +if [ "${counter}" -ge 5 ];then + echo "create_cmake_cfg.sh not found in upper directories!" + exit 1 +fi + +build_generator="Unix Makefiles" +os_fsfw="linux" + +python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "debug" diff --git a/buildsystem/cmake/scripts/Linux/create_cmake_release_cfg.sh b/buildsystem/cmake/scripts/Linux/create_cmake_release_cfg.sh new file mode 100644 index 00000000..914c4581 --- /dev/null +++ b/buildsystem/cmake/scripts/Linux/create_cmake_release_cfg.sh @@ -0,0 +1,20 @@ +#!/bin/sh +counter=0 +while [ ${counter} -lt 5 ] +do + cd .. + if [ -f "cmake_build_config.py" ];then + break + fi + counter=$((counter=counter + 1)) +done + +if [ "${counter}" -ge 5 ];then + echo "create_cmake_cfg.sh not found in upper directories!" + exit 1 +fi + +build_generator="Unix Makefiles" +os_fsfw="linux" + +python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "release" diff --git a/buildsystem/cmake/scripts/Linux/create_cmake_relwithdeb_cfg.sh b/buildsystem/cmake/scripts/Linux/create_cmake_relwithdeb_cfg.sh new file mode 100644 index 00000000..3414d111 --- /dev/null +++ b/buildsystem/cmake/scripts/Linux/create_cmake_relwithdeb_cfg.sh @@ -0,0 +1,20 @@ +#!/bin/sh +counter=0 +while [ ${counter} -lt 5 ] +do + cd .. + if [ -f "cmake_build_config.py" ];then + break + fi + counter=$((counter=counter + 1)) +done + +if [ "${counter}" -ge 5 ];then + echo "create_cmake_cfg.sh not found in upper directories!" + exit 1 +fi + +build_generator="Unix Makefiles" +os_fsfw="linux" + +python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "reldeb" diff --git a/buildsystem/cmake/scripts/Linux/create_cmake_size_cfg.sh b/buildsystem/cmake/scripts/Linux/create_cmake_size_cfg.sh new file mode 100644 index 00000000..d4500d6d --- /dev/null +++ b/buildsystem/cmake/scripts/Linux/create_cmake_size_cfg.sh @@ -0,0 +1,20 @@ +#!/bin/sh +counter=0 +while [ ${counter} -lt 5 ] +do + cd .. + if [ -f "cmake_build_config.py" ];then + break + fi + counter=$((counter=counter + 1)) +done + +if [ "${counter}" -ge 5 ];then + echo "create_cmake_cfg.sh not found in upper directories!" + exit 1 +fi + +build_generator="Unix Makefiles" +os_fsfw="linux" + +python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "size" diff --git a/buildsystem/cmake/scripts/RPi/create_cmake_debug_cfg.sh b/buildsystem/cmake/scripts/RPi/create_cmake_debug_cfg.sh new file mode 100644 index 00000000..deb78243 --- /dev/null +++ b/buildsystem/cmake/scripts/RPi/create_cmake_debug_cfg.sh @@ -0,0 +1,27 @@ +#!/bin/sh +counter=0 +while [ ${counter} -lt 5 ] +do + cd .. + if [ -f "cmake_build_config.py" ];then + break + fi + counter=$((counter=counter + 1)) +done + +if [ "${counter}" -ge 5 ];then + echo "cmake_build_config.py not found in upper directories!" + exit 1 +fi + +os_fsfw="linux" +tgt_bsp="arm/raspberrypi" +build_generator="" +if [ "${OS}" = "Windows_NT" ]; then + build_generator="MinGW Makefiles" +# Could be other OS but this works for now. +else + build_generator="Unix Makefiles" +fi + +python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "debug" -t "${tgt_bsp}" diff --git a/buildsystem/cmake/scripts/RPi/create_cmake_release_cfg.sh b/buildsystem/cmake/scripts/RPi/create_cmake_release_cfg.sh new file mode 100644 index 00000000..0e23bee4 --- /dev/null +++ b/buildsystem/cmake/scripts/RPi/create_cmake_release_cfg.sh @@ -0,0 +1,27 @@ +#!/bin/sh +counter=0 +while [ ${counter} -lt 5 ] +do + cd .. + if [ -f "cmake_build_config.py" ];then + break + fi + counter=$((counter=counter + 1)) +done + +if [ "${counter}" -ge 5 ];then + echo "cmake_build_config.py not found in upper directories!" + exit 1 +fi + +os_fsfw="linux" +tgt_bsp="arm/raspberrypi" +build_generator="" +if [ "${OS}" = "Windows_NT" ]; then + build_generator="MinGW Makefiles" +# Could be other OS but this works for now. +else + build_generator="Unix Makefiles" +fi + +python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "release" -t "${tgt_bsp}" diff --git a/buildsystem/cmake/scripts/RPi/create_cmake_relwithdeb_cfg.sh b/buildsystem/cmake/scripts/RPi/create_cmake_relwithdeb_cfg.sh new file mode 100644 index 00000000..3e952750 --- /dev/null +++ b/buildsystem/cmake/scripts/RPi/create_cmake_relwithdeb_cfg.sh @@ -0,0 +1,27 @@ +#!/bin/sh +counter=0 +while [ ${counter} -lt 5 ] +do + cd .. + if [ -f "cmake_build_config.py" ];then + break + fi + counter=$((counter=counter + 1)) +done + +if [ "${counter}" -ge 5 ];then + echo "cmake_build_config.py not found in upper directories!" + exit 1 +fi + +os_fsfw="linux" +tgt_bsp="arm/raspberrypi" +build_generator="" +if [ "${OS}" = "Windows_NT" ]; then + build_generator="MinGW Makefiles" +# Could be other OS but this works for now. +else + build_generator="Unix Makefiles" +fi + +python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "reldeb" -t "${tgt_bsp}" diff --git a/buildsystem/cmake/scripts/RPi/create_cmake_size_cfg.sh b/buildsystem/cmake/scripts/RPi/create_cmake_size_cfg.sh new file mode 100644 index 00000000..f7bad84e --- /dev/null +++ b/buildsystem/cmake/scripts/RPi/create_cmake_size_cfg.sh @@ -0,0 +1,27 @@ +#!/bin/sh +counter=0 +while [ ${counter} -lt 5 ] +do + cd .. + if [ -f "cmake_build_config.py" ];then + break + fi + counter=$((counter=counter + 1)) +done + +if [ "${counter}" -ge 5 ];then + echo "cmake_build_config.py not found in upper directories!" + exit 1 +fi + +os_fsfw="linux" +tgt_bsp="arm/raspberrypi" +build_generator="" +if [ "${OS}" = "Windows_NT" ]; then + build_generator="MinGW Makefiles" +# Could be other OS but this works for now. +else + build_generator="Unix Makefiles" +fi + +python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "size" -t "${tgt_bsp}" diff --git a/buildsystem/cmake/scripts/RPi/rpi_path_helper.sh b/buildsystem/cmake/scripts/RPi/rpi_path_helper.sh new file mode 100644 index 00000000..95044281 --- /dev/null +++ b/buildsystem/cmake/scripts/RPi/rpi_path_helper.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# This script can be used to set the path to the cross-compile toolchain +# A default path is set if the path is not supplied via command line +if [ $# -eq 1 ];then + export PATH=$PATH:"$1" +else + # TODO: make version configurable via shell argument + export PATH=$PATH:"/opt/cross-pi-gcc/bin" + export CROSS_COMPILE="arm-linux-gnueabihf" + export RASPBERRY_VERSION="4" + export RASPBIAN_ROOTFS="${HOME}/raspberrypi/rootfs" +fi + +# It is also recommended to set up a custom shell script to perform the +# sysroot synchronization so that any software is built with the library and +# headers of the Raspberry Pi. This can for example be dome with the rsync +# command. +# The following command can be used, and the local +# need to be set accordingly. + +# rsync -vR --progress -rl --delete-after --safe-links pi@:/{lib,usr,opt/vc/lib} + +# It is recommended to use $HOME/raspberrypi/rootfs as the rootfs path, +# so the default RASPBIAN_ROOTFS variable set in the CMakeLists.txt is correct. diff --git a/buildsystem/cmake/scripts/RPi/rpi_path_helper_win.sh b/buildsystem/cmake/scripts/RPi/rpi_path_helper_win.sh new file mode 100644 index 00000000..2b590e92 --- /dev/null +++ b/buildsystem/cmake/scripts/RPi/rpi_path_helper_win.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# This script can be used to set the path to the cross-compile toolchain +# A default path is set if the path is not supplied via command line +if [ $# -eq 1 ];then + export PATH=$PATH:"$1" +else + # TODO: make version configurable via shell argument + export PATH=$PATH:"/c/SysGCC/raspberry/bin" + export CROSS_COMPILE="arm-linux-gnueabihf" + export RASPBERRY_VERSION="4" + export RASPBIAN_ROOTFS="/c/Users//raspberrypi/rootfs" +fi + +# It is also recommended to set up a custom shell script to perform the +# sysroot synchronization so that any software is built with the library and +# headers of the Raspberry Pi. This can for example be dome with the rsync +# command. +# The following command can be used, and the local +# need to be set accordingly. + +# rsync -vR --progress -rl --delete-after --safe-links pi@:/{lib,usr,opt/vc/lib} + diff --git a/buildsystem/cmake/scripts/cmake_build_config.py b/buildsystem/cmake/scripts/cmake_build_config.py new file mode 100644 index 00000000..a6388ef8 --- /dev/null +++ b/buildsystem/cmake/scripts/cmake_build_config.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +""" +@brief CMake configuration helper +@details +This script was written to have a portable way to perform the CMake configuration with various parameters on +different OSes. It was first written for the FSFW Example, but could be adapted to be more generic +in the future. + +Run cmake_build_config.py --help to get more information. +""" +import os +import sys +import argparse +import shutil + + +def main(): + print("-- Python CMake build configurator utility --") + + print("Parsing command line arguments..") + parser = argparse.ArgumentParser(description="Processing arguments for CMake build configuration.") + parser.add_argument("-o", "--osal", type=str, choices=["freertos", "linux", "rtems", "host"], + help="FSFW OSAL. Valid arguments: host, linux, rtems, freertos") + parser.add_argument("-b", "--buildtype", type=str, choices=["debug", "release", "size", "reldeb"], + help="CMake build type. Valid arguments: debug, release, size, reldeb (Release with Debug " + "Information)", default="debug") + parser.add_argument("-l", "--builddir", type=str, help="Specify build directory.") + parser.add_argument("-g", "--generator", type=str, help="CMake Generator") + parser.add_argument("-t", "--target-bsp", type=str, help="Target BSP, combination of architecture and machine") + + args = parser.parse_args() + + print("Determining source location..") + source_location = determine_source_location() + print(f"Determined source location: {source_location}") + + print("Building cmake configuration command..") + + if args.osal is None: + print("No FSFW OSAL specified, setting to default (host)..") + osal = "host" + else: + osal = args.osal + + if args.generator is None: + generator_cmake_arg = "" + else: + generator_cmake_arg = f"-G \"{args.generator}\"" + + if args.buildtype == "debug": + cmake_build_type = "Debug" + elif args.buildtype == "release": + cmake_build_type = "Release" + elif args.buildtype == "size": + cmake_build_type = "MinSizeRel" + else: + cmake_build_type = "RelWithDebInfo" + + if args.target_bsp is not None: + cmake_target_cfg_cmd = f"-DTGT_BSP=\"{args.target_bsp}\"" + else: + cmake_target_cfg_cmd = "" + + # TODO: Use builddir if given (need to check whether path is relative or absolute) + build_folder = cmake_build_type + + build_path = source_location + os.path.sep + build_folder + if os.path.isdir(build_path): + remove_old_dir = input(f"{build_folder} folder already exists. Remove old directory? [y/n]: ") + if str(remove_old_dir).lower() in ["yes", "y", 1]: + remove_old_dir = True + else: + build_folder = determine_new_folder() + build_path = source_location + os.path.sep + build_folder + remove_old_dir = False + if remove_old_dir: + shutil.rmtree(build_path) + os.chdir(source_location) + os.mkdir(build_folder) + print(f"Navigating into build directory: {build_path}") + os.chdir(build_folder) + + cmake_command = f"cmake {generator_cmake_arg} -DOS_FSFW=\"{osal}\" " \ + f"-DCMAKE_BUILD_TYPE=\"{cmake_build_type}\" {cmake_target_cfg_cmd} {source_location}" + # Remove redundant spaces + cmake_command = ' '.join(cmake_command.split()) + print("Running CMake command: ") + print(f"\" {cmake_command} \"") + os.system(cmake_command) + print("-- CMake configuration done. --") + + +def determine_source_location() -> str: + index = 0 + while not os.path.isdir("fsfw"): + index += 1 + os.chdir("..") + if index >= 5: + print("Error: Could not find source directory (determined by looking for fsfw folder!)") + sys.exit(1) + return os.getcwd() + + +def determine_new_folder() -> str: + new_folder = input(f"Use different folder name? [y/n]: ") + if str(new_folder).lower() in ["yes", "y", 1]: + new_folder_name = input("New folder name: ") + return new_folder_name + else: + print("Aborting configuration.") + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/fsfw b/fsfw index dcc111e4..5b9c0e01 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit dcc111e4facf39137fe52d8234361b7d99bdde06 +Subproject commit 5b9c0e013e35ab1353d402c6fa2cd75866e3afa5 diff --git a/fsfwconfig/OBSWConfig.h b/fsfwconfig/OBSWConfig.h index 7b9dfbc4..4ceaf459 100644 --- a/fsfwconfig/OBSWConfig.h +++ b/fsfwconfig/OBSWConfig.h @@ -6,13 +6,27 @@ #ifndef FSFWCONFIG_OBSWCONFIG_H_ #define FSFWCONFIG_OBSWCONFIG_H_ -#include "returnvalues/classIds.h" -#include "events/subsystemIdRanges.h" - #define OBSW_ADD_TEST_CODE 0 // These defines should be disabled for mission code but are useful for // debugging. #define OBSW_ENHANCED_PRINTOUT 1 +#include "OBSWVersion.h" + +#ifdef __cplusplus + +#include "objects/systemObjectList.h" +#include "events/subsystemIdRanges.h" +#include "returnvalues/classIds.h" + +namespace config { +#endif + +/* Add mission configuration flags here */ + +#ifdef __cplusplus +} +#endif + #endif /* FSFWCONFIG_OBSWCONFIG_H_ */ diff --git a/mission/CMakeLists.txt b/mission/CMakeLists.txt new file mode 100644 index 00000000..9cb18749 --- /dev/null +++ b/mission/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(core) +add_subdirectory(devices) +add_subdirectory(utility) diff --git a/mission/core/CMakeLists.txt b/mission/core/CMakeLists.txt new file mode 100644 index 00000000..5d088e48 --- /dev/null +++ b/mission/core/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${TARGET_NAME} PUBLIC + GenericFactory.cpp +) + + diff --git a/mission/devices/CMakeLists.txt b/mission/devices/CMakeLists.txt new file mode 100644 index 00000000..f01df0e1 --- /dev/null +++ b/mission/devices/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${TARGET_NAME} PUBLIC + GPSHandler.cpp + GyroL3GD20Handler.cpp + MGMHandlerLIS3MDL.cpp + MGMHandlerRM3100.cpp +) + + diff --git a/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h b/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h index 60a107d8..921c9e5f 100644 --- a/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h +++ b/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h @@ -12,7 +12,7 @@ namespace RM3100 { static constexpr uint8_t READ_MASK = 0b1000'0000; /*----------------------------------------------------------------------------*/ -/* CMM Register +/* CMM Register */ /*----------------------------------------------------------------------------*/ static constexpr uint8_t SET_CMM_CMZ = 1 << 6; static constexpr uint8_t SET_CMM_CMY = 1 << 5; @@ -25,7 +25,7 @@ static constexpr uint8_t CMM_VALUE = SET_CMM_CMZ | SET_CMM_CMY | SET_CMM_CMX | SET_CMM_DRDM | SET_CMM_START; /*----------------------------------------------------------------------------*/ -/* Cycle count register +/* Cycle count register */ /*----------------------------------------------------------------------------*/ // Default value (200) static constexpr uint8_t CYCLE_COUNT_VALUE = 0xC8; @@ -35,7 +35,7 @@ static constexpr float DEFAULT_GAIN = static_cast(CYCLE_COUNT_VALUE) / static constexpr uint8_t CYCLE_COUNT_START_REGISTER = 0x04; /*----------------------------------------------------------------------------*/ -/* TMRC register +/* TMRC register */ /*----------------------------------------------------------------------------*/ static constexpr uint8_t TMRC_150HZ_VALUE = 0x94; static constexpr uint8_t TMRC_75HZ_VALUE = 0x95; diff --git a/mission/utility/CMakeLists.txt b/mission/utility/CMakeLists.txt new file mode 100644 index 00000000..4847dddd --- /dev/null +++ b/mission/utility/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${TARGET_NAME} PUBLIC + TmFunnel.cpp +) + + diff --git a/tmtc b/tmtc index 9be8713f..07b6a9df 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 9be8713fa0cc6128e9469da2e635365b03146de3 +Subproject commit 07b6a9df18baff999ca52c2f2781f8f77f8dcb65 From a817f43ae9ae5db6a900d1ce3ffecc5f25aa2610 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 01:15:35 +0100 Subject: [PATCH 087/360] bugfix --- mission/devices/GyroL3GD20Handler.cpp | 6 +++--- mission/devices/devicedefinitions/GyroL3GD20Definitions.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mission/devices/GyroL3GD20Handler.cpp b/mission/devices/GyroL3GD20Handler.cpp index b6067e5b..11a053c8 100644 --- a/mission/devices/GyroL3GD20Handler.cpp +++ b/mission/devices/GyroL3GD20Handler.cpp @@ -171,11 +171,11 @@ ReturnValue_t GyroHandler::interpretDeviceReply(DeviceCommandId_t id, int8_t temperaturOffset = (-1) * packet[L3GD20H::TEMPERATURE_IDX]; float temperature = 25.0 + temperaturOffset; - ReturnValue_t result = dataset.read(20); + result = dataset.read(20); if(result == HasReturnvaluesIF::RETURN_OK) { dataset.angVelocX = angVelocX; - dataset.angVelocY = angVelocX; - dataset.angVelocZ = angVelocX; + dataset.angVelocY = angVelocY; + dataset.angVelocZ = angVelocZ; dataset.temperature = temperature; dataset.setValidity(true, true); result = dataset.commit(20); diff --git a/mission/devices/devicedefinitions/GyroL3GD20Definitions.h b/mission/devices/devicedefinitions/GyroL3GD20Definitions.h index c6042f58..d2fa9903 100644 --- a/mission/devices/devicedefinitions/GyroL3GD20Definitions.h +++ b/mission/devices/devicedefinitions/GyroL3GD20Definitions.h @@ -14,7 +14,7 @@ static constexpr uint8_t WHO_AM_I_REG = 0b0000'1111; static constexpr uint8_t WHO_AM_I_VAL = 0b1101'0111; /*------------------------------------------------------------------------*/ -/* Control registers +/* Control registers */ /*------------------------------------------------------------------------*/ static constexpr uint8_t CTRL_REG_1 = 0b0010'0000; static constexpr uint8_t CTRL_REG_2 = 0b0010'0001; @@ -88,7 +88,7 @@ static constexpr uint8_t OUT_Z_L = 13; static constexpr uint8_t OUT_Z_H = 14; /*------------------------------------------------------------------------*/ -/* Device Handler specific +/* Device Handler specific */ /*------------------------------------------------------------------------*/ static constexpr DeviceCommandId_t READ_REGS = 0; static constexpr DeviceCommandId_t CONFIGURE_CTRL_REGS = 1; From 97331100a8b4d0a2710f8bb6df46182ad0de61f2 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 01:26:22 +0100 Subject: [PATCH 088/360] added rpi support --- CMakeLists.txt | 9 +++++++-- bsp_linux/boardconfig/CMakeLists.txt | 4 ++++ buildsystem/cmake/HardwareOsPreConfig.cmake | 4 +++- fsfwconfig/CMakeLists.txt | 11 +++++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 fsfwconfig/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 98f2b5e8..159779b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,11 @@ set(MISSION_PATH mission) include (${CMAKE_SCRIPT_PATH}/HardwareOsPreConfig.cmake) pre_source_hw_os_config() +if(${OS_FSFW} MATCHES linux) +set(FSFW_CONFIG_PATH "fsfwconfig") +else() set(FSFW_CONFIG_PATH "${BSP_PATH}/fsfwconfig") +endif() ################################################################################ # Executable and Sources @@ -57,9 +61,10 @@ set(FSFW_CONFIG_PATH "${BSP_PATH}/fsfwconfig") add_executable(${TARGET_NAME}) # Add subdirectories -if(LIB_OS_NAME) - add_subdirectory(${LIB_OS_NAME}) +if(${OS_FSFW} MATCHES linux) + add_subdirectory(${FSFW_CONFIG_PATH}) endif() + add_subdirectory(${BSP_PATH}) add_subdirectory(${FSFW_PATH}) add_subdirectory(${MISSION_PATH}) diff --git a/bsp_linux/boardconfig/CMakeLists.txt b/bsp_linux/boardconfig/CMakeLists.txt index 2a1cb58a..c32b326d 100644 --- a/bsp_linux/boardconfig/CMakeLists.txt +++ b/bsp_linux/boardconfig/CMakeLists.txt @@ -1,3 +1,7 @@ +target_sources(${TARGET_NAME} PRIVATE + print.c +) + target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/buildsystem/cmake/HardwareOsPreConfig.cmake b/buildsystem/cmake/HardwareOsPreConfig.cmake index c2524bd7..39e52168 100644 --- a/buildsystem/cmake/HardwareOsPreConfig.cmake +++ b/buildsystem/cmake/HardwareOsPreConfig.cmake @@ -53,7 +53,9 @@ if(CMAKE_CROSSCOMPILING) endif() if(${TGT_BSP} MATCHES "arm/raspberrypi") - + + set(BSP_PATH "bsp_linux") + else() if(TGT_BSP) diff --git a/fsfwconfig/CMakeLists.txt b/fsfwconfig/CMakeLists.txt new file mode 100644 index 00000000..897789ef --- /dev/null +++ b/fsfwconfig/CMakeLists.txt @@ -0,0 +1,11 @@ +target_sources(${TARGET_NAME} PRIVATE + ipc/MissionMessageTypes.cpp + pollingsequence/PollingSequenceFactory.cpp +) + +target_include_directories(${TARGET_NAME} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + + + From 73cc2ded219c84a3fda607894d6c70fe4ad317bd Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 01:28:21 +0100 Subject: [PATCH 089/360] including taspbery pi bsp --- CMakeLists.txt | 6 ++++++ bsp_rpi/CMakeLists.txt | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 bsp_rpi/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 159779b9..71918df8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,8 @@ else() set(FSFW_CONFIG_PATH "${BSP_PATH}/fsfwconfig") endif() +set(RPI_BSP_PATH "bsp_rpi") + ################################################################################ # Executable and Sources ################################################################################ @@ -65,6 +67,10 @@ if(${OS_FSFW} MATCHES linux) add_subdirectory(${FSFW_CONFIG_PATH}) endif() +if(${TGT_BSP} MATCHES "arm/raspberrypi") + add_subdirectory(${RPI_BSP_PATH}) +endif() + add_subdirectory(${BSP_PATH}) add_subdirectory(${FSFW_PATH}) add_subdirectory(${MISSION_PATH}) diff --git a/bsp_rpi/CMakeLists.txt b/bsp_rpi/CMakeLists.txt new file mode 100644 index 00000000..e2ad16aa --- /dev/null +++ b/bsp_rpi/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(${TARGET_NAME} PUBLIC + +) + + + From a3139c1b52a9369b584ac12b7ca388e41ad165ce Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 01:40:47 +0100 Subject: [PATCH 090/360] added q7s xcompile file --- buildsystem/cmake/HardwareOsPreConfig.cmake | 4 +- buildsystem/cmake/PreProjectConfig.cmake | 7 +- buildsystem/cmake/Q7SCrossCompileConfig.cmake | 81 +++++++++++++++++++ buildsystem/cmake/RPiCrossCompileConfig.cmake | 16 ++-- .../scripts/Q7S/create_cmake_debug_cfg.sh | 27 +++++++ .../scripts/Q7S/create_cmake_release_cfg.sh | 27 +++++++ .../Q7S/create_cmake_relwithdeb_cfg.sh | 27 +++++++ 7 files changed, 178 insertions(+), 11 deletions(-) create mode 100644 buildsystem/cmake/Q7SCrossCompileConfig.cmake create mode 100644 buildsystem/cmake/scripts/Q7S/create_cmake_debug_cfg.sh create mode 100644 buildsystem/cmake/scripts/Q7S/create_cmake_release_cfg.sh create mode 100644 buildsystem/cmake/scripts/Q7S/create_cmake_relwithdeb_cfg.sh diff --git a/buildsystem/cmake/HardwareOsPreConfig.cmake b/buildsystem/cmake/HardwareOsPreConfig.cmake index 39e52168..32080176 100644 --- a/buildsystem/cmake/HardwareOsPreConfig.cmake +++ b/buildsystem/cmake/HardwareOsPreConfig.cmake @@ -48,11 +48,11 @@ if(CMAKE_CROSSCOMPILING) set_property(CACHE TGT_BSP PROPERTY STRINGS - "arm/raspberrypi" + "arm/q7s" "arm/raspberrypi" ) endif() -if(${TGT_BSP} MATCHES "arm/raspberrypi") +if(${TGT_BSP} MATCHES "arm/raspberrypi" OR ${TGT_BSP} MATCHES "arm/q7s") set(BSP_PATH "bsp_linux") diff --git a/buildsystem/cmake/PreProjectConfig.cmake b/buildsystem/cmake/PreProjectConfig.cmake index cc9fe00a..ce18d89d 100644 --- a/buildsystem/cmake/PreProjectConfig.cmake +++ b/buildsystem/cmake/PreProjectConfig.cmake @@ -12,7 +12,12 @@ endif() # Disable compiler checks for cross-compiling. if(${OS_FSFW} STREQUAL linux AND TGT_BSP) - if(${TGT_BSP} MATCHES "arm/raspberrypi") + if(${TGT_BSP} MATCHES "arm/q7s") + set(CMAKE_TOOLCHAIN_FILE + "${CMAKE_SCRIPT_PATH}/Q7SCrossCompileConfig.cmake" + PARENT_SCOPE + ) + elseif (${TGT_BSP} MATCHES "arm/raspberrypi") if(NOT DEFINED ENV{RASPBIAN_ROOTFS}) if(NOT RASPBIAN_ROOTFS) set(ENV{RASPBIAN_ROOTFS} "$ENV{HOME}/raspberrypi/rootfs") diff --git a/buildsystem/cmake/Q7SCrossCompileConfig.cmake b/buildsystem/cmake/Q7SCrossCompileConfig.cmake new file mode 100644 index 00000000..665869f9 --- /dev/null +++ b/buildsystem/cmake/Q7SCrossCompileConfig.cmake @@ -0,0 +1,81 @@ +# CROSS_COMPILE also needs to be set accordingly or passed to the CMake command + +#if(NOT DEFINED ENV{Q7S_ROOTFS}) +# message(FATAL_ERROR +# "Define the Q7S_ROOTFS variable to " +# "point to the raspbian rootfs." +# ) +#else() +# set(SYSROOT_PATH "$ENV{Q7S_ROOTFS}") +#endif() + +if(NOT DEFINED ENV{CROSS_COMPILE}) + set(CROSS_COMPILE "arm-linux-gnueabihf") + message(STATUS + "No CROSS_COMPILE environmental variable set, using default ARM linux " + "cross compiler name ${CROSS_COMPILE}" + ) +else() + set(CROSS_COMPILE "$ENV{CROSS_COMPILE}") + message(STATUS + "Using environmental variable CROSS_COMPILE as cross-compiler: " + "$ENV{CROSS_COMPILE}" + ) +endif() + +# message(STATUS "Using sysroot path: ${SYSROOT_PATH}") + +set(CROSS_COMPILE_CC "${CROSS_COMPILE}-gcc") +set(CROSS_COMPILE_CXX "${CROSS_COMPILE}-g++") +set(CROSS_COMPILE_LD "${CROSS_COMPILE}-ld") +set(CROSS_COMPILE_AR "${CROSS_COMPILE}-ar") +set(CROSS_COMPILE_RANLIB "${CROSS_COMPILE}-ranlib") +set(CROSS_COMPILE_STRIP "${CROSS_COMPILE}-strip") +set(CROSS_COMPILE_NM "${CROSS_COMPILE}-nm") +set(CROSS_COMPILE_OBJCOPY "${CROSS_COMPILE}-objcopy") +set(CROSS_COMPILE_SIZE "${CROSS_COMPILE}-size") + +# At the very least, cross compile gcc and g++ have to be set! +find_program (CROSS_COMPILE_CC_FOUND ${CROSS_COMPILE_CC} REQUIRED) +find_program (CROSS_COMPILE_CXX_FOUND ${CROSS_COMPILE_CXX} REQUIRED) + +set(CMAKE_CROSSCOMPILING TRUE) +# set(CMAKE_SYSROOT "${SYSROOT_PATH}") + +# Define name of the target system +set(CMAKE_SYSTEM_NAME "Linux") +set(CMAKE_SYSTEM_PROCESSOR "armv7") + +# Define the compiler +set(CMAKE_C_COMPILER ${CROSS_COMPILE_CC}) +set(CMAKE_CXX_COMPILER ${CROSS_COMPILE_CXX}) + +# List of library dirs where LD has to look. Pass them directly through gcc. +set(LIB_DIRS +) +# You can additionally check the linker paths if you add the +# flags ' -Xlinker --verbose' +foreach(LIB ${LIB_DIRS}) + set(COMMON_FLAGS "${COMMON_FLAGS} -L${LIB} -Wl,-rpath-link,${LIB}") +endforeach() + +set(CMAKE_PREFIX_PATH + "${CMAKE_PREFIX_PATH}" + # "${SYSROOT_PATH}/usr/lib/${CROSS_COMPILE}" +) + +set(CMAKE_C_FLAGS + "-mcpu=cortex-a9 -mfpu=neon-vfpv3 -mfloat-abi=hard ${COMMON_FLAGS}" + CACHE STRING "C flags for Q7S" +) +set(CMAKE_CXX_FLAGS + "${CMAKE_C_FLAGS}" + CACHE STRING "CPP flags for Q7S" +) + +# search for programs in the build host directories +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +# for libraries and headers in the target directories +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/buildsystem/cmake/RPiCrossCompileConfig.cmake b/buildsystem/cmake/RPiCrossCompileConfig.cmake index 26ca5781..e1b4cce3 100644 --- a/buildsystem/cmake/RPiCrossCompileConfig.cmake +++ b/buildsystem/cmake/RPiCrossCompileConfig.cmake @@ -101,35 +101,35 @@ set(CMAKE_PREFIX_PATH if(RASPBERRY_VERSION VERSION_GREATER 3) set(CMAKE_C_FLAGS "-mcpu=cortex-a72 -mfpu=neon-vfpv4 -mfloat-abi=hard ${COMMON_FLAGS}" - CACHE STRING "Flags for Raspberry PI 4" + CACHE STRING "CPP flags for Raspberry PI 4" ) set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}" - CACHE STRING "Flags for Raspberry PI 4" + CACHE STRING "C flags for Raspberry PI 4" ) elseif(RASPBERRY_VERSION VERSION_GREATER 2) set(CMAKE_C_FLAGS "-mcpu=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard ${COMMON_FLAGS}" - CACHE STRING "Flags for Raspberry PI 3" + CACHE STRING "C flags for Raspberry PI 3" ) set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}" - CACHE STRING "Flags for Raspberry PI 3" + CACHE STRING "CPP flags for Raspberry PI 3" ) elseif(RASPBERRY_VERSION VERSION_GREATER 1) set(CMAKE_C_FLAGS "-mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard ${COMMON_FLAGS}" - CACHE STRING "Flags for Raspberry PI 2" + CACHE STRING "C flags for Raspberry PI 2" ) set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}" - CACHE STRING "Flags for Raspberry PI 2" + CACHE STRING "CPP flags for Raspberry PI 2" ) else() set(CMAKE_C_FLAGS "-mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard ${COMMON_FLAGS}" - CACHE STRING "Flags for Raspberry PI 1 B+ Zero" + CACHE STRING "C flags for Raspberry PI 1 B+ Zero" ) set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}" - CACHE STRING "Flags for Raspberry PI 1 B+ Zero" + CACHE STRING "CPP flags for Raspberry PI 1 B+ Zero" ) endif() diff --git a/buildsystem/cmake/scripts/Q7S/create_cmake_debug_cfg.sh b/buildsystem/cmake/scripts/Q7S/create_cmake_debug_cfg.sh new file mode 100644 index 00000000..7f6753ac --- /dev/null +++ b/buildsystem/cmake/scripts/Q7S/create_cmake_debug_cfg.sh @@ -0,0 +1,27 @@ +#!/bin/sh +counter=0 +while [ ${counter} -lt 5 ] +do + cd .. + if [ -f "cmake_build_config.py" ];then + break + fi + counter=$((counter=counter + 1)) +done + +if [ "${counter}" -ge 5 ];then + echo "cmake_build_config.py not found in upper directories!" + exit 1 +fi + +os_fsfw="linux" +tgt_bsp="arm/q7s" +build_generator="" +if [ "${OS}" = "Windows_NT" ]; then + build_generator="MinGW Makefiles" +# Could be other OS but this works for now. +else + build_generator="Unix Makefiles" +fi + +python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "debug" -t "${tgt_bsp}" diff --git a/buildsystem/cmake/scripts/Q7S/create_cmake_release_cfg.sh b/buildsystem/cmake/scripts/Q7S/create_cmake_release_cfg.sh new file mode 100644 index 00000000..6048a1c6 --- /dev/null +++ b/buildsystem/cmake/scripts/Q7S/create_cmake_release_cfg.sh @@ -0,0 +1,27 @@ +#!/bin/sh +counter=0 +while [ ${counter} -lt 5 ] +do + cd .. + if [ -f "cmake_build_config.py" ];then + break + fi + counter=$((counter=counter + 1)) +done + +if [ "${counter}" -ge 5 ];then + echo "cmake_build_config.py not found in upper directories!" + exit 1 +fi + +os_fsfw="linux" +tgt_bsp="arm/q7s" +build_generator="" +if [ "${OS}" = "Windows_NT" ]; then + build_generator="MinGW Makefiles" +# Could be other OS but this works for now. +else + build_generator="Unix Makefiles" +fi + +python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "release" -t "${tgt_bsp}" diff --git a/buildsystem/cmake/scripts/Q7S/create_cmake_relwithdeb_cfg.sh b/buildsystem/cmake/scripts/Q7S/create_cmake_relwithdeb_cfg.sh new file mode 100644 index 00000000..346067cd --- /dev/null +++ b/buildsystem/cmake/scripts/Q7S/create_cmake_relwithdeb_cfg.sh @@ -0,0 +1,27 @@ +#!/bin/sh +counter=0 +while [ ${counter} -lt 5 ] +do + cd .. + if [ -f "cmake_build_config.py" ];then + break + fi + counter=$((counter=counter + 1)) +done + +if [ "${counter}" -ge 5 ];then + echo "cmake_build_config.py not found in upper directories!" + exit 1 +fi + +os_fsfw="linux" +tgt_bsp="arm/q7s" +build_generator="" +if [ "${OS}" = "Windows_NT" ]; then + build_generator="MinGW Makefiles" +# Could be other OS but this works for now. +else + build_generator="Unix Makefiles" +fi + +python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "reldeb" -t "${tgt_bsp}" From 1f95ad9b42975a06a19ea2576c4492408732223e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 02:15:04 +0100 Subject: [PATCH 091/360] project name corrected --- CMakeLists.txt | 2 +- misc/eclipse/{ => Host}/eive-linux-host-debug.launch | 0 misc/eclipse/{ => Host}/eive-linux-host-release.launch | 0 misc/eclipse/{ => Host}/eive-mingw-debug.launch | 0 misc/eclipse/{ => Host}/eive-mingw-release.launch | 0 5 files changed, 1 insertion(+), 1 deletion(-) rename misc/eclipse/{ => Host}/eive-linux-host-debug.launch (100%) rename misc/eclipse/{ => Host}/eive-linux-host-release.launch (100%) rename misc/eclipse/{ => Host}/eive-mingw-debug.launch (100%) rename misc/eclipse/{ => Host}/eive-mingw-release.launch (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 71918df8..cd91447c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ include(${CMAKE_SCRIPT_PATH}/PreProjectConfig.cmake) pre_project_config() # Project Name -project(fsfw_example ASM C CXX) +project(eive_obsw ASM C CXX) ################################################################################ # Pre-Sources preparation diff --git a/misc/eclipse/eive-linux-host-debug.launch b/misc/eclipse/Host/eive-linux-host-debug.launch similarity index 100% rename from misc/eclipse/eive-linux-host-debug.launch rename to misc/eclipse/Host/eive-linux-host-debug.launch diff --git a/misc/eclipse/eive-linux-host-release.launch b/misc/eclipse/Host/eive-linux-host-release.launch similarity index 100% rename from misc/eclipse/eive-linux-host-release.launch rename to misc/eclipse/Host/eive-linux-host-release.launch diff --git a/misc/eclipse/eive-mingw-debug.launch b/misc/eclipse/Host/eive-mingw-debug.launch similarity index 100% rename from misc/eclipse/eive-mingw-debug.launch rename to misc/eclipse/Host/eive-mingw-debug.launch diff --git a/misc/eclipse/eive-mingw-release.launch b/misc/eclipse/Host/eive-mingw-release.launch similarity index 100% rename from misc/eclipse/eive-mingw-release.launch rename to misc/eclipse/Host/eive-mingw-release.launch From 892a6f61b347d0193b9421295caa837615236aed Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 02:16:39 +0100 Subject: [PATCH 092/360] correction in factoryx --- bsp_linux/ObjectFactory.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bsp_linux/ObjectFactory.cpp b/bsp_linux/ObjectFactory.cpp index a0f82887..4300fbeb 100644 --- a/bsp_linux/ObjectFactory.cpp +++ b/bsp_linux/ObjectFactory.cpp @@ -1,3 +1,4 @@ +#include #include "ObjectFactory.h" #include @@ -25,6 +26,8 @@ void Factory::setStaticFrameworkObjectIds() { // No storage object for now. TmFunnel::storageDestination = objects::NO_OBJECT; + LocalDataPoolManager::defaultHkDestination = objects::NO_OBJECT; + VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION; TmPacketStored::timeStamperId = objects::TIME_STAMPER; } From 944ea763820f6bae91a84dc1cddac71d8773ce54 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 12:15:55 +0100 Subject: [PATCH 093/360] fsfw points to devel now --- fsfw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsfw b/fsfw index 5b9c0e01..dcc111e4 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 5b9c0e013e35ab1353d402c6fa2cd75866e3afa5 +Subproject commit dcc111e4facf39137fe52d8234361b7d99bdde06 From 407078054361a8e833c5ea0ffe917d4a321fc8b2 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 12:16:38 +0100 Subject: [PATCH 094/360] fsfw update --- fsfw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsfw b/fsfw index dcc111e4..426514b9 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit dcc111e4facf39137fe52d8234361b7d99bdde06 +Subproject commit 426514b9a29274f46ea3723c8ef17c989c70bdac From 12785da87e0d9e54e3880fce4004b44a9404167a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 12:22:35 +0100 Subject: [PATCH 095/360] small bugfix --- buildsystem/cmake/HardwareOsPreConfig.cmake | 11 ++++------- fsfw | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/buildsystem/cmake/HardwareOsPreConfig.cmake b/buildsystem/cmake/HardwareOsPreConfig.cmake index 32080176..b8a11f97 100644 --- a/buildsystem/cmake/HardwareOsPreConfig.cmake +++ b/buildsystem/cmake/HardwareOsPreConfig.cmake @@ -52,17 +52,14 @@ if(CMAKE_CROSSCOMPILING) ) endif() -if(${TGT_BSP} MATCHES "arm/raspberrypi" OR ${TGT_BSP} MATCHES "arm/q7s") - - set(BSP_PATH "bsp_linux") - -else() - if(TGT_BSP) +if(TGT_BSP) + if (${TGT_BSP} MATCHES "arm/raspberrypi" OR ${TGT_BSP} MATCHES "arm/q7s") + # set(BSP_PATH "bsp_linux") + else() message(WARNING "CMake not configured for this target!") message(FATAL_ERROR "Target: ${TGT_BSP}!") endif() - endif() set(BSP_PATH ${BSP_PATH} PARENT_SCOPE) diff --git a/fsfw b/fsfw index 426514b9..5b9c0e01 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 426514b9a29274f46ea3723c8ef17c989c70bdac +Subproject commit 5b9c0e013e35ab1353d402c6fa2cd75866e3afa5 From d8185c0611f89db24d57f0ee04d05a2e5312c053 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 13:59:31 +0100 Subject: [PATCH 096/360] added cmake support for csp lib --- CMakeLists.txt | 22 ++- Makefile | 2 +- bsp_hosted/InitMission.cpp | 5 +- {bsp_linux => bsp_q7s}/CMakeLists.txt | 0 {bsp_linux => bsp_q7s}/InitMission.cpp | 11 +- bsp_q7s/InitMission.h | 9 + bsp_q7s/ObjectFactory.cpp | 77 +++++++++ bsp_q7s/ObjectFactory.h | 10 ++ .../boardconfig/CMakeLists.txt | 0 .../boardconfig/etl_profile.h | 0 {bsp_linux => bsp_q7s}/boardconfig/gcov.h | 0 {bsp_linux => bsp_q7s}/boardconfig/print.c | 2 +- {bsp_linux => bsp_q7s}/boardconfig/print.h | 0 bsp_linux/bsp_linux.mk => bsp_q7s/bsp_q7s.mk | 0 {bsp_linux => bsp_q7s}/comIF/CspComIF.cpp | 3 +- {bsp_linux => bsp_q7s}/comIF/CspComIF.h | 0 .../comIF/cookies/CspCookie.cpp | 0 .../comIF/cookies/CspCookie.h | 8 +- bsp_q7s/main.cpp | 29 ++++ bsp_rpi/CMakeLists.txt | 7 +- bsp_rpi/InitMission.cpp | 158 ++++++++++++++++++ {bsp_linux => bsp_rpi}/InitMission.h | 0 {bsp_linux => bsp_rpi}/ObjectFactory.cpp | 0 {bsp_linux => bsp_rpi}/ObjectFactory.h | 0 bsp_rpi/boardconfig/CMakeLists.txt | 10 ++ bsp_rpi/boardconfig/etl_profile.h | 38 +++++ bsp_rpi/boardconfig/gcov.h | 14 ++ bsp_rpi/boardconfig/print.c | 14 ++ bsp_rpi/boardconfig/print.h | 8 + {bsp_linux => bsp_rpi}/main.cpp | 0 buildsystem/cmake/HardwareOsPreConfig.cmake | 7 +- libcsp/CMakeLists.txt | 12 ++ libcsp/include/CMakeLists.txt | 7 + libcsp/src/CMakeLists.txt | 25 +++ libcsp/src/arch/posix/CMakeLists.txt | 9 + libcsp/src/crypto/CMakeLists.txt | 5 + libcsp/src/drivers/CMakeLists.txt | 1 + libcsp/src/drivers/can/CMakeLists.txt | 3 + libcsp/src/interfaces/CMakeLists.txt | 7 + libcsp/src/rtable/CMakeLists.txt | 3 + libcsp/src/transport/CMakeLists.txt | 4 + mission/core/GenericFactory.cpp | 47 +----- 42 files changed, 490 insertions(+), 67 deletions(-) rename {bsp_linux => bsp_q7s}/CMakeLists.txt (100%) rename {bsp_linux => bsp_q7s}/InitMission.cpp (96%) create mode 100644 bsp_q7s/InitMission.h create mode 100644 bsp_q7s/ObjectFactory.cpp create mode 100644 bsp_q7s/ObjectFactory.h rename {bsp_linux => bsp_q7s}/boardconfig/CMakeLists.txt (100%) rename {bsp_linux => bsp_q7s}/boardconfig/etl_profile.h (100%) rename {bsp_linux => bsp_q7s}/boardconfig/gcov.h (100%) rename {bsp_linux => bsp_q7s}/boardconfig/print.c (81%) rename {bsp_linux => bsp_q7s}/boardconfig/print.h (100%) rename bsp_linux/bsp_linux.mk => bsp_q7s/bsp_q7s.mk (100%) rename {bsp_linux => bsp_q7s}/comIF/CspComIF.cpp (99%) rename {bsp_linux => bsp_q7s}/comIF/CspComIF.h (100%) rename {bsp_linux => bsp_q7s}/comIF/cookies/CspCookie.cpp (100%) rename {bsp_linux => bsp_q7s}/comIF/cookies/CspCookie.h (71%) create mode 100644 bsp_q7s/main.cpp create mode 100644 bsp_rpi/InitMission.cpp rename {bsp_linux => bsp_rpi}/InitMission.h (100%) rename {bsp_linux => bsp_rpi}/ObjectFactory.cpp (100%) rename {bsp_linux => bsp_rpi}/ObjectFactory.h (100%) create mode 100644 bsp_rpi/boardconfig/CMakeLists.txt create mode 100644 bsp_rpi/boardconfig/etl_profile.h create mode 100644 bsp_rpi/boardconfig/gcov.h create mode 100644 bsp_rpi/boardconfig/print.c create mode 100644 bsp_rpi/boardconfig/print.h rename {bsp_linux => bsp_rpi}/main.cpp (100%) create mode 100644 libcsp/CMakeLists.txt create mode 100644 libcsp/include/CMakeLists.txt create mode 100644 libcsp/src/CMakeLists.txt create mode 100644 libcsp/src/arch/posix/CMakeLists.txt create mode 100644 libcsp/src/crypto/CMakeLists.txt create mode 100644 libcsp/src/drivers/CMakeLists.txt create mode 100644 libcsp/src/drivers/can/CMakeLists.txt create mode 100644 libcsp/src/interfaces/CMakeLists.txt create mode 100644 libcsp/src/rtable/CMakeLists.txt create mode 100644 libcsp/src/transport/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index cd91447c..9a27a5cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,20 +41,26 @@ set(LIB_FSFW_NAME fsfw) # Set path names set(FSFW_PATH fsfw) set(MISSION_PATH mission) +set(CSPLIB_PATH libcsp) # Analyse different OS and architecture/target options, determine BSP_PATH, # display information about compiler etc. include (${CMAKE_SCRIPT_PATH}/HardwareOsPreConfig.cmake) pre_source_hw_os_config() -if(${OS_FSFW} MATCHES linux) -set(FSFW_CONFIG_PATH "fsfwconfig") +if(TGT_BSP) + if(${TGT_BSP} MATCHES "arm/q7s" OR ${TGT_BSP} MATCHES "arm/raspberrypi") + set(ROOT_CONFIG_FOLDER TRUE) + set(FSFW_CONFIG_PATH "fsfwconfig") + endif() + + if(${TGT_BSP} MATCHES "arm/q7s") + set(ADD_CSP_LIB TRUE) + endif() else() -set(FSFW_CONFIG_PATH "${BSP_PATH}/fsfwconfig") + set(FSFW_CONFIG_PATH "${BSP_PATH}/fsfwconfig") endif() -set(RPI_BSP_PATH "bsp_rpi") - ################################################################################ # Executable and Sources ################################################################################ @@ -63,12 +69,12 @@ set(RPI_BSP_PATH "bsp_rpi") add_executable(${TARGET_NAME}) # Add subdirectories -if(${OS_FSFW} MATCHES linux) +if(ROOT_CONFIG_FOLDER) add_subdirectory(${FSFW_CONFIG_PATH}) endif() -if(${TGT_BSP} MATCHES "arm/raspberrypi") - add_subdirectory(${RPI_BSP_PATH}) +if(ADD_CSP_LIB) + add_subdirectory(${CSPLIB_PATH}) endif() add_subdirectory(${BSP_PATH}) diff --git a/Makefile b/Makefile index 3956d5f1..b1ccd741 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SHELL = /bin/sh # Chip & board used for compilation # (can be overriden by adding CHIP=chip and BOARD=board to the command-line) -BOARD_FILE_ROOT = bsp_linux +BOARD_FILE_ROOT = bsp_q7s BOARD = linux OS_FSFW = linux CUSTOM_DEFINES += -D$(OS_FSFW) diff --git a/bsp_hosted/InitMission.cpp b/bsp_hosted/InitMission.cpp index cfc33db9..d4e58b99 100644 --- a/bsp_hosted/InitMission.cpp +++ b/bsp_hosted/InitMission.cpp @@ -1,6 +1,5 @@ -#include -#include - +#include +#include #include #include #include diff --git a/bsp_linux/CMakeLists.txt b/bsp_q7s/CMakeLists.txt similarity index 100% rename from bsp_linux/CMakeLists.txt rename to bsp_q7s/CMakeLists.txt diff --git a/bsp_linux/InitMission.cpp b/bsp_q7s/InitMission.cpp similarity index 96% rename from bsp_linux/InitMission.cpp rename to bsp_q7s/InitMission.cpp index c50a1d38..94892adf 100644 --- a/bsp_linux/InitMission.cpp +++ b/bsp_q7s/InitMission.cpp @@ -1,5 +1,6 @@ -#include -#include +#include "InitMission.h" +#include "ObjectFactory.h" +#include #include #include @@ -8,8 +9,6 @@ #include #include #include -#include -#include #include #include @@ -144,7 +143,7 @@ void InitMission::initTasks(){ } -#if ADD_TEST_CODE == 1 +#if OBSW_ADD_TEST_CODE == 1 // FixedTimeslotTaskIF* TestTimeslotTask = TaskFactory::instance()-> // createFixedTimeslotTask("PST_TEST_TASK", 10, // PeriodicTaskIF::MINIMUM_STACK_SIZE, 1.0, nullptr); @@ -172,7 +171,7 @@ void InitMission::initTasks(){ // P60DockTask->startTask(); -#if ADD_TEST_CODE == 1 +#if OBSW_ADD_TEST_CODE == 1 // TestTimeslotTask->startTask(); #endif sif::info << "Tasks started.." << std::endl; diff --git a/bsp_q7s/InitMission.h b/bsp_q7s/InitMission.h new file mode 100644 index 00000000..89d65ada --- /dev/null +++ b/bsp_q7s/InitMission.h @@ -0,0 +1,9 @@ +#ifndef BSP_Q7S_INITMISSION_H_ +#define BSP_Q7S_INITMISSION_H_ + +namespace InitMission { +void initMission(); +void initTasks(); +}; + +#endif /* BSP_Q7S_INITMISSION_H_ */ diff --git a/bsp_q7s/ObjectFactory.cpp b/bsp_q7s/ObjectFactory.cpp new file mode 100644 index 00000000..86c0f068 --- /dev/null +++ b/bsp_q7s/ObjectFactory.cpp @@ -0,0 +1,77 @@ +#include "ObjectFactory.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +void Factory::setStaticFrameworkObjectIds() { + PusServiceBase::packetSource = objects::PUS_PACKET_DISTRIBUTOR; + PusServiceBase::packetDestination = objects::TM_FUNNEL; + + CommandingServiceBase::defaultPacketSource = objects::PUS_PACKET_DISTRIBUTOR; + CommandingServiceBase::defaultPacketDestination = objects::TM_FUNNEL; + + TmFunnel::downlinkDestination = objects::UDP_BRIDGE; + // No storage object for now. + TmFunnel::storageDestination = objects::NO_OBJECT; + + LocalDataPoolManager::defaultHkDestination = objects::NO_OBJECT; + + VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION; + TmPacketStored::timeStamperId = objects::TIME_STAMPER; +} + + + +void ObjectFactory::produce(){ + Factory::setStaticFrameworkObjectIds(); + ObjectFactory::produceGenericObjects(); + + /* Cookies */ + CspCookie* p60DockCspCookie = new CspCookie(P60Dock::MAX_REPLY_LENGTH, + addresses::P60DOCK); + CspCookie* pdu1CspCookie = new CspCookie(PDU::MAX_REPLY_LENGTH, + addresses::PDU1); + CspCookie* pdu2CspCookie = new CspCookie(PDU::MAX_REPLY_LENGTH, + addresses::PDU2); + CspCookie* acuCspCookie = new CspCookie(ACU::MAX_REPLY_LENGTH, + addresses::ACU); + + /* Communication interfaces */ + new CspComIF(objects::CSP_COM_IF); + + /* Device Handler */ + new GomspaceDeviceHandler(objects::P60DOCK_HANDLER, objects::CSP_COM_IF, + p60DockCspCookie, P60Dock::MAX_CONFIGTABLE_ADDRESS, + P60Dock::MAX_HKTABLE_ADDRESS); + new GomspaceDeviceHandler(objects::PDU1_HANDLER, objects::CSP_COM_IF, + pdu1CspCookie, PDU::MAX_CONFIGTABLE_ADDRESS, + PDU::MAX_HKTABLE_ADDRESS); + new GomspaceDeviceHandler(objects::PDU2_HANDLER, objects::CSP_COM_IF, + pdu2CspCookie, PDU::MAX_CONFIGTABLE_ADDRESS, + PDU::MAX_HKTABLE_ADDRESS); + new GomspaceDeviceHandler(objects::ACU_HANDLER, objects::CSP_COM_IF, + acuCspCookie, ACU::MAX_CONFIGTABLE_ADDRESS, + ACU::MAX_HKTABLE_ADDRESS); + + new TmTcUnixUdpBridge(objects::UDP_BRIDGE, + objects::CCSDS_PACKET_DISTRIBUTOR, + objects::TM_STORE, objects::TC_STORE); + new TcUnixUdpPollingTask(objects::UDP_POLLING_TASK, objects::UDP_BRIDGE); +} diff --git a/bsp_q7s/ObjectFactory.h b/bsp_q7s/ObjectFactory.h new file mode 100644 index 00000000..5e3358ae --- /dev/null +++ b/bsp_q7s/ObjectFactory.h @@ -0,0 +1,10 @@ +#ifndef BSP_Q7S_OBJECTFACTORY_H_ +#define BSP_Q7S_OBJECTFACTORY_H_ + + +namespace ObjectFactory { + void setStatics(); + void produce(); +}; + +#endif /* BSP_Q7S_OBJECTFACTORY_H_ */ diff --git a/bsp_linux/boardconfig/CMakeLists.txt b/bsp_q7s/boardconfig/CMakeLists.txt similarity index 100% rename from bsp_linux/boardconfig/CMakeLists.txt rename to bsp_q7s/boardconfig/CMakeLists.txt diff --git a/bsp_linux/boardconfig/etl_profile.h b/bsp_q7s/boardconfig/etl_profile.h similarity index 100% rename from bsp_linux/boardconfig/etl_profile.h rename to bsp_q7s/boardconfig/etl_profile.h diff --git a/bsp_linux/boardconfig/gcov.h b/bsp_q7s/boardconfig/gcov.h similarity index 100% rename from bsp_linux/boardconfig/gcov.h rename to bsp_q7s/boardconfig/gcov.h diff --git a/bsp_linux/boardconfig/print.c b/bsp_q7s/boardconfig/print.c similarity index 81% rename from bsp_linux/boardconfig/print.c rename to bsp_q7s/boardconfig/print.c index f409ee1b..c501e0b7 100644 --- a/bsp_linux/boardconfig/print.c +++ b/bsp_q7s/boardconfig/print.c @@ -1,4 +1,4 @@ -#include "print.h" +#include #include void printChar(const char* character, bool errStream) { diff --git a/bsp_linux/boardconfig/print.h b/bsp_q7s/boardconfig/print.h similarity index 100% rename from bsp_linux/boardconfig/print.h rename to bsp_q7s/boardconfig/print.h diff --git a/bsp_linux/bsp_linux.mk b/bsp_q7s/bsp_q7s.mk similarity index 100% rename from bsp_linux/bsp_linux.mk rename to bsp_q7s/bsp_q7s.mk diff --git a/bsp_linux/comIF/CspComIF.cpp b/bsp_q7s/comIF/CspComIF.cpp similarity index 99% rename from bsp_linux/comIF/CspComIF.cpp rename to bsp_q7s/comIF/CspComIF.cpp index 83be2864..cf72be94 100644 --- a/bsp_linux/comIF/CspComIF.cpp +++ b/bsp_q7s/comIF/CspComIF.cpp @@ -1,5 +1,6 @@ #include "CspComIF.h" -#include +#include "cookies/CspCookie.h" + #include #include #include diff --git a/bsp_linux/comIF/CspComIF.h b/bsp_q7s/comIF/CspComIF.h similarity index 100% rename from bsp_linux/comIF/CspComIF.h rename to bsp_q7s/comIF/CspComIF.h diff --git a/bsp_linux/comIF/cookies/CspCookie.cpp b/bsp_q7s/comIF/cookies/CspCookie.cpp similarity index 100% rename from bsp_linux/comIF/cookies/CspCookie.cpp rename to bsp_q7s/comIF/cookies/CspCookie.cpp diff --git a/bsp_linux/comIF/cookies/CspCookie.h b/bsp_q7s/comIF/cookies/CspCookie.h similarity index 71% rename from bsp_linux/comIF/cookies/CspCookie.h rename to bsp_q7s/comIF/cookies/CspCookie.h index 128926e5..e877761d 100644 --- a/bsp_linux/comIF/cookies/CspCookie.h +++ b/bsp_q7s/comIF/cookies/CspCookie.h @@ -1,8 +1,8 @@ -#ifndef BSP_LINUX_COMIF_COOKIES_CSPCOOKIE_H_ -#define BSP_LINUX_COMIF_COOKIES_CSPCOOKIE_H_ +#ifndef BSP_Q7S_COMIF_COOKIES_CSPCOOKIE_H_ +#define BSP_Q7S_COMIF_COOKIES_CSPCOOKIE_H_ #include -#include +#include /** * @brief This is the cookie for devices supporting the CSP (CubeSat Space @@ -24,4 +24,4 @@ private: uint8_t cspAddress; }; -#endif /* BSP_LINUX_COMIF_COOKIES_CSPCOOKIE_H_ */ +#endif /* BSP_Q7S_COMIF_COOKIES_CSPCOOKIE_H_ */ diff --git a/bsp_q7s/main.cpp b/bsp_q7s/main.cpp new file mode 100644 index 00000000..49416ae2 --- /dev/null +++ b/bsp_q7s/main.cpp @@ -0,0 +1,29 @@ +#include "InitMission.h" +#include +#include + +#include + +#include + +/** + * @brief This is the main program for the target hardware. + * @return + */ +int main(void) +{ + std::cout << "-- EIVE OBSW --" << std::endl; + std::cout << "-- Compiled for Linux " << " --" << std::endl; + std::cout << "-- Software version " << SW_NAME << " v" << SW_VERSION << "." + << SW_SUBVERSION << "." << SW_SUBSUBVERSION << " -- " << std::endl; + std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl; + + InitMission::initMission(); + + for(;;) { + // suspend main thread by sleeping it. + TaskFactory::delayTask(5000); + } +} + + diff --git a/bsp_rpi/CMakeLists.txt b/bsp_rpi/CMakeLists.txt index e2ad16aa..8dd8e6f1 100644 --- a/bsp_rpi/CMakeLists.txt +++ b/bsp_rpi/CMakeLists.txt @@ -1,6 +1,11 @@ target_sources(${TARGET_NAME} PUBLIC - + InitMission.cpp + main.cpp + ObjectFactory.cpp ) +add_subdirectory(boardconfig) + + diff --git a/bsp_rpi/InitMission.cpp b/bsp_rpi/InitMission.cpp new file mode 100644 index 00000000..76918716 --- /dev/null +++ b/bsp_rpi/InitMission.cpp @@ -0,0 +1,158 @@ +#include "InitMission.h" +#include "ObjectFactory.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// This is configured for linux without \cr +#ifdef LINUX +ServiceInterfaceStream sif::debug("DEBUG"); +ServiceInterfaceStream sif::info("INFO"); +ServiceInterfaceStream sif::warning("WARNING"); +ServiceInterfaceStream sif::error("ERROR", false, false, true); +#else +ServiceInterfaceStream sif::debug("DEBUG", true); +ServiceInterfaceStream sif::info("INFO", true); +ServiceInterfaceStream sif::warning("WARNING", true); +ServiceInterfaceStream sif::error("ERROR", true, false, true); +#endif + +ObjectManagerIF *objectManager = nullptr; + +void InitMission::initMission() { + sif::info << "Building global objects.." << std::endl; + /* Instantiate global object manager and also create all objects */ + objectManager = new ObjectManager(ObjectFactory::produce); + sif::info << "Initializing all objects.." << std::endl; + objectManager->initialize(); + + /* This function creates and starts all tasks */ + initTasks(); +} + +void InitMission::initTasks(){ + /* TMTC Distribution */ + PeriodicTaskIF* TmTcDistributor = TaskFactory::instance()-> + createPeriodicTask("DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, + 0.100, nullptr); + ReturnValue_t result = TmTcDistributor->addComponent( + objects::CCSDS_PACKET_DISTRIBUTOR); + if(result!=HasReturnvaluesIF::RETURN_OK){ + sif::error << "Object add component failed" << std::endl; + } + result = TmTcDistributor->addComponent(objects::PUS_PACKET_DISTRIBUTOR); + if(result!=HasReturnvaluesIF::RETURN_OK){ + sif::error << "Object add component failed" << std::endl; + } + result = TmTcDistributor->addComponent(objects::TM_FUNNEL); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "Object add component failed" << std::endl; + } + + /* UDP bridge */ + PeriodicTaskIF* UdpBridgeTask = TaskFactory::instance()->createPeriodicTask( + "UDP_UNIX_BRIDGE", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, + 0.2, nullptr); + result = UdpBridgeTask->addComponent(objects::UDP_BRIDGE); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "Add component UDP Unix Bridge failed" << std::endl; + } + PeriodicTaskIF* UdpPollingTask = TaskFactory::instance()-> + createPeriodicTask("UDP_POLLING", 80, + PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, nullptr); + result = UdpPollingTask->addComponent(objects::UDP_POLLING_TASK); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "Add component UDP Polling failed" << std::endl; + } + + /* PUS Services */ + PeriodicTaskIF* PusVerification = TaskFactory::instance()-> + createPeriodicTask("PUS_VERIF_1", 40, + PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, nullptr); + result = PusVerification->addComponent(objects::PUS_SERVICE_1_VERIFICATION); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "Object add component failed" << std::endl; + } + + PeriodicTaskIF* PusEvents = TaskFactory::instance()-> + createPeriodicTask("PUS_VERIF_1", 60, + PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, nullptr); + result = PusVerification->addComponent(objects::PUS_SERVICE_5_EVENT_REPORTING); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "Object add component failed" << std::endl; + } + + PeriodicTaskIF* PusHighPrio = TaskFactory::instance()-> + createPeriodicTask("PUS_HIGH_PRIO", 50, + PeriodicTaskIF::MINIMUM_STACK_SIZE, + 0.200, nullptr); + result = PusHighPrio->addComponent(objects::PUS_SERVICE_2_DEVICE_ACCESS); + if(result!=HasReturnvaluesIF::RETURN_OK){ + sif::error << "Object add component failed" << std::endl; + } + result = PusHighPrio->addComponent(objects::PUS_SERVICE_9_TIME_MGMT); + if(result!=HasReturnvaluesIF::RETURN_OK){ + sif::error << "Object add component failed" << std::endl; + } + + PeriodicTaskIF* PusMedPrio = TaskFactory::instance()-> + createPeriodicTask("PUS_HIGH_PRIO", 40, + PeriodicTaskIF::MINIMUM_STACK_SIZE, + 0.8, nullptr); + result = PusMedPrio->addComponent(objects::PUS_SERVICE_8_FUNCTION_MGMT); + if(result!=HasReturnvaluesIF::RETURN_OK){ + sif::error << "Object add component failed" << std::endl; + } + result = PusMedPrio->addComponent(objects::PUS_SERVICE_200_MODE_MGMT); + if(result!=HasReturnvaluesIF::RETURN_OK){ + sif::error << "Object add component failed" << std::endl; + } + + PeriodicTaskIF* PusLowPrio = TaskFactory::instance()-> + createPeriodicTask("PUSB", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE, + 1.6, nullptr); + result = PusLowPrio->addComponent(objects::PUS_SERVICE_17_TEST); + if(result!=HasReturnvaluesIF::RETURN_OK){ + sif::error << "Object add component failed" << std::endl; + } + + +#if OBSW_ADD_TEST_CODE == 1 + FixedTimeslotTaskIF* TestTimeslotTask = TaskFactory::instance()-> + createFixedTimeslotTask("PST_TEST_TASK", 10, + PeriodicTaskIF::MINIMUM_STACK_SIZE, 1.0, nullptr); + result = pst::pollingSequenceTestFunction(TestTimeslotTask); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "InitMission::createTasks: Test PST initialization " + << "failed!" << std::endl; + } + +#endif + + //Main thread sleep + sif::info << "Starting tasks.." << std::endl; + TmTcDistributor->startTask(); + UdpBridgeTask->startTask(); + UdpPollingTask->startTask(); + + PusVerification->startTask(); + PusEvents->startTask(); + PusHighPrio->startTask(); + PusMedPrio->startTask(); + PusLowPrio->startTask(); + +#if OBSW_ADD_TEST_CODE == 1 + TestTimeslotTask->startTask(); +#endif + sif::info << "Tasks started.." << std::endl; +} diff --git a/bsp_linux/InitMission.h b/bsp_rpi/InitMission.h similarity index 100% rename from bsp_linux/InitMission.h rename to bsp_rpi/InitMission.h diff --git a/bsp_linux/ObjectFactory.cpp b/bsp_rpi/ObjectFactory.cpp similarity index 100% rename from bsp_linux/ObjectFactory.cpp rename to bsp_rpi/ObjectFactory.cpp diff --git a/bsp_linux/ObjectFactory.h b/bsp_rpi/ObjectFactory.h similarity index 100% rename from bsp_linux/ObjectFactory.h rename to bsp_rpi/ObjectFactory.h diff --git a/bsp_rpi/boardconfig/CMakeLists.txt b/bsp_rpi/boardconfig/CMakeLists.txt new file mode 100644 index 00000000..c32b326d --- /dev/null +++ b/bsp_rpi/boardconfig/CMakeLists.txt @@ -0,0 +1,10 @@ +target_sources(${TARGET_NAME} PRIVATE + print.c +) + +target_include_directories(${TARGET_NAME} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + + + diff --git a/bsp_rpi/boardconfig/etl_profile.h b/bsp_rpi/boardconfig/etl_profile.h new file mode 100644 index 00000000..c35ffb46 --- /dev/null +++ b/bsp_rpi/boardconfig/etl_profile.h @@ -0,0 +1,38 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2019 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ +#ifndef __ETL_PROFILE_H__ +#define __ETL_PROFILE_H__ + +#define ETL_CHECK_PUSH_POP + +#define ETL_CPP11_SUPPORTED 1 +#define ETL_NO_NULLPTR_SUPPORT 0 + +#endif diff --git a/bsp_rpi/boardconfig/gcov.h b/bsp_rpi/boardconfig/gcov.h new file mode 100644 index 00000000..491d24c6 --- /dev/null +++ b/bsp_rpi/boardconfig/gcov.h @@ -0,0 +1,14 @@ +#ifndef LINUX_GCOV_H_ +#define LINUX_GCOV_H_ +#include + +#ifdef GCOV +extern "C" void __gcov_flush(); +#else +void __gcov_flush() { + sif::info << "GCC GCOV: Please supply GCOV=1 in Makefile if " + "coverage information is desired.\n" << std::flush; +} +#endif + +#endif /* LINUX_GCOV_H_ */ diff --git a/bsp_rpi/boardconfig/print.c b/bsp_rpi/boardconfig/print.c new file mode 100644 index 00000000..c501e0b7 --- /dev/null +++ b/bsp_rpi/boardconfig/print.c @@ -0,0 +1,14 @@ +#include +#include + +void printChar(const char* character, bool errStream) { + if(errStream) { + putc(*character, stderr); + return; + } + putc(*character, stdout); +} + + + + diff --git a/bsp_rpi/boardconfig/print.h b/bsp_rpi/boardconfig/print.h new file mode 100644 index 00000000..8e7e2e5d --- /dev/null +++ b/bsp_rpi/boardconfig/print.h @@ -0,0 +1,8 @@ +#ifndef HOSTED_BOARDCONFIG_PRINT_H_ +#define HOSTED_BOARDCONFIG_PRINT_H_ + +#include + +void printChar(const char* character, bool errStream); + +#endif /* HOSTED_BOARDCONFIG_PRINT_H_ */ diff --git a/bsp_linux/main.cpp b/bsp_rpi/main.cpp similarity index 100% rename from bsp_linux/main.cpp rename to bsp_rpi/main.cpp diff --git a/buildsystem/cmake/HardwareOsPreConfig.cmake b/buildsystem/cmake/HardwareOsPreConfig.cmake index b8a11f97..4ead6540 100644 --- a/buildsystem/cmake/HardwareOsPreConfig.cmake +++ b/buildsystem/cmake/HardwareOsPreConfig.cmake @@ -10,7 +10,6 @@ elseif(${OS_FSFW} STREQUAL rtems) elseif(${OS_FSFW} STREQUAL linux) add_definitions(-DUNIX -DLINUX) find_package(Threads REQUIRED) - set(BSP_PATH "bsp_linux") # Hosted else() set(BSP_PATH "bsp_hosted") @@ -54,8 +53,10 @@ endif() if(TGT_BSP) - if (${TGT_BSP} MATCHES "arm/raspberrypi" OR ${TGT_BSP} MATCHES "arm/q7s") - # set(BSP_PATH "bsp_linux") + if (${TGT_BSP} MATCHES "arm/raspberrypi") + set(BSP_PATH "bsp_rpi") + elseif(${TGT_BSP} MATCHES "arm/q7s") + set(BSP_PATH "bsp_q7s") else() message(WARNING "CMake not configured for this target!") message(FATAL_ERROR "Target: ${TGT_BSP}!") diff --git a/libcsp/CMakeLists.txt b/libcsp/CMakeLists.txt new file mode 100644 index 00000000..5c9f7677 --- /dev/null +++ b/libcsp/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.13) + +set(LIB_CSP_NAME libcsp) + +add_library(${LIB_CSP_NAME}) + +add_subdirectory(src) +add_subdirectory(include) + +target_include_directories(${LIB_CSP_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) \ No newline at end of file diff --git a/libcsp/include/CMakeLists.txt b/libcsp/include/CMakeLists.txt new file mode 100644 index 00000000..94fee196 --- /dev/null +++ b/libcsp/include/CMakeLists.txt @@ -0,0 +1,7 @@ +target_include_directories(${LIB_CSP_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/csp + ${CMAKE_CURRENT_SOURCE_DIR}/csp/crypto +) + + diff --git a/libcsp/src/CMakeLists.txt b/libcsp/src/CMakeLists.txt new file mode 100644 index 00000000..5d1bfbf5 --- /dev/null +++ b/libcsp/src/CMakeLists.txt @@ -0,0 +1,25 @@ +target_sources(${LIB_CSP_NAME} PRIVATE + csp_bridge.c + csp_buffer.c + csp_conn.c + csp_crc32.c + csp_debug.c + csp_dedup.c + csp_endian.c + csp_hex_dump.c + csp_pflist.c + csp_io.c + csp_port.c + csp_promisc.c + csp_qfifo.c + csp_route.c + csp_service_handler.c + csp_services.c + csp_sfp.c +) + +add_subdirectory(drivers) +add_subdirectory(crypto) +add_subdirectory(interfaces) +add_subdirectory(rtable) + diff --git a/libcsp/src/arch/posix/CMakeLists.txt b/libcsp/src/arch/posix/CMakeLists.txt new file mode 100644 index 00000000..856040bc --- /dev/null +++ b/libcsp/src/arch/posix/CMakeLists.txt @@ -0,0 +1,9 @@ +target_sources(${LIB_CSP_NAME} PRIVATE + csp_malloc.c + csp_queue.c + csp_sempahore.c + csp_system.c + csp_thread.c + csp_time.c + pthread_queue.c +) diff --git a/libcsp/src/crypto/CMakeLists.txt b/libcsp/src/crypto/CMakeLists.txt new file mode 100644 index 00000000..19cb878a --- /dev/null +++ b/libcsp/src/crypto/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_CSP_NAME} PRIVATE + csp_hmac.c + csp_sha1.c + csp_xtea.c +) diff --git a/libcsp/src/drivers/CMakeLists.txt b/libcsp/src/drivers/CMakeLists.txt new file mode 100644 index 00000000..e2dd440b --- /dev/null +++ b/libcsp/src/drivers/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(can) diff --git a/libcsp/src/drivers/can/CMakeLists.txt b/libcsp/src/drivers/can/CMakeLists.txt new file mode 100644 index 00000000..d291fccc --- /dev/null +++ b/libcsp/src/drivers/can/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${LIB_CSP_NAME} PRIVATE + can_socketcan.c +) diff --git a/libcsp/src/interfaces/CMakeLists.txt b/libcsp/src/interfaces/CMakeLists.txt new file mode 100644 index 00000000..33f779e3 --- /dev/null +++ b/libcsp/src/interfaces/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${LIB_CSP_NAME} PRIVATE + csp_if_can_pbuf.c + csp_if_can.c + csp_if_i2c.c + csp_if_kiss.c + csp_if_lo.c +) diff --git a/libcsp/src/rtable/CMakeLists.txt b/libcsp/src/rtable/CMakeLists.txt new file mode 100644 index 00000000..101f4fb9 --- /dev/null +++ b/libcsp/src/rtable/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${LIB_CSP_NAME} PRIVATE + csp_rtable_cidr.c +) diff --git a/libcsp/src/transport/CMakeLists.txt b/libcsp/src/transport/CMakeLists.txt new file mode 100644 index 00000000..c509b755 --- /dev/null +++ b/libcsp/src/transport/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(${LIB_CSP_NAME} PRIVATE + csp_rdp.c + csp_udp.c +) diff --git a/mission/core/GenericFactory.cpp b/mission/core/GenericFactory.cpp index 24572218..b708f964 100644 --- a/mission/core/GenericFactory.cpp +++ b/mission/core/GenericFactory.cpp @@ -1,9 +1,9 @@ #include "GenericFactory.h" -#include -#include -#include + #include -#include + +#include +#include #include #include @@ -21,13 +21,9 @@ #include #include #include -#include -#include -#include "mission/devices/GomspaceDeviceHandler.h" -#include "mission/devices/devicedefinitions/GomspaceDefinitions.h" -#if ADD_TEST_CODE == 1 -//#include +#if OBSW_ADD_TEST_CODE == 1 + #include #endif void ObjectFactory::produceGenericObjects() { @@ -84,35 +80,8 @@ void ObjectFactory::produceGenericObjects() { new CService200ModeCommanding(objects::PUS_SERVICE_200_MODE_MGMT, apid::EIVE_OBSW, pus::PUS_SERVICE_200); - /* Cookies */ - CspCookie* p60DockCspCookie = new CspCookie(P60Dock::MAX_REPLY_LENGTH, - addresses::P60DOCK); - CspCookie* pdu1CspCookie = new CspCookie(PDU::MAX_REPLY_LENGTH, - addresses::PDU1); - CspCookie* pdu2CspCookie = new CspCookie(PDU::MAX_REPLY_LENGTH, - addresses::PDU2); - CspCookie* acuCspCookie = new CspCookie(ACU::MAX_REPLY_LENGTH, - addresses::ACU); - - /* Communication interfaces */ - new CspComIF(objects::CSP_COM_IF); - - /* Device Handler */ - new GomspaceDeviceHandler(objects::P60DOCK_HANDLER, objects::CSP_COM_IF, - p60DockCspCookie, P60Dock::MAX_CONFIGTABLE_ADDRESS, - P60Dock::MAX_HKTABLE_ADDRESS); - new GomspaceDeviceHandler(objects::PDU1_HANDLER, objects::CSP_COM_IF, - pdu1CspCookie, PDU::MAX_CONFIGTABLE_ADDRESS, - PDU::MAX_HKTABLE_ADDRESS); - new GomspaceDeviceHandler(objects::PDU2_HANDLER, objects::CSP_COM_IF, - pdu2CspCookie, PDU::MAX_CONFIGTABLE_ADDRESS, - PDU::MAX_HKTABLE_ADDRESS); - new GomspaceDeviceHandler(objects::ACU_HANDLER, objects::CSP_COM_IF, - acuCspCookie, ACU::MAX_CONFIGTABLE_ADDRESS, - ACU::MAX_HKTABLE_ADDRESS); - /* Test Device Handler */ -#if ADD_TEST_CODE == 1 -// new TestTask(objects::TEST_TASK); +#if OBSW_ADD_TEST_CODE == 1 + new TestTask(objects::TEST_TASK); #endif } From e42cbc31167274d00d69f008dee3f5513b7f0076 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 14:14:11 +0100 Subject: [PATCH 097/360] fsfw points to eive/develop now --- CMakeLists.txt | 7 +++++++ bsp_q7s/CMakeLists.txt | 1 + bsp_q7s/comIF/CMakeLists.txt | 8 ++++++++ fsfw | 2 +- libcsp/include/CMakeLists.txt | 4 ++++ libcsp/src/CMakeLists.txt | 4 +++- libcsp/src/arch/CMakeLists.txt | 3 +++ libcsp/src/arch/posix/CMakeLists.txt | 2 +- mission/devices/CMakeLists.txt | 1 + 9 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 bsp_q7s/comIF/CMakeLists.txt create mode 100644 libcsp/src/arch/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a27a5cc..7d631d3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED True) # Set names and variables set(TARGET_NAME ${CMAKE_PROJECT_NAME}) set(LIB_FSFW_NAME fsfw) +set(LIB_CSP_NAME libcsp) # Set path names set(FSFW_PATH fsfw) @@ -91,6 +92,12 @@ target_link_libraries(${TARGET_NAME} PRIVATE ${LIB_OS_NAME} ) +if(ADD_CSP_LIB) + target_link_libraries(${TARGET_NAME} PRIVATE + ${LIB_CSP_NAME} + ) +endif() + # Add include paths for all sources. target_include_directories(${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/bsp_q7s/CMakeLists.txt b/bsp_q7s/CMakeLists.txt index 8df43ca7..004a2fcd 100644 --- a/bsp_q7s/CMakeLists.txt +++ b/bsp_q7s/CMakeLists.txt @@ -5,6 +5,7 @@ target_sources(${TARGET_NAME} PUBLIC ) add_subdirectory(boardconfig) +add_subdirectory(comIF) diff --git a/bsp_q7s/comIF/CMakeLists.txt b/bsp_q7s/comIF/CMakeLists.txt new file mode 100644 index 00000000..1652702c --- /dev/null +++ b/bsp_q7s/comIF/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${TARGET_NAME} PRIVATE + cookies/CspCookie.cpp + CspComIF.cpp +) + + + + diff --git a/fsfw b/fsfw index 5b9c0e01..8ef6283b 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 5b9c0e013e35ab1353d402c6fa2cd75866e3afa5 +Subproject commit 8ef6283bf4f5cf5d12131c48365a753825fea637 diff --git a/libcsp/include/CMakeLists.txt b/libcsp/include/CMakeLists.txt index 94fee196..cc80ebb5 100644 --- a/libcsp/include/CMakeLists.txt +++ b/libcsp/include/CMakeLists.txt @@ -4,4 +4,8 @@ target_include_directories(${LIB_CSP_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/csp/crypto ) +target_include_directories(${LIB_CSP_NAME} INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} +) + diff --git a/libcsp/src/CMakeLists.txt b/libcsp/src/CMakeLists.txt index 5d1bfbf5..39c67877 100644 --- a/libcsp/src/CMakeLists.txt +++ b/libcsp/src/CMakeLists.txt @@ -7,7 +7,7 @@ target_sources(${LIB_CSP_NAME} PRIVATE csp_dedup.c csp_endian.c csp_hex_dump.c - csp_pflist.c + csp_iflist.c csp_io.c csp_port.c csp_promisc.c @@ -22,4 +22,6 @@ add_subdirectory(drivers) add_subdirectory(crypto) add_subdirectory(interfaces) add_subdirectory(rtable) +add_subdirectory(transport) +add_subdirectory(arch) diff --git a/libcsp/src/arch/CMakeLists.txt b/libcsp/src/arch/CMakeLists.txt new file mode 100644 index 00000000..aa0e4ca6 --- /dev/null +++ b/libcsp/src/arch/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(posix) + + diff --git a/libcsp/src/arch/posix/CMakeLists.txt b/libcsp/src/arch/posix/CMakeLists.txt index 856040bc..6bf13773 100644 --- a/libcsp/src/arch/posix/CMakeLists.txt +++ b/libcsp/src/arch/posix/CMakeLists.txt @@ -1,7 +1,7 @@ target_sources(${LIB_CSP_NAME} PRIVATE csp_malloc.c csp_queue.c - csp_sempahore.c + csp_semaphore.c csp_system.c csp_thread.c csp_time.c diff --git a/mission/devices/CMakeLists.txt b/mission/devices/CMakeLists.txt index f01df0e1..c751800f 100644 --- a/mission/devices/CMakeLists.txt +++ b/mission/devices/CMakeLists.txt @@ -3,6 +3,7 @@ target_sources(${TARGET_NAME} PUBLIC GyroL3GD20Handler.cpp MGMHandlerLIS3MDL.cpp MGMHandlerRM3100.cpp + GomspaceDeviceHandler.cpp ) From bacf50f6632f3322f82e22dc163c32385aacc7ed Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 14:21:52 +0100 Subject: [PATCH 098/360] restructured build system support --- CMakeLists.txt | 2 +- {buildsystem/cmake => cmake}/BuildType.cmake | 0 {buildsystem/cmake => cmake}/HardwareOsPostConfig.cmake | 0 {buildsystem/cmake => cmake}/HardwareOsPreConfig.cmake | 0 {buildsystem/cmake => cmake}/PreProjectConfig.cmake | 0 {buildsystem/cmake => cmake}/Q7SCrossCompileConfig.cmake | 0 {buildsystem/cmake => cmake}/RPiCrossCompileConfig.cmake | 0 .../scripts/.idea/inspectionProfiles/profiles_settings.xml | 0 {buildsystem/cmake => cmake}/scripts/.idea/misc.xml | 0 {buildsystem/cmake => cmake}/scripts/.idea/modules.xml | 0 {buildsystem/cmake => cmake}/scripts/.idea/scripts.iml | 0 {buildsystem/cmake => cmake}/scripts/.idea/vcs.xml | 0 {buildsystem/cmake => cmake}/scripts/.idea/workspace.xml | 0 .../cmake => cmake}/scripts/Host/create_cmake_debug_cfg.sh | 0 .../cmake => cmake}/scripts/Host/create_cmake_release_cfg.sh | 0 .../cmake => cmake}/scripts/Host/create_cmake_relwithdeb_cfg.sh | 0 .../cmake => cmake}/scripts/Host/create_cmake_size_cfg.sh | 0 .../cmake => cmake}/scripts/Linux/create_cmake_debug_cfg.sh | 0 .../cmake => cmake}/scripts/Linux/create_cmake_release_cfg.sh | 0 .../scripts/Linux/create_cmake_relwithdeb_cfg.sh | 0 .../cmake => cmake}/scripts/Linux/create_cmake_size_cfg.sh | 0 .../cmake => cmake}/scripts/Q7S/create_cmake_debug_cfg.sh | 0 .../cmake => cmake}/scripts/Q7S/create_cmake_release_cfg.sh | 0 .../cmake => cmake}/scripts/Q7S/create_cmake_relwithdeb_cfg.sh | 0 .../cmake => cmake}/scripts/RPi/create_cmake_debug_cfg.sh | 0 .../cmake => cmake}/scripts/RPi/create_cmake_release_cfg.sh | 0 .../cmake => cmake}/scripts/RPi/create_cmake_relwithdeb_cfg.sh | 0 .../cmake => cmake}/scripts/RPi/create_cmake_size_cfg.sh | 0 {buildsystem/cmake => cmake}/scripts/RPi/rpi_path_helper.sh | 0 {buildsystem/cmake => cmake}/scripts/RPi/rpi_path_helper_win.sh | 0 {buildsystem/cmake => cmake}/scripts/cmake_build_config.py | 0 31 files changed, 1 insertion(+), 1 deletion(-) rename {buildsystem/cmake => cmake}/BuildType.cmake (100%) rename {buildsystem/cmake => cmake}/HardwareOsPostConfig.cmake (100%) rename {buildsystem/cmake => cmake}/HardwareOsPreConfig.cmake (100%) rename {buildsystem/cmake => cmake}/PreProjectConfig.cmake (100%) rename {buildsystem/cmake => cmake}/Q7SCrossCompileConfig.cmake (100%) rename {buildsystem/cmake => cmake}/RPiCrossCompileConfig.cmake (100%) rename {buildsystem/cmake => cmake}/scripts/.idea/inspectionProfiles/profiles_settings.xml (100%) rename {buildsystem/cmake => cmake}/scripts/.idea/misc.xml (100%) rename {buildsystem/cmake => cmake}/scripts/.idea/modules.xml (100%) rename {buildsystem/cmake => cmake}/scripts/.idea/scripts.iml (100%) rename {buildsystem/cmake => cmake}/scripts/.idea/vcs.xml (100%) rename {buildsystem/cmake => cmake}/scripts/.idea/workspace.xml (100%) rename {buildsystem/cmake => cmake}/scripts/Host/create_cmake_debug_cfg.sh (100%) rename {buildsystem/cmake => cmake}/scripts/Host/create_cmake_release_cfg.sh (100%) rename {buildsystem/cmake => cmake}/scripts/Host/create_cmake_relwithdeb_cfg.sh (100%) rename {buildsystem/cmake => cmake}/scripts/Host/create_cmake_size_cfg.sh (100%) rename {buildsystem/cmake => cmake}/scripts/Linux/create_cmake_debug_cfg.sh (100%) rename {buildsystem/cmake => cmake}/scripts/Linux/create_cmake_release_cfg.sh (100%) rename {buildsystem/cmake => cmake}/scripts/Linux/create_cmake_relwithdeb_cfg.sh (100%) rename {buildsystem/cmake => cmake}/scripts/Linux/create_cmake_size_cfg.sh (100%) rename {buildsystem/cmake => cmake}/scripts/Q7S/create_cmake_debug_cfg.sh (100%) rename {buildsystem/cmake => cmake}/scripts/Q7S/create_cmake_release_cfg.sh (100%) rename {buildsystem/cmake => cmake}/scripts/Q7S/create_cmake_relwithdeb_cfg.sh (100%) rename {buildsystem/cmake => cmake}/scripts/RPi/create_cmake_debug_cfg.sh (100%) rename {buildsystem/cmake => cmake}/scripts/RPi/create_cmake_release_cfg.sh (100%) rename {buildsystem/cmake => cmake}/scripts/RPi/create_cmake_relwithdeb_cfg.sh (100%) rename {buildsystem/cmake => cmake}/scripts/RPi/create_cmake_size_cfg.sh (100%) rename {buildsystem/cmake => cmake}/scripts/RPi/rpi_path_helper.sh (100%) rename {buildsystem/cmake => cmake}/scripts/RPi/rpi_path_helper_win.sh (100%) rename {buildsystem/cmake => cmake}/scripts/cmake_build_config.py (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d631d3b..1be2bbdc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ cmake_minimum_required(VERSION 3.13) # set(CMAKE_VERBOSE TRUE) -set(CMAKE_SCRIPT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/buildsystem/cmake") +set(CMAKE_SCRIPT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") if(NOT OS_FSFW) set(OS_FSFW host CACHE STRING "OS for the FSFW.") diff --git a/buildsystem/cmake/BuildType.cmake b/cmake/BuildType.cmake similarity index 100% rename from buildsystem/cmake/BuildType.cmake rename to cmake/BuildType.cmake diff --git a/buildsystem/cmake/HardwareOsPostConfig.cmake b/cmake/HardwareOsPostConfig.cmake similarity index 100% rename from buildsystem/cmake/HardwareOsPostConfig.cmake rename to cmake/HardwareOsPostConfig.cmake diff --git a/buildsystem/cmake/HardwareOsPreConfig.cmake b/cmake/HardwareOsPreConfig.cmake similarity index 100% rename from buildsystem/cmake/HardwareOsPreConfig.cmake rename to cmake/HardwareOsPreConfig.cmake diff --git a/buildsystem/cmake/PreProjectConfig.cmake b/cmake/PreProjectConfig.cmake similarity index 100% rename from buildsystem/cmake/PreProjectConfig.cmake rename to cmake/PreProjectConfig.cmake diff --git a/buildsystem/cmake/Q7SCrossCompileConfig.cmake b/cmake/Q7SCrossCompileConfig.cmake similarity index 100% rename from buildsystem/cmake/Q7SCrossCompileConfig.cmake rename to cmake/Q7SCrossCompileConfig.cmake diff --git a/buildsystem/cmake/RPiCrossCompileConfig.cmake b/cmake/RPiCrossCompileConfig.cmake similarity index 100% rename from buildsystem/cmake/RPiCrossCompileConfig.cmake rename to cmake/RPiCrossCompileConfig.cmake diff --git a/buildsystem/cmake/scripts/.idea/inspectionProfiles/profiles_settings.xml b/cmake/scripts/.idea/inspectionProfiles/profiles_settings.xml similarity index 100% rename from buildsystem/cmake/scripts/.idea/inspectionProfiles/profiles_settings.xml rename to cmake/scripts/.idea/inspectionProfiles/profiles_settings.xml diff --git a/buildsystem/cmake/scripts/.idea/misc.xml b/cmake/scripts/.idea/misc.xml similarity index 100% rename from buildsystem/cmake/scripts/.idea/misc.xml rename to cmake/scripts/.idea/misc.xml diff --git a/buildsystem/cmake/scripts/.idea/modules.xml b/cmake/scripts/.idea/modules.xml similarity index 100% rename from buildsystem/cmake/scripts/.idea/modules.xml rename to cmake/scripts/.idea/modules.xml diff --git a/buildsystem/cmake/scripts/.idea/scripts.iml b/cmake/scripts/.idea/scripts.iml similarity index 100% rename from buildsystem/cmake/scripts/.idea/scripts.iml rename to cmake/scripts/.idea/scripts.iml diff --git a/buildsystem/cmake/scripts/.idea/vcs.xml b/cmake/scripts/.idea/vcs.xml similarity index 100% rename from buildsystem/cmake/scripts/.idea/vcs.xml rename to cmake/scripts/.idea/vcs.xml diff --git a/buildsystem/cmake/scripts/.idea/workspace.xml b/cmake/scripts/.idea/workspace.xml similarity index 100% rename from buildsystem/cmake/scripts/.idea/workspace.xml rename to cmake/scripts/.idea/workspace.xml diff --git a/buildsystem/cmake/scripts/Host/create_cmake_debug_cfg.sh b/cmake/scripts/Host/create_cmake_debug_cfg.sh similarity index 100% rename from buildsystem/cmake/scripts/Host/create_cmake_debug_cfg.sh rename to cmake/scripts/Host/create_cmake_debug_cfg.sh diff --git a/buildsystem/cmake/scripts/Host/create_cmake_release_cfg.sh b/cmake/scripts/Host/create_cmake_release_cfg.sh similarity index 100% rename from buildsystem/cmake/scripts/Host/create_cmake_release_cfg.sh rename to cmake/scripts/Host/create_cmake_release_cfg.sh diff --git a/buildsystem/cmake/scripts/Host/create_cmake_relwithdeb_cfg.sh b/cmake/scripts/Host/create_cmake_relwithdeb_cfg.sh similarity index 100% rename from buildsystem/cmake/scripts/Host/create_cmake_relwithdeb_cfg.sh rename to cmake/scripts/Host/create_cmake_relwithdeb_cfg.sh diff --git a/buildsystem/cmake/scripts/Host/create_cmake_size_cfg.sh b/cmake/scripts/Host/create_cmake_size_cfg.sh similarity index 100% rename from buildsystem/cmake/scripts/Host/create_cmake_size_cfg.sh rename to cmake/scripts/Host/create_cmake_size_cfg.sh diff --git a/buildsystem/cmake/scripts/Linux/create_cmake_debug_cfg.sh b/cmake/scripts/Linux/create_cmake_debug_cfg.sh similarity index 100% rename from buildsystem/cmake/scripts/Linux/create_cmake_debug_cfg.sh rename to cmake/scripts/Linux/create_cmake_debug_cfg.sh diff --git a/buildsystem/cmake/scripts/Linux/create_cmake_release_cfg.sh b/cmake/scripts/Linux/create_cmake_release_cfg.sh similarity index 100% rename from buildsystem/cmake/scripts/Linux/create_cmake_release_cfg.sh rename to cmake/scripts/Linux/create_cmake_release_cfg.sh diff --git a/buildsystem/cmake/scripts/Linux/create_cmake_relwithdeb_cfg.sh b/cmake/scripts/Linux/create_cmake_relwithdeb_cfg.sh similarity index 100% rename from buildsystem/cmake/scripts/Linux/create_cmake_relwithdeb_cfg.sh rename to cmake/scripts/Linux/create_cmake_relwithdeb_cfg.sh diff --git a/buildsystem/cmake/scripts/Linux/create_cmake_size_cfg.sh b/cmake/scripts/Linux/create_cmake_size_cfg.sh similarity index 100% rename from buildsystem/cmake/scripts/Linux/create_cmake_size_cfg.sh rename to cmake/scripts/Linux/create_cmake_size_cfg.sh diff --git a/buildsystem/cmake/scripts/Q7S/create_cmake_debug_cfg.sh b/cmake/scripts/Q7S/create_cmake_debug_cfg.sh similarity index 100% rename from buildsystem/cmake/scripts/Q7S/create_cmake_debug_cfg.sh rename to cmake/scripts/Q7S/create_cmake_debug_cfg.sh diff --git a/buildsystem/cmake/scripts/Q7S/create_cmake_release_cfg.sh b/cmake/scripts/Q7S/create_cmake_release_cfg.sh similarity index 100% rename from buildsystem/cmake/scripts/Q7S/create_cmake_release_cfg.sh rename to cmake/scripts/Q7S/create_cmake_release_cfg.sh diff --git a/buildsystem/cmake/scripts/Q7S/create_cmake_relwithdeb_cfg.sh b/cmake/scripts/Q7S/create_cmake_relwithdeb_cfg.sh similarity index 100% rename from buildsystem/cmake/scripts/Q7S/create_cmake_relwithdeb_cfg.sh rename to cmake/scripts/Q7S/create_cmake_relwithdeb_cfg.sh diff --git a/buildsystem/cmake/scripts/RPi/create_cmake_debug_cfg.sh b/cmake/scripts/RPi/create_cmake_debug_cfg.sh similarity index 100% rename from buildsystem/cmake/scripts/RPi/create_cmake_debug_cfg.sh rename to cmake/scripts/RPi/create_cmake_debug_cfg.sh diff --git a/buildsystem/cmake/scripts/RPi/create_cmake_release_cfg.sh b/cmake/scripts/RPi/create_cmake_release_cfg.sh similarity index 100% rename from buildsystem/cmake/scripts/RPi/create_cmake_release_cfg.sh rename to cmake/scripts/RPi/create_cmake_release_cfg.sh diff --git a/buildsystem/cmake/scripts/RPi/create_cmake_relwithdeb_cfg.sh b/cmake/scripts/RPi/create_cmake_relwithdeb_cfg.sh similarity index 100% rename from buildsystem/cmake/scripts/RPi/create_cmake_relwithdeb_cfg.sh rename to cmake/scripts/RPi/create_cmake_relwithdeb_cfg.sh diff --git a/buildsystem/cmake/scripts/RPi/create_cmake_size_cfg.sh b/cmake/scripts/RPi/create_cmake_size_cfg.sh similarity index 100% rename from buildsystem/cmake/scripts/RPi/create_cmake_size_cfg.sh rename to cmake/scripts/RPi/create_cmake_size_cfg.sh diff --git a/buildsystem/cmake/scripts/RPi/rpi_path_helper.sh b/cmake/scripts/RPi/rpi_path_helper.sh similarity index 100% rename from buildsystem/cmake/scripts/RPi/rpi_path_helper.sh rename to cmake/scripts/RPi/rpi_path_helper.sh diff --git a/buildsystem/cmake/scripts/RPi/rpi_path_helper_win.sh b/cmake/scripts/RPi/rpi_path_helper_win.sh similarity index 100% rename from buildsystem/cmake/scripts/RPi/rpi_path_helper_win.sh rename to cmake/scripts/RPi/rpi_path_helper_win.sh diff --git a/buildsystem/cmake/scripts/cmake_build_config.py b/cmake/scripts/cmake_build_config.py similarity index 100% rename from buildsystem/cmake/scripts/cmake_build_config.py rename to cmake/scripts/cmake_build_config.py From 96293ebdf1611771c6fb8959c44120f2004b2532 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 14:28:38 +0100 Subject: [PATCH 099/360] updated project files --- misc/eclipse/.cproject | 309 +++++++++++++++++- misc/eclipse/make/.cproject | 257 +++++++++++++++ misc/eclipse/make/.project | 27 ++ .../Host/eive-linux-host-debug.launch | 0 .../Host/eive-linux-host-release.launch | 0 .../{ => make}/Host/eive-mingw-debug.launch | 0 .../{ => make}/Host/eive-mingw-release.launch | 0 7 files changed, 589 insertions(+), 4 deletions(-) create mode 100644 misc/eclipse/make/.cproject create mode 100644 misc/eclipse/make/.project rename misc/eclipse/{ => make}/Host/eive-linux-host-debug.launch (100%) rename misc/eclipse/{ => make}/Host/eive-linux-host-release.launch (100%) rename misc/eclipse/{ => make}/Host/eive-mingw-debug.launch (100%) rename misc/eclipse/{ => make}/Host/eive-mingw-release.launch (100%) diff --git a/misc/eclipse/.cproject b/misc/eclipse/.cproject index 6a50d831..80fd68eb 100644 --- a/misc/eclipse/.cproject +++ b/misc/eclipse/.cproject @@ -15,11 +15,11 @@ - + - + @@ -45,6 +45,9 @@ + + + @@ -67,7 +70,7 @@ - + @@ -93,6 +96,9 @@ + + + @@ -115,7 +121,7 @@ - + + + + @@ -201,6 +210,297 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -220,6 +520,7 @@ + diff --git a/misc/eclipse/make/.cproject b/misc/eclipse/make/.cproject new file mode 100644 index 00000000..6a50d831 --- /dev/null +++ b/misc/eclipse/make/.cproject @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/misc/eclipse/make/.project b/misc/eclipse/make/.project new file mode 100644 index 00000000..906c567f --- /dev/null +++ b/misc/eclipse/make/.project @@ -0,0 +1,27 @@ + + + eive_obsw + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/misc/eclipse/Host/eive-linux-host-debug.launch b/misc/eclipse/make/Host/eive-linux-host-debug.launch similarity index 100% rename from misc/eclipse/Host/eive-linux-host-debug.launch rename to misc/eclipse/make/Host/eive-linux-host-debug.launch diff --git a/misc/eclipse/Host/eive-linux-host-release.launch b/misc/eclipse/make/Host/eive-linux-host-release.launch similarity index 100% rename from misc/eclipse/Host/eive-linux-host-release.launch rename to misc/eclipse/make/Host/eive-linux-host-release.launch diff --git a/misc/eclipse/Host/eive-mingw-debug.launch b/misc/eclipse/make/Host/eive-mingw-debug.launch similarity index 100% rename from misc/eclipse/Host/eive-mingw-debug.launch rename to misc/eclipse/make/Host/eive-mingw-debug.launch diff --git a/misc/eclipse/Host/eive-mingw-release.launch b/misc/eclipse/make/Host/eive-mingw-release.launch similarity index 100% rename from misc/eclipse/Host/eive-mingw-release.launch rename to misc/eclipse/make/Host/eive-mingw-release.launch From 6ba84caaf8610b3c10b9672148957e2aa036781a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 14:29:38 +0100 Subject: [PATCH 100/360] renamed launch configs for clear distrinction --- .../Host/eive-linux-host-debug-make.launch | 33 +++++++++++++++++++ .../Host/eive-linux-host-release-make.launch | 33 +++++++++++++++++++ .../eclipse/Host/eive-mingw-debug-make.launch | 33 +++++++++++++++++++ .../Host/eive-mingw-release-make.launch | 33 +++++++++++++++++++ 4 files changed, 132 insertions(+) create mode 100644 misc/eclipse/Host/eive-linux-host-debug-make.launch create mode 100644 misc/eclipse/Host/eive-linux-host-release-make.launch create mode 100644 misc/eclipse/Host/eive-mingw-debug-make.launch create mode 100644 misc/eclipse/Host/eive-mingw-release-make.launch diff --git a/misc/eclipse/Host/eive-linux-host-debug-make.launch b/misc/eclipse/Host/eive-linux-host-debug-make.launch new file mode 100644 index 00000000..f5ab1ac7 --- /dev/null +++ b/misc/eclipse/Host/eive-linux-host-debug-make.launch @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/eclipse/Host/eive-linux-host-release-make.launch b/misc/eclipse/Host/eive-linux-host-release-make.launch new file mode 100644 index 00000000..7548f831 --- /dev/null +++ b/misc/eclipse/Host/eive-linux-host-release-make.launch @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/eclipse/Host/eive-mingw-debug-make.launch b/misc/eclipse/Host/eive-mingw-debug-make.launch new file mode 100644 index 00000000..4ab7b736 --- /dev/null +++ b/misc/eclipse/Host/eive-mingw-debug-make.launch @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/eclipse/Host/eive-mingw-release-make.launch b/misc/eclipse/Host/eive-mingw-release-make.launch new file mode 100644 index 00000000..da2f47a9 --- /dev/null +++ b/misc/eclipse/Host/eive-mingw-release-make.launch @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From a19c9342a66f34e29c486d10466a6ad86f148951 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 14:31:10 +0100 Subject: [PATCH 101/360] added cmake launch config --- misc/eclipse/Host/eive-mingw-debug-cmake.launch | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 misc/eclipse/Host/eive-mingw-debug-cmake.launch diff --git a/misc/eclipse/Host/eive-mingw-debug-cmake.launch b/misc/eclipse/Host/eive-mingw-debug-cmake.launch new file mode 100644 index 00000000..e69de29b From 56f45e3fb16f783e437cd8ee7ab1297aab5b6a86 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 14:37:39 +0100 Subject: [PATCH 102/360] include fix --- CMakeLists.txt | 1 + bsp_hosted/InitMission.cpp | 9 ++--- .../fsfwconfig/events/subsystemIdRanges.h | 2 +- .../Host/eive-mingw-release-cmake.launch | 33 +++++++++++++++++++ mission/core/GenericFactory.cpp | 2 +- 5 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 misc/eclipse/Host/eive-mingw-release-cmake.launch diff --git a/CMakeLists.txt b/CMakeLists.txt index 1be2bbdc..1786f1af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,7 @@ if(TGT_BSP) set(ADD_CSP_LIB TRUE) endif() else() + # Required by FSFW library set(FSFW_CONFIG_PATH "${BSP_PATH}/fsfwconfig") endif() diff --git a/bsp_hosted/InitMission.cpp b/bsp_hosted/InitMission.cpp index d4e58b99..39dcafff 100644 --- a/bsp_hosted/InitMission.cpp +++ b/bsp_hosted/InitMission.cpp @@ -1,5 +1,8 @@ -#include -#include +#include "InitMission.h" +#include "ObjectFactory.h" + +#include + #include #include #include @@ -7,8 +10,6 @@ #include #include #include -#include -#include #include diff --git a/bsp_hosted/fsfwconfig/events/subsystemIdRanges.h b/bsp_hosted/fsfwconfig/events/subsystemIdRanges.h index 1128b26b..51534f60 100644 --- a/bsp_hosted/fsfwconfig/events/subsystemIdRanges.h +++ b/bsp_hosted/fsfwconfig/events/subsystemIdRanges.h @@ -10,7 +10,7 @@ */ namespace SUBSYSTEM_ID { enum: uint8_t { - SUBSYSTE_ID_START = FW_SUBSYSTEM_ID_RANGE, + SUBSYSTEM_ID_START = FW_SUBSYSTEM_ID_RANGE, PUS_SERVICE_2, PUS_SERVICE_3, PUS_SERVICE_5, diff --git a/misc/eclipse/Host/eive-mingw-release-cmake.launch b/misc/eclipse/Host/eive-mingw-release-cmake.launch new file mode 100644 index 00000000..0a5fbd71 --- /dev/null +++ b/misc/eclipse/Host/eive-mingw-release-cmake.launch @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mission/core/GenericFactory.cpp b/mission/core/GenericFactory.cpp index b708f964..e0e857da 100644 --- a/mission/core/GenericFactory.cpp +++ b/mission/core/GenericFactory.cpp @@ -1,6 +1,6 @@ #include "GenericFactory.h" -#include +#include #include #include From 45ef1abc9df46f1ceac46cdb41fac84b921aef25 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 14:39:03 +0100 Subject: [PATCH 103/360] includes formal correction --- mission/core/GenericFactory.cpp | 2 +- mission/devices/devicedefinitions/GomSpacePackets.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mission/core/GenericFactory.cpp b/mission/core/GenericFactory.cpp index e0e857da..b3866cb0 100644 --- a/mission/core/GenericFactory.cpp +++ b/mission/core/GenericFactory.cpp @@ -1,6 +1,6 @@ #include "GenericFactory.h" -#include +#include #include #include diff --git a/mission/devices/devicedefinitions/GomSpacePackets.h b/mission/devices/devicedefinitions/GomSpacePackets.h index 6c3509f8..24bb67e7 100644 --- a/mission/devices/devicedefinitions/GomSpacePackets.h +++ b/mission/devices/devicedefinitions/GomSpacePackets.h @@ -1,10 +1,10 @@ #ifndef MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEPACKETS_H_ #define MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEPACKETS_H_ -#include "fsfw/serialize/SerialBufferAdapter.h" -#include "fsfw/serialize/SerializeElement.h" -#include "fsfw/serialize/SerialLinkedListAdapter.h" -#include "fsfw/serialize/SerialFixedArrayListAdapter.h" +#include +#include +#include +#include namespace GOMSPACE{ static const uint16_t IGNORE_CHECKSUM = 0xbb0; From 25de1438cedb47115186e4e4cd111ccc814b7ca0 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 14:53:34 +0100 Subject: [PATCH 104/360] some fixes, launch configs added --- cmake/HardwareOsPreConfig.cmake | 2 ++ cmake/scripts/Linux/create_cmake_debug_cfg.sh | 0 .../scripts/Linux/create_cmake_release_cfg.sh | 0 .../Linux/create_cmake_relwithdeb_cfg.sh | 0 cmake/scripts/Linux/create_cmake_size_cfg.sh | 0 .../Host/eive-linux-host-debug-cmake.launch | 33 +++++++++++++++++++ 6 files changed, 35 insertions(+) mode change 100644 => 100755 cmake/scripts/Linux/create_cmake_debug_cfg.sh mode change 100644 => 100755 cmake/scripts/Linux/create_cmake_release_cfg.sh mode change 100644 => 100755 cmake/scripts/Linux/create_cmake_relwithdeb_cfg.sh mode change 100644 => 100755 cmake/scripts/Linux/create_cmake_size_cfg.sh create mode 100644 misc/eclipse/Host/eive-linux-host-debug-cmake.launch diff --git a/cmake/HardwareOsPreConfig.cmake b/cmake/HardwareOsPreConfig.cmake index 4ead6540..ab5c16fd 100644 --- a/cmake/HardwareOsPreConfig.cmake +++ b/cmake/HardwareOsPreConfig.cmake @@ -61,6 +61,8 @@ if(TGT_BSP) message(WARNING "CMake not configured for this target!") message(FATAL_ERROR "Target: ${TGT_BSP}!") endif() +else() + set(BSP_PATH "bsp_hosted") endif() set(BSP_PATH ${BSP_PATH} PARENT_SCOPE) diff --git a/cmake/scripts/Linux/create_cmake_debug_cfg.sh b/cmake/scripts/Linux/create_cmake_debug_cfg.sh old mode 100644 new mode 100755 diff --git a/cmake/scripts/Linux/create_cmake_release_cfg.sh b/cmake/scripts/Linux/create_cmake_release_cfg.sh old mode 100644 new mode 100755 diff --git a/cmake/scripts/Linux/create_cmake_relwithdeb_cfg.sh b/cmake/scripts/Linux/create_cmake_relwithdeb_cfg.sh old mode 100644 new mode 100755 diff --git a/cmake/scripts/Linux/create_cmake_size_cfg.sh b/cmake/scripts/Linux/create_cmake_size_cfg.sh old mode 100644 new mode 100755 diff --git a/misc/eclipse/Host/eive-linux-host-debug-cmake.launch b/misc/eclipse/Host/eive-linux-host-debug-cmake.launch new file mode 100644 index 00000000..e79e2e8d --- /dev/null +++ b/misc/eclipse/Host/eive-linux-host-debug-cmake.launch @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From cab9c2dd142a583aff605061bb8f9416f7e76171 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 14:55:10 +0100 Subject: [PATCH 105/360] deleted make luanch config --- .../Host/eive-linux-host-debug-make.launch | 33 ------------------- .../Host/eive-linux-host-release-make.launch | 33 ------------------- .../eclipse/Host/eive-mingw-debug-make.launch | 33 ------------------- .../Host/eive-mingw-release-make.launch | 33 ------------------- 4 files changed, 132 deletions(-) delete mode 100644 misc/eclipse/Host/eive-linux-host-debug-make.launch delete mode 100644 misc/eclipse/Host/eive-linux-host-release-make.launch delete mode 100644 misc/eclipse/Host/eive-mingw-debug-make.launch delete mode 100644 misc/eclipse/Host/eive-mingw-release-make.launch diff --git a/misc/eclipse/Host/eive-linux-host-debug-make.launch b/misc/eclipse/Host/eive-linux-host-debug-make.launch deleted file mode 100644 index f5ab1ac7..00000000 --- a/misc/eclipse/Host/eive-linux-host-debug-make.launch +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/eclipse/Host/eive-linux-host-release-make.launch b/misc/eclipse/Host/eive-linux-host-release-make.launch deleted file mode 100644 index 7548f831..00000000 --- a/misc/eclipse/Host/eive-linux-host-release-make.launch +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/eclipse/Host/eive-mingw-debug-make.launch b/misc/eclipse/Host/eive-mingw-debug-make.launch deleted file mode 100644 index 4ab7b736..00000000 --- a/misc/eclipse/Host/eive-mingw-debug-make.launch +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/eclipse/Host/eive-mingw-release-make.launch b/misc/eclipse/Host/eive-mingw-release-make.launch deleted file mode 100644 index da2f47a9..00000000 --- a/misc/eclipse/Host/eive-mingw-release-make.launch +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 9d40006f459761e8589fdf95e6f9b5bf4a2f6011 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 14:57:19 +0100 Subject: [PATCH 106/360] added linux release launch config --- .../Host/eive-linux-host-release-cmake.launch | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 misc/eclipse/make/Host/eive-linux-host-release-cmake.launch diff --git a/misc/eclipse/make/Host/eive-linux-host-release-cmake.launch b/misc/eclipse/make/Host/eive-linux-host-release-cmake.launch new file mode 100644 index 00000000..f2647a4f --- /dev/null +++ b/misc/eclipse/make/Host/eive-linux-host-release-cmake.launch @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 4545236f7f4d356027a4f898864928d12234d3a4 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 14:59:14 +0100 Subject: [PATCH 107/360] added launch config --- .../Host/eive-linux-host-release-cmake.launch | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 misc/eclipse/Host/eive-linux-host-release-cmake.launch diff --git a/misc/eclipse/Host/eive-linux-host-release-cmake.launch b/misc/eclipse/Host/eive-linux-host-release-cmake.launch new file mode 100644 index 00000000..f2647a4f --- /dev/null +++ b/misc/eclipse/Host/eive-linux-host-release-cmake.launch @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From cc883c30f43560372604ccb810065fdf32aff1fe Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 15:04:08 +0100 Subject: [PATCH 108/360] reamde update --- README.md | 88 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index f4d5c5f5..0dd496c5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Target systems: -* OBC +* OBC with Linux OS * Xiphos Q7S * Based on Zynq-7020 SoC (xc7z020clg484-2) * Dual-core ARM Cortex-A9 @@ -12,16 +12,19 @@ Target systems: * Artix-7 FPGA (85K pogrammable logic cells) * Datasheet at https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_IRS/Arbeitsdaten/08_Used%20Components/Q7S&fileid=340648 * Also a lot of informatin about the Q7S can be found on the xiphos trac platform: https://trac.xiphos.com/trac/eive-q7/wiki/Q7RevB -* Linux OS - * Built with Yocto 2.5 + * Linux OS built with Yocto 2.5 * Linux Kernel https://github.com/XiphosSystemsCorp/linux-xlnx.git * Host System * Generic software components which are not dependant on hardware can also be run. All host code is contained in the hosted folder * Tested for Linux (Ubuntu 20.04) and Windows 10 +* Raspberry Pi + * EIVE OBC can be built for Raspberry Pi as well (either directly on Raspberry Pi or by installing a cross compiler) +The steps in the primary README are related to the main OBC target Q7S. ## Setting up development environment + * Install Vivado 2018.2 and Xilinx SDK from https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/vivado-design-tools/archive.html. Install the Vivado Design Suite - HLx Editions - 2018.2 Full Product Installation instead of the updates. It is recommended to use the installer * Install settings. In the Devices selection, it is sufficient to pick SoC → Zynq-7000:
@@ -133,65 +136,76 @@ git submodule update ## Debugging the software via Flatsat PC Open SSH connection to flatsat PC: -```` + +```sh ssh eive@2001:7c0:2018:1099:babe:0:e1fe:f1a5 -```` +``` + To access the console of the Q7S run the following: ```sh picocom -b 115200 /dev/ttyUSB0 ``` + To debug an application, first make sure a static IP address is assigned to the Q7S. Run ifconfig on the Q7S serial console. -```` + +```sh ifconfig -```` +``` + Set IP address and netmask with -```` + +```sh ifconfig eth0 192.168.133.10 ifconfig eth0 netmask 255.255.255.0 -```` +``` + To launch application from Xilinx SDK setup port fowarding on the localhost. -```` + +```sh ssh -L 1534:192.168.133.10:1534 eive@2001:7c0:2018:1099:babe:0:e1fe:f1a5 -```` +``` + This forwards any requests to localhost:1534 to the port 1534 of the Q7S with the IP address 192.168.133.10. -Note: When now setting up a debug session in the Xilinx SDK, the host must be set to localhost instead of the IP address - of the Q7S. - +Note: When now setting up a debug session in the Xilinx SDK, the host must be set to localhost instead of the IP address of the Q7S. ## Launching an application after boot Load the root partiton from the flash memory (there are to nor-flash memories and each flash holds two xdi images). Note: It is not possible to modify the current loaded root partition. 1. Disable write protection of the desired root partition -```` -writeprotect 0 0 0 # unlocks nominal image on nor-flash 0 -```` + + ```sh + writeprotect 0 0 0 # unlocks nominal image on nor-flash 0 + ``` + 2. Mount the root partition -```` -xsc_mount_copy 0 0 # Mounts the nominal image from nor-flash 0 -```` + + ```sh + xsc_mount_copy 0 0 # Mounts the nominal image from nor-flash 0 + ``` 3. Copy the executable to /bin/usr 4. Make sure the permissions to execute the application are set -```` -chmod +x application -```` + ```sh + chmod +x application + ``` + 5. Create systemd service in /lib/systemd/system. The following shows an example service. -```` -cat > example.service -[Unit] -Description=Example Service -StartLimitIntervalSec=0 + ```sh + cat > example.service + [Unit] + Description=Example Service + StartLimitIntervalSec=0 -[Service] -Type=simple -Restart=always -RestartSec=1 -User=root -ExecStart=/usr/bin/application + [Service] + Type=simple + Restart=always + RestartSec=1 + User=root + ExecStart=/usr/bin/application -[Install] -WantedBy=multi-user.target -```` + [Install] + WantedBy=multi-user.target + ``` 6. Enable the service. This is normally done with systemctl enable. However, this is not possible when the service is created for a mounted root partition. Therefore create a symlink as follows. ```` From 7f220a1a477adb2f601e02f74ae02554929ff06a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 18:06:52 +0100 Subject: [PATCH 109/360] suppressed warning flags --- CMakeLists.txt | 5 +++- bsp_rpi/CMakeLists.txt | 1 + bsp_rpi/boardtest/CMakeLists.txt | 7 ++++++ bsp_rpi/boardtest/SpiTest.cpp | 43 ++++++++++++++++++++++++++++++++ bsp_rpi/boardtest/SpiTest.h | 31 +++++++++++++++++++++++ fsfw | 2 +- libcsp/include/CMakeLists.txt | 2 -- 7 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 bsp_rpi/boardtest/CMakeLists.txt create mode 100644 bsp_rpi/boardtest/SpiTest.cpp create mode 100644 bsp_rpi/boardtest/SpiTest.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1786f1af..e0b00d30 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,8 @@ if(NOT OS_FSFW) set(OS_FSFW host CACHE STRING "OS for the FSFW.") endif() +set_property(CACHE OS_FSFW PROPERTY STRINGS host linux) + # Perform steps like loading toolchain files where applicable. include(${CMAKE_SCRIPT_PATH}/PreProjectConfig.cmake) pre_project_config() @@ -44,6 +46,8 @@ set(FSFW_PATH fsfw) set(MISSION_PATH mission) set(CSPLIB_PATH libcsp) +set(WARNING_SHADOW_LOCAL FALSE) + # Analyse different OS and architecture/target options, determine BSP_PATH, # display information about compiler etc. include (${CMAKE_SCRIPT_PATH}/HardwareOsPreConfig.cmake) @@ -110,7 +114,6 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(WARNING_FLAGS -Wall -Wextra - -Wshadow=local -Wimplicit-fallthrough=1 -Wno-unused-parameter -Wno-psabi diff --git a/bsp_rpi/CMakeLists.txt b/bsp_rpi/CMakeLists.txt index 8dd8e6f1..7885ca28 100644 --- a/bsp_rpi/CMakeLists.txt +++ b/bsp_rpi/CMakeLists.txt @@ -5,6 +5,7 @@ target_sources(${TARGET_NAME} PUBLIC ) add_subdirectory(boardconfig) +add_subdirectory(boardtest) diff --git a/bsp_rpi/boardtest/CMakeLists.txt b/bsp_rpi/boardtest/CMakeLists.txt new file mode 100644 index 00000000..768fc52f --- /dev/null +++ b/bsp_rpi/boardtest/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${TARGET_NAME} PRIVATE + SpiTest.cpp +) + + + + diff --git a/bsp_rpi/boardtest/SpiTest.cpp b/bsp_rpi/boardtest/SpiTest.cpp new file mode 100644 index 00000000..91939714 --- /dev/null +++ b/bsp_rpi/boardtest/SpiTest.cpp @@ -0,0 +1,43 @@ +#include "SpiTest.h" + +#include + +#include +#include +#include + +SpiTest::SpiTest(object_id_t objectId): SystemObject(objectId) { + wiringPiSetupGpio(); + + int spiFd = open(spiDeviceName.c_str(), O_RDWR); + if (spiFd < 0){ + sif::error << "Could not open SPI device!" << std::endl; + } + + spiMode = SPI_MODE_3; + int ret = ioctl(spiFd, SPI_IOC_WR_MODE, &spiMode); + if(ret < 0) { + sif::error << "Could not set write mode!" << std::endl; + } + + /* Datenrate setzen */ + ret = ioctl(spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &spiSpeed); + if(ret < 0) { + sif::error << "Could not SPI speed!" << std::endl; + } +} + +ReturnValue_t SpiTest::performOperation(uint8_t opCode) { + if(oneShot) { + + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SpiTest::initialize() { + //transferHandle.rx_buf = reinterpret_cast<__u64>(receiveBuffer); + //transferHandle.tx_buf = reinterpret_cast<__u64>(sendBuffer); + //transferHandle.speed_hz = 976000; + //transferHandle.len = 2; + return HasReturnvaluesIF::RETURN_OK; +} \ No newline at end of file diff --git a/bsp_rpi/boardtest/SpiTest.h b/bsp_rpi/boardtest/SpiTest.h new file mode 100644 index 00000000..9bdb8f25 --- /dev/null +++ b/bsp_rpi/boardtest/SpiTest.h @@ -0,0 +1,31 @@ +#ifndef BSP_LINUX_TEST_SPITEST_H_ +#define BSP_LINUX_TEST_SPITEST_H_ + +#include +#include +#include +#include + +class SpiTest: public ExecutableObjectIF, SystemObject { +public: + SpiTest(object_id_t objectId); + + ReturnValue_t performOperation(uint8_t opCode) override; + ReturnValue_t initialize() override; +private: + const std::string spiDeviceName = "/dev/spidev0.0"; + int spiFd = 0; + + uint8_t spiMode = SPI_MODE_3; + uint32_t spiSpeed = 976000; + + uint8_t sendBuffer[32]; + uint8_t receiveBuffer[32]; + struct spi_ioc_transfer transferHandle; + + bool oneShot = true; + +}; + + +#endif /* BSP_LINUX_TEST_SPITEST_H_ */ diff --git a/fsfw b/fsfw index 8ef6283b..1ac2479b 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 8ef6283bf4f5cf5d12131c48365a753825fea637 +Subproject commit 1ac2479b28c1114b0876123e0db4155abfbf06fe diff --git a/libcsp/include/CMakeLists.txt b/libcsp/include/CMakeLists.txt index cc80ebb5..196e26f3 100644 --- a/libcsp/include/CMakeLists.txt +++ b/libcsp/include/CMakeLists.txt @@ -1,7 +1,5 @@ target_include_directories(${LIB_CSP_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/csp - ${CMAKE_CURRENT_SOURCE_DIR}/csp/crypto ) target_include_directories(${LIB_CSP_NAME} INTERFACE From 2815725e5b83494c4c9446bcd07ee24dc231f879 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 18:12:05 +0100 Subject: [PATCH 110/360] cmake lists update --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0b00d30..a1410bdb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,8 +19,6 @@ if(NOT OS_FSFW) set(OS_FSFW host CACHE STRING "OS for the FSFW.") endif() -set_property(CACHE OS_FSFW PROPERTY STRINGS host linux) - # Perform steps like loading toolchain files where applicable. include(${CMAKE_SCRIPT_PATH}/PreProjectConfig.cmake) pre_project_config() @@ -91,6 +89,8 @@ add_subdirectory(${MISSION_PATH}) # Post-Sources preparation ################################################################################ +set_property(CACHE OS_FSFW PROPERTY STRINGS host linux) + # Add libraries for all sources. target_link_libraries(${TARGET_NAME} PRIVATE ${LIB_FSFW_NAME} From 68ce605d756b081f0e345d564c897262a13cd510 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 22:20:38 +0100 Subject: [PATCH 111/360] updared readme, added scripts --- README.md | 138 ++++++++++++------ cmake/Q7SCrossCompileConfig.cmake | 8 +- .../Q7S/win_path_helper_xilinx_tools.sh | 4 + doc/img/vivado-edition.png | Bin 0 -> 36951 bytes doc/img/vivado-hl-design.png | Bin 0 -> 50686 bytes 5 files changed, 105 insertions(+), 45 deletions(-) create mode 100644 cmake/scripts/Q7S/win_path_helper_xilinx_tools.sh create mode 100644 doc/img/vivado-edition.png create mode 100644 doc/img/vivado-hl-design.png diff --git a/README.md b/README.md index 0dd496c5..144d186d 100644 --- a/README.md +++ b/README.md @@ -16,55 +16,118 @@ Target systems: * Linux Kernel https://github.com/XiphosSystemsCorp/linux-xlnx.git * Host System * Generic software components which are not dependant on hardware can also - be run. All host code is contained in the hosted folder + be run on a host system. All host code is contained in the `bsp_hosted` folder * Tested for Linux (Ubuntu 20.04) and Windows 10 * Raspberry Pi * EIVE OBC can be built for Raspberry Pi as well (either directly on Raspberry Pi or by installing a cross compiler) The steps in the primary README are related to the main OBC target Q7S. +The CMake build system can be used to generate build systems as well (see helper scripts in `cmake/scripts`: + +- Linux (Raspberry Pi): Using the `bsp_rpi` BSP folder, and a very similar cross-compiler. + For running the software on a Raspberry Pi, it is recommended to follow the steps specified in + [the fsfw example](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example/src/branch/mueller/master/doc/README-rpi.md#top) and + using the TCF agent to have a similar set-up process also required for the Q7S. +- Linux Host: Uses the `bsp_hosted` BSP folder and the CMake Unix Makefiles generator. +- Windows Host: Uses the `bsp_hosted` BSP folder, the CMake MinGW Makefiles generator and MSYS2. ## Setting up development environment +### Installing Vivado the the Xilinx development tools + * Install Vivado 2018.2 and Xilinx SDK from https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/vivado-design-tools/archive.html. - Install the Vivado Design Suite - HLx Editions - 2018.2 Full Product Installation instead of the updates. It is recommended to use the installer + Install the Vivado Design Suite - HLx Editions - 2018.2 Full Product Installation instead of the updates. It is recommended to use the installer. + * Install settings. In the Devices selection, it is sufficient to pick SoC → Zynq-7000:
-
+ +
+
+
+ * For supported OS refer to https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_2/ug973-vivado-release-notes-install-license.pdf -* Add path of linux cross-compiler to environment variables SDK\2018.2\gnu\aarch32\nt\gcc-arm-linux-gnueabi\bin -* Install make (only on windows, SDK on Linux can use the make installed with the SDK) +* Add path of linux cross-compiler to permanent environment variables (`.profile` file in Linux): + `SDK\2018.2\gnu\aarch32\nt\gcc-arm-linux-gnueabi\bin` + or set up path each time before debugging. -### Installing make on Windows -1. Install NodeJS LTS -2. Install xpm - -```sh -npm install --global xpm -``` +### Installing CMake and MSYS2 on Windows -3. Install Windows build tools (after installation also linux commands like mkdir can be used from windows) +1. Install [MSYS2](https://www.msys2.org/) and [CMake](https://cmake.org/download/) first. -```sh -xpm install --global @xpack-dev-tools/windows-build-tools@latest -``` +2. Open the MinGW64 console. It is recommended to set up aliases in `.bashrc` to navigate to the + software repository quickly + +3. Run the following commands in MinGW64 -## Building the software + ```sh + pacman -Syuuu + ``` + + It is recommended to install the full base development toolchain + + ```sh + pacman -S base-devel + ``` + + It is also possible to only install required packages + + ```sh + pacman -S mingw-w64-x86_64-cmake mingw-w64-x86_64-make mingw-w64-x86_64-gcc mingw-w64-x86_64-gdb python3 + ``` + +### Installing CMake on Linux + +1. Run the following command + + ```sh + sudo apt-get install cmake + ```` + +## Building the software with CMake + +When using Windows, run theses steps in MSYS2. 1. Clone the repository with -```sh -git clone https://egit.irs.uni-stuttgart.de/eive/eive_obsw.git -``` + ```sh + git clone https://egit.irs.uni-stuttgart.de/eive/eive_obsw.git + ``` 2. Update all the submodules -```sh -git submodule init -git submodule sync -git submodule update -``` -3. Open Xilinx SDK 2018.2 -4. Import project + ```sh + git submodule init + git submodule sync + git submodule update + ``` + +3. Ensure that the cross-compiler is working with `arm-linux-gnueabihf-gcc --version`. + It is recommended to run the shell script `win_path_helper_xilinx_tools.sh` in `cmake/scripts/Q7S` + or to set up the [PATH and the CROSS_COMPILE variable permanently](https://unix.stackexchange.com/questions/26047/how-to-correctly-add-a-path-to-path) + in the `.profile` file. + +4. Run the CMake configuration to create the build system in a `Debug` folder. + Navigate into the `eive_obsw` folder first. + + ```sh + cd cmake/scripts/Q7S` + ./create_cmake_debug.sh + cd ../../.. + ``` + + This will invoke a Python script which in turn invokes CMake with the correct + arguments to configure CMake for Q7S cross-compilation. + +5. Build the software with + ```sh + cd Debug + cmake --build . -j + ``` + +## Building in Xilinx SDK 2018.2 + +1. Open Xilinx SDK 2018.2 +2. Import project * File → Import → C/C++ → Existing Code as Makefile Project -5. Set build command. Replace \ with either debug or release. +3. Set build command. Replace \ with either debug or release. * When on Linux right click project → Properties → C/C++ Build → Set build command to `make -j` * -j causes the compiler to use all available cores * The target is used to either compile the debug or the optimized release build. @@ -73,11 +136,13 @@ git submodule update * Target name: all * Uncheck "Same as the target name" * Uncheck "Use builder settings" - * As build command type: `make -j WINDOWS=1` -6. Run build command by double clicking the created target or by right clicking + * As build command type: `cmake --build .` + * In the Behaviour tab, you can enable build acceleration +4. Run build command by double clicking the created target or by right clicking the project folder and selecting Build Project. ## Debugging the software (when workstation is directly conncected to Q7S) + 1. Assign static IP address to Q7S * Open serial console of Q7S (Accessible via the micro-USB of the PIM, see also Q7S user maunal chapter 10.3) * Baudrate 115200 @@ -96,6 +161,7 @@ git submodule update * When IP address is set to 192.168.133.10 and the netmask is 255.255.255.0, an example IP address for the workstation is 192.168.133.2 4. Run tcf-agent on Q7S + * Tcf-agent is not yet integrated in the rootfs of the Q7S. Therefore build tcf-agent manually ```sh @@ -307,17 +373,6 @@ a permanent solution). If running the script before executing the binary does not help or an warning is issue that the soft real time value is invalid, the hard real-time limit of the system might not be high enough (see step 1). -## Building and running the software on a host system - -The host build can be built with following command - -```sh -make -f Makefile-Hosted all -j -``` - -If compiling on Windows, it is recommended to supply `WINDOWS=1` . -A release build can be built by using the `mission` target. - ## Flight Software Framework (FSFW) An EIVE fork of the FSFW is submodules into this repository. @@ -339,6 +394,7 @@ Alternatively, changes from other upstreams (forks) and branches can be merged l the same way. ## PCDU + Connect to serial console of P60 Dock ```` picocom -b 500000 /dev/ttyUSBx diff --git a/cmake/Q7SCrossCompileConfig.cmake b/cmake/Q7SCrossCompileConfig.cmake index 665869f9..2fb8134b 100644 --- a/cmake/Q7SCrossCompileConfig.cmake +++ b/cmake/Q7SCrossCompileConfig.cmake @@ -1,13 +1,13 @@ # CROSS_COMPILE also needs to be set accordingly or passed to the CMake command -#if(NOT DEFINED ENV{Q7S_ROOTFS}) +if(NOT DEFINED ENV{Q7S_SYSROOT}) # message(FATAL_ERROR # "Define the Q7S_ROOTFS variable to " # "point to the raspbian rootfs." # ) -#else() -# set(SYSROOT_PATH "$ENV{Q7S_ROOTFS}") -#endif() +else() + set(SYSROOT_PATH "$ENV{Q7S_SYSROOT}") +endif() if(NOT DEFINED ENV{CROSS_COMPILE}) set(CROSS_COMPILE "arm-linux-gnueabihf") diff --git a/cmake/scripts/Q7S/win_path_helper_xilinx_tools.sh b/cmake/scripts/Q7S/win_path_helper_xilinx_tools.sh new file mode 100644 index 00000000..ac2411b7 --- /dev/null +++ b/cmake/scripts/Q7S/win_path_helper_xilinx_tools.sh @@ -0,0 +1,4 @@ +export PATH=$PATH:"/c/Xilinx/SDK/2018.2/gnu/aarch32/nt/gcc-arm-linux-gnueabi/bin" +export CROSS_COMPILE="arm-linux-gnueabihf" + +export Q7S_SYSROOT="/c/Xilinx/SDK/2018.2/gnu/aarch32/nt/gcc-arm-linux-gnueabi/arm-linux-gnueabihf/libc" diff --git a/doc/img/vivado-edition.png b/doc/img/vivado-edition.png new file mode 100644 index 0000000000000000000000000000000000000000..c34051f3ed3c3cf7c798e8e18d93e5e78d61f26e GIT binary patch literal 36951 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%0A#<4=r+Zl>Dsguq3zsH^zuKVdH!bj zUwtkjx%@Ha{QZCY{kJjyn}7YEx?cbP8OZ-;(f|J){J-B7|8MC2l@KAM@;rq95H5XkuL8yFQjRWqj!N{}7 zHgM!~O}e=zgx3L&4xWlgqvR>n5posL3}g*EBE33c-+@KES~)+>W5Lc7c7uIg;NdS{ zA}ZqY$6Uv&lxs7rDt*B|!J+D7y{UucY+aofCrtMaaPtOA&F`G=-Ptp0!x>*(NZo~vQ1_gLb300Z^~VP zIYQ{FY3W9>WiPX6)4*~=VuLJy%SKJj7ciFyYkE>94lZu_>`$?q>f04oPYsI|pp80s zdvg+|mZZYY$lgQ&0~WLjZbLIEyHaNI<3ZuPL$s!4ewAB1zI^O?*RTv#2L#$UFS^J( z{kdhz8q!dOdGRyiT~t`V$xcMw2{DT}k{|C<36h7t_(^qJnsmBw2Y*mH?%r(Gi4X?e z`u#*aE@xTGv1}?0u&)VY!UK6Z7o%z>5IZX=gPjj6#v{=CEET?esp{9{+bRwo+b zdIUlZPB2?+7ZhsuV+Fchat|L=#yYFtfBPn`O1|Zx4}7FT^Z+A%LRf+^5~~i$;lVvR zI(sF8^L{zAGgU?UnTBWL(AACXiTuR-xj+1tiK=}8O)Pqj20^j4AANf{3EH;V znN@j$bgs^Zbs&rAbYdawW)Rn54KY%UJuQq`KM7Z!D(t7; z;EX?4k(F!j#z$d0RD37#I=|HE*Cz*)nvqL55~70!>GEC=l3;iE0&;;UqmLogUQF-kf$0tETd5mJHmQAtF^hQ*@vu?qCVdK z-IwP{D~8m8e@UCKNAsK8m()qDCntuvuu z;Qe<${

lrO2I>Z+IYp40k)b7h}vE* zANkI*K@Z-&fZSlQ@=8UY3OD2;?+kD5%50wTg(Y~~cMS>-<8?zOsu!PDU4D%yz~RD$ zw;53z?#*OC-j#Z!8n&5)Plz{R#MS7BeDGQybqo6wENRvF&Tg4Chs};|P4HHL;(i$T%vucu z&@ra)12XX4|k0Mkm8yUoPCUVq-$I; z%{L~{Yn!!8S$C}<0lGTj1E&=G{fLT|jM~>oVc#MM`?;V$B`SLgx%l*8~4Lxvfm`{s)iK9-Ibi6@_j!bK}42BOgF9dO9hOCiy*vbEy0oXATtScP@Vbct zy{Sj#$AJnFy-f4nI(t(J)bgPKUuc)6bnc7egab+Nmga);Qm?Lp=GyFS`OpGyt`6Qh;U@C|=6^LzE# z>rVo*bBDG+=a)YiZiHXF;vbUz#<}?!kcM5Wf@}AF+s);b@gfMejHs6t2|%xbiY&?n zVEZexapEGwzz%iYTp7%@-+ZQiwv(;vIp5d^Lp^chHOX5uJJ0^pA=!ncPxj93^WZ+u Kz2rToul#?R_Jb$@ literal 0 HcmV?d00001 diff --git a/doc/img/vivado-hl-design.png b/doc/img/vivado-hl-design.png new file mode 100644 index 0000000000000000000000000000000000000000..3603f8cb7e8be788332ada13ebd19707c1516284 GIT binary patch literal 50686 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

H!;JX8^KAj>L#e;@V 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 Date: Tue, 29 Dec 2020 22:21:39 +0100 Subject: [PATCH 112/360] readme update --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 144d186d..4cf22f57 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,9 @@ The CMake build system can be used to generate build systems as well (see helper * Install settings. In the Devices selection, it is sufficient to pick SoC → Zynq-7000:
-
-
-
+
+
+
* For supported OS refer to https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_2/ug973-vivado-release-notes-install-license.pdf * Add path of linux cross-compiler to permanent environment variables (`.profile` file in Linux): From 81f2508c3763516f2467b5663197e1566a1b8f9b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 22:23:12 +0100 Subject: [PATCH 113/360] one pic not showing,. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4cf22f57..2bf78c10 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,9 @@ The CMake build system can be used to generate build systems as well (see helper * Install settings. In the Devices selection, it is sufficient to pick SoC → Zynq-7000:

+
+
* For supported OS refer to https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_2/ug973-vivado-release-notes-install-license.pdf From 2e5ac80bf7e2c2ee9f68f3b306b5f0e406ddc1ec Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 22:24:38 +0100 Subject: [PATCH 114/360] png capital --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2bf78c10..4c9a2497 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ The CMake build system can be used to generate build systems as well (see helper
-
+
* For supported OS refer to https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_2/ug973-vivado-release-notes-install-license.pdf * Add path of linux cross-compiler to permanent environment variables (`.profile` file in Linux): From 4f6835e070eb1ece18ce22762f8c183c7460a6ba Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 29 Dec 2020 22:29:02 +0100 Subject: [PATCH 115/360] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4c9a2497..2c1c2899 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ When using Windows, run theses steps in MSYS2. Navigate into the `eive_obsw` folder first. ```sh - cd cmake/scripts/Q7S` + cd cmake/scripts/Q7S ./create_cmake_debug.sh cd ../../.. ``` From 9a2662d77e05504f74b4c542b514eea86e93c8f5 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 30 Dec 2020 09:39:34 +0100 Subject: [PATCH 116/360] README update --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2c1c2899..56e8f93d 100644 --- a/README.md +++ b/README.md @@ -203,17 +203,26 @@ When using Windows, run theses steps in MSYS2. * Remote File Path: /tmp/eive_obsw.elf ## Debugging the software via Flatsat PC + Open SSH connection to flatsat PC: ```sh ssh eive@2001:7c0:2018:1099:babe:0:e1fe:f1a5 ``` +or + +```sh +ssh eive@192.168.199.227 +``` + To access the console of the Q7S run the following: ```sh picocom -b 115200 /dev/ttyUSB0 ``` +You can use `AltGr` + `X` to exit the picocom session. + To debug an application, first make sure a static IP address is assigned to the Q7S. Run ifconfig on the Q7S serial console. ```sh @@ -227,7 +236,8 @@ ifconfig eth0 192.168.133.10 ifconfig eth0 netmask 255.255.255.0 ``` -To launch application from Xilinx SDK setup port fowarding on the localhost. +To launch application from Xilinx SDK setup port fowarding on the development machine +(not on the flatsat!) ```sh ssh -L 1534:192.168.133.10:1534 eive@2001:7c0:2018:1099:babe:0:e1fe:f1a5 From 192f864e4c80bb80adec89f49fa52f225390eea9 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 30 Dec 2020 10:10:15 +0100 Subject: [PATCH 117/360] added readme and user manual --- README.md | 29 ++++++++++++++++++++++++++++- doc/Q7S-user-manual.pdf | Bin 0 -> 1572853 bytes 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 doc/Q7S-user-manual.pdf diff --git a/README.md b/README.md index 56e8f93d..720bf5cb 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,10 @@ The CMake build system can be used to generate build systems as well (see helper ### Installing Vivado the the Xilinx development tools +It's also possible to perform debugging with a normal Eclipse installation by installing +the TCF plugin. Still, it is necessary to install Vivado to get the toolchain for generating +C++ applications. + * Install Vivado 2018.2 and Xilinx SDK from https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/vivado-design-tools/archive.html. Install the Vivado Design Suite - HLx Editions - 2018.2 Full Product Installation instead of the updates. It is recommended to use the installer. @@ -48,7 +52,7 @@ The CMake build system can be used to generate build systems as well (see helper * For supported OS refer to https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_2/ug973-vivado-release-notes-install-license.pdf * Add path of linux cross-compiler to permanent environment variables (`.profile` file in Linux): - `SDK\2018.2\gnu\aarch32\nt\gcc-arm-linux-gnueabi\bin` + `\SDK\2018.2\gnu\aarch32\nt\gcc-arm-linux-gnueabi\bin` or set up path each time before debugging. ### Installing CMake and MSYS2 on Windows @@ -89,6 +93,7 @@ The CMake build system can be used to generate build systems as well (see helper When using Windows, run theses steps in MSYS2. 1. Clone the repository with + ```sh git clone https://egit.irs.uni-stuttgart.de/eive/eive_obsw.git ``` @@ -124,6 +129,28 @@ When using Windows, run theses steps in MSYS2. cmake --build . -j ``` +## Setting up default Eclipse for Q7S projects - TCF agent + +The [TCF agent](https://wiki.eclipse.org/TCF) can be used to perform remote debugging on the Q7S. + +1. Install the TCF agent plugin in Eclipse from the [releases](https://www.eclipse.org/tcf/downloads.php). Go to Help → Install New Software and use the download page, for example https://download.eclipse.org/tools/tcf/releases/1.6/1.6.2/ to search for the plugin and install it. + +2. Go to Window → Perspective → Open Perspective and open the **Target Explorer Perspective**. Here, the Raspberry Pi should show up if the TCF agent has been set up on the Raspberry Pi as specified [here](https://wiki.eclipse.org/TCF/Raspberry_Pi) or in the respective [README](README-rpi.md#top). Connect to it. + +3. A launch configuration was provided, but it might be necessary to adapt it for your own needs. Alternatively: + + - Create a new **TCF Remote Application** by pressing the cogs button at the top or going to Run → Debug Configurations → Remote Application and creating a new one there. + + - Set up the correct image in the main tab (it might be necessary to send it the the Raspberry Pi manually once) and file transfer properties + + - It is also recommended to link the correct Eclipse project. + +After that, comfortable remote debugging should be possible with the Debug button. + +A build configuration and a shell helper script has been provided to set up the path variables and build the Q7S binary +on Windows, but a launch configuration needs to be newly created because the IP address and path settings differ +from machine to machine. + ## Building in Xilinx SDK 2018.2 1. Open Xilinx SDK 2018.2 diff --git a/doc/Q7S-user-manual.pdf b/doc/Q7S-user-manual.pdf new file mode 100644 index 0000000000000000000000000000000000000000..70ab7bb42de8b35109fa574281f2d35a9fc162bc GIT binary patch literal 1572853 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
x{f(Tt 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

  • CiCVHYo7#02Asi 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

    7cp>Ju6|y>m0SN7W6)a9@RaWhA;X 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

    W#wo;*IEjHYRd%pRYY08tUFX{upa(B4M> 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

    ;I(k?)g!2 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